Root/
1 | /* |
2 | * Toshiba TC6393XB SoC support |
3 | * |
4 | * Copyright(c) 2005-2006 Chris Humbert |
5 | * Copyright(c) 2005 Dirk Opfer |
6 | * Copyright(c) 2005 Ian Molton <spyro@f2s.com> |
7 | * Copyright(c) 2007 Dmitry Baryshkov |
8 | * |
9 | * Based on code written by Sharp/Lineo for 2.4 kernels |
10 | * Based on locomo.c |
11 | * |
12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as |
14 | * published by the Free Software Foundation. |
15 | */ |
16 | |
17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> |
19 | #include <linux/io.h> |
20 | #include <linux/irq.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/clk.h> |
23 | #include <linux/err.h> |
24 | #include <linux/mfd/core.h> |
25 | #include <linux/mfd/tmio.h> |
26 | #include <linux/mfd/tc6393xb.h> |
27 | #include <linux/gpio.h> |
28 | #include <linux/slab.h> |
29 | |
30 | #define SCR_REVID 0x08 /* b Revision ID */ |
31 | #define SCR_ISR 0x50 /* b Interrupt Status */ |
32 | #define SCR_IMR 0x52 /* b Interrupt Mask */ |
33 | #define SCR_IRR 0x54 /* b Interrupt Routing */ |
34 | #define SCR_GPER 0x60 /* w GP Enable */ |
35 | #define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */ |
36 | #define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */ |
37 | #define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */ |
38 | #define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */ |
39 | #define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */ |
40 | #define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */ |
41 | #define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */ |
42 | #define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */ |
43 | #define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */ |
44 | #define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */ |
45 | #define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */ |
46 | #define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */ |
47 | #define SCR_CCR 0x98 /* w Clock Control */ |
48 | #define SCR_PLL2CR 0x9a /* w PLL2 Control */ |
49 | #define SCR_PLL1CR 0x9c /* l PLL1 Control */ |
50 | #define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */ |
51 | #define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */ |
52 | #define SCR_FER 0xe0 /* b Function Enable */ |
53 | #define SCR_MCR 0xe4 /* w Mode Control */ |
54 | #define SCR_CONFIG 0xfc /* b Configuration Control */ |
55 | #define SCR_DEBUG 0xff /* b Debug */ |
56 | |
57 | #define SCR_CCR_CK32K BIT(0) |
58 | #define SCR_CCR_USBCK BIT(1) |
59 | #define SCR_CCR_UNK1 BIT(4) |
60 | #define SCR_CCR_MCLK_MASK (7 << 8) |
61 | #define SCR_CCR_MCLK_OFF (0 << 8) |
62 | #define SCR_CCR_MCLK_12 (1 << 8) |
63 | #define SCR_CCR_MCLK_24 (2 << 8) |
64 | #define SCR_CCR_MCLK_48 (3 << 8) |
65 | #define SCR_CCR_HCLK_MASK (3 << 12) |
66 | #define SCR_CCR_HCLK_24 (0 << 12) |
67 | #define SCR_CCR_HCLK_48 (1 << 12) |
68 | |
69 | #define SCR_FER_USBEN BIT(0) /* USB host enable */ |
70 | #define SCR_FER_LCDCVEN BIT(1) /* polysilicon TFT enable */ |
71 | #define SCR_FER_SLCDEN BIT(2) /* SLCD enable */ |
72 | |
73 | #define SCR_MCR_RDY_MASK (3 << 0) |
74 | #define SCR_MCR_RDY_OPENDRAIN (0 << 0) |
75 | #define SCR_MCR_RDY_TRISTATE (1 << 0) |
76 | #define SCR_MCR_RDY_PUSHPULL (2 << 0) |
77 | #define SCR_MCR_RDY_UNK BIT(2) |
78 | #define SCR_MCR_RDY_EN BIT(3) |
79 | #define SCR_MCR_INT_MASK (3 << 4) |
80 | #define SCR_MCR_INT_OPENDRAIN (0 << 4) |
81 | #define SCR_MCR_INT_TRISTATE (1 << 4) |
82 | #define SCR_MCR_INT_PUSHPULL (2 << 4) |
83 | #define SCR_MCR_INT_UNK BIT(6) |
84 | #define SCR_MCR_INT_EN BIT(7) |
85 | /* bits 8 - 16 are unknown */ |
86 | |
87 | #define TC_GPIO_BIT(i) (1 << (i & 0x7)) |
88 | |
89 | /*--------------------------------------------------------------------------*/ |
90 | |
91 | struct tc6393xb { |
92 | void __iomem *scr; |
93 | |
94 | struct gpio_chip gpio; |
95 | |
96 | struct clk *clk; /* 3,6 Mhz */ |
97 | |
98 | spinlock_t lock; /* protects RMW cycles */ |
99 | |
100 | struct { |
101 | u8 fer; |
102 | u16 ccr; |
103 | u8 gpi_bcr[3]; |
104 | u8 gpo_dsr[3]; |
105 | u8 gpo_doecr[3]; |
106 | } suspend_state; |
107 | |
108 | struct resource rscr; |
109 | struct resource *iomem; |
110 | int irq; |
111 | int irq_base; |
112 | }; |
113 | |
114 | enum { |
115 | TC6393XB_CELL_NAND, |
116 | TC6393XB_CELL_MMC, |
117 | TC6393XB_CELL_OHCI, |
118 | TC6393XB_CELL_FB, |
119 | }; |
120 | |
121 | /*--------------------------------------------------------------------------*/ |
122 | |
123 | static int tc6393xb_nand_enable(struct platform_device *nand) |
124 | { |
125 | struct platform_device *dev = to_platform_device(nand->dev.parent); |
126 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
127 | unsigned long flags; |
128 | |
129 | spin_lock_irqsave(&tc6393xb->lock, flags); |
130 | |
131 | /* SMD buffer on */ |
132 | dev_dbg(&dev->dev, "SMD buffer on\n"); |
133 | tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); |
134 | |
135 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
136 | |
137 | return 0; |
138 | } |
139 | |
140 | static struct resource __devinitdata tc6393xb_nand_resources[] = { |
141 | { |
142 | .start = 0x1000, |
143 | .end = 0x1007, |
144 | .flags = IORESOURCE_MEM, |
145 | }, |
146 | { |
147 | .start = 0x0100, |
148 | .end = 0x01ff, |
149 | .flags = IORESOURCE_MEM, |
150 | }, |
151 | { |
152 | .start = IRQ_TC6393_NAND, |
153 | .end = IRQ_TC6393_NAND, |
154 | .flags = IORESOURCE_IRQ, |
155 | }, |
156 | }; |
157 | |
158 | static struct resource tc6393xb_mmc_resources[] = { |
159 | { |
160 | .start = 0x800, |
161 | .end = 0x9ff, |
162 | .flags = IORESOURCE_MEM, |
163 | }, |
164 | { |
165 | .start = IRQ_TC6393_MMC, |
166 | .end = IRQ_TC6393_MMC, |
167 | .flags = IORESOURCE_IRQ, |
168 | }, |
169 | }; |
170 | |
171 | static const struct resource tc6393xb_ohci_resources[] = { |
172 | { |
173 | .start = 0x3000, |
174 | .end = 0x31ff, |
175 | .flags = IORESOURCE_MEM, |
176 | }, |
177 | { |
178 | .start = 0x0300, |
179 | .end = 0x03ff, |
180 | .flags = IORESOURCE_MEM, |
181 | }, |
182 | { |
183 | .start = 0x010000, |
184 | .end = 0x017fff, |
185 | .flags = IORESOURCE_MEM, |
186 | }, |
187 | { |
188 | .start = 0x018000, |
189 | .end = 0x01ffff, |
190 | .flags = IORESOURCE_MEM, |
191 | }, |
192 | { |
193 | .start = IRQ_TC6393_OHCI, |
194 | .end = IRQ_TC6393_OHCI, |
195 | .flags = IORESOURCE_IRQ, |
196 | }, |
197 | }; |
198 | |
199 | static struct resource __devinitdata tc6393xb_fb_resources[] = { |
200 | { |
201 | .start = 0x5000, |
202 | .end = 0x51ff, |
203 | .flags = IORESOURCE_MEM, |
204 | }, |
205 | { |
206 | .start = 0x0500, |
207 | .end = 0x05ff, |
208 | .flags = IORESOURCE_MEM, |
209 | }, |
210 | { |
211 | .start = 0x100000, |
212 | .end = 0x1fffff, |
213 | .flags = IORESOURCE_MEM, |
214 | }, |
215 | { |
216 | .start = IRQ_TC6393_FB, |
217 | .end = IRQ_TC6393_FB, |
218 | .flags = IORESOURCE_IRQ, |
219 | }, |
220 | }; |
221 | |
222 | static int tc6393xb_ohci_enable(struct platform_device *dev) |
223 | { |
224 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); |
225 | unsigned long flags; |
226 | u16 ccr; |
227 | u8 fer; |
228 | |
229 | spin_lock_irqsave(&tc6393xb->lock, flags); |
230 | |
231 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); |
232 | ccr |= SCR_CCR_USBCK; |
233 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); |
234 | |
235 | fer = tmio_ioread8(tc6393xb->scr + SCR_FER); |
236 | fer |= SCR_FER_USBEN; |
237 | tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); |
238 | |
239 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
240 | |
241 | return 0; |
242 | } |
243 | |
244 | static int tc6393xb_ohci_disable(struct platform_device *dev) |
245 | { |
246 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); |
247 | unsigned long flags; |
248 | u16 ccr; |
249 | u8 fer; |
250 | |
251 | spin_lock_irqsave(&tc6393xb->lock, flags); |
252 | |
253 | fer = tmio_ioread8(tc6393xb->scr + SCR_FER); |
254 | fer &= ~SCR_FER_USBEN; |
255 | tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); |
256 | |
257 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); |
258 | ccr &= ~SCR_CCR_USBCK; |
259 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); |
260 | |
261 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
262 | |
263 | return 0; |
264 | } |
265 | |
266 | static int tc6393xb_fb_enable(struct platform_device *dev) |
267 | { |
268 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); |
269 | unsigned long flags; |
270 | u16 ccr; |
271 | |
272 | spin_lock_irqsave(&tc6393xb->lock, flags); |
273 | |
274 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); |
275 | ccr &= ~SCR_CCR_MCLK_MASK; |
276 | ccr |= SCR_CCR_MCLK_48; |
277 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); |
278 | |
279 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
280 | |
281 | return 0; |
282 | } |
283 | |
284 | static int tc6393xb_fb_disable(struct platform_device *dev) |
285 | { |
286 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); |
287 | unsigned long flags; |
288 | u16 ccr; |
289 | |
290 | spin_lock_irqsave(&tc6393xb->lock, flags); |
291 | |
292 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); |
293 | ccr &= ~SCR_CCR_MCLK_MASK; |
294 | ccr |= SCR_CCR_MCLK_OFF; |
295 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); |
296 | |
297 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | int tc6393xb_lcd_set_power(struct platform_device *fb, bool on) |
303 | { |
304 | struct platform_device *dev = to_platform_device(fb->dev.parent); |
305 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
306 | u8 fer; |
307 | unsigned long flags; |
308 | |
309 | spin_lock_irqsave(&tc6393xb->lock, flags); |
310 | |
311 | fer = ioread8(tc6393xb->scr + SCR_FER); |
312 | if (on) |
313 | fer |= SCR_FER_SLCDEN; |
314 | else |
315 | fer &= ~SCR_FER_SLCDEN; |
316 | iowrite8(fer, tc6393xb->scr + SCR_FER); |
317 | |
318 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
319 | |
320 | return 0; |
321 | } |
322 | EXPORT_SYMBOL(tc6393xb_lcd_set_power); |
323 | |
324 | int tc6393xb_lcd_mode(struct platform_device *fb, |
325 | const struct fb_videomode *mode) { |
326 | struct platform_device *dev = to_platform_device(fb->dev.parent); |
327 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
328 | unsigned long flags; |
329 | |
330 | spin_lock_irqsave(&tc6393xb->lock, flags); |
331 | |
332 | iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0); |
333 | iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2); |
334 | |
335 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
336 | |
337 | return 0; |
338 | } |
339 | EXPORT_SYMBOL(tc6393xb_lcd_mode); |
340 | |
341 | static int tc6393xb_mmc_enable(struct platform_device *mmc) |
342 | { |
343 | struct platform_device *dev = to_platform_device(mmc->dev.parent); |
344 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
345 | |
346 | tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0, |
347 | tc6393xb_mmc_resources[0].start & 0xfffe); |
348 | |
349 | return 0; |
350 | } |
351 | |
352 | static int tc6393xb_mmc_resume(struct platform_device *mmc) |
353 | { |
354 | struct platform_device *dev = to_platform_device(mmc->dev.parent); |
355 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
356 | |
357 | tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0, |
358 | tc6393xb_mmc_resources[0].start & 0xfffe); |
359 | |
360 | return 0; |
361 | } |
362 | |
363 | static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state) |
364 | { |
365 | struct platform_device *dev = to_platform_device(mmc->dev.parent); |
366 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
367 | |
368 | tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state); |
369 | } |
370 | |
371 | static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state) |
372 | { |
373 | struct platform_device *dev = to_platform_device(mmc->dev.parent); |
374 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
375 | |
376 | tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state); |
377 | } |
378 | |
379 | static struct tmio_mmc_data tc6393xb_mmc_data = { |
380 | .hclk = 24000000, |
381 | .set_pwr = tc6393xb_mmc_pwr, |
382 | .set_clk_div = tc6393xb_mmc_clk_div, |
383 | }; |
384 | |
385 | static struct mfd_cell __devinitdata tc6393xb_cells[] = { |
386 | [TC6393XB_CELL_NAND] = { |
387 | .name = "tmio-nand", |
388 | .enable = tc6393xb_nand_enable, |
389 | .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), |
390 | .resources = tc6393xb_nand_resources, |
391 | }, |
392 | [TC6393XB_CELL_MMC] = { |
393 | .name = "tmio-mmc", |
394 | .enable = tc6393xb_mmc_enable, |
395 | .resume = tc6393xb_mmc_resume, |
396 | .platform_data = &tc6393xb_mmc_data, |
397 | .pdata_size = sizeof(tc6393xb_mmc_data), |
398 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), |
399 | .resources = tc6393xb_mmc_resources, |
400 | }, |
401 | [TC6393XB_CELL_OHCI] = { |
402 | .name = "tmio-ohci", |
403 | .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources), |
404 | .resources = tc6393xb_ohci_resources, |
405 | .enable = tc6393xb_ohci_enable, |
406 | .suspend = tc6393xb_ohci_disable, |
407 | .resume = tc6393xb_ohci_enable, |
408 | .disable = tc6393xb_ohci_disable, |
409 | }, |
410 | [TC6393XB_CELL_FB] = { |
411 | .name = "tmio-fb", |
412 | .num_resources = ARRAY_SIZE(tc6393xb_fb_resources), |
413 | .resources = tc6393xb_fb_resources, |
414 | .enable = tc6393xb_fb_enable, |
415 | .suspend = tc6393xb_fb_disable, |
416 | .resume = tc6393xb_fb_enable, |
417 | .disable = tc6393xb_fb_disable, |
418 | }, |
419 | }; |
420 | |
421 | /*--------------------------------------------------------------------------*/ |
422 | |
423 | static int tc6393xb_gpio_get(struct gpio_chip *chip, |
424 | unsigned offset) |
425 | { |
426 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); |
427 | |
428 | /* XXX: does dsr also represent inputs? */ |
429 | return tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) |
430 | & TC_GPIO_BIT(offset); |
431 | } |
432 | |
433 | static void __tc6393xb_gpio_set(struct gpio_chip *chip, |
434 | unsigned offset, int value) |
435 | { |
436 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); |
437 | u8 dsr; |
438 | |
439 | dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); |
440 | if (value) |
441 | dsr |= TC_GPIO_BIT(offset); |
442 | else |
443 | dsr &= ~TC_GPIO_BIT(offset); |
444 | |
445 | tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); |
446 | } |
447 | |
448 | static void tc6393xb_gpio_set(struct gpio_chip *chip, |
449 | unsigned offset, int value) |
450 | { |
451 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); |
452 | unsigned long flags; |
453 | |
454 | spin_lock_irqsave(&tc6393xb->lock, flags); |
455 | |
456 | __tc6393xb_gpio_set(chip, offset, value); |
457 | |
458 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
459 | } |
460 | |
461 | static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, |
462 | unsigned offset) |
463 | { |
464 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); |
465 | unsigned long flags; |
466 | u8 doecr; |
467 | |
468 | spin_lock_irqsave(&tc6393xb->lock, flags); |
469 | |
470 | doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
471 | doecr &= ~TC_GPIO_BIT(offset); |
472 | tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
473 | |
474 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
475 | |
476 | return 0; |
477 | } |
478 | |
479 | static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, |
480 | unsigned offset, int value) |
481 | { |
482 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); |
483 | unsigned long flags; |
484 | u8 doecr; |
485 | |
486 | spin_lock_irqsave(&tc6393xb->lock, flags); |
487 | |
488 | __tc6393xb_gpio_set(chip, offset, value); |
489 | |
490 | doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
491 | doecr |= TC_GPIO_BIT(offset); |
492 | tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
493 | |
494 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
495 | |
496 | return 0; |
497 | } |
498 | |
499 | static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) |
500 | { |
501 | tc6393xb->gpio.label = "tc6393xb"; |
502 | tc6393xb->gpio.base = gpio_base; |
503 | tc6393xb->gpio.ngpio = 16; |
504 | tc6393xb->gpio.set = tc6393xb_gpio_set; |
505 | tc6393xb->gpio.get = tc6393xb_gpio_get; |
506 | tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input; |
507 | tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output; |
508 | |
509 | return gpiochip_add(&tc6393xb->gpio); |
510 | } |
511 | |
512 | /*--------------------------------------------------------------------------*/ |
513 | |
514 | static void |
515 | tc6393xb_irq(unsigned int irq, struct irq_desc *desc) |
516 | { |
517 | struct tc6393xb *tc6393xb = irq_get_handler_data(irq); |
518 | unsigned int isr; |
519 | unsigned int i, irq_base; |
520 | |
521 | irq_base = tc6393xb->irq_base; |
522 | |
523 | while ((isr = tmio_ioread8(tc6393xb->scr + SCR_ISR) & |
524 | ~tmio_ioread8(tc6393xb->scr + SCR_IMR))) |
525 | for (i = 0; i < TC6393XB_NR_IRQS; i++) { |
526 | if (isr & (1 << i)) |
527 | generic_handle_irq(irq_base + i); |
528 | } |
529 | } |
530 | |
531 | static void tc6393xb_irq_ack(struct irq_data *data) |
532 | { |
533 | } |
534 | |
535 | static void tc6393xb_irq_mask(struct irq_data *data) |
536 | { |
537 | struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); |
538 | unsigned long flags; |
539 | u8 imr; |
540 | |
541 | spin_lock_irqsave(&tc6393xb->lock, flags); |
542 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); |
543 | imr |= 1 << (data->irq - tc6393xb->irq_base); |
544 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); |
545 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
546 | } |
547 | |
548 | static void tc6393xb_irq_unmask(struct irq_data *data) |
549 | { |
550 | struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); |
551 | unsigned long flags; |
552 | u8 imr; |
553 | |
554 | spin_lock_irqsave(&tc6393xb->lock, flags); |
555 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); |
556 | imr &= ~(1 << (data->irq - tc6393xb->irq_base)); |
557 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); |
558 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
559 | } |
560 | |
561 | static struct irq_chip tc6393xb_chip = { |
562 | .name = "tc6393xb", |
563 | .irq_ack = tc6393xb_irq_ack, |
564 | .irq_mask = tc6393xb_irq_mask, |
565 | .irq_unmask = tc6393xb_irq_unmask, |
566 | }; |
567 | |
568 | static void tc6393xb_attach_irq(struct platform_device *dev) |
569 | { |
570 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
571 | unsigned int irq, irq_base; |
572 | |
573 | irq_base = tc6393xb->irq_base; |
574 | |
575 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { |
576 | irq_set_chip_and_handler(irq, &tc6393xb_chip, handle_edge_irq); |
577 | irq_set_chip_data(irq, tc6393xb); |
578 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
579 | } |
580 | |
581 | irq_set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); |
582 | irq_set_handler_data(tc6393xb->irq, tc6393xb); |
583 | irq_set_chained_handler(tc6393xb->irq, tc6393xb_irq); |
584 | } |
585 | |
586 | static void tc6393xb_detach_irq(struct platform_device *dev) |
587 | { |
588 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
589 | unsigned int irq, irq_base; |
590 | |
591 | irq_set_chained_handler(tc6393xb->irq, NULL); |
592 | irq_set_handler_data(tc6393xb->irq, NULL); |
593 | |
594 | irq_base = tc6393xb->irq_base; |
595 | |
596 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { |
597 | set_irq_flags(irq, 0); |
598 | irq_set_chip(irq, NULL); |
599 | irq_set_chip_data(irq, NULL); |
600 | } |
601 | } |
602 | |
603 | /*--------------------------------------------------------------------------*/ |
604 | |
605 | static int __devinit tc6393xb_probe(struct platform_device *dev) |
606 | { |
607 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
608 | struct tc6393xb *tc6393xb; |
609 | struct resource *iomem, *rscr; |
610 | int ret, temp; |
611 | |
612 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); |
613 | if (!iomem) |
614 | return -EINVAL; |
615 | |
616 | tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); |
617 | if (!tc6393xb) { |
618 | ret = -ENOMEM; |
619 | goto err_kzalloc; |
620 | } |
621 | |
622 | spin_lock_init(&tc6393xb->lock); |
623 | |
624 | platform_set_drvdata(dev, tc6393xb); |
625 | |
626 | ret = platform_get_irq(dev, 0); |
627 | if (ret >= 0) |
628 | tc6393xb->irq = ret; |
629 | else |
630 | goto err_noirq; |
631 | |
632 | tc6393xb->iomem = iomem; |
633 | tc6393xb->irq_base = tcpd->irq_base; |
634 | |
635 | tc6393xb->clk = clk_get(&dev->dev, "CLK_CK3P6MI"); |
636 | if (IS_ERR(tc6393xb->clk)) { |
637 | ret = PTR_ERR(tc6393xb->clk); |
638 | goto err_clk_get; |
639 | } |
640 | |
641 | rscr = &tc6393xb->rscr; |
642 | rscr->name = "tc6393xb-core"; |
643 | rscr->start = iomem->start; |
644 | rscr->end = iomem->start + 0xff; |
645 | rscr->flags = IORESOURCE_MEM; |
646 | |
647 | ret = request_resource(iomem, rscr); |
648 | if (ret) |
649 | goto err_request_scr; |
650 | |
651 | tc6393xb->scr = ioremap(rscr->start, resource_size(rscr)); |
652 | if (!tc6393xb->scr) { |
653 | ret = -ENOMEM; |
654 | goto err_ioremap; |
655 | } |
656 | |
657 | ret = clk_enable(tc6393xb->clk); |
658 | if (ret) |
659 | goto err_clk_enable; |
660 | |
661 | ret = tcpd->enable(dev); |
662 | if (ret) |
663 | goto err_enable; |
664 | |
665 | iowrite8(0, tc6393xb->scr + SCR_FER); |
666 | iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); |
667 | iowrite16(SCR_CCR_UNK1 | SCR_CCR_HCLK_48, |
668 | tc6393xb->scr + SCR_CCR); |
669 | iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | |
670 | SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | |
671 | BIT(15), tc6393xb->scr + SCR_MCR); |
672 | iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); |
673 | iowrite8(0, tc6393xb->scr + SCR_IRR); |
674 | iowrite8(0xbf, tc6393xb->scr + SCR_IMR); |
675 | |
676 | printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", |
677 | tmio_ioread8(tc6393xb->scr + SCR_REVID), |
678 | (unsigned long) iomem->start, tc6393xb->irq); |
679 | |
680 | tc6393xb->gpio.base = -1; |
681 | |
682 | if (tcpd->gpio_base >= 0) { |
683 | ret = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); |
684 | if (ret) |
685 | goto err_gpio_add; |
686 | } |
687 | |
688 | tc6393xb_attach_irq(dev); |
689 | |
690 | if (tcpd->setup) { |
691 | ret = tcpd->setup(dev); |
692 | if (ret) |
693 | goto err_setup; |
694 | } |
695 | |
696 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data; |
697 | tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size = |
698 | sizeof(*tcpd->nand_data); |
699 | tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data; |
700 | tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); |
701 | |
702 | ret = mfd_add_devices(&dev->dev, dev->id, |
703 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), |
704 | iomem, tcpd->irq_base, NULL); |
705 | |
706 | if (!ret) |
707 | return 0; |
708 | |
709 | if (tcpd->teardown) |
710 | tcpd->teardown(dev); |
711 | |
712 | err_setup: |
713 | tc6393xb_detach_irq(dev); |
714 | |
715 | err_gpio_add: |
716 | if (tc6393xb->gpio.base != -1) |
717 | temp = gpiochip_remove(&tc6393xb->gpio); |
718 | tcpd->disable(dev); |
719 | err_enable: |
720 | clk_disable(tc6393xb->clk); |
721 | err_clk_enable: |
722 | iounmap(tc6393xb->scr); |
723 | err_ioremap: |
724 | release_resource(&tc6393xb->rscr); |
725 | err_request_scr: |
726 | clk_put(tc6393xb->clk); |
727 | err_noirq: |
728 | err_clk_get: |
729 | kfree(tc6393xb); |
730 | err_kzalloc: |
731 | return ret; |
732 | } |
733 | |
734 | static int __devexit tc6393xb_remove(struct platform_device *dev) |
735 | { |
736 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
737 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
738 | int ret; |
739 | |
740 | mfd_remove_devices(&dev->dev); |
741 | |
742 | if (tcpd->teardown) |
743 | tcpd->teardown(dev); |
744 | |
745 | tc6393xb_detach_irq(dev); |
746 | |
747 | if (tc6393xb->gpio.base != -1) { |
748 | ret = gpiochip_remove(&tc6393xb->gpio); |
749 | if (ret) { |
750 | dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret); |
751 | return ret; |
752 | } |
753 | } |
754 | |
755 | ret = tcpd->disable(dev); |
756 | clk_disable(tc6393xb->clk); |
757 | iounmap(tc6393xb->scr); |
758 | release_resource(&tc6393xb->rscr); |
759 | platform_set_drvdata(dev, NULL); |
760 | clk_put(tc6393xb->clk); |
761 | kfree(tc6393xb); |
762 | |
763 | return ret; |
764 | } |
765 | |
766 | #ifdef CONFIG_PM |
767 | static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) |
768 | { |
769 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
770 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
771 | int i, ret; |
772 | |
773 | tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); |
774 | tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); |
775 | |
776 | for (i = 0; i < 3; i++) { |
777 | tc6393xb->suspend_state.gpo_dsr[i] = |
778 | ioread8(tc6393xb->scr + SCR_GPO_DSR(i)); |
779 | tc6393xb->suspend_state.gpo_doecr[i] = |
780 | ioread8(tc6393xb->scr + SCR_GPO_DOECR(i)); |
781 | tc6393xb->suspend_state.gpi_bcr[i] = |
782 | ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); |
783 | } |
784 | ret = tcpd->suspend(dev); |
785 | clk_disable(tc6393xb->clk); |
786 | |
787 | return ret; |
788 | } |
789 | |
790 | static int tc6393xb_resume(struct platform_device *dev) |
791 | { |
792 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
793 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
794 | int ret; |
795 | int i; |
796 | |
797 | clk_enable(tc6393xb->clk); |
798 | |
799 | ret = tcpd->resume(dev); |
800 | if (ret) |
801 | return ret; |
802 | |
803 | if (!tcpd->resume_restore) |
804 | return 0; |
805 | |
806 | iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER); |
807 | iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); |
808 | iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR); |
809 | iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | |
810 | SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | |
811 | BIT(15), tc6393xb->scr + SCR_MCR); |
812 | iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); |
813 | iowrite8(0, tc6393xb->scr + SCR_IRR); |
814 | iowrite8(0xbf, tc6393xb->scr + SCR_IMR); |
815 | |
816 | for (i = 0; i < 3; i++) { |
817 | iowrite8(tc6393xb->suspend_state.gpo_dsr[i], |
818 | tc6393xb->scr + SCR_GPO_DSR(i)); |
819 | iowrite8(tc6393xb->suspend_state.gpo_doecr[i], |
820 | tc6393xb->scr + SCR_GPO_DOECR(i)); |
821 | iowrite8(tc6393xb->suspend_state.gpi_bcr[i], |
822 | tc6393xb->scr + SCR_GPI_BCR(i)); |
823 | } |
824 | |
825 | return 0; |
826 | } |
827 | #else |
828 | #define tc6393xb_suspend NULL |
829 | #define tc6393xb_resume NULL |
830 | #endif |
831 | |
832 | static struct platform_driver tc6393xb_driver = { |
833 | .probe = tc6393xb_probe, |
834 | .remove = __devexit_p(tc6393xb_remove), |
835 | .suspend = tc6393xb_suspend, |
836 | .resume = tc6393xb_resume, |
837 | |
838 | .driver = { |
839 | .name = "tc6393xb", |
840 | .owner = THIS_MODULE, |
841 | }, |
842 | }; |
843 | |
844 | static int __init tc6393xb_init(void) |
845 | { |
846 | return platform_driver_register(&tc6393xb_driver); |
847 | } |
848 | |
849 | static void __exit tc6393xb_exit(void) |
850 | { |
851 | platform_driver_unregister(&tc6393xb_driver); |
852 | } |
853 | |
854 | subsys_initcall(tc6393xb_init); |
855 | module_exit(tc6393xb_exit); |
856 | |
857 | MODULE_LICENSE("GPL v2"); |
858 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); |
859 | MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); |
860 | MODULE_ALIAS("platform:tc6393xb"); |
861 | |
862 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9