diff options
Diffstat (limited to 'drivers/mfd/tc6393xb.c')
-rw-r--r-- | drivers/mfd/tc6393xb.c | 296 |
1 files changed, 249 insertions, 47 deletions
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index e4c1c788b5f8..f856e9463a9f 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -113,6 +113,8 @@ struct tc6393xb { | |||
113 | enum { | 113 | enum { |
114 | TC6393XB_CELL_NAND, | 114 | TC6393XB_CELL_NAND, |
115 | TC6393XB_CELL_MMC, | 115 | TC6393XB_CELL_MMC, |
116 | TC6393XB_CELL_OHCI, | ||
117 | TC6393XB_CELL_FB, | ||
116 | }; | 118 | }; |
117 | 119 | ||
118 | /*--------------------------------------------------------------------------*/ | 120 | /*--------------------------------------------------------------------------*/ |
@@ -170,6 +172,176 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = { | |||
170 | }, | 172 | }, |
171 | }; | 173 | }; |
172 | 174 | ||
175 | const static struct resource tc6393xb_ohci_resources[] = { | ||
176 | { | ||
177 | .start = 0x3000, | ||
178 | .end = 0x31ff, | ||
179 | .flags = IORESOURCE_MEM, | ||
180 | }, | ||
181 | { | ||
182 | .start = 0x0300, | ||
183 | .end = 0x03ff, | ||
184 | .flags = IORESOURCE_MEM, | ||
185 | }, | ||
186 | { | ||
187 | .start = 0x010000, | ||
188 | .end = 0x017fff, | ||
189 | .flags = IORESOURCE_MEM, | ||
190 | }, | ||
191 | { | ||
192 | .start = 0x018000, | ||
193 | .end = 0x01ffff, | ||
194 | .flags = IORESOURCE_MEM, | ||
195 | }, | ||
196 | { | ||
197 | .start = IRQ_TC6393_OHCI, | ||
198 | .end = IRQ_TC6393_OHCI, | ||
199 | .flags = IORESOURCE_IRQ, | ||
200 | }, | ||
201 | }; | ||
202 | |||
203 | static struct resource __devinitdata tc6393xb_fb_resources[] = { | ||
204 | { | ||
205 | .start = 0x5000, | ||
206 | .end = 0x51ff, | ||
207 | .flags = IORESOURCE_MEM, | ||
208 | }, | ||
209 | { | ||
210 | .start = 0x0500, | ||
211 | .end = 0x05ff, | ||
212 | .flags = IORESOURCE_MEM, | ||
213 | }, | ||
214 | { | ||
215 | .start = 0x100000, | ||
216 | .end = 0x1fffff, | ||
217 | .flags = IORESOURCE_MEM, | ||
218 | }, | ||
219 | { | ||
220 | .start = IRQ_TC6393_FB, | ||
221 | .end = IRQ_TC6393_FB, | ||
222 | .flags = IORESOURCE_IRQ, | ||
223 | }, | ||
224 | }; | ||
225 | |||
226 | static int tc6393xb_ohci_enable(struct platform_device *dev) | ||
227 | { | ||
228 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
229 | unsigned long flags; | ||
230 | u16 ccr; | ||
231 | u8 fer; | ||
232 | |||
233 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
234 | |||
235 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
236 | ccr |= SCR_CCR_USBCK; | ||
237 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
238 | |||
239 | fer = tmio_ioread8(tc6393xb->scr + SCR_FER); | ||
240 | fer |= SCR_FER_USBEN; | ||
241 | tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); | ||
242 | |||
243 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int tc6393xb_ohci_disable(struct platform_device *dev) | ||
249 | { | ||
250 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
251 | unsigned long flags; | ||
252 | u16 ccr; | ||
253 | u8 fer; | ||
254 | |||
255 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
256 | |||
257 | fer = tmio_ioread8(tc6393xb->scr + SCR_FER); | ||
258 | fer &= ~SCR_FER_USBEN; | ||
259 | tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); | ||
260 | |||
261 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
262 | ccr &= ~SCR_CCR_USBCK; | ||
263 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
264 | |||
265 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int tc6393xb_fb_enable(struct platform_device *dev) | ||
271 | { | ||
272 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
273 | unsigned long flags; | ||
274 | u16 ccr; | ||
275 | |||
276 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
277 | |||
278 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
279 | ccr &= ~SCR_CCR_MCLK_MASK; | ||
280 | ccr |= SCR_CCR_MCLK_48; | ||
281 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
282 | |||
283 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int tc6393xb_fb_disable(struct platform_device *dev) | ||
289 | { | ||
290 | struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); | ||
291 | unsigned long flags; | ||
292 | u16 ccr; | ||
293 | |||
294 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
295 | |||
296 | ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); | ||
297 | ccr &= ~SCR_CCR_MCLK_MASK; | ||
298 | ccr |= SCR_CCR_MCLK_OFF; | ||
299 | tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); | ||
300 | |||
301 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | int tc6393xb_lcd_set_power(struct platform_device *fb, bool on) | ||
307 | { | ||
308 | struct platform_device *dev = to_platform_device(fb->dev.parent); | ||
309 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
310 | u8 fer; | ||
311 | unsigned long flags; | ||
312 | |||
313 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
314 | |||
315 | fer = ioread8(tc6393xb->scr + SCR_FER); | ||
316 | if (on) | ||
317 | fer |= SCR_FER_SLCDEN; | ||
318 | else | ||
319 | fer &= ~SCR_FER_SLCDEN; | ||
320 | iowrite8(fer, tc6393xb->scr + SCR_FER); | ||
321 | |||
322 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | EXPORT_SYMBOL(tc6393xb_lcd_set_power); | ||
327 | |||
328 | int tc6393xb_lcd_mode(struct platform_device *fb, | ||
329 | const struct fb_videomode *mode) { | ||
330 | struct platform_device *dev = to_platform_device(fb->dev.parent); | ||
331 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
332 | unsigned long flags; | ||
333 | |||
334 | spin_lock_irqsave(&tc6393xb->lock, flags); | ||
335 | |||
336 | iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0); | ||
337 | iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2); | ||
338 | |||
339 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | EXPORT_SYMBOL(tc6393xb_lcd_mode); | ||
344 | |||
173 | static struct mfd_cell __devinitdata tc6393xb_cells[] = { | 345 | static struct mfd_cell __devinitdata tc6393xb_cells[] = { |
174 | [TC6393XB_CELL_NAND] = { | 346 | [TC6393XB_CELL_NAND] = { |
175 | .name = "tmio-nand", | 347 | .name = "tmio-nand", |
@@ -182,6 +354,24 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { | |||
182 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), | 354 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), |
183 | .resources = tc6393xb_mmc_resources, | 355 | .resources = tc6393xb_mmc_resources, |
184 | }, | 356 | }, |
357 | [TC6393XB_CELL_OHCI] = { | ||
358 | .name = "tmio-ohci", | ||
359 | .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources), | ||
360 | .resources = tc6393xb_ohci_resources, | ||
361 | .enable = tc6393xb_ohci_enable, | ||
362 | .suspend = tc6393xb_ohci_disable, | ||
363 | .resume = tc6393xb_ohci_enable, | ||
364 | .disable = tc6393xb_ohci_disable, | ||
365 | }, | ||
366 | [TC6393XB_CELL_FB] = { | ||
367 | .name = "tmio-fb", | ||
368 | .num_resources = ARRAY_SIZE(tc6393xb_fb_resources), | ||
369 | .resources = tc6393xb_fb_resources, | ||
370 | .enable = tc6393xb_fb_enable, | ||
371 | .suspend = tc6393xb_fb_disable, | ||
372 | .resume = tc6393xb_fb_enable, | ||
373 | .disable = tc6393xb_fb_disable, | ||
374 | }, | ||
185 | }; | 375 | }; |
186 | 376 | ||
187 | /*--------------------------------------------------------------------------*/ | 377 | /*--------------------------------------------------------------------------*/ |
@@ -369,41 +559,12 @@ static void tc6393xb_detach_irq(struct platform_device *dev) | |||
369 | 559 | ||
370 | /*--------------------------------------------------------------------------*/ | 560 | /*--------------------------------------------------------------------------*/ |
371 | 561 | ||
372 | static int tc6393xb_hw_init(struct platform_device *dev) | ||
373 | { | ||
374 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | ||
375 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
376 | int i; | ||
377 | |||
378 | iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER); | ||
379 | iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); | ||
380 | iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR); | ||
381 | iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | | ||
382 | SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | | ||
383 | BIT(15), tc6393xb->scr + SCR_MCR); | ||
384 | iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); | ||
385 | iowrite8(0, tc6393xb->scr + SCR_IRR); | ||
386 | iowrite8(0xbf, tc6393xb->scr + SCR_IMR); | ||
387 | |||
388 | for (i = 0; i < 3; i++) { | ||
389 | iowrite8(tc6393xb->suspend_state.gpo_dsr[i], | ||
390 | tc6393xb->scr + SCR_GPO_DSR(i)); | ||
391 | iowrite8(tc6393xb->suspend_state.gpo_doecr[i], | ||
392 | tc6393xb->scr + SCR_GPO_DOECR(i)); | ||
393 | iowrite8(tc6393xb->suspend_state.gpi_bcr[i], | ||
394 | tc6393xb->scr + SCR_GPI_BCR(i)); | ||
395 | } | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int __devinit tc6393xb_probe(struct platform_device *dev) | 562 | static int __devinit tc6393xb_probe(struct platform_device *dev) |
401 | { | 563 | { |
402 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | 564 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
403 | struct tc6393xb *tc6393xb; | 565 | struct tc6393xb *tc6393xb; |
404 | struct resource *iomem, *rscr; | 566 | struct resource *iomem, *rscr; |
405 | int ret, temp; | 567 | int ret, temp; |
406 | int i; | ||
407 | 568 | ||
408 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | 569 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); |
409 | if (!iomem) | 570 | if (!iomem) |
@@ -458,21 +619,16 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
458 | if (ret) | 619 | if (ret) |
459 | goto err_enable; | 620 | goto err_enable; |
460 | 621 | ||
461 | tc6393xb->suspend_state.fer = 0; | 622 | iowrite8(0, tc6393xb->scr + SCR_FER); |
462 | 623 | iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); | |
463 | for (i = 0; i < 3; i++) { | 624 | iowrite16(SCR_CCR_UNK1 | SCR_CCR_HCLK_48, |
464 | tc6393xb->suspend_state.gpo_dsr[i] = | 625 | tc6393xb->scr + SCR_CCR); |
465 | (tcpd->scr_gpo_dsr >> (8 * i)) & 0xff; | 626 | iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | |
466 | tc6393xb->suspend_state.gpo_doecr[i] = | 627 | SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | |
467 | (tcpd->scr_gpo_doecr >> (8 * i)) & 0xff; | 628 | BIT(15), tc6393xb->scr + SCR_MCR); |
468 | } | 629 | iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); |
469 | 630 | iowrite8(0, tc6393xb->scr + SCR_IRR); | |
470 | tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 | | 631 | iowrite8(0xbf, tc6393xb->scr + SCR_IMR); |
471 | SCR_CCR_HCLK_48; | ||
472 | |||
473 | ret = tc6393xb_hw_init(dev); | ||
474 | if (ret) | ||
475 | goto err_hw_init; | ||
476 | 632 | ||
477 | printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", | 633 | printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", |
478 | tmio_ioread8(tc6393xb->scr + SCR_REVID), | 634 | tmio_ioread8(tc6393xb->scr + SCR_REVID), |
@@ -488,16 +644,33 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
488 | 644 | ||
489 | tc6393xb_attach_irq(dev); | 645 | tc6393xb_attach_irq(dev); |
490 | 646 | ||
647 | if (tcpd->setup) { | ||
648 | ret = tcpd->setup(dev); | ||
649 | if (ret) | ||
650 | goto err_setup; | ||
651 | } | ||
652 | |||
491 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; | 653 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; |
492 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = | 654 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = |
493 | &tc6393xb_cells[TC6393XB_CELL_NAND]; | 655 | &tc6393xb_cells[TC6393XB_CELL_NAND]; |
494 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = | 656 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = |
495 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); | 657 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); |
658 | |||
496 | tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = | 659 | tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = |
497 | &tc6393xb_cells[TC6393XB_CELL_MMC]; | 660 | &tc6393xb_cells[TC6393XB_CELL_MMC]; |
498 | tc6393xb_cells[TC6393XB_CELL_MMC].data_size = | 661 | tc6393xb_cells[TC6393XB_CELL_MMC].data_size = |
499 | sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); | 662 | sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); |
500 | 663 | ||
664 | tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data = | ||
665 | &tc6393xb_cells[TC6393XB_CELL_OHCI]; | ||
666 | tc6393xb_cells[TC6393XB_CELL_OHCI].data_size = | ||
667 | sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]); | ||
668 | |||
669 | tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data; | ||
670 | tc6393xb_cells[TC6393XB_CELL_FB].platform_data = | ||
671 | &tc6393xb_cells[TC6393XB_CELL_FB]; | ||
672 | tc6393xb_cells[TC6393XB_CELL_FB].data_size = | ||
673 | sizeof(tc6393xb_cells[TC6393XB_CELL_FB]); | ||
501 | 674 | ||
502 | ret = mfd_add_devices(&dev->dev, dev->id, | 675 | ret = mfd_add_devices(&dev->dev, dev->id, |
503 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), | 676 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), |
@@ -506,12 +679,15 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
506 | if (!ret) | 679 | if (!ret) |
507 | return 0; | 680 | return 0; |
508 | 681 | ||
682 | if (tcpd->teardown) | ||
683 | tcpd->teardown(dev); | ||
684 | |||
685 | err_setup: | ||
509 | tc6393xb_detach_irq(dev); | 686 | tc6393xb_detach_irq(dev); |
510 | 687 | ||
511 | err_gpio_add: | 688 | err_gpio_add: |
512 | if (tc6393xb->gpio.base != -1) | 689 | if (tc6393xb->gpio.base != -1) |
513 | temp = gpiochip_remove(&tc6393xb->gpio); | 690 | temp = gpiochip_remove(&tc6393xb->gpio); |
514 | err_hw_init: | ||
515 | tcpd->disable(dev); | 691 | tcpd->disable(dev); |
516 | err_clk_enable: | 692 | err_clk_enable: |
517 | clk_disable(tc6393xb->clk); | 693 | clk_disable(tc6393xb->clk); |
@@ -535,6 +711,10 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) | |||
535 | int ret; | 711 | int ret; |
536 | 712 | ||
537 | mfd_remove_devices(&dev->dev); | 713 | mfd_remove_devices(&dev->dev); |
714 | |||
715 | if (tcpd->teardown) | ||
716 | tcpd->teardown(dev); | ||
717 | |||
538 | tc6393xb_detach_irq(dev); | 718 | tc6393xb_detach_irq(dev); |
539 | 719 | ||
540 | if (tc6393xb->gpio.base != -1) { | 720 | if (tc6393xb->gpio.base != -1) { |
@@ -585,15 +765,37 @@ static int tc6393xb_resume(struct platform_device *dev) | |||
585 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | 765 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
586 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | 766 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
587 | int ret; | 767 | int ret; |
768 | int i; | ||
588 | 769 | ||
589 | clk_enable(tc6393xb->clk); | 770 | clk_enable(tc6393xb->clk); |
590 | 771 | ||
591 | ret = tcpd->resume(dev); | 772 | ret = tcpd->resume(dev); |
592 | |||
593 | if (ret) | 773 | if (ret) |
594 | return ret; | 774 | return ret; |
595 | 775 | ||
596 | return tc6393xb_hw_init(dev); | 776 | if (!tcpd->resume_restore) |
777 | return 0; | ||
778 | |||
779 | iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER); | ||
780 | iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); | ||
781 | iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR); | ||
782 | iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | | ||
783 | SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | | ||
784 | BIT(15), tc6393xb->scr + SCR_MCR); | ||
785 | iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); | ||
786 | iowrite8(0, tc6393xb->scr + SCR_IRR); | ||
787 | iowrite8(0xbf, tc6393xb->scr + SCR_IMR); | ||
788 | |||
789 | for (i = 0; i < 3; i++) { | ||
790 | iowrite8(tc6393xb->suspend_state.gpo_dsr[i], | ||
791 | tc6393xb->scr + SCR_GPO_DSR(i)); | ||
792 | iowrite8(tc6393xb->suspend_state.gpo_doecr[i], | ||
793 | tc6393xb->scr + SCR_GPO_DOECR(i)); | ||
794 | iowrite8(tc6393xb->suspend_state.gpi_bcr[i], | ||
795 | tc6393xb->scr + SCR_GPI_BCR(i)); | ||
796 | } | ||
797 | |||
798 | return 0; | ||
597 | } | 799 | } |
598 | #else | 800 | #else |
599 | #define tc6393xb_suspend NULL | 801 | #define tc6393xb_suspend NULL |