diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/clk-vt8500.c | 510 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 6 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-vt8500.c | 316 | ||||
-rw-r--r-- | drivers/rtc/rtc-vt8500.c | 9 | ||||
-rw-r--r-- | drivers/tty/serial/vt8500_serial.c | 58 | ||||
-rw-r--r-- | drivers/video/Kconfig | 6 | ||||
-rw-r--r-- | drivers/video/vt8500lcdfb.c | 79 | ||||
-rw-r--r-- | drivers/video/wm8505fb.c | 97 | ||||
-rw-r--r-- | drivers/video/wmt_ge_rops.c | 9 |
11 files changed, 1056 insertions, 36 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 6327536b4900..e48e0da5a884 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ | |||
16 | endif | 16 | endif |
17 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o | 17 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o |
18 | obj-$(CONFIG_ARCH_U8500) += ux500/ | 18 | obj-$(CONFIG_ARCH_U8500) += ux500/ |
19 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o | ||
19 | 20 | ||
20 | # Chip specific | 21 | # Chip specific |
21 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o | 22 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o |
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/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-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/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); | ||