diff options
author | H. Peter Anvin <hpa@zytor.com> | 2012-05-30 15:11:26 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2012-05-30 15:11:32 -0400 |
commit | bbd771474ec44b516107685d77e1c80bbe09f141 (patch) | |
tree | 0cb15781539a68f27b4ea6c89f827282630cbce6 /drivers/mfd/ab8500-core.c | |
parent | 403e1c5b7495d7b80fae9fc4d0a7a6f5abdc3307 (diff) | |
parent | 319b6ffc6df892e4ccffff823cc5521a4a5d2dca (diff) |
Merge branch 'x86/trampoline' into x86/urgent
x86/trampoline contains an urgent commit which is necessarily on a
newer baseline.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'drivers/mfd/ab8500-core.c')
-rw-r--r-- | drivers/mfd/ab8500-core.c | 423 |
1 files changed, 369 insertions, 54 deletions
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 1f08704f7ae8..dac0e2998603 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -18,7 +18,10 @@ | |||
18 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/abx500.h> | 19 | #include <linux/mfd/abx500.h> |
20 | #include <linux/mfd/abx500/ab8500.h> | 20 | #include <linux/mfd/abx500/ab8500.h> |
21 | #include <linux/mfd/dbx500-prcmu.h> | ||
21 | #include <linux/regulator/ab8500.h> | 22 | #include <linux/regulator/ab8500.h> |
23 | #include <linux/of.h> | ||
24 | #include <linux/of_device.h> | ||
22 | 25 | ||
23 | /* | 26 | /* |
24 | * Interrupt register offsets | 27 | * Interrupt register offsets |
@@ -91,12 +94,24 @@ | |||
91 | #define AB8500_IT_MASK23_REG 0x56 | 94 | #define AB8500_IT_MASK23_REG 0x56 |
92 | #define AB8500_IT_MASK24_REG 0x57 | 95 | #define AB8500_IT_MASK24_REG 0x57 |
93 | 96 | ||
97 | /* | ||
98 | * latch hierarchy registers | ||
99 | */ | ||
100 | #define AB8500_IT_LATCHHIER1_REG 0x60 | ||
101 | #define AB8500_IT_LATCHHIER2_REG 0x61 | ||
102 | #define AB8500_IT_LATCHHIER3_REG 0x62 | ||
103 | |||
104 | #define AB8500_IT_LATCHHIER_NUM 3 | ||
105 | |||
94 | #define AB8500_REV_REG 0x80 | 106 | #define AB8500_REV_REG 0x80 |
95 | #define AB8500_IC_NAME_REG 0x82 | 107 | #define AB8500_IC_NAME_REG 0x82 |
96 | #define AB8500_SWITCH_OFF_STATUS 0x00 | 108 | #define AB8500_SWITCH_OFF_STATUS 0x00 |
97 | 109 | ||
98 | #define AB8500_TURN_ON_STATUS 0x00 | 110 | #define AB8500_TURN_ON_STATUS 0x00 |
99 | 111 | ||
112 | static bool no_bm; /* No battery management */ | ||
113 | module_param(no_bm, bool, S_IRUGO); | ||
114 | |||
100 | #define AB9540_MODEM_CTRL2_REG 0x23 | 115 | #define AB9540_MODEM_CTRL2_REG 0x23 |
101 | #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) | 116 | #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) |
102 | 117 | ||
@@ -125,6 +140,41 @@ static const char ab8500_version_str[][7] = { | |||
125 | [AB8500_VERSION_AB8540] = "AB8540", | 140 | [AB8500_VERSION_AB8540] = "AB8540", |
126 | }; | 141 | }; |
127 | 142 | ||
143 | static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) | ||
144 | { | ||
145 | int ret; | ||
146 | |||
147 | ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); | ||
148 | if (ret < 0) | ||
149 | dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, | ||
154 | u8 data) | ||
155 | { | ||
156 | int ret; | ||
157 | |||
158 | ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, | ||
159 | &mask, 1); | ||
160 | if (ret < 0) | ||
161 | dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr) | ||
166 | { | ||
167 | int ret; | ||
168 | u8 data; | ||
169 | |||
170 | ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); | ||
171 | if (ret < 0) { | ||
172 | dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); | ||
173 | return ret; | ||
174 | } | ||
175 | return (int)data; | ||
176 | } | ||
177 | |||
128 | static int ab8500_get_chip_id(struct device *dev) | 178 | static int ab8500_get_chip_id(struct device *dev) |
129 | { | 179 | { |
130 | struct ab8500 *ab8500; | 180 | struct ab8500 *ab8500; |
@@ -161,9 +211,13 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, | |||
161 | static int ab8500_set_register(struct device *dev, u8 bank, | 211 | static int ab8500_set_register(struct device *dev, u8 bank, |
162 | u8 reg, u8 value) | 212 | u8 reg, u8 value) |
163 | { | 213 | { |
214 | int ret; | ||
164 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); | 215 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
165 | 216 | ||
166 | return set_register_interruptible(ab8500, bank, reg, value); | 217 | atomic_inc(&ab8500->transfer_ongoing); |
218 | ret = set_register_interruptible(ab8500, bank, reg, value); | ||
219 | atomic_dec(&ab8500->transfer_ongoing); | ||
220 | return ret; | ||
167 | } | 221 | } |
168 | 222 | ||
169 | static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, | 223 | static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, |
@@ -192,9 +246,13 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, | |||
192 | static int ab8500_get_register(struct device *dev, u8 bank, | 246 | static int ab8500_get_register(struct device *dev, u8 bank, |
193 | u8 reg, u8 *value) | 247 | u8 reg, u8 *value) |
194 | { | 248 | { |
249 | int ret; | ||
195 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); | 250 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
196 | 251 | ||
197 | return get_register_interruptible(ab8500, bank, reg, value); | 252 | atomic_inc(&ab8500->transfer_ongoing); |
253 | ret = get_register_interruptible(ab8500, bank, reg, value); | ||
254 | atomic_dec(&ab8500->transfer_ongoing); | ||
255 | return ret; | ||
198 | } | 256 | } |
199 | 257 | ||
200 | static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, | 258 | static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, |
@@ -241,11 +299,14 @@ out: | |||
241 | static int ab8500_mask_and_set_register(struct device *dev, | 299 | static int ab8500_mask_and_set_register(struct device *dev, |
242 | u8 bank, u8 reg, u8 bitmask, u8 bitvalues) | 300 | u8 bank, u8 reg, u8 bitmask, u8 bitvalues) |
243 | { | 301 | { |
302 | int ret; | ||
244 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); | 303 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
245 | 304 | ||
246 | return mask_and_set_register_interruptible(ab8500, bank, reg, | 305 | atomic_inc(&ab8500->transfer_ongoing); |
247 | bitmask, bitvalues); | 306 | ret= mask_and_set_register_interruptible(ab8500, bank, reg, |
248 | 307 | bitmask, bitvalues); | |
308 | atomic_dec(&ab8500->transfer_ongoing); | ||
309 | return ret; | ||
249 | } | 310 | } |
250 | 311 | ||
251 | static struct abx500_ops ab8500_ops = { | 312 | static struct abx500_ops ab8500_ops = { |
@@ -264,6 +325,7 @@ static void ab8500_irq_lock(struct irq_data *data) | |||
264 | struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); | 325 | struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); |
265 | 326 | ||
266 | mutex_lock(&ab8500->irq_lock); | 327 | mutex_lock(&ab8500->irq_lock); |
328 | atomic_inc(&ab8500->transfer_ongoing); | ||
267 | } | 329 | } |
268 | 330 | ||
269 | static void ab8500_irq_sync_unlock(struct irq_data *data) | 331 | static void ab8500_irq_sync_unlock(struct irq_data *data) |
@@ -292,7 +354,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data) | |||
292 | reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; | 354 | reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; |
293 | set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); | 355 | set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); |
294 | } | 356 | } |
295 | 357 | atomic_dec(&ab8500->transfer_ongoing); | |
296 | mutex_unlock(&ab8500->irq_lock); | 358 | mutex_unlock(&ab8500->irq_lock); |
297 | } | 359 | } |
298 | 360 | ||
@@ -325,6 +387,90 @@ static struct irq_chip ab8500_irq_chip = { | |||
325 | .irq_unmask = ab8500_irq_unmask, | 387 | .irq_unmask = ab8500_irq_unmask, |
326 | }; | 388 | }; |
327 | 389 | ||
390 | static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, | ||
391 | int latch_offset, u8 latch_val) | ||
392 | { | ||
393 | int int_bit = __ffs(latch_val); | ||
394 | int line, i; | ||
395 | |||
396 | do { | ||
397 | int_bit = __ffs(latch_val); | ||
398 | |||
399 | for (i = 0; i < ab8500->mask_size; i++) | ||
400 | if (ab8500->irq_reg_offset[i] == latch_offset) | ||
401 | break; | ||
402 | |||
403 | if (i >= ab8500->mask_size) { | ||
404 | dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", | ||
405 | latch_offset); | ||
406 | return -ENXIO; | ||
407 | } | ||
408 | |||
409 | line = (i << 3) + int_bit; | ||
410 | latch_val &= ~(1 << int_bit); | ||
411 | |||
412 | handle_nested_irq(ab8500->irq_base + line); | ||
413 | } while (latch_val); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, | ||
419 | int hier_offset, u8 hier_val) | ||
420 | { | ||
421 | int latch_bit, status; | ||
422 | u8 latch_offset, latch_val; | ||
423 | |||
424 | do { | ||
425 | latch_bit = __ffs(hier_val); | ||
426 | latch_offset = (hier_offset << 3) + latch_bit; | ||
427 | |||
428 | /* Fix inconsistent ITFromLatch25 bit mapping... */ | ||
429 | if (unlikely(latch_offset == 17)) | ||
430 | latch_offset = 24; | ||
431 | |||
432 | status = get_register_interruptible(ab8500, | ||
433 | AB8500_INTERRUPT, | ||
434 | AB8500_IT_LATCH1_REG + latch_offset, | ||
435 | &latch_val); | ||
436 | if (status < 0 || latch_val == 0) | ||
437 | goto discard; | ||
438 | |||
439 | status = ab8500_handle_hierarchical_line(ab8500, | ||
440 | latch_offset, latch_val); | ||
441 | if (status < 0) | ||
442 | return status; | ||
443 | discard: | ||
444 | hier_val &= ~(1 << latch_bit); | ||
445 | } while (hier_val); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) | ||
451 | { | ||
452 | struct ab8500 *ab8500 = dev; | ||
453 | u8 i; | ||
454 | |||
455 | dev_vdbg(ab8500->dev, "interrupt\n"); | ||
456 | |||
457 | /* Hierarchical interrupt version */ | ||
458 | for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) { | ||
459 | int status; | ||
460 | u8 hier_val; | ||
461 | |||
462 | status = get_register_interruptible(ab8500, AB8500_INTERRUPT, | ||
463 | AB8500_IT_LATCHHIER1_REG + i, &hier_val); | ||
464 | if (status < 0 || hier_val == 0) | ||
465 | continue; | ||
466 | |||
467 | status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); | ||
468 | if (status < 0) | ||
469 | break; | ||
470 | } | ||
471 | return IRQ_HANDLED; | ||
472 | } | ||
473 | |||
328 | static irqreturn_t ab8500_irq(int irq, void *dev) | 474 | static irqreturn_t ab8500_irq(int irq, void *dev) |
329 | { | 475 | { |
330 | struct ab8500 *ab8500 = dev; | 476 | struct ab8500 *ab8500 = dev; |
@@ -332,6 +478,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
332 | 478 | ||
333 | dev_vdbg(ab8500->dev, "interrupt\n"); | 479 | dev_vdbg(ab8500->dev, "interrupt\n"); |
334 | 480 | ||
481 | atomic_inc(&ab8500->transfer_ongoing); | ||
482 | |||
335 | for (i = 0; i < ab8500->mask_size; i++) { | 483 | for (i = 0; i < ab8500->mask_size; i++) { |
336 | int regoffset = ab8500->irq_reg_offset[i]; | 484 | int regoffset = ab8500->irq_reg_offset[i]; |
337 | int status; | 485 | int status; |
@@ -355,9 +503,10 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
355 | 503 | ||
356 | handle_nested_irq(ab8500->irq_base + line); | 504 | handle_nested_irq(ab8500->irq_base + line); |
357 | value &= ~(1 << bit); | 505 | value &= ~(1 << bit); |
506 | |||
358 | } while (value); | 507 | } while (value); |
359 | } | 508 | } |
360 | 509 | atomic_dec(&ab8500->transfer_ongoing); | |
361 | return IRQ_HANDLED; | 510 | return IRQ_HANDLED; |
362 | } | 511 | } |
363 | 512 | ||
@@ -411,6 +560,14 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) | |||
411 | } | 560 | } |
412 | } | 561 | } |
413 | 562 | ||
563 | int ab8500_suspend(struct ab8500 *ab8500) | ||
564 | { | ||
565 | if (atomic_read(&ab8500->transfer_ongoing)) | ||
566 | return -EINVAL; | ||
567 | else | ||
568 | return 0; | ||
569 | } | ||
570 | |||
414 | /* AB8500 GPIO Resources */ | 571 | /* AB8500 GPIO Resources */ |
415 | static struct resource __devinitdata ab8500_gpio_resources[] = { | 572 | static struct resource __devinitdata ab8500_gpio_resources[] = { |
416 | { | 573 | { |
@@ -744,6 +901,39 @@ static struct resource __devinitdata ab8500_usb_resources[] = { | |||
744 | }, | 901 | }, |
745 | }; | 902 | }; |
746 | 903 | ||
904 | static struct resource __devinitdata ab8505_iddet_resources[] = { | ||
905 | { | ||
906 | .name = "KeyDeglitch", | ||
907 | .start = AB8505_INT_KEYDEGLITCH, | ||
908 | .end = AB8505_INT_KEYDEGLITCH, | ||
909 | .flags = IORESOURCE_IRQ, | ||
910 | }, | ||
911 | { | ||
912 | .name = "KP", | ||
913 | .start = AB8505_INT_KP, | ||
914 | .end = AB8505_INT_KP, | ||
915 | .flags = IORESOURCE_IRQ, | ||
916 | }, | ||
917 | { | ||
918 | .name = "IKP", | ||
919 | .start = AB8505_INT_IKP, | ||
920 | .end = AB8505_INT_IKP, | ||
921 | .flags = IORESOURCE_IRQ, | ||
922 | }, | ||
923 | { | ||
924 | .name = "IKR", | ||
925 | .start = AB8505_INT_IKR, | ||
926 | .end = AB8505_INT_IKR, | ||
927 | .flags = IORESOURCE_IRQ, | ||
928 | }, | ||
929 | { | ||
930 | .name = "KeyStuck", | ||
931 | .start = AB8505_INT_KEYSTUCK, | ||
932 | .end = AB8505_INT_KEYSTUCK, | ||
933 | .flags = IORESOURCE_IRQ, | ||
934 | }, | ||
935 | }; | ||
936 | |||
747 | static struct resource __devinitdata ab8500_temp_resources[] = { | 937 | static struct resource __devinitdata ab8500_temp_resources[] = { |
748 | { | 938 | { |
749 | .name = "AB8500_TEMP_WARM", | 939 | .name = "AB8500_TEMP_WARM", |
@@ -778,35 +968,11 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = { | |||
778 | .resources = ab8500_rtc_resources, | 968 | .resources = ab8500_rtc_resources, |
779 | }, | 969 | }, |
780 | { | 970 | { |
781 | .name = "ab8500-charger", | ||
782 | .num_resources = ARRAY_SIZE(ab8500_charger_resources), | ||
783 | .resources = ab8500_charger_resources, | ||
784 | }, | ||
785 | { | ||
786 | .name = "ab8500-btemp", | ||
787 | .num_resources = ARRAY_SIZE(ab8500_btemp_resources), | ||
788 | .resources = ab8500_btemp_resources, | ||
789 | }, | ||
790 | { | ||
791 | .name = "ab8500-fg", | ||
792 | .num_resources = ARRAY_SIZE(ab8500_fg_resources), | ||
793 | .resources = ab8500_fg_resources, | ||
794 | }, | ||
795 | { | ||
796 | .name = "ab8500-chargalg", | ||
797 | .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), | ||
798 | .resources = ab8500_chargalg_resources, | ||
799 | }, | ||
800 | { | ||
801 | .name = "ab8500-acc-det", | 971 | .name = "ab8500-acc-det", |
802 | .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), | 972 | .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), |
803 | .resources = ab8500_av_acc_detect_resources, | 973 | .resources = ab8500_av_acc_detect_resources, |
804 | }, | 974 | }, |
805 | { | 975 | { |
806 | .name = "ab8500-codec", | ||
807 | }, | ||
808 | |||
809 | { | ||
810 | .name = "ab8500-poweron-key", | 976 | .name = "ab8500-poweron-key", |
811 | .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), | 977 | .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), |
812 | .resources = ab8500_poweronkey_db_resources, | 978 | .resources = ab8500_poweronkey_db_resources, |
@@ -834,6 +1000,29 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = { | |||
834 | }, | 1000 | }, |
835 | }; | 1001 | }; |
836 | 1002 | ||
1003 | static struct mfd_cell __devinitdata ab8500_bm_devs[] = { | ||
1004 | { | ||
1005 | .name = "ab8500-charger", | ||
1006 | .num_resources = ARRAY_SIZE(ab8500_charger_resources), | ||
1007 | .resources = ab8500_charger_resources, | ||
1008 | }, | ||
1009 | { | ||
1010 | .name = "ab8500-btemp", | ||
1011 | .num_resources = ARRAY_SIZE(ab8500_btemp_resources), | ||
1012 | .resources = ab8500_btemp_resources, | ||
1013 | }, | ||
1014 | { | ||
1015 | .name = "ab8500-fg", | ||
1016 | .num_resources = ARRAY_SIZE(ab8500_fg_resources), | ||
1017 | .resources = ab8500_fg_resources, | ||
1018 | }, | ||
1019 | { | ||
1020 | .name = "ab8500-chargalg", | ||
1021 | .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), | ||
1022 | .resources = ab8500_chargalg_resources, | ||
1023 | }, | ||
1024 | }; | ||
1025 | |||
837 | static struct mfd_cell __devinitdata ab8500_devs[] = { | 1026 | static struct mfd_cell __devinitdata ab8500_devs[] = { |
838 | { | 1027 | { |
839 | .name = "ab8500-gpio", | 1028 | .name = "ab8500-gpio", |
@@ -845,6 +1034,9 @@ static struct mfd_cell __devinitdata ab8500_devs[] = { | |||
845 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), | 1034 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), |
846 | .resources = ab8500_usb_resources, | 1035 | .resources = ab8500_usb_resources, |
847 | }, | 1036 | }, |
1037 | { | ||
1038 | .name = "ab8500-codec", | ||
1039 | }, | ||
848 | }; | 1040 | }; |
849 | 1041 | ||
850 | static struct mfd_cell __devinitdata ab9540_devs[] = { | 1042 | static struct mfd_cell __devinitdata ab9540_devs[] = { |
@@ -858,6 +1050,18 @@ static struct mfd_cell __devinitdata ab9540_devs[] = { | |||
858 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), | 1050 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), |
859 | .resources = ab8500_usb_resources, | 1051 | .resources = ab8500_usb_resources, |
860 | }, | 1052 | }, |
1053 | { | ||
1054 | .name = "ab9540-codec", | ||
1055 | }, | ||
1056 | }; | ||
1057 | |||
1058 | /* Device list common to ab9540 and ab8505 */ | ||
1059 | static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = { | ||
1060 | { | ||
1061 | .name = "ab-iddet", | ||
1062 | .num_resources = ARRAY_SIZE(ab8505_iddet_resources), | ||
1063 | .resources = ab8505_iddet_resources, | ||
1064 | }, | ||
861 | }; | 1065 | }; |
862 | 1066 | ||
863 | static ssize_t show_chip_id(struct device *dev, | 1067 | static ssize_t show_chip_id(struct device *dev, |
@@ -1003,18 +1207,66 @@ static struct attribute_group ab9540_attr_group = { | |||
1003 | .attrs = ab9540_sysfs_entries, | 1207 | .attrs = ab9540_sysfs_entries, |
1004 | }; | 1208 | }; |
1005 | 1209 | ||
1006 | int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version) | 1210 | static const struct of_device_id ab8500_match[] = { |
1211 | { | ||
1212 | .compatible = "stericsson,ab8500", | ||
1213 | .data = (void *)AB8500_VERSION_AB8500, | ||
1214 | }, | ||
1215 | {}, | ||
1216 | }; | ||
1217 | |||
1218 | static int __devinit ab8500_probe(struct platform_device *pdev) | ||
1007 | { | 1219 | { |
1008 | struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); | 1220 | struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); |
1221 | const struct platform_device_id *platid = platform_get_device_id(pdev); | ||
1222 | enum ab8500_version version = AB8500_VERSION_UNDEFINED; | ||
1223 | struct device_node *np = pdev->dev.of_node; | ||
1224 | struct ab8500 *ab8500; | ||
1225 | struct resource *resource; | ||
1009 | int ret; | 1226 | int ret; |
1010 | int i; | 1227 | int i; |
1011 | u8 value; | 1228 | u8 value; |
1012 | 1229 | ||
1230 | ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); | ||
1231 | if (!ab8500) | ||
1232 | return -ENOMEM; | ||
1233 | |||
1013 | if (plat) | 1234 | if (plat) |
1014 | ab8500->irq_base = plat->irq_base; | 1235 | ab8500->irq_base = plat->irq_base; |
1236 | else if (np) | ||
1237 | ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base); | ||
1238 | |||
1239 | if (!ab8500->irq_base) { | ||
1240 | dev_info(&pdev->dev, "couldn't find irq-base\n"); | ||
1241 | ret = -EINVAL; | ||
1242 | goto out_free_ab8500; | ||
1243 | } | ||
1244 | |||
1245 | ab8500->dev = &pdev->dev; | ||
1246 | |||
1247 | resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1248 | if (!resource) { | ||
1249 | ret = -ENODEV; | ||
1250 | goto out_free_ab8500; | ||
1251 | } | ||
1252 | |||
1253 | ab8500->irq = resource->start; | ||
1254 | |||
1255 | ab8500->read = ab8500_i2c_read; | ||
1256 | ab8500->write = ab8500_i2c_write; | ||
1257 | ab8500->write_masked = ab8500_i2c_write_masked; | ||
1015 | 1258 | ||
1016 | mutex_init(&ab8500->lock); | 1259 | mutex_init(&ab8500->lock); |
1017 | mutex_init(&ab8500->irq_lock); | 1260 | mutex_init(&ab8500->irq_lock); |
1261 | atomic_set(&ab8500->transfer_ongoing, 0); | ||
1262 | |||
1263 | platform_set_drvdata(pdev, ab8500); | ||
1264 | |||
1265 | if (platid) | ||
1266 | version = platid->driver_data; | ||
1267 | else if (np) | ||
1268 | version = (unsigned int) | ||
1269 | of_match_device(ab8500_match, &pdev->dev)->data; | ||
1018 | 1270 | ||
1019 | if (version != AB8500_VERSION_UNDEFINED) | 1271 | if (version != AB8500_VERSION_UNDEFINED) |
1020 | ab8500->version = version; | 1272 | ab8500->version = version; |
@@ -1022,7 +1274,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version) | |||
1022 | ret = get_register_interruptible(ab8500, AB8500_MISC, | 1274 | ret = get_register_interruptible(ab8500, AB8500_MISC, |
1023 | AB8500_IC_NAME_REG, &value); | 1275 | AB8500_IC_NAME_REG, &value); |
1024 | if (ret < 0) | 1276 | if (ret < 0) |
1025 | return ret; | 1277 | goto out_free_ab8500; |
1026 | 1278 | ||
1027 | ab8500->version = value; | 1279 | ab8500->version = value; |
1028 | } | 1280 | } |
@@ -1030,7 +1282,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version) | |||
1030 | ret = get_register_interruptible(ab8500, AB8500_MISC, | 1282 | ret = get_register_interruptible(ab8500, AB8500_MISC, |
1031 | AB8500_REV_REG, &value); | 1283 | AB8500_REV_REG, &value); |
1032 | if (ret < 0) | 1284 | if (ret < 0) |
1033 | return ret; | 1285 | goto out_free_ab8500; |
1034 | 1286 | ||
1035 | ab8500->chip_id = value; | 1287 | ab8500->chip_id = value; |
1036 | 1288 | ||
@@ -1105,30 +1357,57 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version) | |||
1105 | if (ret) | 1357 | if (ret) |
1106 | goto out_freeoldmask; | 1358 | goto out_freeoldmask; |
1107 | 1359 | ||
1108 | ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq, | 1360 | /* Activate this feature only in ab9540 */ |
1109 | IRQF_ONESHOT | IRQF_NO_SUSPEND, | 1361 | /* till tests are done on ab8500 1p2 or later*/ |
1110 | "ab8500", ab8500); | 1362 | if (is_ab9540(ab8500)) |
1363 | ret = request_threaded_irq(ab8500->irq, NULL, | ||
1364 | ab8500_hierarchical_irq, | ||
1365 | IRQF_ONESHOT | IRQF_NO_SUSPEND, | ||
1366 | "ab8500", ab8500); | ||
1367 | else | ||
1368 | ret = request_threaded_irq(ab8500->irq, NULL, | ||
1369 | ab8500_irq, | ||
1370 | IRQF_ONESHOT | IRQF_NO_SUSPEND, | ||
1371 | "ab8500", ab8500); | ||
1111 | if (ret) | 1372 | if (ret) |
1112 | goto out_removeirq; | 1373 | goto out_removeirq; |
1113 | } | 1374 | } |
1114 | 1375 | ||
1115 | ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, | 1376 | if (!np) { |
1116 | ARRAY_SIZE(abx500_common_devs), NULL, | 1377 | ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, |
1117 | ab8500->irq_base); | 1378 | ARRAY_SIZE(abx500_common_devs), NULL, |
1379 | ab8500->irq_base); | ||
1118 | 1380 | ||
1119 | if (ret) | 1381 | if (ret) |
1120 | goto out_freeirq; | 1382 | goto out_freeirq; |
1383 | |||
1384 | if (is_ab9540(ab8500)) | ||
1385 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, | ||
1386 | ARRAY_SIZE(ab9540_devs), NULL, | ||
1387 | ab8500->irq_base); | ||
1388 | else | ||
1389 | ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, | ||
1390 | ARRAY_SIZE(ab8500_devs), NULL, | ||
1391 | ab8500->irq_base); | ||
1392 | if (ret) | ||
1393 | goto out_freeirq; | ||
1121 | 1394 | ||
1122 | if (is_ab9540(ab8500)) | 1395 | if (is_ab9540(ab8500) || is_ab8505(ab8500)) |
1123 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, | 1396 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, |
1124 | ARRAY_SIZE(ab9540_devs), NULL, | 1397 | ARRAY_SIZE(ab9540_ab8505_devs), NULL, |
1125 | ab8500->irq_base); | 1398 | ab8500->irq_base); |
1126 | else | 1399 | if (ret) |
1127 | ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, | 1400 | goto out_freeirq; |
1128 | ARRAY_SIZE(ab9540_devs), NULL, | 1401 | } |
1129 | ab8500->irq_base); | 1402 | |
1130 | if (ret) | 1403 | if (!no_bm) { |
1131 | goto out_freeirq; | 1404 | /* Add battery management devices */ |
1405 | ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, | ||
1406 | ARRAY_SIZE(ab8500_bm_devs), NULL, | ||
1407 | ab8500->irq_base); | ||
1408 | if (ret) | ||
1409 | dev_err(ab8500->dev, "error adding bm devices\n"); | ||
1410 | } | ||
1132 | 1411 | ||
1133 | if (is_ab9540(ab8500)) | 1412 | if (is_ab9540(ab8500)) |
1134 | ret = sysfs_create_group(&ab8500->dev->kobj, | 1413 | ret = sysfs_create_group(&ab8500->dev->kobj, |
@@ -1151,12 +1430,16 @@ out_freeoldmask: | |||
1151 | kfree(ab8500->oldmask); | 1430 | kfree(ab8500->oldmask); |
1152 | out_freemask: | 1431 | out_freemask: |
1153 | kfree(ab8500->mask); | 1432 | kfree(ab8500->mask); |
1433 | out_free_ab8500: | ||
1434 | kfree(ab8500); | ||
1154 | 1435 | ||
1155 | return ret; | 1436 | return ret; |
1156 | } | 1437 | } |
1157 | 1438 | ||
1158 | int __devexit ab8500_exit(struct ab8500 *ab8500) | 1439 | static int __devexit ab8500_remove(struct platform_device *pdev) |
1159 | { | 1440 | { |
1441 | struct ab8500 *ab8500 = platform_get_drvdata(pdev); | ||
1442 | |||
1160 | if (is_ab9540(ab8500)) | 1443 | if (is_ab9540(ab8500)) |
1161 | sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); | 1444 | sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); |
1162 | else | 1445 | else |
@@ -1168,10 +1451,42 @@ int __devexit ab8500_exit(struct ab8500 *ab8500) | |||
1168 | } | 1451 | } |
1169 | kfree(ab8500->oldmask); | 1452 | kfree(ab8500->oldmask); |
1170 | kfree(ab8500->mask); | 1453 | kfree(ab8500->mask); |
1454 | kfree(ab8500); | ||
1171 | 1455 | ||
1172 | return 0; | 1456 | return 0; |
1173 | } | 1457 | } |
1174 | 1458 | ||
1459 | static const struct platform_device_id ab8500_id[] = { | ||
1460 | { "ab8500-core", AB8500_VERSION_AB8500 }, | ||
1461 | { "ab8505-i2c", AB8500_VERSION_AB8505 }, | ||
1462 | { "ab9540-i2c", AB8500_VERSION_AB9540 }, | ||
1463 | { "ab8540-i2c", AB8500_VERSION_AB8540 }, | ||
1464 | { } | ||
1465 | }; | ||
1466 | |||
1467 | static struct platform_driver ab8500_core_driver = { | ||
1468 | .driver = { | ||
1469 | .name = "ab8500-core", | ||
1470 | .owner = THIS_MODULE, | ||
1471 | .of_match_table = ab8500_match, | ||
1472 | }, | ||
1473 | .probe = ab8500_probe, | ||
1474 | .remove = __devexit_p(ab8500_remove), | ||
1475 | .id_table = ab8500_id, | ||
1476 | }; | ||
1477 | |||
1478 | static int __init ab8500_core_init(void) | ||
1479 | { | ||
1480 | return platform_driver_register(&ab8500_core_driver); | ||
1481 | } | ||
1482 | |||
1483 | static void __exit ab8500_core_exit(void) | ||
1484 | { | ||
1485 | platform_driver_unregister(&ab8500_core_driver); | ||
1486 | } | ||
1487 | arch_initcall(ab8500_core_init); | ||
1488 | module_exit(ab8500_core_exit); | ||
1489 | |||
1175 | MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); | 1490 | MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); |
1176 | MODULE_DESCRIPTION("AB8500 MFD core"); | 1491 | MODULE_DESCRIPTION("AB8500 MFD core"); |
1177 | MODULE_LICENSE("GPL v2"); | 1492 | MODULE_LICENSE("GPL v2"); |