diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/mfd/mc13xxx-core.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/mfd/mc13xxx-core.c')
-rw-r--r-- | drivers/mfd/mc13xxx-core.c | 455 |
1 files changed, 281 insertions, 174 deletions
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 2a9b100c482..7e4d44bf92a 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c | |||
@@ -15,13 +15,30 @@ | |||
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/spi/spi.h> | ||
18 | #include <linux/mfd/core.h> | 19 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/mc13xxx.h> | 20 | #include <linux/mfd/mc13xxx.h> |
20 | #include <linux/of.h> | ||
21 | #include <linux/of_device.h> | ||
22 | #include <linux/of_gpio.h> | ||
23 | 21 | ||
24 | #include "mc13xxx.h" | 22 | struct mc13xxx { |
23 | struct spi_device *spidev; | ||
24 | struct mutex lock; | ||
25 | int irq; | ||
26 | |||
27 | irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; | ||
28 | void *irqdata[MC13XXX_NUM_IRQ]; | ||
29 | }; | ||
30 | |||
31 | struct mc13783 { | ||
32 | struct mc13xxx mc13xxx; | ||
33 | |||
34 | int adcflags; | ||
35 | }; | ||
36 | |||
37 | struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783) | ||
38 | { | ||
39 | return &mc13783->mc13xxx; | ||
40 | } | ||
41 | EXPORT_SYMBOL(mc13783_to_mc13xxx); | ||
25 | 42 | ||
26 | #define MC13XXX_IRQSTAT0 0 | 43 | #define MC13XXX_IRQSTAT0 0 |
27 | #define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0) | 44 | #define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0) |
@@ -119,43 +136,43 @@ | |||
119 | #define MC13XXX_REVISION_FAB (0x03 << 11) | 136 | #define MC13XXX_REVISION_FAB (0x03 << 11) |
120 | #define MC13XXX_REVISION_ICIDCODE (0x3f << 13) | 137 | #define MC13XXX_REVISION_ICIDCODE (0x3f << 13) |
121 | 138 | ||
122 | #define MC34708_REVISION_REVMETAL (0x07 << 0) | 139 | #define MC13783_ADC1 44 |
123 | #define MC34708_REVISION_REVFULL (0x07 << 3) | 140 | #define MC13783_ADC1_ADEN (1 << 0) |
124 | #define MC34708_REVISION_FIN (0x07 << 6) | 141 | #define MC13783_ADC1_RAND (1 << 1) |
125 | #define MC34708_REVISION_FAB (0x07 << 9) | 142 | #define MC13783_ADC1_ADSEL (1 << 3) |
143 | #define MC13783_ADC1_ASC (1 << 20) | ||
144 | #define MC13783_ADC1_ADTRIGIGN (1 << 21) | ||
126 | 145 | ||
127 | #define MC13XXX_ADC1 44 | 146 | #define MC13783_ADC2 45 |
128 | #define MC13XXX_ADC1_ADEN (1 << 0) | ||
129 | #define MC13XXX_ADC1_RAND (1 << 1) | ||
130 | #define MC13XXX_ADC1_ADSEL (1 << 3) | ||
131 | #define MC13XXX_ADC1_ASC (1 << 20) | ||
132 | #define MC13XXX_ADC1_ADTRIGIGN (1 << 21) | ||
133 | 147 | ||
134 | #define MC13XXX_ADC2 45 | 148 | #define MC13XXX_NUMREGS 0x3f |
135 | 149 | ||
136 | void mc13xxx_lock(struct mc13xxx *mc13xxx) | 150 | void mc13xxx_lock(struct mc13xxx *mc13xxx) |
137 | { | 151 | { |
138 | if (!mutex_trylock(&mc13xxx->lock)) { | 152 | if (!mutex_trylock(&mc13xxx->lock)) { |
139 | dev_dbg(mc13xxx->dev, "wait for %s from %pf\n", | 153 | dev_dbg(&mc13xxx->spidev->dev, "wait for %s from %pf\n", |
140 | __func__, __builtin_return_address(0)); | 154 | __func__, __builtin_return_address(0)); |
141 | 155 | ||
142 | mutex_lock(&mc13xxx->lock); | 156 | mutex_lock(&mc13xxx->lock); |
143 | } | 157 | } |
144 | dev_dbg(mc13xxx->dev, "%s from %pf\n", | 158 | dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", |
145 | __func__, __builtin_return_address(0)); | 159 | __func__, __builtin_return_address(0)); |
146 | } | 160 | } |
147 | EXPORT_SYMBOL(mc13xxx_lock); | 161 | EXPORT_SYMBOL(mc13xxx_lock); |
148 | 162 | ||
149 | void mc13xxx_unlock(struct mc13xxx *mc13xxx) | 163 | void mc13xxx_unlock(struct mc13xxx *mc13xxx) |
150 | { | 164 | { |
151 | dev_dbg(mc13xxx->dev, "%s from %pf\n", | 165 | dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", |
152 | __func__, __builtin_return_address(0)); | 166 | __func__, __builtin_return_address(0)); |
153 | mutex_unlock(&mc13xxx->lock); | 167 | mutex_unlock(&mc13xxx->lock); |
154 | } | 168 | } |
155 | EXPORT_SYMBOL(mc13xxx_unlock); | 169 | EXPORT_SYMBOL(mc13xxx_unlock); |
156 | 170 | ||
171 | #define MC13XXX_REGOFFSET_SHIFT 25 | ||
157 | int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) | 172 | int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) |
158 | { | 173 | { |
174 | struct spi_transfer t; | ||
175 | struct spi_message m; | ||
159 | int ret; | 176 | int ret; |
160 | 177 | ||
161 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | 178 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); |
@@ -163,35 +180,84 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) | |||
163 | if (offset > MC13XXX_NUMREGS) | 180 | if (offset > MC13XXX_NUMREGS) |
164 | return -EINVAL; | 181 | return -EINVAL; |
165 | 182 | ||
166 | ret = regmap_read(mc13xxx->regmap, offset, val); | 183 | *val = offset << MC13XXX_REGOFFSET_SHIFT; |
167 | dev_vdbg(mc13xxx->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | ||
168 | 184 | ||
169 | return ret; | 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 | |||
204 | dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | ||
205 | |||
206 | return 0; | ||
170 | } | 207 | } |
171 | EXPORT_SYMBOL(mc13xxx_reg_read); | 208 | EXPORT_SYMBOL(mc13xxx_reg_read); |
172 | 209 | ||
173 | int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) | 210 | int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) |
174 | { | 211 | { |
212 | u32 buf; | ||
213 | struct spi_transfer t; | ||
214 | struct spi_message m; | ||
215 | int ret; | ||
216 | |||
175 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | 217 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); |
176 | 218 | ||
177 | dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val); | 219 | dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); |
178 | 220 | ||
179 | if (offset > MC13XXX_NUMREGS || val > 0xffffff) | 221 | if (offset > MC13XXX_NUMREGS || val > 0xffffff) |
180 | return -EINVAL; | 222 | return -EINVAL; |
181 | 223 | ||
182 | return regmap_write(mc13xxx->regmap, offset, val); | 224 | buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val; |
225 | |||
226 | memset(&t, 0, sizeof(t)); | ||
227 | |||
228 | t.tx_buf = &buf; | ||
229 | t.rx_buf = &buf; | ||
230 | t.len = sizeof(u32); | ||
231 | |||
232 | spi_message_init(&m); | ||
233 | spi_message_add_tail(&t, &m); | ||
234 | |||
235 | ret = spi_sync(mc13xxx->spidev, &m); | ||
236 | |||
237 | BUG_ON(!ret && m.status); | ||
238 | |||
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | return 0; | ||
183 | } | 243 | } |
184 | EXPORT_SYMBOL(mc13xxx_reg_write); | 244 | EXPORT_SYMBOL(mc13xxx_reg_write); |
185 | 245 | ||
186 | int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, | 246 | int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, |
187 | u32 mask, u32 val) | 247 | u32 mask, u32 val) |
188 | { | 248 | { |
189 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | 249 | int ret; |
250 | u32 valread; | ||
251 | |||
190 | BUG_ON(val & ~mask); | 252 | BUG_ON(val & ~mask); |
191 | dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n", | ||
192 | offset, val, mask); | ||
193 | 253 | ||
194 | return regmap_update_bits(mc13xxx->regmap, offset, mask, val); | 254 | ret = mc13xxx_reg_read(mc13xxx, offset, &valread); |
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | valread = (valread & ~mask) | val; | ||
259 | |||
260 | return mc13xxx_reg_write(mc13xxx, offset, valread); | ||
195 | } | 261 | } |
196 | EXPORT_SYMBOL(mc13xxx_reg_rmw); | 262 | EXPORT_SYMBOL(mc13xxx_reg_rmw); |
197 | 263 | ||
@@ -379,7 +445,7 @@ static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx, | |||
379 | if (handled == IRQ_HANDLED) | 445 | if (handled == IRQ_HANDLED) |
380 | num_handled++; | 446 | num_handled++; |
381 | } else { | 447 | } else { |
382 | dev_err(mc13xxx->dev, | 448 | dev_err(&mc13xxx->spidev->dev, |
383 | "BUG: irq %u but no handler\n", | 449 | "BUG: irq %u but no handler\n", |
384 | baseirq + irq); | 450 | baseirq + irq); |
385 | 451 | ||
@@ -415,71 +481,103 @@ static irqreturn_t mc13xxx_irq_thread(int irq, void *data) | |||
415 | return IRQ_RETVAL(handled); | 481 | return IRQ_RETVAL(handled); |
416 | } | 482 | } |
417 | 483 | ||
484 | enum mc13xxx_id { | ||
485 | MC13XXX_ID_MC13783, | ||
486 | MC13XXX_ID_MC13892, | ||
487 | MC13XXX_ID_INVALID, | ||
488 | }; | ||
489 | |||
490 | const char *mc13xxx_chipname[] = { | ||
491 | [MC13XXX_ID_MC13783] = "mc13783", | ||
492 | [MC13XXX_ID_MC13892] = "mc13892", | ||
493 | }; | ||
494 | |||
418 | #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) | 495 | #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) |
419 | static void mc13xxx_print_revision(struct mc13xxx *mc13xxx, u32 revision) | 496 | static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id) |
420 | { | 497 | { |
421 | dev_info(mc13xxx->dev, "%s: rev: %d.%d, " | 498 | u32 icid; |
422 | "fin: %d, fab: %d, icid: %d/%d\n", | 499 | u32 revision; |
423 | mc13xxx->variant->name, | 500 | const char *name; |
424 | maskval(revision, MC13XXX_REVISION_REVFULL), | 501 | int ret; |
425 | maskval(revision, MC13XXX_REVISION_REVMETAL), | ||
426 | maskval(revision, MC13XXX_REVISION_FIN), | ||
427 | maskval(revision, MC13XXX_REVISION_FAB), | ||
428 | maskval(revision, MC13XXX_REVISION_ICID), | ||
429 | maskval(revision, MC13XXX_REVISION_ICIDCODE)); | ||
430 | } | ||
431 | 502 | ||
432 | static void mc34708_print_revision(struct mc13xxx *mc13xxx, u32 revision) | 503 | ret = mc13xxx_reg_read(mc13xxx, 46, &icid); |
433 | { | 504 | if (ret) |
434 | dev_info(mc13xxx->dev, "%s: rev %d.%d, fin: %d, fab: %d\n", | 505 | return ret; |
435 | mc13xxx->variant->name, | ||
436 | maskval(revision, MC34708_REVISION_REVFULL), | ||
437 | maskval(revision, MC34708_REVISION_REVMETAL), | ||
438 | maskval(revision, MC34708_REVISION_FIN), | ||
439 | maskval(revision, MC34708_REVISION_FAB)); | ||
440 | } | ||
441 | 506 | ||
442 | /* These are only exported for mc13xxx-i2c and mc13xxx-spi */ | 507 | icid = (icid >> 6) & 0x7; |
443 | struct mc13xxx_variant mc13xxx_variant_mc13783 = { | ||
444 | .name = "mc13783", | ||
445 | .print_revision = mc13xxx_print_revision, | ||
446 | }; | ||
447 | EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13783); | ||
448 | 508 | ||
449 | struct mc13xxx_variant mc13xxx_variant_mc13892 = { | 509 | switch (icid) { |
450 | .name = "mc13892", | 510 | case 2: |
451 | .print_revision = mc13xxx_print_revision, | 511 | *id = MC13XXX_ID_MC13783; |
452 | }; | 512 | name = "mc13783"; |
453 | EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13892); | 513 | break; |
514 | case 7: | ||
515 | *id = MC13XXX_ID_MC13892; | ||
516 | name = "mc13892"; | ||
517 | break; | ||
518 | default: | ||
519 | *id = MC13XXX_ID_INVALID; | ||
520 | break; | ||
521 | } | ||
454 | 522 | ||
455 | struct mc13xxx_variant mc13xxx_variant_mc34708 = { | 523 | if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) { |
456 | .name = "mc34708", | 524 | ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); |
457 | .print_revision = mc34708_print_revision, | 525 | if (ret) |
458 | }; | 526 | return ret; |
459 | EXPORT_SYMBOL_GPL(mc13xxx_variant_mc34708); | 527 | |
528 | dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, " | ||
529 | "fin: %d, fab: %d, icid: %d/%d\n", | ||
530 | mc13xxx_chipname[*id], | ||
531 | maskval(revision, MC13XXX_REVISION_REVFULL), | ||
532 | maskval(revision, MC13XXX_REVISION_REVMETAL), | ||
533 | maskval(revision, MC13XXX_REVISION_FIN), | ||
534 | maskval(revision, MC13XXX_REVISION_FAB), | ||
535 | maskval(revision, MC13XXX_REVISION_ICID), | ||
536 | maskval(revision, MC13XXX_REVISION_ICIDCODE)); | ||
537 | } | ||
538 | |||
539 | if (*id != MC13XXX_ID_INVALID) { | ||
540 | const struct spi_device_id *devid = | ||
541 | spi_get_device_id(mc13xxx->spidev); | ||
542 | if (!devid || devid->driver_data != *id) | ||
543 | dev_warn(&mc13xxx->spidev->dev, "device id doesn't " | ||
544 | "match auto detection!\n"); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
460 | 549 | ||
461 | static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) | 550 | static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) |
462 | { | 551 | { |
463 | return mc13xxx->variant->name; | 552 | const struct spi_device_id *devid = |
553 | spi_get_device_id(mc13xxx->spidev); | ||
554 | |||
555 | if (!devid) | ||
556 | return NULL; | ||
557 | |||
558 | return mc13xxx_chipname[devid->driver_data]; | ||
464 | } | 559 | } |
465 | 560 | ||
561 | #include <linux/mfd/mc13783.h> | ||
562 | |||
466 | int mc13xxx_get_flags(struct mc13xxx *mc13xxx) | 563 | int mc13xxx_get_flags(struct mc13xxx *mc13xxx) |
467 | { | 564 | { |
468 | return mc13xxx->flags; | 565 | struct mc13xxx_platform_data *pdata = |
566 | dev_get_platdata(&mc13xxx->spidev->dev); | ||
567 | |||
568 | return pdata->flags; | ||
469 | } | 569 | } |
470 | EXPORT_SYMBOL(mc13xxx_get_flags); | 570 | EXPORT_SYMBOL(mc13xxx_get_flags); |
471 | 571 | ||
472 | #define MC13XXX_ADC1_CHAN0_SHIFT 5 | 572 | #define MC13783_ADC1_CHAN0_SHIFT 5 |
473 | #define MC13XXX_ADC1_CHAN1_SHIFT 8 | 573 | #define MC13783_ADC1_CHAN1_SHIFT 8 |
474 | #define MC13783_ADC1_ATO_SHIFT 11 | ||
475 | #define MC13783_ADC1_ATOX (1 << 19) | ||
476 | 574 | ||
477 | struct mc13xxx_adcdone_data { | 575 | struct mc13xxx_adcdone_data { |
478 | struct mc13xxx *mc13xxx; | 576 | struct mc13xxx *mc13xxx; |
479 | struct completion done; | 577 | struct completion done; |
480 | }; | 578 | }; |
481 | 579 | ||
482 | static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data) | 580 | static irqreturn_t mc13783_handler_adcdone(int irq, void *data) |
483 | { | 581 | { |
484 | struct mc13xxx_adcdone_data *adcdone_data = data; | 582 | struct mc13xxx_adcdone_data *adcdone_data = data; |
485 | 583 | ||
@@ -490,12 +588,12 @@ static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data) | |||
490 | return IRQ_HANDLED; | 588 | return IRQ_HANDLED; |
491 | } | 589 | } |
492 | 590 | ||
493 | #define MC13XXX_ADC_WORKING (1 << 0) | 591 | #define MC13783_ADC_WORKING (1 << 0) |
494 | 592 | ||
495 | int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, | 593 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, |
496 | unsigned int channel, u8 ato, bool atox, | 594 | unsigned int channel, unsigned int *sample) |
497 | unsigned int *sample) | ||
498 | { | 595 | { |
596 | struct mc13xxx *mc13xxx = &mc13783->mc13xxx; | ||
499 | u32 adc0, adc1, old_adc0; | 597 | u32 adc0, adc1, old_adc0; |
500 | int i, ret; | 598 | int i, ret; |
501 | struct mc13xxx_adcdone_data adcdone_data = { | 599 | struct mc13xxx_adcdone_data adcdone_data = { |
@@ -503,59 +601,55 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, | |||
503 | }; | 601 | }; |
504 | init_completion(&adcdone_data.done); | 602 | init_completion(&adcdone_data.done); |
505 | 603 | ||
506 | dev_dbg(mc13xxx->dev, "%s\n", __func__); | 604 | dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__); |
507 | 605 | ||
508 | mc13xxx_lock(mc13xxx); | 606 | mc13xxx_lock(mc13xxx); |
509 | 607 | ||
510 | if (mc13xxx->adcflags & MC13XXX_ADC_WORKING) { | 608 | if (mc13783->adcflags & MC13783_ADC_WORKING) { |
511 | ret = -EBUSY; | 609 | ret = -EBUSY; |
512 | goto out; | 610 | goto out; |
513 | } | 611 | } |
514 | 612 | ||
515 | mc13xxx->adcflags |= MC13XXX_ADC_WORKING; | 613 | mc13783->adcflags |= MC13783_ADC_WORKING; |
516 | 614 | ||
517 | mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0); | 615 | mc13xxx_reg_read(mc13xxx, MC13783_ADC0, &old_adc0); |
518 | 616 | ||
519 | adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2; | 617 | adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; |
520 | adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC; | 618 | adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; |
521 | 619 | ||
522 | if (channel > 7) | 620 | if (channel > 7) |
523 | adc1 |= MC13XXX_ADC1_ADSEL; | 621 | adc1 |= MC13783_ADC1_ADSEL; |
524 | 622 | ||
525 | switch (mode) { | 623 | switch (mode) { |
526 | case MC13XXX_ADC_MODE_TS: | 624 | case MC13783_ADC_MODE_TS: |
527 | adc0 |= MC13XXX_ADC0_ADREFEN | MC13XXX_ADC0_TSMOD0 | | 625 | adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | |
528 | MC13XXX_ADC0_TSMOD1; | 626 | MC13783_ADC0_TSMOD1; |
529 | adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT; | 627 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; |
530 | break; | 628 | break; |
531 | 629 | ||
532 | case MC13XXX_ADC_MODE_SINGLE_CHAN: | 630 | case MC13783_ADC_MODE_SINGLE_CHAN: |
533 | adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK; | 631 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; |
534 | adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT; | 632 | adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; |
535 | adc1 |= MC13XXX_ADC1_RAND; | 633 | adc1 |= MC13783_ADC1_RAND; |
536 | break; | 634 | break; |
537 | 635 | ||
538 | case MC13XXX_ADC_MODE_MULT_CHAN: | 636 | case MC13783_ADC_MODE_MULT_CHAN: |
539 | adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK; | 637 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; |
540 | adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT; | 638 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; |
541 | break; | 639 | break; |
542 | 640 | ||
543 | default: | 641 | default: |
544 | mc13xxx_unlock(mc13xxx); | 642 | mc13783_unlock(mc13783); |
545 | return -EINVAL; | 643 | return -EINVAL; |
546 | } | 644 | } |
547 | 645 | ||
548 | adc1 |= ato << MC13783_ADC1_ATO_SHIFT; | 646 | dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__); |
549 | if (atox) | 647 | mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE, |
550 | adc1 |= MC13783_ADC1_ATOX; | 648 | mc13783_handler_adcdone, __func__, &adcdone_data); |
551 | 649 | mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE); | |
552 | dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__); | ||
553 | mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, | ||
554 | mc13xxx_handler_adcdone, __func__, &adcdone_data); | ||
555 | mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_ADCDONE); | ||
556 | 650 | ||
557 | mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0); | 651 | mc13xxx_reg_write(mc13xxx, MC13783_ADC0, adc0); |
558 | mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1); | 652 | mc13xxx_reg_write(mc13xxx, MC13783_ADC1, adc1); |
559 | 653 | ||
560 | mc13xxx_unlock(mc13xxx); | 654 | mc13xxx_unlock(mc13xxx); |
561 | 655 | ||
@@ -566,27 +660,27 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, | |||
566 | 660 | ||
567 | mc13xxx_lock(mc13xxx); | 661 | mc13xxx_lock(mc13xxx); |
568 | 662 | ||
569 | mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_ADCDONE, &adcdone_data); | 663 | mc13xxx_irq_free(mc13xxx, MC13783_IRQ_ADCDONE, &adcdone_data); |
570 | 664 | ||
571 | if (ret > 0) | 665 | if (ret > 0) |
572 | for (i = 0; i < 4; ++i) { | 666 | for (i = 0; i < 4; ++i) { |
573 | ret = mc13xxx_reg_read(mc13xxx, | 667 | ret = mc13xxx_reg_read(mc13xxx, |
574 | MC13XXX_ADC2, &sample[i]); | 668 | MC13783_ADC2, &sample[i]); |
575 | if (ret) | 669 | if (ret) |
576 | break; | 670 | break; |
577 | } | 671 | } |
578 | 672 | ||
579 | if (mode == MC13XXX_ADC_MODE_TS) | 673 | if (mode == MC13783_ADC_MODE_TS) |
580 | /* restore TSMOD */ | 674 | /* restore TSMOD */ |
581 | mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, old_adc0); | 675 | mc13xxx_reg_write(mc13xxx, MC13783_ADC0, old_adc0); |
582 | 676 | ||
583 | mc13xxx->adcflags &= ~MC13XXX_ADC_WORKING; | 677 | mc13783->adcflags &= ~MC13783_ADC_WORKING; |
584 | out: | 678 | out: |
585 | mc13xxx_unlock(mc13xxx); | 679 | mc13xxx_unlock(mc13xxx); |
586 | 680 | ||
587 | return ret; | 681 | return ret; |
588 | } | 682 | } |
589 | EXPORT_SYMBOL_GPL(mc13xxx_adc_do_conversion); | 683 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); |
590 | 684 | ||
591 | static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | 685 | static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, |
592 | const char *format, void *pdata, size_t pdata_size) | 686 | const char *format, void *pdata, size_t pdata_size) |
@@ -607,7 +701,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | |||
607 | if (!cell.name) | 701 | if (!cell.name) |
608 | return -ENOMEM; | 702 | return -ENOMEM; |
609 | 703 | ||
610 | return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0, NULL); | 704 | return mfd_add_devices(&mc13xxx->spidev->dev, -1, &cell, 1, NULL, 0); |
611 | } | 705 | } |
612 | 706 | ||
613 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) | 707 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) |
@@ -615,49 +709,31 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) | |||
615 | return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); | 709 | return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); |
616 | } | 710 | } |
617 | 711 | ||
618 | #ifdef CONFIG_OF | 712 | static int mc13xxx_probe(struct spi_device *spi) |
619 | static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) | ||
620 | { | 713 | { |
621 | struct device_node *np = mc13xxx->dev->of_node; | 714 | struct mc13xxx *mc13xxx; |
622 | 715 | struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); | |
623 | if (!np) | 716 | enum mc13xxx_id id; |
624 | return -ENODEV; | 717 | int ret; |
625 | |||
626 | if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL)) | ||
627 | mc13xxx->flags |= MC13XXX_USE_ADC; | ||
628 | |||
629 | if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL)) | ||
630 | mc13xxx->flags |= MC13XXX_USE_CODEC; | ||
631 | 718 | ||
632 | if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL)) | 719 | mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); |
633 | mc13xxx->flags |= MC13XXX_USE_RTC; | 720 | if (!mc13xxx) |
721 | return -ENOMEM; | ||
634 | 722 | ||
635 | if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL)) | 723 | dev_set_drvdata(&spi->dev, mc13xxx); |
636 | mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN; | 724 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; |
725 | spi->bits_per_word = 32; | ||
726 | spi_setup(spi); | ||
637 | 727 | ||
638 | return 0; | 728 | mc13xxx->spidev = spi; |
639 | } | ||
640 | #else | ||
641 | static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) | ||
642 | { | ||
643 | return -ENODEV; | ||
644 | } | ||
645 | #endif | ||
646 | |||
647 | int mc13xxx_common_init(struct mc13xxx *mc13xxx, | ||
648 | struct mc13xxx_platform_data *pdata, int irq) | ||
649 | { | ||
650 | int ret; | ||
651 | u32 revision; | ||
652 | 729 | ||
730 | mutex_init(&mc13xxx->lock); | ||
653 | mc13xxx_lock(mc13xxx); | 731 | mc13xxx_lock(mc13xxx); |
654 | 732 | ||
655 | ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); | 733 | ret = mc13xxx_identify(mc13xxx, &id); |
656 | if (ret) | 734 | if (ret || id == MC13XXX_ID_INVALID) |
657 | goto err_revision; | 735 | goto err_revision; |
658 | 736 | ||
659 | mc13xxx->variant->print_revision(mc13xxx, revision); | ||
660 | |||
661 | /* mask all irqs */ | 737 | /* mask all irqs */ |
662 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); | 738 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); |
663 | if (ret) | 739 | if (ret) |
@@ -667,61 +743,92 @@ int mc13xxx_common_init(struct mc13xxx *mc13xxx, | |||
667 | if (ret) | 743 | if (ret) |
668 | goto err_mask; | 744 | goto err_mask; |
669 | 745 | ||
670 | ret = request_threaded_irq(irq, NULL, mc13xxx_irq_thread, | 746 | ret = request_threaded_irq(spi->irq, NULL, mc13xxx_irq_thread, |
671 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); | 747 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); |
672 | 748 | ||
673 | if (ret) { | 749 | if (ret) { |
674 | err_mask: | 750 | err_mask: |
675 | err_revision: | 751 | err_revision: |
676 | mc13xxx_unlock(mc13xxx); | 752 | mc13xxx_unlock(mc13xxx); |
753 | dev_set_drvdata(&spi->dev, NULL); | ||
754 | kfree(mc13xxx); | ||
677 | return ret; | 755 | return ret; |
678 | } | 756 | } |
679 | 757 | ||
680 | mc13xxx->irq = irq; | ||
681 | |||
682 | mc13xxx_unlock(mc13xxx); | 758 | mc13xxx_unlock(mc13xxx); |
683 | 759 | ||
684 | if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata) | 760 | if (pdata->flags & MC13XXX_USE_ADC) |
685 | mc13xxx->flags = pdata->flags; | ||
686 | |||
687 | if (mc13xxx->flags & MC13XXX_USE_ADC) | ||
688 | mc13xxx_add_subdevice(mc13xxx, "%s-adc"); | 761 | mc13xxx_add_subdevice(mc13xxx, "%s-adc"); |
689 | 762 | ||
690 | if (mc13xxx->flags & MC13XXX_USE_CODEC) | 763 | if (pdata->flags & MC13XXX_USE_CODEC) |
691 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec", | 764 | mc13xxx_add_subdevice(mc13xxx, "%s-codec"); |
692 | pdata->codec, sizeof(*pdata->codec)); | 765 | |
766 | if (pdata->flags & MC13XXX_USE_REGULATOR) { | ||
767 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", | ||
768 | &pdata->regulators, sizeof(pdata->regulators)); | ||
769 | } | ||
693 | 770 | ||
694 | if (mc13xxx->flags & MC13XXX_USE_RTC) | 771 | if (pdata->flags & MC13XXX_USE_RTC) |
695 | mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); | 772 | mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); |
696 | 773 | ||
697 | if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) | 774 | if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) |
698 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts", | 775 | mc13xxx_add_subdevice(mc13xxx, "%s-ts"); |
699 | &pdata->touch, sizeof(pdata->touch)); | ||
700 | 776 | ||
701 | if (pdata) { | 777 | if (pdata->flags & MC13XXX_USE_LED) |
702 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", | ||
703 | &pdata->regulators, sizeof(pdata->regulators)); | ||
704 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", | 778 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", |
705 | pdata->leds, sizeof(*pdata->leds)); | 779 | pdata->leds, sizeof(*pdata->leds)); |
706 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton", | ||
707 | pdata->buttons, sizeof(*pdata->buttons)); | ||
708 | } else { | ||
709 | mc13xxx_add_subdevice(mc13xxx, "%s-regulator"); | ||
710 | mc13xxx_add_subdevice(mc13xxx, "%s-led"); | ||
711 | mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton"); | ||
712 | } | ||
713 | 780 | ||
714 | return 0; | 781 | return 0; |
715 | } | 782 | } |
716 | EXPORT_SYMBOL_GPL(mc13xxx_common_init); | ||
717 | 783 | ||
718 | void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx) | 784 | static int __devexit mc13xxx_remove(struct spi_device *spi) |
719 | { | 785 | { |
720 | free_irq(mc13xxx->irq, mc13xxx); | 786 | struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); |
787 | |||
788 | free_irq(mc13xxx->spidev->irq, mc13xxx); | ||
721 | 789 | ||
722 | mfd_remove_devices(mc13xxx->dev); | 790 | mfd_remove_devices(&spi->dev); |
791 | |||
792 | kfree(mc13xxx); | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static const struct spi_device_id mc13xxx_device_id[] = { | ||
798 | { | ||
799 | .name = "mc13783", | ||
800 | .driver_data = MC13XXX_ID_MC13783, | ||
801 | }, { | ||
802 | .name = "mc13892", | ||
803 | .driver_data = MC13XXX_ID_MC13892, | ||
804 | }, { | ||
805 | /* sentinel */ | ||
806 | } | ||
807 | }; | ||
808 | MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); | ||
809 | |||
810 | static struct spi_driver mc13xxx_driver = { | ||
811 | .id_table = mc13xxx_device_id, | ||
812 | .driver = { | ||
813 | .name = "mc13xxx", | ||
814 | .bus = &spi_bus_type, | ||
815 | .owner = THIS_MODULE, | ||
816 | }, | ||
817 | .probe = mc13xxx_probe, | ||
818 | .remove = __devexit_p(mc13xxx_remove), | ||
819 | }; | ||
820 | |||
821 | static int __init mc13xxx_init(void) | ||
822 | { | ||
823 | return spi_register_driver(&mc13xxx_driver); | ||
824 | } | ||
825 | subsys_initcall(mc13xxx_init); | ||
826 | |||
827 | static void __exit mc13xxx_exit(void) | ||
828 | { | ||
829 | spi_unregister_driver(&mc13xxx_driver); | ||
723 | } | 830 | } |
724 | EXPORT_SYMBOL_GPL(mc13xxx_common_cleanup); | 831 | module_exit(mc13xxx_exit); |
725 | 832 | ||
726 | MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC"); | 833 | MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC"); |
727 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | 834 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); |