aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@openedhand.com>2008-02-07 03:14:49 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 11:42:23 -0500
commitfa9ff4b185b8f7f124c1c6686f02e690f0625287 (patch)
treef25c1f4f9b27f19070d8a79ea245137a5e10d04f /drivers/mfd
parent8f5aa26c75b7722e80c0c5c5bb833d41865d7019 (diff)
ASIC3 driver
This is a patch for the Compaq ASIC3 multi function chip, found in many PDAs (iPAQs, HTCs...). It is a simplified version of Paul Sokolovsky's first proposal [1]. With this code, it is basically a GPIO and IRQ expander. My plan is to add more features once this patch gets reviewed and accepted. [1] http://lkml.org/lkml/2007/5/1/46 Signed-off-by: Samuel Ortiz <sameo@openedhand.com> Cc: Paul Sokolovsky <pmiscml@gmail.com> Cc: Ben Dooks <ben@trinity.fluff.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig7
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/asic3.c588
3 files changed, 596 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 25716193a534..0c886c882385 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -15,6 +15,13 @@ config MFD_SM501
15 interface. The device may be connected by PCI or local bus with 15 interface. The device may be connected by PCI or local bus with
16 varying functions enabled. 16 varying functions enabled.
17 17
18config MFD_ASIC3
19 bool "Support for Compaq ASIC3"
20 depends on GENERIC_HARDIRQS && ARM
21 ---help---
22 This driver supports the ASIC3 multifunction chip found on many
23 PDAs (mainly iPAQ and HTC based ones)
24
18endmenu 25endmenu
19 26
20menu "Multimedia Capabilities Port drivers" 27menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 51432091b323..521cd5cb68af 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5obj-$(CONFIG_MFD_SM501) += sm501.o 5obj-$(CONFIG_MFD_SM501) += sm501.o
6obj-$(CONFIG_MFD_ASIC3) += asic3.o
6 7
7obj-$(CONFIG_MCP) += mcp-core.o 8obj-$(CONFIG_MCP) += mcp-core.o
8obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o 9obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
new file mode 100644
index 000000000000..63fb1ff3ad10
--- /dev/null
+++ b/drivers/mfd/asic3.c
@@ -0,0 +1,588 @@
1/*
2 * driver/mfd/asic3.c
3 *
4 * Compaq ASIC3 support.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Copyright 2001 Compaq Computer Corporation.
11 * Copyright 2004-2005 Phil Blundell
12 * Copyright 2007 OpenedHand Ltd.
13 *
14 * Authors: Phil Blundell <pb@handhelds.org>,
15 * Samuel Ortiz <sameo@openedhand.com>
16 *
17 */
18
19#include <linux/version.h>
20#include <linux/kernel.h>
21#include <linux/irq.h>
22#include <linux/io.h>
23#include <linux/spinlock.h>
24#include <linux/platform_device.h>
25
26#include <linux/mfd/asic3.h>
27
28static inline void asic3_write_register(struct asic3 *asic,
29 unsigned int reg, u32 value)
30{
31 iowrite16(value, (unsigned long)asic->mapping +
32 (reg >> asic->bus_shift));
33}
34
35static inline u32 asic3_read_register(struct asic3 *asic,
36 unsigned int reg)
37{
38 return ioread16((unsigned long)asic->mapping +
39 (reg >> asic->bus_shift));
40}
41
42/* IRQs */
43#define MAX_ASIC_ISR_LOOPS 20
44#define ASIC3_GPIO_Base_INCR \
45 (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base)
46
47static void asic3_irq_flip_edge(struct asic3 *asic,
48 u32 base, int bit)
49{
50 u16 edge;
51 unsigned long flags;
52
53 spin_lock_irqsave(&asic->lock, flags);
54 edge = asic3_read_register(asic,
55 base + ASIC3_GPIO_EdgeTrigger);
56 edge ^= bit;
57 asic3_write_register(asic,
58 base + ASIC3_GPIO_EdgeTrigger, edge);
59 spin_unlock_irqrestore(&asic->lock, flags);
60}
61
62static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
63{
64 int iter, i;
65 unsigned long flags;
66 struct asic3 *asic;
67
68 desc->chip->ack(irq);
69
70 asic = desc->handler_data;
71
72 for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
73 u32 status;
74 int bank;
75
76 spin_lock_irqsave(&asic->lock, flags);
77 status = asic3_read_register(asic,
78 ASIC3_OFFSET(INTR, PIntStat));
79 spin_unlock_irqrestore(&asic->lock, flags);
80
81 /* Check all ten register bits */
82 if ((status & 0x3ff) == 0)
83 break;
84
85 /* Handle GPIO IRQs */
86 for (bank = 0; bank < ASIC3_NUM_GPIO_BANKS; bank++) {
87 if (status & (1 << bank)) {
88 unsigned long base, istat;
89
90 base = ASIC3_GPIO_A_Base
91 + bank * ASIC3_GPIO_Base_INCR;
92
93 spin_lock_irqsave(&asic->lock, flags);
94 istat = asic3_read_register(asic,
95 base +
96 ASIC3_GPIO_IntStatus);
97 /* Clearing IntStatus */
98 asic3_write_register(asic,
99 base +
100 ASIC3_GPIO_IntStatus, 0);
101 spin_unlock_irqrestore(&asic->lock, flags);
102
103 for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) {
104 int bit = (1 << i);
105 unsigned int irqnr;
106
107 if (!(istat & bit))
108 continue;
109
110 irqnr = asic->irq_base +
111 (ASIC3_GPIOS_PER_BANK * bank)
112 + i;
113 desc = irq_desc + irqnr;
114 desc->handle_irq(irqnr, desc);
115 if (asic->irq_bothedge[bank] & bit)
116 asic3_irq_flip_edge(asic, base,
117 bit);
118 }
119 }
120 }
121
122 /* Handle remaining IRQs in the status register */
123 for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) {
124 /* They start at bit 4 and go up */
125 if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) {
126 desc = irq_desc + + i;
127 desc->handle_irq(asic->irq_base + i,
128 desc);
129 }
130 }
131 }
132
133 if (iter >= MAX_ASIC_ISR_LOOPS)
134 printk(KERN_ERR "%s: interrupt processing overrun\n",
135 __FUNCTION__);
136}
137
138static inline int asic3_irq_to_bank(struct asic3 *asic, int irq)
139{
140 int n;
141
142 n = (irq - asic->irq_base) >> 4;
143
144 return (n * (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base));
145}
146
147static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
148{
149 return (irq - asic->irq_base) & 0xf;
150}
151
152static void asic3_mask_gpio_irq(unsigned int irq)
153{
154 struct asic3 *asic = get_irq_chip_data(irq);
155 u32 val, bank, index;
156 unsigned long flags;
157
158 bank = asic3_irq_to_bank(asic, irq);
159 index = asic3_irq_to_index(asic, irq);
160
161 spin_lock_irqsave(&asic->lock, flags);
162 val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask);
163 val |= 1 << index;
164 asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val);
165 spin_unlock_irqrestore(&asic->lock, flags);
166}
167
168static void asic3_mask_irq(unsigned int irq)
169{
170 struct asic3 *asic = get_irq_chip_data(irq);
171 int regval;
172 unsigned long flags;
173
174 spin_lock_irqsave(&asic->lock, flags);
175 regval = asic3_read_register(asic,
176 ASIC3_INTR_Base +
177 ASIC3_INTR_IntMask);
178
179 regval &= ~(ASIC3_INTMASK_MASK0 <<
180 (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
181
182 asic3_write_register(asic,
183 ASIC3_INTR_Base +
184 ASIC3_INTR_IntMask,
185 regval);
186 spin_unlock_irqrestore(&asic->lock, flags);
187}
188
189static void asic3_unmask_gpio_irq(unsigned int irq)
190{
191 struct asic3 *asic = get_irq_chip_data(irq);
192 u32 val, bank, index;
193 unsigned long flags;
194
195 bank = asic3_irq_to_bank(asic, irq);
196 index = asic3_irq_to_index(asic, irq);
197
198 spin_lock_irqsave(&asic->lock, flags);
199 val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask);
200 val &= ~(1 << index);
201 asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val);
202 spin_unlock_irqrestore(&asic->lock, flags);
203}
204
205static void asic3_unmask_irq(unsigned int irq)
206{
207 struct asic3 *asic = get_irq_chip_data(irq);
208 int regval;
209 unsigned long flags;
210
211 spin_lock_irqsave(&asic->lock, flags);
212 regval = asic3_read_register(asic,
213 ASIC3_INTR_Base +
214 ASIC3_INTR_IntMask);
215
216 regval |= (ASIC3_INTMASK_MASK0 <<
217 (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
218
219 asic3_write_register(asic,
220 ASIC3_INTR_Base +
221 ASIC3_INTR_IntMask,
222 regval);
223 spin_unlock_irqrestore(&asic->lock, flags);
224}
225
226static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
227{
228 struct asic3 *asic = get_irq_chip_data(irq);
229 u32 bank, index;
230 u16 trigger, level, edge, bit;
231 unsigned long flags;
232
233 bank = asic3_irq_to_bank(asic, irq);
234 index = asic3_irq_to_index(asic, irq);
235 bit = 1<<index;
236
237 spin_lock_irqsave(&asic->lock, flags);
238 level = asic3_read_register(asic,
239 bank + ASIC3_GPIO_LevelTrigger);
240 edge = asic3_read_register(asic,
241 bank + ASIC3_GPIO_EdgeTrigger);
242 trigger = asic3_read_register(asic,
243 bank + ASIC3_GPIO_TriggerType);
244 asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
245
246 if (type == IRQT_RISING) {
247 trigger |= bit;
248 edge |= bit;
249 } else if (type == IRQT_FALLING) {
250 trigger |= bit;
251 edge &= ~bit;
252 } else if (type == IRQT_BOTHEDGE) {
253 trigger |= bit;
254 if (asic3_gpio_get_value(asic, irq - asic->irq_base))
255 edge &= ~bit;
256 else
257 edge |= bit;
258 asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
259 } else if (type == IRQT_LOW) {
260 trigger &= ~bit;
261 level &= ~bit;
262 } else if (type == IRQT_HIGH) {
263 trigger &= ~bit;
264 level |= bit;
265 } else {
266 /*
267 * if type == IRQT_NOEDGE, we should mask interrupts, but
268 * be careful to not unmask them if mask was also called.
269 * Probably need internal state for mask.
270 */
271 printk(KERN_NOTICE "asic3: irq type not changed.\n");
272 }
273 asic3_write_register(asic, bank + ASIC3_GPIO_LevelTrigger,
274 level);
275 asic3_write_register(asic, bank + ASIC3_GPIO_EdgeTrigger,
276 edge);
277 asic3_write_register(asic, bank + ASIC3_GPIO_TriggerType,
278 trigger);
279 spin_unlock_irqrestore(&asic->lock, flags);
280 return 0;
281}
282
283static struct irq_chip asic3_gpio_irq_chip = {
284 .name = "ASIC3-GPIO",
285 .ack = asic3_mask_gpio_irq,
286 .mask = asic3_mask_gpio_irq,
287 .unmask = asic3_unmask_gpio_irq,
288 .set_type = asic3_gpio_irq_type,
289};
290
291static struct irq_chip asic3_irq_chip = {
292 .name = "ASIC3",
293 .ack = asic3_mask_irq,
294 .mask = asic3_mask_irq,
295 .unmask = asic3_unmask_irq,
296};
297
298static int asic3_irq_probe(struct platform_device *pdev)
299{
300 struct asic3 *asic = platform_get_drvdata(pdev);
301 unsigned long clksel = 0;
302 unsigned int irq, irq_base;
303
304 asic->irq_nr = platform_get_irq(pdev, 0);
305 if (asic->irq_nr < 0)
306 return asic->irq_nr;
307
308 /* turn on clock to IRQ controller */
309 clksel |= CLOCK_SEL_CX;
310 asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL),
311 clksel);
312
313 irq_base = asic->irq_base;
314
315 for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) {
316 if (irq < asic->irq_base + ASIC3_NUM_GPIOS)
317 set_irq_chip(irq, &asic3_gpio_irq_chip);
318 else
319 set_irq_chip(irq, &asic3_irq_chip);
320
321 set_irq_chip_data(irq, asic);
322 set_irq_handler(irq, handle_level_irq);
323 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
324 }
325
326 asic3_write_register(asic, ASIC3_OFFSET(INTR, IntMask),
327 ASIC3_INTMASK_GINTMASK);
328
329 set_irq_chained_handler(asic->irq_nr, asic3_irq_demux);
330 set_irq_type(asic->irq_nr, IRQT_RISING);
331 set_irq_data(asic->irq_nr, asic);
332
333 return 0;
334}
335
336static void asic3_irq_remove(struct platform_device *pdev)
337{
338 struct asic3 *asic = platform_get_drvdata(pdev);
339 unsigned int irq, irq_base;
340
341 irq_base = asic->irq_base;
342
343 for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) {
344 set_irq_flags(irq, 0);
345 set_irq_handler(irq, NULL);
346 set_irq_chip(irq, NULL);
347 set_irq_chip_data(irq, NULL);
348 }
349 set_irq_chained_handler(asic->irq_nr, NULL);
350}
351
352/* GPIOs */
353static inline u32 asic3_get_gpio(struct asic3 *asic, unsigned int base,
354 unsigned int function)
355{
356 return asic3_read_register(asic, base + function);
357}
358
359static void asic3_set_gpio(struct asic3 *asic, unsigned int base,
360 unsigned int function, u32 bits, u32 val)
361{
362 unsigned long flags;
363
364 spin_lock_irqsave(&asic->lock, flags);
365 val |= (asic3_read_register(asic, base + function) & ~bits);
366
367 asic3_write_register(asic, base + function, val);
368 spin_unlock_irqrestore(&asic->lock, flags);
369}
370
371#define asic3_get_gpio_a(asic, fn) \
372 asic3_get_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn)
373#define asic3_get_gpio_b(asic, fn) \
374 asic3_get_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn)
375#define asic3_get_gpio_c(asic, fn) \
376 asic3_get_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn)
377#define asic3_get_gpio_d(asic, fn) \
378 asic3_get_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn)
379
380#define asic3_set_gpio_a(asic, fn, bits, val) \
381 asic3_set_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn, bits, val)
382#define asic3_set_gpio_b(asic, fn, bits, val) \
383 asic3_set_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn, bits, val)
384#define asic3_set_gpio_c(asic, fn, bits, val) \
385 asic3_set_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn, bits, val)
386#define asic3_set_gpio_d(asic, fn, bits, val) \
387 asic3_set_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn, bits, val)
388
389#define asic3_set_gpio_banks(asic, fn, bits, pdata, field) \
390 do { \
391 asic3_set_gpio_a((asic), fn, (bits), (pdata)->gpio_a.field); \
392 asic3_set_gpio_b((asic), fn, (bits), (pdata)->gpio_b.field); \
393 asic3_set_gpio_c((asic), fn, (bits), (pdata)->gpio_c.field); \
394 asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \
395 } while (0)
396
397int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio)
398{
399 u32 mask = ASIC3_GPIO_bit(gpio);
400
401 switch (gpio >> 4) {
402 case ASIC3_GPIO_BANK_A:
403 return asic3_get_gpio_a(asic, Status) & mask;
404 case ASIC3_GPIO_BANK_B:
405 return asic3_get_gpio_b(asic, Status) & mask;
406 case ASIC3_GPIO_BANK_C:
407 return asic3_get_gpio_c(asic, Status) & mask;
408 case ASIC3_GPIO_BANK_D:
409 return asic3_get_gpio_d(asic, Status) & mask;
410 default:
411 printk(KERN_ERR "%s: invalid GPIO value 0x%x",
412 __FUNCTION__, gpio);
413 return -EINVAL;
414 }
415}
416EXPORT_SYMBOL(asic3_gpio_get_value);
417
418void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val)
419{
420 u32 mask = ASIC3_GPIO_bit(gpio);
421 u32 bitval = 0;
422 if (val)
423 bitval = mask;
424
425 switch (gpio >> 4) {
426 case ASIC3_GPIO_BANK_A:
427 asic3_set_gpio_a(asic, Out, mask, bitval);
428 return;
429 case ASIC3_GPIO_BANK_B:
430 asic3_set_gpio_b(asic, Out, mask, bitval);
431 return;
432 case ASIC3_GPIO_BANK_C:
433 asic3_set_gpio_c(asic, Out, mask, bitval);
434 return;
435 case ASIC3_GPIO_BANK_D:
436 asic3_set_gpio_d(asic, Out, mask, bitval);
437 return;
438 default:
439 printk(KERN_ERR "%s: invalid GPIO value 0x%x",
440 __FUNCTION__, gpio);
441 return;
442 }
443}
444EXPORT_SYMBOL(asic3_gpio_set_value);
445
446static int asic3_gpio_probe(struct platform_device *pdev)
447{
448 struct asic3_platform_data *pdata = pdev->dev.platform_data;
449 struct asic3 *asic = platform_get_drvdata(pdev);
450
451 asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, Mask), 0xffff);
452 asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, Mask), 0xffff);
453 asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, Mask), 0xffff);
454 asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, Mask), 0xffff);
455
456 asic3_set_gpio_a(asic, SleepMask, 0xffff, 0xffff);
457 asic3_set_gpio_b(asic, SleepMask, 0xffff, 0xffff);
458 asic3_set_gpio_c(asic, SleepMask, 0xffff, 0xffff);
459 asic3_set_gpio_d(asic, SleepMask, 0xffff, 0xffff);
460
461 if (pdata) {
462 asic3_set_gpio_banks(asic, Out, 0xffff, pdata, init);
463 asic3_set_gpio_banks(asic, Direction, 0xffff, pdata, dir);
464 asic3_set_gpio_banks(asic, SleepMask, 0xffff, pdata,
465 sleep_mask);
466 asic3_set_gpio_banks(asic, SleepOut, 0xffff, pdata, sleep_out);
467 asic3_set_gpio_banks(asic, BattFaultOut, 0xffff, pdata,
468 batt_fault_out);
469 asic3_set_gpio_banks(asic, SleepConf, 0xffff, pdata,
470 sleep_conf);
471 asic3_set_gpio_banks(asic, AltFunction, 0xffff, pdata,
472 alt_function);
473 }
474
475 return 0;
476}
477
478static void asic3_gpio_remove(struct platform_device *pdev)
479{
480 return;
481}
482
483
484/* Core */
485static int asic3_probe(struct platform_device *pdev)
486{
487 struct asic3_platform_data *pdata = pdev->dev.platform_data;
488 struct asic3 *asic;
489 struct resource *mem;
490 unsigned long clksel;
491 int ret;
492
493 asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
494 if (!asic)
495 return -ENOMEM;
496
497 spin_lock_init(&asic->lock);
498 platform_set_drvdata(pdev, asic);
499 asic->dev = &pdev->dev;
500
501 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
502 if (!mem) {
503 ret = -ENOMEM;
504 printk(KERN_ERR "asic3: no MEM resource\n");
505 goto err_out_1;
506 }
507
508 asic->mapping = ioremap(mem->start, PAGE_SIZE);
509 if (!asic->mapping) {
510 ret = -ENOMEM;
511 printk(KERN_ERR "asic3: couldn't ioremap\n");
512 goto err_out_1;
513 }
514
515 asic->irq_base = pdata->irq_base;
516
517 if (pdata && pdata->bus_shift)
518 asic->bus_shift = 2 - pdata->bus_shift;
519 else
520 asic->bus_shift = 0;
521
522 clksel = 0;
523 asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel);
524
525 ret = asic3_irq_probe(pdev);
526 if (ret < 0) {
527 printk(KERN_ERR "asic3: couldn't probe IRQs\n");
528 goto err_out_2;
529 }
530 asic3_gpio_probe(pdev);
531
532 if (pdata->children) {
533 int i;
534 for (i = 0; i < pdata->n_children; i++) {
535 pdata->children[i]->dev.parent = &pdev->dev;
536 platform_device_register(pdata->children[i]);
537 }
538 }
539
540 printk(KERN_INFO "ASIC3 Core driver\n");
541
542 return 0;
543
544 err_out_2:
545 iounmap(asic->mapping);
546 err_out_1:
547 kfree(asic);
548
549 return ret;
550}
551
552static int asic3_remove(struct platform_device *pdev)
553{
554 struct asic3 *asic = platform_get_drvdata(pdev);
555
556 asic3_gpio_remove(pdev);
557 asic3_irq_remove(pdev);
558
559 asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0);
560
561 iounmap(asic->mapping);
562
563 kfree(asic);
564
565 return 0;
566}
567
568static void asic3_shutdown(struct platform_device *pdev)
569{
570}
571
572static struct platform_driver asic3_device_driver = {
573 .driver = {
574 .name = "asic3",
575 },
576 .probe = asic3_probe,
577 .remove = __devexit_p(asic3_remove),
578 .shutdown = asic3_shutdown,
579};
580
581static int __init asic3_init(void)
582{
583 int retval = 0;
584 retval = platform_driver_register(&asic3_device_driver);
585 return retval;
586}
587
588subsys_initcall(asic3_init);