blob: c8b7a28b2669095b57251e66fbd057b00bffebdb [file] [log] [blame]
Uwe Kleine-König8e005932010-09-28 16:37:20 +02001/*
2 * Copyright 2009-2010 Pengutronix
3 * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
4 *
5 * loosely based on an earlier driver that has
6 * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
7 *
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License version 2 as published by the
10 * Free Software Foundation.
11 */
Uwe Kleine-König8e005932010-09-28 16:37:20 +020012
13#include <linux/slab.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/mutex.h>
17#include <linux/interrupt.h>
18#include <linux/spi/spi.h>
19#include <linux/mfd/core.h>
20#include <linux/mfd/mc13xxx.h>
Shawn Guo876989d2011-12-12 18:52:57 +010021#include <linux/of.h>
22#include <linux/of_device.h>
23#include <linux/of_gpio.h>
Uwe Kleine-König8e005932010-09-28 16:37:20 +020024
Marc Reilly5006fe52012-05-01 12:26:46 +020025enum mc13xxx_id {
26 MC13XXX_ID_MC13783,
27 MC13XXX_ID_MC13892,
28 MC13XXX_ID_INVALID,
29};
30
Uwe Kleine-König8e005932010-09-28 16:37:20 +020031struct mc13xxx {
32 struct spi_device *spidev;
Marc Reilly5006fe52012-05-01 12:26:46 +020033
34 struct device *dev;
35 enum mc13xxx_id ictype;
36
Uwe Kleine-König8e005932010-09-28 16:37:20 +020037 struct mutex lock;
38 int irq;
Shawn Guo876989d2011-12-12 18:52:57 +010039 int flags;
Uwe Kleine-König8e005932010-09-28 16:37:20 +020040
41 irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
42 void *irqdata[MC13XXX_NUM_IRQ];
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +020043
44 int adcflags;
Uwe Kleine-König8e005932010-09-28 16:37:20 +020045};
46
Uwe Kleine-König8e005932010-09-28 16:37:20 +020047#define MC13XXX_IRQSTAT0 0
48#define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0)
49#define MC13XXX_IRQSTAT0_ADCBISDONEI (1 << 1)
50#define MC13XXX_IRQSTAT0_TSI (1 << 2)
51#define MC13783_IRQSTAT0_WHIGHI (1 << 3)
52#define MC13783_IRQSTAT0_WLOWI (1 << 4)
53#define MC13XXX_IRQSTAT0_CHGDETI (1 << 6)
54#define MC13783_IRQSTAT0_CHGOVI (1 << 7)
55#define MC13XXX_IRQSTAT0_CHGREVI (1 << 8)
56#define MC13XXX_IRQSTAT0_CHGSHORTI (1 << 9)
57#define MC13XXX_IRQSTAT0_CCCVI (1 << 10)
58#define MC13XXX_IRQSTAT0_CHGCURRI (1 << 11)
59#define MC13XXX_IRQSTAT0_BPONI (1 << 12)
60#define MC13XXX_IRQSTAT0_LOBATLI (1 << 13)
61#define MC13XXX_IRQSTAT0_LOBATHI (1 << 14)
62#define MC13783_IRQSTAT0_UDPI (1 << 15)
63#define MC13783_IRQSTAT0_USBI (1 << 16)
64#define MC13783_IRQSTAT0_IDI (1 << 19)
65#define MC13783_IRQSTAT0_SE1I (1 << 21)
66#define MC13783_IRQSTAT0_CKDETI (1 << 22)
67#define MC13783_IRQSTAT0_UDMI (1 << 23)
68
69#define MC13XXX_IRQMASK0 1
70#define MC13XXX_IRQMASK0_ADCDONEM MC13XXX_IRQSTAT0_ADCDONEI
71#define MC13XXX_IRQMASK0_ADCBISDONEM MC13XXX_IRQSTAT0_ADCBISDONEI
72#define MC13XXX_IRQMASK0_TSM MC13XXX_IRQSTAT0_TSI
73#define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI
74#define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI
75#define MC13XXX_IRQMASK0_CHGDETM MC13XXX_IRQSTAT0_CHGDETI
76#define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI
77#define MC13XXX_IRQMASK0_CHGREVM MC13XXX_IRQSTAT0_CHGREVI
78#define MC13XXX_IRQMASK0_CHGSHORTM MC13XXX_IRQSTAT0_CHGSHORTI
79#define MC13XXX_IRQMASK0_CCCVM MC13XXX_IRQSTAT0_CCCVI
80#define MC13XXX_IRQMASK0_CHGCURRM MC13XXX_IRQSTAT0_CHGCURRI
81#define MC13XXX_IRQMASK0_BPONM MC13XXX_IRQSTAT0_BPONI
82#define MC13XXX_IRQMASK0_LOBATLM MC13XXX_IRQSTAT0_LOBATLI
83#define MC13XXX_IRQMASK0_LOBATHM MC13XXX_IRQSTAT0_LOBATHI
84#define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI
85#define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI
86#define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI
87#define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I
88#define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI
89#define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI
90
91#define MC13XXX_IRQSTAT1 3
92#define MC13XXX_IRQSTAT1_1HZI (1 << 0)
93#define MC13XXX_IRQSTAT1_TODAI (1 << 1)
94#define MC13783_IRQSTAT1_ONOFD1I (1 << 3)
95#define MC13783_IRQSTAT1_ONOFD2I (1 << 4)
96#define MC13783_IRQSTAT1_ONOFD3I (1 << 5)
97#define MC13XXX_IRQSTAT1_SYSRSTI (1 << 6)
98#define MC13XXX_IRQSTAT1_RTCRSTI (1 << 7)
99#define MC13XXX_IRQSTAT1_PCI (1 << 8)
100#define MC13XXX_IRQSTAT1_WARMI (1 << 9)
101#define MC13XXX_IRQSTAT1_MEMHLDI (1 << 10)
102#define MC13783_IRQSTAT1_PWRRDYI (1 << 11)
103#define MC13XXX_IRQSTAT1_THWARNLI (1 << 12)
104#define MC13XXX_IRQSTAT1_THWARNHI (1 << 13)
105#define MC13XXX_IRQSTAT1_CLKI (1 << 14)
106#define MC13783_IRQSTAT1_SEMAFI (1 << 15)
107#define MC13783_IRQSTAT1_MC2BI (1 << 17)
108#define MC13783_IRQSTAT1_HSDETI (1 << 18)
109#define MC13783_IRQSTAT1_HSLI (1 << 19)
110#define MC13783_IRQSTAT1_ALSPTHI (1 << 20)
111#define MC13783_IRQSTAT1_AHSSHORTI (1 << 21)
112
113#define MC13XXX_IRQMASK1 4
114#define MC13XXX_IRQMASK1_1HZM MC13XXX_IRQSTAT1_1HZI
115#define MC13XXX_IRQMASK1_TODAM MC13XXX_IRQSTAT1_TODAI
116#define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I
117#define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I
118#define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I
119#define MC13XXX_IRQMASK1_SYSRSTM MC13XXX_IRQSTAT1_SYSRSTI
120#define MC13XXX_IRQMASK1_RTCRSTM MC13XXX_IRQSTAT1_RTCRSTI
121#define MC13XXX_IRQMASK1_PCM MC13XXX_IRQSTAT1_PCI
122#define MC13XXX_IRQMASK1_WARMM MC13XXX_IRQSTAT1_WARMI
123#define MC13XXX_IRQMASK1_MEMHLDM MC13XXX_IRQSTAT1_MEMHLDI
124#define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI
125#define MC13XXX_IRQMASK1_THWARNLM MC13XXX_IRQSTAT1_THWARNLI
126#define MC13XXX_IRQMASK1_THWARNHM MC13XXX_IRQSTAT1_THWARNHI
127#define MC13XXX_IRQMASK1_CLKM MC13XXX_IRQSTAT1_CLKI
128#define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI
129#define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI
130#define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI
131#define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI
132#define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI
133#define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI
134
135#define MC13XXX_REVISION 7
136#define MC13XXX_REVISION_REVMETAL (0x07 << 0)
137#define MC13XXX_REVISION_REVFULL (0x03 << 3)
138#define MC13XXX_REVISION_ICID (0x07 << 6)
139#define MC13XXX_REVISION_FIN (0x03 << 9)
140#define MC13XXX_REVISION_FAB (0x03 << 11)
141#define MC13XXX_REVISION_ICIDCODE (0x3f << 13)
142
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200143#define MC13XXX_ADC1 44
144#define MC13XXX_ADC1_ADEN (1 << 0)
145#define MC13XXX_ADC1_RAND (1 << 1)
146#define MC13XXX_ADC1_ADSEL (1 << 3)
147#define MC13XXX_ADC1_ASC (1 << 20)
148#define MC13XXX_ADC1_ADTRIGIGN (1 << 21)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200149
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200150#define MC13XXX_ADC2 45
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200151
152#define MC13XXX_NUMREGS 0x3f
153
154void mc13xxx_lock(struct mc13xxx *mc13xxx)
155{
156 if (!mutex_trylock(&mc13xxx->lock)) {
Marc Reilly5006fe52012-05-01 12:26:46 +0200157 dev_dbg(mc13xxx->dev, "wait for %s from %pf\n",
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200158 __func__, __builtin_return_address(0));
159
160 mutex_lock(&mc13xxx->lock);
161 }
Marc Reilly5006fe52012-05-01 12:26:46 +0200162 dev_dbg(mc13xxx->dev, "%s from %pf\n",
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200163 __func__, __builtin_return_address(0));
164}
165EXPORT_SYMBOL(mc13xxx_lock);
166
167void mc13xxx_unlock(struct mc13xxx *mc13xxx)
168{
Marc Reilly5006fe52012-05-01 12:26:46 +0200169 dev_dbg(mc13xxx->dev, "%s from %pf\n",
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200170 __func__, __builtin_return_address(0));
171 mutex_unlock(&mc13xxx->lock);
172}
173EXPORT_SYMBOL(mc13xxx_unlock);
174
175#define MC13XXX_REGOFFSET_SHIFT 25
Marc Reilly5006fe52012-05-01 12:26:46 +0200176static int mc13xxx_spi_reg_read(struct mc13xxx *mc13xxx,
177 unsigned int offset, u32 *val)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200178{
179 struct spi_transfer t;
180 struct spi_message m;
181 int ret;
182
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200183 *val = offset << MC13XXX_REGOFFSET_SHIFT;
184
185 memset(&t, 0, sizeof(t));
186
187 t.tx_buf = val;
188 t.rx_buf = val;
189 t.len = sizeof(u32);
190
191 spi_message_init(&m);
192 spi_message_add_tail(&t, &m);
193
194 ret = spi_sync(mc13xxx->spidev, &m);
195
196 /* error in message.status implies error return from spi_sync */
197 BUG_ON(!ret && m.status);
198
199 if (ret)
200 return ret;
201
202 *val &= 0xffffff;
203
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200204 return 0;
205}
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200206
Marc Reilly5006fe52012-05-01 12:26:46 +0200207static int mc13xxx_spi_reg_write(struct mc13xxx *mc13xxx, unsigned int offset,
208 u32 val)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200209{
210 u32 buf;
211 struct spi_transfer t;
212 struct spi_message m;
213 int ret;
214
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200215 buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val;
216
217 memset(&t, 0, sizeof(t));
218
219 t.tx_buf = &buf;
220 t.rx_buf = &buf;
221 t.len = sizeof(u32);
222
223 spi_message_init(&m);
224 spi_message_add_tail(&t, &m);
225
226 ret = spi_sync(mc13xxx->spidev, &m);
227
228 BUG_ON(!ret && m.status);
229
230 if (ret)
231 return ret;
232
233 return 0;
234}
Marc Reilly5006fe52012-05-01 12:26:46 +0200235
236int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
237{
238 int ret;
239
240 BUG_ON(!mutex_is_locked(&mc13xxx->lock));
241
242 if (offset > MC13XXX_NUMREGS)
243 return -EINVAL;
244
245 ret = mc13xxx_spi_reg_read(mc13xxx, offset, val);
246 dev_vdbg(mc13xxx->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
247
248 return ret;
249}
250EXPORT_SYMBOL(mc13xxx_reg_read);
251
252int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
253{
254 BUG_ON(!mutex_is_locked(&mc13xxx->lock));
255
256 dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val);
257
258 if (offset > MC13XXX_NUMREGS || val > 0xffffff)
259 return -EINVAL;
260
261 return mc13xxx_spi_reg_write(mc13xxx, offset, val);
262}
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200263EXPORT_SYMBOL(mc13xxx_reg_write);
264
265int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
266 u32 mask, u32 val)
267{
268 int ret;
269 u32 valread;
270
271 BUG_ON(val & ~mask);
272
273 ret = mc13xxx_reg_read(mc13xxx, offset, &valread);
274 if (ret)
275 return ret;
276
277 valread = (valread & ~mask) | val;
278
279 return mc13xxx_reg_write(mc13xxx, offset, valread);
280}
281EXPORT_SYMBOL(mc13xxx_reg_rmw);
282
283int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq)
284{
285 int ret;
286 unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
287 u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
288 u32 mask;
289
290 if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
291 return -EINVAL;
292
293 ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
294 if (ret)
295 return ret;
296
297 if (mask & irqbit)
298 /* already masked */
299 return 0;
300
301 return mc13xxx_reg_write(mc13xxx, offmask, mask | irqbit);
302}
303EXPORT_SYMBOL(mc13xxx_irq_mask);
304
305int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq)
306{
307 int ret;
308 unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
309 u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
310 u32 mask;
311
312 if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
313 return -EINVAL;
314
315 ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
316 if (ret)
317 return ret;
318
319 if (!(mask & irqbit))
320 /* already unmasked */
321 return 0;
322
323 return mc13xxx_reg_write(mc13xxx, offmask, mask & ~irqbit);
324}
325EXPORT_SYMBOL(mc13xxx_irq_unmask);
326
327int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq,
328 int *enabled, int *pending)
329{
330 int ret;
331 unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
332 unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1;
333 u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
334
335 if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
336 return -EINVAL;
337
338 if (enabled) {
339 u32 mask;
340
341 ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
342 if (ret)
343 return ret;
344
345 *enabled = mask & irqbit;
346 }
347
348 if (pending) {
349 u32 stat;
350
351 ret = mc13xxx_reg_read(mc13xxx, offstat, &stat);
352 if (ret)
353 return ret;
354
355 *pending = stat & irqbit;
356 }
357
358 return 0;
359}
360EXPORT_SYMBOL(mc13xxx_irq_status);
361
362int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq)
363{
364 unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1;
365 unsigned int val = 1 << (irq < 24 ? irq : irq - 24);
366
367 BUG_ON(irq < 0 || irq >= MC13XXX_NUM_IRQ);
368
369 return mc13xxx_reg_write(mc13xxx, offstat, val);
370}
371EXPORT_SYMBOL(mc13xxx_irq_ack);
372
373int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq,
374 irq_handler_t handler, const char *name, void *dev)
375{
376 BUG_ON(!mutex_is_locked(&mc13xxx->lock));
377 BUG_ON(!handler);
378
379 if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
380 return -EINVAL;
381
382 if (mc13xxx->irqhandler[irq])
383 return -EBUSY;
384
385 mc13xxx->irqhandler[irq] = handler;
386 mc13xxx->irqdata[irq] = dev;
387
388 return 0;
389}
390EXPORT_SYMBOL(mc13xxx_irq_request_nounmask);
391
392int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq,
393 irq_handler_t handler, const char *name, void *dev)
394{
395 int ret;
396
397 ret = mc13xxx_irq_request_nounmask(mc13xxx, irq, handler, name, dev);
398 if (ret)
399 return ret;
400
401 ret = mc13xxx_irq_unmask(mc13xxx, irq);
402 if (ret) {
403 mc13xxx->irqhandler[irq] = NULL;
404 mc13xxx->irqdata[irq] = NULL;
405 return ret;
406 }
407
408 return 0;
409}
410EXPORT_SYMBOL(mc13xxx_irq_request);
411
412int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev)
413{
414 int ret;
415 BUG_ON(!mutex_is_locked(&mc13xxx->lock));
416
417 if (irq < 0 || irq >= MC13XXX_NUM_IRQ || !mc13xxx->irqhandler[irq] ||
418 mc13xxx->irqdata[irq] != dev)
419 return -EINVAL;
420
421 ret = mc13xxx_irq_mask(mc13xxx, irq);
422 if (ret)
423 return ret;
424
425 mc13xxx->irqhandler[irq] = NULL;
426 mc13xxx->irqdata[irq] = NULL;
427
428 return 0;
429}
430EXPORT_SYMBOL(mc13xxx_irq_free);
431
432static inline irqreturn_t mc13xxx_irqhandler(struct mc13xxx *mc13xxx, int irq)
433{
434 return mc13xxx->irqhandler[irq](irq, mc13xxx->irqdata[irq]);
435}
436
437/*
438 * returns: number of handled irqs or negative error
439 * locking: holds mc13xxx->lock
440 */
441static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx,
442 unsigned int offstat, unsigned int offmask, int baseirq)
443{
444 u32 stat, mask;
445 int ret = mc13xxx_reg_read(mc13xxx, offstat, &stat);
446 int num_handled = 0;
447
448 if (ret)
449 return ret;
450
451 ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
452 if (ret)
453 return ret;
454
455 while (stat & ~mask) {
456 int irq = __ffs(stat & ~mask);
457
458 stat &= ~(1 << irq);
459
460 if (likely(mc13xxx->irqhandler[baseirq + irq])) {
461 irqreturn_t handled;
462
463 handled = mc13xxx_irqhandler(mc13xxx, baseirq + irq);
464 if (handled == IRQ_HANDLED)
465 num_handled++;
466 } else {
Marc Reilly5006fe52012-05-01 12:26:46 +0200467 dev_err(mc13xxx->dev,
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200468 "BUG: irq %u but no handler\n",
469 baseirq + irq);
470
471 mask |= 1 << irq;
472
473 ret = mc13xxx_reg_write(mc13xxx, offmask, mask);
474 }
475 }
476
477 return num_handled;
478}
479
480static irqreturn_t mc13xxx_irq_thread(int irq, void *data)
481{
482 struct mc13xxx *mc13xxx = data;
483 irqreturn_t ret;
484 int handled = 0;
485
486 mc13xxx_lock(mc13xxx);
487
488 ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT0,
489 MC13XXX_IRQMASK0, 0);
490 if (ret > 0)
491 handled = 1;
492
493 ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT1,
494 MC13XXX_IRQMASK1, 24);
495 if (ret > 0)
496 handled = 1;
497
498 mc13xxx_unlock(mc13xxx);
499
500 return IRQ_RETVAL(handled);
501}
502
Uwe Kleine-Königbb3149a92011-09-23 21:51:42 +0200503static const char *mc13xxx_chipname[] = {
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200504 [MC13XXX_ID_MC13783] = "mc13783",
505 [MC13XXX_ID_MC13892] = "mc13892",
506};
507
508#define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask))
Marc Reilly5006fe52012-05-01 12:26:46 +0200509static int mc13xxx_identify(struct mc13xxx *mc13xxx)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200510{
511 u32 icid;
512 u32 revision;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200513 int ret;
514
Marc Reilly5006fe52012-05-01 12:26:46 +0200515 /*
516 * Get the generation ID from register 46, as apparently some older
517 * IC revisions only have this info at this location. Newer ICs seem to
518 * have both.
519 */
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200520 ret = mc13xxx_reg_read(mc13xxx, 46, &icid);
521 if (ret)
522 return ret;
523
524 icid = (icid >> 6) & 0x7;
525
526 switch (icid) {
527 case 2:
Marc Reilly5006fe52012-05-01 12:26:46 +0200528 mc13xxx->ictype = MC13XXX_ID_MC13783;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200529 break;
530 case 7:
Marc Reilly5006fe52012-05-01 12:26:46 +0200531 mc13xxx->ictype = MC13XXX_ID_MC13892;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200532 break;
533 default:
Marc Reilly5006fe52012-05-01 12:26:46 +0200534 mc13xxx->ictype = MC13XXX_ID_INVALID;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200535 break;
536 }
537
Marc Reilly5006fe52012-05-01 12:26:46 +0200538 if (mc13xxx->ictype == MC13XXX_ID_MC13783 ||
539 mc13xxx->ictype == MC13XXX_ID_MC13892) {
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200540 ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200541
Marc Reilly5006fe52012-05-01 12:26:46 +0200542 dev_info(mc13xxx->dev, "%s: rev: %d.%d, "
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200543 "fin: %d, fab: %d, icid: %d/%d\n",
Marc Reilly5006fe52012-05-01 12:26:46 +0200544 mc13xxx_chipname[mc13xxx->ictype],
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200545 maskval(revision, MC13XXX_REVISION_REVFULL),
546 maskval(revision, MC13XXX_REVISION_REVMETAL),
547 maskval(revision, MC13XXX_REVISION_FIN),
548 maskval(revision, MC13XXX_REVISION_FAB),
549 maskval(revision, MC13XXX_REVISION_ICID),
550 maskval(revision, MC13XXX_REVISION_ICIDCODE));
551 }
552
Marc Reilly5006fe52012-05-01 12:26:46 +0200553 return (mc13xxx->ictype == MC13XXX_ID_INVALID) ? -ENODEV : 0;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200554}
555
556static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
557{
Marc Reilly5006fe52012-05-01 12:26:46 +0200558 return mc13xxx_chipname[mc13xxx->ictype];
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200559}
560
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200561int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
562{
Shawn Guo876989d2011-12-12 18:52:57 +0100563 return mc13xxx->flags;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200564}
565EXPORT_SYMBOL(mc13xxx_get_flags);
566
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200567#define MC13XXX_ADC1_CHAN0_SHIFT 5
568#define MC13XXX_ADC1_CHAN1_SHIFT 8
Michael Thalmeier1039d762012-02-20 12:18:13 +0100569#define MC13783_ADC1_ATO_SHIFT 11
570#define MC13783_ADC1_ATOX (1 << 19)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200571
572struct mc13xxx_adcdone_data {
573 struct mc13xxx *mc13xxx;
574 struct completion done;
575};
576
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200577static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200578{
579 struct mc13xxx_adcdone_data *adcdone_data = data;
580
581 mc13xxx_irq_ack(adcdone_data->mc13xxx, irq);
582
583 complete_all(&adcdone_data->done);
584
585 return IRQ_HANDLED;
586}
587
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200588#define MC13XXX_ADC_WORKING (1 << 0)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200589
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200590int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
Michael Thalmeier1039d762012-02-20 12:18:13 +0100591 unsigned int channel, u8 ato, bool atox,
592 unsigned int *sample)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200593{
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200594 u32 adc0, adc1, old_adc0;
595 int i, ret;
596 struct mc13xxx_adcdone_data adcdone_data = {
597 .mc13xxx = mc13xxx,
598 };
599 init_completion(&adcdone_data.done);
600
Marc Reilly5006fe52012-05-01 12:26:46 +0200601 dev_dbg(mc13xxx->dev, "%s\n", __func__);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200602
603 mc13xxx_lock(mc13xxx);
604
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200605 if (mc13xxx->adcflags & MC13XXX_ADC_WORKING) {
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200606 ret = -EBUSY;
607 goto out;
608 }
609
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200610 mc13xxx->adcflags |= MC13XXX_ADC_WORKING;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200611
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200612 mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200613
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200614 adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2;
615 adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200616
617 if (channel > 7)
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200618 adc1 |= MC13XXX_ADC1_ADSEL;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200619
620 switch (mode) {
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200621 case MC13XXX_ADC_MODE_TS:
622 adc0 |= MC13XXX_ADC0_ADREFEN | MC13XXX_ADC0_TSMOD0 |
623 MC13XXX_ADC0_TSMOD1;
624 adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200625 break;
626
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200627 case MC13XXX_ADC_MODE_SINGLE_CHAN:
Robin van der Gracht21618912011-11-29 12:09:03 +0100628 adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200629 adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
630 adc1 |= MC13XXX_ADC1_RAND;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200631 break;
632
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200633 case MC13XXX_ADC_MODE_MULT_CHAN:
Robin van der Gracht21618912011-11-29 12:09:03 +0100634 adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200635 adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200636 break;
637
638 default:
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200639 mc13xxx_unlock(mc13xxx);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200640 return -EINVAL;
641 }
642
Michael Thalmeier1039d762012-02-20 12:18:13 +0100643 adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
644 if (atox)
645 adc1 |= MC13783_ADC1_ATOX;
Marc Reilly5006fe52012-05-01 12:26:46 +0200646
647 dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__);
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200648 mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
649 mc13xxx_handler_adcdone, __func__, &adcdone_data);
650 mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_ADCDONE);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200651
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200652 mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0);
653 mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200654
655 mc13xxx_unlock(mc13xxx);
656
657 ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ);
658
659 if (!ret)
660 ret = -ETIMEDOUT;
661
662 mc13xxx_lock(mc13xxx);
663
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200664 mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_ADCDONE, &adcdone_data);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200665
666 if (ret > 0)
667 for (i = 0; i < 4; ++i) {
668 ret = mc13xxx_reg_read(mc13xxx,
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200669 MC13XXX_ADC2, &sample[i]);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200670 if (ret)
671 break;
672 }
673
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200674 if (mode == MC13XXX_ADC_MODE_TS)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200675 /* restore TSMOD */
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200676 mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, old_adc0);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200677
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200678 mc13xxx->adcflags &= ~MC13XXX_ADC_WORKING;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200679out:
680 mc13xxx_unlock(mc13xxx);
681
682 return ret;
683}
Uwe Kleine-Königfec316d2011-08-24 15:28:21 +0200684EXPORT_SYMBOL_GPL(mc13xxx_adc_do_conversion);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200685
686static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
Samuel Ortizc8a03c962011-04-08 01:55:01 +0200687 const char *format, void *pdata, size_t pdata_size)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200688{
689 char buf[30];
690 const char *name = mc13xxx_get_chipname(mc13xxx);
691
692 struct mfd_cell cell = {
Samuel Ortizc8a03c962011-04-08 01:55:01 +0200693 .platform_data = pdata,
694 .pdata_size = pdata_size,
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200695 };
696
697 /* there is no asnprintf in the kernel :-( */
698 if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf))
699 return -E2BIG;
700
701 cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL);
702 if (!cell.name)
703 return -ENOMEM;
704
Marc Reilly5006fe52012-05-01 12:26:46 +0200705 return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200706}
707
708static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
709{
Samuel Ortizc8a03c962011-04-08 01:55:01 +0200710 return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200711}
712
Shawn Guo876989d2011-12-12 18:52:57 +0100713#ifdef CONFIG_OF
714static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
715{
Marc Reilly5006fe52012-05-01 12:26:46 +0200716 struct device_node *np = mc13xxx->dev.of_node;
Shawn Guo876989d2011-12-12 18:52:57 +0100717
718 if (!np)
719 return -ENODEV;
720
721 if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL))
722 mc13xxx->flags |= MC13XXX_USE_ADC;
723
724 if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL))
725 mc13xxx->flags |= MC13XXX_USE_CODEC;
726
727 if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL))
728 mc13xxx->flags |= MC13XXX_USE_RTC;
729
730 if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL))
731 mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
732
733 return 0;
734}
735#else
736static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
737{
738 return -ENODEV;
739}
740#endif
741
742static const struct spi_device_id mc13xxx_device_id[] = {
743 {
744 .name = "mc13783",
745 .driver_data = MC13XXX_ID_MC13783,
746 }, {
747 .name = "mc13892",
748 .driver_data = MC13XXX_ID_MC13892,
749 }, {
750 /* sentinel */
751 }
752};
753MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
754
755static const struct of_device_id mc13xxx_dt_ids[] = {
756 { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
757 { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
758 { /* sentinel */ }
759};
760MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
761
Marc Reilly5006fe52012-05-01 12:26:46 +0200762static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
763 struct mc13xxx_platform_data *pdata, int irq);
764
765static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx);
766
767static int mc13xxx_spi_probe(struct spi_device *spi)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200768{
Shawn Guo876989d2011-12-12 18:52:57 +0100769 const struct of_device_id *of_id;
770 struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200771 struct mc13xxx *mc13xxx;
772 struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200773 int ret;
774
Shawn Guo876989d2011-12-12 18:52:57 +0100775 of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
776 if (of_id)
777 sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
Philippe Rétornaz30fc7ac2011-09-18 18:10:53 +0200778
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200779 mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
780 if (!mc13xxx)
781 return -ENOMEM;
782
783 dev_set_drvdata(&spi->dev, mc13xxx);
784 spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
785 spi->bits_per_word = 32;
786 spi_setup(spi);
787
Marc Reilly5006fe52012-05-01 12:26:46 +0200788 mc13xxx->dev = &spi->dev;
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200789 mc13xxx->spidev = spi;
790
Marc Reilly5006fe52012-05-01 12:26:46 +0200791 ret = mc13xxx_common_init(mc13xxx, pdata, spi->irq);
792
793 if (ret) {
794 dev_set_drvdata(&spi->dev, NULL);
795 } else {
796 const struct spi_device_id *devid =
797 spi_get_device_id(mc13xxx->spidev);
798 if (!devid || devid->driver_data != mc13xxx->ictype)
799 dev_warn(mc13xxx->dev,
800 "device id doesn't match auto detection!\n");
801 }
802
803 return ret;
804}
805
806static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
807 struct mc13xxx_platform_data *pdata, int irq)
808{
809 int ret;
810
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200811 mutex_init(&mc13xxx->lock);
812 mc13xxx_lock(mc13xxx);
813
Marc Reilly5006fe52012-05-01 12:26:46 +0200814 ret = mc13xxx_identify(mc13xxx);
815 if (ret)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200816 goto err_revision;
817
818 /* mask all irqs */
819 ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
820 if (ret)
821 goto err_mask;
822
823 ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
824 if (ret)
825 goto err_mask;
826
Marc Reilly5006fe52012-05-01 12:26:46 +0200827 ret = request_threaded_irq(irq, NULL, mc13xxx_irq_thread,
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200828 IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
829
830 if (ret) {
831err_mask:
832err_revision:
Uwe Kleine-Könige1b88eb2010-11-11 16:47:50 +0100833 mc13xxx_unlock(mc13xxx);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200834 kfree(mc13xxx);
835 return ret;
836 }
837
Marc Reilly5006fe52012-05-01 12:26:46 +0200838 mc13xxx->irq = irq;
839
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200840 mc13xxx_unlock(mc13xxx);
841
Shawn Guo876989d2011-12-12 18:52:57 +0100842 if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
843 mc13xxx->flags = pdata->flags;
844
845 if (mc13xxx->flags & MC13XXX_USE_ADC)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200846 mc13xxx_add_subdevice(mc13xxx, "%s-adc");
847
Shawn Guo876989d2011-12-12 18:52:57 +0100848 if (mc13xxx->flags & MC13XXX_USE_CODEC)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200849 mc13xxx_add_subdevice(mc13xxx, "%s-codec");
850
Shawn Guo876989d2011-12-12 18:52:57 +0100851 if (mc13xxx->flags & MC13XXX_USE_RTC)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200852 mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
853
Shawn Guo876989d2011-12-12 18:52:57 +0100854 if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
Michael Thalmeier1039d762012-02-20 12:18:13 +0100855 mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
856 &pdata->touch, sizeof(pdata->touch));
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200857
Shawn Guo876989d2011-12-12 18:52:57 +0100858 if (pdata) {
859 mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
860 &pdata->regulators, sizeof(pdata->regulators));
Samuel Ortizc8a03c962011-04-08 01:55:01 +0200861 mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
862 pdata->leds, sizeof(*pdata->leds));
Philippe Rétornaz30fc7ac2011-09-18 18:10:53 +0200863 mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
864 pdata->buttons, sizeof(*pdata->buttons));
Shawn Guo876989d2011-12-12 18:52:57 +0100865 } else {
866 mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
867 mc13xxx_add_subdevice(mc13xxx, "%s-led");
868 mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
869 }
Philippe Rétornaz30fc7ac2011-09-18 18:10:53 +0200870
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200871 return 0;
872}
873
Marc Reilly5006fe52012-05-01 12:26:46 +0200874static int __devexit mc13xxx_spi_remove(struct spi_device *spi)
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200875{
876 struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev);
877
Marc Reilly5006fe52012-05-01 12:26:46 +0200878 mc13xxx_common_cleanup(mc13xxx);
Axel Lincef92fe2010-10-22 12:29:21 +0200879
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200880 return 0;
881}
882
Marc Reilly5006fe52012-05-01 12:26:46 +0200883static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx)
884{
885 free_irq(mc13xxx->irq, mc13xxx);
886
887 mfd_remove_devices(mc13xxx->dev);
888
889 kfree(mc13xxx);
890}
891
892static struct spi_driver mc13xxx_spi_driver = {
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200893 .id_table = mc13xxx_device_id,
894 .driver = {
895 .name = "mc13xxx",
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200896 .owner = THIS_MODULE,
Shawn Guo876989d2011-12-12 18:52:57 +0100897 .of_match_table = mc13xxx_dt_ids,
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200898 },
Marc Reilly5006fe52012-05-01 12:26:46 +0200899 .probe = mc13xxx_spi_probe,
900 .remove = __devexit_p(mc13xxx_spi_remove),
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200901};
902
903static int __init mc13xxx_init(void)
904{
Marc Reilly5006fe52012-05-01 12:26:46 +0200905 return spi_register_driver(&mc13xxx_spi_driver);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200906}
907subsys_initcall(mc13xxx_init);
908
909static void __exit mc13xxx_exit(void)
910{
Marc Reilly5006fe52012-05-01 12:26:46 +0200911 spi_unregister_driver(&mc13xxx_spi_driver);
Uwe Kleine-König8e005932010-09-28 16:37:20 +0200912}
913module_exit(mc13xxx_exit);
914
915MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC");
916MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
917MODULE_LICENSE("GPL v2");