diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 21 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 2 | ||||
-rw-r--r-- | drivers/mfd/asic3.c | 1 | ||||
-rw-r--r-- | drivers/mfd/t7l66xb.c | 419 | ||||
-rw-r--r-- | drivers/mfd/tc6387xb.c | 181 | ||||
-rw-r--r-- | drivers/mfd/tc6393xb.c | 159 |
6 files changed, 716 insertions, 67 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 371d22a98f19..5dba1651f9cc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -59,10 +59,31 @@ config UCB1400_CORE | |||
59 | To compile this driver as a module, choose M here: the | 59 | To compile this driver as a module, choose M here: the |
60 | module will be called ucb1400_core. | 60 | module will be called ucb1400_core. |
61 | 61 | ||
62 | config MFD_TMIO | ||
63 | bool | ||
64 | default n | ||
65 | |||
66 | config MFD_T7L66XB | ||
67 | bool "Support Toshiba T7L66XB" | ||
68 | depends on ARM | ||
69 | select MFD_CORE | ||
70 | select MFD_TMIO | ||
71 | help | ||
72 | Support for Toshiba Mobile IO Controller T7L66XB | ||
73 | |||
74 | config MFD_TC6387XB | ||
75 | bool "Support Toshiba TC6387XB" | ||
76 | depends on ARM | ||
77 | select MFD_CORE | ||
78 | select MFD_TMIO | ||
79 | help | ||
80 | Support for Toshiba Mobile IO Controller TC6387XB | ||
81 | |||
62 | config MFD_TC6393XB | 82 | config MFD_TC6393XB |
63 | bool "Support Toshiba TC6393XB" | 83 | bool "Support Toshiba TC6393XB" |
64 | depends on GPIOLIB && ARM | 84 | depends on GPIOLIB && ARM |
65 | select MFD_CORE | 85 | select MFD_CORE |
86 | select MFD_TMIO | ||
66 | help | 87 | help |
67 | Support for Toshiba Mobile IO Controller TC6393XB | 88 | Support for Toshiba Mobile IO Controller TC6393XB |
68 | 89 | ||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f7cfd5b4119c..6abebe364419 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -8,6 +8,8 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o | |||
8 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 8 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
9 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o | 9 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o |
10 | 10 | ||
11 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o | ||
12 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o | ||
11 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o | 13 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o |
12 | 14 | ||
13 | obj-$(CONFIG_MFD_CORE) += mfd-core.o | 15 | obj-$(CONFIG_MFD_CORE) += mfd-core.o |
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index c6408a62d95e..bc2a807f210d 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
@@ -16,7 +16,6 @@ | |||
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/version.h> | ||
20 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
21 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
22 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c new file mode 100644 index 000000000000..49a0fffc02af --- /dev/null +++ b/drivers/mfd/t7l66xb.c | |||
@@ -0,0 +1,419 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Toshiba T7L66XB core mfd support | ||
4 | * | ||
5 | * Copyright (c) 2005, 2007, 2008 Ian Molton | ||
6 | * Copyright (c) 2008 Dmitry Baryshkov | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * T7L66 features: | ||
13 | * | ||
14 | * Supported in this driver: | ||
15 | * SD/MMC | ||
16 | * SM/NAND flash controller | ||
17 | * | ||
18 | * As yet not supported | ||
19 | * GPIO interface (on NAND pins) | ||
20 | * Serial interface | ||
21 | * TFT 'interface converter' | ||
22 | * PCMCIA interface logic | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/mfd/core.h> | ||
31 | #include <linux/mfd/tmio.h> | ||
32 | #include <linux/mfd/t7l66xb.h> | ||
33 | |||
34 | enum { | ||
35 | T7L66XB_CELL_NAND, | ||
36 | T7L66XB_CELL_MMC, | ||
37 | }; | ||
38 | |||
39 | #define SCR_REVID 0x08 /* b Revision ID */ | ||
40 | #define SCR_IMR 0x42 /* b Interrupt Mask */ | ||
41 | #define SCR_DEV_CTL 0xe0 /* b Device control */ | ||
42 | #define SCR_ISR 0xe1 /* b Interrupt Status */ | ||
43 | #define SCR_GPO_OC 0xf0 /* b GPO output control */ | ||
44 | #define SCR_GPO_OS 0xf1 /* b GPO output enable */ | ||
45 | #define SCR_GPI_S 0xf2 /* w GPI status */ | ||
46 | #define SCR_APDC 0xf8 /* b Active pullup down ctrl */ | ||
47 | |||
48 | #define SCR_DEV_CTL_USB BIT(0) /* USB enable */ | ||
49 | #define SCR_DEV_CTL_MMC BIT(1) /* MMC enable */ | ||
50 | |||
51 | /*--------------------------------------------------------------------------*/ | ||
52 | |||
53 | struct t7l66xb { | ||
54 | void __iomem *scr; | ||
55 | /* Lock to protect registers requiring read/modify/write ops. */ | ||
56 | spinlock_t lock; | ||
57 | |||
58 | struct resource rscr; | ||
59 | int irq; | ||
60 | int irq_base; | ||
61 | }; | ||
62 | |||
63 | /*--------------------------------------------------------------------------*/ | ||
64 | |||
65 | static int t7l66xb_mmc_enable(struct platform_device *mmc) | ||
66 | { | ||
67 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
68 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
69 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
70 | unsigned long flags; | ||
71 | u8 dev_ctl; | ||
72 | |||
73 | if (pdata->enable_clk32k) | ||
74 | pdata->enable_clk32k(dev); | ||
75 | |||
76 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
77 | |||
78 | dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); | ||
79 | dev_ctl |= SCR_DEV_CTL_MMC; | ||
80 | tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); | ||
81 | |||
82 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int t7l66xb_mmc_disable(struct platform_device *mmc) | ||
88 | { | ||
89 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
90 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
91 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
92 | unsigned long flags; | ||
93 | u8 dev_ctl; | ||
94 | |||
95 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
96 | |||
97 | dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); | ||
98 | dev_ctl &= ~SCR_DEV_CTL_MMC; | ||
99 | tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); | ||
100 | |||
101 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
102 | |||
103 | if (pdata->disable_clk32k) | ||
104 | pdata->disable_clk32k(dev); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /*--------------------------------------------------------------------------*/ | ||
110 | |||
111 | const static struct resource t7l66xb_mmc_resources[] = { | ||
112 | { | ||
113 | .start = 0x800, | ||
114 | .end = 0x9ff, | ||
115 | .flags = IORESOURCE_MEM, | ||
116 | }, | ||
117 | { | ||
118 | .start = 0x200, | ||
119 | .end = 0x2ff, | ||
120 | .flags = IORESOURCE_MEM, | ||
121 | }, | ||
122 | { | ||
123 | .start = IRQ_T7L66XB_MMC, | ||
124 | .end = IRQ_T7L66XB_MMC, | ||
125 | .flags = IORESOURCE_IRQ, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | const static struct resource t7l66xb_nand_resources[] = { | ||
130 | { | ||
131 | .start = 0xc00, | ||
132 | .end = 0xc07, | ||
133 | .flags = IORESOURCE_MEM, | ||
134 | }, | ||
135 | { | ||
136 | .start = 0x0100, | ||
137 | .end = 0x01ff, | ||
138 | .flags = IORESOURCE_MEM, | ||
139 | }, | ||
140 | { | ||
141 | .start = IRQ_T7L66XB_NAND, | ||
142 | .end = IRQ_T7L66XB_NAND, | ||
143 | .flags = IORESOURCE_IRQ, | ||
144 | }, | ||
145 | }; | ||
146 | |||
147 | static struct mfd_cell t7l66xb_cells[] = { | ||
148 | [T7L66XB_CELL_MMC] = { | ||
149 | .name = "tmio-mmc", | ||
150 | .enable = t7l66xb_mmc_enable, | ||
151 | .disable = t7l66xb_mmc_disable, | ||
152 | .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), | ||
153 | .resources = t7l66xb_mmc_resources, | ||
154 | }, | ||
155 | [T7L66XB_CELL_NAND] = { | ||
156 | .name = "tmio-nand", | ||
157 | .num_resources = ARRAY_SIZE(t7l66xb_nand_resources), | ||
158 | .resources = t7l66xb_nand_resources, | ||
159 | }, | ||
160 | }; | ||
161 | |||
162 | /*--------------------------------------------------------------------------*/ | ||
163 | |||
164 | /* Handle the T7L66XB interrupt mux */ | ||
165 | static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) | ||
166 | { | ||
167 | struct t7l66xb *t7l66xb = get_irq_data(irq); | ||
168 | unsigned int isr; | ||
169 | unsigned int i, irq_base; | ||
170 | |||
171 | irq_base = t7l66xb->irq_base; | ||
172 | |||
173 | while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) & | ||
174 | ~tmio_ioread8(t7l66xb->scr + SCR_IMR))) | ||
175 | for (i = 0; i < T7L66XB_NR_IRQS; i++) | ||
176 | if (isr & (1 << i)) | ||
177 | generic_handle_irq(irq_base + i); | ||
178 | } | ||
179 | |||
180 | static void t7l66xb_irq_mask(unsigned int irq) | ||
181 | { | ||
182 | struct t7l66xb *t7l66xb = get_irq_chip_data(irq); | ||
183 | unsigned long flags; | ||
184 | u8 imr; | ||
185 | |||
186 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
187 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); | ||
188 | imr |= 1 << (irq - t7l66xb->irq_base); | ||
189 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); | ||
190 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
191 | } | ||
192 | |||
193 | static void t7l66xb_irq_unmask(unsigned int irq) | ||
194 | { | ||
195 | struct t7l66xb *t7l66xb = get_irq_chip_data(irq); | ||
196 | unsigned long flags; | ||
197 | u8 imr; | ||
198 | |||
199 | spin_lock_irqsave(&t7l66xb->lock, flags); | ||
200 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); | ||
201 | imr &= ~(1 << (irq - t7l66xb->irq_base)); | ||
202 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); | ||
203 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | ||
204 | } | ||
205 | |||
206 | static struct irq_chip t7l66xb_chip = { | ||
207 | .name = "t7l66xb", | ||
208 | .ack = t7l66xb_irq_mask, | ||
209 | .mask = t7l66xb_irq_mask, | ||
210 | .unmask = t7l66xb_irq_unmask, | ||
211 | }; | ||
212 | |||
213 | /*--------------------------------------------------------------------------*/ | ||
214 | |||
215 | /* Install the IRQ handler */ | ||
216 | static void t7l66xb_attach_irq(struct platform_device *dev) | ||
217 | { | ||
218 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
219 | unsigned int irq, irq_base; | ||
220 | |||
221 | irq_base = t7l66xb->irq_base; | ||
222 | |||
223 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | ||
224 | set_irq_chip(irq, &t7l66xb_chip); | ||
225 | set_irq_chip_data(irq, t7l66xb); | ||
226 | set_irq_handler(irq, handle_level_irq); | ||
227 | #ifdef CONFIG_ARM | ||
228 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
229 | #endif | ||
230 | } | ||
231 | |||
232 | set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); | ||
233 | set_irq_data(t7l66xb->irq, t7l66xb); | ||
234 | set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); | ||
235 | } | ||
236 | |||
237 | static void t7l66xb_detach_irq(struct platform_device *dev) | ||
238 | { | ||
239 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
240 | unsigned int irq, irq_base; | ||
241 | |||
242 | irq_base = t7l66xb->irq_base; | ||
243 | |||
244 | set_irq_chained_handler(t7l66xb->irq, NULL); | ||
245 | set_irq_data(t7l66xb->irq, NULL); | ||
246 | |||
247 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | ||
248 | #ifdef CONFIG_ARM | ||
249 | set_irq_flags(irq, 0); | ||
250 | #endif | ||
251 | set_irq_chip(irq, NULL); | ||
252 | set_irq_chip_data(irq, NULL); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /*--------------------------------------------------------------------------*/ | ||
257 | |||
258 | #ifdef CONFIG_PM | ||
259 | static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) | ||
260 | { | ||
261 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
262 | |||
263 | if (pdata && pdata->suspend) | ||
264 | pdata->suspend(dev); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int t7l66xb_resume(struct platform_device *dev) | ||
270 | { | ||
271 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
272 | |||
273 | if (pdata && pdata->resume) | ||
274 | pdata->resume(dev); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | #else | ||
279 | #define t7l66xb_suspend NULL | ||
280 | #define t7l66xb_resume NULL | ||
281 | #endif | ||
282 | |||
283 | /*--------------------------------------------------------------------------*/ | ||
284 | |||
285 | static int t7l66xb_probe(struct platform_device *dev) | ||
286 | { | ||
287 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
288 | struct t7l66xb *t7l66xb; | ||
289 | struct resource *iomem, *rscr; | ||
290 | int ret; | ||
291 | |||
292 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
293 | if (!iomem) | ||
294 | return -EINVAL; | ||
295 | |||
296 | t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL); | ||
297 | if (!t7l66xb) | ||
298 | return -ENOMEM; | ||
299 | |||
300 | spin_lock_init(&t7l66xb->lock); | ||
301 | |||
302 | platform_set_drvdata(dev, t7l66xb); | ||
303 | |||
304 | ret = platform_get_irq(dev, 0); | ||
305 | if (ret >= 0) | ||
306 | t7l66xb->irq = ret; | ||
307 | else | ||
308 | goto err_noirq; | ||
309 | |||
310 | t7l66xb->irq_base = pdata->irq_base; | ||
311 | |||
312 | rscr = &t7l66xb->rscr; | ||
313 | rscr->name = "t7l66xb-core"; | ||
314 | rscr->start = iomem->start; | ||
315 | rscr->end = iomem->start + 0xff; | ||
316 | rscr->flags = IORESOURCE_MEM; | ||
317 | |||
318 | ret = request_resource(iomem, rscr); | ||
319 | if (ret) | ||
320 | goto err_request_scr; | ||
321 | |||
322 | t7l66xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); | ||
323 | if (!t7l66xb->scr) { | ||
324 | ret = -ENOMEM; | ||
325 | goto err_ioremap; | ||
326 | } | ||
327 | |||
328 | if (pdata && pdata->enable) | ||
329 | pdata->enable(dev); | ||
330 | |||
331 | /* Mask all interrupts */ | ||
332 | tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR); | ||
333 | |||
334 | printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n", | ||
335 | dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID), | ||
336 | (unsigned long)iomem->start, t7l66xb->irq); | ||
337 | |||
338 | t7l66xb_attach_irq(dev); | ||
339 | |||
340 | t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; | ||
341 | t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = | ||
342 | &t7l66xb_cells[T7L66XB_CELL_NAND]; | ||
343 | t7l66xb_cells[T7L66XB_CELL_NAND].data_size = | ||
344 | sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); | ||
345 | |||
346 | t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = | ||
347 | &t7l66xb_cells[T7L66XB_CELL_MMC]; | ||
348 | t7l66xb_cells[T7L66XB_CELL_MMC].data_size = | ||
349 | sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); | ||
350 | |||
351 | ret = mfd_add_devices(&dev->dev, dev->id, | ||
352 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), | ||
353 | iomem, t7l66xb->irq_base); | ||
354 | |||
355 | if (!ret) | ||
356 | return 0; | ||
357 | |||
358 | t7l66xb_detach_irq(dev); | ||
359 | iounmap(t7l66xb->scr); | ||
360 | err_ioremap: | ||
361 | release_resource(&t7l66xb->rscr); | ||
362 | err_noirq: | ||
363 | err_request_scr: | ||
364 | kfree(t7l66xb); | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static int t7l66xb_remove(struct platform_device *dev) | ||
369 | { | ||
370 | struct t7l66xb_platform_data *pdata = dev->dev.platform_data; | ||
371 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
372 | int ret; | ||
373 | |||
374 | ret = pdata->disable(dev); | ||
375 | |||
376 | t7l66xb_detach_irq(dev); | ||
377 | iounmap(t7l66xb->scr); | ||
378 | release_resource(&t7l66xb->rscr); | ||
379 | mfd_remove_devices(&dev->dev); | ||
380 | platform_set_drvdata(dev, NULL); | ||
381 | kfree(t7l66xb); | ||
382 | |||
383 | return ret; | ||
384 | |||
385 | } | ||
386 | |||
387 | static struct platform_driver t7l66xb_platform_driver = { | ||
388 | .driver = { | ||
389 | .name = "t7l66xb", | ||
390 | .owner = THIS_MODULE, | ||
391 | }, | ||
392 | .suspend = t7l66xb_suspend, | ||
393 | .resume = t7l66xb_resume, | ||
394 | .probe = t7l66xb_probe, | ||
395 | .remove = t7l66xb_remove, | ||
396 | }; | ||
397 | |||
398 | /*--------------------------------------------------------------------------*/ | ||
399 | |||
400 | static int __init t7l66xb_init(void) | ||
401 | { | ||
402 | int retval = 0; | ||
403 | |||
404 | retval = platform_driver_register(&t7l66xb_platform_driver); | ||
405 | return retval; | ||
406 | } | ||
407 | |||
408 | static void __exit t7l66xb_exit(void) | ||
409 | { | ||
410 | platform_driver_unregister(&t7l66xb_platform_driver); | ||
411 | } | ||
412 | |||
413 | module_init(t7l66xb_init); | ||
414 | module_exit(t7l66xb_exit); | ||
415 | |||
416 | MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); | ||
417 | MODULE_LICENSE("GPL v2"); | ||
418 | MODULE_AUTHOR("Ian Molton"); | ||
419 | MODULE_ALIAS("platform:t7l66xb"); | ||
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c new file mode 100644 index 000000000000..a22b21ac6cf8 --- /dev/null +++ b/drivers/mfd/tc6387xb.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Toshiba TC6387XB support | ||
3 | * Copyright (c) 2005 Ian Molton | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This file contains TC6387XB base support. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/mfd/core.h> | ||
17 | #include <linux/mfd/tmio.h> | ||
18 | #include <linux/mfd/tc6387xb.h> | ||
19 | |||
20 | enum { | ||
21 | TC6387XB_CELL_MMC, | ||
22 | }; | ||
23 | |||
24 | #ifdef CONFIG_PM | ||
25 | static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) | ||
26 | { | ||
27 | struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); | ||
28 | |||
29 | if (pdata && pdata->suspend) | ||
30 | pdata->suspend(dev); | ||
31 | |||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static int tc6387xb_resume(struct platform_device *dev) | ||
36 | { | ||
37 | struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); | ||
38 | |||
39 | if (pdata && pdata->resume) | ||
40 | pdata->resume(dev); | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | #else | ||
45 | #define tc6387xb_suspend NULL | ||
46 | #define tc6387xb_resume NULL | ||
47 | #endif | ||
48 | |||
49 | /*--------------------------------------------------------------------------*/ | ||
50 | |||
51 | static int tc6387xb_mmc_enable(struct platform_device *mmc) | ||
52 | { | ||
53 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
54 | struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; | ||
55 | |||
56 | if (tc6387xb->enable_clk32k) | ||
57 | tc6387xb->enable_clk32k(dev); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int tc6387xb_mmc_disable(struct platform_device *mmc) | ||
63 | { | ||
64 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | ||
65 | struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; | ||
66 | |||
67 | if (tc6387xb->disable_clk32k) | ||
68 | tc6387xb->disable_clk32k(dev); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | /*--------------------------------------------------------------------------*/ | ||
74 | |||
75 | static struct resource tc6387xb_mmc_resources[] = { | ||
76 | { | ||
77 | .start = 0x800, | ||
78 | .end = 0x9ff, | ||
79 | .flags = IORESOURCE_MEM, | ||
80 | }, | ||
81 | { | ||
82 | .start = 0x200, | ||
83 | .end = 0x2ff, | ||
84 | .flags = IORESOURCE_MEM, | ||
85 | }, | ||
86 | { | ||
87 | .start = 0, | ||
88 | .end = 0, | ||
89 | .flags = IORESOURCE_IRQ, | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | static struct mfd_cell tc6387xb_cells[] = { | ||
94 | [TC6387XB_CELL_MMC] = { | ||
95 | .name = "tmio-mmc", | ||
96 | .enable = tc6387xb_mmc_enable, | ||
97 | .disable = tc6387xb_mmc_disable, | ||
98 | .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), | ||
99 | .resources = tc6387xb_mmc_resources, | ||
100 | }, | ||
101 | }; | ||
102 | |||
103 | static int tc6387xb_probe(struct platform_device *dev) | ||
104 | { | ||
105 | struct tc6387xb_platform_data *data = platform_get_drvdata(dev); | ||
106 | struct resource *iomem; | ||
107 | int irq, ret; | ||
108 | |||
109 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
110 | if (!iomem) { | ||
111 | ret = -EINVAL; | ||
112 | goto err_resource; | ||
113 | } | ||
114 | |||
115 | ret = platform_get_irq(dev, 0); | ||
116 | if (ret >= 0) | ||
117 | irq = ret; | ||
118 | else | ||
119 | goto err_resource; | ||
120 | |||
121 | if (data && data->enable) | ||
122 | data->enable(dev); | ||
123 | |||
124 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); | ||
125 | |||
126 | tc6387xb_cells[TC6387XB_CELL_MMC].platform_data = | ||
127 | &tc6387xb_cells[TC6387XB_CELL_MMC]; | ||
128 | tc6387xb_cells[TC6387XB_CELL_MMC].data_size = | ||
129 | sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]); | ||
130 | |||
131 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, | ||
132 | ARRAY_SIZE(tc6387xb_cells), iomem, irq); | ||
133 | |||
134 | if (!ret) | ||
135 | return 0; | ||
136 | |||
137 | err_resource: | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static int tc6387xb_remove(struct platform_device *dev) | ||
142 | { | ||
143 | struct tc6387xb_platform_data *data = platform_get_drvdata(dev); | ||
144 | |||
145 | if (data && data->disable) | ||
146 | data->disable(dev); | ||
147 | |||
148 | /* FIXME - free the resources! */ | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | |||
154 | static struct platform_driver tc6387xb_platform_driver = { | ||
155 | .driver = { | ||
156 | .name = "tc6387xb", | ||
157 | }, | ||
158 | .probe = tc6387xb_probe, | ||
159 | .remove = tc6387xb_remove, | ||
160 | .suspend = tc6387xb_suspend, | ||
161 | .resume = tc6387xb_resume, | ||
162 | }; | ||
163 | |||
164 | |||
165 | static int __init tc6387xb_init(void) | ||
166 | { | ||
167 | return platform_driver_register(&tc6387xb_platform_driver); | ||
168 | } | ||
169 | |||
170 | static void __exit tc6387xb_exit(void) | ||
171 | { | ||
172 | platform_driver_unregister(&tc6387xb_platform_driver); | ||
173 | } | ||
174 | |||
175 | module_init(tc6387xb_init); | ||
176 | module_exit(tc6387xb_exit); | ||
177 | |||
178 | MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); | ||
179 | MODULE_LICENSE("GPL v2"); | ||
180 | MODULE_AUTHOR("Ian Molton"); | ||
181 | MODULE_ALIAS("platform:tc6387xb"); | ||
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index f4fd797c1590..e4c1c788b5f8 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/fb.h> | ||
23 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
23 | #include <linux/err.h> | ||
24 | #include <linux/mfd/core.h> | 24 | #include <linux/mfd/core.h> |
25 | #include <linux/mfd/tmio.h> | 25 | #include <linux/mfd/tmio.h> |
26 | #include <linux/mfd/tc6393xb.h> | 26 | #include <linux/mfd/tc6393xb.h> |
@@ -112,6 +112,7 @@ struct tc6393xb { | |||
112 | 112 | ||
113 | enum { | 113 | enum { |
114 | TC6393XB_CELL_NAND, | 114 | TC6393XB_CELL_NAND, |
115 | TC6393XB_CELL_MMC, | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | /*--------------------------------------------------------------------------*/ | 118 | /*--------------------------------------------------------------------------*/ |
@@ -126,7 +127,7 @@ static int tc6393xb_nand_enable(struct platform_device *nand) | |||
126 | 127 | ||
127 | /* SMD buffer on */ | 128 | /* SMD buffer on */ |
128 | dev_dbg(&dev->dev, "SMD buffer on\n"); | 129 | dev_dbg(&dev->dev, "SMD buffer on\n"); |
129 | iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); | 130 | tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); |
130 | 131 | ||
131 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | 132 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
132 | 133 | ||
@@ -135,25 +136,40 @@ static int tc6393xb_nand_enable(struct platform_device *nand) | |||
135 | 136 | ||
136 | static struct resource __devinitdata tc6393xb_nand_resources[] = { | 137 | static struct resource __devinitdata tc6393xb_nand_resources[] = { |
137 | { | 138 | { |
138 | .name = TMIO_NAND_CONFIG, | 139 | .start = 0x1000, |
139 | .start = 0x0100, | 140 | .end = 0x1007, |
140 | .end = 0x01ff, | ||
141 | .flags = IORESOURCE_MEM, | 141 | .flags = IORESOURCE_MEM, |
142 | }, | 142 | }, |
143 | { | 143 | { |
144 | .name = TMIO_NAND_CONTROL, | 144 | .start = 0x0100, |
145 | .start = 0x1000, | 145 | .end = 0x01ff, |
146 | .end = 0x1007, | ||
147 | .flags = IORESOURCE_MEM, | 146 | .flags = IORESOURCE_MEM, |
148 | }, | 147 | }, |
149 | { | 148 | { |
150 | .name = TMIO_NAND_IRQ, | ||
151 | .start = IRQ_TC6393_NAND, | 149 | .start = IRQ_TC6393_NAND, |
152 | .end = IRQ_TC6393_NAND, | 150 | .end = IRQ_TC6393_NAND, |
153 | .flags = IORESOURCE_IRQ, | 151 | .flags = IORESOURCE_IRQ, |
154 | }, | 152 | }, |
155 | }; | 153 | }; |
156 | 154 | ||
155 | static struct resource __devinitdata tc6393xb_mmc_resources[] = { | ||
156 | { | ||
157 | .start = 0x800, | ||
158 | .end = 0x9ff, | ||
159 | .flags = IORESOURCE_MEM, | ||
160 | }, | ||
161 | { | ||
162 | .start = 0x200, | ||
163 | .end = 0x2ff, | ||
164 | .flags = IORESOURCE_MEM, | ||
165 | }, | ||
166 | { | ||
167 | .start = IRQ_TC6393_MMC, | ||
168 | .end = IRQ_TC6393_MMC, | ||
169 | .flags = IORESOURCE_IRQ, | ||
170 | }, | ||
171 | }; | ||
172 | |||
157 | static struct mfd_cell __devinitdata tc6393xb_cells[] = { | 173 | static struct mfd_cell __devinitdata tc6393xb_cells[] = { |
158 | [TC6393XB_CELL_NAND] = { | 174 | [TC6393XB_CELL_NAND] = { |
159 | .name = "tmio-nand", | 175 | .name = "tmio-nand", |
@@ -161,6 +177,11 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { | |||
161 | .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), | 177 | .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), |
162 | .resources = tc6393xb_nand_resources, | 178 | .resources = tc6393xb_nand_resources, |
163 | }, | 179 | }, |
180 | [TC6393XB_CELL_MMC] = { | ||
181 | .name = "tmio-mmc", | ||
182 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), | ||
183 | .resources = tc6393xb_mmc_resources, | ||
184 | }, | ||
164 | }; | 185 | }; |
165 | 186 | ||
166 | /*--------------------------------------------------------------------------*/ | 187 | /*--------------------------------------------------------------------------*/ |
@@ -171,7 +192,7 @@ static int tc6393xb_gpio_get(struct gpio_chip *chip, | |||
171 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); | 192 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); |
172 | 193 | ||
173 | /* XXX: does dsr also represent inputs? */ | 194 | /* XXX: does dsr also represent inputs? */ |
174 | return ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) | 195 | return tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) |
175 | & TC_GPIO_BIT(offset); | 196 | & TC_GPIO_BIT(offset); |
176 | } | 197 | } |
177 | 198 | ||
@@ -181,13 +202,13 @@ static void __tc6393xb_gpio_set(struct gpio_chip *chip, | |||
181 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); | 202 | struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); |
182 | u8 dsr; | 203 | u8 dsr; |
183 | 204 | ||
184 | dsr = ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); | 205 | dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); |
185 | if (value) | 206 | if (value) |
186 | dsr |= TC_GPIO_BIT(offset); | 207 | dsr |= TC_GPIO_BIT(offset); |
187 | else | 208 | else |
188 | dsr &= ~TC_GPIO_BIT(offset); | 209 | dsr &= ~TC_GPIO_BIT(offset); |
189 | 210 | ||
190 | iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); | 211 | tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); |
191 | } | 212 | } |
192 | 213 | ||
193 | static void tc6393xb_gpio_set(struct gpio_chip *chip, | 214 | static void tc6393xb_gpio_set(struct gpio_chip *chip, |
@@ -212,9 +233,9 @@ static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, | |||
212 | 233 | ||
213 | spin_lock_irqsave(&tc6393xb->lock, flags); | 234 | spin_lock_irqsave(&tc6393xb->lock, flags); |
214 | 235 | ||
215 | doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | 236 | doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
216 | doecr &= ~TC_GPIO_BIT(offset); | 237 | doecr &= ~TC_GPIO_BIT(offset); |
217 | iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | 238 | tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
218 | 239 | ||
219 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | 240 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
220 | 241 | ||
@@ -232,9 +253,9 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, | |||
232 | 253 | ||
233 | __tc6393xb_gpio_set(chip, offset, value); | 254 | __tc6393xb_gpio_set(chip, offset, value); |
234 | 255 | ||
235 | doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | 256 | doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
236 | doecr |= TC_GPIO_BIT(offset); | 257 | doecr |= TC_GPIO_BIT(offset); |
237 | iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); | 258 | tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); |
238 | 259 | ||
239 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | 260 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
240 | 261 | ||
@@ -265,8 +286,8 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc) | |||
265 | 286 | ||
266 | irq_base = tc6393xb->irq_base; | 287 | irq_base = tc6393xb->irq_base; |
267 | 288 | ||
268 | while ((isr = ioread8(tc6393xb->scr + SCR_ISR) & | 289 | while ((isr = tmio_ioread8(tc6393xb->scr + SCR_ISR) & |
269 | ~ioread8(tc6393xb->scr + SCR_IMR))) | 290 | ~tmio_ioread8(tc6393xb->scr + SCR_IMR))) |
270 | for (i = 0; i < TC6393XB_NR_IRQS; i++) { | 291 | for (i = 0; i < TC6393XB_NR_IRQS; i++) { |
271 | if (isr & (1 << i)) | 292 | if (isr & (1 << i)) |
272 | generic_handle_irq(irq_base + i); | 293 | generic_handle_irq(irq_base + i); |
@@ -284,9 +305,9 @@ static void tc6393xb_irq_mask(unsigned int irq) | |||
284 | u8 imr; | 305 | u8 imr; |
285 | 306 | ||
286 | spin_lock_irqsave(&tc6393xb->lock, flags); | 307 | spin_lock_irqsave(&tc6393xb->lock, flags); |
287 | imr = ioread8(tc6393xb->scr + SCR_IMR); | 308 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); |
288 | imr |= 1 << (irq - tc6393xb->irq_base); | 309 | imr |= 1 << (irq - tc6393xb->irq_base); |
289 | iowrite8(imr, tc6393xb->scr + SCR_IMR); | 310 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); |
290 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | 311 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
291 | } | 312 | } |
292 | 313 | ||
@@ -297,9 +318,9 @@ static void tc6393xb_irq_unmask(unsigned int irq) | |||
297 | u8 imr; | 318 | u8 imr; |
298 | 319 | ||
299 | spin_lock_irqsave(&tc6393xb->lock, flags); | 320 | spin_lock_irqsave(&tc6393xb->lock, flags); |
300 | imr = ioread8(tc6393xb->scr + SCR_IMR); | 321 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); |
301 | imr &= ~(1 << (irq - tc6393xb->irq_base)); | 322 | imr &= ~(1 << (irq - tc6393xb->irq_base)); |
302 | iowrite8(imr, tc6393xb->scr + SCR_IMR); | 323 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); |
303 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | 324 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
304 | } | 325 | } |
305 | 326 | ||
@@ -380,9 +401,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
380 | { | 401 | { |
381 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | 402 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
382 | struct tc6393xb *tc6393xb; | 403 | struct tc6393xb *tc6393xb; |
383 | struct resource *iomem; | 404 | struct resource *iomem, *rscr; |
384 | struct resource *rscr; | 405 | int ret, temp; |
385 | int retval, temp; | ||
386 | int i; | 406 | int i; |
387 | 407 | ||
388 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | 408 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); |
@@ -391,20 +411,26 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
391 | 411 | ||
392 | tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); | 412 | tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); |
393 | if (!tc6393xb) { | 413 | if (!tc6393xb) { |
394 | retval = -ENOMEM; | 414 | ret = -ENOMEM; |
395 | goto err_kzalloc; | 415 | goto err_kzalloc; |
396 | } | 416 | } |
397 | 417 | ||
398 | spin_lock_init(&tc6393xb->lock); | 418 | spin_lock_init(&tc6393xb->lock); |
399 | 419 | ||
400 | platform_set_drvdata(dev, tc6393xb); | 420 | platform_set_drvdata(dev, tc6393xb); |
421 | |||
422 | ret = platform_get_irq(dev, 0); | ||
423 | if (ret >= 0) | ||
424 | tc6393xb->irq = ret; | ||
425 | else | ||
426 | goto err_noirq; | ||
427 | |||
401 | tc6393xb->iomem = iomem; | 428 | tc6393xb->iomem = iomem; |
402 | tc6393xb->irq = platform_get_irq(dev, 0); | ||
403 | tc6393xb->irq_base = tcpd->irq_base; | 429 | tc6393xb->irq_base = tcpd->irq_base; |
404 | 430 | ||
405 | tc6393xb->clk = clk_get(&dev->dev, "GPIO27_CLK" /* "CK3P6MI" */); | 431 | tc6393xb->clk = clk_get(&dev->dev, "CLK_CK3P6MI"); |
406 | if (IS_ERR(tc6393xb->clk)) { | 432 | if (IS_ERR(tc6393xb->clk)) { |
407 | retval = PTR_ERR(tc6393xb->clk); | 433 | ret = PTR_ERR(tc6393xb->clk); |
408 | goto err_clk_get; | 434 | goto err_clk_get; |
409 | } | 435 | } |
410 | 436 | ||
@@ -414,71 +440,73 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
414 | rscr->end = iomem->start + 0xff; | 440 | rscr->end = iomem->start + 0xff; |
415 | rscr->flags = IORESOURCE_MEM; | 441 | rscr->flags = IORESOURCE_MEM; |
416 | 442 | ||
417 | retval = request_resource(iomem, rscr); | 443 | ret = request_resource(iomem, rscr); |
418 | if (retval) | 444 | if (ret) |
419 | goto err_request_scr; | 445 | goto err_request_scr; |
420 | 446 | ||
421 | tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); | 447 | tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); |
422 | if (!tc6393xb->scr) { | 448 | if (!tc6393xb->scr) { |
423 | retval = -ENOMEM; | 449 | ret = -ENOMEM; |
424 | goto err_ioremap; | 450 | goto err_ioremap; |
425 | } | 451 | } |
426 | 452 | ||
427 | retval = clk_enable(tc6393xb->clk); | 453 | ret = clk_enable(tc6393xb->clk); |
428 | if (retval) | 454 | if (ret) |
429 | goto err_clk_enable; | 455 | goto err_clk_enable; |
430 | 456 | ||
431 | retval = tcpd->enable(dev); | 457 | ret = tcpd->enable(dev); |
432 | if (retval) | 458 | if (ret) |
433 | goto err_enable; | 459 | goto err_enable; |
434 | 460 | ||
435 | tc6393xb->suspend_state.fer = 0; | 461 | tc6393xb->suspend_state.fer = 0; |
462 | |||
436 | for (i = 0; i < 3; i++) { | 463 | for (i = 0; i < 3; i++) { |
437 | tc6393xb->suspend_state.gpo_dsr[i] = | 464 | tc6393xb->suspend_state.gpo_dsr[i] = |
438 | (tcpd->scr_gpo_dsr >> (8 * i)) & 0xff; | 465 | (tcpd->scr_gpo_dsr >> (8 * i)) & 0xff; |
439 | tc6393xb->suspend_state.gpo_doecr[i] = | 466 | tc6393xb->suspend_state.gpo_doecr[i] = |
440 | (tcpd->scr_gpo_doecr >> (8 * i)) & 0xff; | 467 | (tcpd->scr_gpo_doecr >> (8 * i)) & 0xff; |
441 | } | 468 | } |
442 | /* | 469 | |
443 | * It may be necessary to change this back to | ||
444 | * platform-dependant code | ||
445 | */ | ||
446 | tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 | | 470 | tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 | |
447 | SCR_CCR_HCLK_48; | 471 | SCR_CCR_HCLK_48; |
448 | 472 | ||
449 | retval = tc6393xb_hw_init(dev); | 473 | ret = tc6393xb_hw_init(dev); |
450 | if (retval) | 474 | if (ret) |
451 | goto err_hw_init; | 475 | goto err_hw_init; |
452 | 476 | ||
453 | printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", | 477 | printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", |
454 | ioread8(tc6393xb->scr + SCR_REVID), | 478 | tmio_ioread8(tc6393xb->scr + SCR_REVID), |
455 | (unsigned long) iomem->start, tc6393xb->irq); | 479 | (unsigned long) iomem->start, tc6393xb->irq); |
456 | 480 | ||
457 | tc6393xb->gpio.base = -1; | 481 | tc6393xb->gpio.base = -1; |
458 | 482 | ||
459 | if (tcpd->gpio_base >= 0) { | 483 | if (tcpd->gpio_base >= 0) { |
460 | retval = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); | 484 | ret = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); |
461 | if (retval) | 485 | if (ret) |
462 | goto err_gpio_add; | 486 | goto err_gpio_add; |
463 | } | 487 | } |
464 | 488 | ||
465 | if (tc6393xb->irq) | 489 | tc6393xb_attach_irq(dev); |
466 | tc6393xb_attach_irq(dev); | ||
467 | 490 | ||
468 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; | 491 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; |
469 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = | 492 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = |
470 | &tc6393xb_cells[TC6393XB_CELL_NAND]; | 493 | &tc6393xb_cells[TC6393XB_CELL_NAND]; |
471 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = | 494 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = |
472 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); | 495 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); |
496 | tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = | ||
497 | &tc6393xb_cells[TC6393XB_CELL_MMC]; | ||
498 | tc6393xb_cells[TC6393XB_CELL_MMC].data_size = | ||
499 | sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); | ||
500 | |||
473 | 501 | ||
474 | retval = mfd_add_devices(&dev->dev, dev->id, | 502 | ret = mfd_add_devices(&dev->dev, dev->id, |
475 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), | 503 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), |
476 | iomem, tcpd->irq_base); | 504 | iomem, tcpd->irq_base); |
477 | 505 | ||
478 | return 0; | 506 | if (!ret) |
507 | return 0; | ||
479 | 508 | ||
480 | if (tc6393xb->irq) | 509 | tc6393xb_detach_irq(dev); |
481 | tc6393xb_detach_irq(dev); | ||
482 | 510 | ||
483 | err_gpio_add: | 511 | err_gpio_add: |
484 | if (tc6393xb->gpio.base != -1) | 512 | if (tc6393xb->gpio.base != -1) |
@@ -493,10 +521,11 @@ err_ioremap: | |||
493 | release_resource(&tc6393xb->rscr); | 521 | release_resource(&tc6393xb->rscr); |
494 | err_request_scr: | 522 | err_request_scr: |
495 | clk_put(tc6393xb->clk); | 523 | clk_put(tc6393xb->clk); |
524 | err_noirq: | ||
496 | err_clk_get: | 525 | err_clk_get: |
497 | kfree(tc6393xb); | 526 | kfree(tc6393xb); |
498 | err_kzalloc: | 527 | err_kzalloc: |
499 | return retval; | 528 | return ret; |
500 | } | 529 | } |
501 | 530 | ||
502 | static int __devexit tc6393xb_remove(struct platform_device *dev) | 531 | static int __devexit tc6393xb_remove(struct platform_device *dev) |
@@ -506,9 +535,7 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) | |||
506 | int ret; | 535 | int ret; |
507 | 536 | ||
508 | mfd_remove_devices(&dev->dev); | 537 | mfd_remove_devices(&dev->dev); |
509 | 538 | tc6393xb_detach_irq(dev); | |
510 | if (tc6393xb->irq) | ||
511 | tc6393xb_detach_irq(dev); | ||
512 | 539 | ||
513 | if (tc6393xb->gpio.base != -1) { | 540 | if (tc6393xb->gpio.base != -1) { |
514 | ret = gpiochip_remove(&tc6393xb->gpio); | 541 | ret = gpiochip_remove(&tc6393xb->gpio); |
@@ -519,17 +546,11 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) | |||
519 | } | 546 | } |
520 | 547 | ||
521 | ret = tcpd->disable(dev); | 548 | ret = tcpd->disable(dev); |
522 | |||
523 | clk_disable(tc6393xb->clk); | 549 | clk_disable(tc6393xb->clk); |
524 | |||
525 | iounmap(tc6393xb->scr); | 550 | iounmap(tc6393xb->scr); |
526 | |||
527 | release_resource(&tc6393xb->rscr); | 551 | release_resource(&tc6393xb->rscr); |
528 | |||
529 | platform_set_drvdata(dev, NULL); | 552 | platform_set_drvdata(dev, NULL); |
530 | |||
531 | clk_put(tc6393xb->clk); | 553 | clk_put(tc6393xb->clk); |
532 | |||
533 | kfree(tc6393xb); | 554 | kfree(tc6393xb); |
534 | 555 | ||
535 | return ret; | 556 | return ret; |
@@ -540,8 +561,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) | |||
540 | { | 561 | { |
541 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | 562 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
542 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | 563 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
543 | int i; | 564 | int i, ret; |
544 | |||
545 | 565 | ||
546 | tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); | 566 | tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); |
547 | tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); | 567 | tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); |
@@ -554,14 +574,21 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) | |||
554 | tc6393xb->suspend_state.gpi_bcr[i] = | 574 | tc6393xb->suspend_state.gpi_bcr[i] = |
555 | ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); | 575 | ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); |
556 | } | 576 | } |
577 | ret = tcpd->suspend(dev); | ||
578 | clk_disable(tc6393xb->clk); | ||
557 | 579 | ||
558 | return tcpd->suspend(dev); | 580 | return ret; |
559 | } | 581 | } |
560 | 582 | ||
561 | static int tc6393xb_resume(struct platform_device *dev) | 583 | static int tc6393xb_resume(struct platform_device *dev) |
562 | { | 584 | { |
563 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; | 585 | struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; |
564 | int ret = tcpd->resume(dev); | 586 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
587 | int ret; | ||
588 | |||
589 | clk_enable(tc6393xb->clk); | ||
590 | |||
591 | ret = tcpd->resume(dev); | ||
565 | 592 | ||
566 | if (ret) | 593 | if (ret) |
567 | return ret; | 594 | return ret; |
@@ -598,7 +625,7 @@ static void __exit tc6393xb_exit(void) | |||
598 | subsys_initcall(tc6393xb_init); | 625 | subsys_initcall(tc6393xb_init); |
599 | module_exit(tc6393xb_exit); | 626 | module_exit(tc6393xb_exit); |
600 | 627 | ||
601 | MODULE_LICENSE("GPL"); | 628 | MODULE_LICENSE("GPL v2"); |
602 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); | 629 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); |
603 | MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); | 630 | MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); |
604 | MODULE_ALIAS("platform:tc6393xb"); | 631 | MODULE_ALIAS("platform:tc6393xb"); |