]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/mfd/db8500-prcmu.c
Merge tag 'linux-watchdog-5.5-rc1' of git://www.linux-watchdog.org/linux-watchdog
[linux.git] / drivers / mfd / db8500-prcmu.c
index 90e0f21bc49c55045bb03ff7582200b403b320a7..57ac58b4b5f304e3d610ee74bd72e836f6d740ff 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/bitops.h>
 #include <linux/fs.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>
@@ -36,7 +37,6 @@
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
 #include <linux/platform_data/ux500_wdt.h>
-#include <linux/platform_data/db8500_thermal.h>
 #include "dbx500-prcmu-regs.h"
 
 /* Index of different voltages to be used when accessing AVSData */
@@ -669,6 +669,14 @@ struct prcmu_fw_version *prcmu_get_fw_version(void)
        return fw_info.valid ? &fw_info.version : NULL;
 }
 
+static bool prcmu_is_ulppll_disabled(void)
+{
+       struct prcmu_fw_version *ver;
+
+       ver = prcmu_get_fw_version();
+       return ver && ver->project == PRCMU_FW_PROJECT_U8420_SYSCLK;
+}
+
 bool prcmu_has_arm_maxopp(void)
 {
        return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
@@ -1309,10 +1317,23 @@ static int request_sysclk(bool enable)
 
 static int request_timclk(bool enable)
 {
-       u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK);
+       u32 val;
+
+       /*
+        * On the U8420_CLKSEL firmware, the ULP (Ultra Low Power)
+        * PLL is disabled so we cannot use doze mode, this will
+        * stop the clock on this firmware.
+        */
+       if (prcmu_is_ulppll_disabled())
+               val = 0;
+       else
+               val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK);
 
        if (!enable)
-               val |= PRCM_TCR_STOP_TIMERS;
+               val |= PRCM_TCR_STOP_TIMERS |
+                       PRCM_TCR_DOZE_MODE |
+                       PRCM_TCR_TENSEL_MASK;
+
        writel(val, PRCM_TCR);
 
        return 0;
@@ -1616,7 +1637,8 @@ unsigned long prcmu_clock_rate(u8 clock)
        if (clock < PRCMU_NUM_REG_CLOCKS)
                return clock_rate(clock);
        else if (clock == PRCMU_TIMCLK)
-               return ROOT_CLOCK_RATE / 16;
+               return prcmu_is_ulppll_disabled() ?
+                       32768 : ROOT_CLOCK_RATE / 16;
        else if (clock == PRCMU_SYSCLK)
                return ROOT_CLOCK_RATE;
        else if (clock == PRCMU_PLLSOC0)
@@ -1695,21 +1717,41 @@ static long round_clock_rate(u8 clock, unsigned long rate)
        return rounded_rate;
 }
 
