Merge branch 'fixes-non-critical' into next/drivers2
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-lpc32xx / clock.c
index 0e01bf44479c27a4f45ba037848354845e0aa8d3..b7ef51119d37580839f9773431f69c4282bdbae0 100644 (file)
@@ -87,6 +87,7 @@
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/amba/bus.h>
 
 static DEFINE_SPINLOCK(global_clkregs_lock);
 
+static int usb_pll_enable, usb_pll_valid;
+
 static struct clk clk_armpll;
 static struct clk clk_usbpll;
 
@@ -384,30 +387,62 @@ static u32 local_clk_usbpll_setup(struct clk_pll_setup *pHCLKPllSetup)
 static int local_usbpll_enable(struct clk *clk, int enable)
 {
        u32 reg;
-       int ret = -ENODEV;
-       unsigned long timeout = jiffies + msecs_to_jiffies(10);
+       int ret = 0;
+       unsigned long timeout = jiffies + msecs_to_jiffies(20);
 
        reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
 
-       if (enable == 0) {
-               reg &= ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
-                       LPC32XX_CLKPWR_USBCTRL_CLK_EN2);
-               __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
-       } else if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP) {
+       __raw_writel(reg & ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN2 |
+               LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP),
+               LPC32XX_CLKPWR_USB_CTRL);
+       __raw_writel(reg & ~LPC32XX_CLKPWR_USBCTRL_CLK_EN1,
+               LPC32XX_CLKPWR_USB_CTRL);
+
+       if (enable && usb_pll_valid && usb_pll_enable) {
+               ret = -ENODEV;
+               /*
+                * If the PLL rate has been previously set, then the rate
+                * in the PLL register is valid and can be enabled here.
+                * Otherwise, it needs to be enabled as part of setrate.
+                */
+
+               /*
+                * Gate clock into PLL
+                */
                reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
                __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
 
-               /* Wait for PLL lock */
+               /*
+                * Enable PLL
+                */
+               reg |= LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP;
+               __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+               /*
+                * Wait for PLL to lock
+                */
                while (time_before(jiffies, timeout) && (ret == -ENODEV)) {
                        reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
                        if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_STS)
                                ret = 0;
+                       else
+                               udelay(10);
                }
 
+               /*
+                * Gate clock from PLL if PLL is locked
+                */
                if (ret == 0) {
-                       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
-                       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+                       __raw_writel(reg | LPC32XX_CLKPWR_USBCTRL_CLK_EN2,
+                               LPC32XX_CLKPWR_USB_CTRL);
+               } else {
+                       __raw_writel(reg & ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
+                               LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP),
+                               LPC32XX_CLKPWR_USB_CTRL);
                }
+       } else if ((enable == 0) && usb_pll_valid  && usb_pll_enable) {
+               usb_pll_valid = 0;
+               usb_pll_enable = 0;
        }
 
        return ret;
@@ -425,7 +460,7 @@ static unsigned long local_usbpll_round_rate(struct clk *clk,
         */
        rate = rate * 1000;
 
-       clkin = clk->parent->rate;
+       clkin = clk->get_rate(clk);
        usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
                LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
        clkin = clkin / usbdiv;
@@ -439,7 +474,8 @@ static unsigned long local_usbpll_round_rate(struct clk *clk,
 
 static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 clkin, reg, usbdiv;
+       int ret = -ENODEV;
+       u32 clkin, usbdiv;
        struct clk_pll_setup pllsetup;
 
        /*
@@ -448,7 +484,7 @@ static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
         */
        rate = rate * 1000;
 
-       clkin = clk->get_rate(clk);
+       clkin = clk->get_rate(clk->parent);
        usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
                LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
        clkin = clkin / usbdiv;
@@ -457,22 +493,25 @@ static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
        if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
                return -EINVAL;
 
+       /*
+        * Disable PLL clocks during PLL change
+        */
        local_usbpll_enable(clk, 0);
-
-       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
-       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
-       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
-
-       pllsetup.analog_on = 1;
+       pllsetup.analog_on = 0;
        local_clk_usbpll_setup(&pllsetup);
 
-       clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+       /*
+        * Start USB PLL and check PLL status
+        */
 
-       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
-       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
-       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+       usb_pll_valid = 1;
+       usb_pll_enable = 1;
 
-       return 0;
+       ret = local_usbpll_enable(clk, 1);
+       if (ret >= 0)
+               clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+
+       return ret;
 }
 
 static struct clk clk_usbpll = {
@@ -721,6 +760,41 @@ static struct clk clk_tsc = {
        .get_rate       = local_return_parent_rate,
 };
 
+static int adc_onoff_enable(struct clk *clk, int enable)
+{
+       u32 tmp;
+       u32 divider;
+
+       /* Use PERIPH_CLOCK */
+       tmp = __raw_readl(LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+       tmp |= LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL;
+       /*
+        * Set clock divider so that we have equal to or less than
+        * 4.5MHz clock at ADC
+        */
+       divider = clk->get_rate(clk) / 4500000 + 1;
+       tmp |= divider;
+       __raw_writel(tmp, LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+
+       /* synchronize rate of this clock w/ actual HW setting */
+       clk->rate = clk->get_rate(clk->parent) / divider;
+
+       if (enable == 0)
+               __raw_writel(0, clk->enable_reg);
+       else
+               __raw_writel(clk->enable_mask, clk->enable_reg);
+
+       return 0;
+}
+
+static struct clk clk_adc = {
+       .parent         = &clk_pclk,
+       .enable         = adc_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_ADC_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
 static int mmc_onoff_enable(struct clk *clk, int enable)
 {
        u32 tmp;
@@ -1055,6 +1129,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
        _REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
        _REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
+       _REGISTER_CLOCK("lpc32xx-adc", NULL, clk_adc)
        _REGISTER_CLOCK(NULL, "i2s0_ck", clk_i2s0)
        _REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1)
        _REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc)