pvtm: rk3368: add pvtm_pmu clk support (output 32k)
authordkl <dkl@rock-chips.com>
Fri, 30 Jan 2015 06:57:59 +0000 (14:57 +0800)
committerdkl <dkl@rock-chips.com>
Fri, 6 Mar 2015 07:06:38 +0000 (15:06 +0800)
Support pvtm_pmu output 32k clk. By default, 32k use xin32k,
and pvtm_pmu 32k clk is disabled.

Signed-off-by: dkl <dkl@rock-chips.com>
arch/arm/mach-rockchip/pvtm.c
arch/arm64/boot/dts/rk3368-clocks.dtsi
arch/arm64/boot/dts/rk3368.dtsi

index d8aa8f77f223f8b9a73ee1d9882102e9c7975271..e6c5ca2fe772094a7527ccd439bfd73463471dc4 100644 (file)
 #define RK3368_PVTM_STATUS1 (0x810)
 #define RK3368_PVTM_STATUS2 (0x814)
 
+#define RK3368_PMUPVTM_CON0 (0x180)
+#define RK3368_PMUPVTM_CON1 (0x184)
+#define RK3368_PMUPVTM_STATUS0 (0x190)
+#define RK3368_PMUPVTM_STATUS1 (0x194)
+
 #define grf_readl(offset)      readl_relaxed(RK_GRF_VIRT+offset)
 #define grf_writel(val, offset)        writel_relaxed(val, RK_GRF_VIRT+offset)
 
@@ -56,22 +61,30 @@ struct rockchip_pvtm {
 static struct rockchip_pvtm pvtm;
 
 static struct regmap *grf_regmap;
+static struct regmap *pmugrf_regmap;
 
 static DEFINE_MUTEX(pvtm_mutex);
 
-/* 0 core, 1 gpu */
+/* 0 core, 1 gpu, 2 pmu */
 static u32 rk3368_pvtm_get_value(u32 ch , u32 time_us)
 {
        u32 val = 0, clk_cnt, check_cnt, pvtm_done_bit;
        u32 sta = 0;
 
-       if (ch > 1)
+       if (ch > 2)
                return 0;
        /* 24m clk ,24cnt=1us */
        clk_cnt = time_us*24;
 
-       regmap_write(grf_regmap, RK3368_PVTM_CON0+(ch+1)*4, clk_cnt);
-       regmap_write(grf_regmap, RK3368_PVTM_CON0, wr_msk_bit(3, ch*8, 0x3));
+       if (ch == 2) {
+               regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON1, clk_cnt);
+               regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
+                            wr_msk_bit(3, 0, 0x3));
+       } else {
+               regmap_write(grf_regmap, RK3368_PVTM_CON0+(ch+1)*4, clk_cnt);
+               regmap_write(grf_regmap, RK3368_PVTM_CON0,
+                            wr_msk_bit(3, ch*8, 0x3));
+       }
 
        if (time_us >= 1000)
                mdelay(time_us / 1000);
@@ -83,18 +96,42 @@ static u32 rk3368_pvtm_get_value(u32 ch , u32 time_us)
                pvtm_done_bit = 1;
 
        check_cnt = 100;
-       while (!((regmap_read(grf_regmap, RK3368_PVTM_STATUS0, &sta) == 0) &&
-                (sta & (1 << pvtm_done_bit)))) {
-               udelay(4);
-               check_cnt--;
-               if (!check_cnt)
-                       break;
+       if (ch == 2) {
+               while (check_cnt--) {
+                       regmap_read(pmugrf_regmap, RK3368_PMUPVTM_STATUS0,
+                                   &sta);
+                       if (sta & 0x1)
+                               break;
+                       udelay(4);
+               }
+
+       } else {
+               while (check_cnt--) {
+                       regmap_read(grf_regmap, RK3368_PVTM_STATUS0, &sta);
+                       if (sta & (1 << pvtm_done_bit))
+                               break;
+                       udelay(4);
+               }
        }
 
        if (check_cnt)
-               regmap_read(grf_regmap, RK3368_PVTM_STATUS0+(ch+1)*4, &val);
+               if (ch == 2)
+                       regmap_read(pmugrf_regmap, RK3368_PMUPVTM_STATUS1,
+                                   &val);
+               else
+                       regmap_read(grf_regmap, RK3368_PVTM_STATUS0+(ch+1)*4,
+                                   &val);
+       else {
+               pr_err("%s: wait pvtm_done timeout!\n", __func__);
+               val = 0;
+       }
 
-       regmap_write(grf_regmap, RK3368_PVTM_CON0, wr_msk_bit(0, ch*8, 0x3));
+       if (ch == 2)
+               regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
+                            wr_msk_bit(0, 0, 0x3));
+       else
+               regmap_write(grf_regmap, RK3368_PVTM_CON0,
+                            wr_msk_bit(0, ch*8, 0x3));
 
        return val;
 }
@@ -200,9 +237,48 @@ u32 pvtm_get_value(u32 ch, u32 time_us)
        return val;
 }
 
