]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/mfd/db8500-prcmu.c
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[linux-beck.git] / drivers / mfd / db8500-prcmu.c
index 003a10eb12b6bce31ce21af0f93d096a9aacbf0b..a2bacf95b59ea543ca46104f9137a72497b89905 100644 (file)
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/db8500-regs.h>
-#include <mach/id.h>
 #include "dbx500-prcmu-regs.h"
 
-/* Offset for the firmware version within the TCPM */
-#define PRCMU_FW_VERSION_OFFSET 0xA4
-
 /* Index of different voltages to be used when accessing AVSData */
 #define PRCM_AVS_BASE          0x2FC
 #define PRCM_AVS_VBB_RET       (PRCM_AVS_BASE + 0x0)
 #define PRCM_REQ_MB5_I2C_HW_BITS       (PRCM_REQ_MB5 + 0x1)
 #define PRCM_REQ_MB5_I2C_REG           (PRCM_REQ_MB5 + 0x2)
 #define PRCM_REQ_MB5_I2C_VAL           (PRCM_REQ_MB5 + 0x3)
-#define PRCMU_I2C_WRITE(slave) \
-       (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
-#define PRCMU_I2C_READ(slave) \
-       (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_WRITE(slave) (((slave) << 1) | BIT(6))
+#define PRCMU_I2C_READ(slave) (((slave) << 1) | BIT(0) | BIT(6))
 #define PRCMU_I2C_STOP_EN              BIT(3)
 
 /* Mailbox 5 ACKs */
@@ -1049,12 +1043,13 @@ int db8500_prcmu_get_ddr_opp(void)
  *
  * This function sets the operating point of the DDR.
  */
+static bool enable_set_ddr_opp;
 int db8500_prcmu_set_ddr_opp(u8 opp)
 {
        if (opp < DDR_100_OPP || opp > DDR_25_OPP)
                return -EINVAL;
        /* Changing the DDR OPP can hang the hardware pre-v21 */
-       if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20())
+       if (enable_set_ddr_opp)
                writeb(opp, PRCM_DDR_SUBSYS_APE_MINBW);
 
        return 0;
@@ -2524,7 +2519,7 @@ static bool read_mailbox_0(void)
 
                for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
                        if (ev & prcmu_irq_bit[n])
-                               generic_handle_irq(IRQ_PRCMU_BASE + n);
+                               generic_handle_irq(irq_find_mapping(db8500_irq_domain, n));
                }
                r = true;
                break;
@@ -2706,21 +2701,43 @@ static struct irq_chip prcmu_irq_chip = {
        .irq_unmask     = prcmu_irq_unmask,
 };
 
-static char *fw_project_name(u8 project)
+static __init char *fw_project_name(u32 project)
 {
        switch (project) {
        case PRCMU_FW_PROJECT_U8500:
                return "U8500";
-       case PRCMU_FW_PROJECT_U8500_C2:
-               return "U8500 C2";
+       case PRCMU_FW_PROJECT_U8400:
+               return "U8400";
        case PRCMU_FW_PROJECT_U9500:
                return "U9500";
-       case PRCMU_FW_PROJECT_U9500_C2:
-               return "U9500 C2";
+       case PRCMU_FW_PROJECT_U8500_MBB:
+               return "U8500 MBB";
+       case PRCMU_FW_PROJECT_U8500_C1:
+               return "U8500 C1";
+       case PRCMU_FW_PROJECT_U8500_C2:
+               return "U8500 C2";
+       case PRCMU_FW_PROJECT_U8500_C3:
+               return "U8500 C3";
+       case PRCMU_FW_PROJECT_U8500_C4:
+               return "U8500 C4";
+       case PRCMU_FW_PROJECT_U9500_MBL:
+               return "U9500 MBL";
+       case PRCMU_FW_PROJECT_U8500_MBL:
+               return "U8500 MBL";
+       case PRCMU_FW_PROJECT_U8500_MBL2:
+               return "U8500 MBL2";
        case PRCMU_FW_PROJECT_U8520:
-               return "U8520";
+               return "U8520 MBL";
        case PRCMU_FW_PROJECT_U8420:
                return "U8420";
+       case PRCMU_FW_PROJECT_U9540:
+               return "U9540";
+       case PRCMU_FW_PROJECT_A9420:
+               return "A9420";
+       case PRCMU_FW_PROJECT_L8540:
+               return "L8540";
+       case PRCMU_FW_PROJECT_L8580:
+               return "L8580";
        default:
                return "Unknown";
        }
@@ -2737,13 +2754,14 @@ static int db8500_irq_map(struct irq_domain *d, unsigned int virq,
 }
 
 static struct irq_domain_ops db8500_irq_ops = {
-        .map    = db8500_irq_map,
-        .xlate  = irq_domain_xlate_twocell,
+       .map    = db8500_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
 static int db8500_irq_init(struct device_node *np)
 {
-       int irq_base = -1;
+       int irq_base = 0;
+       int i;
 
        /* In the device tree case, just take some IRQs */
        if (!np)
@@ -2758,39 +2776,51 @@ static int db8500_irq_init(struct device_node *np)
                return -ENOSYS;
        }
 
+       /* All wakeups will be used, so create mappings for all */
+       for (i = 0; i < NUM_PRCMU_WAKEUPS; i++)
+               irq_create_mapping(db8500_irq_domain, i);
+
        return 0;
 }
 
-void __init db8500_prcmu_early_init(void)
+static void dbx500_fw_version_init(struct platform_device *pdev,
+                           u32 version_offset)
 {
-       if (cpu_is_u8500v2() || cpu_is_u9540()) {
-               void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
-
-               if (tcpm_base != NULL) {
-                       u32 version;
-                       version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
-                       fw_info.version.project = version & 0xFF;
-                       fw_info.version.api_version = (version >> 8) & 0xFF;
-                       fw_info.version.func_version = (version >> 16) & 0xFF;
-                       fw_info.version.errata = (version >> 24) & 0xFF;
-                       fw_info.valid = true;
-                       pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
-                               fw_project_name(fw_info.version.project),
-                               (version >> 8) & 0xFF, (version >> 16) & 0xFF,
-                               (version >> 24) & 0xFF);
-                       iounmap(tcpm_base);
-               }
+       struct resource *res;
+       void __iomem *tcpm_base;
 
-               if (cpu_is_u9540())
-                       tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE,
-                                               SZ_4K + SZ_8K) + SZ_8K;
-               else
-                       tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
-       } else {
-               pr_err("prcmu: Unsupported chip version\n");
-               BUG();
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                          "prcmu-tcpm");
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Error: no prcmu tcpm memory region provided\n");
+               return;
+       }
+       tcpm_base = ioremap(res->start, resource_size(res));
+       if (tcpm_base != NULL) {
+               u32 version;
+
+               version = readl(tcpm_base + version_offset);
+               fw_info.version.project = (version & 0xFF);
+               fw_info.version.api_version = (version >> 8) & 0xFF;
+               fw_info.version.func_version = (version >> 16) & 0xFF;
+               fw_info.version.errata = (version >> 24) & 0xFF;
+               strncpy(fw_info.version.project_name,
+                       fw_project_name(fw_info.version.project),
+                       PRCMU_FW_PROJECT_NAME_LEN);
+               fw_info.valid = true;
+               pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n",
+                       fw_info.version.project_name,
+                       fw_info.version.project,
+                       fw_info.version.api_version,
+                       fw_info.version.func_version,
+                       fw_info.version.errata);
+               iounmap(tcpm_base);
        }
