diff options
Diffstat (limited to 'drivers')
44 files changed, 5605 insertions, 283 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 7f0b5ca78516..bace9e98f75d 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -40,4 +40,17 @@ config COMMON_CLK_WM831X | |||
40 | Supports the clocking subsystem of the WM831x/2x series of | 40 | Supports the clocking subsystem of the WM831x/2x series of |
41 | PMICs from Wolfson Microlectronics. | 41 | PMICs from Wolfson Microlectronics. |
42 | 42 | ||
43 | config COMMON_CLK_VERSATILE | ||
44 | bool "Clock driver for ARM Reference designs" | ||
45 | depends on ARCH_INTEGRATOR || ARCH_REALVIEW | ||
46 | ---help--- | ||
47 | Supports clocking on ARM Reference designs Integrator/AP, | ||
48 | Integrator/CP, RealView PB1176, EB, PB11MP and PBX. | ||
49 | |||
50 | config COMMON_CLK_MAX77686 | ||
51 | tristate "Clock driver for Maxim 77686 MFD" | ||
52 | depends on MFD_MAX77686 | ||
53 | ---help--- | ||
54 | This driver supports Maxim 77686 crystal oscillator clock. | ||
55 | |||
43 | endmenu | 56 | endmenu |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5869ea387054..e48e0da5a884 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -9,7 +9,15 @@ obj-$(CONFIG_ARCH_MXS) += mxs/ | |||
9 | obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ | 9 | obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ |
10 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | 10 | obj-$(CONFIG_PLAT_SPEAR) += spear/ |
11 | obj-$(CONFIG_ARCH_U300) += clk-u300.o | 11 | obj-$(CONFIG_ARCH_U300) += clk-u300.o |
12 | obj-$(CONFIG_ARCH_INTEGRATOR) += versatile/ | 12 | obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ |
13 | obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o | ||
14 | ifeq ($(CONFIG_COMMON_CLK), y) | ||
15 | obj-$(CONFIG_ARCH_MMP) += mmp/ | ||
16 | endif | ||
17 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o | ||
18 | obj-$(CONFIG_ARCH_U8500) += ux500/ | ||
19 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o | ||
13 | 20 | ||
14 | # Chip specific | 21 | # Chip specific |
15 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o | 22 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o |
23 | obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o | ||
diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c new file mode 100644 index 000000000000..f20b750235f6 --- /dev/null +++ b/drivers/clk/clk-ls1x.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/clkdev.h> | ||
11 | #include <linux/clk-provider.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/err.h> | ||
15 | |||
16 | #include <loongson1.h> | ||
17 | |||
18 | #define OSC 33 | ||
19 | |||
20 | static DEFINE_SPINLOCK(_lock); | ||
21 | |||
22 | static int ls1x_pll_clk_enable(struct clk_hw *hw) | ||
23 | { | ||
24 | return 0; | ||
25 | } | ||
26 | |||
27 | static void ls1x_pll_clk_disable(struct clk_hw *hw) | ||
28 | { | ||
29 | } | ||
30 | |||
31 | static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, | ||
32 | unsigned long parent_rate) | ||
33 | { | ||
34 | u32 pll, rate; | ||
35 | |||
36 | pll = __raw_readl(LS1X_CLK_PLL_FREQ); | ||
37 | rate = ((12 + (pll & 0x3f)) * 1000000) + | ||
38 | ((((pll >> 8) & 0x3ff) * 1000000) >> 10); | ||
39 | rate *= OSC; | ||
40 | rate >>= 1; | ||
41 | |||
42 | return rate; | ||
43 | } | ||
44 | |||
45 | static const struct clk_ops ls1x_pll_clk_ops = { | ||
46 | .enable = ls1x_pll_clk_enable, | ||
47 | .disable = ls1x_pll_clk_disable, | ||
48 | .recalc_rate = ls1x_pll_recalc_rate, | ||
49 | }; | ||
50 | |||
51 | static struct clk * __init clk_register_pll(struct device *dev, | ||
52 | const char *name, const char *parent_name, unsigned long flags) | ||
53 | { | ||
54 | struct clk_hw *hw; | ||
55 | struct clk *clk; | ||
56 | struct clk_init_data init; | ||
57 | |||
58 | /* allocate the divider */ | ||
59 | hw = kzalloc(sizeof(struct clk_hw), GFP_KERNEL); | ||
60 | if (!hw) { | ||
61 | pr_err("%s: could not allocate clk_hw\n", __func__); | ||
62 | return ERR_PTR(-ENOMEM); | ||
63 | } | ||
64 | |||
65 | init.name = name; | ||
66 | init.ops = &ls1x_pll_clk_ops; | ||
67 | init.flags = flags | CLK_IS_BASIC; | ||
68 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
69 | init.num_parents = (parent_name ? 1 : 0); | ||
70 | hw->init = &init; | ||
71 | |||
72 | /* register the clock */ | ||
73 | clk = clk_register(dev, hw); | ||
74 | |||
75 | if (IS_ERR(clk)) | ||
76 | kfree(hw); | ||
77 | |||
78 | return clk; | ||
79 | } | ||
80 | |||
81 | void __init ls1x_clk_init(void) | ||
82 | { | ||
83 | struct clk *clk; | ||
84 | |||
85 | clk = clk_register_pll(NULL, "pll_clk", NULL, CLK_IS_ROOT); | ||
86 | clk_prepare_enable(clk); | ||
87 | |||
88 | clk = clk_register_divider(NULL, "cpu_clk", "pll_clk", | ||
89 | CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT, | ||
90 | DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | ||
91 | clk_prepare_enable(clk); | ||
92 | clk_register_clkdev(clk, "cpu", NULL); | ||
93 | |||
94 | clk = clk_register_divider(NULL, "dc_clk", "pll_clk", | ||
95 | CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, | ||
96 | DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | ||
97 | clk_prepare_enable(clk); | ||
98 | clk_register_clkdev(clk, "dc", NULL); | ||
99 | |||
100 | clk = clk_register_divider(NULL, "ahb_clk", "pll_clk", | ||
101 | CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, | ||
102 | DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | ||
103 | clk_prepare_enable(clk); | ||
104 | clk_register_clkdev(clk, "ahb", NULL); | ||
105 | clk_register_clkdev(clk, "stmmaceth", NULL); | ||
106 | |||
107 | clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 2); | ||
108 | clk_prepare_enable(clk); | ||
109 | clk_register_clkdev(clk, "apb", NULL); | ||
110 | clk_register_clkdev(clk, "serial8250", NULL); | ||
111 | } | ||
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c new file mode 100644 index 000000000000..ac5f5434cb9a --- /dev/null +++ b/drivers/clk/clk-max77686.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * clk-max77686.c - Clock driver for Maxim 77686 | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electornics | ||
5 | * Jonghwa Lee <jonghwa3.lee@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/mfd/max77686.h> | ||
28 | #include <linux/mfd/max77686-private.h> | ||
29 | #include <linux/clk-provider.h> | ||
30 | #include <linux/mutex.h> | ||
31 | #include <linux/clkdev.h> | ||
32 | |||
33 | enum { | ||
34 | MAX77686_CLK_AP = 0, | ||
35 | MAX77686_CLK_CP, | ||
36 | MAX77686_CLK_PMIC, | ||
37 | MAX77686_CLKS_NUM, | ||
38 | }; | ||
39 | |||
40 | struct max77686_clk { | ||
41 | struct max77686_dev *iodev; | ||
42 | u32 mask; | ||
43 | struct clk_hw hw; | ||
44 | struct clk_lookup *lookup; | ||
45 | }; | ||
46 | |||
47 | static struct max77686_clk *get_max77686_clk(struct clk_hw *hw) | ||
48 | { | ||
49 | return container_of(hw, struct max77686_clk, hw); | ||
50 | } | ||
51 | |||
52 | static int max77686_clk_prepare(struct clk_hw *hw) | ||
53 | { | ||
54 | struct max77686_clk *max77686; | ||
55 | int ret; | ||
56 | |||
57 | max77686 = get_max77686_clk(hw); | ||
58 | if (!max77686) | ||
59 | return -ENOMEM; | ||
60 | |||
61 | ret = regmap_update_bits(max77686->iodev->regmap, | ||
62 | MAX77686_REG_32KHZ, max77686->mask, max77686->mask); | ||
63 | |||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | static void max77686_clk_unprepare(struct clk_hw *hw) | ||
68 | { | ||
69 | struct max77686_clk *max77686; | ||
70 | |||
71 | max77686 = get_max77686_clk(hw); | ||
72 | if (!max77686) | ||
73 | return; | ||
74 | |||
75 | regmap_update_bits(max77686->iodev->regmap, | ||
76 | MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask); | ||
77 | } | ||
78 | |||
79 | static int max77686_clk_is_enabled(struct clk_hw *hw) | ||
80 | { | ||
81 | struct max77686_clk *max77686; | ||
82 | int ret; | ||
83 | u32 val; | ||
84 | |||
85 | max77686 = get_max77686_clk(hw); | ||
86 | if (!max77686) | ||
87 | return -ENOMEM; | ||
88 | |||
89 | ret = regmap_read(max77686->iodev->regmap, | ||
90 | MAX77686_REG_32KHZ, &val); | ||
91 | |||
92 | if (ret < 0) | ||
93 | return -EINVAL; | ||
94 | |||
95 | return val & max77686->mask; | ||
96 | } | ||
97 | |||
98 | static struct clk_ops max77686_clk_ops = { | ||
99 | .prepare = max77686_clk_prepare, | ||
100 | .unprepare = max77686_clk_unprepare, | ||
101 | .is_enabled = max77686_clk_is_enabled, | ||
102 | }; | ||
103 | |||
104 | static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { | ||
105 | [MAX77686_CLK_AP] = { | ||
106 | .name = "32khz_ap", | ||
107 | .ops = &max77686_clk_ops, | ||
108 | .flags = CLK_IS_ROOT, | ||
109 | }, | ||
110 | [MAX77686_CLK_CP] = { | ||
111 | .name = "32khz_cp", | ||
112 | .ops = &max77686_clk_ops, | ||
113 | .flags = CLK_IS_ROOT, | ||
114 | }, | ||
115 | [MAX77686_CLK_PMIC] = { | ||
116 | .name = "32khz_pmic", | ||
117 | .ops = &max77686_clk_ops, | ||
118 | .flags = CLK_IS_ROOT, | ||
119 | }, | ||
120 | }; | ||
121 | |||
122 | static int max77686_clk_register(struct device *dev, | ||
123 | struct max77686_clk *max77686) | ||
124 | { | ||
125 | struct clk *clk; | ||
126 | struct clk_hw *hw = &max77686->hw; | ||
127 | |||
128 | clk = clk_register(dev, hw); | ||
129 | |||
130 | if (IS_ERR(clk)) | ||
131 | return -ENOMEM; | ||
132 | |||
133 | max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup), | ||
134 | GFP_KERNEL); | ||
135 | if (IS_ERR(max77686->lookup)) | ||
136 | return -ENOMEM; | ||
137 | |||
138 | max77686->lookup->con_id = hw->init->name; | ||
139 | max77686->lookup->clk = clk; | ||
140 | |||
141 | clkdev_add(max77686->lookup); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static __devinit int max77686_clk_probe(struct platform_device *pdev) | ||
147 | { | ||
148 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | ||
149 | struct max77686_clk **max77686_clks; | ||
150 | int i, ret; | ||
151 | |||
152 | max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *) | ||
153 | * MAX77686_CLKS_NUM, GFP_KERNEL); | ||
154 | if (IS_ERR(max77686_clks)) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
158 | max77686_clks[i] = devm_kzalloc(&pdev->dev, | ||
159 | sizeof(struct max77686_clk), GFP_KERNEL); | ||
160 | if (IS_ERR(max77686_clks[i])) | ||
161 | return -ENOMEM; | ||
162 | } | ||
163 | |||
164 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
165 | max77686_clks[i]->iodev = iodev; | ||
166 | max77686_clks[i]->mask = 1 << i; | ||
167 | max77686_clks[i]->hw.init = &max77686_clks_init[i]; | ||
168 | |||
169 | ret = max77686_clk_register(&pdev->dev, max77686_clks[i]); | ||
170 | if (ret) { | ||
171 | switch (i) { | ||
172 | case MAX77686_CLK_AP: | ||
173 | dev_err(&pdev->dev, "Fail to register CLK_AP\n"); | ||
174 | goto err_clk_ap; | ||
175 | break; | ||
176 | case MAX77686_CLK_CP: | ||
177 | dev_err(&pdev->dev, "Fail to register CLK_CP\n"); | ||
178 | goto err_clk_cp; | ||
179 | break; | ||
180 | case MAX77686_CLK_PMIC: | ||
181 | dev_err(&pdev->dev, "Fail to register CLK_PMIC\n"); | ||
182 | goto err_clk_pmic; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | |||
187 | platform_set_drvdata(pdev, max77686_clks); | ||
188 | |||
189 | goto out; | ||
190 | |||
191 | err_clk_pmic: | ||
192 | clkdev_drop(max77686_clks[MAX77686_CLK_CP]->lookup); | ||
193 | kfree(max77686_clks[MAX77686_CLK_CP]->hw.clk); | ||
194 | err_clk_cp: | ||
195 | clkdev_drop(max77686_clks[MAX77686_CLK_AP]->lookup); | ||
196 | kfree(max77686_clks[MAX77686_CLK_AP]->hw.clk); | ||
197 | err_clk_ap: | ||
198 | out: | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int __devexit max77686_clk_remove(struct platform_device *pdev) | ||
203 | { | ||
204 | struct max77686_clk **max77686_clks = platform_get_drvdata(pdev); | ||
205 | int i; | ||
206 | |||
207 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
208 | clkdev_drop(max77686_clks[i]->lookup); | ||
209 | kfree(max77686_clks[i]->hw.clk); | ||
210 | } | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static const struct platform_device_id max77686_clk_id[] = { | ||
215 | { "max77686-clk", 0}, | ||
216 | { }, | ||
217 | }; | ||
218 | MODULE_DEVICE_TABLE(platform, max77686_clk_id); | ||
219 | |||
220 | static struct platform_driver max77686_clk_driver = { | ||
221 | .driver = { | ||
222 | .name = "max77686-clk", | ||
223 | .owner = THIS_MODULE, | ||
224 | }, | ||
225 | .probe = max77686_clk_probe, | ||
226 | .remove = __devexit_p(max77686_clk_remove), | ||
227 | .id_table = max77686_clk_id, | ||
228 | }; | ||
229 | |||
230 | static int __init max77686_clk_init(void) | ||
231 | { | ||
232 | return platform_driver_register(&max77686_clk_driver); | ||
233 | } | ||
234 | subsys_initcall(max77686_clk_init); | ||
235 | |||
236 | static void __init max77686_clk_cleanup(void) | ||
237 | { | ||
238 | platform_driver_unregister(&max77686_clk_driver); | ||
239 | } | ||
240 | module_exit(max77686_clk_cleanup); | ||
241 | |||
242 | MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); | ||
243 | MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); | ||
244 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c new file mode 100644 index 000000000000..517874fa6858 --- /dev/null +++ b/drivers/clk/clk-prima2.c | |||
@@ -0,0 +1,1171 @@ | |||
1 | /* | ||
2 | * Clock tree for CSR SiRFprimaII | ||
3 | * | ||
4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
5 | * | ||
6 | * Licensed under GPLv2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/bitops.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/of_address.h> | ||
16 | #include <linux/syscore_ops.h> | ||
17 | |||
18 | #define SIRFSOC_CLKC_CLK_EN0 0x0000 | ||
19 | #define SIRFSOC_CLKC_CLK_EN1 0x0004 | ||
20 | #define SIRFSOC_CLKC_REF_CFG 0x0014 | ||
21 | #define SIRFSOC_CLKC_CPU_CFG 0x0018 | ||
22 | #define SIRFSOC_CLKC_MEM_CFG 0x001c | ||
23 | #define SIRFSOC_CLKC_SYS_CFG 0x0020 | ||
24 | #define SIRFSOC_CLKC_IO_CFG 0x0024 | ||
25 | #define SIRFSOC_CLKC_DSP_CFG 0x0028 | ||
26 | #define SIRFSOC_CLKC_GFX_CFG 0x002c | ||
27 | #define SIRFSOC_CLKC_MM_CFG 0x0030 | ||
28 | #define SIRFSOC_CLKC_LCD_CFG 0x0034 | ||
29 | #define SIRFSOC_CLKC_MMC_CFG 0x0038 | ||
30 | #define SIRFSOC_CLKC_PLL1_CFG0 0x0040 | ||
31 | #define SIRFSOC_CLKC_PLL2_CFG0 0x0044 | ||
32 | #define SIRFSOC_CLKC_PLL3_CFG0 0x0048 | ||
33 | #define SIRFSOC_CLKC_PLL1_CFG1 0x004c | ||
34 | #define SIRFSOC_CLKC_PLL2_CFG1 0x0050 | ||
35 | #define SIRFSOC_CLKC_PLL3_CFG1 0x0054 | ||
36 | #define SIRFSOC_CLKC_PLL1_CFG2 0x0058 | ||
37 | #define SIRFSOC_CLKC_PLL2_CFG2 0x005c | ||
38 | #define SIRFSOC_CLKC_PLL3_CFG2 0x0060 | ||
39 | #define SIRFSOC_USBPHY_PLL_CTRL 0x0008 | ||
40 | #define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1) | ||
41 | #define SIRFSOC_USBPHY_PLL_BYPASS BIT(2) | ||
42 | #define SIRFSOC_USBPHY_PLL_LOCK BIT(3) | ||
43 | |||
44 | static void *sirfsoc_clk_vbase, *sirfsoc_rsc_vbase; | ||
45 | |||
46 | #define KHZ 1000 | ||
47 | #define MHZ (KHZ * KHZ) | ||
48 | |||
49 | /* | ||
50 | * SiRFprimaII clock controller | ||
51 | * - 2 oscillators: osc-26MHz, rtc-32.768KHz | ||
52 | * - 3 standard configurable plls: pll1, pll2 & pll3 | ||
53 | * - 2 exclusive plls: usb phy pll and sata phy pll | ||
54 | * - 8 clock domains: cpu/cpudiv, mem/memdiv, sys/io, dsp, graphic, multimedia, | ||
55 | * display and sdphy. | ||
56 | * Each clock domain can select its own clock source from five clock sources, | ||
57 | * X_XIN, X_XINW, PLL1, PLL2 and PLL3. The domain clock is used as the source | ||
58 | * clock of the group clock. | ||
59 | * - dsp domain: gps, mf | ||
60 | * - io domain: dmac, nand, audio, uart, i2c, spi, usp, pwm, pulse | ||
61 | * - sys domain: security | ||
62 | */ | ||
63 | |||
64 | struct clk_pll { | ||
65 | struct clk_hw hw; | ||
66 | unsigned short regofs; /* register offset */ | ||
67 | }; | ||
68 | |||
69 | #define to_pllclk(_hw) container_of(_hw, struct clk_pll, hw) | ||
70 | |||
71 | struct clk_dmn { | ||
72 | struct clk_hw hw; | ||
73 | signed char enable_bit; /* enable bit: 0 ~ 63 */ | ||
74 | unsigned short regofs; /* register offset */ | ||
75 | }; | ||
76 | |||
77 | #define to_dmnclk(_hw) container_of(_hw, struct clk_dmn, hw) | ||
78 | |||
79 | struct clk_std { | ||
80 | struct clk_hw hw; | ||
81 | signed char enable_bit; /* enable bit: 0 ~ 63 */ | ||
82 | }; | ||
83 | |||
84 | #define to_stdclk(_hw) container_of(_hw, struct clk_std, hw) | ||
85 | |||
86 | static int std_clk_is_enabled(struct clk_hw *hw); | ||
87 | static int std_clk_enable(struct clk_hw *hw); | ||
88 | static void std_clk_disable(struct clk_hw *hw); | ||
89 | |||
90 | static inline unsigned long clkc_readl(unsigned reg) | ||
91 | { | ||
92 | return readl(sirfsoc_clk_vbase + reg); | ||
93 | } | ||
94 | |||
95 | static inline void clkc_writel(u32 val, unsigned reg) | ||
96 | { | ||
97 | writel(val, sirfsoc_clk_vbase + reg); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * std pll | ||
102 | */ | ||
103 | |||
104 | static unsigned long pll_clk_recalc_rate(struct clk_hw *hw, | ||
105 | unsigned long parent_rate) | ||
106 | { | ||
107 | unsigned long fin = parent_rate; | ||
108 | struct clk_pll *clk = to_pllclk(hw); | ||
109 | u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - | ||
110 | SIRFSOC_CLKC_PLL1_CFG0; | ||
111 | |||
112 | if (clkc_readl(regcfg2) & BIT(2)) { | ||
113 | /* pll bypass mode */ | ||
114 | return fin; | ||
115 | } else { | ||
116 | /* fout = fin * nf / nr / od */ | ||
117 | u32 cfg0 = clkc_readl(clk->regofs); | ||
118 | u32 nf = (cfg0 & (BIT(13) - 1)) + 1; | ||
119 | u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1; | ||
120 | u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1; | ||
121 | WARN_ON(fin % MHZ); | ||
122 | return fin / MHZ * nf / nr / od * MHZ; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static long pll_clk_round_rate(struct clk_hw *hw, unsigned long rate, | ||
127 | unsigned long *parent_rate) | ||
128 | { | ||
129 | unsigned long fin, nf, nr, od; | ||
130 | |||
131 | /* | ||
132 | * fout = fin * nf / (nr * od); | ||
133 | * set od = 1, nr = fin/MHz, so fout = nf * MHz | ||
134 | */ | ||
135 | rate = rate - rate % MHZ; | ||
136 | |||
137 | nf = rate / MHZ; | ||
138 | if (nf > BIT(13)) | ||
139 | nf = BIT(13); | ||
140 | if (nf < 1) | ||
141 | nf = 1; | ||
142 | |||
143 | fin = *parent_rate; | ||
144 | |||
145 | nr = fin / MHZ; | ||
146 | if (nr > BIT(6)) | ||
147 | nr = BIT(6); | ||
148 | od = 1; | ||
149 | |||
150 | return fin * nf / (nr * od); | ||
151 | } | ||
152 | |||
153 | static int pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, | ||
154 | unsigned long parent_rate) | ||
155 | { | ||
156 | struct clk_pll *clk = to_pllclk(hw); | ||
157 | unsigned long fin, nf, nr, od, reg; | ||
158 | |||
159 | /* | ||
160 | * fout = fin * nf / (nr * od); | ||
161 | * set od = 1, nr = fin/MHz, so fout = nf * MHz | ||
162 | */ | ||
163 | |||
164 | nf = rate / MHZ; | ||
165 | if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1)) | ||
166 | return -EINVAL; | ||
167 | |||
168 | fin = parent_rate; | ||
169 | BUG_ON(fin < MHZ); | ||
170 | |||
171 | nr = fin / MHZ; | ||
172 | BUG_ON((fin % MHZ) || nr > BIT(6)); | ||
173 | |||
174 | od = 1; | ||
175 | |||
176 | reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19); | ||
177 | clkc_writel(reg, clk->regofs); | ||
178 | |||
179 | reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0; | ||
180 | clkc_writel((nf >> 1) - 1, reg); | ||
181 | |||
182 | reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0; | ||
183 | while (!(clkc_readl(reg) & BIT(6))) | ||
184 | cpu_relax(); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static struct clk_ops std_pll_ops = { | ||
190 | .recalc_rate = pll_clk_recalc_rate, | ||
191 | .round_rate = pll_clk_round_rate, | ||
192 | .set_rate = pll_clk_set_rate, | ||
193 | }; | ||
194 | |||
195 | static const char *pll_clk_parents[] = { | ||
196 | "osc", | ||
197 | }; | ||
198 | |||
199 | static struct clk_init_data clk_pll1_init = { | ||
200 | .name = "pll1", | ||
201 | .ops = &std_pll_ops, | ||
202 | .parent_names = pll_clk_parents, | ||
203 | .num_parents = ARRAY_SIZE(pll_clk_parents), | ||
204 | }; | ||
205 | |||
206 | static struct clk_init_data clk_pll2_init = { | ||
207 | .name = "pll2", | ||
208 | .ops = &std_pll_ops, | ||
209 | .parent_names = pll_clk_parents, | ||
210 | .num_parents = ARRAY_SIZE(pll_clk_parents), | ||
211 | }; | ||
212 | |||
213 | static struct clk_init_data clk_pll3_init = { | ||
214 | .name = "pll3", | ||
215 | .ops = &std_pll_ops, | ||
216 | .parent_names = pll_clk_parents, | ||
217 | .num_parents = ARRAY_SIZE(pll_clk_parents), | ||
218 | }; | ||
219 | |||
220 | static struct clk_pll clk_pll1 = { | ||
221 | .regofs = SIRFSOC_CLKC_PLL1_CFG0, | ||
222 | .hw = { | ||
223 | .init = &clk_pll1_init, | ||
224 | }, | ||
225 | }; | ||
226 | |||
227 | static struct clk_pll clk_pll2 = { | ||
228 | .regofs = SIRFSOC_CLKC_PLL2_CFG0, | ||
229 | .hw = { | ||
230 | .init = &clk_pll2_init, | ||
231 | }, | ||
232 | }; | ||
233 | |||
234 | static struct clk_pll clk_pll3 = { | ||
235 | .regofs = SIRFSOC_CLKC_PLL3_CFG0, | ||
236 | .hw = { | ||
237 | .init = &clk_pll3_init, | ||
238 | }, | ||
239 | }; | ||
240 | |||
241 | /* | ||
242 | * usb uses specified pll | ||
243 | */ | ||
244 | |||
245 | static int usb_pll_clk_enable(struct clk_hw *hw) | ||
246 | { | ||
247 | u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); | ||
248 | reg &= ~(SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS); | ||
249 | writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); | ||
250 | while (!(readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL) & | ||
251 | SIRFSOC_USBPHY_PLL_LOCK)) | ||
252 | cpu_relax(); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static void usb_pll_clk_disable(struct clk_hw *clk) | ||
258 | { | ||
259 | u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); | ||
260 | reg |= (SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS); | ||
261 | writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); | ||
262 | } | ||
263 | |||
264 | static unsigned long usb_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
265 | { | ||
266 | u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); | ||
267 | return (reg & SIRFSOC_USBPHY_PLL_BYPASS) ? parent_rate : 48*MHZ; | ||
268 | } | ||
269 | |||
270 | static struct clk_ops usb_pll_ops = { | ||
271 | .enable = usb_pll_clk_enable, | ||
272 | .disable = usb_pll_clk_disable, | ||
273 | .recalc_rate = usb_pll_clk_recalc_rate, | ||
274 | }; | ||
275 | |||
276 | static struct clk_init_data clk_usb_pll_init = { | ||
277 | .name = "usb_pll", | ||
278 | .ops = &usb_pll_ops, | ||
279 | .parent_names = pll_clk_parents, | ||
280 | .num_parents = ARRAY_SIZE(pll_clk_parents), | ||
281 | }; | ||
282 | |||
283 | static struct clk_hw usb_pll_clk_hw = { | ||
284 | .init = &clk_usb_pll_init, | ||
285 | }; | ||
286 | |||
287 | /* | ||
288 | * clock domains - cpu, mem, sys/io, dsp, gfx | ||
289 | */ | ||
290 | |||
291 | static const char *dmn_clk_parents[] = { | ||
292 | "rtc", | ||
293 | "osc", | ||
294 | "pll1", | ||
295 | "pll2", | ||
296 | "pll3", | ||
297 | }; | ||
298 | |||
299 | static u8 dmn_clk_get_parent(struct clk_hw *hw) | ||
300 | { | ||
301 | struct clk_dmn *clk = to_dmnclk(hw); | ||
302 | u32 cfg = clkc_readl(clk->regofs); | ||
303 | |||
304 | /* parent of io domain can only be pll3 */ | ||
305 | if (strcmp(hw->init->name, "io") == 0) | ||
306 | return 4; | ||
307 | |||
308 | WARN_ON((cfg & (BIT(3) - 1)) > 4); | ||
309 | |||
310 | return cfg & (BIT(3) - 1); | ||
311 | } | ||
312 | |||
313 | static int dmn_clk_set_parent(struct clk_hw *hw, u8 parent) | ||
314 | { | ||
315 | struct clk_dmn *clk = to_dmnclk(hw); | ||
316 | u32 cfg = clkc_readl(clk->regofs); | ||
317 | |||
318 | /* parent of io domain can only be pll3 */ | ||
319 | if (strcmp(hw->init->name, "io") == 0) | ||
320 | return -EINVAL; | ||
321 | |||
322 | cfg &= ~(BIT(3) - 1); | ||
323 | clkc_writel(cfg | parent, clk->regofs); | ||
324 | /* BIT(3) - switching status: 1 - busy, 0 - done */ | ||
325 | while (clkc_readl(clk->regofs) & BIT(3)) | ||
326 | cpu_relax(); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static unsigned long dmn_clk_recalc_rate(struct clk_hw *hw, | ||
332 | unsigned long parent_rate) | ||
333 | |||
334 | { | ||
335 | unsigned long fin = parent_rate; | ||
336 | struct clk_dmn *clk = to_dmnclk(hw); | ||
337 | |||
338 | u32 cfg = clkc_readl(clk->regofs); | ||
339 | |||
340 | if (cfg & BIT(24)) { | ||
341 | /* fcd bypass mode */ | ||
342 | return fin; | ||
343 | } else { | ||
344 | /* | ||
345 | * wait count: bit[19:16], hold count: bit[23:20] | ||
346 | */ | ||
347 | u32 wait = (cfg >> 16) & (BIT(4) - 1); | ||
348 | u32 hold = (cfg >> 20) & (BIT(4) - 1); | ||
349 | |||
350 | return fin / (wait + hold + 2); | ||
351 | } | ||
352 | } | ||
353 | |||
354 | static long dmn_clk_round_rate(struct clk_hw *hw, unsigned long rate, | ||
355 | unsigned long *parent_rate) | ||
356 | { | ||
357 | unsigned long fin; | ||
358 | unsigned ratio, wait, hold; | ||
359 | unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4; | ||
360 | |||
361 | fin = *parent_rate; | ||
362 | ratio = fin / rate; | ||
363 | |||
364 | if (ratio < 2) | ||
365 | ratio = 2; | ||
366 | if (ratio > BIT(bits + 1)) | ||
367 | ratio = BIT(bits + 1); | ||
368 | |||
369 | wait = (ratio >> 1) - 1; | ||
370 | hold = ratio - wait - 2; | ||
371 | |||
372 | return fin / (wait + hold + 2); | ||
373 | } | ||
374 | |||
375 | static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate, | ||
376 | unsigned long parent_rate) | ||
377 | { | ||
378 | struct clk_dmn *clk = to_dmnclk(hw); | ||
379 | unsigned long fin; | ||
380 | unsigned ratio, wait, hold, reg; | ||
381 | unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4; | ||
382 | |||
383 | fin = parent_rate; | ||
384 | ratio = fin / rate; | ||
385 | |||
386 | if (unlikely(ratio < 2 || ratio > BIT(bits + 1))) | ||
387 | return -EINVAL; | ||
388 | |||
389 | WARN_ON(fin % rate); | ||
390 | |||
391 | wait = (ratio >> 1) - 1; | ||
392 | hold = ratio - wait - 2; | ||
393 | |||
394 | reg = clkc_readl(clk->regofs); | ||
395 | reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20)); | ||
396 | reg |= (wait << 16) | (hold << 20) | BIT(25); | ||
397 | clkc_writel(reg, clk->regofs); | ||
398 | |||
399 | /* waiting FCD been effective */ | ||
400 | while (clkc_readl(clk->regofs) & BIT(25)) | ||
401 | cpu_relax(); | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static struct clk_ops msi_ops = { | ||
407 | .set_rate = dmn_clk_set_rate, | ||
408 | .round_rate = dmn_clk_round_rate, | ||
409 | .recalc_rate = dmn_clk_recalc_rate, | ||
410 | .set_parent = dmn_clk_set_parent, | ||
411 | .get_parent = dmn_clk_get_parent, | ||
412 | }; | ||
413 | |||
414 | static struct clk_init_data clk_mem_init = { | ||
415 | .name = "mem", | ||
416 | .ops = &msi_ops, | ||
417 | .parent_names = dmn_clk_parents, | ||
418 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
419 | }; | ||
420 | |||
421 | static struct clk_dmn clk_mem = { | ||
422 | .regofs = SIRFSOC_CLKC_MEM_CFG, | ||
423 | .hw = { | ||
424 | .init = &clk_mem_init, | ||
425 | }, | ||
426 | }; | ||
427 | |||
428 | static struct clk_init_data clk_sys_init = { | ||
429 | .name = "sys", | ||
430 | .ops = &msi_ops, | ||
431 | .parent_names = dmn_clk_parents, | ||
432 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
433 | .flags = CLK_SET_RATE_GATE, | ||
434 | }; | ||
435 | |||
436 | static struct clk_dmn clk_sys = { | ||
437 | .regofs = SIRFSOC_CLKC_SYS_CFG, | ||
438 | .hw = { | ||
439 | .init = &clk_sys_init, | ||
440 | }, | ||
441 | }; | ||
442 | |||
443 | static struct clk_init_data clk_io_init = { | ||
444 | .name = "io", | ||
445 | .ops = &msi_ops, | ||
446 | .parent_names = dmn_clk_parents, | ||
447 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
448 | }; | ||
449 | |||
450 | static struct clk_dmn clk_io = { | ||
451 | .regofs = SIRFSOC_CLKC_IO_CFG, | ||
452 | .hw = { | ||
453 | .init = &clk_io_init, | ||
454 | }, | ||
455 | }; | ||
456 | |||
457 | static struct clk_ops cpu_ops = { | ||
458 | .set_parent = dmn_clk_set_parent, | ||
459 | .get_parent = dmn_clk_get_parent, | ||
460 | }; | ||
461 | |||
462 | static struct clk_init_data clk_cpu_init = { | ||
463 | .name = "cpu", | ||
464 | .ops = &cpu_ops, | ||
465 | .parent_names = dmn_clk_parents, | ||
466 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
467 | .flags = CLK_SET_RATE_PARENT, | ||
468 | }; | ||
469 | |||
470 | static struct clk_dmn clk_cpu = { | ||
471 | .regofs = SIRFSOC_CLKC_CPU_CFG, | ||
472 | .hw = { | ||
473 | .init = &clk_cpu_init, | ||
474 | }, | ||
475 | }; | ||
476 | |||
477 | static struct clk_ops dmn_ops = { | ||
478 | .is_enabled = std_clk_is_enabled, | ||
479 | .enable = std_clk_enable, | ||
480 | .disable = std_clk_disable, | ||
481 | .set_rate = dmn_clk_set_rate, | ||
482 | .round_rate = dmn_clk_round_rate, | ||
483 | .recalc_rate = dmn_clk_recalc_rate, | ||
484 | .set_parent = dmn_clk_set_parent, | ||
485 | .get_parent = dmn_clk_get_parent, | ||
486 | }; | ||
487 | |||
488 | /* dsp, gfx, mm, lcd and vpp domain */ | ||
489 | |||
490 | static struct clk_init_data clk_dsp_init = { | ||
491 | .name = "dsp", | ||
492 | .ops = &dmn_ops, | ||
493 | .parent_names = dmn_clk_parents, | ||
494 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
495 | }; | ||
496 | |||
497 | static struct clk_dmn clk_dsp = { | ||
498 | .regofs = SIRFSOC_CLKC_DSP_CFG, | ||
499 | .enable_bit = 0, | ||
500 | .hw = { | ||
501 | .init = &clk_dsp_init, | ||
502 | }, | ||
503 | }; | ||
504 | |||
505 | static struct clk_init_data clk_gfx_init = { | ||
506 | .name = "gfx", | ||
507 | .ops = &dmn_ops, | ||
508 | .parent_names = dmn_clk_parents, | ||
509 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
510 | }; | ||
511 | |||
512 | static struct clk_dmn clk_gfx = { | ||
513 | .regofs = SIRFSOC_CLKC_GFX_CFG, | ||
514 | .enable_bit = 8, | ||
515 | .hw = { | ||
516 | .init = &clk_gfx_init, | ||
517 | }, | ||
518 | }; | ||
519 | |||
520 | static struct clk_init_data clk_mm_init = { | ||
521 | .name = "mm", | ||
522 | .ops = &dmn_ops, | ||
523 | .parent_names = dmn_clk_parents, | ||
524 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
525 | }; | ||
526 | |||
527 | static struct clk_dmn clk_mm = { | ||
528 | .regofs = SIRFSOC_CLKC_MM_CFG, | ||
529 | .enable_bit = 9, | ||
530 | .hw = { | ||
531 | .init = &clk_mm_init, | ||
532 | }, | ||
533 | }; | ||
534 | |||
535 | static struct clk_init_data clk_lcd_init = { | ||
536 | .name = "lcd", | ||
537 | .ops = &dmn_ops, | ||
538 | .parent_names = dmn_clk_parents, | ||
539 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
540 | }; | ||
541 | |||
542 | static struct clk_dmn clk_lcd = { | ||
543 | .regofs = SIRFSOC_CLKC_LCD_CFG, | ||
544 | .enable_bit = 10, | ||
545 | .hw = { | ||
546 | .init = &clk_lcd_init, | ||
547 | }, | ||
548 | }; | ||
549 | |||
550 | static struct clk_init_data clk_vpp_init = { | ||
551 | .name = "vpp", | ||
552 | .ops = &dmn_ops, | ||
553 | .parent_names = dmn_clk_parents, | ||
554 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
555 | }; | ||
556 | |||
557 | static struct clk_dmn clk_vpp = { | ||
558 | .regofs = SIRFSOC_CLKC_LCD_CFG, | ||
559 | .enable_bit = 11, | ||
560 | .hw = { | ||
561 | .init = &clk_vpp_init, | ||
562 | }, | ||
563 | }; | ||
564 | |||
565 | static struct clk_init_data clk_mmc01_init = { | ||
566 | .name = "mmc01", | ||
567 | .ops = &dmn_ops, | ||
568 | .parent_names = dmn_clk_parents, | ||
569 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
570 | }; | ||
571 | |||
572 | static struct clk_dmn clk_mmc01 = { | ||
573 | .regofs = SIRFSOC_CLKC_MMC_CFG, | ||
574 | .enable_bit = 59, | ||
575 | .hw = { | ||
576 | .init = &clk_mmc01_init, | ||
577 | }, | ||
578 | }; | ||
579 | |||
580 | static struct clk_init_data clk_mmc23_init = { | ||
581 | .name = "mmc23", | ||
582 | .ops = &dmn_ops, | ||
583 | .parent_names = dmn_clk_parents, | ||
584 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
585 | }; | ||
586 | |||
587 | static struct clk_dmn clk_mmc23 = { | ||
588 | .regofs = SIRFSOC_CLKC_MMC_CFG, | ||
589 | .enable_bit = 60, | ||
590 | .hw = { | ||
591 | .init = &clk_mmc23_init, | ||
592 | }, | ||
593 | }; | ||
594 | |||
595 | static struct clk_init_data clk_mmc45_init = { | ||
596 | .name = "mmc45", | ||
597 | .ops = &dmn_ops, | ||
598 | .parent_names = dmn_clk_parents, | ||
599 | .num_parents = ARRAY_SIZE(dmn_clk_parents), | ||
600 | }; | ||
601 | |||
602 | static struct clk_dmn clk_mmc45 = { | ||
603 | .regofs = SIRFSOC_CLKC_MMC_CFG, | ||
604 | .enable_bit = 61, | ||
605 | .hw = { | ||
606 | .init = &clk_mmc45_init, | ||
607 | }, | ||
608 | }; | ||
609 | |||
610 | /* | ||
611 | * peripheral controllers in io domain | ||
612 | */ | ||
613 | |||
614 | static int std_clk_is_enabled(struct clk_hw *hw) | ||
615 | { | ||
616 | u32 reg; | ||
617 | int bit; | ||
618 | struct clk_std *clk = to_stdclk(hw); | ||
619 | |||
620 | bit = clk->enable_bit % 32; | ||
621 | reg = clk->enable_bit / 32; | ||
622 | reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg); | ||
623 | |||
624 | return !!(clkc_readl(reg) & BIT(bit)); | ||
625 | } | ||
626 | |||
627 | static int std_clk_enable(struct clk_hw *hw) | ||
628 | { | ||
629 | u32 val, reg; | ||
630 | int bit; | ||
631 | struct clk_std *clk = to_stdclk(hw); | ||
632 | |||
633 | BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63); | ||
634 | |||
635 | bit = clk->enable_bit % 32; | ||
636 | reg = clk->enable_bit / 32; | ||
637 | reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg); | ||
638 | |||
639 | val = clkc_readl(reg) | BIT(bit); | ||
640 | clkc_writel(val, reg); | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static void std_clk_disable(struct clk_hw *hw) | ||
645 | { | ||
646 | u32 val, reg; | ||
647 | int bit; | ||
648 | struct clk_std *clk = to_stdclk(hw); | ||
649 | |||
650 | BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63); | ||
651 | |||
652 | bit = clk->enable_bit % 32; | ||
653 | reg = clk->enable_bit / 32; | ||
654 | reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg); | ||
655 | |||
656 | val = clkc_readl(reg) & ~BIT(bit); | ||
657 | clkc_writel(val, reg); | ||
658 | } | ||
659 | |||
660 | static const char *std_clk_io_parents[] = { | ||
661 | "io", | ||
662 | }; | ||
663 | |||
664 | static struct clk_ops ios_ops = { | ||
665 | .is_enabled = std_clk_is_enabled, | ||
666 | .enable = std_clk_enable, | ||
667 | .disable = std_clk_disable, | ||
668 | }; | ||
669 | |||
670 | static struct clk_init_data clk_dmac0_init = { | ||
671 | .name = "dmac0", | ||
672 | .ops = &ios_ops, | ||
673 | .parent_names = std_clk_io_parents, | ||
674 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
675 | }; | ||
676 | |||
677 | static struct clk_std clk_dmac0 = { | ||
678 | .enable_bit = 32, | ||
679 | .hw = { | ||
680 | .init = &clk_dmac0_init, | ||
681 | }, | ||
682 | }; | ||
683 | |||
684 | static struct clk_init_data clk_dmac1_init = { | ||
685 | .name = "dmac1", | ||
686 | .ops = &ios_ops, | ||
687 | .parent_names = std_clk_io_parents, | ||
688 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
689 | }; | ||
690 | |||
691 | static struct clk_std clk_dmac1 = { | ||
692 | .enable_bit = 33, | ||
693 | .hw = { | ||
694 | .init = &clk_dmac1_init, | ||
695 | }, | ||
696 | }; | ||
697 | |||
698 | static struct clk_init_data clk_nand_init = { | ||
699 | .name = "nand", | ||
700 | .ops = &ios_ops, | ||
701 | .parent_names = std_clk_io_parents, | ||
702 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
703 | }; | ||
704 | |||
705 | static struct clk_std clk_nand = { | ||
706 | .enable_bit = 34, | ||
707 | .hw = { | ||
708 | .init = &clk_nand_init, | ||
709 | }, | ||
710 | }; | ||
711 | |||
712 | static struct clk_init_data clk_audio_init = { | ||
713 | .name = "audio", | ||
714 | .ops = &ios_ops, | ||
715 | .parent_names = std_clk_io_parents, | ||
716 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
717 | }; | ||
718 | |||
719 | static struct clk_std clk_audio = { | ||
720 | .enable_bit = 35, | ||
721 | .hw = { | ||
722 | .init = &clk_audio_init, | ||
723 | }, | ||
724 | }; | ||
725 | |||
726 | static struct clk_init_data clk_uart0_init = { | ||
727 | .name = "uart0", | ||
728 | .ops = &ios_ops, | ||
729 | .parent_names = std_clk_io_parents, | ||
730 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
731 | }; | ||
732 | |||
733 | static struct clk_std clk_uart0 = { | ||
734 | .enable_bit = 36, | ||
735 | .hw = { | ||
736 | .init = &clk_uart0_init, | ||
737 | }, | ||
738 | }; | ||
739 | |||
740 | static struct clk_init_data clk_uart1_init = { | ||
741 | .name = "uart1", | ||
742 | .ops = &ios_ops, | ||
743 | .parent_names = std_clk_io_parents, | ||
744 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
745 | }; | ||
746 | |||
747 | static struct clk_std clk_uart1 = { | ||
748 | .enable_bit = 37, | ||
749 | .hw = { | ||
750 | .init = &clk_uart1_init, | ||
751 | }, | ||
752 | }; | ||
753 | |||
754 | static struct clk_init_data clk_uart2_init = { | ||
755 | .name = "uart2", | ||
756 | .ops = &ios_ops, | ||
757 | .parent_names = std_clk_io_parents, | ||
758 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
759 | }; | ||
760 | |||
761 | static struct clk_std clk_uart2 = { | ||
762 | .enable_bit = 38, | ||
763 | .hw = { | ||
764 | .init = &clk_uart2_init, | ||
765 | }, | ||
766 | }; | ||
767 | |||
768 | static struct clk_init_data clk_usp0_init = { | ||
769 | .name = "usp0", | ||
770 | .ops = &ios_ops, | ||
771 | .parent_names = std_clk_io_parents, | ||
772 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
773 | }; | ||
774 | |||
775 | static struct clk_std clk_usp0 = { | ||
776 | .enable_bit = 39, | ||
777 | .hw = { | ||
778 | .init = &clk_usp0_init, | ||
779 | }, | ||
780 | }; | ||
781 | |||
782 | static struct clk_init_data clk_usp1_init = { | ||
783 | .name = "usp1", | ||
784 | .ops = &ios_ops, | ||
785 | .parent_names = std_clk_io_parents, | ||
786 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
787 | }; | ||
788 | |||
789 | static struct clk_std clk_usp1 = { | ||
790 | .enable_bit = 40, | ||
791 | .hw = { | ||
792 | .init = &clk_usp1_init, | ||
793 | }, | ||
794 | }; | ||
795 | |||
796 | static struct clk_init_data clk_usp2_init = { | ||
797 | .name = "usp2", | ||
798 | .ops = &ios_ops, | ||
799 | .parent_names = std_clk_io_parents, | ||
800 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
801 | }; | ||
802 | |||
803 | static struct clk_std clk_usp2 = { | ||
804 | .enable_bit = 41, | ||
805 | .hw = { | ||
806 | .init = &clk_usp2_init, | ||
807 | }, | ||
808 | }; | ||
809 | |||
810 | static struct clk_init_data clk_vip_init = { | ||
811 | .name = "vip", | ||
812 | .ops = &ios_ops, | ||
813 | .parent_names = std_clk_io_parents, | ||
814 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
815 | }; | ||
816 | |||
817 | static struct clk_std clk_vip = { | ||
818 | .enable_bit = 42, | ||
819 | .hw = { | ||
820 | .init = &clk_vip_init, | ||
821 | }, | ||
822 | }; | ||
823 | |||
824 | static struct clk_init_data clk_spi0_init = { | ||
825 | .name = "spi0", | ||
826 | .ops = &ios_ops, | ||
827 | .parent_names = std_clk_io_parents, | ||
828 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
829 | }; | ||
830 | |||
831 | static struct clk_std clk_spi0 = { | ||
832 | .enable_bit = 43, | ||
833 | .hw = { | ||
834 | .init = &clk_spi0_init, | ||
835 | }, | ||
836 | }; | ||
837 | |||
838 | static struct clk_init_data clk_spi1_init = { | ||
839 | .name = "spi1", | ||
840 | .ops = &ios_ops, | ||
841 | .parent_names = std_clk_io_parents, | ||
842 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
843 | }; | ||
844 | |||
845 | static struct clk_std clk_spi1 = { | ||
846 | .enable_bit = 44, | ||
847 | .hw = { | ||
848 | .init = &clk_spi1_init, | ||
849 | }, | ||
850 | }; | ||
851 | |||
852 | static struct clk_init_data clk_tsc_init = { | ||
853 | .name = "tsc", | ||
854 | .ops = &ios_ops, | ||
855 | .parent_names = std_clk_io_parents, | ||
856 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
857 | }; | ||
858 | |||
859 | static struct clk_std clk_tsc = { | ||
860 | .enable_bit = 45, | ||
861 | .hw = { | ||
862 | .init = &clk_tsc_init, | ||
863 | }, | ||
864 | }; | ||
865 | |||
866 | static struct clk_init_data clk_i2c0_init = { | ||
867 | .name = "i2c0", | ||
868 | .ops = &ios_ops, | ||
869 | .parent_names = std_clk_io_parents, | ||
870 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
871 | }; | ||
872 | |||
873 | static struct clk_std clk_i2c0 = { | ||
874 | .enable_bit = 46, | ||
875 | .hw = { | ||
876 | .init = &clk_i2c0_init, | ||
877 | }, | ||
878 | }; | ||
879 | |||
880 | static struct clk_init_data clk_i2c1_init = { | ||
881 | .name = "i2c1", | ||
882 | .ops = &ios_ops, | ||
883 | .parent_names = std_clk_io_parents, | ||
884 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
885 | }; | ||
886 | |||
887 | static struct clk_std clk_i2c1 = { | ||
888 | .enable_bit = 47, | ||
889 | .hw = { | ||
890 | .init = &clk_i2c1_init, | ||
891 | }, | ||
892 | }; | ||
893 | |||
894 | static struct clk_init_data clk_pwmc_init = { | ||
895 | .name = "pwmc", | ||
896 | .ops = &ios_ops, | ||
897 | .parent_names = std_clk_io_parents, | ||
898 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
899 | }; | ||
900 | |||
901 | static struct clk_std clk_pwmc = { | ||
902 | .enable_bit = 48, | ||
903 | .hw = { | ||
904 | .init = &clk_pwmc_init, | ||
905 | }, | ||
906 | }; | ||
907 | |||
908 | static struct clk_init_data clk_efuse_init = { | ||
909 | .name = "efuse", | ||
910 | .ops = &ios_ops, | ||
911 | .parent_names = std_clk_io_parents, | ||
912 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
913 | }; | ||
914 | |||
915 | static struct clk_std clk_efuse = { | ||
916 | .enable_bit = 49, | ||
917 | .hw = { | ||
918 | .init = &clk_efuse_init, | ||
919 | }, | ||
920 | }; | ||
921 | |||
922 | static struct clk_init_data clk_pulse_init = { | ||
923 | .name = "pulse", | ||
924 | .ops = &ios_ops, | ||
925 | .parent_names = std_clk_io_parents, | ||
926 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
927 | }; | ||
928 | |||
929 | static struct clk_std clk_pulse = { | ||
930 | .enable_bit = 50, | ||
931 | .hw = { | ||
932 | .init = &clk_pulse_init, | ||
933 | }, | ||
934 | }; | ||
935 | |||
936 | static const char *std_clk_dsp_parents[] = { | ||
937 | "dsp", | ||
938 | }; | ||
939 | |||
940 | static struct clk_init_data clk_gps_init = { | ||
941 | .name = "gps", | ||
942 | .ops = &ios_ops, | ||
943 | .parent_names = std_clk_dsp_parents, | ||
944 | .num_parents = ARRAY_SIZE(std_clk_dsp_parents), | ||
945 | }; | ||
946 | |||
947 | static struct clk_std clk_gps = { | ||
948 | .enable_bit = 1, | ||
949 | .hw = { | ||
950 | .init = &clk_gps_init, | ||
951 | }, | ||
952 | }; | ||
953 | |||
954 | static struct clk_init_data clk_mf_init = { | ||
955 | .name = "mf", | ||
956 | .ops = &ios_ops, | ||
957 | .parent_names = std_clk_io_parents, | ||
958 | .num_parents = ARRAY_SIZE(std_clk_io_parents), | ||
959 | }; | ||
960 | |||
961 | static struct clk_std clk_mf = { | ||
962 | .enable_bit = 2, | ||
963 | .hw = { | ||
964 | .init = &clk_mf_init, | ||
965 | }, | ||
966 | }; | ||
967 | |||
968 | static const char *std_clk_sys_parents[] = { | ||
969 | "sys", | ||
970 | }; | ||
971 | |||
972 | static struct clk_init_data clk_security_init = { | ||
973 | .name = "mf", | ||
974 | .ops = &ios_ops, | ||
975 | .parent_names = std_clk_sys_parents, | ||
976 | .num_parents = ARRAY_SIZE(std_clk_sys_parents), | ||
977 | }; | ||
978 | |||
979 | static struct clk_std clk_security = { | ||
980 | .enable_bit = 19, | ||
981 | .hw = { | ||
982 | .init = &clk_security_init, | ||
983 | }, | ||
984 | }; | ||
985 | |||
986 | static const char *std_clk_usb_parents[] = { | ||
987 | "usb_pll", | ||
988 | }; | ||
989 | |||
990 | static struct clk_init_data clk_usb0_init = { | ||
991 | .name = "usb0", | ||
992 | .ops = &ios_ops, | ||
993 | .parent_names = std_clk_usb_parents, | ||
994 | .num_parents = ARRAY_SIZE(std_clk_usb_parents), | ||
995 | }; | ||
996 | |||
997 | static struct clk_std clk_usb0 = { | ||
998 | .enable_bit = 16, | ||
999 | .hw = { | ||
1000 | .init = &clk_usb0_init, | ||
1001 | }, | ||
1002 | }; | ||
1003 | |||
1004 | static struct clk_init_data clk_usb1_init = { | ||
1005 | .name = "usb1", | ||
1006 | .ops = &ios_ops, | ||
1007 | .parent_names = std_clk_usb_parents, | ||
1008 | .num_parents = ARRAY_SIZE(std_clk_usb_parents), | ||
1009 | }; | ||
1010 | |||
1011 | static struct clk_std clk_usb1 = { | ||
1012 | .enable_bit = 17, | ||
1013 | .hw = { | ||
1014 | .init = &clk_usb1_init, | ||
1015 | }, | ||
1016 | }; | ||
1017 | |||
1018 | static struct of_device_id clkc_ids[] = { | ||
1019 | { .compatible = "sirf,prima2-clkc" }, | ||
1020 | {}, | ||
1021 | }; | ||
1022 | |||
1023 | static struct of_device_id rsc_ids[] = { | ||
1024 | { .compatible = "sirf,prima2-rsc" }, | ||
1025 | {}, | ||
1026 | }; | ||
1027 | |||
1028 | void __init sirfsoc_of_clk_init(void) | ||
1029 | { | ||
1030 | struct clk *clk; | ||
1031 | struct device_node *np; | ||
1032 | |||
1033 | np = of_find_matching_node(NULL, clkc_ids); | ||
1034 | if (!np) | ||
1035 | panic("unable to find compatible clkc node in dtb\n"); | ||
1036 | |||
1037 | sirfsoc_clk_vbase = of_iomap(np, 0); | ||
1038 | if (!sirfsoc_clk_vbase) | ||
1039 | panic("unable to map clkc registers\n"); | ||
1040 | |||
1041 | of_node_put(np); | ||
1042 | |||
1043 | np = of_find_matching_node(NULL, rsc_ids); | ||
1044 | if (!np) | ||
1045 | panic("unable to find compatible rsc node in dtb\n"); | ||
1046 | |||
1047 | sirfsoc_rsc_vbase = of_iomap(np, 0); | ||
1048 | if (!sirfsoc_rsc_vbase) | ||
1049 | panic("unable to map rsc registers\n"); | ||
1050 | |||
1051 | of_node_put(np); | ||
1052 | |||
1053 | |||
1054 | /* These are always available (RTC and 26MHz OSC)*/ | ||
1055 | clk = clk_register_fixed_rate(NULL, "rtc", NULL, | ||
1056 | CLK_IS_ROOT, 32768); | ||
1057 | BUG_ON(!clk); | ||
1058 | clk = clk_register_fixed_rate(NULL, "osc", NULL, | ||
1059 | CLK_IS_ROOT, 26000000); | ||
1060 | BUG_ON(!clk); | ||
1061 | |||
1062 | clk = clk_register(NULL, &clk_pll1.hw); | ||
1063 | BUG_ON(!clk); | ||
1064 | clk = clk_register(NULL, &clk_pll2.hw); | ||
1065 | BUG_ON(!clk); | ||
1066 | clk = clk_register(NULL, &clk_pll3.hw); | ||
1067 | BUG_ON(!clk); | ||
1068 | clk = clk_register(NULL, &clk_mem.hw); | ||
1069 | BUG_ON(!clk); | ||
1070 | clk = clk_register(NULL, &clk_sys.hw); | ||
1071 | BUG_ON(!clk); | ||
1072 | clk = clk_register(NULL, &clk_security.hw); | ||
1073 | BUG_ON(!clk); | ||
1074 | clk_register_clkdev(clk, NULL, "b8030000.security"); | ||
1075 | clk = clk_register(NULL, &clk_dsp.hw); | ||
1076 | BUG_ON(!clk); | ||
1077 | clk = clk_register(NULL, &clk_gps.hw); | ||
1078 | BUG_ON(!clk); | ||
1079 | clk_register_clkdev(clk, NULL, "a8010000.gps"); | ||
1080 | clk = clk_register(NULL, &clk_mf.hw); | ||
1081 | BUG_ON(!clk); | ||
1082 | clk = clk_register(NULL, &clk_io.hw); | ||
1083 | BUG_ON(!clk); | ||
1084 | clk_register_clkdev(clk, NULL, "io"); | ||
1085 | clk = clk_register(NULL, &clk_cpu.hw); | ||
1086 | BUG_ON(!clk); | ||
1087 | clk_register_clkdev(clk, NULL, "cpu"); | ||
1088 | clk = clk_register(NULL, &clk_uart0.hw); | ||
1089 | BUG_ON(!clk); | ||
1090 | clk_register_clkdev(clk, NULL, "b0050000.uart"); | ||
1091 | clk = clk_register(NULL, &clk_uart1.hw); | ||
1092 | BUG_ON(!clk); | ||
1093 | clk_register_clkdev(clk, NULL, "b0060000.uart"); | ||
1094 | clk = clk_register(NULL, &clk_uart2.hw); | ||
1095 | BUG_ON(!clk); | ||
1096 | clk_register_clkdev(clk, NULL, "b0070000.uart"); | ||
1097 | clk = clk_register(NULL, &clk_tsc.hw); | ||
1098 | BUG_ON(!clk); | ||
1099 | clk_register_clkdev(clk, NULL, "b0110000.tsc"); | ||
1100 | clk = clk_register(NULL, &clk_i2c0.hw); | ||
1101 | BUG_ON(!clk); | ||
1102 | clk_register_clkdev(clk, NULL, "b00e0000.i2c"); | ||
1103 | clk = clk_register(NULL, &clk_i2c1.hw); | ||
1104 | BUG_ON(!clk); | ||
1105 | clk_register_clkdev(clk, NULL, "b00f0000.i2c"); | ||
1106 | clk = clk_register(NULL, &clk_spi0.hw); | ||
1107 | BUG_ON(!clk); | ||
1108 | clk_register_clkdev(clk, NULL, "b00d0000.spi"); | ||
1109 | clk = clk_register(NULL, &clk_spi1.hw); | ||
1110 | BUG_ON(!clk); | ||
1111 | clk_register_clkdev(clk, NULL, "b0170000.spi"); | ||
1112 | clk = clk_register(NULL, &clk_pwmc.hw); | ||
1113 | BUG_ON(!clk); | ||
1114 | clk_register_clkdev(clk, NULL, "b0130000.pwm"); | ||
1115 | clk = clk_register(NULL, &clk_efuse.hw); | ||
1116 | BUG_ON(!clk); | ||
1117 | clk_register_clkdev(clk, NULL, "b0140000.efusesys"); | ||
1118 | clk = clk_register(NULL, &clk_pulse.hw); | ||
1119 | BUG_ON(!clk); | ||
1120 | clk_register_clkdev(clk, NULL, "b0150000.pulsec"); | ||
1121 | clk = clk_register(NULL, &clk_dmac0.hw); | ||
1122 | BUG_ON(!clk); | ||
1123 | clk_register_clkdev(clk, NULL, "b00b0000.dma-controller"); | ||
1124 | clk = clk_register(NULL, &clk_dmac1.hw); | ||
1125 | BUG_ON(!clk); | ||
1126 | clk_register_clkdev(clk, NULL, "b0160000.dma-controller"); | ||
1127 | clk = clk_register(NULL, &clk_nand.hw); | ||
1128 | BUG_ON(!clk); | ||
1129 | clk_register_clkdev(clk, NULL, "b0030000.nand"); | ||
1130 | clk = clk_register(NULL, &clk_audio.hw); | ||
1131 | BUG_ON(!clk); | ||
1132 | clk_register_clkdev(clk, NULL, "b0040000.audio"); | ||
1133 | clk = clk_register(NULL, &clk_usp0.hw); | ||
1134 | BUG_ON(!clk); | ||
1135 | clk_register_clkdev(clk, NULL, "b0080000.usp"); | ||
1136 | clk = clk_register(NULL, &clk_usp1.hw); | ||
1137 | BUG_ON(!clk); | ||
1138 | clk_register_clkdev(clk, NULL, "b0090000.usp"); | ||
1139 | clk = clk_register(NULL, &clk_usp2.hw); | ||
1140 | BUG_ON(!clk); | ||
1141 | clk_register_clkdev(clk, NULL, "b00a0000.usp"); | ||
1142 | clk = clk_register(NULL, &clk_vip.hw); | ||
1143 | BUG_ON(!clk); | ||
1144 | clk_register_clkdev(clk, NULL, "b00c0000.vip"); | ||
1145 | clk = clk_register(NULL, &clk_gfx.hw); | ||
1146 | BUG_ON(!clk); | ||
1147 | clk_register_clkdev(clk, NULL, "98000000.graphics"); | ||
1148 | clk = clk_register(NULL, &clk_mm.hw); | ||
1149 | BUG_ON(!clk); | ||
1150 | clk_register_clkdev(clk, NULL, "a0000000.multimedia"); | ||
1151 | clk = clk_register(NULL, &clk_lcd.hw); | ||
1152 | BUG_ON(!clk); | ||
1153 | clk_register_clkdev(clk, NULL, "90010000.display"); | ||
1154 | clk = clk_register(NULL, &clk_vpp.hw); | ||
1155 | BUG_ON(!clk); | ||
1156 | clk_register_clkdev(clk, NULL, "90020000.vpp"); | ||
1157 | clk = clk_register(NULL, &clk_mmc01.hw); | ||
1158 | BUG_ON(!clk); | ||
1159 | clk = clk_register(NULL, &clk_mmc23.hw); | ||
1160 | BUG_ON(!clk); | ||
1161 | clk = clk_register(NULL, &clk_mmc45.hw); | ||
1162 | BUG_ON(!clk); | ||
1163 | clk = clk_register(NULL, &usb_pll_clk_hw); | ||
1164 | BUG_ON(!clk); | ||
1165 | clk = clk_register(NULL, &clk_usb0.hw); | ||
1166 | BUG_ON(!clk); | ||
1167 | clk_register_clkdev(clk, NULL, "b00e0000.usb"); | ||
1168 | clk = clk_register(NULL, &clk_usb1.hw); | ||
1169 | BUG_ON(!clk); | ||
1170 | clk_register_clkdev(clk, NULL, "b00f0000.usb"); | ||
1171 | } | ||
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c new file mode 100644 index 000000000000..a885600f5270 --- /dev/null +++ b/drivers/clk/clk-vt8500.c | |||
@@ -0,0 +1,510 @@ | |||
1 | /* | ||
2 | * Clock implementation for VIA/Wondermedia SoC's | ||
3 | * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/io.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/clkdev.h> | ||
21 | #include <linux/clk-provider.h> | ||
22 | |||
23 | /* All clocks share the same lock as none can be changed concurrently */ | ||
24 | static DEFINE_SPINLOCK(_lock); | ||
25 | |||
26 | struct clk_device { | ||
27 | struct clk_hw hw; | ||
28 | void __iomem *div_reg; | ||
29 | unsigned int div_mask; | ||
30 | void __iomem *en_reg; | ||
31 | int en_bit; | ||
32 | spinlock_t *lock; | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * Add new PLL_TYPE_x definitions here as required. Use the first known model | ||
37 | * to support the new type as the name. | ||
38 | * Add case statements to vtwm_pll_recalc_rate(), vtwm_pll_round_round() and | ||
39 | * vtwm_pll_set_rate() to handle the new PLL_TYPE_x | ||
40 | */ | ||
41 | |||
42 | #define PLL_TYPE_VT8500 0 | ||
43 | #define PLL_TYPE_WM8650 1 | ||
44 | |||
45 | struct clk_pll { | ||
46 | struct clk_hw hw; | ||
47 | void __iomem *reg; | ||
48 | spinlock_t *lock; | ||
49 | int type; | ||
50 | }; | ||
51 | |||
52 | static void __iomem *pmc_base; | ||
53 | |||
54 | #define to_clk_device(_hw) container_of(_hw, struct clk_device, hw) | ||
55 | |||
56 | #define VT8500_PMC_BUSY_MASK 0x18 | ||
57 | |||
58 | static void vt8500_pmc_wait_busy(void) | ||
59 | { | ||
60 | while (readl(pmc_base) & VT8500_PMC_BUSY_MASK) | ||
61 | cpu_relax(); | ||
62 | } | ||
63 | |||
64 | static int vt8500_dclk_enable(struct clk_hw *hw) | ||
65 | { | ||
66 | struct clk_device *cdev = to_clk_device(hw); | ||
67 | u32 en_val; | ||
68 | unsigned long flags = 0; | ||
69 | |||
70 | spin_lock_irqsave(cdev->lock, flags); | ||
71 | |||
72 | en_val = readl(cdev->en_reg); | ||
73 | en_val |= BIT(cdev->en_bit); | ||
74 | writel(en_val, cdev->en_reg); | ||
75 | |||
76 | spin_unlock_irqrestore(cdev->lock, flags); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static void vt8500_dclk_disable(struct clk_hw *hw) | ||
81 | { | ||
82 | struct clk_device *cdev = to_clk_device(hw); | ||
83 | u32 en_val; | ||
84 | unsigned long flags = 0; | ||
85 | |||
86 | spin_lock_irqsave(cdev->lock, flags); | ||
87 | |||
88 | en_val = readl(cdev->en_reg); | ||
89 | en_val &= ~BIT(cdev->en_bit); | ||
90 | writel(en_val, cdev->en_reg); | ||
91 | |||
92 | spin_unlock_irqrestore(cdev->lock, flags); | ||
93 | } | ||
94 | |||
95 | static int vt8500_dclk_is_enabled(struct clk_hw *hw) | ||
96 | { | ||
97 | struct clk_device *cdev = to_clk_device(hw); | ||
98 | u32 en_val = (readl(cdev->en_reg) & BIT(cdev->en_bit)); | ||
99 | |||
100 | return en_val ? 1 : 0; | ||
101 | } | ||
102 | |||
103 | static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw, | ||
104 | unsigned long parent_rate) | ||
105 | { | ||
106 | struct clk_device *cdev = to_clk_device(hw); | ||
107 | u32 div = readl(cdev->div_reg) & cdev->div_mask; | ||
108 | |||
109 | /* Special case for SDMMC devices */ | ||
110 | if ((cdev->div_mask == 0x3F) && (div & BIT(5))) | ||
111 | div = 64 * (div & 0x1f); | ||
112 | |||
113 | /* div == 0 is actually the highest divisor */ | ||
114 | if (div == 0) | ||
115 | div = (cdev->div_mask + 1); | ||
116 | |||
117 | return parent_rate / div; | ||
118 | } | ||
119 | |||
120 | static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate, | ||
121 | unsigned long *prate) | ||
122 | { | ||
123 | u32 divisor = *prate / rate; | ||
124 | |||
125 | return *prate / divisor; | ||
126 | } | ||
127 | |||
128 | static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate, | ||
129 | unsigned long parent_rate) | ||
130 | { | ||
131 | struct clk_device *cdev = to_clk_device(hw); | ||
132 | u32 divisor = parent_rate / rate; | ||
133 | unsigned long flags = 0; | ||
134 | |||
135 | if (divisor == cdev->div_mask + 1) | ||
136 | divisor = 0; | ||
137 | |||
138 | if (divisor > cdev->div_mask) { | ||
139 | pr_err("%s: invalid divisor for clock\n", __func__); | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | |||
143 | spin_lock_irqsave(cdev->lock, flags); | ||
144 | |||
145 | vt8500_pmc_wait_busy(); | ||
146 | writel(divisor, cdev->div_reg); | ||
147 | vt8500_pmc_wait_busy(); | ||
148 | |||
149 | spin_lock_irqsave(cdev->lock, flags); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | |||
155 | static const struct clk_ops vt8500_gated_clk_ops = { | ||
156 | .enable = vt8500_dclk_enable, | ||
157 | .disable = vt8500_dclk_disable, | ||
158 | .is_enabled = vt8500_dclk_is_enabled, | ||
159 | }; | ||
160 | |||
161 | static const struct clk_ops vt8500_divisor_clk_ops = { | ||
162 | .round_rate = vt8500_dclk_round_rate, | ||
163 | .set_rate = vt8500_dclk_set_rate, | ||
164 | .recalc_rate = vt8500_dclk_recalc_rate, | ||
165 | }; | ||
166 | |||
167 | static const struct clk_ops vt8500_gated_divisor_clk_ops = { | ||
168 | .enable = vt8500_dclk_enable, | ||
169 | .disable = vt8500_dclk_disable, | ||
170 | .is_enabled = vt8500_dclk_is_enabled, | ||
171 | .round_rate = vt8500_dclk_round_rate, | ||
172 | .set_rate = vt8500_dclk_set_rate, | ||
173 | .recalc_rate = vt8500_dclk_recalc_rate, | ||
174 | }; | ||
175 | |||
176 | #define CLK_INIT_GATED BIT(0) | ||
177 | #define CLK_INIT_DIVISOR BIT(1) | ||
178 | #define CLK_INIT_GATED_DIVISOR (CLK_INIT_DIVISOR | CLK_INIT_GATED) | ||
179 | |||
180 | static __init void vtwm_device_clk_init(struct device_node *node) | ||
181 | { | ||
182 | u32 en_reg, div_reg; | ||
183 | struct clk *clk; | ||
184 | struct clk_device *dev_clk; | ||
185 | const char *clk_name = node->name; | ||
186 | const char *parent_name; | ||
187 | struct clk_init_data init; | ||
188 | int rc; | ||
189 | int clk_init_flags = 0; | ||
190 | |||
191 | dev_clk = kzalloc(sizeof(*dev_clk), GFP_KERNEL); | ||
192 | if (WARN_ON(!dev_clk)) | ||
193 | return; | ||
194 | |||
195 | dev_clk->lock = &_lock; | ||
196 | |||
197 | rc = of_property_read_u32(node, "enable-reg", &en_reg); | ||
198 | if (!rc) { | ||
199 | dev_clk->en_reg = pmc_base + en_reg; | ||
200 | rc = of_property_read_u32(node, "enable-bit", &dev_clk->en_bit); | ||
201 | if (rc) { | ||
202 | pr_err("%s: enable-bit property required for gated clock\n", | ||
203 | __func__); | ||
204 | return; | ||
205 | } | ||
206 | clk_init_flags |= CLK_INIT_GATED; | ||
207 | } | ||
208 | |||
209 | rc = of_property_read_u32(node, "divisor-reg", &div_reg); | ||
210 | if (!rc) { | ||
211 | dev_clk->div_reg = pmc_base + div_reg; | ||
212 | /* | ||
213 | * use 0x1f as the default mask since it covers | ||
214 | * almost all the clocks and reduces dts properties | ||
215 | */ | ||
216 | dev_clk->div_mask = 0x1f; | ||
217 | |||
218 | of_property_read_u32(node, "divisor-mask", &dev_clk->div_mask); | ||
219 | clk_init_flags |= CLK_INIT_DIVISOR; | ||
220 | } | ||
221 | |||
222 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
223 | |||
224 | switch (clk_init_flags) { | ||
225 | case CLK_INIT_GATED: | ||
226 | init.ops = &vt8500_gated_clk_ops; | ||
227 | break; | ||
228 | case CLK_INIT_DIVISOR: | ||
229 | init.ops = &vt8500_divisor_clk_ops; | ||
230 | break; | ||
231 | case CLK_INIT_GATED_DIVISOR: | ||
232 | init.ops = &vt8500_gated_divisor_clk_ops; | ||
233 | break; | ||
234 | default: | ||
235 | pr_err("%s: Invalid clock description in device tree\n", | ||
236 | __func__); | ||
237 | kfree(dev_clk); | ||
238 | return; | ||
239 | } | ||
240 | |||
241 | init.name = clk_name; | ||
242 | init.flags = 0; | ||
243 | parent_name = of_clk_get_parent_name(node, 0); | ||
244 | init.parent_names = &parent_name; | ||
245 | init.num_parents = 1; | ||
246 | |||
247 | dev_clk->hw.init = &init; | ||
248 | |||
249 | clk = clk_register(NULL, &dev_clk->hw); | ||
250 | if (WARN_ON(IS_ERR(clk))) { | ||
251 | kfree(dev_clk); | ||
252 | return; | ||
253 | } | ||
254 | rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
255 | clk_register_clkdev(clk, clk_name, NULL); | ||
256 | } | ||
257 | |||
258 | |||
259 | /* PLL clock related functions */ | ||
260 | |||
261 | #define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) | ||
262 | |||
263 | /* Helper macros for PLL_VT8500 */ | ||
264 | #define VT8500_PLL_MUL(x) ((x & 0x1F) << 1) | ||
265 | #define VT8500_PLL_DIV(x) ((x & 0x100) ? 1 : 2) | ||
266 | |||
267 | #define VT8500_BITS_TO_FREQ(r, m, d) \ | ||
268 | ((r / d) * m) | ||
269 | |||
270 | #define VT8500_BITS_TO_VAL(m, d) \ | ||
271 | ((d == 2 ? 0 : 0x100) | ((m >> 1) & 0x1F)) | ||
272 | |||
273 | /* Helper macros for PLL_WM8650 */ | ||
274 | #define WM8650_PLL_MUL(x) (x & 0x3FF) | ||
275 | #define WM8650_PLL_DIV(x) (((x >> 10) & 7) * (1 << ((x >> 13) & 3))) | ||
276 | |||
277 | #define WM8650_BITS_TO_FREQ(r, m, d1, d2) \ | ||
278 | (r * m / (d1 * (1 << d2))) | ||
279 | |||
280 | #define WM8650_BITS_TO_VAL(m, d1, d2) \ | ||
281 | ((d2 << 13) | (d1 << 10) | (m & 0x3FF)) | ||
282 | |||
283 | |||
284 | static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, | ||
285 | u32 *multiplier, u32 *prediv) | ||
286 | { | ||
287 | unsigned long tclk; | ||
288 | |||
289 | /* sanity check */ | ||
290 | if ((rate < parent_rate * 4) || (rate > parent_rate * 62)) { | ||
291 | pr_err("%s: requested rate out of range\n", __func__); | ||
292 | *multiplier = 0; | ||
293 | *prediv = 1; | ||
294 | return; | ||
295 | } | ||
296 | if (rate <= parent_rate * 31) | ||
297 | /* use the prediv to double the resolution */ | ||
298 | *prediv = 2; | ||
299 | else | ||
300 | *prediv = 1; | ||
301 | |||
302 | *multiplier = rate / (parent_rate / *prediv); | ||
303 | tclk = (parent_rate / *prediv) * *multiplier; | ||
304 | |||
305 | if (tclk != rate) | ||
306 | pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, | ||
307 | rate, tclk); | ||
308 | } | ||
309 | |||
310 | static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, | ||
311 | u32 *multiplier, u32 *divisor1, u32 *divisor2) | ||
312 | { | ||
313 | u32 mul, div1, div2; | ||
314 | u32 best_mul, best_div1, best_div2; | ||
315 | unsigned long tclk, rate_err, best_err; | ||
316 | |||
317 | best_err = (unsigned long)-1; | ||
318 | |||
319 | /* Find the closest match (lower or equal to requested) */ | ||
320 | for (div1 = 5; div1 >= 3; div1--) | ||
321 | for (div2 = 3; div2 >= 0; div2--) | ||
322 | for (mul = 3; mul <= 1023; mul++) { | ||
323 | tclk = parent_rate * mul / (div1 * (1 << div2)); | ||
324 | if (tclk > rate) | ||
325 | continue; | ||
326 | /* error will always be +ve */ | ||
327 | rate_err = rate - tclk; | ||
328 | if (rate_err == 0) { | ||
329 | *multiplier = mul; | ||
330 | *divisor1 = div1; | ||
331 | *divisor2 = div2; | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | if (rate_err < best_err) { | ||
336 | best_err = rate_err; | ||
337 | best_mul = mul; | ||
338 | best_div1 = div1; | ||
339 | best_div2 = div2; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | /* if we got here, it wasn't an exact match */ | ||
344 | pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, | ||
345 | rate - best_err); | ||
346 | *multiplier = mul; | ||
347 | *divisor1 = div1; | ||
348 | *divisor2 = div2; | ||
349 | } | ||
350 | |||
351 | static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, | ||
352 | unsigned long parent_rate) | ||
353 | { | ||
354 | struct clk_pll *pll = to_clk_pll(hw); | ||
355 | u32 mul, div1, div2; | ||
356 | u32 pll_val; | ||
357 | unsigned long flags = 0; | ||
358 | |||
359 | /* sanity check */ | ||
360 | |||
361 | switch (pll->type) { | ||
362 | case PLL_TYPE_VT8500: | ||
363 | vt8500_find_pll_bits(rate, parent_rate, &mul, &div1); | ||
364 | pll_val = VT8500_BITS_TO_VAL(mul, div1); | ||
365 | break; | ||
366 | case PLL_TYPE_WM8650: | ||
367 | wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); | ||
368 | pll_val = WM8650_BITS_TO_VAL(mul, div1, div2); | ||
369 | break; | ||
370 | default: | ||
371 | pr_err("%s: invalid pll type\n", __func__); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | spin_lock_irqsave(pll->lock, flags); | ||
376 | |||
377 | vt8500_pmc_wait_busy(); | ||
378 | writel(pll_val, pll->reg); | ||
379 | vt8500_pmc_wait_busy(); | ||
380 | |||
381 | spin_unlock_irqrestore(pll->lock, flags); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, | ||
387 | unsigned long *prate) | ||
388 | { | ||
389 | struct clk_pll *pll = to_clk_pll(hw); | ||
390 | u32 mul, div1, div2; | ||
391 | long round_rate; | ||
392 | |||
393 | switch (pll->type) { | ||
394 | case PLL_TYPE_VT8500: | ||
395 | vt8500_find_pll_bits(rate, *prate, &mul, &div1); | ||
396 | round_rate = VT8500_BITS_TO_FREQ(*prate, mul, div1); | ||
397 | break; | ||
398 | case PLL_TYPE_WM8650: | ||
399 | wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2); | ||
400 | round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2); | ||
401 | break; | ||
402 | default: | ||
403 | round_rate = 0; | ||
404 | } | ||
405 | |||
406 | return round_rate; | ||
407 | } | ||
408 | |||
409 | static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw, | ||
410 | unsigned long parent_rate) | ||
411 | { | ||
412 | struct clk_pll *pll = to_clk_pll(hw); | ||
413 | u32 pll_val = readl(pll->reg); | ||
414 | unsigned long pll_freq; | ||
415 | |||
416 | switch (pll->type) { | ||
417 | case PLL_TYPE_VT8500: | ||
418 | pll_freq = parent_rate * VT8500_PLL_MUL(pll_val); | ||
419 | pll_freq /= VT8500_PLL_DIV(pll_val); | ||
420 | break; | ||
421 | case PLL_TYPE_WM8650: | ||
422 | pll_freq = parent_rate * WM8650_PLL_MUL(pll_val); | ||
423 | pll_freq /= WM8650_PLL_DIV(pll_val); | ||
424 | break; | ||
425 | default: | ||
426 | pll_freq = 0; | ||
427 | } | ||
428 | |||
429 | return pll_freq; | ||
430 | } | ||
431 | |||
432 | const struct clk_ops vtwm_pll_ops = { | ||
433 | .round_rate = vtwm_pll_round_rate, | ||
434 | .set_rate = vtwm_pll_set_rate, | ||
435 | .recalc_rate = vtwm_pll_recalc_rate, | ||
436 | }; | ||
437 | |||
438 | static __init void vtwm_pll_clk_init(struct device_node *node, int pll_type) | ||
439 | { | ||
440 | u32 reg; | ||
441 | struct clk *clk; | ||
442 | struct clk_pll *pll_clk; | ||
443 | const char *clk_name = node->name; | ||
444 | const char *parent_name; | ||
445 | struct clk_init_data init; | ||
446 | int rc; | ||
447 | |||
448 | rc = of_property_read_u32(node, "reg", ®); | ||
449 | if (WARN_ON(rc)) | ||
450 | return; | ||
451 | |||
452 | pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); | ||
453 | if (WARN_ON(!pll_clk)) | ||
454 | return; | ||
455 | |||
456 | pll_clk->reg = pmc_base + reg; | ||
457 | pll_clk->lock = &_lock; | ||
458 | pll_clk->type = pll_type; | ||
459 | |||
460 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
461 | |||
462 | init.name = clk_name; | ||
463 | init.ops = &vtwm_pll_ops; | ||
464 | init.flags = 0; | ||
465 | parent_name = of_clk_get_parent_name(node, 0); | ||
466 | init.parent_names = &parent_name; | ||
467 | init.num_parents = 1; | ||
468 | |||
469 | pll_clk->hw.init = &init; | ||
470 | |||
471 | clk = clk_register(NULL, &pll_clk->hw); | ||
472 | if (WARN_ON(IS_ERR(clk))) { | ||
473 | kfree(pll_clk); | ||
474 | return; | ||
475 | } | ||
476 | rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
477 | clk_register_clkdev(clk, clk_name, NULL); | ||
478 | } | ||
479 | |||
480 | |||
481 | /* Wrappers for initialization functions */ | ||
482 | |||
483 | static void __init vt8500_pll_init(struct device_node *node) | ||
484 | { | ||
485 | vtwm_pll_clk_init(node, PLL_TYPE_VT8500); | ||
486 | } | ||
487 | |||
488 | static void __init wm8650_pll_init(struct device_node *node) | ||
489 | { | ||
490 | vtwm_pll_clk_init(node, PLL_TYPE_WM8650); | ||
491 | } | ||
492 | |||
493 | static const __initconst struct of_device_id clk_match[] = { | ||
494 | { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, | ||
495 | { .compatible = "via,vt8500-pll-clock", .data = vt8500_pll_init, }, | ||
496 | { .compatible = "wm,wm8650-pll-clock", .data = wm8650_pll_init, }, | ||
497 | { .compatible = "via,vt8500-device-clock", | ||
498 | .data = vtwm_device_clk_init, }, | ||
499 | { /* sentinel */ } | ||
500 | }; | ||
501 | |||
502 | void __init vtwm_clk_init(void __iomem *base) | ||
503 | { | ||
504 | if (!base) | ||
505 | return; | ||
506 | |||
507 | pmc_base = base; | ||
508 | |||
509 | of_clk_init(clk_match); | ||
510 | } | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index efdfd009c270..56e4495ebeb1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -558,25 +558,6 @@ int clk_enable(struct clk *clk) | |||
558 | EXPORT_SYMBOL_GPL(clk_enable); | 558 | EXPORT_SYMBOL_GPL(clk_enable); |
559 | 559 | ||
560 | /** | 560 | /** |
561 | * clk_get_rate - return the rate of clk | ||
562 | * @clk: the clk whose rate is being returned | ||
563 | * | ||
564 | * Simply returns the cached rate of the clk. Does not query the hardware. If | ||
565 | * clk is NULL then returns 0. | ||
566 | */ | ||
567 | unsigned long clk_get_rate(struct clk *clk) | ||
568 | { | ||
569 | unsigned long rate; | ||
570 | |||
571 | mutex_lock(&prepare_lock); | ||
572 | rate = __clk_get_rate(clk); | ||
573 | mutex_unlock(&prepare_lock); | ||
574 | |||
575 | return rate; | ||
576 | } | ||
577 | EXPORT_SYMBOL_GPL(clk_get_rate); | ||
578 | |||
579 | /** | ||
580 | * __clk_round_rate - round the given rate for a clk | 561 | * __clk_round_rate - round the given rate for a clk |
581 | * @clk: round the rate of this clock | 562 | * @clk: round the rate of this clock |
582 | * | 563 | * |
@@ -702,6 +683,30 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg) | |||
702 | } | 683 | } |
703 | 684 | ||
704 | /** | 685 | /** |
686 | * clk_get_rate - return the rate of clk | ||
687 | * @clk: the clk whose rate is being returned | ||
688 | * | ||
689 | * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag | ||
690 | * is set, which means a recalc_rate will be issued. | ||
691 | * If clk is NULL then returns 0. | ||
692 | */ | ||
693 | unsigned long clk_get_rate(struct clk *clk) | ||
694 | { | ||
695 | unsigned long rate; | ||
696 | |||
697 | mutex_lock(&prepare_lock); | ||
698 | |||
699 | if (clk && (clk->flags & CLK_GET_RATE_NOCACHE)) | ||
700 | __clk_recalc_rates(clk, 0); | ||
701 | |||
702 | rate = __clk_get_rate(clk); | ||
703 | mutex_unlock(&prepare_lock); | ||
704 | |||
705 | return rate; | ||
706 | } | ||
707 | EXPORT_SYMBOL_GPL(clk_get_rate); | ||
708 | |||
709 | /** | ||
705 | * __clk_speculate_rates | 710 | * __clk_speculate_rates |
706 | * @clk: first clk in the subtree | 711 | * @clk: first clk in the subtree |
707 | * @parent_rate: the "future" rate of clk's parent | 712 | * @parent_rate: the "future" rate of clk's parent |
@@ -1582,6 +1587,20 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, | |||
1582 | } | 1587 | } |
1583 | EXPORT_SYMBOL_GPL(of_clk_src_simple_get); | 1588 | EXPORT_SYMBOL_GPL(of_clk_src_simple_get); |
1584 | 1589 | ||
1590 | struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data) | ||
1591 | { | ||
1592 | struct clk_onecell_data *clk_data = data; | ||
1593 | unsigned int idx = clkspec->args[0]; | ||
1594 | |||
1595 | if (idx >= clk_data->clk_num) { | ||
1596 | pr_err("%s: invalid clock index %d\n", __func__, idx); | ||
1597 | return ERR_PTR(-EINVAL); | ||
1598 | } | ||
1599 | |||
1600 | return clk_data->clks[idx]; | ||
1601 | } | ||
1602 | EXPORT_SYMBOL_GPL(of_clk_src_onecell_get); | ||
1603 | |||
1585 | /** | 1604 | /** |
1586 | * of_clk_add_provider() - Register a clock provider for a node | 1605 | * of_clk_add_provider() - Register a clock provider for a node |
1587 | * @np: Device node pointer associated with clock provider | 1606 | * @np: Device node pointer associated with clock provider |
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile new file mode 100644 index 000000000000..392d78044ce3 --- /dev/null +++ b/drivers/clk/mmp/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for mmp specific clk | ||
3 | # | ||
4 | |||
5 | obj-y += clk-apbc.o clk-apmu.o clk-frac.o | ||
6 | |||
7 | obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o | ||
8 | obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o | ||
9 | obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o | ||
diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c new file mode 100644 index 000000000000..d14120eaa71f --- /dev/null +++ b/drivers/clk/mmp/clk-apbc.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * mmp APB clock operation source file | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * Chao Xie <xiechao.mail@gmail.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include "clk.h" | ||
20 | |||
21 | /* Common APB clock register bit definitions */ | ||
22 | #define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */ | ||
23 | #define APBC_FNCLK (1 << 1) /* Functional Clock Enable */ | ||
24 | #define APBC_RST (1 << 2) /* Reset Generation */ | ||
25 | #define APBC_POWER (1 << 7) /* Reset Generation */ | ||
26 | |||
27 | #define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw) | ||
28 | struct clk_apbc { | ||
29 | struct clk_hw hw; | ||
30 | void __iomem *base; | ||
31 | unsigned int delay; | ||
32 | unsigned int flags; | ||
33 | spinlock_t *lock; | ||
34 | }; | ||
35 | |||
36 | static int clk_apbc_prepare(struct clk_hw *hw) | ||
37 | { | ||
38 | struct clk_apbc *apbc = to_clk_apbc(hw); | ||
39 | unsigned int data; | ||
40 | unsigned long flags = 0; | ||
41 | |||
42 | /* | ||
43 | * It may share same register as MUX clock, | ||
44 | * and it will impact FNCLK enable. Spinlock is needed | ||
45 | */ | ||
46 | if (apbc->lock) | ||
47 | spin_lock_irqsave(apbc->lock, flags); | ||
48 | |||
49 | data = readl_relaxed(apbc->base); | ||
50 | if (apbc->flags & APBC_POWER_CTRL) | ||
51 | data |= APBC_POWER; | ||
52 | data |= APBC_FNCLK; | ||
53 | writel_relaxed(data, apbc->base); | ||
54 | |||
55 | if (apbc->lock) | ||
56 | spin_unlock_irqrestore(apbc->lock, flags); | ||
57 | |||
58 | udelay(apbc->delay); | ||
59 | |||
60 | if (apbc->lock) | ||
61 | spin_lock_irqsave(apbc->lock, flags); | ||
62 | |||
63 | data = readl_relaxed(apbc->base); | ||
64 | data |= APBC_APBCLK; | ||
65 | writel_relaxed(data, apbc->base); | ||
66 | |||
67 | if (apbc->lock) | ||
68 | spin_unlock_irqrestore(apbc->lock, flags); | ||
69 | |||
70 | udelay(apbc->delay); | ||
71 | |||
72 | if (!(apbc->flags & APBC_NO_BUS_CTRL)) { | ||
73 | if (apbc->lock) | ||
74 | spin_lock_irqsave(apbc->lock, flags); | ||
75 | |||
76 | data = readl_relaxed(apbc->base); | ||
77 | data &= ~APBC_RST; | ||
78 | writel_relaxed(data, apbc->base); | ||
79 | |||
80 | if (apbc->lock) | ||
81 | spin_unlock_irqrestore(apbc->lock, flags); | ||
82 | } | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static void clk_apbc_unprepare(struct clk_hw *hw) | ||
88 | { | ||
89 | struct clk_apbc *apbc = to_clk_apbc(hw); | ||
90 | unsigned long data; | ||
91 | unsigned long flags = 0; | ||
92 | |||
93 | if (apbc->lock) | ||
94 | spin_lock_irqsave(apbc->lock, flags); | ||
95 | |||
96 | data = readl_relaxed(apbc->base); | ||
97 | if (apbc->flags & APBC_POWER_CTRL) | ||
98 | data &= ~APBC_POWER; | ||
99 | data &= ~APBC_FNCLK; | ||
100 | writel_relaxed(data, apbc->base); | ||
101 | |||
102 | if (apbc->lock) | ||
103 | spin_unlock_irqrestore(apbc->lock, flags); | ||
104 | |||
105 | udelay(10); | ||
106 | |||
107 | if (apbc->lock) | ||
108 | spin_lock_irqsave(apbc->lock, flags); | ||
109 | |||
110 | data = readl_relaxed(apbc->base); | ||
111 | data &= ~APBC_APBCLK; | ||
112 | writel_relaxed(data, apbc->base); | ||
113 | |||
114 | if (apbc->lock) | ||
115 | spin_unlock_irqrestore(apbc->lock, flags); | ||
116 | } | ||
117 | |||
118 | struct clk_ops clk_apbc_ops = { | ||
119 | .prepare = clk_apbc_prepare, | ||
120 | .unprepare = clk_apbc_unprepare, | ||
121 | }; | ||
122 | |||
123 | struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name, | ||
124 | void __iomem *base, unsigned int delay, | ||
125 | unsigned int apbc_flags, spinlock_t *lock) | ||
126 | { | ||
127 | struct clk_apbc *apbc; | ||
128 | struct clk *clk; | ||
129 | struct clk_init_data init; | ||
130 | |||
131 | apbc = kzalloc(sizeof(*apbc), GFP_KERNEL); | ||
132 | if (!apbc) | ||
133 | return NULL; | ||
134 | |||
135 | init.name = name; | ||
136 | init.ops = &clk_apbc_ops; | ||
137 | init.flags = CLK_SET_RATE_PARENT; | ||
138 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
139 | init.num_parents = (parent_name ? 1 : 0); | ||
140 | |||
141 | apbc->base = base; | ||
142 | apbc->delay = delay; | ||
143 | apbc->flags = apbc_flags; | ||
144 | apbc->lock = lock; | ||
145 | apbc->hw.init = &init; | ||
146 | |||
147 | clk = clk_register(NULL, &apbc->hw); | ||
148 | if (IS_ERR(clk)) | ||
149 | kfree(apbc); | ||
150 | |||
151 | return clk; | ||
152 | } | ||
diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c new file mode 100644 index 000000000000..abe182b2377f --- /dev/null +++ b/drivers/clk/mmp/clk-apmu.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * mmp AXI peripharal clock operation source file | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * Chao Xie <xiechao.mail@gmail.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include "clk.h" | ||
20 | |||
21 | #define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk)) | ||
22 | struct clk_apmu { | ||
23 | struct clk_hw hw; | ||
24 | void __iomem *base; | ||
25 | u32 rst_mask; | ||
26 | u32 enable_mask; | ||
27 | spinlock_t *lock; | ||
28 | }; | ||
29 | |||
30 | static int clk_apmu_enable(struct clk_hw *hw) | ||
31 | { | ||
32 | struct clk_apmu *apmu = to_clk_apmu(hw); | ||
33 | unsigned long data; | ||
34 | unsigned long flags = 0; | ||
35 | |||
36 | if (apmu->lock) | ||
37 | spin_lock_irqsave(apmu->lock, flags); | ||
38 | |||
39 | data = readl_relaxed(apmu->base) | apmu->enable_mask; | ||
40 | writel_relaxed(data, apmu->base); | ||
41 | |||
42 | if (apmu->lock) | ||
43 | spin_unlock_irqrestore(apmu->lock, flags); | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static void clk_apmu_disable(struct clk_hw *hw) | ||
49 | { | ||
50 | struct clk_apmu *apmu = to_clk_apmu(hw); | ||
51 | unsigned long data; | ||
52 | unsigned long flags = 0; | ||
53 | |||
54 | if (apmu->lock) | ||
55 | spin_lock_irqsave(apmu->lock, flags); | ||
56 | |||
57 | data = readl_relaxed(apmu->base) & ~apmu->enable_mask; | ||
58 | writel_relaxed(data, apmu->base); | ||
59 | |||
60 | if (apmu->lock) | ||
61 | spin_unlock_irqrestore(apmu->lock, flags); | ||
62 | } | ||
63 | |||
64 | struct clk_ops clk_apmu_ops = { | ||
65 | .enable = clk_apmu_enable, | ||
66 | .disable = clk_apmu_disable, | ||
67 | }; | ||
68 | |||
69 | struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name, | ||
70 | void __iomem *base, u32 enable_mask, spinlock_t *lock) | ||
71 | { | ||
72 | struct clk_apmu *apmu; | ||
73 | struct clk *clk; | ||
74 | struct clk_init_data init; | ||
75 | |||
76 | apmu = kzalloc(sizeof(*apmu), GFP_KERNEL); | ||
77 | if (!apmu) | ||
78 | return NULL; | ||
79 | |||
80 | init.name = name; | ||
81 | init.ops = &clk_apmu_ops; | ||
82 | init.flags = CLK_SET_RATE_PARENT; | ||
83 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
84 | init.num_parents = (parent_name ? 1 : 0); | ||
85 | |||
86 | apmu->base = base; | ||
87 | apmu->enable_mask = enable_mask; | ||
88 | apmu->lock = lock; | ||
89 | apmu->hw.init = &init; | ||
90 | |||
91 | clk = clk_register(NULL, &apmu->hw); | ||
92 | |||
93 | if (IS_ERR(clk)) | ||
94 | kfree(apmu); | ||
95 | |||
96 | return clk; | ||
97 | } | ||
diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c new file mode 100644 index 000000000000..80c1dd15d15c --- /dev/null +++ b/drivers/clk/mmp/clk-frac.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * mmp factor clock operation source file | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * Chao Xie <xiechao.mail@gmail.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk-provider.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/err.h> | ||
16 | |||
17 | #include "clk.h" | ||
18 | /* | ||
19 | * It is M/N clock | ||
20 | * | ||
21 | * Fout from synthesizer can be given from two equations: | ||
22 | * numerator/denominator = Fin / (Fout * factor) | ||
23 | */ | ||
24 | |||
25 | #define to_clk_factor(hw) container_of(hw, struct clk_factor, hw) | ||
26 | struct clk_factor { | ||
27 | struct clk_hw hw; | ||
28 | void __iomem *base; | ||
29 | struct clk_factor_masks *masks; | ||
30 | struct clk_factor_tbl *ftbl; | ||
31 | unsigned int ftbl_cnt; | ||
32 | }; | ||
33 | |||
34 | static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, | ||
35 | unsigned long *prate) | ||
36 | { | ||
37 | struct clk_factor *factor = to_clk_factor(hw); | ||
38 | unsigned long rate = 0, prev_rate; | ||
39 | int i; | ||
40 | |||
41 | for (i = 0; i < factor->ftbl_cnt; i++) { | ||
42 | prev_rate = rate; | ||
43 | rate = (((*prate / 10000) * factor->ftbl[i].num) / | ||
44 | (factor->ftbl[i].den * factor->masks->factor)) * 10000; | ||
45 | if (rate > drate) | ||
46 | break; | ||
47 | } | ||
48 | if (i == 0) | ||
49 | return rate; | ||
50 | else | ||
51 | return prev_rate; | ||
52 | } | ||
53 | |||
54 | static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, | ||
55 | unsigned long parent_rate) | ||
56 | { | ||
57 | struct clk_factor *factor = to_clk_factor(hw); | ||
58 | struct clk_factor_masks *masks = factor->masks; | ||
59 | unsigned int val, num, den; | ||
60 | |||
61 | val = readl_relaxed(factor->base); | ||
62 | |||
63 | /* calculate numerator */ | ||
64 | num = (val >> masks->num_shift) & masks->num_mask; | ||
65 | |||
66 | /* calculate denominator */ | ||
67 | den = (val >> masks->den_shift) & masks->num_mask; | ||
68 | |||
69 | if (!den) | ||
70 | return 0; | ||
71 | |||
72 | return (((parent_rate / 10000) * den) / | ||
73 | (num * factor->masks->factor)) * 10000; | ||
74 | } | ||
75 | |||
76 | /* Configures new clock rate*/ | ||
77 | static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, | ||
78 | unsigned long prate) | ||
79 | { | ||
80 | struct clk_factor *factor = to_clk_factor(hw); | ||
81 | struct clk_factor_masks *masks = factor->masks; | ||
82 | int i; | ||
83 | unsigned long val; | ||
84 | unsigned long prev_rate, rate = 0; | ||
85 | |||
86 | for (i = 0; i < factor->ftbl_cnt; i++) { | ||
87 | prev_rate = rate; | ||
88 | rate = (((prate / 10000) * factor->ftbl[i].num) / | ||
89 | (factor->ftbl[i].den * factor->masks->factor)) * 10000; | ||
90 | if (rate > drate) | ||
91 | break; | ||
92 | } | ||
93 | if (i > 0) | ||
94 | i--; | ||
95 | |||
96 | val = readl_relaxed(factor->base); | ||
97 | |||
98 | val &= ~(masks->num_mask << masks->num_shift); | ||
99 | val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift; | ||
100 | |||
101 | val &= ~(masks->den_mask << masks->den_shift); | ||
102 | val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift; | ||
103 | |||
104 | writel_relaxed(val, factor->base); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static struct clk_ops clk_factor_ops = { | ||
110 | .recalc_rate = clk_factor_recalc_rate, | ||
111 | .round_rate = clk_factor_round_rate, | ||
112 | .set_rate = clk_factor_set_rate, | ||
113 | }; | ||
114 | |||
115 | struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, | ||
116 | unsigned long flags, void __iomem *base, | ||
117 | struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl, | ||
118 | unsigned int ftbl_cnt) | ||
119 | { | ||
120 | struct clk_factor *factor; | ||
121 | struct clk_init_data init; | ||
122 | struct clk *clk; | ||
123 | |||
124 | if (!masks) { | ||
125 | pr_err("%s: must pass a clk_factor_mask\n", __func__); | ||
126 | return ERR_PTR(-EINVAL); | ||
127 | } | ||
128 | |||
129 | factor = kzalloc(sizeof(*factor), GFP_KERNEL); | ||
130 | if (!factor) { | ||
131 | pr_err("%s: could not allocate factor clk\n", __func__); | ||
132 | return ERR_PTR(-ENOMEM); | ||
133 | } | ||
134 | |||
135 | /* struct clk_aux assignments */ | ||
136 | factor->base = base; | ||
137 | factor->masks = masks; | ||
138 | factor->ftbl = ftbl; | ||
139 | factor->ftbl_cnt = ftbl_cnt; | ||
140 | factor->hw.init = &init; | ||
141 | |||
142 | init.name = name; | ||
143 | init.ops = &clk_factor_ops; | ||
144 | init.flags = flags; | ||
145 | init.parent_names = &parent_name; | ||
146 | init.num_parents = 1; | ||
147 | |||
148 | clk = clk_register(NULL, &factor->hw); | ||
149 | if (IS_ERR_OR_NULL(clk)) | ||
150 | kfree(factor); | ||
151 | |||
152 | return clk; | ||
153 | } | ||
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c new file mode 100644 index 000000000000..ade435820c7e --- /dev/null +++ b/drivers/clk/mmp/clk-mmp2.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * mmp2 clock framework source file | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * Chao Xie <xiechao.mail@gmail.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/err.h> | ||
18 | |||
19 | #include <mach/addr-map.h> | ||
20 | |||
21 | #include "clk.h" | ||
22 | |||
23 | #define APBC_RTC 0x0 | ||
24 | #define APBC_TWSI0 0x4 | ||
25 | #define APBC_TWSI1 0x8 | ||
26 | #define APBC_TWSI2 0xc | ||
27 | #define APBC_TWSI3 0x10 | ||
28 | #define APBC_TWSI4 0x7c | ||
29 | #define APBC_TWSI5 0x80 | ||
30 | #define APBC_KPC 0x18 | ||
31 | #define APBC_UART0 0x2c | ||
32 | #define APBC_UART1 0x30 | ||
33 | #define APBC_UART2 0x34 | ||
34 | #define APBC_UART3 0x88 | ||
35 | #define APBC_GPIO 0x38 | ||
36 | #define APBC_PWM0 0x3c | ||
37 | #define APBC_PWM1 0x40 | ||
38 | #define APBC_PWM2 0x44 | ||
39 | #define APBC_PWM3 0x48 | ||
40 | #define APBC_SSP0 0x50 | ||
41 | #define APBC_SSP1 0x54 | ||
42 | #define APBC_SSP2 0x58 | ||
43 | #define APBC_SSP3 0x5c | ||
44 | #define APMU_SDH0 0x54 | ||
45 | #define APMU_SDH1 0x58 | ||
46 | #define APMU_SDH2 0xe8 | ||
47 | #define APMU_SDH3 0xec | ||
48 | #define APMU_USB 0x5c | ||
49 | #define APMU_DISP0 0x4c | ||
50 | #define APMU_DISP1 0x110 | ||
51 | #define APMU_CCIC0 0x50 | ||
52 | #define APMU_CCIC1 0xf4 | ||
53 | #define MPMU_UART_PLL 0x14 | ||
54 | |||
55 | static DEFINE_SPINLOCK(clk_lock); | ||
56 | |||
57 | static struct clk_factor_masks uart_factor_masks = { | ||
58 | .factor = 2, | ||
59 | .num_mask = 0x1fff, | ||
60 | .den_mask = 0x1fff, | ||
61 | .num_shift = 16, | ||
62 | .den_shift = 0, | ||
63 | }; | ||
64 | |||
65 | static struct clk_factor_tbl uart_factor_tbl[] = { | ||
66 | {.num = 14634, .den = 2165}, /*14.745MHZ */ | ||
67 | {.num = 3521, .den = 689}, /*19.23MHZ */ | ||
68 | {.num = 9679, .den = 5728}, /*58.9824MHZ */ | ||
69 | {.num = 15850, .den = 9451}, /*59.429MHZ */ | ||
70 | }; | ||
71 | |||
72 | static const char *uart_parent[] = {"uart_pll", "vctcxo"}; | ||
73 | static const char *ssp_parent[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; | ||
74 | static const char *sdh_parent[] = {"pll1_4", "pll2", "usb_pll", "pll1"}; | ||
75 | static const char *disp_parent[] = {"pll1", "pll1_16", "pll2", "vctcxo"}; | ||
76 | static const char *ccic_parent[] = {"pll1_2", "pll1_16", "vctcxo"}; | ||
77 | |||
78 | void __init mmp2_clk_init(void) | ||
79 | { | ||
80 | struct clk *clk; | ||
81 | struct clk *vctcxo; | ||
82 | void __iomem *mpmu_base; | ||
83 | void __iomem *apmu_base; | ||
84 | void __iomem *apbc_base; | ||
85 | |||
86 | mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K); | ||
87 | if (mpmu_base == NULL) { | ||
88 | pr_err("error to ioremap MPMU base\n"); | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K); | ||
93 | if (apmu_base == NULL) { | ||
94 | pr_err("error to ioremap APMU base\n"); | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K); | ||
99 | if (apbc_base == NULL) { | ||
100 | pr_err("error to ioremap APBC base\n"); | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); | ||
105 | clk_register_clkdev(clk, "clk32", NULL); | ||
106 | |||
107 | vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, | ||
108 | 26000000); | ||
109 | clk_register_clkdev(vctcxo, "vctcxo", NULL); | ||
110 | |||
111 | clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, | ||
112 | 800000000); | ||
113 | clk_register_clkdev(clk, "pll1", NULL); | ||
114 | |||
115 | clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, CLK_IS_ROOT, | ||
116 | 480000000); | ||
117 | clk_register_clkdev(clk, "usb_pll", NULL); | ||
118 | |||
119 | clk = clk_register_fixed_rate(NULL, "pll2", NULL, CLK_IS_ROOT, | ||
120 | 960000000); | ||
121 | clk_register_clkdev(clk, "pll2", NULL); | ||
122 | |||
123 | clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", | ||
124 | CLK_SET_RATE_PARENT, 1, 2); | ||
125 | clk_register_clkdev(clk, "pll1_2", NULL); | ||
126 | |||
127 | clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2", | ||
128 | CLK_SET_RATE_PARENT, 1, 2); | ||
129 | clk_register_clkdev(clk, "pll1_4", NULL); | ||
130 | |||
131 | clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4", | ||
132 | CLK_SET_RATE_PARENT, 1, 2); | ||
133 | clk_register_clkdev(clk, "pll1_8", NULL); | ||
134 | |||
135 | clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8", | ||
136 | CLK_SET_RATE_PARENT, 1, 2); | ||
137 | clk_register_clkdev(clk, "pll1_16", NULL); | ||
138 | |||
139 | clk = clk_register_fixed_factor(NULL, "pll1_20", "pll1_4", | ||
140 | CLK_SET_RATE_PARENT, 1, 5); | ||
141 | clk_register_clkdev(clk, "pll1_20", NULL); | ||
142 | |||
143 | clk = clk_register_fixed_factor(NULL, "pll1_3", "pll1", | ||
144 | CLK_SET_RATE_PARENT, 1, 3); | ||
145 | clk_register_clkdev(clk, "pll1_3", NULL); | ||
146 | |||
147 | clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_3", | ||
148 | CLK_SET_RATE_PARENT, 1, 2); | ||
149 | clk_register_clkdev(clk, "pll1_6", NULL); | ||
150 | |||
151 | clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6", | ||
152 | CLK_SET_RATE_PARENT, 1, 2); | ||
153 | clk_register_clkdev(clk, "pll1_12", NULL); | ||
154 | |||
155 | clk = clk_register_fixed_factor(NULL, "pll2_2", "pll2", | ||
156 | CLK_SET_RATE_PARENT, 1, 2); | ||
157 | clk_register_clkdev(clk, "pll2_2", NULL); | ||
158 | |||
159 | clk = clk_register_fixed_factor(NULL, "pll2_4", "pll2_2", | ||
160 | CLK_SET_RATE_PARENT, 1, 2); | ||
161 | clk_register_clkdev(clk, "pll2_4", NULL); | ||
162 | |||
163 | clk = clk_register_fixed_factor(NULL, "pll2_8", "pll2_4", | ||
164 | CLK_SET_RATE_PARENT, 1, 2); | ||
165 | clk_register_clkdev(clk, "pll2_8", NULL); | ||
166 | |||
167 | clk = clk_register_fixed_factor(NULL, "pll2_16", "pll2_8", | ||
168 | CLK_SET_RATE_PARENT, 1, 2); | ||
169 | clk_register_clkdev(clk, "pll2_16", NULL); | ||
170 | |||
171 | clk = clk_register_fixed_factor(NULL, "pll2_3", "pll2", | ||
172 | CLK_SET_RATE_PARENT, 1, 3); | ||
173 | clk_register_clkdev(clk, "pll2_3", NULL); | ||
174 | |||
175 | clk = clk_register_fixed_factor(NULL, "pll2_6", "pll2_3", | ||
176 | CLK_SET_RATE_PARENT, 1, 2); | ||
177 | clk_register_clkdev(clk, "pll2_6", NULL); | ||
178 | |||
179 | clk = clk_register_fixed_factor(NULL, "pll2_12", "pll2_6", | ||
180 | CLK_SET_RATE_PARENT, 1, 2); | ||
181 | clk_register_clkdev(clk, "pll2_12", NULL); | ||
182 | |||
183 | clk = clk_register_fixed_factor(NULL, "vctcxo_2", "vctcxo", | ||
184 | CLK_SET_RATE_PARENT, 1, 2); | ||
185 | clk_register_clkdev(clk, "vctcxo_2", NULL); | ||
186 | |||
187 | clk = clk_register_fixed_factor(NULL, "vctcxo_4", "vctcxo_2", | ||
188 | CLK_SET_RATE_PARENT, 1, 2); | ||
189 | clk_register_clkdev(clk, "vctcxo_4", NULL); | ||
190 | |||
191 | clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0, | ||
192 | mpmu_base + MPMU_UART_PLL, | ||
193 | &uart_factor_masks, uart_factor_tbl, | ||
194 | ARRAY_SIZE(uart_factor_tbl)); | ||
195 | clk_set_rate(clk, 14745600); | ||
196 | clk_register_clkdev(clk, "uart_pll", NULL); | ||
197 | |||
198 | clk = mmp_clk_register_apbc("twsi0", "vctcxo", | ||
199 | apbc_base + APBC_TWSI0, 10, 0, &clk_lock); | ||
200 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0"); | ||
201 | |||
202 | clk = mmp_clk_register_apbc("twsi1", "vctcxo", | ||
203 | apbc_base + APBC_TWSI1, 10, 0, &clk_lock); | ||
204 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1"); | ||
205 | |||
206 | clk = mmp_clk_register_apbc("twsi2", "vctcxo", | ||
207 | apbc_base + APBC_TWSI2, 10, 0, &clk_lock); | ||
208 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.2"); | ||
209 | |||
210 | clk = mmp_clk_register_apbc("twsi3", "vctcxo", | ||
211 | apbc_base + APBC_TWSI3, 10, 0, &clk_lock); | ||
212 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.3"); | ||
213 | |||
214 | clk = mmp_clk_register_apbc("twsi4", "vctcxo", | ||
215 | apbc_base + APBC_TWSI4, 10, 0, &clk_lock); | ||
216 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.4"); | ||
217 | |||
218 | clk = mmp_clk_register_apbc("twsi5", "vctcxo", | ||
219 | apbc_base + APBC_TWSI5, 10, 0, &clk_lock); | ||
220 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.5"); | ||
221 | |||
222 | clk = mmp_clk_register_apbc("gpio", "vctcxo", | ||
223 | apbc_base + APBC_GPIO, 10, 0, &clk_lock); | ||
224 | clk_register_clkdev(clk, NULL, "pxa-gpio"); | ||
225 | |||
226 | clk = mmp_clk_register_apbc("kpc", "clk32", | ||
227 | apbc_base + APBC_KPC, 10, 0, &clk_lock); | ||
228 | clk_register_clkdev(clk, NULL, "pxa27x-keypad"); | ||
229 | |||
230 | clk = mmp_clk_register_apbc("rtc", "clk32", | ||
231 | apbc_base + APBC_RTC, 10, 0, &clk_lock); | ||
232 | clk_register_clkdev(clk, NULL, "mmp-rtc"); | ||
233 | |||
234 | clk = mmp_clk_register_apbc("pwm0", "vctcxo", | ||
235 | apbc_base + APBC_PWM0, 10, 0, &clk_lock); | ||
236 | clk_register_clkdev(clk, NULL, "mmp2-pwm.0"); | ||
237 | |||
238 | clk = mmp_clk_register_apbc("pwm1", "vctcxo", | ||
239 | apbc_base + APBC_PWM1, 10, 0, &clk_lock); | ||
240 | clk_register_clkdev(clk, NULL, "mmp2-pwm.1"); | ||
241 | |||
242 | clk = mmp_clk_register_apbc("pwm2", "vctcxo", | ||
243 | apbc_base + APBC_PWM2, 10, 0, &clk_lock); | ||
244 | clk_register_clkdev(clk, NULL, "mmp2-pwm.2"); | ||
245 | |||
246 | clk = mmp_clk_register_apbc("pwm3", "vctcxo", | ||
247 | apbc_base + APBC_PWM3, 10, 0, &clk_lock); | ||
248 | clk_register_clkdev(clk, NULL, "mmp2-pwm.3"); | ||
249 | |||
250 | clk = clk_register_mux(NULL, "uart0_mux", uart_parent, | ||
251 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
252 | apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); | ||
253 | clk_set_parent(clk, vctcxo); | ||
254 | clk_register_clkdev(clk, "uart_mux.0", NULL); | ||
255 | |||
256 | clk = mmp_clk_register_apbc("uart0", "uart0_mux", | ||
257 | apbc_base + APBC_UART0, 10, 0, &clk_lock); | ||
258 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); | ||
259 | |||
260 | clk = clk_register_mux(NULL, "uart1_mux", uart_parent, | ||
261 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
262 | apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); | ||
263 | clk_set_parent(clk, vctcxo); | ||
264 | clk_register_clkdev(clk, "uart_mux.1", NULL); | ||
265 | |||
266 | clk = mmp_clk_register_apbc("uart1", "uart1_mux", | ||
267 | apbc_base + APBC_UART1, 10, 0, &clk_lock); | ||
268 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); | ||
269 | |||
270 | clk = clk_register_mux(NULL, "uart2_mux", uart_parent, | ||
271 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
272 | apbc_base + APBC_UART2, 4, 3, 0, &clk_lock); | ||
273 | clk_set_parent(clk, vctcxo); | ||
274 | clk_register_clkdev(clk, "uart_mux.2", NULL); | ||
275 | |||
276 | clk = mmp_clk_register_apbc("uart2", "uart2_mux", | ||
277 | apbc_base + APBC_UART2, 10, 0, &clk_lock); | ||
278 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); | ||
279 | |||
280 | clk = clk_register_mux(NULL, "uart3_mux", uart_parent, | ||
281 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
282 | apbc_base + APBC_UART3, 4, 3, 0, &clk_lock); | ||
283 | clk_set_parent(clk, vctcxo); | ||
284 | clk_register_clkdev(clk, "uart_mux.3", NULL); | ||
285 | |||
286 | clk = mmp_clk_register_apbc("uart3", "uart3_mux", | ||
287 | apbc_base + APBC_UART3, 10, 0, &clk_lock); | ||
288 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.3"); | ||
289 | |||
290 | clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, | ||
291 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
292 | apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock); | ||
293 | clk_register_clkdev(clk, "uart_mux.0", NULL); | ||
294 | |||
295 | clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", | ||
296 | apbc_base + APBC_SSP0, 10, 0, &clk_lock); | ||
297 | clk_register_clkdev(clk, NULL, "mmp-ssp.0"); | ||
298 | |||
299 | clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent, | ||
300 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
301 | apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock); | ||
302 | clk_register_clkdev(clk, "ssp_mux.1", NULL); | ||
303 | |||
304 | clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", | ||
305 | apbc_base + APBC_SSP1, 10, 0, &clk_lock); | ||
306 | clk_register_clkdev(clk, NULL, "mmp-ssp.1"); | ||
307 | |||
308 | clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent, | ||
309 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
310 | apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock); | ||
311 | clk_register_clkdev(clk, "ssp_mux.2", NULL); | ||
312 | |||
313 | clk = mmp_clk_register_apbc("ssp2", "ssp2_mux", | ||
314 | apbc_base + APBC_SSP2, 10, 0, &clk_lock); | ||
315 | clk_register_clkdev(clk, NULL, "mmp-ssp.2"); | ||
316 | |||
317 | clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent, | ||
318 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
319 | apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock); | ||
320 | clk_register_clkdev(clk, "ssp_mux.3", NULL); | ||
321 | |||
322 | clk = mmp_clk_register_apbc("ssp3", "ssp3_mux", | ||
323 | apbc_base + APBC_SSP3, 10, 0, &clk_lock); | ||
324 | clk_register_clkdev(clk, NULL, "mmp-ssp.3"); | ||
325 | |||
326 | clk = clk_register_mux(NULL, "sdh_mux", sdh_parent, | ||
327 | ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, | ||
328 | apmu_base + APMU_SDH0, 8, 2, 0, &clk_lock); | ||
329 | clk_register_clkdev(clk, "sdh_mux", NULL); | ||
330 | |||
331 | clk = clk_register_divider(NULL, "sdh_div", "sdh_mux", | ||
332 | CLK_SET_RATE_PARENT, apmu_base + APMU_SDH0, | ||
333 | 10, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); | ||
334 | clk_register_clkdev(clk, "sdh_div", NULL); | ||
335 | |||
336 | clk = mmp_clk_register_apmu("sdh0", "sdh_div", apmu_base + APMU_SDH0, | ||
337 | 0x1b, &clk_lock); | ||
338 | clk_register_clkdev(clk, NULL, "sdhci-pxav3.0"); | ||
339 | |||
340 | clk = mmp_clk_register_apmu("sdh1", "sdh_div", apmu_base + APMU_SDH1, | ||
341 | 0x1b, &clk_lock); | ||
342 | clk_register_clkdev(clk, NULL, "sdhci-pxav3.1"); | ||
343 | |||
344 | clk = mmp_clk_register_apmu("sdh2", "sdh_div", apmu_base + APMU_SDH2, | ||
345 | 0x1b, &clk_lock); | ||
346 | clk_register_clkdev(clk, NULL, "sdhci-pxav3.2"); | ||
347 | |||
348 | clk = mmp_clk_register_apmu("sdh3", "sdh_div", apmu_base + APMU_SDH3, | ||
349 | 0x1b, &clk_lock); | ||
350 | clk_register_clkdev(clk, NULL, "sdhci-pxav3.3"); | ||
351 | |||
352 | clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB, | ||
353 | 0x9, &clk_lock); | ||
354 | clk_register_clkdev(clk, "usb_clk", NULL); | ||
355 | |||
356 | clk = clk_register_mux(NULL, "disp0_mux", disp_parent, | ||
357 | ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, | ||
358 | apmu_base + APMU_DISP0, 6, 2, 0, &clk_lock); | ||
359 | clk_register_clkdev(clk, "disp_mux.0", NULL); | ||
360 | |||
361 | clk = clk_register_divider(NULL, "disp0_div", "disp0_mux", | ||
362 | CLK_SET_RATE_PARENT, apmu_base + APMU_DISP0, | ||
363 | 8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); | ||
364 | clk_register_clkdev(clk, "disp_div.0", NULL); | ||
365 | |||
366 | clk = mmp_clk_register_apmu("disp0", "disp0_div", | ||
367 | apmu_base + APMU_DISP0, 0x1b, &clk_lock); | ||
368 | clk_register_clkdev(clk, NULL, "mmp-disp.0"); | ||
369 | |||
370 | clk = clk_register_divider(NULL, "disp0_sphy_div", "disp0_mux", 0, | ||
371 | apmu_base + APMU_DISP0, 15, 5, 0, &clk_lock); | ||
372 | clk_register_clkdev(clk, "disp_sphy_div.0", NULL); | ||
373 | |||
374 | clk = mmp_clk_register_apmu("disp0_sphy", "disp0_sphy_div", | ||
375 | apmu_base + APMU_DISP0, 0x1024, &clk_lock); | ||
376 | clk_register_clkdev(clk, "disp_sphy.0", NULL); | ||
377 | |||
378 | clk = clk_register_mux(NULL, "disp1_mux", disp_parent, | ||
379 | ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, | ||
380 | apmu_base + APMU_DISP1, 6, 2, 0, &clk_lock); | ||
381 | clk_register_clkdev(clk, "disp_mux.1", NULL); | ||
382 | |||
383 | clk = clk_register_divider(NULL, "disp1_div", "disp1_mux", | ||
384 | CLK_SET_RATE_PARENT, apmu_base + APMU_DISP1, | ||
385 | 8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); | ||
386 | clk_register_clkdev(clk, "disp_div.1", NULL); | ||
387 | |||
388 | clk = mmp_clk_register_apmu("disp1", "disp1_div", | ||
389 | apmu_base + APMU_DISP1, 0x1b, &clk_lock); | ||
390 | clk_register_clkdev(clk, NULL, "mmp-disp.1"); | ||
391 | |||
392 | clk = mmp_clk_register_apmu("ccic_arbiter", "vctcxo", | ||
393 | apmu_base + APMU_CCIC0, 0x1800, &clk_lock); | ||
394 | clk_register_clkdev(clk, "ccic_arbiter", NULL); | ||
395 | |||
396 | clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent, | ||
397 | ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, | ||
398 | apmu_base + APMU_CCIC0, 6, 2, 0, &clk_lock); | ||
399 | clk_register_clkdev(clk, "ccic_mux.0", NULL); | ||
400 | |||
401 | clk = clk_register_divider(NULL, "ccic0_div", "ccic0_mux", | ||
402 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, | ||
403 | 17, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); | ||
404 | clk_register_clkdev(clk, "ccic_div.0", NULL); | ||
405 | |||
406 | clk = mmp_clk_register_apmu("ccic0", "ccic0_div", | ||
407 | apmu_base + APMU_CCIC0, 0x1b, &clk_lock); | ||
408 | clk_register_clkdev(clk, "fnclk", "mmp-ccic.0"); | ||
409 | |||
410 | clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_div", | ||
411 | apmu_base + APMU_CCIC0, 0x24, &clk_lock); | ||
412 | clk_register_clkdev(clk, "phyclk", "mmp-ccic.0"); | ||
413 | |||
414 | clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_div", | ||
415 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, | ||
416 | 10, 5, 0, &clk_lock); | ||
417 | clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.0"); | ||
418 | |||
419 | clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div", | ||
420 | apmu_base + APMU_CCIC0, 0x300, &clk_lock); | ||
421 | clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0"); | ||
422 | |||
423 | clk = clk_register_mux(NULL, "ccic1_mux", ccic_parent, | ||
424 | ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, | ||
425 | apmu_base + APMU_CCIC1, 6, 2, 0, &clk_lock); | ||
426 | clk_register_clkdev(clk, "ccic_mux.1", NULL); | ||
427 | |||
428 | clk = clk_register_divider(NULL, "ccic1_div", "ccic1_mux", | ||
429 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1, | ||
430 | 16, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); | ||
431 | clk_register_clkdev(clk, "ccic_div.1", NULL); | ||
432 | |||
433 | clk = mmp_clk_register_apmu("ccic1", "ccic1_div", | ||
434 | apmu_base + APMU_CCIC1, 0x1b, &clk_lock); | ||
435 | clk_register_clkdev(clk, "fnclk", "mmp-ccic.1"); | ||
436 | |||
437 | clk = mmp_clk_register_apmu("ccic1_phy", "ccic1_div", | ||
438 | apmu_base + APMU_CCIC1, 0x24, &clk_lock); | ||
439 | clk_register_clkdev(clk, "phyclk", "mmp-ccic.1"); | ||
440 | |||
441 | clk = clk_register_divider(NULL, "ccic1_sphy_div", "ccic1_div", | ||
442 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1, | ||
443 | 10, 5, 0, &clk_lock); | ||
444 | clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.1"); | ||
445 | |||
446 | clk = mmp_clk_register_apmu("ccic1_sphy", "ccic1_sphy_div", | ||
447 | apmu_base + APMU_CCIC1, 0x300, &clk_lock); | ||
448 | clk_register_clkdev(clk, "sphyclk", "mmp-ccic.1"); | ||
449 | } | ||
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c new file mode 100644 index 000000000000..e8d036c12cbf --- /dev/null +++ b/drivers/clk/mmp/clk-pxa168.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * pxa168 clock framework source file | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * Chao Xie <xiechao.mail@gmail.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/err.h> | ||
18 | |||
19 | #include <mach/addr-map.h> | ||
20 | |||
21 | #include "clk.h" | ||
22 | |||
23 | #define APBC_RTC 0x28 | ||
24 | #define APBC_TWSI0 0x2c | ||
25 | #define APBC_KPC 0x30 | ||
26 | #define APBC_UART0 0x0 | ||
27 | #define APBC_UART1 0x4 | ||
28 | #define APBC_GPIO 0x8 | ||
29 | #define APBC_PWM0 0xc | ||
30 | #define APBC_PWM1 0x10 | ||
31 | #define APBC_PWM2 0x14 | ||
32 | #define APBC_PWM3 0x18 | ||
33 | #define APBC_SSP0 0x81c | ||
34 | #define APBC_SSP1 0x820 | ||
35 | #define APBC_SSP2 0x84c | ||
36 | #define APBC_SSP3 0x858 | ||
37 | #define APBC_SSP4 0x85c | ||
38 | #define APBC_TWSI1 0x6c | ||
39 | #define APBC_UART2 0x70 | ||
40 | #define APMU_SDH0 0x54 | ||
41 | #define APMU_SDH1 0x58 | ||
42 | #define APMU_USB 0x5c | ||
43 | #define APMU_DISP0 0x4c | ||
44 | #define APMU_CCIC0 0x50 | ||
45 | #define APMU_DFC 0x60 | ||
46 | #define MPMU_UART_PLL 0x14 | ||
47 | |||
48 | static DEFINE_SPINLOCK(clk_lock); | ||
49 | |||
50 | static struct clk_factor_masks uart_factor_masks = { | ||
51 | .factor = 2, | ||
52 | .num_mask = 0x1fff, | ||
53 | .den_mask = 0x1fff, | ||
54 | .num_shift = 16, | ||
55 | .den_shift = 0, | ||
56 | }; | ||
57 | |||
58 | static struct clk_factor_tbl uart_factor_tbl[] = { | ||
59 | {.num = 8125, .den = 1536}, /*14.745MHZ */ | ||
60 | }; | ||
61 | |||
62 | static const char *uart_parent[] = {"pll1_3_16", "uart_pll"}; | ||
63 | static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; | ||
64 | static const char *sdh_parent[] = {"pll1_12", "pll1_13"}; | ||
65 | static const char *disp_parent[] = {"pll1_2", "pll1_12"}; | ||
66 | static const char *ccic_parent[] = {"pll1_2", "pll1_12"}; | ||
67 | static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"}; | ||
68 | |||
69 | void __init pxa168_clk_init(void) | ||
70 | { | ||
71 | struct clk *clk; | ||
72 | struct clk *uart_pll; | ||
73 | void __iomem *mpmu_base; | ||
74 | void __iomem *apmu_base; | ||
75 | void __iomem *apbc_base; | ||
76 | |||
77 | mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K); | ||
78 | if (mpmu_base == NULL) { | ||
79 | pr_err("error to ioremap MPMU base\n"); | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K); | ||
84 | if (apmu_base == NULL) { | ||
85 | pr_err("error to ioremap APMU base\n"); | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K); | ||
90 | if (apbc_base == NULL) { | ||
91 | pr_err("error to ioremap APBC base\n"); | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); | ||
96 | clk_register_clkdev(clk, "clk32", NULL); | ||
97 | |||
98 | clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, | ||
99 | 26000000); | ||
100 | clk_register_clkdev(clk, "vctcxo", NULL); | ||
101 | |||
102 | clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, | ||
103 | 624000000); | ||
104 | clk_register_clkdev(clk, "pll1", NULL); | ||
105 | |||
106 | clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", | ||
107 | CLK_SET_RATE_PARENT, 1, 2); | ||
108 | clk_register_clkdev(clk, "pll1_2", NULL); | ||
109 | |||
110 | clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2", | ||
111 | CLK_SET_RATE_PARENT, 1, 2); | ||
112 | clk_register_clkdev(clk, "pll1_4", NULL); | ||
113 | |||
114 | clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4", | ||
115 | CLK_SET_RATE_PARENT, 1, 2); | ||
116 | clk_register_clkdev(clk, "pll1_8", NULL); | ||
117 | |||
118 | clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8", | ||
119 | CLK_SET_RATE_PARENT, 1, 2); | ||
120 | clk_register_clkdev(clk, "pll1_16", NULL); | ||
121 | |||
122 | clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2", | ||
123 | CLK_SET_RATE_PARENT, 1, 3); | ||
124 | clk_register_clkdev(clk, "pll1_6", NULL); | ||
125 | |||
126 | clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6", | ||
127 | CLK_SET_RATE_PARENT, 1, 2); | ||
128 | clk_register_clkdev(clk, "pll1_12", NULL); | ||
129 | |||
130 | clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12", | ||
131 | CLK_SET_RATE_PARENT, 1, 2); | ||
132 | clk_register_clkdev(clk, "pll1_24", NULL); | ||
133 | |||
134 | clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24", | ||
135 | CLK_SET_RATE_PARENT, 1, 2); | ||
136 | clk_register_clkdev(clk, "pll1_48", NULL); | ||
137 | |||
138 | clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48", | ||
139 | CLK_SET_RATE_PARENT, 1, 2); | ||
140 | clk_register_clkdev(clk, "pll1_96", NULL); | ||
141 | |||
142 | clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1", | ||
143 | CLK_SET_RATE_PARENT, 1, 13); | ||
144 | clk_register_clkdev(clk, "pll1_13", NULL); | ||
145 | |||
146 | clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1", | ||
147 | CLK_SET_RATE_PARENT, 2, 3); | ||
148 | clk_register_clkdev(clk, "pll1_13_1_5", NULL); | ||
149 | |||
150 | clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1", | ||
151 | CLK_SET_RATE_PARENT, 2, 3); | ||
152 | clk_register_clkdev(clk, "pll1_2_1_5", NULL); | ||
153 | |||
154 | clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1", | ||
155 | CLK_SET_RATE_PARENT, 3, 16); | ||
156 | clk_register_clkdev(clk, "pll1_3_16", NULL); | ||
157 | |||
158 | uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, | ||
159 | mpmu_base + MPMU_UART_PLL, | ||
160 | &uart_factor_masks, uart_factor_tbl, | ||
161 | ARRAY_SIZE(uart_factor_tbl)); | ||
162 | clk_set_rate(uart_pll, 14745600); | ||
163 | clk_register_clkdev(uart_pll, "uart_pll", NULL); | ||
164 | |||
165 | clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5", | ||
166 | apbc_base + APBC_TWSI0, 10, 0, &clk_lock); | ||
167 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0"); | ||
168 | |||
169 | clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5", | ||
170 | apbc_base + APBC_TWSI1, 10, 0, &clk_lock); | ||
171 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1"); | ||
172 | |||
173 | clk = mmp_clk_register_apbc("gpio", "vctcxo", | ||
174 | apbc_base + APBC_GPIO, 10, 0, &clk_lock); | ||
175 | clk_register_clkdev(clk, NULL, "pxa-gpio"); | ||
176 | |||
177 | clk = mmp_clk_register_apbc("kpc", "clk32", | ||
178 | apbc_base + APBC_KPC, 10, 0, &clk_lock); | ||
179 | clk_register_clkdev(clk, NULL, "pxa27x-keypad"); | ||
180 | |||
181 | clk = mmp_clk_register_apbc("rtc", "clk32", | ||
182 | apbc_base + APBC_RTC, 10, 0, &clk_lock); | ||
183 | clk_register_clkdev(clk, NULL, "sa1100-rtc"); | ||
184 | |||
185 | clk = mmp_clk_register_apbc("pwm0", "pll1_48", | ||
186 | apbc_base + APBC_PWM0, 10, 0, &clk_lock); | ||
187 | clk_register_clkdev(clk, NULL, "pxa168-pwm.0"); | ||
188 | |||
189 | clk = mmp_clk_register_apbc("pwm1", "pll1_48", | ||
190 | apbc_base + APBC_PWM1, 10, 0, &clk_lock); | ||
191 | clk_register_clkdev(clk, NULL, "pxa168-pwm.1"); | ||
192 | |||
193 | clk = mmp_clk_register_apbc("pwm2", "pll1_48", | ||
194 | apbc_base + APBC_PWM2, 10, 0, &clk_lock); | ||
195 | clk_register_clkdev(clk, NULL, "pxa168-pwm.2"); | ||
196 | |||
197 | clk = mmp_clk_register_apbc("pwm3", "pll1_48", | ||
198 | apbc_base + APBC_PWM3, 10, 0, &clk_lock); | ||
199 | clk_register_clkdev(clk, NULL, "pxa168-pwm.3"); | ||
200 | |||
201 | clk = clk_register_mux(NULL, "uart0_mux", uart_parent, | ||
202 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
203 | apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); | ||
204 | clk_set_parent(clk, uart_pll); | ||
205 | clk_register_clkdev(clk, "uart_mux.0", NULL); | ||
206 | |||
207 | clk = mmp_clk_register_apbc("uart0", "uart0_mux", | ||
208 | apbc_base + APBC_UART0, 10, 0, &clk_lock); | ||
209 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); | ||
210 | |||
211 | clk = clk_register_mux(NULL, "uart1_mux", uart_parent, | ||
212 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
213 | apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); | ||
214 | clk_set_parent(clk, uart_pll); | ||
215 | clk_register_clkdev(clk, "uart_mux.1", NULL); | ||
216 | |||
217 | clk = mmp_clk_register_apbc("uart1", "uart1_mux", | ||
218 | apbc_base + APBC_UART1, 10, 0, &clk_lock); | ||
219 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); | ||
220 | |||
221 | clk = clk_register_mux(NULL, "uart2_mux", uart_parent, | ||
222 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
223 | apbc_base + APBC_UART2, 4, 3, 0, &clk_lock); | ||
224 | clk_set_parent(clk, uart_pll); | ||
225 | clk_register_clkdev(clk, "uart_mux.2", NULL); | ||
226 | |||
227 | clk = mmp_clk_register_apbc("uart2", "uart2_mux", | ||
228 | apbc_base + APBC_UART2, 10, 0, &clk_lock); | ||
229 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); | ||
230 | |||
231 | clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, | ||
232 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
233 | apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock); | ||
234 | clk_register_clkdev(clk, "uart_mux.0", NULL); | ||
235 | |||
236 | clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", apbc_base + APBC_SSP0, | ||
237 | 10, 0, &clk_lock); | ||
238 | clk_register_clkdev(clk, NULL, "mmp-ssp.0"); | ||
239 | |||
240 | clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent, | ||
241 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
242 | apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock); | ||
243 | clk_register_clkdev(clk, "ssp_mux.1", NULL); | ||
244 | |||
245 | clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", apbc_base + APBC_SSP1, | ||
246 | 10, 0, &clk_lock); | ||
247 | clk_register_clkdev(clk, NULL, "mmp-ssp.1"); | ||
248 | |||
249 | clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent, | ||
250 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
251 | apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock); | ||
252 | clk_register_clkdev(clk, "ssp_mux.2", NULL); | ||
253 | |||
254 | clk = mmp_clk_register_apbc("ssp2", "ssp1_mux", apbc_base + APBC_SSP2, | ||
255 | 10, 0, &clk_lock); | ||
256 | clk_register_clkdev(clk, NULL, "mmp-ssp.2"); | ||
257 | |||
258 | clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent, | ||
259 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
260 | apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock); | ||
261 | clk_register_clkdev(clk, "ssp_mux.3", NULL); | ||
262 | |||
263 | clk = mmp_clk_register_apbc("ssp3", "ssp1_mux", apbc_base + APBC_SSP3, | ||
264 | 10, 0, &clk_lock); | ||
265 | clk_register_clkdev(clk, NULL, "mmp-ssp.3"); | ||
266 | |||
267 | clk = clk_register_mux(NULL, "ssp4_mux", ssp_parent, | ||
268 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
269 | apbc_base + APBC_SSP4, 4, 3, 0, &clk_lock); | ||
270 | clk_register_clkdev(clk, "ssp_mux.4", NULL); | ||
271 | |||
272 | clk = mmp_clk_register_apbc("ssp4", "ssp1_mux", apbc_base + APBC_SSP4, | ||
273 | 10, 0, &clk_lock); | ||
274 | clk_register_clkdev(clk, NULL, "mmp-ssp.4"); | ||
275 | |||
276 | clk = mmp_clk_register_apmu("dfc", "pll1_4", apmu_base + APMU_DFC, | ||
277 | 0x19b, &clk_lock); | ||
278 | clk_register_clkdev(clk, NULL, "pxa3xx-nand.0"); | ||
279 | |||
280 | clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent, | ||
281 | ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, | ||
282 | apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock); | ||
283 | clk_register_clkdev(clk, "sdh0_mux", NULL); | ||
284 | |||
285 | clk = mmp_clk_register_apmu("sdh0", "sdh_mux", apmu_base + APMU_SDH0, | ||
286 | 0x1b, &clk_lock); | ||
287 | clk_register_clkdev(clk, NULL, "sdhci-pxa.0"); | ||
288 | |||
289 | clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent, | ||
290 | ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, | ||
291 | apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock); | ||
292 | clk_register_clkdev(clk, "sdh1_mux", NULL); | ||
293 | |||
294 | clk = mmp_clk_register_apmu("sdh1", "sdh1_mux", apmu_base + APMU_SDH1, | ||
295 | 0x1b, &clk_lock); | ||
296 | clk_register_clkdev(clk, NULL, "sdhci-pxa.1"); | ||
297 | |||
298 | clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB, | ||
299 | 0x9, &clk_lock); | ||
300 | clk_register_clkdev(clk, "usb_clk", NULL); | ||
301 | |||
302 | clk = mmp_clk_register_apmu("sph", "usb_pll", apmu_base + APMU_USB, | ||
303 | 0x12, &clk_lock); | ||
304 | clk_register_clkdev(clk, "sph_clk", NULL); | ||
305 | |||
306 | clk = clk_register_mux(NULL, "disp0_mux", disp_parent, | ||
307 | ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, | ||
308 | apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock); | ||
309 | clk_register_clkdev(clk, "disp_mux.0", NULL); | ||
310 | |||
311 | clk = mmp_clk_register_apmu("disp0", "disp0_mux", | ||
312 | apmu_base + APMU_DISP0, 0x1b, &clk_lock); | ||
313 | clk_register_clkdev(clk, "fnclk", "mmp-disp.0"); | ||
314 | |||
315 | clk = mmp_clk_register_apmu("disp0_hclk", "disp0_mux", | ||
316 | apmu_base + APMU_DISP0, 0x24, &clk_lock); | ||
317 | clk_register_clkdev(clk, "hclk", "mmp-disp.0"); | ||
318 | |||
319 | clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent, | ||
320 | ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, | ||
321 | apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock); | ||
322 | clk_register_clkdev(clk, "ccic_mux.0", NULL); | ||
323 | |||
324 | clk = mmp_clk_register_apmu("ccic0", "ccic0_mux", | ||
325 | apmu_base + APMU_CCIC0, 0x1b, &clk_lock); | ||
326 | clk_register_clkdev(clk, "fnclk", "mmp-ccic.0"); | ||
327 | |||
328 | clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent, | ||
329 | ARRAY_SIZE(ccic_phy_parent), | ||
330 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, | ||
331 | 7, 1, 0, &clk_lock); | ||
332 | clk_register_clkdev(clk, "ccic_phy_mux.0", NULL); | ||
333 | |||
334 | clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux", | ||
335 | apmu_base + APMU_CCIC0, 0x24, &clk_lock); | ||
336 | clk_register_clkdev(clk, "phyclk", "mmp-ccic.0"); | ||
337 | |||
338 | clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux", | ||
339 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, | ||
340 | 10, 5, 0, &clk_lock); | ||
341 | clk_register_clkdev(clk, "sphyclk_div", NULL); | ||
342 | |||
343 | clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div", | ||
344 | apmu_base + APMU_CCIC0, 0x300, &clk_lock); | ||
345 | clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0"); | ||
346 | } | ||
diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c new file mode 100644 index 000000000000..7048c31d6e7e --- /dev/null +++ b/drivers/clk/mmp/clk-pxa910.c | |||
@@ -0,0 +1,320 @@ | |||
1 | /* | ||
2 | * pxa910 clock framework source file | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * Chao Xie <xiechao.mail@gmail.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/err.h> | ||
18 | |||
19 | #include <mach/addr-map.h> | ||
20 | |||
21 | #include "clk.h" | ||
22 | |||
23 | #define APBC_RTC 0x28 | ||
24 | #define APBC_TWSI0 0x2c | ||
25 | #define APBC_KPC 0x18 | ||
26 | #define APBC_UART0 0x0 | ||
27 | #define APBC_UART1 0x4 | ||
28 | #define APBC_GPIO 0x8 | ||
29 | #define APBC_PWM0 0xc | ||
30 | #define APBC_PWM1 0x10 | ||
31 | #define APBC_PWM2 0x14 | ||
32 | #define APBC_PWM3 0x18 | ||
33 | #define APBC_SSP0 0x1c | ||
34 | #define APBC_SSP1 0x20 | ||
35 | #define APBC_SSP2 0x4c | ||
36 | #define APBCP_TWSI1 0x28 | ||
37 | #define APBCP_UART2 0x1c | ||
38 | #define APMU_SDH0 0x54 | ||
39 | #define APMU_SDH1 0x58 | ||
40 | #define APMU_USB 0x5c | ||
41 | #define APMU_DISP0 0x4c | ||
42 | #define APMU_CCIC0 0x50 | ||
43 | #define APMU_DFC 0x60 | ||
44 | #define MPMU_UART_PLL 0x14 | ||
45 | |||
46 | static DEFINE_SPINLOCK(clk_lock); | ||
47 | |||
48 | static struct clk_factor_masks uart_factor_masks = { | ||
49 | .factor = 2, | ||
50 | .num_mask = 0x1fff, | ||
51 | .den_mask = 0x1fff, | ||
52 | .num_shift = 16, | ||
53 | .den_shift = 0, | ||
54 | }; | ||
55 | |||
56 | static struct clk_factor_tbl uart_factor_tbl[] = { | ||
57 | {.num = 8125, .den = 1536}, /*14.745MHZ */ | ||
58 | }; | ||
59 | |||
60 | static const char *uart_parent[] = {"pll1_3_16", "uart_pll"}; | ||
61 | static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; | ||
62 | static const char *sdh_parent[] = {"pll1_12", "pll1_13"}; | ||
63 | static const char *disp_parent[] = {"pll1_2", "pll1_12"}; | ||
64 | static const char *ccic_parent[] = {"pll1_2", "pll1_12"}; | ||
65 | static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"}; | ||
66 | |||
67 | void __init pxa910_clk_init(void) | ||
68 | { | ||
69 | struct clk *clk; | ||
70 | struct clk *uart_pll; | ||
71 | void __iomem *mpmu_base; | ||
72 | void __iomem *apmu_base; | ||
73 | void __iomem *apbcp_base; | ||
74 | void __iomem *apbc_base; | ||
75 | |||
76 | mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K); | ||
77 | if (mpmu_base == NULL) { | ||
78 | pr_err("error to ioremap MPMU base\n"); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K); | ||
83 | if (apmu_base == NULL) { | ||
84 | pr_err("error to ioremap APMU base\n"); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | apbcp_base = ioremap(APB_PHYS_BASE + 0x3b000, SZ_4K); | ||
89 | if (apbcp_base == NULL) { | ||
90 | pr_err("error to ioremap APBC extension base\n"); | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K); | ||
95 | if (apbc_base == NULL) { | ||
96 | pr_err("error to ioremap APBC base\n"); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); | ||
101 | clk_register_clkdev(clk, "clk32", NULL); | ||
102 | |||
103 | clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, | ||
104 | 26000000); | ||
105 | clk_register_clkdev(clk, "vctcxo", NULL); | ||
106 | |||
107 | clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, | ||
108 | 624000000); | ||
109 | clk_register_clkdev(clk, "pll1", NULL); | ||
110 | |||
111 | clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", | ||
112 | CLK_SET_RATE_PARENT, 1, 2); | ||
113 | clk_register_clkdev(clk, "pll1_2", NULL); | ||
114 | |||
115 | clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2", | ||
116 | CLK_SET_RATE_PARENT, 1, 2); | ||
117 | clk_register_clkdev(clk, "pll1_4", NULL); | ||
118 | |||
119 | clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4", | ||
120 | CLK_SET_RATE_PARENT, 1, 2); | ||
121 | clk_register_clkdev(clk, "pll1_8", NULL); | ||
122 | |||
123 | clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8", | ||
124 | CLK_SET_RATE_PARENT, 1, 2); | ||
125 | clk_register_clkdev(clk, "pll1_16", NULL); | ||
126 | |||
127 | clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2", | ||
128 | CLK_SET_RATE_PARENT, 1, 3); | ||
129 | clk_register_clkdev(clk, "pll1_6", NULL); | ||
130 | |||
131 | clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6", | ||
132 | CLK_SET_RATE_PARENT, 1, 2); | ||
133 | clk_register_clkdev(clk, "pll1_12", NULL); | ||
134 | |||
135 | clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12", | ||
136 | CLK_SET_RATE_PARENT, 1, 2); | ||
137 | clk_register_clkdev(clk, "pll1_24", NULL); | ||
138 | |||
139 | clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24", | ||
140 | CLK_SET_RATE_PARENT, 1, 2); | ||
141 | clk_register_clkdev(clk, "pll1_48", NULL); | ||
142 | |||
143 | clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48", | ||
144 | CLK_SET_RATE_PARENT, 1, 2); | ||
145 | clk_register_clkdev(clk, "pll1_96", NULL); | ||
146 | |||
147 | clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1", | ||
148 | CLK_SET_RATE_PARENT, 1, 13); | ||
149 | clk_register_clkdev(clk, "pll1_13", NULL); | ||
150 | |||
151 | clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1", | ||
152 | CLK_SET_RATE_PARENT, 2, 3); | ||
153 | clk_register_clkdev(clk, "pll1_13_1_5", NULL); | ||
154 | |||
155 | clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1", | ||
156 | CLK_SET_RATE_PARENT, 2, 3); | ||
157 | clk_register_clkdev(clk, "pll1_2_1_5", NULL); | ||
158 | |||
159 | clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1", | ||
160 | CLK_SET_RATE_PARENT, 3, 16); | ||
161 | clk_register_clkdev(clk, "pll1_3_16", NULL); | ||
162 | |||
163 | uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, | ||
164 | mpmu_base + MPMU_UART_PLL, | ||
165 | &uart_factor_masks, uart_factor_tbl, | ||
166 | ARRAY_SIZE(uart_factor_tbl)); | ||
167 | clk_set_rate(uart_pll, 14745600); | ||
168 | clk_register_clkdev(uart_pll, "uart_pll", NULL); | ||
169 | |||
170 | clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5", | ||
171 | apbc_base + APBC_TWSI0, 10, 0, &clk_lock); | ||
172 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0"); | ||
173 | |||
174 | clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5", | ||
175 | apbcp_base + APBCP_TWSI1, 10, 0, &clk_lock); | ||
176 | clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1"); | ||
177 | |||
178 | clk = mmp_clk_register_apbc("gpio", "vctcxo", | ||
179 | apbc_base + APBC_GPIO, 10, 0, &clk_lock); | ||
180 | clk_register_clkdev(clk, NULL, "pxa-gpio"); | ||
181 | |||
182 | clk = mmp_clk_register_apbc("kpc", "clk32", | ||
183 | apbc_base + APBC_KPC, 10, 0, &clk_lock); | ||
184 | clk_register_clkdev(clk, NULL, "pxa27x-keypad"); | ||
185 | |||
186 | clk = mmp_clk_register_apbc("rtc", "clk32", | ||
187 | apbc_base + APBC_RTC, 10, 0, &clk_lock); | ||
188 | clk_register_clkdev(clk, NULL, "sa1100-rtc"); | ||
189 | |||
190 | clk = mmp_clk_register_apbc("pwm0", "pll1_48", | ||
191 | apbc_base + APBC_PWM0, 10, 0, &clk_lock); | ||
192 | clk_register_clkdev(clk, NULL, "pxa910-pwm.0"); | ||
193 | |||
194 | clk = mmp_clk_register_apbc("pwm1", "pll1_48", | ||
195 | apbc_base + APBC_PWM1, 10, 0, &clk_lock); | ||
196 | clk_register_clkdev(clk, NULL, "pxa910-pwm.1"); | ||
197 | |||
198 | clk = mmp_clk_register_apbc("pwm2", "pll1_48", | ||
199 | apbc_base + APBC_PWM2, 10, 0, &clk_lock); | ||
200 | clk_register_clkdev(clk, NULL, "pxa910-pwm.2"); | ||
201 | |||
202 | clk = mmp_clk_register_apbc("pwm3", "pll1_48", | ||
203 | apbc_base + APBC_PWM3, 10, 0, &clk_lock); | ||
204 | clk_register_clkdev(clk, NULL, "pxa910-pwm.3"); | ||
205 | |||
206 | clk = clk_register_mux(NULL, "uart0_mux", uart_parent, | ||
207 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
208 | apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); | ||
209 | clk_set_parent(clk, uart_pll); | ||
210 | clk_register_clkdev(clk, "uart_mux.0", NULL); | ||
211 | |||
212 | clk = mmp_clk_register_apbc("uart0", "uart0_mux", | ||
213 | apbc_base + APBC_UART0, 10, 0, &clk_lock); | ||
214 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); | ||
215 | |||
216 | clk = clk_register_mux(NULL, "uart1_mux", uart_parent, | ||
217 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
218 | apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); | ||
219 | clk_set_parent(clk, uart_pll); | ||
220 | clk_register_clkdev(clk, "uart_mux.1", NULL); | ||
221 | |||
222 | clk = mmp_clk_register_apbc("uart1", "uart1_mux", | ||
223 | apbc_base + APBC_UART1, 10, 0, &clk_lock); | ||
224 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); | ||
225 | |||
226 | clk = clk_register_mux(NULL, "uart2_mux", uart_parent, | ||
227 | ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, | ||
228 | apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock); | ||
229 | clk_set_parent(clk, uart_pll); | ||
230 | clk_register_clkdev(clk, "uart_mux.2", NULL); | ||
231 | |||
232 | clk = mmp_clk_register_apbc("uart2", "uart2_mux", | ||
233 | apbcp_base + APBCP_UART2, 10, 0, &clk_lock); | ||
234 | clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); | ||
235 | |||
236 | clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, | ||
237 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
238 | apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock); | ||
239 | clk_register_clkdev(clk, "uart_mux.0", NULL); | ||
240 | |||
241 | clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", | ||
242 | apbc_base + APBC_SSP0, 10, 0, &clk_lock); | ||
243 | clk_register_clkdev(clk, NULL, "mmp-ssp.0"); | ||
244 | |||
245 | clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent, | ||
246 | ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, | ||
247 | apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock); | ||
248 | clk_register_clkdev(clk, "ssp_mux.1", NULL); | ||
249 | |||
250 | clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", | ||
251 | apbc_base + APBC_SSP1, 10, 0, &clk_lock); | ||
252 | clk_register_clkdev(clk, NULL, "mmp-ssp.1"); | ||
253 | |||
254 | clk = mmp_clk_register_apmu("dfc", "pll1_4", | ||
255 | apmu_base + APMU_DFC, 0x19b, &clk_lock); | ||
256 | clk_register_clkdev(clk, NULL, "pxa3xx-nand.0"); | ||
257 | |||
258 | clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent, | ||
259 | ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, | ||
260 | apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock); | ||
261 | clk_register_clkdev(clk, "sdh0_mux", NULL); | ||
262 | |||
263 | clk = mmp_clk_register_apmu("sdh0", "sdh_mux", | ||
264 | apmu_base + APMU_SDH0, 0x1b, &clk_lock); | ||
265 | clk_register_clkdev(clk, NULL, "sdhci-pxa.0"); | ||
266 | |||
267 | clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent, | ||
268 | ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, | ||
269 | apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock); | ||
270 | clk_register_clkdev(clk, "sdh1_mux", NULL); | ||
271 | |||
272 | clk = mmp_clk_register_apmu("sdh1", "sdh1_mux", | ||
273 | apmu_base + APMU_SDH1, 0x1b, &clk_lock); | ||
274 | clk_register_clkdev(clk, NULL, "sdhci-pxa.1"); | ||
275 | |||
276 | clk = mmp_clk_register_apmu("usb", "usb_pll", | ||
277 | apmu_base + APMU_USB, 0x9, &clk_lock); | ||
278 | clk_register_clkdev(clk, "usb_clk", NULL); | ||
279 | |||
280 | clk = mmp_clk_register_apmu("sph", "usb_pll", | ||
281 | apmu_base + APMU_USB, 0x12, &clk_lock); | ||
282 | clk_register_clkdev(clk, "sph_clk", NULL); | ||
283 | |||
284 | clk = clk_register_mux(NULL, "disp0_mux", disp_parent, | ||
285 | ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, | ||
286 | apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock); | ||
287 | clk_register_clkdev(clk, "disp_mux.0", NULL); | ||
288 | |||
289 | clk = mmp_clk_register_apmu("disp0", "disp0_mux", | ||
290 | apmu_base + APMU_DISP0, 0x1b, &clk_lock); | ||
291 | clk_register_clkdev(clk, NULL, "mmp-disp.0"); | ||
292 | |||
293 | clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent, | ||
294 | ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, | ||
295 | apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock); | ||
296 | clk_register_clkdev(clk, "ccic_mux.0", NULL); | ||
297 | |||
298 | clk = mmp_clk_register_apmu("ccic0", "ccic0_mux", | ||
299 | apmu_base + APMU_CCIC0, 0x1b, &clk_lock); | ||
300 | clk_register_clkdev(clk, "fnclk", "mmp-ccic.0"); | ||
301 | |||
302 | clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent, | ||
303 | ARRAY_SIZE(ccic_phy_parent), | ||
304 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, | ||
305 | 7, 1, 0, &clk_lock); | ||
306 | clk_register_clkdev(clk, "ccic_phy_mux.0", NULL); | ||
307 | |||
308 | clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux", | ||
309 | apmu_base + APMU_CCIC0, 0x24, &clk_lock); | ||
310 | clk_register_clkdev(clk, "phyclk", "mmp-ccic.0"); | ||
311 | |||
312 | clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux", | ||
313 | CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, | ||
314 | 10, 5, 0, &clk_lock); | ||
315 | clk_register_clkdev(clk, "sphyclk_div", NULL); | ||
316 | |||
317 | clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div", | ||
318 | apmu_base + APMU_CCIC0, 0x300, &clk_lock); | ||
319 | clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0"); | ||
320 | } | ||
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h new file mode 100644 index 000000000000..ab86dd4a416a --- /dev/null +++ b/drivers/clk/mmp/clk.h | |||
@@ -0,0 +1,35 @@ | |||
1 | #ifndef __MACH_MMP_CLK_H | ||
2 | #define __MACH_MMP_CLK_H | ||
3 | |||
4 | #include <linux/clk-provider.h> | ||
5 | #include <linux/clkdev.h> | ||
6 | |||
7 | #define APBC_NO_BUS_CTRL BIT(0) | ||
8 | #define APBC_POWER_CTRL BIT(1) | ||
9 | |||
10 | struct clk_factor_masks { | ||
11 | unsigned int factor; | ||
12 | unsigned int num_mask; | ||
13 | unsigned int den_mask; | ||
14 | unsigned int num_shift; | ||
15 | unsigned int den_shift; | ||
16 | }; | ||
17 | |||
18 | struct clk_factor_tbl { | ||
19 | unsigned int num; | ||
20 | unsigned int den; | ||
21 | }; | ||
22 | |||
23 | extern struct clk *mmp_clk_register_pll2(const char *name, | ||
24 | const char *parent_name, unsigned long flags); | ||
25 | extern struct clk *mmp_clk_register_apbc(const char *name, | ||
26 | const char *parent_name, void __iomem *base, | ||
27 | unsigned int delay, unsigned int apbc_flags, spinlock_t *lock); | ||
28 | extern struct clk *mmp_clk_register_apmu(const char *name, | ||
29 | const char *parent_name, void __iomem *base, u32 enable_mask, | ||
30 | spinlock_t *lock); | ||
31 | extern struct clk *mmp_clk_register_factor(const char *name, | ||
32 | const char *parent_name, unsigned long flags, | ||
33 | void __iomem *base, struct clk_factor_masks *masks, | ||
34 | struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt); | ||
35 | #endif | ||
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c index 844043ad0fe4..9f6d15546cbe 100644 --- a/drivers/clk/mxs/clk-imx23.c +++ b/drivers/clk/mxs/clk-imx23.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/of.h> | ||
17 | #include <mach/common.h> | 18 | #include <mach/common.h> |
18 | #include <mach/mx23.h> | 19 | #include <mach/mx23.h> |
19 | #include "clk.h" | 20 | #include "clk.h" |
@@ -71,44 +72,6 @@ static void __init clk_misc_init(void) | |||
71 | __mxs_setl(30 << BP_FRAC_IOFRAC, FRAC); | 72 | __mxs_setl(30 << BP_FRAC_IOFRAC, FRAC); |
72 | } | 73 | } |
73 | 74 | ||
74 | static struct clk_lookup uart_lookups[] = { | ||
75 | { .dev_id = "duart", }, | ||
76 | { .dev_id = "mxs-auart.0", }, | ||
77 | { .dev_id = "mxs-auart.1", }, | ||
78 | { .dev_id = "8006c000.serial", }, | ||
79 | { .dev_id = "8006e000.serial", }, | ||
80 | { .dev_id = "80070000.serial", }, | ||
81 | }; | ||
82 | |||
83 | static struct clk_lookup hbus_lookups[] = { | ||
84 | { .dev_id = "imx23-dma-apbh", }, | ||
85 | { .dev_id = "80004000.dma-apbh", }, | ||
86 | }; | ||
87 | |||
88 | static struct clk_lookup xbus_lookups[] = { | ||
89 | { .dev_id = "duart", .con_id = "apb_pclk"}, | ||
90 | { .dev_id = "80070000.serial", .con_id = "apb_pclk"}, | ||
91 | { .dev_id = "imx23-dma-apbx", }, | ||
92 | { .dev_id = "80024000.dma-apbx", }, | ||
93 | }; | ||
94 | |||
95 | static struct clk_lookup ssp_lookups[] = { | ||
96 | { .dev_id = "imx23-mmc.0", }, | ||
97 | { .dev_id = "imx23-mmc.1", }, | ||
98 | { .dev_id = "80010000.ssp", }, | ||
99 | { .dev_id = "80034000.ssp", }, | ||
100 | }; | ||
101 | |||
102 | static struct clk_lookup lcdif_lookups[] = { | ||
103 | { .dev_id = "imx23-fb", }, | ||
104 | { .dev_id = "80030000.lcdif", }, | ||
105 | }; | ||
106 | |||
107 | static struct clk_lookup gpmi_lookups[] = { | ||
108 | { .dev_id = "imx23-gpmi-nand", }, | ||
109 | { .dev_id = "8000c000.gpmi-nand", }, | ||
110 | }; | ||
111 | |||
112 | static const char *sel_pll[] __initconst = { "pll", "ref_xtal", }; | 75 | static const char *sel_pll[] __initconst = { "pll", "ref_xtal", }; |
113 | static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; | 76 | static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; |
114 | static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; | 77 | static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; |
@@ -127,6 +90,7 @@ enum imx23_clk { | |||
127 | }; | 90 | }; |
128 | 91 | ||
129 | static struct clk *clks[clk_max]; | 92 | static struct clk *clks[clk_max]; |
93 | static struct clk_onecell_data clk_data; | ||
130 | 94 | ||
131 | static enum imx23_clk clks_init_on[] __initdata = { | 95 | static enum imx23_clk clks_init_on[] __initdata = { |
132 | cpu, hbus, xbus, emi, uart, | 96 | cpu, hbus, xbus, emi, uart, |
@@ -134,6 +98,7 @@ static enum imx23_clk clks_init_on[] __initdata = { | |||
134 | 98 | ||
135 | int __init mx23_clocks_init(void) | 99 | int __init mx23_clocks_init(void) |
136 | { | 100 | { |
101 | struct device_node *np; | ||
137 | int i; | 102 | int i; |
138 | 103 | ||
139 | clk_misc_init(); | 104 | clk_misc_init(); |
@@ -188,14 +153,14 @@ int __init mx23_clocks_init(void) | |||
188 | return PTR_ERR(clks[i]); | 153 | return PTR_ERR(clks[i]); |
189 | } | 154 | } |
190 | 155 | ||
156 | np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl"); | ||
157 | if (np) { | ||
158 | clk_data.clks = clks; | ||
159 | clk_data.clk_num = ARRAY_SIZE(clks); | ||
160 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
161 | } | ||
162 | |||
191 | clk_register_clkdev(clks[clk32k], NULL, "timrot"); | 163 | clk_register_clkdev(clks[clk32k], NULL, "timrot"); |
192 | clk_register_clkdev(clks[pwm], NULL, "80064000.pwm"); | ||
193 | clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); | ||
194 | clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); | ||
195 | clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); | ||
196 | clk_register_clkdevs(clks[ssp], ssp_lookups, ARRAY_SIZE(ssp_lookups)); | ||
197 | clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); | ||
198 | clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); | ||
199 | 164 | ||
200 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) | 165 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) |
201 | clk_prepare_enable(clks[clks_init_on[i]]); | 166 | clk_prepare_enable(clks[clks_init_on[i]]); |
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index e3aab67b3eb7..613e76f3758e 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/of.h> | ||
17 | #include <mach/common.h> | 18 | #include <mach/common.h> |
18 | #include <mach/mx28.h> | 19 | #include <mach/mx28.h> |
19 | #include "clk.h" | 20 | #include "clk.h" |
@@ -120,90 +121,6 @@ static void __init clk_misc_init(void) | |||
120 | writel_relaxed(val, FRAC0); | 121 | writel_relaxed(val, FRAC0); |
121 | } | 122 | } |
122 | 123 | ||
123 | static struct clk_lookup uart_lookups[] = { | ||
124 | { .dev_id = "duart", }, | ||
125 | { .dev_id = "mxs-auart.0", }, | ||
126 | { .dev_id = "mxs-auart.1", }, | ||
127 | { .dev_id = "mxs-auart.2", }, | ||
128 | { .dev_id = "mxs-auart.3", }, | ||
129 | { .dev_id = "mxs-auart.4", }, | ||
130 | { .dev_id = "8006a000.serial", }, | ||
131 | { .dev_id = "8006c000.serial", }, | ||
132 | { .dev_id = "8006e000.serial", }, | ||
133 | { .dev_id = "80070000.serial", }, | ||
134 | { .dev_id = "80072000.serial", }, | ||
135 | { .dev_id = "80074000.serial", }, | ||
136 | }; | ||
137 | |||
138 | static struct clk_lookup hbus_lookups[] = { | ||
139 | { .dev_id = "imx28-dma-apbh", }, | ||
140 | { .dev_id = "80004000.dma-apbh", }, | ||
141 | }; | ||
142 | |||
143 | static struct clk_lookup xbus_lookups[] = { | ||
144 | { .dev_id = "duart", .con_id = "apb_pclk"}, | ||
145 | { .dev_id = "80074000.serial", .con_id = "apb_pclk"}, | ||
146 | { .dev_id = "imx28-dma-apbx", }, | ||
147 | { .dev_id = "80024000.dma-apbx", }, | ||
148 | }; | ||
149 | |||
150 | static struct clk_lookup ssp0_lookups[] = { | ||
151 | { .dev_id = "imx28-mmc.0", }, | ||
152 | { .dev_id = "80010000.ssp", }, | ||
153 | }; | ||
154 | |||
155 | static struct clk_lookup ssp1_lookups[] = { | ||
156 | { .dev_id = "imx28-mmc.1", }, | ||
157 | { .dev_id = "80012000.ssp", }, | ||
158 | }; | ||
159 | |||
160 | static struct clk_lookup ssp2_lookups[] = { | ||
161 | { .dev_id = "imx28-mmc.2", }, | ||
162 | { .dev_id = "80014000.ssp", }, | ||
163 | }; | ||
164 | |||
165 | static struct clk_lookup ssp3_lookups[] = { | ||
166 | { .dev_id = "imx28-mmc.3", }, | ||
167 | { .dev_id = "80016000.ssp", }, | ||
168 | }; | ||
169 | |||
170 | static struct clk_lookup lcdif_lookups[] = { | ||
171 | { .dev_id = "imx28-fb", }, | ||
172 | { .dev_id = "80030000.lcdif", }, | ||
173 | }; | ||
174 | |||
175 | static struct clk_lookup gpmi_lookups[] = { | ||
176 | { .dev_id = "imx28-gpmi-nand", }, | ||
177 | { .dev_id = "8000c000.gpmi-nand", }, | ||
178 | }; | ||
179 | |||
180 | static struct clk_lookup fec_lookups[] = { | ||
181 | { .dev_id = "imx28-fec.0", }, | ||
182 | { .dev_id = "imx28-fec.1", }, | ||
183 | { .dev_id = "800f0000.ethernet", }, | ||
184 | { .dev_id = "800f4000.ethernet", }, | ||
185 | }; | ||
186 | |||
187 | static struct clk_lookup can0_lookups[] = { | ||
188 | { .dev_id = "flexcan.0", }, | ||
189 | { .dev_id = "80032000.can", }, | ||
190 | }; | ||
191 | |||
192 | static struct clk_lookup can1_lookups[] = { | ||
193 | { .dev_id = "flexcan.1", }, | ||
194 | { .dev_id = "80034000.can", }, | ||
195 | }; | ||
196 | |||
197 | static struct clk_lookup saif0_lookups[] = { | ||
198 | { .dev_id = "mxs-saif.0", }, | ||
199 | { .dev_id = "80042000.saif", }, | ||
200 | }; | ||
201 | |||
202 | static struct clk_lookup saif1_lookups[] = { | ||
203 | { .dev_id = "mxs-saif.1", }, | ||
204 | { .dev_id = "80046000.saif", }, | ||
205 | }; | ||
206 | |||
207 | static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; | 124 | static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; |
208 | static const char *sel_io0[] __initconst = { "ref_io0", "ref_xtal", }; | 125 | static const char *sel_io0[] __initconst = { "ref_io0", "ref_xtal", }; |
209 | static const char *sel_io1[] __initconst = { "ref_io1", "ref_xtal", }; | 126 | static const char *sel_io1[] __initconst = { "ref_io1", "ref_xtal", }; |
@@ -228,6 +145,7 @@ enum imx28_clk { | |||
228 | }; | 145 | }; |
229 | 146 | ||
230 | static struct clk *clks[clk_max]; | 147 | static struct clk *clks[clk_max]; |
148 | static struct clk_onecell_data clk_data; | ||
231 | 149 | ||
232 | static enum imx28_clk clks_init_on[] __initdata = { | 150 | static enum imx28_clk clks_init_on[] __initdata = { |
233 | cpu, hbus, xbus, emi, uart, | 151 | cpu, hbus, xbus, emi, uart, |
@@ -235,6 +153,7 @@ static enum imx28_clk clks_init_on[] __initdata = { | |||
235 | 153 | ||
236 | int __init mx28_clocks_init(void) | 154 | int __init mx28_clocks_init(void) |
237 | { | 155 | { |
156 | struct device_node *np; | ||
238 | int i; | 157 | int i; |
239 | 158 | ||
240 | clk_misc_init(); | 159 | clk_misc_init(); |
@@ -312,27 +231,15 @@ int __init mx28_clocks_init(void) | |||
312 | return PTR_ERR(clks[i]); | 231 | return PTR_ERR(clks[i]); |
313 | } | 232 | } |
314 | 233 | ||
234 | np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl"); | ||
235 | if (np) { | ||
236 | clk_data.clks = clks; | ||
237 | clk_data.clk_num = ARRAY_SIZE(clks); | ||
238 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
239 | } | ||
240 | |||
315 | clk_register_clkdev(clks[clk32k], NULL, "timrot"); | 241 | clk_register_clkdev(clks[clk32k], NULL, "timrot"); |
316 | clk_register_clkdev(clks[enet_out], NULL, "enet_out"); | 242 | clk_register_clkdev(clks[enet_out], NULL, "enet_out"); |
317 | clk_register_clkdev(clks[pwm], NULL, "80064000.pwm"); | ||
318 | clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); | ||
319 | clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); | ||
320 | clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); | ||
321 | clk_register_clkdevs(clks[ssp0], ssp0_lookups, ARRAY_SIZE(ssp0_lookups)); | ||
322 | clk_register_clkdevs(clks[ssp1], ssp1_lookups, ARRAY_SIZE(ssp1_lookups)); | ||
323 | clk_register_clkdevs(clks[ssp2], ssp2_lookups, ARRAY_SIZE(ssp2_lookups)); | ||
324 | clk_register_clkdevs(clks[ssp3], ssp3_lookups, ARRAY_SIZE(ssp3_lookups)); | ||
325 | clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); | ||
326 | clk_register_clkdevs(clks[saif0], saif0_lookups, ARRAY_SIZE(saif0_lookups)); | ||
327 | clk_register_clkdevs(clks[saif1], saif1_lookups, ARRAY_SIZE(saif1_lookups)); | ||
328 | clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); | ||
329 | clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups)); | ||
330 | clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups)); | ||
331 | clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups)); | ||
332 | clk_register_clkdev(clks[usb0_pwr], NULL, "8007c000.usbphy"); | ||
333 | clk_register_clkdev(clks[usb1_pwr], NULL, "8007e000.usbphy"); | ||
334 | clk_register_clkdev(clks[usb0], NULL, "80080000.usb"); | ||
335 | clk_register_clkdev(clks[usb1], NULL, "80090000.usb"); | ||
336 | 243 | ||
337 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) | 244 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) |
338 | clk_prepare_enable(clks[clks_init_on[i]]); | 245 | clk_prepare_enable(clks[clks_init_on[i]]); |
diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile new file mode 100644 index 000000000000..858fbfe66281 --- /dev/null +++ b/drivers/clk/ux500/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Makefile for ux500 clocks | ||
3 | # | ||
4 | |||
5 | # Clock types | ||
6 | obj-y += clk-prcc.o | ||
7 | obj-y += clk-prcmu.o | ||
8 | |||
9 | # Clock definitions | ||
10 | obj-y += u8500_clk.o | ||
11 | obj-y += u9540_clk.o | ||
12 | obj-y += u8540_clk.o | ||
diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c new file mode 100644 index 000000000000..7eee7f768355 --- /dev/null +++ b/drivers/clk/ux500/clk-prcc.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * PRCC clock implementation for ux500 platform. | ||
3 | * | ||
4 | * Copyright (C) 2012 ST-Ericsson SA | ||
5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | ||
6 | * | ||
7 | * License terms: GNU General Public License (GPL) version 2 | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk-provider.h> | ||
11 | #include <linux/clk-private.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <mach/hardware.h> | ||
17 | |||
18 | #include "clk.h" | ||
19 | |||
20 | #define PRCC_PCKEN 0x000 | ||
21 | #define PRCC_PCKDIS 0x004 | ||
22 | #define PRCC_KCKEN 0x008 | ||
23 | #define PRCC_KCKDIS 0x00C | ||
24 | #define PRCC_PCKSR 0x010 | ||
25 | #define PRCC_KCKSR 0x014 | ||
26 | |||
27 | #define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw) | ||
28 | |||
29 | struct clk_prcc { | ||
30 | struct clk_hw hw; | ||
31 | void __iomem *base; | ||
32 | u32 cg_sel; | ||
33 | int is_enabled; | ||
34 | }; | ||
35 | |||
36 | /* PRCC clock operations. */ | ||
37 | |||
38 | static int clk_prcc_pclk_enable(struct clk_hw *hw) | ||
39 | { | ||
40 | struct clk_prcc *clk = to_clk_prcc(hw); | ||
41 | |||
42 | writel(clk->cg_sel, (clk->base + PRCC_PCKEN)); | ||
43 | while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel)) | ||
44 | cpu_relax(); | ||
45 | |||
46 | clk->is_enabled = 1; | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void clk_prcc_pclk_disable(struct clk_hw *hw) | ||
51 | { | ||
52 | struct clk_prcc *clk = to_clk_prcc(hw); | ||
53 | |||
54 | writel(clk->cg_sel, (clk->base + PRCC_PCKDIS)); | ||
55 | clk->is_enabled = 0; | ||
56 | } | ||
57 | |||
58 | static int clk_prcc_kclk_enable(struct clk_hw *hw) | ||
59 | { | ||
60 | struct clk_prcc *clk = to_clk_prcc(hw); | ||
61 | |||
62 | writel(clk->cg_sel, (clk->base + PRCC_KCKEN)); | ||
63 | while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel)) | ||
64 | cpu_relax(); | ||
65 | |||
66 | clk->is_enabled = 1; | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static void clk_prcc_kclk_disable(struct clk_hw *hw) | ||
71 | { | ||
72 | struct clk_prcc *clk = to_clk_prcc(hw); | ||
73 | |||
74 | writel(clk->cg_sel, (clk->base + PRCC_KCKDIS)); | ||
75 | clk->is_enabled = 0; | ||
76 | } | ||
77 | |||
78 | static int clk_prcc_is_enabled(struct clk_hw *hw) | ||
79 | { | ||
80 | struct clk_prcc *clk = to_clk_prcc(hw); | ||
81 | return clk->is_enabled; | ||
82 | } | ||
83 | |||
84 | static struct clk_ops clk_prcc_pclk_ops = { | ||
85 | .enable = clk_prcc_pclk_enable, | ||
86 | .disable = clk_prcc_pclk_disable, | ||
87 | .is_enabled = clk_prcc_is_enabled, | ||
88 | }; | ||
89 | |||
90 | static struct clk_ops clk_prcc_kclk_ops = { | ||
91 | .enable = clk_prcc_kclk_enable, | ||
92 | .disable = clk_prcc_kclk_disable, | ||
93 | .is_enabled = clk_prcc_is_enabled, | ||
94 | }; | ||
95 | |||
96 | static struct clk *clk_reg_prcc(const char *name, | ||
97 | const char *parent_name, | ||
98 | resource_size_t phy_base, | ||
99 | u32 cg_sel, | ||
100 | unsigned long flags, | ||
101 | struct clk_ops *clk_prcc_ops) | ||
102 | { | ||
103 | struct clk_prcc *clk; | ||
104 | struct clk_init_data clk_prcc_init; | ||
105 | struct clk *clk_reg; | ||
106 | |||
107 | if (!name) { | ||
108 | pr_err("clk_prcc: %s invalid arguments passed\n", __func__); | ||
109 | return ERR_PTR(-EINVAL); | ||
110 | } | ||
111 | |||
112 | clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL); | ||
113 | if (!clk) { | ||
114 | pr_err("clk_prcc: %s could not allocate clk\n", __func__); | ||
115 | return ERR_PTR(-ENOMEM); | ||
116 | } | ||
117 | |||
118 | clk->base = ioremap(phy_base, SZ_4K); | ||
119 | if (!clk->base) | ||
120 | goto free_clk; | ||
121 | |||
122 | clk->cg_sel = cg_sel; | ||
123 | clk->is_enabled = 1; | ||
124 | |||
125 | clk_prcc_init.name = name; | ||
126 | clk_prcc_init.ops = clk_prcc_ops; | ||
127 | clk_prcc_init.flags = flags; | ||
128 | clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL); | ||
129 | clk_prcc_init.num_parents = (parent_name ? 1 : 0); | ||
130 | clk->hw.init = &clk_prcc_init; | ||
131 | |||
132 | clk_reg = clk_register(NULL, &clk->hw); | ||
133 | if (IS_ERR_OR_NULL(clk_reg)) | ||
134 | goto unmap_clk; | ||
135 | |||
136 | return clk_reg; | ||
137 | |||
138 | unmap_clk: | ||
139 | iounmap(clk->base); | ||
140 | free_clk: | ||
141 | kfree(clk); | ||
142 | pr_err("clk_prcc: %s failed to register clk\n", __func__); | ||
143 | return ERR_PTR(-ENOMEM); | ||
144 | } | ||
145 | |||
146 | struct clk *clk_reg_prcc_pclk(const char *name, | ||
147 | const char *parent_name, | ||
148 | resource_size_t phy_base, | ||
149 | u32 cg_sel, | ||
150 | unsigned long flags) | ||
151 | { | ||
152 | return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, | ||
153 | &clk_prcc_pclk_ops); | ||
154 | } | ||
155 | |||
156 | struct clk *clk_reg_prcc_kclk(const char *name, | ||
157 | const char *parent_name, | ||
158 | resource_size_t phy_base, | ||
159 | u32 cg_sel, | ||
160 | unsigned long flags) | ||
161 | { | ||
162 | return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, | ||
163 | &clk_prcc_kclk_ops); | ||
164 | } | ||
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c new file mode 100644 index 000000000000..930cdfeb47ab --- /dev/null +++ b/drivers/clk/ux500/clk-prcmu.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * PRCMU clock implementation for ux500 platform. | ||
3 | * | ||
4 | * Copyright (C) 2012 ST-Ericsson SA | ||
5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | ||
6 | * | ||
7 | * License terms: GNU General Public License (GPL) version 2 | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk-provider.h> | ||
11 | #include <linux/clk-private.h> | ||
12 | #include <linux/mfd/dbx500-prcmu.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/err.h> | ||
16 | #include "clk.h" | ||
17 | |||
18 | #define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw) | ||
19 | |||
20 | struct clk_prcmu { | ||
21 | struct clk_hw hw; | ||
22 | u8 cg_sel; | ||
23 | int is_enabled; | ||
24 | }; | ||
25 | |||
26 | /* PRCMU clock operations. */ | ||
27 | |||
28 | static int clk_prcmu_prepare(struct clk_hw *hw) | ||
29 | { | ||
30 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
31 | return prcmu_request_clock(clk->cg_sel, true); | ||
32 | } | ||
33 | |||
34 | static void clk_prcmu_unprepare(struct clk_hw *hw) | ||
35 | { | ||
36 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
37 | if (prcmu_request_clock(clk->cg_sel, false)) | ||
38 | pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, | ||
39 | hw->init->name); | ||
40 | } | ||
41 | |||
42 | static int clk_prcmu_enable(struct clk_hw *hw) | ||
43 | { | ||
44 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
45 | clk->is_enabled = 1; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static void clk_prcmu_disable(struct clk_hw *hw) | ||
50 | { | ||
51 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
52 | clk->is_enabled = 0; | ||
53 | } | ||
54 | |||
55 | static int clk_prcmu_is_enabled(struct clk_hw *hw) | ||
56 | { | ||
57 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
58 | return clk->is_enabled; | ||
59 | } | ||
60 | |||
61 | static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw, | ||
62 | unsigned long parent_rate) | ||
63 | { | ||
64 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
65 | return prcmu_clock_rate(clk->cg_sel); | ||
66 | } | ||
67 | |||
68 | static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate, | ||
69 | unsigned long *parent_rate) | ||
70 | { | ||
71 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
72 | return prcmu_round_clock_rate(clk->cg_sel, rate); | ||
73 | } | ||
74 | |||
75 | static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate, | ||
76 | unsigned long parent_rate) | ||
77 | { | ||
78 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
79 | return prcmu_set_clock_rate(clk->cg_sel, rate); | ||
80 | } | ||
81 | |||
82 | static int request_ape_opp100(bool enable) | ||
83 | { | ||
84 | static int reqs; | ||
85 | int err = 0; | ||
86 | |||
87 | if (enable) { | ||
88 | if (!reqs) | ||
89 | err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, | ||
90 | "clock", 100); | ||
91 | if (!err) | ||
92 | reqs++; | ||
93 | } else { | ||
94 | reqs--; | ||
95 | if (!reqs) | ||
96 | prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, | ||
97 | "clock"); | ||
98 | } | ||
99 | return err; | ||
100 | } | ||
101 | |||
102 | static int clk_prcmu_opp_prepare(struct clk_hw *hw) | ||
103 | { | ||
104 | int err; | ||
105 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
106 | |||
107 | err = request_ape_opp100(true); | ||
108 | if (err) { | ||
109 | pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n", | ||
110 | __func__, hw->init->name); | ||
111 | return err; | ||
112 | } | ||
113 | |||
114 | err = prcmu_request_clock(clk->cg_sel, true); | ||
115 | if (err) | ||
116 | request_ape_opp100(false); | ||
117 | |||
118 | return err; | ||
119 | } | ||
120 | |||
121 | static void clk_prcmu_opp_unprepare(struct clk_hw *hw) | ||
122 | { | ||
123 | struct clk_prcmu *clk = to_clk_prcmu(hw); | ||
124 | |||
125 | if (prcmu_request_clock(clk->cg_sel, false)) | ||
126 | goto out_error; | ||
127 | if (request_ape_opp100(false)) | ||
128 | goto out_error; | ||
129 | return; | ||
130 | |||
131 | out_error: | ||
132 | pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, | ||
133 | hw->init->name); | ||
134 | } | ||
135 | |||
136 | static struct clk_ops clk_prcmu_scalable_ops = { | ||
137 | .prepare = clk_prcmu_prepare, | ||
138 | .unprepare = clk_prcmu_unprepare, | ||
139 | .enable = clk_prcmu_enable, | ||
140 | .disable = clk_prcmu_disable, | ||
141 | .is_enabled = clk_prcmu_is_enabled, | ||
142 | .recalc_rate = clk_prcmu_recalc_rate, | ||
143 | .round_rate = clk_prcmu_round_rate, | ||
144 | .set_rate = clk_prcmu_set_rate, | ||
145 | }; | ||
146 | |||
147 | static struct clk_ops clk_prcmu_gate_ops = { | ||
148 | .prepare = clk_prcmu_prepare, | ||
149 | .unprepare = clk_prcmu_unprepare, | ||
150 | .enable = clk_prcmu_enable, | ||
151 | .disable = clk_prcmu_disable, | ||
152 | .is_enabled = clk_prcmu_is_enabled, | ||
153 | .recalc_rate = clk_prcmu_recalc_rate, | ||
154 | }; | ||
155 | |||
156 | static struct clk_ops clk_prcmu_rate_ops = { | ||
157 | .is_enabled = clk_prcmu_is_enabled, | ||
158 | .recalc_rate = clk_prcmu_recalc_rate, | ||
159 | }; | ||
160 | |||
161 | static struct clk_ops clk_prcmu_opp_gate_ops = { | ||
162 | .prepare = clk_prcmu_opp_prepare, | ||
163 | .unprepare = clk_prcmu_opp_unprepare, | ||
164 | .enable = clk_prcmu_enable, | ||
165 | .disable = clk_prcmu_disable, | ||
166 | .is_enabled = clk_prcmu_is_enabled, | ||
167 | .recalc_rate = clk_prcmu_recalc_rate, | ||
168 | }; | ||
169 | |||
170 | static struct clk *clk_reg_prcmu(const char *name, | ||
171 | const char *parent_name, | ||
172 | u8 cg_sel, | ||
173 | unsigned long rate, | ||
174 | unsigned long flags, | ||
175 | struct clk_ops *clk_prcmu_ops) | ||
176 | { | ||
177 | struct clk_prcmu *clk; | ||
178 | struct clk_init_data clk_prcmu_init; | ||
179 | struct clk *clk_reg; | ||
180 | |||
181 | if (!name) { | ||
182 | pr_err("clk_prcmu: %s invalid arguments passed\n", __func__); | ||
183 | return ERR_PTR(-EINVAL); | ||
184 | } | ||
185 | |||
186 | clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL); | ||
187 | if (!clk) { | ||
188 | pr_err("clk_prcmu: %s could not allocate clk\n", __func__); | ||
189 | return ERR_PTR(-ENOMEM); | ||
190 | } | ||
191 | |||
192 | clk->cg_sel = cg_sel; | ||
193 | clk->is_enabled = 1; | ||
194 | /* "rate" can be used for changing the initial frequency */ | ||
195 | if (rate) | ||
196 | prcmu_set_clock_rate(cg_sel, rate); | ||
197 | |||
198 | clk_prcmu_init.name = name; | ||
199 | clk_prcmu_init.ops = clk_prcmu_ops; | ||
200 | clk_prcmu_init.flags = flags; | ||
201 | clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL); | ||
202 | clk_prcmu_init.num_parents = (parent_name ? 1 : 0); | ||
203 | clk->hw.init = &clk_prcmu_init; | ||
204 | |||
205 | clk_reg = clk_register(NULL, &clk->hw); | ||
206 | if (IS_ERR_OR_NULL(clk_reg)) | ||
207 | goto free_clk; | ||
208 | |||
209 | return clk_reg; | ||
210 | |||
211 | free_clk: | ||
212 | kfree(clk); | ||
213 | pr_err("clk_prcmu: %s failed to register clk\n", __func__); | ||
214 | return ERR_PTR(-ENOMEM); | ||
215 | } | ||
216 | |||
217 | struct clk *clk_reg_prcmu_scalable(const char *name, | ||
218 | const char *parent_name, | ||
219 | u8 cg_sel, | ||
220 | unsigned long rate, | ||
221 | unsigned long flags) | ||
222 | { | ||
223 | return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, | ||
224 | &clk_prcmu_scalable_ops); | ||
225 | } | ||
226 | |||
227 | struct clk *clk_reg_prcmu_gate(const char *name, | ||
228 | const char *parent_name, | ||
229 | u8 cg_sel, | ||
230 | unsigned long flags) | ||
231 | { | ||
232 | return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, | ||
233 | &clk_prcmu_gate_ops); | ||
234 | } | ||
235 | |||
236 | struct clk *clk_reg_prcmu_rate(const char *name, | ||
237 | const char *parent_name, | ||
238 | u8 cg_sel, | ||
239 | unsigned long flags) | ||
240 | { | ||
241 | return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, | ||
242 | &clk_prcmu_rate_ops); | ||
243 | } | ||
244 | |||
245 | struct clk *clk_reg_prcmu_opp_gate(const char *name, | ||
246 | const char *parent_name, | ||
247 | u8 cg_sel, | ||
248 | unsigned long flags) | ||
249 | { | ||
250 | return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, | ||
251 | &clk_prcmu_opp_gate_ops); | ||
252 | } | ||
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h new file mode 100644 index 000000000000..836d7d16751e --- /dev/null +++ b/drivers/clk/ux500/clk.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Clocks for ux500 platforms | ||
3 | * | ||
4 | * Copyright (C) 2012 ST-Ericsson SA | ||
5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | ||
6 | * | ||
7 | * License terms: GNU General Public License (GPL) version 2 | ||
8 | */ | ||
9 | |||
10 | #ifndef __UX500_CLK_H | ||
11 | #define __UX500_CLK_H | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | |||
15 | struct clk *clk_reg_prcc_pclk(const char *name, | ||
16 | const char *parent_name, | ||
17 | unsigned int phy_base, | ||
18 | u32 cg_sel, | ||
19 | unsigned long flags); | ||
20 | |||
21 | struct clk *clk_reg_prcc_kclk(const char *name, | ||
22 | const char *parent_name, | ||
23 | unsigned int phy_base, | ||
24 | u32 cg_sel, | ||
25 | unsigned long flags); | ||
26 | |||
27 | struct clk *clk_reg_prcmu_scalable(const char *name, | ||
28 | const char *parent_name, | ||
29 | u8 cg_sel, | ||
30 | unsigned long rate, | ||
31 | unsigned long flags); | ||
32 | |||
33 | struct clk *clk_reg_prcmu_gate(const char *name, | ||
34 | const char *parent_name, | ||
35 | u8 cg_sel, | ||
36 | unsigned long flags); | ||
37 | |||
38 | struct clk *clk_reg_prcmu_rate(const char *name, | ||
39 | const char *parent_name, | ||
40 | u8 cg_sel, | ||
41 | unsigned long flags); | ||
42 | |||
43 | struct clk *clk_reg_prcmu_opp_gate(const char *name, | ||
44 | const char *parent_name, | ||
45 | u8 cg_sel, | ||
46 | unsigned long flags); | ||
47 | |||
48 | #endif /* __UX500_CLK_H */ | ||
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c new file mode 100644 index 000000000000..ca4a25ed844c --- /dev/null +++ b/drivers/clk/ux500/u8500_clk.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * Clock definitions for u8500 platform. | ||
3 | * | ||
4 | * Copyright (C) 2012 ST-Ericsson SA | ||
5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | ||
6 | * | ||
7 | * License terms: GNU General Public License (GPL) version 2 | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/clkdev.h> | ||
12 | #include <linux/clk-provider.h> | ||
13 | #include <linux/mfd/dbx500-prcmu.h> | ||
14 | #include <linux/platform_data/clk-ux500.h> | ||
15 | |||
16 | #include "clk.h" | ||
17 | |||
18 | void u8500_clk_init(void) | ||
19 | { | ||
20 | struct prcmu_fw_version *fw_version; | ||
21 | const char *sgaclk_parent = NULL; | ||
22 | struct clk *clk; | ||
23 | |||
24 | /* Clock sources */ | ||
25 | clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0, | ||
26 | CLK_IS_ROOT|CLK_IGNORE_UNUSED); | ||
27 | clk_register_clkdev(clk, "soc0_pll", NULL); | ||
28 | |||
29 | clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1, | ||
30 | CLK_IS_ROOT|CLK_IGNORE_UNUSED); | ||
31 | clk_register_clkdev(clk, "soc1_pll", NULL); | ||
32 | |||
33 | clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR, | ||
34 | CLK_IS_ROOT|CLK_IGNORE_UNUSED); | ||
35 | clk_register_clkdev(clk, "ddr_pll", NULL); | ||
36 | |||
37 | /* FIXME: Add sys, ulp and int clocks here. */ | ||
38 | |||
39 | clk = clk_register_fixed_rate(NULL, "rtc32k", "NULL", | ||
40 | CLK_IS_ROOT|CLK_IGNORE_UNUSED, | ||
41 | 32768); | ||
42 | clk_register_clkdev(clk, "clk32k", NULL); | ||
43 | clk_register_clkdev(clk, NULL, "rtc-pl031"); | ||
44 | |||
45 | /* PRCMU clocks */ | ||
46 | fw_version = prcmu_get_fw_version(); | ||
47 | if (fw_version != NULL) { | ||
48 | switch (fw_version->project) { | ||
49 | case PRCMU_FW_PROJECT_U8500_C2: | ||
50 | case PRCMU_FW_PROJECT_U8520: | ||
51 | case PRCMU_FW_PROJECT_U8420: | ||
52 | sgaclk_parent = "soc0_pll"; | ||
53 | break; | ||
54 | default: | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | if (sgaclk_parent) | ||
60 | clk = clk_reg_prcmu_gate("sgclk", sgaclk_parent, | ||
61 | PRCMU_SGACLK, 0); | ||
62 | else | ||
63 | clk = clk_reg_prcmu_gate("sgclk", NULL, | ||
64 | PRCMU_SGACLK, CLK_IS_ROOT); | ||
65 | clk_register_clkdev(clk, NULL, "mali"); | ||
66 | |||
67 | clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT); | ||
68 | clk_register_clkdev(clk, NULL, "UART"); | ||
69 | |||
70 | clk = clk_reg_prcmu_gate("msp02clk", NULL, PRCMU_MSP02CLK, CLK_IS_ROOT); | ||
71 | clk_register_clkdev(clk, NULL, "MSP02"); | ||
72 | |||
73 | clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT); | ||
74 | clk_register_clkdev(clk, NULL, "MSP1"); | ||
75 | |||
76 | clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT); | ||
77 | clk_register_clkdev(clk, NULL, "I2C"); | ||
78 | |||
79 | clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT); | ||
80 | clk_register_clkdev(clk, NULL, "slim"); | ||
81 | |||
82 | clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT); | ||
83 | clk_register_clkdev(clk, NULL, "PERIPH1"); | ||
84 | |||
85 | clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT); | ||
86 | clk_register_clkdev(clk, NULL, "PERIPH2"); | ||
87 | |||
88 | clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT); | ||
89 | clk_register_clkdev(clk, NULL, "PERIPH3"); | ||
90 | |||
91 | clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT); | ||
92 | clk_register_clkdev(clk, NULL, "PERIPH5"); | ||
93 | |||
94 | clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT); | ||
95 | clk_register_clkdev(clk, NULL, "PERIPH6"); | ||
96 | |||
97 | clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT); | ||
98 | clk_register_clkdev(clk, NULL, "PERIPH7"); | ||
99 | |||
100 | clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0, | ||
101 | CLK_IS_ROOT|CLK_SET_RATE_GATE); | ||
102 | clk_register_clkdev(clk, NULL, "lcd"); | ||
103 | clk_register_clkdev(clk, "lcd", "mcde"); | ||
104 | |||
105 | clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BMLCLK, CLK_IS_ROOT); | ||
106 | clk_register_clkdev(clk, NULL, "bml"); | ||
107 | |||
108 | clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0, | ||
109 | CLK_IS_ROOT|CLK_SET_RATE_GATE); | ||
110 | |||
111 | clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0, | ||
112 | CLK_IS_ROOT|CLK_SET_RATE_GATE); | ||
113 | |||
114 | clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0, | ||
115 | CLK_IS_ROOT|CLK_SET_RATE_GATE); | ||
116 | clk_register_clkdev(clk, NULL, "hdmi"); | ||
117 | clk_register_clkdev(clk, "hdmi", "mcde"); | ||
118 | |||
119 | clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT); | ||
120 | clk_register_clkdev(clk, NULL, "apeat"); | ||
121 | |||
122 | clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK, | ||
123 | CLK_IS_ROOT); | ||
124 | clk_register_clkdev(clk, NULL, "apetrace"); | ||
125 | |||
126 | clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT); | ||
127 | clk_register_clkdev(clk, NULL, "mcde"); | ||
128 | clk_register_clkdev(clk, "mcde", "mcde"); | ||
129 | clk_register_clkdev(clk, "dsisys", "dsilink.0"); | ||
130 | clk_register_clkdev(clk, "dsisys", "dsilink.1"); | ||
131 | clk_register_clkdev(clk, "dsisys", "dsilink.2"); | ||
132 | |||
133 | clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK, | ||
134 | CLK_IS_ROOT); | ||
135 | clk_register_clkdev(clk, NULL, "ipi2"); | ||
136 | |||
137 | clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK, | ||
138 | CLK_IS_ROOT); | ||
139 | clk_register_clkdev(clk, NULL, "dsialt"); | ||
140 | |||
141 | clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT); | ||
142 | clk_register_clkdev(clk, NULL, "dma40.0"); | ||
143 | |||
144 | clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT); | ||
145 | clk_register_clkdev(clk, NULL, "b2r2"); | ||
146 | clk_register_clkdev(clk, NULL, "b2r2_core"); | ||
147 | clk_register_clkdev(clk, NULL, "U8500-B2R2.0"); | ||
148 | |||
149 | clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0, | ||
150 | CLK_IS_ROOT|CLK_SET_RATE_GATE); | ||
151 | clk_register_clkdev(clk, NULL, "tv"); | ||
152 | clk_register_clkdev(clk, "tv", "mcde"); | ||
153 | |||
154 | clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT); | ||
155 | clk_register_clkdev(clk, NULL, "SSP"); | ||
156 | |||
157 | clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT); | ||
158 | clk_register_clkdev(clk, NULL, "rngclk"); | ||
159 | |||
160 | clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT); | ||
161 | clk_register_clkdev(clk, NULL, "uicc"); | ||
162 | |||
163 | /* | ||
164 | * FIXME: The MTU clocks might need some kind of "parent muxed join" | ||
165 | * and these have no K-clocks. For now, we ignore the missing | ||
166 | * connection to the corresponding P-clocks, p6_mtu0_clk and | ||
167 | * p6_mtu1_clk. Instead timclk is used which is the valid parent. | ||
168 | */ | ||
169 | clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT); | ||
170 | clk_register_clkdev(clk, NULL, "mtu0"); | ||
171 | clk_register_clkdev(clk, NULL, "mtu1"); | ||
172 | |||
173 | clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT); | ||
174 | clk_register_clkdev(clk, NULL, "sdmmc"); | ||
175 | |||
176 | |||
177 | clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", | ||
178 | PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); | ||
179 | clk_register_clkdev(clk, "dsihs2", "mcde"); | ||
180 | clk_register_clkdev(clk, "dsihs2", "dsilink.2"); | ||
181 | |||
182 | |||
183 | clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll", | ||
184 | PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE); | ||
185 | clk_register_clkdev(clk, "dsihs0", "mcde"); | ||
186 | clk_register_clkdev(clk, "dsihs0", "dsilink.0"); | ||
187 | |||
188 | clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll", | ||
189 | PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE); | ||
190 | clk_register_clkdev(clk, "dsihs1", "mcde"); | ||
191 | clk_register_clkdev(clk, "dsihs1", "dsilink.1"); | ||
192 | |||
193 | clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk", | ||
194 | PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE); | ||
195 | clk_register_clkdev(clk, "dsilp0", "dsilink.0"); | ||
196 | clk_register_clkdev(clk, "dsilp0", "mcde"); | ||
197 | |||
198 | clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk", | ||
199 | PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE); | ||
200 | clk_register_clkdev(clk, "dsilp1", "dsilink.1"); | ||
201 | clk_register_clkdev(clk, "dsilp1", "mcde"); | ||
202 | |||
203 | clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk", | ||
204 | PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE); | ||
205 | clk_register_clkdev(clk, "dsilp2", "dsilink.2"); | ||
206 | clk_register_clkdev(clk, "dsilp2", "mcde"); | ||
207 | |||
208 | clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS, | ||
209 | CLK_IS_ROOT|CLK_GET_RATE_NOCACHE| | ||
210 | CLK_IGNORE_UNUSED); | ||
211 | clk_register_clkdev(clk, NULL, "smp_twd"); | ||
212 | |||
213 | /* | ||
214 | * FIXME: Add special handled PRCMU clocks here: | ||
215 | * 1. clk_arm, use PRCMU_ARMCLK. | ||
216 | * 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl. | ||
217 | * 3. ab9540_clkout1yuv, see clkout0yuv | ||
218 | */ | ||
219 | |||
220 | /* PRCC P-clocks */ | ||
221 | clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", U8500_CLKRST1_BASE, | ||
222 | BIT(0), 0); | ||
223 | clk_register_clkdev(clk, "apb_pclk", "uart0"); | ||
224 | |||
225 | clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", U8500_CLKRST1_BASE, | ||
226 | BIT(1), 0); | ||
227 | clk_register_clkdev(clk, "apb_pclk", "uart1"); | ||
228 | |||
229 | clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", U8500_CLKRST1_BASE, | ||
230 | BIT(2), 0); | ||
231 | clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", U8500_CLKRST1_BASE, | ||
232 | BIT(3), 0); | ||
233 | clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", U8500_CLKRST1_BASE, | ||
234 | BIT(4), 0); | ||
235 | |||
236 | clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", U8500_CLKRST1_BASE, | ||
237 | BIT(5), 0); | ||
238 | clk_register_clkdev(clk, "apb_pclk", "sdi0"); | ||
239 | |||
240 | clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", U8500_CLKRST1_BASE, | ||
241 | BIT(6), 0); | ||
242 | |||
243 | clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", U8500_CLKRST1_BASE, | ||
244 | BIT(7), 0); | ||
245 | clk_register_clkdev(clk, NULL, "spi3"); | ||
246 | |||
247 | clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", U8500_CLKRST1_BASE, | ||
248 | BIT(8), 0); | ||
249 | |||
250 | clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", U8500_CLKRST1_BASE, | ||
251 | BIT(9), 0); | ||
252 | clk_register_clkdev(clk, NULL, "gpio.0"); | ||
253 | clk_register_clkdev(clk, NULL, "gpio.1"); | ||
254 | clk_register_clkdev(clk, NULL, "gpioblock0"); | ||
255 | |||
256 | clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", U8500_CLKRST1_BASE, | ||
257 | BIT(10), 0); | ||
258 | clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", U8500_CLKRST1_BASE, | ||
259 | BIT(11), 0); | ||
260 | |||
261 | clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", U8500_CLKRST2_BASE, | ||
262 | BIT(0), 0); | ||
263 | |||
264 | clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", U8500_CLKRST2_BASE, | ||
265 | BIT(1), 0); | ||
266 | clk_register_clkdev(clk, NULL, "spi2"); | ||
267 | |||
268 | clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", U8500_CLKRST2_BASE, | ||
269 | BIT(2), 0); | ||
270 | clk_register_clkdev(clk, NULL, "spi1"); | ||
271 | |||
272 | clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", U8500_CLKRST2_BASE, | ||
273 | BIT(3), 0); | ||
274 | clk_register_clkdev(clk, NULL, "pwl"); | ||
275 | |||
276 | clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", U8500_CLKRST2_BASE, | ||
277 | BIT(4), 0); | ||
278 | clk_register_clkdev(clk, "apb_pclk", "sdi4"); | ||
279 | |||
280 | clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", U8500_CLKRST2_BASE, | ||
281 | BIT(5), 0); | ||
282 | |||
283 | clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", U8500_CLKRST2_BASE, | ||
284 | BIT(6), 0); | ||
285 | clk_register_clkdev(clk, "apb_pclk", "sdi1"); | ||
286 | |||
287 | |||
288 | clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", U8500_CLKRST2_BASE, | ||
289 | BIT(7), 0); | ||
290 | clk_register_clkdev(clk, "apb_pclk", "sdi3"); | ||
291 | |||
292 | clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", U8500_CLKRST2_BASE, | ||
293 | BIT(8), 0); | ||
294 | clk_register_clkdev(clk, NULL, "spi0"); | ||
295 | |||
296 | clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", U8500_CLKRST2_BASE, | ||
297 | BIT(9), 0); | ||
298 | clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0"); | ||
299 | |||
300 | clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", U8500_CLKRST2_BASE, | ||
301 | BIT(10), 0); | ||
302 | clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0"); | ||
303 | |||
304 | clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", U8500_CLKRST2_BASE, | ||
305 | BIT(11), 0); | ||
306 | clk_register_clkdev(clk, NULL, "gpio.6"); | ||
307 | clk_register_clkdev(clk, NULL, "gpio.7"); | ||
308 | clk_register_clkdev(clk, NULL, "gpioblock1"); | ||
309 | |||
310 | clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE, | ||
311 | BIT(11), 0); | ||
312 | |||
313 | clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE, | ||
314 | BIT(0), 0); | ||
315 | clk_register_clkdev(clk, NULL, "fsmc"); | ||
316 | |||
317 | clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", U8500_CLKRST3_BASE, | ||
318 | BIT(1), 0); | ||
319 | clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", U8500_CLKRST3_BASE, | ||
320 | BIT(2), 0); | ||
321 | clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", U8500_CLKRST3_BASE, | ||
322 | BIT(3), 0); | ||
323 | |||
324 | clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", U8500_CLKRST3_BASE, | ||
325 | BIT(4), 0); | ||
326 | clk_register_clkdev(clk, "apb_pclk", "sdi2"); | ||
327 | |||
328 | clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE, | ||
329 | BIT(5), 0); | ||
330 | |||
331 | clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE, | ||
332 | BIT(6), 0); | ||
333 | clk_register_clkdev(clk, "apb_pclk", "uart2"); | ||
334 | |||
335 | clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", U8500_CLKRST3_BASE, | ||
336 | BIT(7), 0); | ||
337 | clk_register_clkdev(clk, "apb_pclk", "sdi5"); | ||
338 | |||
339 | clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", U8500_CLKRST3_BASE, | ||
340 | BIT(8), 0); | ||
341 | clk_register_clkdev(clk, NULL, "gpio.2"); | ||
342 | clk_register_clkdev(clk, NULL, "gpio.3"); | ||
343 | clk_register_clkdev(clk, NULL, "gpio.4"); | ||
344 | clk_register_clkdev(clk, NULL, "gpio.5"); | ||
345 | clk_register_clkdev(clk, NULL, "gpioblock2"); | ||
346 | |||
347 | clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", U8500_CLKRST5_BASE, | ||
348 | BIT(0), 0); | ||
349 | clk_register_clkdev(clk, "usb", "musb-ux500.0"); | ||
350 | |||
351 | clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", U8500_CLKRST5_BASE, | ||
352 | BIT(1), 0); | ||
353 | clk_register_clkdev(clk, NULL, "gpio.8"); | ||
354 | clk_register_clkdev(clk, NULL, "gpioblock3"); | ||
355 | |||
356 | clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE, | ||
357 | BIT(0), 0); | ||
358 | |||
359 | clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE, | ||
360 | BIT(1), 0); | ||
361 | clk_register_clkdev(clk, NULL, "cryp0"); | ||
362 | clk_register_clkdev(clk, NULL, "cryp1"); | ||
363 | |||
364 | clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", U8500_CLKRST6_BASE, | ||
365 | BIT(2), 0); | ||
366 | clk_register_clkdev(clk, NULL, "hash0"); | ||
367 | |||
368 | clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", U8500_CLKRST6_BASE, | ||
369 | BIT(3), 0); | ||
370 | clk_register_clkdev(clk, NULL, "pka"); | ||
371 | |||
372 | clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", U8500_CLKRST6_BASE, | ||
373 | BIT(4), 0); | ||
374 | clk_register_clkdev(clk, NULL, "hash1"); | ||
375 | |||
376 | clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", U8500_CLKRST6_BASE, | ||
377 | BIT(5), 0); | ||
378 | clk_register_clkdev(clk, NULL, "cfgreg"); | ||
379 | |||
380 | clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", U8500_CLKRST6_BASE, | ||
381 | BIT(6), 0); | ||
382 | clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", U8500_CLKRST6_BASE, | ||
383 | BIT(7), 0); | ||
384 | |||
385 | /* PRCC K-clocks | ||
386 | * | ||
387 | * FIXME: Some drivers requires PERPIH[n| to be automatically enabled | ||
388 | * by enabling just the K-clock, even if it is not a valid parent to | ||
389 | * the K-clock. Until drivers get fixed we might need some kind of | ||
390 | * "parent muxed join". | ||
391 | */ | ||
392 | |||
393 | /* Periph1 */ | ||
394 | clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk", | ||
395 | U8500_CLKRST1_BASE, BIT(0), CLK_SET_RATE_GATE); | ||
396 | clk_register_clkdev(clk, NULL, "uart0"); | ||
397 | |||
398 | clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk", | ||
399 | U8500_CLKRST1_BASE, BIT(1), CLK_SET_RATE_GATE); | ||
400 | clk_register_clkdev(clk, NULL, "uart1"); | ||
401 | |||
402 | clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk", | ||
403 | U8500_CLKRST1_BASE, BIT(2), CLK_SET_RATE_GATE); | ||
404 | clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk", | ||
405 | U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE); | ||
406 | clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk", | ||
407 | U8500_CLKRST1_BASE, BIT(4), CLK_SET_RATE_GATE); | ||
408 | |||
409 | clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk", | ||
410 | U8500_CLKRST1_BASE, BIT(5), CLK_SET_RATE_GATE); | ||
411 | clk_register_clkdev(clk, NULL, "sdi0"); | ||
412 | |||
413 | clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk", | ||
414 | U8500_CLKRST1_BASE, BIT(6), CLK_SET_RATE_GATE); | ||
415 | clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk", | ||
416 | U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE); | ||
417 | /* FIXME: Redefinition of BIT(3). */ | ||
418 | clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk", | ||
419 | U8500_CLKRST1_BASE, BIT(9), CLK_SET_RATE_GATE); | ||
420 | clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk", | ||
421 | U8500_CLKRST1_BASE, BIT(10), CLK_SET_RATE_GATE); | ||
422 | |||
423 | /* Periph2 */ | ||
424 | clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk", | ||
425 | U8500_CLKRST2_BASE, BIT(0), CLK_SET_RATE_GATE); | ||
426 | |||
427 | clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk", | ||
428 | U8500_CLKRST2_BASE, BIT(2), CLK_SET_RATE_GATE); | ||
429 | clk_register_clkdev(clk, NULL, "sdi4"); | ||
430 | |||
431 | clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk", | ||
432 | U8500_CLKRST2_BASE, BIT(3), CLK_SET_RATE_GATE); | ||
433 | |||
434 | clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk", | ||
435 | U8500_CLKRST2_BASE, BIT(4), CLK_SET_RATE_GATE); | ||
436 | clk_register_clkdev(clk, NULL, "sdi1"); | ||
437 | |||
438 | clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk", | ||
439 | U8500_CLKRST2_BASE, BIT(5), CLK_SET_RATE_GATE); | ||
440 | clk_register_clkdev(clk, NULL, "sdi3"); | ||
441 | |||
442 | /* Note that rate is received from parent. */ | ||
443 | clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk", | ||
444 | U8500_CLKRST2_BASE, BIT(6), | ||
445 | CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); | ||
446 | clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk", | ||
447 | U8500_CLKRST2_BASE, BIT(7), | ||
448 | CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); | ||
449 | |||
450 | /* Periph3 */ | ||
451 | clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk", | ||
452 | U8500_CLKRST3_BASE, BIT(1), CLK_SET_RATE_GATE); | ||
453 | clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk", | ||
454 | U8500_CLKRST3_BASE, BIT(2), CLK_SET_RATE_GATE); | ||
455 | clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk", | ||
456 | U8500_CLKRST3_BASE, BIT(3), CLK_SET_RATE_GATE); | ||
457 | |||
458 | clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk", | ||
459 | U8500_CLKRST3_BASE, BIT(4), CLK_SET_RATE_GATE); | ||
460 | clk_register_clkdev(clk, NULL, "sdi2"); | ||
461 | |||
462 | clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k", | ||
463 | U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE); | ||
464 | |||
465 | clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk", | ||
466 | U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE); | ||
467 | clk_register_clkdev(clk, NULL, "uart2"); | ||
468 | |||
469 | clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk", | ||
470 | U8500_CLKRST3_BASE, BIT(7), CLK_SET_RATE_GATE); | ||
471 | clk_register_clkdev(clk, NULL, "sdi5"); | ||
472 | |||
473 | /* Periph6 */ | ||
474 | clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk", | ||
475 | U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE); | ||
476 | |||
477 | } | ||
diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c new file mode 100644 index 000000000000..10adfd2ead21 --- /dev/null +++ b/drivers/clk/ux500/u8540_clk.c | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * Clock definitions for u8540 platform. | ||
3 | * | ||
4 | * Copyright (C) 2012 ST-Ericsson SA | ||
5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | ||
6 | * | ||
7 | * License terms: GNU General Public License (GPL) version 2 | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/clkdev.h> | ||
12 | #include <linux/clk-provider.h> | ||
13 | #include <linux/mfd/dbx500-prcmu.h> | ||
14 | #include <linux/platform_data/clk-ux500.h> | ||
15 | |||
16 | #include "clk.h" | ||
17 | |||
18 | void u8540_clk_init(void) | ||
19 | { | ||
20 | /* register clocks here */ | ||
21 | } | ||
diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c new file mode 100644 index 000000000000..dbc0191e16c8 --- /dev/null +++ b/drivers/clk/ux500/u9540_clk.c | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * Clock definitions for u9540 platform. | ||
3 | * | ||
4 | * Copyright (C) 2012 ST-Ericsson SA | ||
5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | ||
6 | * | ||
7 | * License terms: GNU General Public License (GPL) version 2 | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/clkdev.h> | ||
12 | #include <linux/clk-provider.h> | ||
13 | #include <linux/mfd/dbx500-prcmu.h> | ||
14 | #include <linux/platform_data/clk-ux500.h> | ||
15 | |||
16 | #include "clk.h" | ||
17 | |||
18 | void u9540_clk_init(void) | ||
19 | { | ||
20 | /* register clocks here */ | ||
21 | } | ||
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index 50cf6a2ee693..c0a0f6478798 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | # Makefile for Versatile-specific clocks | 1 | # Makefile for Versatile-specific clocks |
2 | obj-$(CONFIG_ICST) += clk-icst.o | 2 | obj-$(CONFIG_ICST) += clk-icst.o |
3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o | 3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o |
4 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o | ||
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c new file mode 100644 index 000000000000..e21a99cef378 --- /dev/null +++ b/drivers/clk/versatile/clk-realview.c | |||
@@ -0,0 +1,114 @@ | |||
1 | #include <linux/clk.h> | ||
2 | #include <linux/clkdev.h> | ||
3 | #include <linux/err.h> | ||
4 | #include <linux/io.h> | ||
5 | #include <linux/clk-provider.h> | ||
6 | |||
7 | #include <mach/hardware.h> | ||
8 | #include <mach/platform.h> | ||
9 | |||
10 | #include "clk-icst.h" | ||
11 | |||
12 | /* | ||
13 | * Implementation of the ARM RealView clock trees. | ||
14 | */ | ||
15 | |||
16 | static void __iomem *sys_lock; | ||
17 | static void __iomem *sys_vcoreg; | ||
18 | |||
19 | /** | ||
20 | * realview_oscvco_get() - get ICST OSC settings for the RealView | ||
21 | */ | ||
22 | static struct icst_vco realview_oscvco_get(void) | ||
23 | { | ||
24 | u32 val; | ||
25 | struct icst_vco vco; | ||
26 | |||
27 | val = readl(sys_vcoreg); | ||
28 | vco.v = val & 0x1ff; | ||
29 | vco.r = (val >> 9) & 0x7f; | ||
30 | vco.s = (val >> 16) & 03; | ||
31 | return vco; | ||
32 | } | ||
33 | |||
34 | static void realview_oscvco_set(struct icst_vco vco) | ||
35 | { | ||
36 | u32 val; | ||
37 | |||
38 | val = readl(sys_vcoreg) & ~0x7ffff; | ||
39 | val |= vco.v | (vco.r << 9) | (vco.s << 16); | ||
40 | |||
41 | /* This magic unlocks the CM VCO so it can be controlled */ | ||
42 | writel(0xa05f, sys_lock); | ||
43 | writel(val, sys_vcoreg); | ||
44 | /* This locks the CM again */ | ||
45 | writel(0, sys_lock); | ||
46 | } | ||
47 | |||
48 | static const struct icst_params realview_oscvco_params = { | ||
49 | .ref = 24000000, | ||
50 | .vco_max = ICST307_VCO_MAX, | ||
51 | .vco_min = ICST307_VCO_MIN, | ||
52 | .vd_min = 4 + 8, | ||
53 | .vd_max = 511 + 8, | ||
54 | .rd_min = 1 + 2, | ||
55 | .rd_max = 127 + 2, | ||
56 | .s2div = icst307_s2div, | ||
57 | .idx2s = icst307_idx2s, | ||
58 | }; | ||
59 | |||
60 | static const struct clk_icst_desc __initdata realview_icst_desc = { | ||
61 | .params = &realview_oscvco_params, | ||
62 | .getvco = realview_oscvco_get, | ||
63 | .setvco = realview_oscvco_set, | ||
64 | }; | ||
65 | |||
66 | /* | ||
67 | * realview_clk_init() - set up the RealView clock tree | ||
68 | */ | ||
69 | void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) | ||
70 | { | ||
71 | struct clk *clk; | ||
72 | |||
73 | sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET; | ||
74 | if (is_pb1176) | ||
75 | sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET; | ||
76 | else | ||
77 | sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET; | ||
78 | |||
79 | |||
80 | /* APB clock dummy */ | ||
81 | clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); | ||
82 | clk_register_clkdev(clk, "apb_pclk", NULL); | ||
83 | |||
84 | /* 24 MHz clock */ | ||
85 | clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT, | ||
86 | 24000000); | ||
87 | clk_register_clkdev(clk, NULL, "dev:uart0"); | ||
88 | clk_register_clkdev(clk, NULL, "dev:uart1"); | ||
89 | clk_register_clkdev(clk, NULL, "dev:uart2"); | ||
90 | clk_register_clkdev(clk, NULL, "fpga:kmi0"); | ||
91 | clk_register_clkdev(clk, NULL, "fpga:kmi1"); | ||
92 | clk_register_clkdev(clk, NULL, "fpga:mmc0"); | ||
93 | clk_register_clkdev(clk, NULL, "dev:ssp0"); | ||
94 | if (is_pb1176) { | ||
95 | /* | ||
96 | * UART3 is on the dev chip in PB1176 | ||
97 | * UART4 only exists in PB1176 | ||
98 | */ | ||
99 | clk_register_clkdev(clk, NULL, "dev:uart3"); | ||
100 | clk_register_clkdev(clk, NULL, "dev:uart4"); | ||
101 | } else | ||
102 | clk_register_clkdev(clk, NULL, "fpga:uart3"); | ||
103 | |||
104 | |||
105 | /* 1 MHz clock */ | ||
106 | clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT, | ||
107 | 1000000); | ||
108 | clk_register_clkdev(clk, NULL, "sp804"); | ||
109 | |||
110 | /* ICST VCO clock */ | ||
111 | clk = icst_clk_register(NULL, &realview_icst_desc); | ||
112 | clk_register_clkdev(clk, NULL, "dev:clcd"); | ||
113 | clk_register_clkdev(clk, NULL, "issp:clcd"); | ||
114 | } | ||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ba7926f5c099..a00b828b1643 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -183,6 +183,12 @@ config GPIO_STA2X11 | |||
183 | Say yes here to support the STA2x11/ConneXt GPIO device. | 183 | Say yes here to support the STA2x11/ConneXt GPIO device. |
184 | The GPIO module has 128 GPIO pins with alternate functions. | 184 | The GPIO module has 128 GPIO pins with alternate functions. |
185 | 185 | ||
186 | config GPIO_VT8500 | ||
187 | bool "VIA/Wondermedia SoC GPIO Support" | ||
188 | depends on ARCH_VT8500 | ||
189 | help | ||
190 | Say yes here to support the VT8500/WM8505/WM8650 GPIO controller. | ||
191 | |||
186 | config GPIO_XILINX | 192 | config GPIO_XILINX |
187 | bool "Xilinx GPIO support" | 193 | bool "Xilinx GPIO support" |
188 | depends on PPC_OF || MICROBLAZE | 194 | depends on PPC_OF || MICROBLAZE |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 153caceeb053..a288142ad998 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -69,6 +69,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o | |||
69 | obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o | 69 | obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o |
70 | obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o | 70 | obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o |
71 | obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o | 71 | obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o |
72 | obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o | ||
72 | obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o | 73 | obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o |
73 | obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o | 74 | obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o |
74 | obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o | 75 | obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o |
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 9cac88a65f78..9528779ca463 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/syscore_ops.h> | 26 | #include <linux/syscore_ops.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | 28 | ||
29 | #include <asm/mach/irq.h> | ||
30 | |||
29 | #include <mach/irqs.h> | 31 | #include <mach/irqs.h> |
30 | 32 | ||
31 | /* | 33 | /* |
@@ -59,6 +61,7 @@ | |||
59 | #define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) | 61 | #define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) |
60 | 62 | ||
61 | int pxa_last_gpio; | 63 | int pxa_last_gpio; |
64 | static int irq_base; | ||
62 | 65 | ||
63 | #ifdef CONFIG_OF | 66 | #ifdef CONFIG_OF |
64 | static struct irq_domain *domain; | 67 | static struct irq_domain *domain; |
@@ -167,63 +170,14 @@ static inline int __gpio_is_occupied(unsigned gpio) | |||
167 | return ret; | 170 | return ret; |
168 | } | 171 | } |
169 | 172 | ||
170 | #ifdef CONFIG_ARCH_PXA | ||
171 | static inline int __pxa_gpio_to_irq(int gpio) | ||
172 | { | ||
173 | if (gpio_is_pxa_type(gpio_type)) | ||
174 | return PXA_GPIO_TO_IRQ(gpio); | ||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | static inline int __pxa_irq_to_gpio(int irq) | ||
179 | { | ||
180 | if (gpio_is_pxa_type(gpio_type)) | ||
181 | return irq - PXA_GPIO_TO_IRQ(0); | ||
182 | return -1; | ||
183 | } | ||
184 | #else | ||
185 | static inline int __pxa_gpio_to_irq(int gpio) { return -1; } | ||
186 | static inline int __pxa_irq_to_gpio(int irq) { return -1; } | ||
187 | #endif | ||
188 | |||
189 | #ifdef CONFIG_ARCH_MMP | ||
190 | static inline int __mmp_gpio_to_irq(int gpio) | ||
191 | { | ||
192 | if (gpio_is_mmp_type(gpio_type)) | ||
193 | return MMP_GPIO_TO_IRQ(gpio); | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | static inline int __mmp_irq_to_gpio(int irq) | ||
198 | { | ||
199 | if (gpio_is_mmp_type(gpio_type)) | ||
200 | return irq - MMP_GPIO_TO_IRQ(0); | ||
201 | return -1; | ||
202 | } | ||
203 | #else | ||
204 | static inline int __mmp_gpio_to_irq(int gpio) { return -1; } | ||
205 | static inline int __mmp_irq_to_gpio(int irq) { return -1; } | ||
206 | #endif | ||
207 | |||
208 | static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | 173 | static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) |
209 | { | 174 | { |
210 | int gpio, ret; | 175 | return chip->base + offset + irq_base; |
211 | |||
212 | gpio = chip->base + offset; | ||
213 | ret = __pxa_gpio_to_irq(gpio); | ||
214 | if (ret >= 0) | ||
215 | return ret; | ||
216 | return __mmp_gpio_to_irq(gpio); | ||
217 | } | 176 | } |
218 | 177 | ||
219 | int pxa_irq_to_gpio(int irq) | 178 | int pxa_irq_to_gpio(int irq) |
220 | { | 179 | { |
221 | int ret; | 180 | return irq - irq_base; |
222 | |||
223 | ret = __pxa_irq_to_gpio(irq); | ||
224 | if (ret >= 0) | ||
225 | return ret; | ||
226 | return __mmp_irq_to_gpio(irq); | ||
227 | } | 181 | } |
228 | 182 | ||
229 | static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | 183 | static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) |
@@ -403,6 +357,9 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) | |||
403 | struct pxa_gpio_chip *c; | 357 | struct pxa_gpio_chip *c; |
404 | int loop, gpio, gpio_base, n; | 358 | int loop, gpio, gpio_base, n; |
405 | unsigned long gedr; | 359 | unsigned long gedr; |
360 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
361 | |||
362 | chained_irq_enter(chip, desc); | ||
406 | 363 | ||
407 | do { | 364 | do { |
408 | loop = 0; | 365 | loop = 0; |
@@ -422,6 +379,8 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) | |||
422 | } | 379 | } |
423 | } | 380 | } |
424 | } while (loop); | 381 | } while (loop); |
382 | |||
383 | chained_irq_exit(chip, desc); | ||
425 | } | 384 | } |
426 | 385 | ||
427 | static void pxa_ack_muxed_gpio(struct irq_data *d) | 386 | static void pxa_ack_muxed_gpio(struct irq_data *d) |
@@ -535,7 +494,7 @@ const struct irq_domain_ops pxa_irq_domain_ops = { | |||
535 | 494 | ||
536 | static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev) | 495 | static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev) |
537 | { | 496 | { |
538 | int ret, nr_banks, nr_gpios, irq_base; | 497 | int ret, nr_banks, nr_gpios; |
539 | struct device_node *prev, *next, *np = pdev->dev.of_node; | 498 | struct device_node *prev, *next, *np = pdev->dev.of_node; |
540 | const struct of_device_id *of_id = | 499 | const struct of_device_id *of_id = |
541 | of_match_device(pxa_gpio_dt_ids, &pdev->dev); | 500 | of_match_device(pxa_gpio_dt_ids, &pdev->dev); |
@@ -590,10 +549,20 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev) | |||
590 | int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; | 549 | int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; |
591 | 550 | ||
592 | ret = pxa_gpio_probe_dt(pdev); | 551 | ret = pxa_gpio_probe_dt(pdev); |
593 | if (ret < 0) | 552 | if (ret < 0) { |
594 | pxa_last_gpio = pxa_gpio_nums(); | 553 | pxa_last_gpio = pxa_gpio_nums(); |
595 | else | 554 | #ifdef CONFIG_ARCH_PXA |
555 | if (gpio_is_pxa_type(gpio_type)) | ||
556 | irq_base = PXA_GPIO_TO_IRQ(0); | ||
557 | #endif | ||
558 | #ifdef CONFIG_ARCH_MMP | ||
559 | if (gpio_is_mmp_type(gpio_type)) | ||
560 | irq_base = MMP_GPIO_TO_IRQ(0); | ||
561 | #endif | ||
562 | } else { | ||
596 | use_of = 1; | 563 | use_of = 1; |
564 | } | ||
565 | |||
597 | if (!pxa_last_gpio) | 566 | if (!pxa_last_gpio) |
598 | return -EINVAL; | 567 | return -EINVAL; |
599 | 568 | ||
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index ba126cc04073..f4814a889a5b 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c | |||
@@ -938,6 +938,67 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) | |||
938 | s3c_gpiolib_track(chip); | 938 | s3c_gpiolib_track(chip); |
939 | } | 939 | } |
940 | 940 | ||
941 | #if defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) | ||
942 | static int s3c24xx_gpio_xlate(struct gpio_chip *gc, | ||
943 | const struct of_phandle_args *gpiospec, u32 *flags) | ||
944 | { | ||
945 | unsigned int pin; | ||
946 | |||
947 | if (WARN_ON(gc->of_gpio_n_cells < 3)) | ||
948 | return -EINVAL; | ||
949 | |||
950 | if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) | ||
951 | return -EINVAL; | ||
952 | |||
953 | if (gpiospec->args[0] > gc->ngpio) | ||
954 | return -EINVAL; | ||
955 | |||
956 | pin = gc->base + gpiospec->args[0]; | ||
957 | |||
958 | if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) | ||
959 | pr_warn("gpio_xlate: failed to set pin function\n"); | ||
960 | if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) | ||
961 | pr_warn("gpio_xlate: failed to set pin pull up/down\n"); | ||
962 | |||
963 | if (flags) | ||
964 | *flags = gpiospec->args[2] >> 16; | ||
965 | |||
966 | return gpiospec->args[0]; | ||
967 | } | ||
968 | |||
969 | static const struct of_device_id s3c24xx_gpio_dt_match[] __initdata = { | ||
970 | { .compatible = "samsung,s3c24xx-gpio", }, | ||
971 | {} | ||
972 | }; | ||
973 | |||
974 | static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, | ||
975 | u64 base, u64 offset) | ||
976 | { | ||
977 | struct gpio_chip *gc = &chip->chip; | ||
978 | u64 address; | ||
979 | |||
980 | if (!of_have_populated_dt()) | ||
981 | return; | ||
982 | |||
983 | address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; | ||
984 | gc->of_node = of_find_matching_node_by_address(NULL, | ||
985 | s3c24xx_gpio_dt_match, address); | ||
986 | if (!gc->of_node) { | ||
987 | pr_info("gpio: device tree node not found for gpio controller" | ||
988 | " with base address %08llx\n", address); | ||
989 | return; | ||
990 | } | ||
991 | gc->of_gpio_n_cells = 3; | ||
992 | gc->of_xlate = s3c24xx_gpio_xlate; | ||
993 | } | ||
994 | #else | ||
995 | static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, | ||
996 | u64 base, u64 offset) | ||
997 | { | ||
998 | return; | ||
999 | } | ||
1000 | #endif /* defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) */ | ||
1001 | |||
941 | static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, | 1002 | static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, |
942 | int nr_chips, void __iomem *base) | 1003 | int nr_chips, void __iomem *base) |
943 | { | 1004 | { |
@@ -962,6 +1023,8 @@ static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, | |||
962 | gc->direction_output = samsung_gpiolib_2bit_output; | 1023 | gc->direction_output = samsung_gpiolib_2bit_output; |
963 | 1024 | ||
964 | samsung_gpiolib_add(chip); | 1025 | samsung_gpiolib_add(chip); |
1026 | |||
1027 | s3c24xx_gpiolib_attach_ofnode(chip, S3C24XX_PA_GPIO, i * 0x10); | ||
965 | } | 1028 | } |
966 | } | 1029 | } |
967 | 1030 | ||
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c new file mode 100644 index 000000000000..bcd8e4aa7c7d --- /dev/null +++ b/drivers/gpio/gpio-vt8500.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* drivers/gpio/gpio-vt8500.c | ||
2 | * | ||
3 | * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> | ||
4 | * Based on arch/arm/mach-vt8500/gpio.c: | ||
5 | * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/bitops.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/of_address.h> | ||
26 | #include <linux/of_irq.h> | ||
27 | #include <linux/of_device.h> | ||
28 | |||
29 | /* | ||
30 | We handle GPIOs by bank, each bank containing up to 32 GPIOs covered | ||
31 | by one set of registers (although not all may be valid). | ||
32 | |||
33 | Because different SoC's have different register offsets, we pass the | ||
34 | register offsets as data in vt8500_gpio_dt_ids[]. | ||
35 | |||
36 | A value of NO_REG is used to indicate that this register is not | ||
37 | supported. Only used for ->en at the moment. | ||
38 | */ | ||
39 | |||
40 | #define NO_REG 0xFFFF | ||
41 | |||
42 | /* | ||
43 | * struct vt8500_gpio_bank_regoffsets | ||
44 | * @en: offset to enable register of the bank | ||
45 | * @dir: offset to direction register of the bank | ||
46 | * @data_out: offset to the data out register of the bank | ||
47 | * @data_in: offset to the data in register of the bank | ||
48 | * @ngpio: highest valid pin in this bank | ||
49 | */ | ||
50 | |||
51 | struct vt8500_gpio_bank_regoffsets { | ||
52 | unsigned int en; | ||
53 | unsigned int dir; | ||
54 | unsigned int data_out; | ||
55 | unsigned int data_in; | ||
56 | unsigned char ngpio; | ||
57 | }; | ||
58 | |||
59 | struct vt8500_gpio_data { | ||
60 | unsigned int num_banks; | ||
61 | struct vt8500_gpio_bank_regoffsets banks[]; | ||
62 | }; | ||
63 | |||
64 | #define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \ | ||
65 | { \ | ||
66 | .en = __en, \ | ||
67 | .dir = __dir, \ | ||
68 | .data_out = __out, \ | ||
69 | .data_in = __in, \ | ||
70 | .ngpio = __ngpio, \ | ||
71 | } | ||
72 | |||
73 | static struct vt8500_gpio_data vt8500_data = { | ||
74 | .num_banks = 7, | ||
75 | .banks = { | ||
76 | VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), | ||
77 | VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), | ||
78 | VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), | ||
79 | VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), | ||
80 | VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), | ||
81 | VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), | ||
82 | VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), | ||
83 | }, | ||
84 | }; | ||
85 | |||
86 | static struct vt8500_gpio_data wm8505_data = { | ||
87 | .num_banks = 10, | ||
88 | .banks = { | ||
89 | VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), | ||
90 | VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), | ||
91 | VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), | ||
92 | VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16), | ||
93 | VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25), | ||
94 | VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5), | ||
95 | VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), | ||
96 | VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), | ||
97 | VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), | ||
98 | VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), | ||
99 | }, | ||
100 | }; | ||
101 | |||
102 | /* | ||
103 | * No information about which bits are valid so we just make | ||
104 | * them all available until its figured out. | ||
105 | */ | ||
106 | static struct vt8500_gpio_data wm8650_data = { | ||
107 | .num_banks = 9, | ||
108 | .banks = { | ||
109 | VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32), | ||
110 | VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32), | ||
111 | VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32), | ||
112 | VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32), | ||
113 | VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32), | ||
114 | VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32), | ||
115 | VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32), | ||
116 | VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32), | ||
117 | VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32), | ||
118 | }, | ||
119 | }; | ||
120 | |||
121 | struct vt8500_gpio_chip { | ||
122 | struct gpio_chip chip; | ||
123 | |||
124 | const struct vt8500_gpio_bank_regoffsets *regs; | ||
125 | void __iomem *base; | ||
126 | }; | ||
127 | |||
128 | |||
129 | #define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) | ||
130 | |||
131 | static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
132 | { | ||
133 | u32 val; | ||
134 | struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); | ||
135 | |||
136 | if (vt8500_chip->regs->en == NO_REG) | ||
137 | return 0; | ||
138 | |||
139 | val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); | ||
140 | val |= BIT(offset); | ||
141 | writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
147 | { | ||
148 | struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); | ||
149 | u32 val; | ||
150 | |||
151 | if (vt8500_chip->regs->en == NO_REG) | ||
152 | return; | ||
153 | |||
154 | val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); | ||
155 | val &= ~BIT(offset); | ||
156 | writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); | ||
157 | } | ||
158 | |||
159 | static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
160 | { | ||
161 | struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); | ||
162 | |||
163 | u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); | ||
164 | val &= ~BIT(offset); | ||
165 | writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | ||
171 | int value) | ||
172 | { | ||
173 | struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); | ||
174 | |||
175 | u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); | ||
176 | val |= BIT(offset); | ||
177 | writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); | ||
178 | |||
179 | if (value) { | ||
180 | val = readl_relaxed(vt8500_chip->base + | ||
181 | vt8500_chip->regs->data_out); | ||
182 | val |= BIT(offset); | ||
183 | writel_relaxed(val, vt8500_chip->base + | ||
184 | vt8500_chip->regs->data_out); | ||
185 | } | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset) | ||
190 | { | ||
191 | struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); | ||
192 | |||
193 | return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >> | ||
194 | offset) & 1; | ||
195 | } | ||
196 | |||
197 | static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset, | ||
198 | int value) | ||
199 | { | ||
200 | struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); | ||
201 | |||
202 | u32 val = readl_relaxed(vt8500_chip->base + | ||
203 | vt8500_chip->regs->data_out); | ||
204 | if (value) | ||
205 | val |= BIT(offset); | ||
206 | else | ||
207 | val &= ~BIT(offset); | ||
208 | |||
209 | writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out); | ||
210 | } | ||
211 | |||
212 | static int vt8500_of_xlate(struct gpio_chip *gc, | ||
213 | const struct of_phandle_args *gpiospec, u32 *flags) | ||
214 | { | ||
215 | /* bank if specificed in gpiospec->args[0] */ | ||
216 | if (flags) | ||
217 | *flags = gpiospec->args[2]; | ||
218 | |||
219 | return gpiospec->args[1]; | ||
220 | } | ||
221 | |||
222 | static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base, | ||
223 | const struct vt8500_gpio_data *data) | ||
224 | { | ||
225 | struct vt8500_gpio_chip *vtchip; | ||
226 | struct gpio_chip *chip; | ||
227 | int i; | ||
228 | int pin_cnt = 0; | ||
229 | |||
230 | vtchip = devm_kzalloc(&pdev->dev, | ||
231 | sizeof(struct vt8500_gpio_chip) * data->num_banks, | ||
232 | GFP_KERNEL); | ||
233 | if (!vtchip) { | ||
234 | pr_err("%s: failed to allocate chip memory\n", __func__); | ||
235 | return -ENOMEM; | ||
236 | } | ||
237 | |||
238 | for (i = 0; i < data->num_banks; i++) { | ||
239 | vtchip[i].base = base; | ||
240 | vtchip[i].regs = &data->banks[i]; | ||
241 | |||
242 | chip = &vtchip[i].chip; | ||
243 | |||
244 | chip->of_xlate = vt8500_of_xlate; | ||
245 | chip->of_gpio_n_cells = 3; | ||
246 | chip->of_node = pdev->dev.of_node; | ||
247 | |||
248 | chip->request = vt8500_gpio_request; | ||
249 | chip->free = vt8500_gpio_free; | ||
250 | chip->direction_input = vt8500_gpio_direction_input; | ||
251 | chip->direction_output = vt8500_gpio_direction_output; | ||
252 | chip->get = vt8500_gpio_get_value; | ||
253 | chip->set = vt8500_gpio_set_value; | ||
254 | chip->can_sleep = 0; | ||
255 | chip->base = pin_cnt; | ||
256 | chip->ngpio = data->banks[i].ngpio; | ||
257 | |||
258 | pin_cnt += data->banks[i].ngpio; | ||
259 | |||
260 | gpiochip_add(chip); | ||
261 | } | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static struct of_device_id vt8500_gpio_dt_ids[] = { | ||
266 | { .compatible = "via,vt8500-gpio", .data = &vt8500_data, }, | ||
267 | { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, }, | ||
268 | { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, }, | ||
269 | { /* Sentinel */ }, | ||
270 | }; | ||
271 | |||
272 | static int __devinit vt8500_gpio_probe(struct platform_device *pdev) | ||
273 | { | ||
274 | void __iomem *gpio_base; | ||
275 | struct device_node *np; | ||
276 | const struct of_device_id *of_id = | ||
277 | of_match_device(vt8500_gpio_dt_ids, &pdev->dev); | ||
278 | |||
279 | if (!of_id) { | ||
280 | dev_err(&pdev->dev, "Failed to find gpio controller\n"); | ||
281 | return -ENODEV; | ||
282 | } | ||
283 | |||
284 | np = pdev->dev.of_node; | ||
285 | if (!np) { | ||
286 | dev_err(&pdev->dev, "Missing GPIO description in devicetree\n"); | ||
287 | return -EFAULT; | ||
288 | } | ||
289 | |||
290 | gpio_base = of_iomap(np, 0); | ||
291 | if (!gpio_base) { | ||
292 | dev_err(&pdev->dev, "Unable to map GPIO registers\n"); | ||
293 | of_node_put(np); | ||
294 | return -ENOMEM; | ||
295 | } | ||
296 | |||
297 | vt8500_add_chips(pdev, gpio_base, of_id->data); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static struct platform_driver vt8500_gpio_driver = { | ||
303 | .probe = vt8500_gpio_probe, | ||
304 | .driver = { | ||
305 | .name = "vt8500-gpio", | ||
306 | .owner = THIS_MODULE, | ||
307 | .of_match_table = vt8500_gpio_dt_ids, | ||
308 | }, | ||
309 | }; | ||
310 | |||
311 | module_platform_driver(vt8500_gpio_driver); | ||
312 | |||
313 | MODULE_DESCRIPTION("VT8500 GPIO Driver"); | ||
314 | MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); | ||
315 | MODULE_LICENSE("GPL v2"); | ||
316 | MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids); | ||
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index f06231b7cab1..84ec691c05aa 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c | |||
@@ -74,8 +74,8 @@ static int __devinit ab8500_ponkey_probe(struct platform_device *pdev) | |||
74 | 74 | ||
75 | ponkey->idev = input; | 75 | ponkey->idev = input; |
76 | ponkey->ab8500 = ab8500; | 76 | ponkey->ab8500 = ab8500; |
77 | ponkey->irq_dbf = ab8500_irq_get_virq(ab8500, irq_dbf); | 77 | ponkey->irq_dbf = irq_dbf; |
78 | ponkey->irq_dbr = ab8500_irq_get_virq(ab8500, irq_dbr); | 78 | ponkey->irq_dbr = irq_dbr; |
79 | 79 | ||
80 | input->name = "AB8500 POn(PowerOn) Key"; | 80 | input->name = "AB8500 POn(PowerOn) Key"; |
81 | input->dev.parent = &pdev->dev; | 81 | input->dev.parent = &pdev->dev; |
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 0e63cdd9b52a..6b67edbdbd01 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
@@ -418,6 +418,9 @@ static struct { | |||
418 | 418 | ||
419 | static atomic_t ac_wake_req_state = ATOMIC_INIT(0); | 419 | static atomic_t ac_wake_req_state = ATOMIC_INIT(0); |
420 | 420 | ||
421 | /* Functions definition */ | ||
422 | static void compute_armss_rate(void); | ||
423 | |||
421 | /* Spinlocks */ | 424 | /* Spinlocks */ |
422 | static DEFINE_SPINLOCK(prcmu_lock); | 425 | static DEFINE_SPINLOCK(prcmu_lock); |
423 | static DEFINE_SPINLOCK(clkout_lock); | 426 | static DEFINE_SPINLOCK(clkout_lock); |
@@ -517,6 +520,7 @@ static struct dsiescclk dsiescclk[3] = { | |||
517 | } | 520 | } |
518 | }; | 521 | }; |
519 | 522 | ||
523 | |||
520 | /* | 524 | /* |
521 | * Used by MCDE to setup all necessary PRCMU registers | 525 | * Used by MCDE to setup all necessary PRCMU registers |
522 | */ | 526 | */ |
@@ -1013,6 +1017,7 @@ int db8500_prcmu_set_arm_opp(u8 opp) | |||
1013 | (mb1_transfer.ack.arm_opp != opp)) | 1017 | (mb1_transfer.ack.arm_opp != opp)) |
1014 | r = -EIO; | 1018 | r = -EIO; |
1015 | 1019 | ||
1020 | compute_armss_rate(); | ||
1016 | mutex_unlock(&mb1_transfer.lock); | 1021 | mutex_unlock(&mb1_transfer.lock); |
1017 | 1022 | ||
1018 | return r; | 1023 | return r; |
@@ -1612,6 +1617,7 @@ static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate, | |||
1612 | if ((branch == PLL_FIX) || ((branch == PLL_DIV) && | 1617 | if ((branch == PLL_FIX) || ((branch == PLL_DIV) && |
1613 | (val & PRCM_PLL_FREQ_DIV2EN) && | 1618 | (val & PRCM_PLL_FREQ_DIV2EN) && |
1614 | ((reg == PRCM_PLLSOC0_FREQ) || | 1619 | ((reg == PRCM_PLLSOC0_FREQ) || |
1620 | (reg == PRCM_PLLARM_FREQ) || | ||
1615 | (reg == PRCM_PLLDDR_FREQ)))) | 1621 | (reg == PRCM_PLLDDR_FREQ)))) |
1616 | div *= 2; | 1622 | div *= 2; |
1617 | 1623 | ||
@@ -1661,6 +1667,39 @@ static unsigned long clock_rate(u8 clock) | |||
1661 | else | 1667 | else |
1662 | return 0; | 1668 | return 0; |
1663 | } | 1669 | } |
1670 | static unsigned long latest_armss_rate; | ||
1671 | static unsigned long armss_rate(void) | ||
1672 | { | ||
1673 | return latest_armss_rate; | ||
1674 | } | ||
1675 | |||
1676 | static void compute_armss_rate(void) | ||
1677 | { | ||
1678 | u32 r; | ||
1679 | unsigned long rate; | ||
1680 | |||
1681 | r = readl(PRCM_ARM_CHGCLKREQ); | ||
1682 | |||
1683 | if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) { | ||
1684 | /* External ARMCLKFIX clock */ | ||
1685 | |||
1686 | rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX); | ||
1687 | |||
1688 | /* Check PRCM_ARM_CHGCLKREQ divider */ | ||
1689 | if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL)) | ||
1690 | rate /= 2; | ||
1691 | |||
1692 | /* Check PRCM_ARMCLKFIX_MGT divider */ | ||
1693 | r = readl(PRCM_ARMCLKFIX_MGT); | ||
1694 | r &= PRCM_CLK_MGT_CLKPLLDIV_MASK; | ||
1695 | rate /= r; | ||
1696 | |||
1697 | } else {/* ARM PLL */ | ||
1698 | rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV); | ||
1699 | } | ||
1700 | |||
1701 | latest_armss_rate = rate; | ||
1702 | } | ||
1664 | 1703 | ||
1665 | static unsigned long dsiclk_rate(u8 n) | 1704 | static unsigned long dsiclk_rate(u8 n) |
1666 | { | 1705 | { |
@@ -1707,6 +1746,8 @@ unsigned long prcmu_clock_rate(u8 clock) | |||
1707 | return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW); | 1746 | return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW); |
1708 | else if (clock == PRCMU_PLLSOC1) | 1747 | else if (clock == PRCMU_PLLSOC1) |
1709 | return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW); | 1748 | return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW); |
1749 | else if (clock == PRCMU_ARMSS) | ||
1750 | return armss_rate(); | ||
1710 | else if (clock == PRCMU_PLLDDR) | 1751 | else if (clock == PRCMU_PLLDDR) |
1711 | return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW); | 1752 | return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW); |
1712 | else if (clock == PRCMU_PLLDSI) | 1753 | else if (clock == PRCMU_PLLDSI) |
@@ -2693,6 +2734,7 @@ void __init db8500_prcmu_early_init(void) | |||
2693 | handle_simple_irq); | 2734 | handle_simple_irq); |
2694 | set_irq_flags(irq, IRQF_VALID); | 2735 | set_irq_flags(irq, IRQF_VALID); |
2695 | } | 2736 | } |
2737 | compute_armss_rate(); | ||
2696 | } | 2738 | } |
2697 | 2739 | ||
2698 | static void __init init_prcm_registers(void) | 2740 | static void __init init_prcm_registers(void) |
diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h index 23108a6e3167..79c76ebdba52 100644 --- a/drivers/mfd/dbx500-prcmu-regs.h +++ b/drivers/mfd/dbx500-prcmu-regs.h | |||
@@ -61,7 +61,8 @@ | |||
61 | #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2 | 61 | #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2 |
62 | 62 | ||
63 | #define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114) | 63 | #define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114) |
64 | #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1 | 64 | #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0) |
65 | #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL BIT(16) | ||
65 | 66 | ||
66 | #define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98) | 67 | #define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98) |
67 | #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1 | 68 | #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1 |
@@ -140,6 +141,7 @@ | |||
140 | /* PRCMU clock/PLL/reset registers */ | 141 | /* PRCMU clock/PLL/reset registers */ |
141 | #define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080) | 142 | #define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080) |
142 | #define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084) | 143 | #define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084) |
144 | #define PRCM_PLLARM_FREQ (_PRCMU_BASE + 0x088) | ||
143 | #define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C) | 145 | #define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C) |
144 | #define PRCM_PLL_FREQ_D_SHIFT 0 | 146 | #define PRCM_PLL_FREQ_D_SHIFT 0 |
145 | #define PRCM_PLL_FREQ_D_MASK BITS(0, 7) | 147 | #define PRCM_PLL_FREQ_D_MASK BITS(0, 7) |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 252aaefcacfa..d944d6ef7da8 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/irq.h> | 23 | #include <linux/irq.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
25 | 27 | ||
26 | #include <mach/dma.h> | 28 | #include <mach/dma.h> |
27 | #include <plat/pxa3xx_nand.h> | 29 | #include <plat/pxa3xx_nand.h> |
@@ -1032,7 +1034,7 @@ static int alloc_nand_resource(struct platform_device *pdev) | |||
1032 | struct pxa3xx_nand_platform_data *pdata; | 1034 | struct pxa3xx_nand_platform_data *pdata; |
1033 | struct pxa3xx_nand_info *info; | 1035 | struct pxa3xx_nand_info *info; |
1034 | struct pxa3xx_nand_host *host; | 1036 | struct pxa3xx_nand_host *host; |
1035 | struct nand_chip *chip; | 1037 | struct nand_chip *chip = NULL; |
1036 | struct mtd_info *mtd; | 1038 | struct mtd_info *mtd; |
1037 | struct resource *r; | 1039 | struct resource *r; |
1038 | int ret, irq, cs; | 1040 | int ret, irq, cs; |
@@ -1081,21 +1083,31 @@ static int alloc_nand_resource(struct platform_device *pdev) | |||
1081 | } | 1083 | } |
1082 | clk_enable(info->clk); | 1084 | clk_enable(info->clk); |
1083 | 1085 | ||
1084 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 1086 | /* |
1085 | if (r == NULL) { | 1087 | * This is a dirty hack to make this driver work from devicetree |
1086 | dev_err(&pdev->dev, "no resource defined for data DMA\n"); | 1088 | * bindings. It can be removed once we have a prober DMA controller |
1087 | ret = -ENXIO; | 1089 | * framework for DT. |
1088 | goto fail_put_clk; | 1090 | */ |
1089 | } | 1091 | if (pdev->dev.of_node && cpu_is_pxa3xx()) { |
1090 | info->drcmr_dat = r->start; | 1092 | info->drcmr_dat = 97; |
1093 | info->drcmr_cmd = 99; | ||
1094 | } else { | ||
1095 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
1096 | if (r == NULL) { | ||
1097 | dev_err(&pdev->dev, "no resource defined for data DMA\n"); | ||
1098 | ret = -ENXIO; | ||
1099 | goto fail_put_clk; | ||
1100 | } | ||
1101 | info->drcmr_dat = r->start; | ||
1091 | 1102 | ||
1092 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 1103 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
1093 | if (r == NULL) { | 1104 | if (r == NULL) { |
1094 | dev_err(&pdev->dev, "no resource defined for command DMA\n"); | 1105 | dev_err(&pdev->dev, "no resource defined for command DMA\n"); |
1095 | ret = -ENXIO; | 1106 | ret = -ENXIO; |
1096 | goto fail_put_clk; | 1107 | goto fail_put_clk; |
1108 | } | ||
1109 | info->drcmr_cmd = r->start; | ||
1097 | } | 1110 | } |
1098 | info->drcmr_cmd = r->start; | ||
1099 | 1111 | ||
1100 | irq = platform_get_irq(pdev, 0); | 1112 | irq = platform_get_irq(pdev, 0); |
1101 | if (irq < 0) { | 1113 | if (irq < 0) { |
@@ -1200,12 +1212,55 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) | |||
1200 | return 0; | 1212 | return 0; |
1201 | } | 1213 | } |
1202 | 1214 | ||
1215 | #ifdef CONFIG_OF | ||
1216 | static struct of_device_id pxa3xx_nand_dt_ids[] = { | ||
1217 | { .compatible = "marvell,pxa3xx-nand" }, | ||
1218 | {} | ||
1219 | }; | ||
1220 | MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); | ||
1221 | |||
1222 | static int pxa3xx_nand_probe_dt(struct platform_device *pdev) | ||
1223 | { | ||
1224 | struct pxa3xx_nand_platform_data *pdata; | ||
1225 | struct device_node *np = pdev->dev.of_node; | ||
1226 | const struct of_device_id *of_id = | ||
1227 | of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); | ||
1228 | |||
1229 | if (!of_id) | ||
1230 | return 0; | ||
1231 | |||
1232 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
1233 | if (!pdata) | ||
1234 | return -ENOMEM; | ||
1235 | |||
1236 | if (of_get_property(np, "marvell,nand-enable-arbiter", NULL)) | ||
1237 | pdata->enable_arbiter = 1; | ||
1238 | if (of_get_property(np, "marvell,nand-keep-config", NULL)) | ||
1239 | pdata->keep_config = 1; | ||
1240 | of_property_read_u32(np, "num-cs", &pdata->num_cs); | ||
1241 | |||
1242 | pdev->dev.platform_data = pdata; | ||
1243 | |||
1244 | return 0; | ||
1245 | } | ||
1246 | #else | ||
1247 | static inline int pxa3xx_nand_probe_dt(struct platform_device *pdev) | ||
1248 | { | ||
1249 | return 0; | ||
1250 | } | ||
1251 | #endif | ||
1252 | |||
1203 | static int pxa3xx_nand_probe(struct platform_device *pdev) | 1253 | static int pxa3xx_nand_probe(struct platform_device *pdev) |
1204 | { | 1254 | { |
1205 | struct pxa3xx_nand_platform_data *pdata; | 1255 | struct pxa3xx_nand_platform_data *pdata; |
1256 | struct mtd_part_parser_data ppdata = {}; | ||
1206 | struct pxa3xx_nand_info *info; | 1257 | struct pxa3xx_nand_info *info; |
1207 | int ret, cs, probe_success; | 1258 | int ret, cs, probe_success; |
1208 | 1259 | ||
1260 | ret = pxa3xx_nand_probe_dt(pdev); | ||
1261 | if (ret) | ||
1262 | return ret; | ||
1263 | |||
1209 | pdata = pdev->dev.platform_data; | 1264 | pdata = pdev->dev.platform_data; |
1210 | if (!pdata) { | 1265 | if (!pdata) { |
1211 | dev_err(&pdev->dev, "no platform data defined\n"); | 1266 | dev_err(&pdev->dev, "no platform data defined\n"); |
@@ -1229,8 +1284,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) | |||
1229 | continue; | 1284 | continue; |
1230 | } | 1285 | } |
1231 | 1286 | ||
1287 | ppdata.of_node = pdev->dev.of_node; | ||
1232 | ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, | 1288 | ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, |
1233 | NULL, pdata->parts[cs], | 1289 | &ppdata, pdata->parts[cs], |
1234 | pdata->nr_parts[cs]); | 1290 | pdata->nr_parts[cs]); |
1235 | if (!ret) | 1291 | if (!ret) |
1236 | probe_success = 1; | 1292 | probe_success = 1; |
@@ -1306,6 +1362,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) | |||
1306 | static struct platform_driver pxa3xx_nand_driver = { | 1362 | static struct platform_driver pxa3xx_nand_driver = { |
1307 | .driver = { | 1363 | .driver = { |
1308 | .name = "pxa3xx-nand", | 1364 | .name = "pxa3xx-nand", |
1365 | .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids), | ||
1309 | }, | 1366 | }, |
1310 | .probe = pxa3xx_nand_probe, | 1367 | .probe = pxa3xx_nand_probe, |
1311 | .remove = pxa3xx_nand_remove, | 1368 | .remove = pxa3xx_nand_remove, |
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 7fca6ce5952b..304360cd213e 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/pinctrl/pinctrl.h> | 17 | #include <linux/pinctrl/pinctrl.h> |
18 | #include <linux/pinctrl/pinmux.h> | 18 | #include <linux/pinctrl/pinmux.h> |
19 | #include <linux/pinctrl/consumer.h> | 19 | #include <linux/pinctrl/consumer.h> |
20 | #include <linux/pinctrl/machine.h> | ||
20 | #include <linux/of.h> | 21 | #include <linux/of.h> |
21 | #include <linux/of_address.h> | 22 | #include <linux/of_address.h> |
22 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
@@ -916,11 +917,66 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s | |||
916 | seq_printf(s, " " DRIVER_NAME); | 917 | seq_printf(s, " " DRIVER_NAME); |
917 | } | 918 | } |
918 | 919 | ||
920 | static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
921 | struct device_node *np_config, | ||
922 | struct pinctrl_map **map, unsigned *num_maps) | ||
923 | { | ||
924 | struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev); | ||
925 | struct device_node *np; | ||
926 | struct property *prop; | ||
927 | const char *function, *group; | ||
928 | int ret, index = 0, count = 0; | ||
929 | |||
930 | /* calculate number of maps required */ | ||
931 | for_each_child_of_node(np_config, np) { | ||
932 | ret = of_property_read_string(np, "sirf,function", &function); | ||
933 | if (ret < 0) | ||
934 | return ret; | ||
935 | |||
936 | ret = of_property_count_strings(np, "sirf,pins"); | ||
937 | if (ret < 0) | ||
938 | return ret; | ||
939 | |||
940 | count += ret; | ||
941 | } | ||
942 | |||
943 | if (!count) { | ||
944 | dev_err(spmx->dev, "No child nodes passed via DT\n"); | ||
945 | return -ENODEV; | ||
946 | } | ||
947 | |||
948 | *map = kzalloc(sizeof(**map) * count, GFP_KERNEL); | ||
949 | if (!*map) | ||
950 | return -ENOMEM; | ||
951 | |||
952 | for_each_child_of_node(np_config, np) { | ||
953 | of_property_read_string(np, "sirf,function", &function); | ||
954 | of_property_for_each_string(np, "sirf,pins", prop, group) { | ||
955 | (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP; | ||
956 | (*map)[index].data.mux.group = group; | ||
957 | (*map)[index].data.mux.function = function; | ||
958 | index++; | ||
959 | } | ||
960 | } | ||
961 | |||
962 | *num_maps = count; | ||
963 | |||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev, | ||
968 | struct pinctrl_map *map, unsigned num_maps) | ||
969 | { | ||
970 | kfree(map); | ||
971 | } | ||
972 | |||
919 | static struct pinctrl_ops sirfsoc_pctrl_ops = { | 973 | static struct pinctrl_ops sirfsoc_pctrl_ops = { |
920 | .get_groups_count = sirfsoc_get_groups_count, | 974 | .get_groups_count = sirfsoc_get_groups_count, |
921 | .get_group_name = sirfsoc_get_group_name, | 975 | .get_group_name = sirfsoc_get_group_name, |
922 | .get_group_pins = sirfsoc_get_group_pins, | 976 | .get_group_pins = sirfsoc_get_group_pins, |
923 | .pin_dbg_show = sirfsoc_pin_dbg_show, | 977 | .pin_dbg_show = sirfsoc_pin_dbg_show, |
978 | .dt_node_to_map = sirfsoc_dt_node_to_map, | ||
979 | .dt_free_map = sirfsoc_dt_free_map, | ||
924 | }; | 980 | }; |
925 | 981 | ||
926 | struct sirfsoc_pmx_func { | 982 | struct sirfsoc_pmx_func { |
@@ -1221,7 +1277,7 @@ out_no_gpio_remap: | |||
1221 | } | 1277 | } |
1222 | 1278 | ||
1223 | static const struct of_device_id pinmux_ids[] __devinitconst = { | 1279 | static const struct of_device_id pinmux_ids[] __devinitconst = { |
1224 | { .compatible = "sirf,prima2-gpio-pinmux" }, | 1280 | { .compatible = "sirf,prima2-pinctrl" }, |
1225 | {} | 1281 | {} |
1226 | }; | 1282 | }; |
1227 | 1283 | ||
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index bf3c2f669c3c..2e5970fe9eeb 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c | |||
@@ -462,16 +462,10 @@ static int __devexit ab8500_rtc_remove(struct platform_device *pdev) | |||
462 | return 0; | 462 | return 0; |
463 | } | 463 | } |
464 | 464 | ||
465 | static const struct of_device_id ab8500_rtc_match[] = { | ||
466 | { .compatible = "stericsson,ab8500-rtc", }, | ||
467 | {} | ||
468 | }; | ||
469 | |||
470 | static struct platform_driver ab8500_rtc_driver = { | 465 | static struct platform_driver ab8500_rtc_driver = { |
471 | .driver = { | 466 | .driver = { |
472 | .name = "ab8500-rtc", | 467 | .name = "ab8500-rtc", |
473 | .owner = THIS_MODULE, | 468 | .owner = THIS_MODULE, |
474 | .of_match_table = ab8500_rtc_match, | ||
475 | }, | 469 | }, |
476 | .probe = ab8500_rtc_probe, | 470 | .probe = ab8500_rtc_probe, |
477 | .remove = __devexit_p(ab8500_rtc_remove), | 471 | .remove = __devexit_p(ab8500_rtc_remove), |
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index 0075c8fd93d8..f771b2ee4b18 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/of.h> | ||
31 | #include <linux/of_device.h> | ||
30 | 32 | ||
31 | #include <mach/hardware.h> | 33 | #include <mach/hardware.h> |
32 | 34 | ||
@@ -396,6 +398,14 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev) | |||
396 | return 0; | 398 | return 0; |
397 | } | 399 | } |
398 | 400 | ||
401 | #ifdef CONFIG_OF | ||
402 | static struct of_device_id pxa_rtc_dt_ids[] = { | ||
403 | { .compatible = "marvell,pxa-rtc" }, | ||
404 | {} | ||
405 | }; | ||
406 | MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids); | ||
407 | #endif | ||
408 | |||
399 | #ifdef CONFIG_PM | 409 | #ifdef CONFIG_PM |
400 | static int pxa_rtc_suspend(struct device *dev) | 410 | static int pxa_rtc_suspend(struct device *dev) |
401 | { | 411 | { |
@@ -425,6 +435,7 @@ static struct platform_driver pxa_rtc_driver = { | |||
425 | .remove = __exit_p(pxa_rtc_remove), | 435 | .remove = __exit_p(pxa_rtc_remove), |
426 | .driver = { | 436 | .driver = { |
427 | .name = "pxa-rtc", | 437 | .name = "pxa-rtc", |
438 | .of_match_table = of_match_ptr(pxa_rtc_dt_ids), | ||
428 | #ifdef CONFIG_PM | 439 | #ifdef CONFIG_PM |
429 | .pm = &pxa_rtc_pm_ops, | 440 | .pm = &pxa_rtc_pm_ops, |
430 | #endif | 441 | #endif |
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 9e94fb147c26..07bf19364a74 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/bcd.h> | 23 | #include <linux/bcd.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/of.h> | ||
26 | 27 | ||
27 | /* | 28 | /* |
28 | * Register definitions | 29 | * Register definitions |
@@ -302,12 +303,18 @@ static int __devexit vt8500_rtc_remove(struct platform_device *pdev) | |||
302 | return 0; | 303 | return 0; |
303 | } | 304 | } |
304 | 305 | ||
306 | static const struct of_device_id wmt_dt_ids[] = { | ||
307 | { .compatible = "via,vt8500-rtc", }, | ||
308 | {} | ||
309 | }; | ||
310 | |||
305 | static struct platform_driver vt8500_rtc_driver = { | 311 | static struct platform_driver vt8500_rtc_driver = { |
306 | .probe = vt8500_rtc_probe, | 312 | .probe = vt8500_rtc_probe, |
307 | .remove = __devexit_p(vt8500_rtc_remove), | 313 | .remove = __devexit_p(vt8500_rtc_remove), |
308 | .driver = { | 314 | .driver = { |
309 | .name = "vt8500-rtc", | 315 | .name = "vt8500-rtc", |
310 | .owner = THIS_MODULE, | 316 | .owner = THIS_MODULE, |
317 | .of_match_table = of_match_ptr(wmt_dt_ids), | ||
311 | }, | 318 | }, |
312 | }; | 319 | }; |
313 | 320 | ||
@@ -315,5 +322,5 @@ module_platform_driver(vt8500_rtc_driver); | |||
315 | 322 | ||
316 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); | 323 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); |
317 | MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)"); | 324 | MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)"); |
318 | MODULE_LICENSE("GPL"); | 325 | MODULE_LICENSE("GPL v2"); |
319 | MODULE_ALIAS("platform:vt8500-rtc"); | 326 | MODULE_ALIAS("platform:vt8500-rtc"); |
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 2be006fb3da0..205d4cf4a063 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/clk.h> | 35 | #include <linux/clk.h> |
36 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
37 | #include <linux/of.h> | ||
37 | 38 | ||
38 | /* | 39 | /* |
39 | * UART Register offsets | 40 | * UART Register offsets |
@@ -76,6 +77,8 @@ | |||
76 | #define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) | 77 | #define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) |
77 | #define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) | 78 | #define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) |
78 | 79 | ||
80 | #define VT8500_MAX_PORTS 6 | ||
81 | |||
79 | struct vt8500_port { | 82 | struct vt8500_port { |
80 | struct uart_port uart; | 83 | struct uart_port uart; |
81 | char name[16]; | 84 | char name[16]; |
@@ -83,6 +86,13 @@ struct vt8500_port { | |||
83 | unsigned int ier; | 86 | unsigned int ier; |
84 | }; | 87 | }; |
85 | 88 | ||
89 | /* | ||
90 | * we use this variable to keep track of which ports | ||
91 | * have been allocated as we can't use pdev->id in | ||
92 | * devicetree | ||
93 | */ | ||
94 | static unsigned long vt8500_ports_in_use; | ||
95 | |||
86 | static inline void vt8500_write(struct uart_port *port, unsigned int val, | 96 | static inline void vt8500_write(struct uart_port *port, unsigned int val, |
87 | unsigned int off) | 97 | unsigned int off) |
88 | { | 98 | { |
@@ -431,7 +441,7 @@ static int vt8500_verify_port(struct uart_port *port, | |||
431 | return 0; | 441 | return 0; |
432 | } | 442 | } |
433 | 443 | ||
434 | static struct vt8500_port *vt8500_uart_ports[4]; | 444 | static struct vt8500_port *vt8500_uart_ports[VT8500_MAX_PORTS]; |
435 | static struct uart_driver vt8500_uart_driver; | 445 | static struct uart_driver vt8500_uart_driver; |
436 | 446 | ||
437 | #ifdef CONFIG_SERIAL_VT8500_CONSOLE | 447 | #ifdef CONFIG_SERIAL_VT8500_CONSOLE |
@@ -548,7 +558,9 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) | |||
548 | { | 558 | { |
549 | struct vt8500_port *vt8500_port; | 559 | struct vt8500_port *vt8500_port; |
550 | struct resource *mmres, *irqres; | 560 | struct resource *mmres, *irqres; |
561 | struct device_node *np = pdev->dev.of_node; | ||
551 | int ret; | 562 | int ret; |
563 | int port; | ||
552 | 564 | ||
553 | mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 565 | mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
554 | irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 566 | irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
@@ -559,16 +571,46 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) | |||
559 | if (!vt8500_port) | 571 | if (!vt8500_port) |
560 | return -ENOMEM; | 572 | return -ENOMEM; |
561 | 573 | ||
574 | if (np) | ||
575 | port = of_alias_get_id(np, "serial"); | ||
576 | if (port > VT8500_MAX_PORTS) | ||
577 | port = -1; | ||
578 | else | ||
579 | port = -1; | ||
580 | |||
581 | if (port < 0) { | ||
582 | /* calculate the port id */ | ||
583 | port = find_first_zero_bit(&vt8500_ports_in_use, | ||
584 | sizeof(vt8500_ports_in_use)); | ||
585 | } | ||
586 | |||
587 | if (port > VT8500_MAX_PORTS) | ||
588 | return -ENODEV; | ||
589 | |||
590 | /* reserve the port id */ | ||
591 | if (test_and_set_bit(port, &vt8500_ports_in_use)) { | ||
592 | /* port already in use - shouldn't really happen */ | ||
593 | return -EBUSY; | ||
594 | } | ||
595 | |||
562 | vt8500_port->uart.type = PORT_VT8500; | 596 | vt8500_port->uart.type = PORT_VT8500; |
563 | vt8500_port->uart.iotype = UPIO_MEM; | 597 | vt8500_port->uart.iotype = UPIO_MEM; |
564 | vt8500_port->uart.mapbase = mmres->start; | 598 | vt8500_port->uart.mapbase = mmres->start; |
565 | vt8500_port->uart.irq = irqres->start; | 599 | vt8500_port->uart.irq = irqres->start; |
566 | vt8500_port->uart.fifosize = 16; | 600 | vt8500_port->uart.fifosize = 16; |
567 | vt8500_port->uart.ops = &vt8500_uart_pops; | 601 | vt8500_port->uart.ops = &vt8500_uart_pops; |
568 | vt8500_port->uart.line = pdev->id; | 602 | vt8500_port->uart.line = port; |
569 | vt8500_port->uart.dev = &pdev->dev; | 603 | vt8500_port->uart.dev = &pdev->dev; |
570 | vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; | 604 | vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; |
571 | vt8500_port->uart.uartclk = 24000000; | 605 | |
606 | vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0); | ||
607 | if (vt8500_port->clk) { | ||
608 | vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk); | ||
609 | } else { | ||
610 | /* use the default of 24Mhz if not specified and warn */ | ||
611 | pr_warn("%s: serial clock source not specified\n", __func__); | ||
612 | vt8500_port->uart.uartclk = 24000000; | ||
613 | } | ||
572 | 614 | ||
573 | snprintf(vt8500_port->name, sizeof(vt8500_port->name), | 615 | snprintf(vt8500_port->name, sizeof(vt8500_port->name), |
574 | "VT8500 UART%d", pdev->id); | 616 | "VT8500 UART%d", pdev->id); |
@@ -579,7 +621,7 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) | |||
579 | goto err; | 621 | goto err; |
580 | } | 622 | } |
581 | 623 | ||
582 | vt8500_uart_ports[pdev->id] = vt8500_port; | 624 | vt8500_uart_ports[port] = vt8500_port; |
583 | 625 | ||
584 | uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart); | 626 | uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart); |
585 | 627 | ||
@@ -603,12 +645,18 @@ static int __devexit vt8500_serial_remove(struct platform_device *pdev) | |||
603 | return 0; | 645 | return 0; |
604 | } | 646 | } |
605 | 647 | ||
648 | static const struct of_device_id wmt_dt_ids[] = { | ||
649 | { .compatible = "via,vt8500-uart", }, | ||
650 | {} | ||
651 | }; | ||
652 | |||
606 | static struct platform_driver vt8500_platform_driver = { | 653 | static struct platform_driver vt8500_platform_driver = { |
607 | .probe = vt8500_serial_probe, | 654 | .probe = vt8500_serial_probe, |
608 | .remove = __devexit_p(vt8500_serial_remove), | 655 | .remove = __devexit_p(vt8500_serial_remove), |
609 | .driver = { | 656 | .driver = { |
610 | .name = "vt8500_serial", | 657 | .name = "vt8500_serial", |
611 | .owner = THIS_MODULE, | 658 | .owner = THIS_MODULE, |
659 | .of_match_table = of_match_ptr(wmt_dt_ids), | ||
612 | }, | 660 | }, |
613 | }; | 661 | }; |
614 | 662 | ||
@@ -642,4 +690,4 @@ module_exit(vt8500_serial_exit); | |||
642 | 690 | ||
643 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); | 691 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); |
644 | MODULE_DESCRIPTION("Driver for vt8500 serial device"); | 692 | MODULE_DESCRIPTION("Driver for vt8500 serial device"); |
645 | MODULE_LICENSE("GPL"); | 693 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0217f7415ef5..b66d951b8e32 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1788,7 +1788,7 @@ config FB_AU1200 | |||
1788 | 1788 | ||
1789 | config FB_VT8500 | 1789 | config FB_VT8500 |
1790 | bool "VT8500 LCD Driver" | 1790 | bool "VT8500 LCD Driver" |
1791 | depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_VT8500 | 1791 | depends on (FB = y) && ARM && ARCH_VT8500 |
1792 | select FB_WMT_GE_ROPS | 1792 | select FB_WMT_GE_ROPS |
1793 | select FB_SYS_IMAGEBLIT | 1793 | select FB_SYS_IMAGEBLIT |
1794 | help | 1794 | help |
@@ -1797,11 +1797,11 @@ config FB_VT8500 | |||
1797 | 1797 | ||
1798 | config FB_WM8505 | 1798 | config FB_WM8505 |
1799 | bool "WM8505 frame buffer support" | 1799 | bool "WM8505 frame buffer support" |
1800 | depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_WM8505 | 1800 | depends on (FB = y) && ARM && ARCH_VT8500 |
1801 | select FB_WMT_GE_ROPS | 1801 | select FB_WMT_GE_ROPS |
1802 | select FB_SYS_IMAGEBLIT | 1802 | select FB_SYS_IMAGEBLIT |
1803 | help | 1803 | help |
1804 | This is the framebuffer driver for WonderMedia WM8505 | 1804 | This is the framebuffer driver for WonderMedia WM8505/WM8650 |
1805 | integrated LCD controller. | 1805 | integrated LCD controller. |
1806 | 1806 | ||
1807 | source "drivers/video/geode/Kconfig" | 1807 | source "drivers/video/geode/Kconfig" |
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 2a5fe6ede845..d24595cd0c9b 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c | |||
@@ -35,6 +35,13 @@ | |||
35 | #include "vt8500lcdfb.h" | 35 | #include "vt8500lcdfb.h" |
36 | #include "wmt_ge_rops.h" | 36 | #include "wmt_ge_rops.h" |
37 | 37 | ||
38 | #ifdef CONFIG_OF | ||
39 | #include <linux/of.h> | ||
40 | #include <linux/of_fdt.h> | ||
41 | #include <linux/memblock.h> | ||
42 | #endif | ||
43 | |||
44 | |||
38 | #define to_vt8500lcd_info(__info) container_of(__info, \ | 45 | #define to_vt8500lcd_info(__info) container_of(__info, \ |
39 | struct vt8500lcd_info, fb) | 46 | struct vt8500lcd_info, fb) |
40 | 47 | ||
@@ -270,15 +277,21 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev) | |||
270 | { | 277 | { |
271 | struct vt8500lcd_info *fbi; | 278 | struct vt8500lcd_info *fbi; |
272 | struct resource *res; | 279 | struct resource *res; |
273 | struct vt8500fb_platform_data *pdata = pdev->dev.platform_data; | ||
274 | void *addr; | 280 | void *addr; |
275 | int irq, ret; | 281 | int irq, ret; |
276 | 282 | ||
283 | struct fb_videomode of_mode; | ||
284 | struct device_node *np; | ||
285 | u32 bpp; | ||
286 | dma_addr_t fb_mem_phys; | ||
287 | unsigned long fb_mem_len; | ||
288 | void *fb_mem_virt; | ||
289 | |||
277 | ret = -ENOMEM; | 290 | ret = -ENOMEM; |
278 | fbi = NULL; | 291 | fbi = NULL; |
279 | 292 | ||
280 | fbi = kzalloc(sizeof(struct vt8500lcd_info) + sizeof(u32) * 16, | 293 | fbi = devm_kzalloc(&pdev->dev, sizeof(struct vt8500lcd_info) |
281 | GFP_KERNEL); | 294 | + sizeof(u32) * 16, GFP_KERNEL); |
282 | if (!fbi) { | 295 | if (!fbi) { |
283 | dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); | 296 | dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); |
284 | ret = -ENOMEM; | 297 | ret = -ENOMEM; |
@@ -333,9 +346,45 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev) | |||
333 | goto failed_free_res; | 346 | goto failed_free_res; |
334 | } | 347 | } |
335 | 348 | ||
336 | fbi->fb.fix.smem_start = pdata->video_mem_phys; | 349 | np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0); |
337 | fbi->fb.fix.smem_len = pdata->video_mem_len; | 350 | if (!np) { |
338 | fbi->fb.screen_base = pdata->video_mem_virt; | 351 | pr_err("%s: No display description in Device Tree\n", __func__); |
352 | ret = -EINVAL; | ||
353 | goto failed_free_res; | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * This code is copied from Sascha Hauer's of_videomode helper | ||
358 | * and can be replaced with a call to the helper once mainlined | ||
359 | */ | ||
360 | ret = 0; | ||
361 | ret |= of_property_read_u32(np, "hactive", &of_mode.xres); | ||
362 | ret |= of_property_read_u32(np, "vactive", &of_mode.yres); | ||
363 | ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin); | ||
364 | ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin); | ||
365 | ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len); | ||
366 | ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin); | ||
367 | ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin); | ||
368 | ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len); | ||
369 | ret |= of_property_read_u32(np, "bpp", &bpp); | ||
370 | if (ret) { | ||
371 | pr_err("%s: Unable to read display properties\n", __func__); | ||
372 | goto failed_free_res; | ||
373 | } | ||
374 | of_mode.vmode = FB_VMODE_NONINTERLACED; | ||
375 | |||
376 | /* try allocating the framebuffer */ | ||
377 | fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8); | ||
378 | fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, | ||
379 | GFP_KERNEL); | ||
380 | if (!fb_mem_virt) { | ||
381 | pr_err("%s: Failed to allocate framebuffer\n", __func__); | ||
382 | return -ENOMEM; | ||
383 | }; | ||
384 | |||
385 | fbi->fb.fix.smem_start = fb_mem_phys; | ||
386 | fbi->fb.fix.smem_len = fb_mem_len; | ||
387 | fbi->fb.screen_base = fb_mem_virt; | ||
339 | 388 | ||
340 | fbi->palette_size = PAGE_ALIGN(512); | 389 | fbi->palette_size = PAGE_ALIGN(512); |
341 | fbi->palette_cpu = dma_alloc_coherent(&pdev->dev, | 390 | fbi->palette_cpu = dma_alloc_coherent(&pdev->dev, |
@@ -370,10 +419,11 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev) | |||
370 | goto failed_free_irq; | 419 | goto failed_free_irq; |
371 | } | 420 | } |
372 | 421 | ||
373 | fb_videomode_to_var(&fbi->fb.var, &pdata->mode); | 422 | fb_videomode_to_var(&fbi->fb.var, &of_mode); |
374 | fbi->fb.var.bits_per_pixel = pdata->bpp; | 423 | |
375 | fbi->fb.var.xres_virtual = pdata->xres_virtual; | 424 | fbi->fb.var.xres_virtual = of_mode.xres; |
376 | fbi->fb.var.yres_virtual = pdata->yres_virtual; | 425 | fbi->fb.var.yres_virtual = of_mode.yres * 2; |
426 | fbi->fb.var.bits_per_pixel = bpp; | ||
377 | 427 | ||
378 | ret = vt8500lcd_set_par(&fbi->fb); | 428 | ret = vt8500lcd_set_par(&fbi->fb); |
379 | if (ret) { | 429 | if (ret) { |
@@ -448,12 +498,18 @@ static int __devexit vt8500lcd_remove(struct platform_device *pdev) | |||
448 | return 0; | 498 | return 0; |
449 | } | 499 | } |
450 | 500 | ||
501 | static const struct of_device_id via_dt_ids[] = { | ||
502 | { .compatible = "via,vt8500-fb", }, | ||
503 | {} | ||
504 | }; | ||
505 | |||
451 | static struct platform_driver vt8500lcd_driver = { | 506 | static struct platform_driver vt8500lcd_driver = { |
452 | .probe = vt8500lcd_probe, | 507 | .probe = vt8500lcd_probe, |
453 | .remove = __devexit_p(vt8500lcd_remove), | 508 | .remove = __devexit_p(vt8500lcd_remove), |
454 | .driver = { | 509 | .driver = { |
455 | .owner = THIS_MODULE, | 510 | .owner = THIS_MODULE, |
456 | .name = "vt8500-lcd", | 511 | .name = "vt8500-lcd", |
512 | .of_match_table = of_match_ptr(via_dt_ids), | ||
457 | }, | 513 | }, |
458 | }; | 514 | }; |
459 | 515 | ||
@@ -461,4 +517,5 @@ module_platform_driver(vt8500lcd_driver); | |||
461 | 517 | ||
462 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); | 518 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); |
463 | MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); | 519 | MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); |
464 | MODULE_LICENSE("GPL"); | 520 | MODULE_LICENSE("GPL v2"); |
521 | MODULE_DEVICE_TABLE(of, via_dt_ids); | ||
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index c8703bd61b74..ec4742442103 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <linux/dma-mapping.h> | 28 | #include <linux/dma-mapping.h> |
29 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/wait.h> | 30 | #include <linux/wait.h> |
31 | #include <linux/of.h> | ||
32 | #include <linux/of_fdt.h> | ||
33 | #include <linux/memblock.h> | ||
31 | 34 | ||
32 | #include <mach/vt8500fb.h> | 35 | #include <mach/vt8500fb.h> |
33 | 36 | ||
@@ -59,8 +62,12 @@ static int wm8505fb_init_hw(struct fb_info *info) | |||
59 | writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR); | 62 | writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR); |
60 | writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR1); | 63 | writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR1); |
61 | 64 | ||
62 | /* Set in-memory picture format to RGB 32bpp */ | 65 | /* |
63 | writel(0x1c, fbi->regbase + WMT_GOVR_COLORSPACE); | 66 | * Set in-memory picture format to RGB |
67 | * 0x31C sets the correct color mode (RGB565) for WM8650 | ||
68 | * Bit 8+9 (0x300) are ignored on WM8505 as reserved | ||
69 | */ | ||
70 | writel(0x31c, fbi->regbase + WMT_GOVR_COLORSPACE); | ||
64 | writel(1, fbi->regbase + WMT_GOVR_COLORSPACE1); | 71 | writel(1, fbi->regbase + WMT_GOVR_COLORSPACE1); |
65 | 72 | ||
66 | /* Virtual buffer size */ | 73 | /* Virtual buffer size */ |
@@ -127,6 +134,18 @@ static int wm8505fb_set_par(struct fb_info *info) | |||
127 | info->var.blue.msb_right = 0; | 134 | info->var.blue.msb_right = 0; |
128 | info->fix.visual = FB_VISUAL_TRUECOLOR; | 135 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
129 | info->fix.line_length = info->var.xres_virtual << 2; | 136 | info->fix.line_length = info->var.xres_virtual << 2; |
137 | } else if (info->var.bits_per_pixel == 16) { | ||
138 | info->var.red.offset = 11; | ||
139 | info->var.red.length = 5; | ||
140 | info->var.red.msb_right = 0; | ||
141 | info->var.green.offset = 5; | ||
142 | info->var.green.length = 6; | ||
143 | info->var.green.msb_right = 0; | ||
144 | info->var.blue.offset = 0; | ||
145 | info->var.blue.length = 5; | ||
146 | info->var.blue.msb_right = 0; | ||
147 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
148 | info->fix.line_length = info->var.xres_virtual << 1; | ||
130 | } | 149 | } |
131 | 150 | ||
132 | wm8505fb_set_timing(info); | 151 | wm8505fb_set_timing(info); |
@@ -246,16 +265,20 @@ static int __devinit wm8505fb_probe(struct platform_device *pdev) | |||
246 | struct wm8505fb_info *fbi; | 265 | struct wm8505fb_info *fbi; |
247 | struct resource *res; | 266 | struct resource *res; |
248 | void *addr; | 267 | void *addr; |
249 | struct vt8500fb_platform_data *pdata; | ||
250 | int ret; | 268 | int ret; |
251 | 269 | ||
252 | pdata = pdev->dev.platform_data; | 270 | struct fb_videomode of_mode; |
271 | struct device_node *np; | ||
272 | u32 bpp; | ||
273 | dma_addr_t fb_mem_phys; | ||
274 | unsigned long fb_mem_len; | ||
275 | void *fb_mem_virt; | ||
253 | 276 | ||
254 | ret = -ENOMEM; | 277 | ret = -ENOMEM; |
255 | fbi = NULL; | 278 | fbi = NULL; |
256 | 279 | ||
257 | fbi = kzalloc(sizeof(struct wm8505fb_info) + sizeof(u32) * 16, | 280 | fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) + |
258 | GFP_KERNEL); | 281 | sizeof(u32) * 16, GFP_KERNEL); |
259 | if (!fbi) { | 282 | if (!fbi) { |
260 | dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); | 283 | dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); |
261 | ret = -ENOMEM; | 284 | ret = -ENOMEM; |
@@ -305,21 +328,58 @@ static int __devinit wm8505fb_probe(struct platform_device *pdev) | |||
305 | goto failed_free_res; | 328 | goto failed_free_res; |
306 | } | 329 | } |
307 | 330 | ||
308 | fb_videomode_to_var(&fbi->fb.var, &pdata->mode); | 331 | np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0); |
332 | if (!np) { | ||
333 | pr_err("%s: No display description in Device Tree\n", __func__); | ||
334 | ret = -EINVAL; | ||
335 | goto failed_free_res; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * This code is copied from Sascha Hauer's of_videomode helper | ||
340 | * and can be replaced with a call to the helper once mainlined | ||
341 | */ | ||
342 | ret = 0; | ||
343 | ret |= of_property_read_u32(np, "hactive", &of_mode.xres); | ||
344 | ret |= of_property_read_u32(np, "vactive", &of_mode.yres); | ||
345 | ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin); | ||
346 | ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin); | ||
347 | ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len); | ||
348 | ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin); | ||
349 | ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin); | ||
350 | ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len); | ||
351 | ret |= of_property_read_u32(np, "bpp", &bpp); | ||
352 | if (ret) { | ||
353 | pr_err("%s: Unable to read display properties\n", __func__); | ||
354 | goto failed_free_res; | ||
355 | } | ||
356 | |||
357 | of_mode.vmode = FB_VMODE_NONINTERLACED; | ||
358 | fb_videomode_to_var(&fbi->fb.var, &of_mode); | ||
309 | 359 | ||
310 | fbi->fb.var.nonstd = 0; | 360 | fbi->fb.var.nonstd = 0; |
311 | fbi->fb.var.activate = FB_ACTIVATE_NOW; | 361 | fbi->fb.var.activate = FB_ACTIVATE_NOW; |
312 | 362 | ||
313 | fbi->fb.var.height = -1; | 363 | fbi->fb.var.height = -1; |
314 | fbi->fb.var.width = -1; | 364 | fbi->fb.var.width = -1; |
315 | fbi->fb.var.xres_virtual = pdata->xres_virtual; | ||
316 | fbi->fb.var.yres_virtual = pdata->yres_virtual; | ||
317 | fbi->fb.var.bits_per_pixel = pdata->bpp; | ||
318 | 365 | ||
319 | fbi->fb.fix.smem_start = pdata->video_mem_phys; | 366 | /* try allocating the framebuffer */ |
320 | fbi->fb.fix.smem_len = pdata->video_mem_len; | 367 | fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8); |
321 | fbi->fb.screen_base = pdata->video_mem_virt; | 368 | fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, |
322 | fbi->fb.screen_size = pdata->video_mem_len; | 369 | GFP_KERNEL); |
370 | if (!fb_mem_virt) { | ||
371 | pr_err("%s: Failed to allocate framebuffer\n", __func__); | ||
372 | return -ENOMEM; | ||
373 | }; | ||
374 | |||
375 | fbi->fb.var.xres_virtual = of_mode.xres; | ||
376 | fbi->fb.var.yres_virtual = of_mode.yres * 2; | ||
377 | fbi->fb.var.bits_per_pixel = bpp; | ||
378 | |||
379 | fbi->fb.fix.smem_start = fb_mem_phys; | ||
380 | fbi->fb.fix.smem_len = fb_mem_len; | ||
381 | fbi->fb.screen_base = fb_mem_virt; | ||
382 | fbi->fb.screen_size = fb_mem_len; | ||
323 | 383 | ||
324 | if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { | 384 | if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { |
325 | dev_err(&pdev->dev, "Failed to allocate color map\n"); | 385 | dev_err(&pdev->dev, "Failed to allocate color map\n"); |
@@ -395,12 +455,18 @@ static int __devexit wm8505fb_remove(struct platform_device *pdev) | |||
395 | return 0; | 455 | return 0; |
396 | } | 456 | } |
397 | 457 | ||
458 | static const struct of_device_id wmt_dt_ids[] = { | ||
459 | { .compatible = "wm,wm8505-fb", }, | ||
460 | {} | ||
461 | }; | ||
462 | |||
398 | static struct platform_driver wm8505fb_driver = { | 463 | static struct platform_driver wm8505fb_driver = { |
399 | .probe = wm8505fb_probe, | 464 | .probe = wm8505fb_probe, |
400 | .remove = __devexit_p(wm8505fb_remove), | 465 | .remove = __devexit_p(wm8505fb_remove), |
401 | .driver = { | 466 | .driver = { |
402 | .owner = THIS_MODULE, | 467 | .owner = THIS_MODULE, |
403 | .name = DRIVER_NAME, | 468 | .name = DRIVER_NAME, |
469 | .of_match_table = of_match_ptr(wmt_dt_ids), | ||
404 | }, | 470 | }, |
405 | }; | 471 | }; |
406 | 472 | ||
@@ -408,4 +474,5 @@ module_platform_driver(wm8505fb_driver); | |||
408 | 474 | ||
409 | MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); | 475 | MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); |
410 | MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); | 476 | MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); |
411 | MODULE_LICENSE("GPL"); | 477 | MODULE_LICENSE("GPL v2"); |
478 | MODULE_DEVICE_TABLE(of, wmt_dt_ids); | ||
diff --git a/drivers/video/wmt_ge_rops.c b/drivers/video/wmt_ge_rops.c index 55be3865015b..ba025b4c7d09 100644 --- a/drivers/video/wmt_ge_rops.c +++ b/drivers/video/wmt_ge_rops.c | |||
@@ -158,12 +158,18 @@ static int __devexit wmt_ge_rops_remove(struct platform_device *pdev) | |||
158 | return 0; | 158 | return 0; |
159 | } | 159 | } |
160 | 160 | ||
161 | static const struct of_device_id wmt_dt_ids[] = { | ||
162 | { .compatible = "wm,prizm-ge-rops", }, | ||
163 | { /* sentinel */ } | ||
164 | }; | ||
165 | |||
161 | static struct platform_driver wmt_ge_rops_driver = { | 166 | static struct platform_driver wmt_ge_rops_driver = { |
162 | .probe = wmt_ge_rops_probe, | 167 | .probe = wmt_ge_rops_probe, |
163 | .remove = __devexit_p(wmt_ge_rops_remove), | 168 | .remove = __devexit_p(wmt_ge_rops_remove), |
164 | .driver = { | 169 | .driver = { |
165 | .owner = THIS_MODULE, | 170 | .owner = THIS_MODULE, |
166 | .name = "wmt_ge_rops", | 171 | .name = "wmt_ge_rops", |
172 | .of_match_table = of_match_ptr(wmt_dt_ids), | ||
167 | }, | 173 | }, |
168 | }; | 174 | }; |
169 | 175 | ||
@@ -172,4 +178,5 @@ module_platform_driver(wmt_ge_rops_driver); | |||
172 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); | 178 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); |
173 | MODULE_DESCRIPTION("Accelerators for raster operations using " | 179 | MODULE_DESCRIPTION("Accelerators for raster operations using " |
174 | "WonderMedia Graphics Engine"); | 180 | "WonderMedia Graphics Engine"); |
175 | MODULE_LICENSE("GPL"); | 181 | MODULE_LICENSE("GPL v2"); |
182 | MODULE_DEVICE_TABLE(of, wmt_dt_ids); | ||