+static int __init rk3368_pmupvtm_clk_init(void)
+{
+       u32 pvtm_cnt = 0, div, val, time_us;
+       unsigned long rate = 32;/* KHZ */
+       int ret = 0;
+
+       pr_info("%s\n", __func__);
+
+       time_us = 1000;
+       pvtm_cnt = pvtm_get_value(2, time_us);
+       pr_debug("get pvtm_cnt = %d\n", pvtm_cnt);
+
+       /* set pvtm_div to get rate */
+       div = DIV_ROUND_UP(1000*pvtm_cnt, time_us*rate);
+       val = DIV_ROUND_UP(div-1, 4);
+
+       if (val > 0x3f) {
+               pr_err("need pvtm_div out of bounary! set max instead\n");
+               val = 0x3f;
+       }
+
+       pr_debug("will set div %d, val %d, rate %luKHZ\n", div, val, rate);
+       ret = regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
+                          wr_msk_bit(val, 2, 0x3f));
+       if (ret != 0)
+               goto out;
+
+       /* pvtm oscilator enable */
+       ret = regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
+                          wr_msk_bit(1, 1, 0x1));
+out:
+       if (ret != 0)
+               pr_err("%s: fail to write register\n", __func__);
+
+       return ret;
+}
+
 static int __init pvtm_init(void)
 {
        struct device_node *np;
+       int ret;
+       u32 clk_out;
 
        np = of_find_node_by_name(NULL, "pvtm");
        if (!IS_ERR_OR_NULL(np)) {
@@ -212,11 +288,29 @@ static int __init pvtm_init(void)
                        pr_err("pvtm: dts couldn't find grf regmap\n");
                        return PTR_ERR(grf_regmap);
                }
+               pmugrf_regmap = syscon_regmap_lookup_by_phandle(np,
+                                                               "rockchip,pmugrf");
+               if (IS_ERR(pmugrf_regmap)) {
+                       pr_err("pvtm: dts couldn't find pmugrf regmap\n");
+                       return PTR_ERR(pmugrf_regmap);
+               }
+
                if (of_device_is_compatible(np, "rockchip,rk3368-pvtm")) {
                        ch_clk[0] = clk_get(NULL, "clk_pvtm_core");
                        ch_clk[1] = clk_get(NULL, "clk_pvtm_gpu");
+                       ch_clk[2] = clk_get(NULL, "clk_pvtm_pmu");
                        pvtm.get_value = rk3368_pvtm_get_value;
+                       ret = of_property_read_u32(np, "rockchip,pvtm-clk-out",
+                                                  &clk_out);
+                       if (!ret && clk_out) {
+                               ret = rk3368_pmupvtm_clk_init();
+                               if (ret != 0) {
+                                       pr_err("rk3368_pmupvtm_clk_init failed\n");
+                                       return ret;
+                               }
+                       }
                }
+
                return 0;
        }
 
index 40103bbf8c58071de99ca01c23a36875ae4be5a7..0e8fc0a7b615e2f1506e5f71bac5c54ef256b71e 100644 (file)
                                #clock-cells = <0>;
                        };
 
+                       pvtm_clkout: pvtm_clkout {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clock-output-names = "pvtm_clkout";
+                               clock-frequency = <32000>;
+                               #clock-cells = <0>;
+                       };
+
                        dummy: dummy {
                                compatible = "rockchip,rk-fixed-clock";
                                clock-output-names = "dummy";
                                compatible = "rockchip,rk3188-mux-con";
                                reg = <0x0 0xff738100 0x0 0x4>;
                                rockchip,bits = <6 1>;
-                               clocks = <&xin32k>, <&clk_gates7 3>;
+                               clocks = <&xin32k>, <&pvtm_clkout>;
                                clock-output-names = "clk_32k_mux";
                                #clock-cells = <0>;
                                #clock-init-cells = <1>;
index c36f9c16461efb4f923667507dec749ce803b07b..080b88737bd2cdbf8c046795f3b8b6e93b0625fa 100755 (executable)
                        <&i2s_pll &clk_gpll>, <&spdif_8ch_pll &clk_gpll>,
                        <&i2s_2ch_pll &clk_gpll>, <&usbphy_480m &usbotg_480m_out>,
                        <&clk_uart_pll &clk_gpll>, <&aclk_gpu &clk_cpll>,
-                       <&clk_cs &clk_gpll>;
+                       <&clk_cs &clk_gpll>, <&clk_32k_mux &xin32k>;
                rockchip,clocks-init-rate =
                        <&clk_gpll 576000000>,          <&clk_core_b 792000000>,
                        <&clk_core_l 600000000>,        <&clk_cpll 400000000>,
        pvtm {
                compatible = "rockchip,rk3368-pvtm";
                rockchip,grf = <&grf>;
+               rockchip,pmugrf = <&pmugrf>;
+               rockchip,pvtm-clk-out = <0>;
        };
 
        cpufreq {