+}
 
+void __init db8500_prcmu_early_init(void)
+{
        spin_lock_init(&mb0_transfer.lock);
        spin_lock_init(&mb0_transfer.dbb_irqs_lock);
        mutex_init(&mb0_transfer.ac_wake_lock);
@@ -3100,23 +3130,30 @@ static void db8500_prcmu_update_cpufreq(void)
  */
 static int db8500_prcmu_probe(struct platform_device *pdev)
 {
-       struct ab8500_platform_data *ab8500_platdata = pdev->dev.platform_data;
        struct device_node *np = pdev->dev.of_node;
+       struct prcmu_pdata *pdata = dev_get_platdata(&pdev->dev);
        int irq = 0, err = 0, i;
-
-       if (ux500_is_svp())
-               return -ENODEV;
+       struct resource *res;
 
        init_prcm_registers();
 
+       dbx500_fw_version_init(pdev, pdata->version_offset);
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
+       if (!res) {
+               dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
+               return -ENOENT;
+       }
+       tcdm_base = devm_ioremap(&pdev->dev, res->start,
+                       resource_size(res));
+
        /* Clean up the mailbox interrupts after pre-kernel code. */
        writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
 
-       if (np)
-               irq = platform_get_irq(pdev, 0);
-
-       if (!np || irq <= 0)
-               irq = IRQ_DB8500_PRCMU1;
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(&pdev->dev, "no prcmu irq provided\n");
+               return -ENOENT;
+       }
 
        err = request_threaded_irq(irq, prcmu_irq_handler,
                prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
@@ -3130,13 +3167,12 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
 
        for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) {
                if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) {
-                       db8500_prcmu_devs[i].platform_data = ab8500_platdata;
+                       db8500_prcmu_devs[i].platform_data = pdata->ab_platdata;
                        db8500_prcmu_devs[i].pdata_size = sizeof(struct ab8500_platform_data);
                }
        }
 
-       if (cpu_is_u8500v20_or_later())
-               prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+       prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
 
        db8500_prcmu_update_cpufreq();