aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/rockchip/Makefile1
-rw-r--r--drivers/clk/rockchip/clk-mmc-phase.c154
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c12
-rw-r--r--drivers/clk/rockchip/clk.c8
-rw-r--r--drivers/clk/rockchip/clk.h23
5 files changed, 198 insertions, 0 deletions
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index bd8514d63634..2714097f90db 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -6,6 +6,7 @@ obj-y += clk-rockchip.o
6obj-y += clk.o 6obj-y += clk.o
7obj-y += clk-pll.o 7obj-y += clk-pll.o
8obj-y += clk-cpu.o 8obj-y += clk-cpu.o
9obj-y += clk-mmc-phase.o
9obj-$(CONFIG_RESET_CONTROLLER) += softrst.o 10obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
10 11
11obj-y += clk-rk3188.o 12obj-y += clk-rk3188.o
diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
new file mode 100644
index 000000000000..c842e3b60f21
--- /dev/null
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -0,0 +1,154 @@
1/*
2 * Copyright 2014 Google, Inc
3 * Author: Alexandru M Stan <amstan@chromium.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/slab.h>
17#include <linux/clk-provider.h>
18#include "clk.h"
19
20struct rockchip_mmc_clock {
21 struct clk_hw hw;
22 void __iomem *reg;
23 int id;
24 int shift;
25};
26
27#define to_mmc_clock(_hw) container_of(_hw, struct rockchip_mmc_clock, hw)
28
29#define RK3288_MMC_CLKGEN_DIV 2
30
31static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
32 unsigned long parent_rate)
33{
34 return parent_rate / RK3288_MMC_CLKGEN_DIV;
35}
36
37#define ROCKCHIP_MMC_DELAY_SEL BIT(10)
38#define ROCKCHIP_MMC_DEGREE_MASK 0x3
39#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
40#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
41
42#define PSECS_PER_SEC 1000000000000LL
43
44/*
45 * Each fine delay is between 40ps-80ps. Assume each fine delay is 60ps to
46 * simplify calculations. So 45degs could be anywhere between 33deg and 66deg.
47 */
48#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
49
50static int rockchip_mmc_get_phase(struct clk_hw *hw)
51{
52 struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
53 unsigned long rate = clk_get_rate(hw->clk);
54 u32 raw_value;
55 u16 degrees;
56 u32 delay_num = 0;
57
58 raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
59
60 degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
61
62 if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
63 /* degrees/delaynum * 10000 */
64 unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
65 36 * (rate / 1000000);
66
67 delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
68 delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
69 degrees += delay_num * factor / 10000;
70 }
71
72 return degrees % 360;
73}
74
75static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
76{
77 struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
78 unsigned long rate = clk_get_rate(hw->clk);
79 u8 nineties, remainder;
80 u8 delay_num;
81 u32 raw_value;
82 u64 delay;
83
84 /* allow 22 to be 22.5 */
85 degrees++;
86 /* floor to 22.5 increment */
87 degrees -= ((degrees) * 10 % 225) / 10;
88
89 nineties = degrees / 90;
90 /* 22.5 multiples */
91 remainder = (degrees % 90) / 22;
92
93 delay = PSECS_PER_SEC;
94 do_div(delay, rate);
95 /* / 360 / 22.5 */
96 do_div(delay, 16);
97 do_div(delay, ROCKCHIP_MMC_DELAY_ELEMENT_PSEC);
98
99 delay *= remainder;
100 delay_num = (u8) min(delay, 255ULL);
101
102 raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
103 raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
104 raw_value |= nineties;
105 writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), mmc_clock->reg);
106
107 pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n",
108 __clk_get_name(hw->clk), degrees, delay_num,
109 mmc_clock->reg, raw_value>>(mmc_clock->shift),
110 rockchip_mmc_get_phase(hw)
111 );
112
113 return 0;
114}
115
116static const struct clk_ops rockchip_mmc_clk_ops = {
117 .recalc_rate = rockchip_mmc_recalc,
118 .get_phase = rockchip_mmc_get_phase,
119 .set_phase = rockchip_mmc_set_phase,
120};
121
122struct clk *rockchip_clk_register_mmc(const char *name,
123 const char **parent_names, u8 num_parents,
124 void __iomem *reg, int shift)
125{
126 struct clk_init_data init;
127 struct rockchip_mmc_clock *mmc_clock;
128 struct clk *clk;
129
130 mmc_clock = kmalloc(sizeof(*mmc_clock), GFP_KERNEL);
131 if (!mmc_clock)
132 return NULL;
133
134 init.num_parents = num_parents;
135 init.parent_names = parent_names;
136 init.ops = &rockchip_mmc_clk_ops;
137
138 mmc_clock->hw.init = &init;
139 mmc_clock->reg = reg;
140 mmc_clock->shift = shift;
141
142 if (name)
143 init.name = name;
144
145 clk = clk_register(NULL, &mmc_clock->hw);
146 if (IS_ERR(clk))
147 goto err_free;
148
149 return clk;
150
151err_free:
152 kfree(mmc_clock);
153 return NULL;
154}
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index a43045b05d98..ac6be7c0132d 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -486,6 +486,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
486 RK3288_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 6, DFLAGS, 486 RK3288_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 6, DFLAGS,
487 RK3288_CLKGATE_CON(13), 3, GFLAGS), 487 RK3288_CLKGATE_CON(13), 3, GFLAGS),
488 488
489 MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3288_SDMMC_CON0, 1),
490 MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3288_SDMMC_CON1, 0),
491
492 MMC(SCLK_SDIO0_DRV, "sdio0_drv", "sclk_sdio0", RK3288_SDIO0_CON0, 1),
493 MMC(SCLK_SDIO0_SAMPLE, "sdio0_sample", "sclk_sdio0", RK3288_SDIO0_CON1, 0),
494
495 MMC(SCLK_SDIO1_DRV, "sdio1_drv", "sclk_sdio1", RK3288_SDIO1_CON0, 1),
496 MMC(SCLK_SDIO1_SAMPLE, "sdio1_sample", "sclk_sdio1", RK3288_SDIO1_CON1, 0),
497
498 MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3288_EMMC_CON0, 1),
499 MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3288_EMMC_CON1, 0),
500
489 COMPOSITE(0, "sclk_tspout", mux_tspout_p, 0, 501 COMPOSITE(0, "sclk_tspout", mux_tspout_p, 0,
490 RK3288_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS, 502 RK3288_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS,
491 RK3288_CLKGATE_CON(4), 11, GFLAGS), 503 RK3288_CLKGATE_CON(4), 11, GFLAGS),
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index 3b8f26e2cd1a..f6150da97e8b 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -271,6 +271,14 @@ void __init rockchip_clk_register_branches(
271 list->gate_offset, list->gate_shift, 271 list->gate_offset, list->gate_shift,
272 list->gate_flags, flags, &clk_lock); 272 list->gate_flags, flags, &clk_lock);
273 break; 273 break;
274 case branch_mmc:
275 clk = rockchip_clk_register_mmc(
276 list->name,
277 list->parent_names, list->num_parents,
278 reg_base + list->muxdiv_offset,
279 list->div_shift
280 );
281 break;
274 } 282 }
275 283
276 /* none of the cases above matched */ 284 /* none of the cases above matched */
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index dc9468132ef1..58d2e3bdf22f 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -48,6 +48,14 @@
48#define RK3288_GLB_SRST_SND 0x1b4 48#define RK3288_GLB_SRST_SND 0x1b4
49#define RK3288_SOFTRST_CON(x) (x * 0x4 + 0x1b8) 49#define RK3288_SOFTRST_CON(x) (x * 0x4 + 0x1b8)
50#define RK3288_MISC_CON 0x1e8 50#define RK3288_MISC_CON 0x1e8
51#define RK3288_SDMMC_CON0 0x200
52#define RK3288_SDMMC_CON1 0x204
53#define RK3288_SDIO0_CON0 0x208
54#define RK3288_SDIO0_CON1 0x20c
55#define RK3288_SDIO1_CON0 0x210
56#define RK3288_SDIO1_CON1 0x214
57#define RK3288_EMMC_CON0 0x218
58#define RK3288_EMMC_CON1 0x21c
51 59
52enum rockchip_pll_type { 60enum rockchip_pll_type {
53 pll_rk3066, 61 pll_rk3066,
@@ -170,6 +178,10 @@ struct clk *rockchip_clk_register_cpuclk(const char *name,
170 const struct rockchip_cpuclk_rate_table *rates, 178 const struct rockchip_cpuclk_rate_table *rates,
171 int nrates, void __iomem *reg_base, spinlock_t *lock); 179 int nrates, void __iomem *reg_base, spinlock_t *lock);
172 180
181struct clk *rockchip_clk_register_mmc(const char *name,
182 const char **parent_names, u8 num_parents,
183 void __iomem *reg, int shift);
184
173#define PNAME(x) static const char *x[] __initconst 185#define PNAME(x) static const char *x[] __initconst
174 186
175enum rockchip_clk_branch_type { 187enum rockchip_clk_branch_type {
@@ -178,6 +190,7 @@ enum rockchip_clk_branch_type {
178 branch_divider, 190 branch_divider,
179 branch_fraction_divider, 191 branch_fraction_divider,
180 branch_gate, 192 branch_gate,
193 branch_mmc,
181}; 194};
182 195
183struct rockchip_clk_branch { 196struct rockchip_clk_branch {
@@ -370,6 +383,16 @@ struct rockchip_clk_branch {
370 .gate_flags = gf, \ 383 .gate_flags = gf, \
371 } 384 }
372 385
386#define MMC(_id, cname, pname, offset, shift) \
387 { \
388 .id = _id, \
389 .branch_type = branch_mmc, \
390 .name = cname, \
391 .parent_names = (const char *[]){ pname }, \
392 .num_parents = 1, \
393 .muxdiv_offset = offset, \
394 .div_shift = shift, \
395 }
373 396
374void rockchip_clk_init(struct device_node *np, void __iomem *base, 397void rockchip_clk_init(struct device_node *np, void __iomem *base,
375 unsigned long nr_clks); 398 unsigned long nr_clks);