-static const unsigned long armss_freqs[] = {
+static const unsigned long db8500_armss_freqs[] = {
        200000000,
        400000000,
        800000000,
        998400000
 };
 
+/* The DB8520 has slightly higher ARMSS max frequency */
+static const unsigned long db8520_armss_freqs[] = {
+       200000000,
+       400000000,
+       800000000,
+       1152000000
+};
+
+
+
 static long round_armss_rate(unsigned long rate)
 {
        unsigned long freq = 0;
+       const unsigned long *freqs;
+       int nfreqs;
        int i;
 
+       if (fw_info.version.project == PRCMU_FW_PROJECT_U8520) {
+               freqs = db8520_armss_freqs;
+               nfreqs = ARRAY_SIZE(db8520_armss_freqs);
+       } else {
+               freqs = db8500_armss_freqs;
+               nfreqs = ARRAY_SIZE(db8500_armss_freqs);
+       }
+
        /* Find the corresponding arm opp from the cpufreq table. */
-       for (i = 0; i < ARRAY_SIZE(armss_freqs); i++) {
-               freq = armss_freqs[i];
+       for (i = 0; i < nfreqs; i++) {
+               freq = freqs[i];
                if (rate <= freq)
                        break;
        }
@@ -1854,11 +1896,21 @@ static int set_armss_rate(unsigned long rate)
 {
        unsigned long freq;
        u8 opps[] = { ARM_EXTCLK, ARM_50_OPP, ARM_100_OPP, ARM_MAX_OPP };
+       const unsigned long *freqs;
+       int nfreqs;
        int i;
 
+       if (fw_info.version.project == PRCMU_FW_PROJECT_U8520) {
+               freqs = db8520_armss_freqs;
+               nfreqs = ARRAY_SIZE(db8520_armss_freqs);
+       } else {
+               freqs = db8500_armss_freqs;
+               nfreqs = ARRAY_SIZE(db8500_armss_freqs);
+       }
+
        /* Find the corresponding arm opp from the cpufreq table. */
-       for (i = 0; i < ARRAY_SIZE(armss_freqs); i++) {
-               freq = armss_freqs[i];
+       for (i = 0; i < nfreqs; i++) {
+               freq = freqs[i];
                if (rate == freq)
                        break;
        }
@@ -2617,6 +2669,8 @@ static char *fw_project_name(u32 project)
                return "U8520 MBL";
        case PRCMU_FW_PROJECT_U8420:
                return "U8420";
+       case PRCMU_FW_PROJECT_U8420_SYSCLK:
+               return "U8420-sysclk";
        case PRCMU_FW_PROJECT_U9540:
                return "U9540";
        case PRCMU_FW_PROJECT_A9420:
@@ -2664,27 +2718,18 @@ static int db8500_irq_init(struct device_node *np)
        return 0;
 }
 
-static void dbx500_fw_version_init(struct platform_device *pdev,
-                           u32 version_offset)
+static void dbx500_fw_version_init(struct device_node *np)
 {
-       struct resource *res;
        void __iomem *tcpm_base;
        u32 version;
 
-       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));
+       tcpm_base = of_iomap(np, 1);
        if (!tcpm_base) {
-               dev_err(&pdev->dev, "no prcmu tcpm mem region provided\n");
+               pr_err("no prcmu tcpm mem region provided\n");
                return;
        }
 
-       version = readl(tcpm_base + version_offset);
+       version = readl(tcpm_base + DB8500_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;
@@ -2702,7 +2747,7 @@ static void dbx500_fw_version_init(struct platform_device *pdev,
        iounmap(tcpm_base);
 }
 
-void __init db8500_prcmu_early_init(u32 phy_base, u32 size)
+void __init db8500_prcmu_early_init(void)
 {
        /*
         * This is a temporary remap to bring up the clocks. It is
@@ -2711,9 +2756,17 @@ void __init db8500_prcmu_early_init(u32 phy_base, u32 size)
         * clock driver can probe independently. An early initcall will
         * still be needed, but it can be diverted into drivers/clk/ux500.
         */
-       prcmu_base = ioremap(phy_base, size);
-       if (!prcmu_base)
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
+       prcmu_base = of_iomap(np, 0);
+       if (!prcmu_base) {
+               of_node_put(np);
                pr_err("%s: ioremap() of prcmu registers failed!\n", __func__);
+               return;
+       }
+       dbx500_fw_version_init(np);
+       of_node_put(np);
 
        spin_lock_init(&mb0_transfer.lock);
        spin_lock_init(&mb0_transfer.dbb_irqs_lock);
@@ -2984,53 +3037,6 @@ static struct ux500_wdt_data db8500_wdt_pdata = {
        .timeout = 600, /* 10 minutes */
        .has_28_bits_resolution = true,
 };
-/*
- * Thermal Sensor
- */
-
-static struct resource db8500_thsens_resources[] = {
-       {
-               .name = "IRQ_HOTMON_LOW",
-               .start  = IRQ_PRCMU_HOTMON_LOW,
-               .end    = IRQ_PRCMU_HOTMON_LOW,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .name = "IRQ_HOTMON_HIGH",
-               .start  = IRQ_PRCMU_HOTMON_HIGH,
-               .end    = IRQ_PRCMU_HOTMON_HIGH,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct db8500_thsens_platform_data db8500_thsens_data = {
-       .trip_points[0] = {
-               .temp = 70000,
-               .type = THERMAL_TRIP_ACTIVE,
-               .cdev_name = {
-                       [0] = "thermal-cpufreq-0",
-               },
-       },
-       .trip_points[1] = {
-               .temp = 75000,
-               .type = THERMAL_TRIP_ACTIVE,
-               .cdev_name = {
-                       [0] = "thermal-cpufreq-0",
-               },
-       },
-       .trip_points[2] = {
-               .temp = 80000,
-               .type = THERMAL_TRIP_ACTIVE,
-               .cdev_name = {
-                       [0] = "thermal-cpufreq-0",
-               },
-       },
-       .trip_points[3] = {
-               .temp = 85000,
-               .type = THERMAL_TRIP_CRITICAL,
-       },
-       .num_trips = 4,
-};
 
 static const struct mfd_cell common_prcmu_devs[] = {
        {
@@ -3042,23 +3048,13 @@ static const struct mfd_cell common_prcmu_devs[] = {
 };
 
 static const struct mfd_cell db8500_prcmu_devs[] = {
-       {
-               .name = "db8500-prcmu-regulators",
-               .of_compatible = "stericsson,db8500-prcmu-regulator",
-               .platform_data = &db8500_regulators,
-               .pdata_size = sizeof(db8500_regulators),
-       },
-       {
-               .name = "cpuidle-dbx500",
-               .of_compatible = "stericsson,cpuidle-dbx500",
-       },
-       {
-               .name = "db8500-thermal",
-               .num_resources = ARRAY_SIZE(db8500_thsens_resources),
-               .resources = db8500_thsens_resources,
-               .platform_data = &db8500_thsens_data,
-               .pdata_size = sizeof(db8500_thsens_data),
-       },
+       OF_MFD_CELL("db8500-prcmu-regulators", NULL,
+                   &db8500_regulators, sizeof(db8500_regulators), 0,
+                   "stericsson,db8500-prcmu-regulator"),
+       OF_MFD_CELL("cpuidle-dbx500",
+                   NULL, NULL, 0, 0, "stericsson,cpuidle-dbx500"),
+       OF_MFD_CELL("db8500-thermal",
+                   NULL, NULL, 0, 0, "stericsson,db8500-thermal"),
 };
 
 static int db8500_prcmu_register_ab8500(struct device *parent)
@@ -3112,7 +3108,6 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        init_prcm_registers();
-       dbx500_fw_version_init(pdev, DB8500_PRCMU_FW_VERSION_OFFSET);
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
        if (!res) {
                dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
@@ -3130,10 +3125,8 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
        writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(&pdev->dev, "no prcmu irq provided\n");
+       if (irq <= 0)
                return irq;
-       }
 
        err = request_threaded_irq(irq, prcmu_irq_handler,
                prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);