diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-24 10:59:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-24 10:59:01 -0400 |
commit | a6a1d6485e77f28c11cdf943a3ed2a3fd83ac727 (patch) | |
tree | d9b1948c2c07509f9fab16cd1444de15457c08f4 /drivers/mfd | |
parent | 1b506cfb6ae63f352643d6e208c85c1351547036 (diff) | |
parent | 316b6cc081b112546842d44ded21512bd8454a85 (diff) |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (90 commits)
mfd: Push byte swaps out of wm8994 bulk read path
mfd: Rename ab8500 gpadc header
mfd: Constify WM8994 write path
mfd: Push byte swap out of WM8994 bulk I/O
mfd: Avoid copying data in WM8994 I2C write
mfd: Remove copy from WM831x I2C write function
mfd: Staticise WM8994 PM ops
regulator: Add a subdriver for TI TPS6105x regulator portions v2
mfd: Add a core driver for TI TPS61050/TPS61052 chips v2
gpio: Add Tunnel Creek support to sch_gpio
mfd: Add Tunnel Creek support to lpc_sch
pci_ids: Add Intel Tunnel Creek LPC Bridge device ID.
regulator: MAX8997/8966 support
mfd: Add WM8994 bulk register write operation
mfd: Append additional read write on 88pm860x
mfd: Adopt mfd_data in 88pm860x input driver
mfd: Adopt mfd_data in 88pm860x regulator
mfd: Adopt mfd_data in 88pm860x led
mfd: Adopt mfd_data in 88pm860x backlight
mfd: Fix MAX8997 Kconfig entry typos
...
Diffstat (limited to 'drivers/mfd')
43 files changed, 3077 insertions, 530 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 793300c554b4..9c511c1604a5 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -17,230 +17,138 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/88pm860x.h> | 19 | #include <linux/mfd/88pm860x.h> |
20 | #include <linux/regulator/machine.h> | ||
20 | 21 | ||
21 | #define INT_STATUS_NUM 3 | 22 | #define INT_STATUS_NUM 3 |
22 | 23 | ||
23 | char pm860x_backlight_name[][MFD_NAME_SIZE] = { | 24 | static struct resource bk_resources[] __initdata = { |
24 | "backlight-0", | 25 | {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,}, |
25 | "backlight-1", | 26 | {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,}, |
26 | "backlight-2", | 27 | {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, |
27 | }; | 28 | }; |
28 | EXPORT_SYMBOL(pm860x_backlight_name); | ||
29 | |||
30 | char pm860x_led_name[][MFD_NAME_SIZE] = { | ||
31 | "led0-red", | ||
32 | "led0-green", | ||
33 | "led0-blue", | ||
34 | "led1-red", | ||
35 | "led1-green", | ||
36 | "led1-blue", | ||
37 | }; | ||
38 | EXPORT_SYMBOL(pm860x_led_name); | ||
39 | |||
40 | #define PM8606_BACKLIGHT_RESOURCE(_i, _x) \ | ||
41 | { \ | ||
42 | .name = pm860x_backlight_name[_i], \ | ||
43 | .start = PM8606_##_x, \ | ||
44 | .end = PM8606_##_x, \ | ||
45 | .flags = IORESOURCE_IO, \ | ||
46 | } | ||
47 | 29 | ||
48 | static struct resource backlight_resources[] = { | 30 | static struct resource led_resources[] __initdata = { |
49 | PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A), | 31 | {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,}, |
50 | PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A), | 32 | {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,}, |
51 | PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A), | 33 | {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,}, |
34 | {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,}, | ||
35 | {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,}, | ||
36 | {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, | ||
52 | }; | 37 | }; |
53 | 38 | ||
54 | #define PM8606_BACKLIGHT_DEVS(_i) \ | 39 | static struct resource regulator_resources[] __initdata = { |
55 | { \ | 40 | {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,}, |
56 | .name = "88pm860x-backlight", \ | 41 | {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,}, |
57 | .num_resources = 1, \ | 42 | {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,}, |
58 | .resources = &backlight_resources[_i], \ | 43 | {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,}, |
59 | .id = _i, \ | 44 | {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,}, |
60 | } | 45 | {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,}, |
61 | 46 | {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,}, | |
62 | static struct mfd_cell backlight_devs[] = { | 47 | {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,}, |
63 | PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1), | 48 | {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,}, |
64 | PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2), | 49 | {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,}, |
65 | PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3), | 50 | {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,}, |
51 | {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,}, | ||
52 | {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,}, | ||
53 | {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,}, | ||
54 | {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,}, | ||
55 | {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,}, | ||
56 | {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,}, | ||
57 | {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, | ||
66 | }; | 58 | }; |
67 | 59 | ||
68 | #define PM8606_LED_RESOURCE(_i, _x) \ | 60 | static struct resource touch_resources[] __initdata = { |
69 | { \ | 61 | {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,}, |
70 | .name = pm860x_led_name[_i], \ | ||
71 | .start = PM8606_##_x, \ | ||
72 | .end = PM8606_##_x, \ | ||
73 | .flags = IORESOURCE_IO, \ | ||
74 | } | ||
75 | |||
76 | static struct resource led_resources[] = { | ||
77 | PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B), | ||
78 | PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C), | ||
79 | PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D), | ||
80 | PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B), | ||
81 | PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C), | ||
82 | PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D), | ||
83 | }; | 62 | }; |
84 | 63 | ||
85 | #define PM8606_LED_DEVS(_i) \ | 64 | static struct resource onkey_resources[] __initdata = { |
86 | { \ | 65 | {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,}, |
87 | .name = "88pm860x-led", \ | ||
88 | .num_resources = 1, \ | ||
89 | .resources = &led_resources[_i], \ | ||
90 | .id = _i, \ | ||
91 | } | ||
92 | |||
93 | static struct mfd_cell led_devs[] = { | ||
94 | PM8606_LED_DEVS(PM8606_LED1_RED), | ||
95 | PM8606_LED_DEVS(PM8606_LED1_GREEN), | ||
96 | PM8606_LED_DEVS(PM8606_LED1_BLUE), | ||
97 | PM8606_LED_DEVS(PM8606_LED2_RED), | ||
98 | PM8606_LED_DEVS(PM8606_LED2_GREEN), | ||
99 | PM8606_LED_DEVS(PM8606_LED2_BLUE), | ||
100 | }; | 66 | }; |
101 | 67 | ||
102 | static struct resource touch_resources[] = { | 68 | static struct resource codec_resources[] __initdata = { |
103 | { | 69 | /* Headset microphone insertion or removal */ |
104 | .start = PM8607_IRQ_PEN, | 70 | {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,}, |
105 | .end = PM8607_IRQ_PEN, | 71 | /* Hook-switch press or release */ |
106 | .flags = IORESOURCE_IRQ, | 72 | {PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,}, |
107 | }, | 73 | /* Headset insertion or removal */ |
74 | {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,}, | ||
75 | /* Audio short */ | ||
76 | {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,}, | ||
108 | }; | 77 | }; |
109 | 78 | ||
110 | static struct mfd_cell touch_devs[] = { | 79 | static struct resource battery_resources[] __initdata = { |
111 | { | 80 | {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,}, |
112 | .name = "88pm860x-touch", | 81 | {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,}, |
113 | .num_resources = 1, | ||
114 | .resources = &touch_resources[0], | ||
115 | }, | ||
116 | }; | 82 | }; |
117 | 83 | ||
118 | #define PM8607_REG_RESOURCE(_start, _end) \ | 84 | static struct resource charger_resources[] __initdata = { |
119 | { \ | 85 | {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,}, |
120 | .start = PM8607_##_start, \ | 86 | {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,}, |
121 | .end = PM8607_##_end, \ | 87 | {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,}, |
122 | .flags = IORESOURCE_IO, \ | 88 | {PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature", IORESOURCE_IRQ,}, |
123 | } | 89 | {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,}, |
124 | 90 | {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, | |
125 | static struct resource power_supply_resources[] = { | ||
126 | { | ||
127 | .name = "88pm860x-power", | ||
128 | .start = PM8607_IRQ_CHG, | ||
129 | .end = PM8607_IRQ_CHG, | ||
130 | .flags = IORESOURCE_IRQ, | ||
131 | }, | ||
132 | }; | 91 | }; |
133 | 92 | ||
134 | static struct mfd_cell power_devs[] = { | 93 | static struct mfd_cell bk_devs[] __initdata = { |
135 | { | 94 | {"88pm860x-backlight", 0,}, |
136 | .name = "88pm860x-power", | 95 | {"88pm860x-backlight", 1,}, |
137 | .num_resources = 1, | 96 | {"88pm860x-backlight", 2,}, |
138 | .resources = &power_supply_resources[0], | ||
139 | .id = -1, | ||
140 | }, | ||
141 | }; | 97 | }; |
142 | 98 | ||
143 | static struct resource onkey_resources[] = { | 99 | static struct mfd_cell led_devs[] __initdata = { |
144 | { | 100 | {"88pm860x-led", 0,}, |
145 | .name = "88pm860x-onkey", | 101 | {"88pm860x-led", 1,}, |
146 | .start = PM8607_IRQ_ONKEY, | 102 | {"88pm860x-led", 2,}, |
147 | .end = PM8607_IRQ_ONKEY, | 103 | {"88pm860x-led", 3,}, |
148 | .flags = IORESOURCE_IRQ, | 104 | {"88pm860x-led", 4,}, |
149 | }, | 105 | {"88pm860x-led", 5,}, |
150 | }; | 106 | }; |
151 | 107 | ||
152 | static struct mfd_cell onkey_devs[] = { | 108 | static struct mfd_cell regulator_devs[] __initdata = { |
153 | { | 109 | {"88pm860x-regulator", 0,}, |
154 | .name = "88pm860x-onkey", | 110 | {"88pm860x-regulator", 1,}, |
155 | .num_resources = 1, | 111 | {"88pm860x-regulator", 2,}, |
156 | .resources = &onkey_resources[0], | 112 | {"88pm860x-regulator", 3,}, |
157 | .id = -1, | 113 | {"88pm860x-regulator", 4,}, |
158 | }, | 114 | {"88pm860x-regulator", 5,}, |
115 | {"88pm860x-regulator", 6,}, | ||
116 | {"88pm860x-regulator", 7,}, | ||
117 | {"88pm860x-regulator", 8,}, | ||
118 | {"88pm860x-regulator", 9,}, | ||
119 | {"88pm860x-regulator", 10,}, | ||
120 | {"88pm860x-regulator", 11,}, | ||
121 | {"88pm860x-regulator", 12,}, | ||
122 | {"88pm860x-regulator", 13,}, | ||
123 | {"88pm860x-regulator", 14,}, | ||
124 | {"88pm860x-regulator", 15,}, | ||
125 | {"88pm860x-regulator", 16,}, | ||
126 | {"88pm860x-regulator", 17,}, | ||
159 | }; | 127 | }; |
160 | 128 | ||
161 | static struct resource codec_resources[] = { | 129 | static struct mfd_cell touch_devs[] __initdata = { |
162 | { | 130 | {"88pm860x-touch", -1,}, |
163 | /* Headset microphone insertion or removal */ | ||
164 | .name = "micin", | ||
165 | .start = PM8607_IRQ_MICIN, | ||
166 | .end = PM8607_IRQ_MICIN, | ||
167 | .flags = IORESOURCE_IRQ, | ||
168 | }, { | ||
169 | /* Hook-switch press or release */ | ||
170 | .name = "hook", | ||
171 | .start = PM8607_IRQ_HOOK, | ||
172 | .end = PM8607_IRQ_HOOK, | ||
173 | .flags = IORESOURCE_IRQ, | ||
174 | }, { | ||
175 | /* Headset insertion or removal */ | ||
176 | .name = "headset", | ||
177 | .start = PM8607_IRQ_HEADSET, | ||
178 | .end = PM8607_IRQ_HEADSET, | ||
179 | .flags = IORESOURCE_IRQ, | ||
180 | }, { | ||
181 | /* Audio short */ | ||
182 | .name = "audio-short", | ||
183 | .start = PM8607_IRQ_AUDIO_SHORT, | ||
184 | .end = PM8607_IRQ_AUDIO_SHORT, | ||
185 | .flags = IORESOURCE_IRQ, | ||
186 | }, | ||
187 | }; | 131 | }; |
188 | 132 | ||
189 | static struct mfd_cell codec_devs[] = { | 133 | static struct mfd_cell onkey_devs[] __initdata = { |
190 | { | 134 | {"88pm860x-onkey", -1,}, |
191 | .name = "88pm860x-codec", | ||
192 | .num_resources = ARRAY_SIZE(codec_resources), | ||
193 | .resources = &codec_resources[0], | ||
194 | .id = -1, | ||
195 | }, | ||
196 | }; | 135 | }; |
197 | 136 | ||
198 | static struct resource regulator_resources[] = { | 137 | static struct mfd_cell codec_devs[] __initdata = { |
199 | PM8607_REG_RESOURCE(BUCK1, BUCK1), | 138 | {"88pm860x-codec", -1,}, |
200 | PM8607_REG_RESOURCE(BUCK2, BUCK2), | ||
201 | PM8607_REG_RESOURCE(BUCK3, BUCK3), | ||
202 | PM8607_REG_RESOURCE(LDO1, LDO1), | ||
203 | PM8607_REG_RESOURCE(LDO2, LDO2), | ||
204 | PM8607_REG_RESOURCE(LDO3, LDO3), | ||
205 | PM8607_REG_RESOURCE(LDO4, LDO4), | ||
206 | PM8607_REG_RESOURCE(LDO5, LDO5), | ||
207 | PM8607_REG_RESOURCE(LDO6, LDO6), | ||
208 | PM8607_REG_RESOURCE(LDO7, LDO7), | ||
209 | PM8607_REG_RESOURCE(LDO8, LDO8), | ||
210 | PM8607_REG_RESOURCE(LDO9, LDO9), | ||
211 | PM8607_REG_RESOURCE(LDO10, LDO10), | ||
212 | PM8607_REG_RESOURCE(LDO12, LDO12), | ||
213 | PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET), | ||
214 | PM8607_REG_RESOURCE(LDO14, LDO14), | ||
215 | }; | 139 | }; |
216 | 140 | ||
217 | #define PM8607_REG_DEVS(_id) \ | 141 | static struct mfd_cell power_devs[] = { |
218 | { \ | 142 | {"88pm860x-battery", -1,}, |
219 | .name = "88pm860x-regulator", \ | 143 | {"88pm860x-charger", -1,}, |
220 | .num_resources = 1, \ | ||
221 | .resources = ®ulator_resources[PM8607_ID_##_id], \ | ||
222 | .id = PM8607_ID_##_id, \ | ||
223 | } | ||
224 | |||
225 | static struct mfd_cell regulator_devs[] = { | ||
226 | PM8607_REG_DEVS(BUCK1), | ||
227 | PM8607_REG_DEVS(BUCK2), | ||
228 | PM8607_REG_DEVS(BUCK3), | ||
229 | PM8607_REG_DEVS(LDO1), | ||
230 | PM8607_REG_DEVS(LDO2), | ||
231 | PM8607_REG_DEVS(LDO3), | ||
232 | PM8607_REG_DEVS(LDO4), | ||
233 | PM8607_REG_DEVS(LDO5), | ||
234 | PM8607_REG_DEVS(LDO6), | ||
235 | PM8607_REG_DEVS(LDO7), | ||
236 | PM8607_REG_DEVS(LDO8), | ||
237 | PM8607_REG_DEVS(LDO9), | ||
238 | PM8607_REG_DEVS(LDO10), | ||
239 | PM8607_REG_DEVS(LDO12), | ||
240 | PM8607_REG_DEVS(LDO13), | ||
241 | PM8607_REG_DEVS(LDO14), | ||
242 | }; | 144 | }; |
243 | 145 | ||
146 | static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; | ||
147 | static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)]; | ||
148 | static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)]; | ||
149 | static struct pm860x_touch_pdata touch_pdata; | ||
150 | static struct pm860x_power_pdata power_pdata; | ||
151 | |||
244 | struct pm860x_irq_data { | 152 | struct pm860x_irq_data { |
245 | int reg; | 153 | int reg; |
246 | int mask_reg; | 154 | int mask_reg; |
@@ -595,37 +503,212 @@ static void device_irq_exit(struct pm860x_chip *chip) | |||
595 | free_irq(chip->core_irq, chip); | 503 | free_irq(chip->core_irq, chip); |
596 | } | 504 | } |
597 | 505 | ||
598 | static void __devinit device_8606_init(struct pm860x_chip *chip, | 506 | static void __devinit device_bk_init(struct pm860x_chip *chip, |
599 | struct i2c_client *i2c, | 507 | struct i2c_client *i2c, |
600 | struct pm860x_platform_data *pdata) | 508 | struct pm860x_platform_data *pdata) |
601 | { | 509 | { |
602 | int ret; | 510 | int ret; |
511 | int i, j, id; | ||
512 | |||
513 | if ((pdata == NULL) || (pdata->backlight == NULL)) | ||
514 | return; | ||
515 | |||
516 | if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) | ||
517 | pdata->num_backlights = ARRAY_SIZE(bk_devs); | ||
518 | |||
519 | for (i = 0; i < pdata->num_backlights; i++) { | ||
520 | memcpy(&bk_pdata[i], &pdata->backlight[i], | ||
521 | sizeof(struct pm860x_backlight_pdata)); | ||
522 | bk_devs[i].mfd_data = &bk_pdata[i]; | ||
523 | |||
524 | for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { | ||
525 | id = bk_resources[j].start; | ||
526 | if (bk_pdata[i].flags != id) | ||
527 | continue; | ||
528 | |||
529 | bk_devs[i].num_resources = 1; | ||
530 | bk_devs[i].resources = &bk_resources[j]; | ||
531 | ret = mfd_add_devices(chip->dev, 0, | ||
532 | &bk_devs[i], 1, | ||
533 | &bk_resources[j], 0); | ||
534 | if (ret < 0) { | ||
535 | dev_err(chip->dev, "Failed to add " | ||
536 | "backlight subdev\n"); | ||
537 | return; | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | } | ||
603 | 542 | ||
604 | if (pdata && pdata->backlight) { | 543 | static void __devinit device_led_init(struct pm860x_chip *chip, |
605 | ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], | 544 | struct i2c_client *i2c, |
606 | ARRAY_SIZE(backlight_devs), | 545 | struct pm860x_platform_data *pdata) |
607 | &backlight_resources[0], 0); | 546 | { |
608 | if (ret < 0) { | 547 | int ret; |
609 | dev_err(chip->dev, "Failed to add backlight " | 548 | int i, j, id; |
610 | "subdev\n"); | 549 | |
611 | goto out_dev; | 550 | if ((pdata == NULL) || (pdata->led == NULL)) |
551 | return; | ||
552 | |||
553 | if (pdata->num_leds > ARRAY_SIZE(led_devs)) | ||
554 | pdata->num_leds = ARRAY_SIZE(led_devs); | ||
555 | |||
556 | for (i = 0; i < pdata->num_leds; i++) { | ||
557 | memcpy(&led_pdata[i], &pdata->led[i], | ||
558 | sizeof(struct pm860x_led_pdata)); | ||
559 | led_devs[i].mfd_data = &led_pdata[i]; | ||
560 | |||
561 | for (j = 0; j < ARRAY_SIZE(led_devs); j++) { | ||
562 | id = led_resources[j].start; | ||
563 | if (led_pdata[i].flags != id) | ||
564 | continue; | ||
565 | |||
566 | led_devs[i].num_resources = 1; | ||
567 | led_devs[i].resources = &led_resources[j], | ||
568 | ret = mfd_add_devices(chip->dev, 0, | ||
569 | &led_devs[i], 1, | ||
570 | &led_resources[j], 0); | ||
571 | if (ret < 0) { | ||
572 | dev_err(chip->dev, "Failed to add " | ||
573 | "led subdev\n"); | ||
574 | return; | ||
575 | } | ||
612 | } | 576 | } |
613 | } | 577 | } |
578 | } | ||
614 | 579 | ||
615 | if (pdata && pdata->led) { | 580 | static void __devinit device_regulator_init(struct pm860x_chip *chip, |
616 | ret = mfd_add_devices(chip->dev, 0, &led_devs[0], | 581 | struct i2c_client *i2c, |
617 | ARRAY_SIZE(led_devs), | 582 | struct pm860x_platform_data *pdata) |
618 | &led_resources[0], 0); | 583 | { |
584 | struct regulator_init_data *initdata; | ||
585 | int ret; | ||
586 | int i, j; | ||
587 | |||
588 | if ((pdata == NULL) || (pdata->regulator == NULL)) | ||
589 | return; | ||
590 | |||
591 | if (pdata->num_regulators > ARRAY_SIZE(regulator_devs)) | ||
592 | pdata->num_regulators = ARRAY_SIZE(regulator_devs); | ||
593 | |||
594 | for (i = 0, j = -1; i < pdata->num_regulators; i++) { | ||
595 | initdata = &pdata->regulator[i]; | ||
596 | if (strstr(initdata->constraints.name, "BUCK")) { | ||
597 | sscanf(initdata->constraints.name, "BUCK%d", &j); | ||
598 | /* BUCK1 ~ BUCK3 */ | ||
599 | if ((j < 1) || (j > 3)) { | ||
600 | dev_err(chip->dev, "Failed to add constraint " | ||
601 | "(%s)\n", initdata->constraints.name); | ||
602 | goto out; | ||
603 | } | ||
604 | j = (j - 1) + PM8607_ID_BUCK1; | ||
605 | } | ||
606 | if (strstr(initdata->constraints.name, "LDO")) { | ||
607 | sscanf(initdata->constraints.name, "LDO%d", &j); | ||
608 | /* LDO1 ~ LDO15 */ | ||
609 | if ((j < 1) || (j > 15)) { | ||
610 | dev_err(chip->dev, "Failed to add constraint " | ||
611 | "(%s)\n", initdata->constraints.name); | ||
612 | goto out; | ||
613 | } | ||
614 | j = (j - 1) + PM8607_ID_LDO1; | ||
615 | } | ||
616 | if (j == -1) { | ||
617 | dev_err(chip->dev, "Failed to add constraint (%s)\n", | ||
618 | initdata->constraints.name); | ||
619 | goto out; | ||
620 | } | ||
621 | memcpy(®ulator_pdata[i], &pdata->regulator[i], | ||
622 | sizeof(struct regulator_init_data)); | ||
623 | regulator_devs[i].mfd_data = ®ulator_pdata[i]; | ||
624 | regulator_devs[i].num_resources = 1; | ||
625 | regulator_devs[i].resources = ®ulator_resources[j]; | ||
626 | |||
627 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, | ||
628 | ®ulator_resources[j], 0); | ||
619 | if (ret < 0) { | 629 | if (ret < 0) { |
620 | dev_err(chip->dev, "Failed to add led " | 630 | dev_err(chip->dev, "Failed to add regulator subdev\n"); |
621 | "subdev\n"); | 631 | goto out; |
622 | goto out_dev; | ||
623 | } | 632 | } |
624 | } | 633 | } |
634 | out: | ||
625 | return; | 635 | return; |
626 | out_dev: | 636 | } |
627 | mfd_remove_devices(chip->dev); | 637 | |
628 | device_irq_exit(chip); | 638 | static void __devinit device_touch_init(struct pm860x_chip *chip, |
639 | struct i2c_client *i2c, | ||
640 | struct pm860x_platform_data *pdata) | ||
641 | { | ||
642 | int ret; | ||
643 | |||
644 | if ((pdata == NULL) || (pdata->touch == NULL)) | ||
645 | return; | ||
646 | |||
647 | memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata)); | ||
648 | touch_devs[0].mfd_data = &touch_pdata; | ||
649 | touch_devs[0].num_resources = ARRAY_SIZE(touch_resources); | ||
650 | touch_devs[0].resources = &touch_resources[0]; | ||
651 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], | ||
652 | ARRAY_SIZE(touch_devs), &touch_resources[0], | ||
653 | chip->irq_base); | ||
654 | if (ret < 0) | ||
655 | dev_err(chip->dev, "Failed to add touch subdev\n"); | ||
656 | } | ||
657 | |||
658 | static void __devinit device_power_init(struct pm860x_chip *chip, | ||
659 | struct i2c_client *i2c, | ||
660 | struct pm860x_platform_data *pdata) | ||
661 | { | ||
662 | int ret; | ||
663 | |||
664 | if ((pdata == NULL) || (pdata->power == NULL)) | ||
665 | return; | ||
666 | |||
667 | memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata)); | ||
668 | power_devs[0].mfd_data = &power_pdata; | ||
669 | power_devs[0].num_resources = ARRAY_SIZE(battery_resources); | ||
670 | power_devs[0].resources = &battery_resources[0], | ||
671 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, | ||
672 | &battery_resources[0], chip->irq_base); | ||
673 | if (ret < 0) | ||
674 | dev_err(chip->dev, "Failed to add battery subdev\n"); | ||
675 | |||
676 | power_devs[1].mfd_data = &power_pdata; | ||
677 | power_devs[1].num_resources = ARRAY_SIZE(charger_resources); | ||
678 | power_devs[1].resources = &charger_resources[0], | ||
679 | ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, | ||
680 | &charger_resources[0], chip->irq_base); | ||
681 | if (ret < 0) | ||
682 | dev_err(chip->dev, "Failed to add charger subdev\n"); | ||
683 | } | ||
684 | |||
685 | static void __devinit device_onkey_init(struct pm860x_chip *chip, | ||
686 | struct i2c_client *i2c, | ||
687 | struct pm860x_platform_data *pdata) | ||
688 | { | ||
689 | int ret; | ||
690 | |||
691 | onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources); | ||
692 | onkey_devs[0].resources = &onkey_resources[0], | ||
693 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], | ||
694 | ARRAY_SIZE(onkey_devs), &onkey_resources[0], | ||
695 | chip->irq_base); | ||
696 | if (ret < 0) | ||
697 | dev_err(chip->dev, "Failed to add onkey subdev\n"); | ||
698 | } | ||
699 | |||
700 | static void __devinit device_codec_init(struct pm860x_chip *chip, | ||
701 | struct i2c_client *i2c, | ||
702 | struct pm860x_platform_data *pdata) | ||
703 | { | ||
704 | int ret; | ||
705 | |||
706 | codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); | ||
707 | codec_devs[0].resources = &codec_resources[0], | ||
708 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], | ||
709 | ARRAY_SIZE(codec_devs), &codec_resources[0], 0); | ||
710 | if (ret < 0) | ||
711 | dev_err(chip->dev, "Failed to add codec subdev\n"); | ||
629 | } | 712 | } |
630 | 713 | ||
631 | static void __devinit device_8607_init(struct pm860x_chip *chip, | 714 | static void __devinit device_8607_init(struct pm860x_chip *chip, |
@@ -683,55 +766,11 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, | |||
683 | if (ret < 0) | 766 | if (ret < 0) |
684 | goto out; | 767 | goto out; |
685 | 768 | ||
686 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], | 769 | device_regulator_init(chip, i2c, pdata); |
687 | ARRAY_SIZE(regulator_devs), | 770 | device_onkey_init(chip, i2c, pdata); |
688 | ®ulator_resources[0], 0); | 771 | device_touch_init(chip, i2c, pdata); |
689 | if (ret < 0) { | 772 | device_power_init(chip, i2c, pdata); |
690 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | 773 | device_codec_init(chip, i2c, pdata); |
691 | goto out_dev; | ||
692 | } | ||
693 | |||
694 | if (pdata && pdata->touch) { | ||
695 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], | ||
696 | ARRAY_SIZE(touch_devs), | ||
697 | &touch_resources[0], 0); | ||
698 | if (ret < 0) { | ||
699 | dev_err(chip->dev, "Failed to add touch " | ||
700 | "subdev\n"); | ||
701 | goto out_dev; | ||
702 | } | ||
703 | } | ||
704 | |||
705 | if (pdata && pdata->power) { | ||
706 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], | ||
707 | ARRAY_SIZE(power_devs), | ||
708 | &power_supply_resources[0], 0); | ||
709 | if (ret < 0) { | ||
710 | dev_err(chip->dev, "Failed to add power supply " | ||
711 | "subdev\n"); | ||
712 | goto out_dev; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], | ||
717 | ARRAY_SIZE(onkey_devs), | ||
718 | &onkey_resources[0], 0); | ||
719 | if (ret < 0) { | ||
720 | dev_err(chip->dev, "Failed to add onkey subdev\n"); | ||
721 | goto out_dev; | ||
722 | } | ||
723 | |||
724 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], | ||
725 | ARRAY_SIZE(codec_devs), | ||
726 | &codec_resources[0], 0); | ||
727 | if (ret < 0) { | ||
728 | dev_err(chip->dev, "Failed to add codec subdev\n"); | ||
729 | goto out_dev; | ||
730 | } | ||
731 | return; | ||
732 | out_dev: | ||
733 | mfd_remove_devices(chip->dev); | ||
734 | device_irq_exit(chip); | ||
735 | out: | 774 | out: |
736 | return; | 775 | return; |
737 | } | 776 | } |
@@ -743,7 +782,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, | |||
743 | 782 | ||
744 | switch (chip->id) { | 783 | switch (chip->id) { |
745 | case CHIP_PM8606: | 784 | case CHIP_PM8606: |
746 | device_8606_init(chip, chip->client, pdata); | 785 | device_bk_init(chip, chip->client, pdata); |
786 | device_led_init(chip, chip->client, pdata); | ||
747 | break; | 787 | break; |
748 | case CHIP_PM8607: | 788 | case CHIP_PM8607: |
749 | device_8607_init(chip, chip->client, pdata); | 789 | device_8607_init(chip, chip->client, pdata); |
@@ -753,7 +793,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, | |||
753 | if (chip->companion) { | 793 | if (chip->companion) { |
754 | switch (chip->id) { | 794 | switch (chip->id) { |
755 | case CHIP_PM8607: | 795 | case CHIP_PM8607: |
756 | device_8606_init(chip, chip->companion, pdata); | 796 | device_bk_init(chip, chip->companion, pdata); |
797 | device_led_init(chip, chip->companion, pdata); | ||
757 | break; | 798 | break; |
758 | case CHIP_PM8606: | 799 | case CHIP_PM8606: |
759 | device_8607_init(chip, chip->companion, pdata); | 800 | device_8607_init(chip, chip->companion, pdata); |
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index bc02e6b21608..e017dc88622a 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c | |||
@@ -126,6 +126,109 @@ out: | |||
126 | } | 126 | } |
127 | EXPORT_SYMBOL(pm860x_set_bits); | 127 | EXPORT_SYMBOL(pm860x_set_bits); |
128 | 128 | ||
129 | int pm860x_page_reg_read(struct i2c_client *i2c, int reg) | ||
130 | { | ||
131 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
132 | unsigned char zero = 0; | ||
133 | unsigned char data; | ||
134 | int ret; | ||
135 | |||
136 | mutex_lock(&chip->io_lock); | ||
137 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
138 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
139 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
140 | ret = pm860x_read_device(i2c, reg, 1, &data); | ||
141 | if (ret >= 0) | ||
142 | ret = (int)data; | ||
143 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
144 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
145 | mutex_unlock(&chip->io_lock); | ||
146 | return ret; | ||
147 | } | ||
148 | EXPORT_SYMBOL(pm860x_page_reg_read); | ||
149 | |||
150 | int pm860x_page_reg_write(struct i2c_client *i2c, int reg, | ||
151 | unsigned char data) | ||
152 | { | ||
153 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
154 | unsigned char zero; | ||
155 | int ret; | ||
156 | |||
157 | mutex_lock(&chip->io_lock); | ||
158 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
159 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
160 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
161 | ret = pm860x_write_device(i2c, reg, 1, &data); | ||
162 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
163 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
164 | mutex_unlock(&chip->io_lock); | ||
165 | return ret; | ||
166 | } | ||
167 | EXPORT_SYMBOL(pm860x_page_reg_write); | ||
168 | |||
169 | int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, | ||
170 | int count, unsigned char *buf) | ||
171 | { | ||
172 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
173 | unsigned char zero = 0; | ||
174 | int ret; | ||
175 | |||
176 | mutex_lock(&chip->io_lock); | ||
177 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
178 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
179 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
180 | ret = pm860x_read_device(i2c, reg, count, buf); | ||
181 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
182 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
183 | mutex_unlock(&chip->io_lock); | ||
184 | return ret; | ||
185 | } | ||
186 | EXPORT_SYMBOL(pm860x_page_bulk_read); | ||
187 | |||
188 | int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, | ||
189 | int count, unsigned char *buf) | ||
190 | { | ||
191 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
192 | unsigned char zero = 0; | ||
193 | int ret; | ||
194 | |||
195 | mutex_lock(&chip->io_lock); | ||
196 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
197 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
198 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
199 | ret = pm860x_write_device(i2c, reg, count, buf); | ||
200 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
201 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
202 | mutex_unlock(&chip->io_lock); | ||
203 | return ret; | ||
204 | } | ||
205 | EXPORT_SYMBOL(pm860x_page_bulk_write); | ||
206 | |||
207 | int pm860x_page_set_bits(struct i2c_client *i2c, int reg, | ||
208 | unsigned char mask, unsigned char data) | ||
209 | { | ||
210 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
211 | unsigned char zero; | ||
212 | unsigned char value; | ||
213 | int ret; | ||
214 | |||
215 | mutex_lock(&chip->io_lock); | ||
216 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
217 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
218 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
219 | ret = pm860x_read_device(i2c, reg, 1, &value); | ||
220 | if (ret < 0) | ||
221 | goto out; | ||
222 | value &= ~mask; | ||
223 | value |= data; | ||
224 | ret = pm860x_write_device(i2c, reg, 1, &value); | ||
225 | out: | ||
226 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
227 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
228 | mutex_unlock(&chip->io_lock); | ||
229 | return ret; | ||
230 | } | ||
231 | EXPORT_SYMBOL(pm860x_page_set_bits); | ||
129 | 232 | ||
130 | static const struct i2c_device_id pm860x_id_table[] = { | 233 | static const struct i2c_device_id pm860x_id_table[] = { |
131 | { "88PM860x", 0 }, | 234 | { "88PM860x", 0 }, |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fdca643249e1..8d7d098f7a03 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -129,6 +129,17 @@ config UCB1400_CORE | |||
129 | To compile this driver as a module, choose M here: the | 129 | To compile this driver as a module, choose M here: the |
130 | module will be called ucb1400_core. | 130 | module will be called ucb1400_core. |
131 | 131 | ||
132 | config TPS6105X | ||
133 | tristate "TPS61050/61052 Boost Converters" | ||
134 | depends on I2C | ||
135 | select REGULATOR | ||
136 | select REGULATOR_FIXED_VOLTAGE | ||
137 | help | ||
138 | This option enables a driver for the TP61050/TPS61052 | ||
139 | high-power "white LED driver". This boost converter is | ||
140 | sometimes used for other things than white LEDs, and | ||
141 | also contains a GPIO pin. | ||
142 | |||
132 | config TPS65010 | 143 | config TPS65010 |
133 | tristate "TPS6501x Power Management chips" | 144 | tristate "TPS6501x Power Management chips" |
134 | depends on I2C && GPIOLIB | 145 | depends on I2C && GPIOLIB |
@@ -178,6 +189,16 @@ config TWL4030_CORE | |||
178 | high speed USB OTG transceiver, an audio codec (on most | 189 | high speed USB OTG transceiver, an audio codec (on most |
179 | versions) and many other features. | 190 | versions) and many other features. |
180 | 191 | ||
192 | config TWL4030_MADC | ||
193 | tristate "Texas Instruments TWL4030 MADC" | ||
194 | depends on TWL4030_CORE | ||
195 | help | ||
196 | This driver provides support for triton TWL4030-MADC. The | ||
197 | driver supports both RT and SW conversion methods. | ||
198 | |||
199 | This driver can be built as a module. If so it will be | ||
200 | named twl4030-madc | ||
201 | |||
181 | config TWL4030_POWER | 202 | config TWL4030_POWER |
182 | bool "Support power resources on TWL4030 family chips" | 203 | bool "Support power resources on TWL4030 family chips" |
183 | depends on TWL4030_CORE && ARM | 204 | depends on TWL4030_CORE && ARM |
@@ -304,6 +325,18 @@ config MFD_MAX8925 | |||
304 | accessing the device, additional drivers must be enabled in order | 325 | accessing the device, additional drivers must be enabled in order |
305 | to use the functionality of the device. | 326 | to use the functionality of the device. |
306 | 327 | ||
328 | config MFD_MAX8997 | ||
329 | bool "Maxim Semiconductor MAX8997/8966 PMIC Support" | ||
330 | depends on I2C=y && GENERIC_HARDIRQS | ||
331 | select MFD_CORE | ||
332 | help | ||
333 | Say yes here to support for Maxim Semiconductor MAX8998/8966. | ||
334 | This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, | ||
335 | MUIC controls on chip. | ||
336 | This driver provides common support for accessing the device; | ||
337 | additional drivers must be enabled in order to use the functionality | ||
338 | of the device. | ||
339 | |||
307 | config MFD_MAX8998 | 340 | config MFD_MAX8998 |
308 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" | 341 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" |
309 | depends on I2C=y && GENERIC_HARDIRQS | 342 | depends on I2C=y && GENERIC_HARDIRQS |
@@ -534,6 +567,13 @@ config AB8500_DEBUG | |||
534 | Select this option if you want debug information using the debug | 567 | Select this option if you want debug information using the debug |
535 | filesystem, debugfs. | 568 | filesystem, debugfs. |
536 | 569 | ||
570 | config AB8500_GPADC | ||
571 | bool "AB8500 GPADC driver" | ||
572 | depends on AB8500_CORE && REGULATOR_AB8500 | ||
573 | default y | ||
574 | help | ||
575 | AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage | ||
576 | |||
537 | config AB3550_CORE | 577 | config AB3550_CORE |
538 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" | 578 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" |
539 | select MFD_CORE | 579 | select MFD_CORE |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f0e25cad762e..47f5709f3828 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -33,11 +33,13 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o | |||
33 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o | 33 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o |
34 | obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o | 34 | obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o |
35 | 35 | ||
36 | obj-$(CONFIG_TPS6105X) += tps6105x.o | ||
36 | obj-$(CONFIG_TPS65010) += tps65010.o | 37 | obj-$(CONFIG_TPS65010) += tps65010.o |
37 | obj-$(CONFIG_TPS6507X) += tps6507x.o | 38 | obj-$(CONFIG_TPS6507X) += tps6507x.o |
38 | obj-$(CONFIG_MENELAUS) += menelaus.o | 39 | obj-$(CONFIG_MENELAUS) += menelaus.o |
39 | 40 | ||
40 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o | 41 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o |
42 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o | ||
41 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | 43 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o |
42 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o | 44 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o |
43 | obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o | 45 | obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o |
@@ -61,6 +63,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | |||
61 | obj-$(CONFIG_PMIC_DA903X) += da903x.o | 63 | obj-$(CONFIG_PMIC_DA903X) += da903x.o |
62 | max8925-objs := max8925-core.o max8925-i2c.o | 64 | max8925-objs := max8925-core.o max8925-i2c.o |
63 | obj-$(CONFIG_MFD_MAX8925) += max8925.o | 65 | obj-$(CONFIG_MFD_MAX8925) += max8925.o |
66 | obj-$(CONFIG_MFD_MAX8997) += max8997.o | ||
64 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o | 67 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o |
65 | 68 | ||
66 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o | 69 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o |
@@ -71,9 +74,10 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o | |||
71 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | 74 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o |
72 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 75 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
73 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o | 76 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o |
74 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o | 77 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o |
75 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o | 78 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o |
76 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o | 79 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o |
80 | obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o | ||
77 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o | 81 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
78 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o | 82 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
79 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o | 83 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 4193af5f2743..a751927047ac 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
@@ -613,7 +613,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100) | |||
613 | ab3100_get_priv.ab3100 = ab3100; | 613 | ab3100_get_priv.ab3100 = ab3100; |
614 | ab3100_get_priv.mode = false; | 614 | ab3100_get_priv.mode = false; |
615 | ab3100_get_reg_file = debugfs_create_file("get_reg", | 615 | ab3100_get_reg_file = debugfs_create_file("get_reg", |
616 | S_IWUGO, ab3100_dir, &ab3100_get_priv, | 616 | S_IWUSR, ab3100_dir, &ab3100_get_priv, |
617 | &ab3100_get_set_reg_fops); | 617 | &ab3100_get_set_reg_fops); |
618 | if (!ab3100_get_reg_file) { | 618 | if (!ab3100_get_reg_file) { |
619 | err = -ENOMEM; | 619 | err = -ENOMEM; |
@@ -623,7 +623,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100) | |||
623 | ab3100_set_priv.ab3100 = ab3100; | 623 | ab3100_set_priv.ab3100 = ab3100; |
624 | ab3100_set_priv.mode = true; | 624 | ab3100_set_priv.mode = true; |
625 | ab3100_set_reg_file = debugfs_create_file("set_reg", | 625 | ab3100_set_reg_file = debugfs_create_file("set_reg", |
626 | S_IWUGO, ab3100_dir, &ab3100_set_priv, | 626 | S_IWUSR, ab3100_dir, &ab3100_set_priv, |
627 | &ab3100_get_set_reg_fops); | 627 | &ab3100_get_set_reg_fops); |
628 | if (!ab3100_set_reg_file) { | 628 | if (!ab3100_set_reg_file) { |
629 | err = -ENOMEM; | 629 | err = -ENOMEM; |
@@ -949,10 +949,8 @@ static int __devinit ab3100_probe(struct i2c_client *client, | |||
949 | goto exit_no_ops; | 949 | goto exit_no_ops; |
950 | 950 | ||
951 | /* Set up and register the platform devices. */ | 951 | /* Set up and register the platform devices. */ |
952 | for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { | 952 | for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) |
953 | ab3100_devs[i].platform_data = ab3100_plf_data; | 953 | ab3100_devs[i].mfd_data = ab3100_plf_data; |
954 | ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data); | ||
955 | } | ||
956 | 954 | ||
957 | err = mfd_add_devices(&client->dev, 0, ab3100_devs, | 955 | err = mfd_add_devices(&client->dev, 0, ab3100_devs, |
958 | ARRAY_SIZE(ab3100_devs), NULL, 0); | 956 | ARRAY_SIZE(ab3100_devs), NULL, 0); |
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index 5fbca346b998..c12d04285226 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c | |||
@@ -1053,17 +1053,17 @@ static inline void ab3550_setup_debugfs(struct ab3550 *ab) | |||
1053 | goto exit_destroy_dir; | 1053 | goto exit_destroy_dir; |
1054 | 1054 | ||
1055 | ab3550_bank_file = debugfs_create_file("register-bank", | 1055 | ab3550_bank_file = debugfs_create_file("register-bank", |
1056 | (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_bank_fops); | 1056 | (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_bank_fops); |
1057 | if (!ab3550_bank_file) | 1057 | if (!ab3550_bank_file) |
1058 | goto exit_destroy_reg; | 1058 | goto exit_destroy_reg; |
1059 | 1059 | ||
1060 | ab3550_address_file = debugfs_create_file("register-address", | 1060 | ab3550_address_file = debugfs_create_file("register-address", |
1061 | (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_address_fops); | 1061 | (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_address_fops); |
1062 | if (!ab3550_address_file) | 1062 | if (!ab3550_address_file) |
1063 | goto exit_destroy_bank; | 1063 | goto exit_destroy_bank; |
1064 | 1064 | ||
1065 | ab3550_val_file = debugfs_create_file("register-value", | 1065 | ab3550_val_file = debugfs_create_file("register-value", |
1066 | (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_val_fops); | 1066 | (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_val_fops); |
1067 | if (!ab3550_val_file) | 1067 | if (!ab3550_val_file) |
1068 | goto exit_destroy_address; | 1068 | goto exit_destroy_address; |
1069 | 1069 | ||
@@ -1320,10 +1320,8 @@ static int __init ab3550_probe(struct i2c_client *client, | |||
1320 | goto exit_no_ops; | 1320 | goto exit_no_ops; |
1321 | 1321 | ||
1322 | /* Set up and register the platform devices. */ | 1322 | /* Set up and register the platform devices. */ |
1323 | for (i = 0; i < AB3550_NUM_DEVICES; i++) { | 1323 | for (i = 0; i < AB3550_NUM_DEVICES; i++) |
1324 | ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i]; | 1324 | ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i]; |
1325 | ab3550_devs[i].data_size = ab3550_plf_data->dev_data_sz[i]; | ||
1326 | } | ||
1327 | 1325 | ||
1328 | err = mfd_add_devices(&client->dev, 0, ab3550_devs, | 1326 | err = mfd_add_devices(&client->dev, 0, ab3550_devs, |
1329 | ARRAY_SIZE(ab3550_devs), NULL, | 1327 | ARRAY_SIZE(ab3550_devs), NULL, |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index b6887014d687..6e185b272d00 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * License Terms: GNU General Public License v2 | 4 | * License Terms: GNU General Public License v2 |
5 | * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> | 5 | * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> |
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> | 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> |
7 | * Changes: Mattias Wallin <mattias.wallin@stericsson.com> | 7 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -90,6 +90,7 @@ | |||
90 | #define AB8500_IT_MASK24_REG 0x57 | 90 | #define AB8500_IT_MASK24_REG 0x57 |
91 | 91 | ||
92 | #define AB8500_REV_REG 0x80 | 92 | #define AB8500_REV_REG 0x80 |
93 | #define AB8500_SWITCH_OFF_STATUS 0x00 | ||
93 | 94 | ||
94 | /* | 95 | /* |
95 | * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt | 96 | * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt |
@@ -652,10 +653,38 @@ static ssize_t show_chip_id(struct device *dev, | |||
652 | return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); | 653 | return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); |
653 | } | 654 | } |
654 | 655 | ||
656 | /* | ||
657 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): | ||
658 | * 0x01 Swoff bit programming | ||
659 | * 0x02 Thermal protection activation | ||
660 | * 0x04 Vbat lower then BattOk falling threshold | ||
661 | * 0x08 Watchdog expired | ||
662 | * 0x10 Non presence of 32kHz clock | ||
663 | * 0x20 Battery level lower than power on reset threshold | ||
664 | * 0x40 Power on key 1 pressed longer than 10 seconds | ||
665 | * 0x80 DB8500 thermal shutdown | ||
666 | */ | ||
667 | static ssize_t show_switch_off_status(struct device *dev, | ||
668 | struct device_attribute *attr, char *buf) | ||
669 | { | ||
670 | int ret; | ||
671 | u8 value; | ||
672 | struct ab8500 *ab8500; | ||
673 | |||
674 | ab8500 = dev_get_drvdata(dev); | ||
675 | ret = get_register_interruptible(ab8500, AB8500_RTC, | ||
676 | AB8500_SWITCH_OFF_STATUS, &value); | ||
677 | if (ret < 0) | ||
678 | return ret; | ||
679 | return sprintf(buf, "%#x\n", value); | ||
680 | } | ||
681 | |||
655 | static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); | 682 | static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); |
683 | static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); | ||
656 | 684 | ||
657 | static struct attribute *ab8500_sysfs_entries[] = { | 685 | static struct attribute *ab8500_sysfs_entries[] = { |
658 | &dev_attr_chip_id.attr, | 686 | &dev_attr_chip_id.attr, |
687 | &dev_attr_switch_off_status.attr, | ||
659 | NULL, | 688 | NULL, |
660 | }; | 689 | }; |
661 | 690 | ||
@@ -686,9 +715,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
686 | * 0x10 - Cut 1.0 | 715 | * 0x10 - Cut 1.0 |
687 | * 0x11 - Cut 1.1 | 716 | * 0x11 - Cut 1.1 |
688 | * 0x20 - Cut 2.0 | 717 | * 0x20 - Cut 2.0 |
718 | * 0x30 - Cut 3.0 | ||
689 | */ | 719 | */ |
690 | if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) { | 720 | if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 || |
691 | ab8500->revision = value; | 721 | value == 0x30) { |
692 | dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); | 722 | dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); |
693 | } else { | 723 | } else { |
694 | dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); | 724 | dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); |
@@ -696,6 +726,24 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
696 | } | 726 | } |
697 | ab8500->chip_id = value; | 727 | ab8500->chip_id = value; |
698 | 728 | ||
729 | /* | ||
730 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): | ||
731 | * 0x01 Swoff bit programming | ||
732 | * 0x02 Thermal protection activation | ||
733 | * 0x04 Vbat lower then BattOk falling threshold | ||
734 | * 0x08 Watchdog expired | ||
735 | * 0x10 Non presence of 32kHz clock | ||
736 | * 0x20 Battery level lower than power on reset threshold | ||
737 | * 0x40 Power on key 1 pressed longer than 10 seconds | ||
738 | * 0x80 DB8500 thermal shutdown | ||
739 | */ | ||
740 | |||
741 | ret = get_register_interruptible(ab8500, AB8500_RTC, | ||
742 | AB8500_SWITCH_OFF_STATUS, &value); | ||
743 | if (ret < 0) | ||
744 | return ret; | ||
745 | dev_info(ab8500->dev, "switch off status: %#x", value); | ||
746 | |||
699 | if (plat && plat->init) | 747 | if (plat && plat->init) |
700 | plat->init(ab8500); | 748 | plat->init(ab8500); |
701 | 749 | ||
@@ -764,6 +812,6 @@ int __devexit ab8500_exit(struct ab8500 *ab8500) | |||
764 | return 0; | 812 | return 0; |
765 | } | 813 | } |
766 | 814 | ||
767 | MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent"); | 815 | MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); |
768 | MODULE_DESCRIPTION("AB8500 MFD core"); | 816 | MODULE_DESCRIPTION("AB8500 MFD core"); |
769 | MODULE_LICENSE("GPL v2"); | 817 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 3c1541ae7223..64748e42ac03 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c | |||
@@ -585,18 +585,18 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf) | |||
585 | goto exit_destroy_dir; | 585 | goto exit_destroy_dir; |
586 | 586 | ||
587 | ab8500_bank_file = debugfs_create_file("register-bank", | 587 | ab8500_bank_file = debugfs_create_file("register-bank", |
588 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops); | 588 | (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops); |
589 | if (!ab8500_bank_file) | 589 | if (!ab8500_bank_file) |
590 | goto exit_destroy_reg; | 590 | goto exit_destroy_reg; |
591 | 591 | ||
592 | ab8500_address_file = debugfs_create_file("register-address", | 592 | ab8500_address_file = debugfs_create_file("register-address", |
593 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, | 593 | (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, |
594 | &ab8500_address_fops); | 594 | &ab8500_address_fops); |
595 | if (!ab8500_address_file) | 595 | if (!ab8500_address_file) |
596 | goto exit_destroy_bank; | 596 | goto exit_destroy_bank; |
597 | 597 | ||
598 | ab8500_val_file = debugfs_create_file("register-value", | 598 | ab8500_val_file = debugfs_create_file("register-value", |
599 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops); | 599 | (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops); |
600 | if (!ab8500_val_file) | 600 | if (!ab8500_val_file) |
601 | goto exit_destroy_address; | 601 | goto exit_destroy_address; |
602 | 602 | ||
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c new file mode 100644 index 000000000000..bc93b2e8230c --- /dev/null +++ b/drivers/mfd/ab8500-gpadc.c | |||
@@ -0,0 +1,614 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Author: Arun R Murthy <arun.murthy@stericsson.com> | ||
6 | * Author: Daniel Willerud <daniel.willerud@stericsson.com> | ||
7 | * Author: Johan Palsson <johan.palsson@stericsson.com> | ||
8 | */ | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/completion.h> | ||
17 | #include <linux/regulator/consumer.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/list.h> | ||
21 | #include <linux/mfd/ab8500.h> | ||
22 | #include <linux/mfd/abx500.h> | ||
23 | #include <linux/mfd/ab8500/gpadc.h> | ||
24 | |||
25 | /* | ||
26 | * GPADC register offsets | ||
27 | * Bank : 0x0A | ||
28 | */ | ||
29 | #define AB8500_GPADC_CTRL1_REG 0x00 | ||
30 | #define AB8500_GPADC_CTRL2_REG 0x01 | ||
31 | #define AB8500_GPADC_CTRL3_REG 0x02 | ||
32 | #define AB8500_GPADC_AUTO_TIMER_REG 0x03 | ||
33 | #define AB8500_GPADC_STAT_REG 0x04 | ||
34 | #define AB8500_GPADC_MANDATAL_REG 0x05 | ||
35 | #define AB8500_GPADC_MANDATAH_REG 0x06 | ||
36 | #define AB8500_GPADC_AUTODATAL_REG 0x07 | ||
37 | #define AB8500_GPADC_AUTODATAH_REG 0x08 | ||
38 | #define AB8500_GPADC_MUX_CTRL_REG 0x09 | ||
39 | |||
40 | /* | ||
41 | * OTP register offsets | ||
42 | * Bank : 0x15 | ||
43 | */ | ||
44 | #define AB8500_GPADC_CAL_1 0x0F | ||
45 | #define AB8500_GPADC_CAL_2 0x10 | ||
46 | #define AB8500_GPADC_CAL_3 0x11 | ||
47 | #define AB8500_GPADC_CAL_4 0x12 | ||
48 | #define AB8500_GPADC_CAL_5 0x13 | ||
49 | #define AB8500_GPADC_CAL_6 0x14 | ||
50 | #define AB8500_GPADC_CAL_7 0x15 | ||
51 | |||
52 | /* gpadc constants */ | ||
53 | #define EN_VINTCORE12 0x04 | ||
54 | #define EN_VTVOUT 0x02 | ||
55 | #define EN_GPADC 0x01 | ||
56 | #define DIS_GPADC 0x00 | ||
57 | #define SW_AVG_16 0x60 | ||
58 | #define ADC_SW_CONV 0x04 | ||
59 | #define EN_ICHAR 0x80 | ||
60 | #define EN_BUF 0x40 | ||
61 | #define DIS_ZERO 0x00 | ||
62 | #define GPADC_BUSY 0x01 | ||
63 | |||
64 | /* GPADC constants from AB8500 spec, UM0836 */ | ||
65 | #define ADC_RESOLUTION 1024 | ||
66 | #define ADC_CH_BTEMP_MIN 0 | ||
67 | #define ADC_CH_BTEMP_MAX 1350 | ||
68 | #define ADC_CH_DIETEMP_MIN 0 | ||
69 | #define ADC_CH_DIETEMP_MAX 1350 | ||
70 | #define ADC_CH_CHG_V_MIN 0 | ||
71 | #define ADC_CH_CHG_V_MAX 20030 | ||
72 | #define ADC_CH_ACCDET2_MIN 0 | ||
73 | #define ADC_CH_ACCDET2_MAX 2500 | ||
74 | #define ADC_CH_VBAT_MIN 2300 | ||
75 | #define ADC_CH_VBAT_MAX 4800 | ||
76 | #define ADC_CH_CHG_I_MIN 0 | ||
77 | #define ADC_CH_CHG_I_MAX 1500 | ||
78 | #define ADC_CH_BKBAT_MIN 0 | ||
79 | #define ADC_CH_BKBAT_MAX 3200 | ||
80 | |||
81 | /* This is used to not lose precision when dividing to get gain and offset */ | ||
82 | #define CALIB_SCALE 1000 | ||
83 | |||
84 | enum cal_channels { | ||
85 | ADC_INPUT_VMAIN = 0, | ||
86 | ADC_INPUT_BTEMP, | ||
87 | ADC_INPUT_VBAT, | ||
88 | NBR_CAL_INPUTS, | ||
89 | }; | ||
90 | |||
91 | /** | ||
92 | * struct adc_cal_data - Table for storing gain and offset for the calibrated | ||
93 | * ADC channels | ||
94 | * @gain: Gain of the ADC channel | ||
95 | * @offset: Offset of the ADC channel | ||
96 | */ | ||
97 | struct adc_cal_data { | ||
98 | u64 gain; | ||
99 | u64 offset; | ||
100 | }; | ||
101 | |||
102 | /** | ||
103 | * struct ab8500_gpadc - AB8500 GPADC device information | ||
104 | * @dev: pointer to the struct device | ||
105 | * @node: a list of AB8500 GPADCs, hence prepared for | ||
106 | reentrance | ||
107 | * @ab8500_gpadc_complete: pointer to the struct completion, to indicate | ||
108 | * the completion of gpadc conversion | ||
109 | * @ab8500_gpadc_lock: structure of type mutex | ||
110 | * @regu: pointer to the struct regulator | ||
111 | * @irq: interrupt number that is used by gpadc | ||
112 | * @cal_data array of ADC calibration data structs | ||
113 | */ | ||
114 | struct ab8500_gpadc { | ||
115 | struct device *dev; | ||
116 | struct list_head node; | ||
117 | struct completion ab8500_gpadc_complete; | ||
118 | struct mutex ab8500_gpadc_lock; | ||
119 | struct regulator *regu; | ||
120 | int irq; | ||
121 | struct adc_cal_data cal_data[NBR_CAL_INPUTS]; | ||
122 | }; | ||
123 | |||
124 | static LIST_HEAD(ab8500_gpadc_list); | ||
125 | |||
126 | /** | ||
127 | * ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC | ||
128 | * (i.e. the first GPADC in the instance list) | ||
129 | */ | ||
130 | struct ab8500_gpadc *ab8500_gpadc_get(char *name) | ||
131 | { | ||
132 | struct ab8500_gpadc *gpadc; | ||
133 | |||
134 | list_for_each_entry(gpadc, &ab8500_gpadc_list, node) { | ||
135 | if (!strcmp(name, dev_name(gpadc->dev))) | ||
136 | return gpadc; | ||
137 | } | ||
138 | |||
139 | return ERR_PTR(-ENOENT); | ||
140 | } | ||
141 | EXPORT_SYMBOL(ab8500_gpadc_get); | ||
142 | |||
143 | static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 input, | ||
144 | int ad_value) | ||
145 | { | ||
146 | int res; | ||
147 | |||
148 | switch (input) { | ||
149 | case MAIN_CHARGER_V: | ||
150 | /* For some reason we don't have calibrated data */ | ||
151 | if (!gpadc->cal_data[ADC_INPUT_VMAIN].gain) { | ||
152 | res = ADC_CH_CHG_V_MIN + (ADC_CH_CHG_V_MAX - | ||
153 | ADC_CH_CHG_V_MIN) * ad_value / | ||
154 | ADC_RESOLUTION; | ||
155 | break; | ||
156 | } | ||
157 | /* Here we can use the calibrated data */ | ||
158 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VMAIN].gain + | ||
159 | gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE; | ||
160 | break; | ||
161 | |||
162 | case BAT_CTRL: | ||
163 | case BTEMP_BALL: | ||
164 | case ACC_DETECT1: | ||
165 | case ADC_AUX1: | ||
166 | case ADC_AUX2: | ||
167 | /* For some reason we don't have calibrated data */ | ||
168 | if (!gpadc->cal_data[ADC_INPUT_BTEMP].gain) { | ||
169 | res = ADC_CH_BTEMP_MIN + (ADC_CH_BTEMP_MAX - | ||
170 | ADC_CH_BTEMP_MIN) * ad_value / | ||
171 | ADC_RESOLUTION; | ||
172 | break; | ||
173 | } | ||
174 | /* Here we can use the calibrated data */ | ||
175 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_BTEMP].gain + | ||
176 | gpadc->cal_data[ADC_INPUT_BTEMP].offset) / CALIB_SCALE; | ||
177 | break; | ||
178 | |||
179 | case MAIN_BAT_V: | ||
180 | /* For some reason we don't have calibrated data */ | ||
181 | if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) { | ||
182 | res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX - | ||
183 | ADC_CH_VBAT_MIN) * ad_value / | ||
184 | ADC_RESOLUTION; | ||
185 | break; | ||
186 | } | ||
187 | /* Here we can use the calibrated data */ | ||
188 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VBAT].gain + | ||
189 | gpadc->cal_data[ADC_INPUT_VBAT].offset) / CALIB_SCALE; | ||
190 | break; | ||
191 | |||
192 | case DIE_TEMP: | ||
193 | res = ADC_CH_DIETEMP_MIN + | ||
194 | (ADC_CH_DIETEMP_MAX - ADC_CH_DIETEMP_MIN) * ad_value / | ||
195 | ADC_RESOLUTION; | ||
196 | break; | ||
197 | |||
198 | case ACC_DETECT2: | ||
199 | res = ADC_CH_ACCDET2_MIN + | ||
200 | (ADC_CH_ACCDET2_MAX - ADC_CH_ACCDET2_MIN) * ad_value / | ||
201 | ADC_RESOLUTION; | ||
202 | break; | ||
203 | |||
204 | case VBUS_V: | ||
205 | res = ADC_CH_CHG_V_MIN + | ||
206 | (ADC_CH_CHG_V_MAX - ADC_CH_CHG_V_MIN) * ad_value / | ||
207 | ADC_RESOLUTION; | ||
208 | break; | ||
209 | |||
210 | case MAIN_CHARGER_C: | ||
211 | case USB_CHARGER_C: | ||
212 | res = ADC_CH_CHG_I_MIN + | ||
213 | (ADC_CH_CHG_I_MAX - ADC_CH_CHG_I_MIN) * ad_value / | ||
214 | ADC_RESOLUTION; | ||
215 | break; | ||
216 | |||
217 | case BK_BAT_V: | ||
218 | res = ADC_CH_BKBAT_MIN + | ||
219 | (ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * ad_value / | ||
220 | ADC_RESOLUTION; | ||
221 | break; | ||
222 | |||
223 | default: | ||
224 | dev_err(gpadc->dev, | ||
225 | "unknown channel, not possible to convert\n"); | ||
226 | res = -EINVAL; | ||
227 | break; | ||
228 | |||
229 | } | ||
230 | return res; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * ab8500_gpadc_convert() - gpadc conversion | ||
235 | * @input: analog input to be converted to digital data | ||
236 | * | ||
237 | * This function converts the selected analog i/p to digital | ||
238 | * data. | ||
239 | */ | ||
240 | int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) | ||
241 | { | ||
242 | int ret; | ||
243 | u16 data = 0; | ||
244 | int looplimit = 0; | ||
245 | u8 val, low_data, high_data; | ||
246 | |||
247 | if (!gpadc) | ||
248 | return -ENODEV; | ||
249 | |||
250 | mutex_lock(&gpadc->ab8500_gpadc_lock); | ||
251 | /* Enable VTVout LDO this is required for GPADC */ | ||
252 | regulator_enable(gpadc->regu); | ||
253 | |||
254 | /* Check if ADC is not busy, lock and proceed */ | ||
255 | do { | ||
256 | ret = abx500_get_register_interruptible(gpadc->dev, | ||
257 | AB8500_GPADC, AB8500_GPADC_STAT_REG, &val); | ||
258 | if (ret < 0) | ||
259 | goto out; | ||
260 | if (!(val & GPADC_BUSY)) | ||
261 | break; | ||
262 | msleep(10); | ||
263 | } while (++looplimit < 10); | ||
264 | if (looplimit >= 10 && (val & GPADC_BUSY)) { | ||
265 | dev_err(gpadc->dev, "gpadc_conversion: GPADC busy"); | ||
266 | ret = -EINVAL; | ||
267 | goto out; | ||
268 | } | ||
269 | |||
270 | /* Enable GPADC */ | ||
271 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
272 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC); | ||
273 | if (ret < 0) { | ||
274 | dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n"); | ||
275 | goto out; | ||
276 | } | ||
277 | /* Select the input source and set average samples to 16 */ | ||
278 | ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
279 | AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16)); | ||
280 | if (ret < 0) { | ||
281 | dev_err(gpadc->dev, | ||
282 | "gpadc_conversion: set avg samples failed\n"); | ||
283 | goto out; | ||
284 | } | ||
285 | /* | ||
286 | * Enable ADC, buffering, select rising edge and enable ADC path | ||
287 | * charging current sense if it needed | ||
288 | */ | ||
289 | switch (input) { | ||
290 | case MAIN_CHARGER_C: | ||
291 | case USB_CHARGER_C: | ||
292 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
293 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, | ||
294 | EN_BUF | EN_ICHAR, | ||
295 | EN_BUF | EN_ICHAR); | ||
296 | break; | ||
297 | default: | ||
298 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
299 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); | ||
300 | break; | ||
301 | } | ||
302 | if (ret < 0) { | ||
303 | dev_err(gpadc->dev, | ||
304 | "gpadc_conversion: select falling edge failed\n"); | ||
305 | goto out; | ||
306 | } | ||
307 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
308 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); | ||
309 | if (ret < 0) { | ||
310 | dev_err(gpadc->dev, | ||
311 | "gpadc_conversion: start s/w conversion failed\n"); | ||
312 | goto out; | ||
313 | } | ||
314 | /* wait for completion of conversion */ | ||
315 | if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) { | ||
316 | dev_err(gpadc->dev, | ||
317 | "timeout: didnt recieve GPADC conversion interrupt\n"); | ||
318 | ret = -EINVAL; | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | /* Read the converted RAW data */ | ||
323 | ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
324 | AB8500_GPADC_MANDATAL_REG, &low_data); | ||
325 | if (ret < 0) { | ||
326 | dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n"); | ||
327 | goto out; | ||
328 | } | ||
329 | |||
330 | ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
331 | AB8500_GPADC_MANDATAH_REG, &high_data); | ||
332 | if (ret < 0) { | ||
333 | dev_err(gpadc->dev, | ||
334 | "gpadc_conversion: read high data failed\n"); | ||
335 | goto out; | ||
336 | } | ||
337 | |||
338 | data = (high_data << 8) | low_data; | ||
339 | /* Disable GPADC */ | ||
340 | ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
341 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); | ||
342 | if (ret < 0) { | ||
343 | dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n"); | ||
344 | goto out; | ||
345 | } | ||
346 | /* Disable VTVout LDO this is required for GPADC */ | ||
347 | regulator_disable(gpadc->regu); | ||
348 | mutex_unlock(&gpadc->ab8500_gpadc_lock); | ||
349 | ret = ab8500_gpadc_ad_to_voltage(gpadc, input, data); | ||
350 | return ret; | ||
351 | |||
352 | out: | ||
353 | /* | ||
354 | * It has shown to be needed to turn off the GPADC if an error occurs, | ||
355 | * otherwise we might have problem when waiting for the busy bit in the | ||
356 | * GPADC status register to go low. In V1.1 there wait_for_completion | ||
357 | * seems to timeout when waiting for an interrupt.. Not seen in V2.0 | ||
358 | */ | ||
359 | (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
360 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); | ||
361 | regulator_disable(gpadc->regu); | ||
362 | mutex_unlock(&gpadc->ab8500_gpadc_lock); | ||
363 | dev_err(gpadc->dev, | ||
364 | "gpadc_conversion: Failed to AD convert channel %d\n", input); | ||
365 | return ret; | ||
366 | } | ||
367 | EXPORT_SYMBOL(ab8500_gpadc_convert); | ||
368 | |||
369 | /** | ||
370 | * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion | ||
371 | * @irq: irq number | ||
372 | * @data: pointer to the data passed during request irq | ||
373 | * | ||
374 | * This is a interrupt service routine for s/w gpadc conversion completion. | ||
375 | * Notifies the gpadc completion is completed and the converted raw value | ||
376 | * can be read from the registers. | ||
377 | * Returns IRQ status(IRQ_HANDLED) | ||
378 | */ | ||
379 | static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc) | ||
380 | { | ||
381 | struct ab8500_gpadc *gpadc = _gpadc; | ||
382 | |||
383 | complete(&gpadc->ab8500_gpadc_complete); | ||
384 | |||
385 | return IRQ_HANDLED; | ||
386 | } | ||
387 | |||
388 | static int otp_cal_regs[] = { | ||
389 | AB8500_GPADC_CAL_1, | ||
390 | AB8500_GPADC_CAL_2, | ||
391 | AB8500_GPADC_CAL_3, | ||
392 | AB8500_GPADC_CAL_4, | ||
393 | AB8500_GPADC_CAL_5, | ||
394 | AB8500_GPADC_CAL_6, | ||
395 | AB8500_GPADC_CAL_7, | ||
396 | }; | ||
397 | |||
398 | static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) | ||
399 | { | ||
400 | int i; | ||
401 | int ret[ARRAY_SIZE(otp_cal_regs)]; | ||
402 | u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)]; | ||
403 | |||
404 | int vmain_high, vmain_low; | ||
405 | int btemp_high, btemp_low; | ||
406 | int vbat_high, vbat_low; | ||
407 | |||
408 | /* First we read all OTP registers and store the error code */ | ||
409 | for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) { | ||
410 | ret[i] = abx500_get_register_interruptible(gpadc->dev, | ||
411 | AB8500_OTP_EMUL, otp_cal_regs[i], &gpadc_cal[i]); | ||
412 | if (ret[i] < 0) | ||
413 | dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n", | ||
414 | __func__, otp_cal_regs[i]); | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * The ADC calibration data is stored in OTP registers. | ||
419 | * The layout of the calibration data is outlined below and a more | ||
420 | * detailed description can be found in UM0836 | ||
421 | * | ||
422 | * vm_h/l = vmain_high/low | ||
423 | * bt_h/l = btemp_high/low | ||
424 | * vb_h/l = vbat_high/low | ||
425 | * | ||
426 | * Data bits: | ||
427 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
428 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
429 | * | | vm_h9 | vm_h8 | ||
430 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
431 | * | | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 | ||
432 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
433 | * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 | ||
434 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
435 | * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 | ||
436 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
437 | * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 | ||
438 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
439 | * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 | ||
440 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
441 | * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | | ||
442 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
443 | * | ||
444 | * | ||
445 | * Ideal output ADC codes corresponding to injected input voltages | ||
446 | * during manufacturing is: | ||
447 | * | ||
448 | * vmain_high: Vin = 19500mV / ADC ideal code = 997 | ||
449 | * vmain_low: Vin = 315mV / ADC ideal code = 16 | ||
450 | * btemp_high: Vin = 1300mV / ADC ideal code = 985 | ||
451 | * btemp_low: Vin = 21mV / ADC ideal code = 16 | ||
452 | * vbat_high: Vin = 4700mV / ADC ideal code = 982 | ||
453 | * vbat_low: Vin = 2380mV / ADC ideal code = 33 | ||
454 | */ | ||
455 | |||
456 | /* Calculate gain and offset for VMAIN if all reads succeeded */ | ||
457 | if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) { | ||
458 | vmain_high = (((gpadc_cal[0] & 0x03) << 8) | | ||
459 | ((gpadc_cal[1] & 0x3F) << 2) | | ||
460 | ((gpadc_cal[2] & 0xC0) >> 6)); | ||
461 | |||
462 | vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); | ||
463 | |||
464 | gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE * | ||
465 | (19500 - 315) / (vmain_high - vmain_low); | ||
466 | |||
467 | gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 - | ||
468 | (CALIB_SCALE * (19500 - 315) / | ||
469 | (vmain_high - vmain_low)) * vmain_high; | ||
470 | } else { | ||
471 | gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0; | ||
472 | } | ||
473 | |||
474 | /* Calculate gain and offset for BTEMP if all reads succeeded */ | ||
475 | if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) { | ||
476 | btemp_high = (((gpadc_cal[2] & 0x01) << 9) | | ||
477 | (gpadc_cal[3] << 1) | | ||
478 | ((gpadc_cal[4] & 0x80) >> 7)); | ||
479 | |||
480 | btemp_low = ((gpadc_cal[4] & 0x7C) >> 2); | ||
481 | |||
482 | gpadc->cal_data[ADC_INPUT_BTEMP].gain = | ||
483 | CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low); | ||
484 | |||
485 | gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 - | ||
486 | (CALIB_SCALE * (1300 - 21) / | ||
487 | (btemp_high - btemp_low)) * btemp_high; | ||
488 | } else { | ||
489 | gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0; | ||
490 | } | ||
491 | |||
492 | /* Calculate gain and offset for VBAT if all reads succeeded */ | ||
493 | if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) { | ||
494 | vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]); | ||
495 | vbat_low = ((gpadc_cal[6] & 0xFC) >> 2); | ||
496 | |||
497 | gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE * | ||
498 | (4700 - 2380) / (vbat_high - vbat_low); | ||
499 | |||
500 | gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 - | ||
501 | (CALIB_SCALE * (4700 - 2380) / | ||
502 | (vbat_high - vbat_low)) * vbat_high; | ||
503 | } else { | ||
504 | gpadc->cal_data[ADC_INPUT_VBAT].gain = 0; | ||
505 | } | ||
506 | |||
507 | dev_dbg(gpadc->dev, "VMAIN gain %llu offset %llu\n", | ||
508 | gpadc->cal_data[ADC_INPUT_VMAIN].gain, | ||
509 | gpadc->cal_data[ADC_INPUT_VMAIN].offset); | ||
510 | |||
511 | dev_dbg(gpadc->dev, "BTEMP gain %llu offset %llu\n", | ||
512 | gpadc->cal_data[ADC_INPUT_BTEMP].gain, | ||
513 | gpadc->cal_data[ADC_INPUT_BTEMP].offset); | ||
514 | |||
515 | dev_dbg(gpadc->dev, "VBAT gain %llu offset %llu\n", | ||
516 | gpadc->cal_data[ADC_INPUT_VBAT].gain, | ||
517 | gpadc->cal_data[ADC_INPUT_VBAT].offset); | ||
518 | } | ||
519 | |||
520 | static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) | ||
521 | { | ||
522 | int ret = 0; | ||
523 | struct ab8500_gpadc *gpadc; | ||
524 | |||
525 | gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL); | ||
526 | if (!gpadc) { | ||
527 | dev_err(&pdev->dev, "Error: No memory\n"); | ||
528 | return -ENOMEM; | ||
529 | } | ||
530 | |||
531 | gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END"); | ||
532 | if (gpadc->irq < 0) { | ||
533 | dev_err(gpadc->dev, "failed to get platform irq-%d\n", | ||
534 | gpadc->irq); | ||
535 | ret = gpadc->irq; | ||
536 | goto fail; | ||
537 | } | ||
538 | |||
539 | gpadc->dev = &pdev->dev; | ||
540 | mutex_init(&gpadc->ab8500_gpadc_lock); | ||
541 | |||
542 | /* Initialize completion used to notify completion of conversion */ | ||
543 | init_completion(&gpadc->ab8500_gpadc_complete); | ||
544 | |||
545 | /* Register interrupt - SwAdcComplete */ | ||
546 | ret = request_threaded_irq(gpadc->irq, NULL, | ||
547 | ab8500_bm_gpswadcconvend_handler, | ||
548 | IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc); | ||
549 | if (ret < 0) { | ||
550 | dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n", | ||
551 | gpadc->irq); | ||
552 | goto fail; | ||
553 | } | ||
554 | |||
555 | /* VTVout LDO used to power up ab8500-GPADC */ | ||
556 | gpadc->regu = regulator_get(&pdev->dev, "vddadc"); | ||
557 | if (IS_ERR(gpadc->regu)) { | ||
558 | ret = PTR_ERR(gpadc->regu); | ||
559 | dev_err(gpadc->dev, "failed to get vtvout LDO\n"); | ||
560 | goto fail_irq; | ||
561 | } | ||
562 | ab8500_gpadc_read_calibration_data(gpadc); | ||
563 | list_add_tail(&gpadc->node, &ab8500_gpadc_list); | ||
564 | dev_dbg(gpadc->dev, "probe success\n"); | ||
565 | return 0; | ||
566 | fail_irq: | ||
567 | free_irq(gpadc->irq, gpadc); | ||
568 | fail: | ||
569 | kfree(gpadc); | ||
570 | gpadc = NULL; | ||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | static int __devexit ab8500_gpadc_remove(struct platform_device *pdev) | ||
575 | { | ||
576 | struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); | ||
577 | |||
578 | /* remove this gpadc entry from the list */ | ||
579 | list_del(&gpadc->node); | ||
580 | /* remove interrupt - completion of Sw ADC conversion */ | ||
581 | free_irq(gpadc->irq, gpadc); | ||
582 | /* disable VTVout LDO that is being used by GPADC */ | ||
583 | regulator_put(gpadc->regu); | ||
584 | kfree(gpadc); | ||
585 | gpadc = NULL; | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static struct platform_driver ab8500_gpadc_driver = { | ||
590 | .probe = ab8500_gpadc_probe, | ||
591 | .remove = __devexit_p(ab8500_gpadc_remove), | ||
592 | .driver = { | ||
593 | .name = "ab8500-gpadc", | ||
594 | .owner = THIS_MODULE, | ||
595 | }, | ||
596 | }; | ||
597 | |||
598 | static int __init ab8500_gpadc_init(void) | ||
599 | { | ||
600 | return platform_driver_register(&ab8500_gpadc_driver); | ||
601 | } | ||
602 | |||
603 | static void __exit ab8500_gpadc_exit(void) | ||
604 | { | ||
605 | platform_driver_unregister(&ab8500_gpadc_driver); | ||
606 | } | ||
607 | |||
608 | subsys_initcall_sync(ab8500_gpadc_init); | ||
609 | module_exit(ab8500_gpadc_exit); | ||
610 | |||
611 | MODULE_LICENSE("GPL v2"); | ||
612 | MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson"); | ||
613 | MODULE_ALIAS("platform:ab8500_gpadc"); | ||
614 | MODULE_DESCRIPTION("AB8500 GPADC driver"); | ||
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c new file mode 100644 index 000000000000..392185965b39 --- /dev/null +++ b/drivers/mfd/ab8500-sysctrl.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson. | ||
4 | * License terms: GNU General Public License (GPL) version 2 | ||
5 | */ | ||
6 | |||
7 | #include <linux/err.h> | ||
8 | #include <linux/platform_device.h> | ||
9 | #include <linux/mfd/ab8500.h> | ||
10 | #include <linux/mfd/abx500.h> | ||
11 | #include <linux/mfd/ab8500/sysctrl.h> | ||
12 | |||
13 | static struct device *sysctrl_dev; | ||
14 | |||
15 | static inline bool valid_bank(u8 bank) | ||
16 | { | ||
17 | return ((bank == AB8500_SYS_CTRL1_BLOCK) || | ||
18 | (bank == AB8500_SYS_CTRL2_BLOCK)); | ||
19 | } | ||
20 | |||
21 | int ab8500_sysctrl_read(u16 reg, u8 *value) | ||
22 | { | ||
23 | u8 bank; | ||
24 | |||
25 | if (sysctrl_dev == NULL) | ||
26 | return -EAGAIN; | ||
27 | |||
28 | bank = (reg >> 8); | ||
29 | if (!valid_bank(bank)) | ||
30 | return -EINVAL; | ||
31 | |||
32 | return abx500_get_register_interruptible(sysctrl_dev, bank, | ||
33 | (u8)(reg & 0xFF), value); | ||
34 | } | ||
35 | |||
36 | int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value) | ||
37 | { | ||
38 | u8 bank; | ||
39 | |||
40 | if (sysctrl_dev == NULL) | ||
41 | return -EAGAIN; | ||
42 | |||
43 | bank = (reg >> 8); | ||
44 | if (!valid_bank(bank)) | ||
45 | return -EINVAL; | ||
46 | |||
47 | return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank, | ||
48 | (u8)(reg & 0xFF), mask, value); | ||
49 | } | ||
50 | |||
51 | static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev) | ||
52 | { | ||
53 | sysctrl_dev = &pdev->dev; | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev) | ||
58 | { | ||
59 | sysctrl_dev = NULL; | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static struct platform_driver ab8500_sysctrl_driver = { | ||
64 | .driver = { | ||
65 | .name = "ab8500-sysctrl", | ||
66 | .owner = THIS_MODULE, | ||
67 | }, | ||
68 | .probe = ab8500_sysctrl_probe, | ||
69 | .remove = __devexit_p(ab8500_sysctrl_remove), | ||
70 | }; | ||
71 | |||
72 | static int __init ab8500_sysctrl_init(void) | ||
73 | { | ||
74 | return platform_driver_register(&ab8500_sysctrl_driver); | ||
75 | } | ||
76 | subsys_initcall(ab8500_sysctrl_init); | ||
77 | |||
78 | MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com"); | ||
79 | MODULE_DESCRIPTION("AB8500 system control driver"); | ||
80 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 3122139b4300..f1d88483112c 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c | |||
@@ -321,27 +321,27 @@ static int __devexit adp5520_remove(struct i2c_client *client) | |||
321 | } | 321 | } |
322 | 322 | ||
323 | #ifdef CONFIG_PM | 323 | #ifdef CONFIG_PM |
324 | static int adp5520_suspend(struct i2c_client *client, | 324 | static int adp5520_suspend(struct device *dev) |
325 | pm_message_t state) | ||
326 | { | 325 | { |
326 | struct i2c_client *client = to_i2c_client(dev); | ||
327 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 327 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
328 | 328 | ||
329 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 329 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int adp5520_resume(struct i2c_client *client) | 333 | static int adp5520_resume(struct device *dev) |
334 | { | 334 | { |
335 | struct i2c_client *client = to_i2c_client(dev); | ||
335 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 336 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
336 | 337 | ||
337 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 338 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); |
338 | return 0; | 339 | return 0; |
339 | } | 340 | } |
340 | #else | ||
341 | #define adp5520_suspend NULL | ||
342 | #define adp5520_resume NULL | ||
343 | #endif | 341 | #endif |
344 | 342 | ||
343 | static SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume); | ||
344 | |||
345 | static const struct i2c_device_id adp5520_id[] = { | 345 | static const struct i2c_device_id adp5520_id[] = { |
346 | { "pmic-adp5520", ID_ADP5520 }, | 346 | { "pmic-adp5520", ID_ADP5520 }, |
347 | { "pmic-adp5501", ID_ADP5501 }, | 347 | { "pmic-adp5501", ID_ADP5501 }, |
@@ -353,11 +353,10 @@ static struct i2c_driver adp5520_driver = { | |||
353 | .driver = { | 353 | .driver = { |
354 | .name = "adp5520", | 354 | .name = "adp5520", |
355 | .owner = THIS_MODULE, | 355 | .owner = THIS_MODULE, |
356 | .pm = &adp5520_pm, | ||
356 | }, | 357 | }, |
357 | .probe = adp5520_probe, | 358 | .probe = adp5520_probe, |
358 | .remove = __devexit_p(adp5520_remove), | 359 | .remove = __devexit_p(adp5520_remove), |
359 | .suspend = adp5520_suspend, | ||
360 | .resume = adp5520_resume, | ||
361 | .id_table = adp5520_id, | 360 | .id_table = adp5520_id, |
362 | }; | 361 | }; |
363 | 362 | ||
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index c45e6305b26f..0241f08fc00d 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
@@ -682,7 +682,7 @@ static struct mfd_cell asic3_cell_ds1wm = { | |||
682 | .name = "ds1wm", | 682 | .name = "ds1wm", |
683 | .enable = ds1wm_enable, | 683 | .enable = ds1wm_enable, |
684 | .disable = ds1wm_disable, | 684 | .disable = ds1wm_disable, |
685 | .driver_data = &ds1wm_pdata, | 685 | .mfd_data = &ds1wm_pdata, |
686 | .num_resources = ARRAY_SIZE(ds1wm_resources), | 686 | .num_resources = ARRAY_SIZE(ds1wm_resources), |
687 | .resources = ds1wm_resources, | 687 | .resources = ds1wm_resources, |
688 | }; | 688 | }; |
@@ -783,7 +783,7 @@ static struct mfd_cell asic3_cell_mmc = { | |||
783 | .name = "tmio-mmc", | 783 | .name = "tmio-mmc", |
784 | .enable = asic3_mmc_enable, | 784 | .enable = asic3_mmc_enable, |
785 | .disable = asic3_mmc_disable, | 785 | .disable = asic3_mmc_disable, |
786 | .driver_data = &asic3_mmc_data, | 786 | .mfd_data = &asic3_mmc_data, |
787 | .num_resources = ARRAY_SIZE(asic3_mmc_resources), | 787 | .num_resources = ARRAY_SIZE(asic3_mmc_resources), |
788 | .resources = asic3_mmc_resources, | 788 | .resources = asic3_mmc_resources, |
789 | }; | 789 | }; |
@@ -810,9 +810,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, | |||
810 | ds1wm_resources[0].start >>= asic->bus_shift; | 810 | ds1wm_resources[0].start >>= asic->bus_shift; |
811 | ds1wm_resources[0].end >>= asic->bus_shift; | 811 | ds1wm_resources[0].end >>= asic->bus_shift; |
812 | 812 | ||
813 | asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm; | ||
814 | asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); | ||
815 | |||
816 | /* MMC */ | 813 | /* MMC */ |
817 | asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + | 814 | asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + |
818 | mem_sdio->start, 0x400 >> asic->bus_shift); | 815 | mem_sdio->start, 0x400 >> asic->bus_shift); |
@@ -824,9 +821,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, | |||
824 | asic3_mmc_resources[0].start >>= asic->bus_shift; | 821 | asic3_mmc_resources[0].start >>= asic->bus_shift; |
825 | asic3_mmc_resources[0].end >>= asic->bus_shift; | 822 | asic3_mmc_resources[0].end >>= asic->bus_shift; |
826 | 823 | ||
827 | asic3_cell_mmc.platform_data = &asic3_cell_mmc; | ||
828 | asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); | ||
829 | |||
830 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 824 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
831 | &asic3_cell_ds1wm, 1, mem, asic->irq_base); | 825 | &asic3_cell_ds1wm, 1, mem, asic->irq_base); |
832 | if (ret < 0) | 826 | if (ret < 0) |
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 59ca6f151e78..886a06871065 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c | |||
@@ -39,6 +39,37 @@ enum cs5535_mfd_bars { | |||
39 | NR_BARS, | 39 | NR_BARS, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static int cs5535_mfd_res_enable(struct platform_device *pdev) | ||
43 | { | ||
44 | struct resource *res; | ||
45 | |||
46 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
47 | if (!res) { | ||
48 | dev_err(&pdev->dev, "can't fetch device resource info\n"); | ||
49 | return -EIO; | ||
50 | } | ||
51 | |||
52 | if (!request_region(res->start, resource_size(res), DRV_NAME)) { | ||
53 | dev_err(&pdev->dev, "can't request region\n"); | ||
54 | return -EIO; | ||
55 | } | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int cs5535_mfd_res_disable(struct platform_device *pdev) | ||
61 | { | ||
62 | struct resource *res; | ||
63 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
64 | if (!res) { | ||
65 | dev_err(&pdev->dev, "can't fetch device resource info\n"); | ||
66 | return -EIO; | ||
67 | } | ||
68 | |||
69 | release_region(res->start, resource_size(res)); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
42 | static __devinitdata struct resource cs5535_mfd_resources[NR_BARS]; | 73 | static __devinitdata struct resource cs5535_mfd_resources[NR_BARS]; |
43 | 74 | ||
44 | static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { | 75 | static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { |
@@ -65,12 +96,18 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { | |||
65 | .name = "cs5535-pms", | 96 | .name = "cs5535-pms", |
66 | .num_resources = 1, | 97 | .num_resources = 1, |
67 | .resources = &cs5535_mfd_resources[PMS_BAR], | 98 | .resources = &cs5535_mfd_resources[PMS_BAR], |
99 | |||
100 | .enable = cs5535_mfd_res_enable, | ||
101 | .disable = cs5535_mfd_res_disable, | ||
68 | }, | 102 | }, |
69 | { | 103 | { |
70 | .id = ACPI_BAR, | 104 | .id = ACPI_BAR, |
71 | .name = "cs5535-acpi", | 105 | .name = "cs5535-acpi", |
72 | .num_resources = 1, | 106 | .num_resources = 1, |
73 | .resources = &cs5535_mfd_resources[ACPI_BAR], | 107 | .resources = &cs5535_mfd_resources[ACPI_BAR], |
108 | |||
109 | .enable = cs5535_mfd_res_enable, | ||
110 | .disable = cs5535_mfd_res_disable, | ||
74 | }, | 111 | }, |
75 | }; | 112 | }; |
76 | 113 | ||
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index fdd8a1b8bc67..414783b04849 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c | |||
@@ -119,12 +119,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev) | |||
119 | /* Voice codec interface client */ | 119 | /* Voice codec interface client */ |
120 | cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; | 120 | cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; |
121 | cell->name = "davinci-vcif"; | 121 | cell->name = "davinci-vcif"; |
122 | cell->driver_data = davinci_vc; | 122 | cell->mfd_data = davinci_vc; |
123 | 123 | ||
124 | /* Voice codec CQ93VC client */ | 124 | /* Voice codec CQ93VC client */ |
125 | cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; | 125 | cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; |
126 | cell->name = "cq93vc-codec"; | 126 | cell->name = "cq93vc-codec"; |
127 | cell->driver_data = davinci_vc; | 127 | cell->mfd_data = davinci_vc; |
128 | 128 | ||
129 | ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, | 129 | ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, |
130 | DAVINCI_VC_CELLS, NULL, 0); | 130 | DAVINCI_VC_CELLS, NULL, 0); |
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 7bc752272dc1..fb9770b39a32 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c | |||
@@ -117,7 +117,7 @@ static struct mfd_cell ds1wm_cell __initdata = { | |||
117 | .name = "ds1wm", | 117 | .name = "ds1wm", |
118 | .enable = ds1wm_enable, | 118 | .enable = ds1wm_enable, |
119 | .disable = ds1wm_disable, | 119 | .disable = ds1wm_disable, |
120 | .driver_data = &ds1wm_pdata, | 120 | .mfd_data = &ds1wm_pdata, |
121 | .num_resources = 2, | 121 | .num_resources = 2, |
122 | .resources = ds1wm_resources, | 122 | .resources = ds1wm_resources, |
123 | }; | 123 | }; |
@@ -165,8 +165,6 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
165 | ds1wm_pdata.clock_rate = pdata->clock_rate; | 165 | ds1wm_pdata.clock_rate = pdata->clock_rate; |
166 | /* the first 5 PASIC3 registers control the DS1WM */ | 166 | /* the first 5 PASIC3 registers control the DS1WM */ |
167 | ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; | 167 | ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; |
168 | ds1wm_cell.platform_data = &ds1wm_cell; | ||
169 | ds1wm_cell.data_size = sizeof(ds1wm_cell); | ||
170 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 168 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
171 | &ds1wm_cell, 1, r, irq); | 169 | &ds1wm_cell, 1, r, irq); |
172 | if (ret < 0) | 170 | if (ret < 0) |
@@ -174,9 +172,6 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
174 | } | 172 | } |
175 | 173 | ||
176 | if (pdata && pdata->led_pdata) { | 174 | if (pdata && pdata->led_pdata) { |
177 | led_cell.driver_data = pdata->led_pdata; | ||
178 | led_cell.platform_data = &led_cell; | ||
179 | led_cell.data_size = sizeof(ds1wm_cell); | ||
180 | ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); | 175 | ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); |
181 | if (ret < 0) | 176 | if (ret < 0) |
182 | dev_warn(dev, "failed to register LED device\n"); | 177 | dev_warn(dev, "failed to register LED device\n"); |
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 36a166bcdb08..fc4191137e90 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c | |||
@@ -86,8 +86,7 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv, | |||
86 | 86 | ||
87 | /* Add platform data */ | 87 | /* Add platform data */ |
88 | pdata->modno = modno; | 88 | pdata->modno = modno; |
89 | cell->platform_data = pdata; | 89 | cell->mfd_data = pdata; |
90 | cell->data_size = sizeof(*pdata); | ||
91 | 90 | ||
92 | /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */ | 91 | /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */ |
93 | res->flags = IORESOURCE_MEM; | 92 | res->flags = IORESOURCE_MEM; |
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 0cc59795f600..aa518b9beaf5 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c | |||
@@ -232,8 +232,6 @@ const struct mfd_cell jz4740_adc_cells[] = { | |||
232 | .name = "jz4740-hwmon", | 232 | .name = "jz4740-hwmon", |
233 | .num_resources = ARRAY_SIZE(jz4740_hwmon_resources), | 233 | .num_resources = ARRAY_SIZE(jz4740_hwmon_resources), |
234 | .resources = jz4740_hwmon_resources, | 234 | .resources = jz4740_hwmon_resources, |
235 | .platform_data = (void *)&jz4740_adc_cells[0], | ||
236 | .data_size = sizeof(struct mfd_cell), | ||
237 | 235 | ||
238 | .enable = jz4740_adc_cell_enable, | 236 | .enable = jz4740_adc_cell_enable, |
239 | .disable = jz4740_adc_cell_disable, | 237 | .disable = jz4740_adc_cell_disable, |
@@ -243,8 +241,6 @@ const struct mfd_cell jz4740_adc_cells[] = { | |||
243 | .name = "jz4740-battery", | 241 | .name = "jz4740-battery", |
244 | .num_resources = ARRAY_SIZE(jz4740_battery_resources), | 242 | .num_resources = ARRAY_SIZE(jz4740_battery_resources), |
245 | .resources = jz4740_battery_resources, | 243 | .resources = jz4740_battery_resources, |
246 | .platform_data = (void *)&jz4740_adc_cells[1], | ||
247 | .data_size = sizeof(struct mfd_cell), | ||
248 | 244 | ||
249 | .enable = jz4740_adc_cell_enable, | 245 | .enable = jz4740_adc_cell_enable, |
250 | .disable = jz4740_adc_cell_disable, | 246 | .disable = jz4740_adc_cell_disable, |
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 51b2f6065a0b..ea3f52c07ef7 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c | |||
@@ -61,6 +61,7 @@ static struct mfd_cell lpc_sch_cells[] = { | |||
61 | 61 | ||
62 | static struct pci_device_id lpc_sch_ids[] = { | 62 | static struct pci_device_id lpc_sch_ids[] = { |
63 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, | 63 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, |
64 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) }, | ||
64 | { 0, } | 65 | { 0, } |
65 | }; | 66 | }; |
66 | MODULE_DEVICE_TABLE(pci, lpc_sch_ids); | 67 | MODULE_DEVICE_TABLE(pci, lpc_sch_ids); |
@@ -70,6 +71,7 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, | |||
70 | { | 71 | { |
71 | unsigned int base_addr_cfg; | 72 | unsigned int base_addr_cfg; |
72 | unsigned short base_addr; | 73 | unsigned short base_addr; |
74 | int i; | ||
73 | 75 | ||
74 | pci_read_config_dword(dev, SMBASE, &base_addr_cfg); | 76 | pci_read_config_dword(dev, SMBASE, &base_addr_cfg); |
75 | if (!(base_addr_cfg & (1 << 31))) { | 77 | if (!(base_addr_cfg & (1 << 31))) { |
@@ -99,7 +101,10 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, | |||
99 | gpio_sch_resource.start = base_addr; | 101 | gpio_sch_resource.start = base_addr; |
100 | gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; | 102 | gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; |
101 | 103 | ||
102 | return mfd_add_devices(&dev->dev, -1, | 104 | for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++) |
105 | lpc_sch_cells[i].id = id->device; | ||
106 | |||
107 | return mfd_add_devices(&dev->dev, 0, | ||
103 | lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); | 108 | lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); |
104 | } | 109 | } |
105 | 110 | ||
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c new file mode 100644 index 000000000000..5d1fca0277ef --- /dev/null +++ b/drivers/mfd/max8997.c | |||
@@ -0,0 +1,427 @@ | |||
1 | /* | ||
2 | * max8997.c - mfd core driver for the Maxim 8966 and 8997 | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics | ||
5 | * MyungJoo Ham <myungjoo.ham@smasung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | * This driver is based on max8998.c | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/mfd/core.h> | ||
29 | #include <linux/mfd/max8997.h> | ||
30 | #include <linux/mfd/max8997-private.h> | ||
31 | |||
32 | #define I2C_ADDR_PMIC (0xCC >> 1) | ||
33 | #define I2C_ADDR_MUIC (0x4A >> 1) | ||
34 | #define I2C_ADDR_BATTERY (0x6C >> 1) | ||
35 | #define I2C_ADDR_RTC (0x0C >> 1) | ||
36 | #define I2C_ADDR_HAPTIC (0x90 >> 1) | ||
37 | |||
38 | static struct mfd_cell max8997_devs[] = { | ||
39 | { .name = "max8997-pmic", }, | ||
40 | { .name = "max8997-rtc", }, | ||
41 | { .name = "max8997-battery", }, | ||
42 | { .name = "max8997-haptic", }, | ||
43 | { .name = "max8997-muic", }, | ||
44 | { .name = "max8997-flash", }, | ||
45 | }; | ||
46 | |||
47 | int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) | ||
48 | { | ||
49 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
50 | int ret; | ||
51 | |||
52 | mutex_lock(&max8997->iolock); | ||
53 | ret = i2c_smbus_read_byte_data(i2c, reg); | ||
54 | mutex_unlock(&max8997->iolock); | ||
55 | if (ret < 0) | ||
56 | return ret; | ||
57 | |||
58 | ret &= 0xff; | ||
59 | *dest = ret; | ||
60 | return 0; | ||
61 | } | ||
62 | EXPORT_SYMBOL_GPL(max8997_read_reg); | ||
63 | |||
64 | int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf) | ||
65 | { | ||
66 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
67 | int ret; | ||
68 | |||
69 | mutex_lock(&max8997->iolock); | ||
70 | ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf); | ||
71 | mutex_unlock(&max8997->iolock); | ||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | EXPORT_SYMBOL_GPL(max8997_bulk_read); | ||
78 | |||
79 | int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value) | ||
80 | { | ||
81 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
82 | int ret; | ||
83 | |||
84 | mutex_lock(&max8997->iolock); | ||
85 | ret = i2c_smbus_write_byte_data(i2c, reg, value); | ||
86 | mutex_unlock(&max8997->iolock); | ||
87 | return ret; | ||
88 | } | ||
89 | EXPORT_SYMBOL_GPL(max8997_write_reg); | ||
90 | |||
91 | int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf) | ||
92 | { | ||
93 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
94 | int ret; | ||
95 | |||
96 | mutex_lock(&max8997->iolock); | ||
97 | ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf); | ||
98 | mutex_unlock(&max8997->iolock); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(max8997_bulk_write); | ||
105 | |||
106 | int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) | ||
107 | { | ||
108 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
109 | int ret; | ||
110 | |||
111 | mutex_lock(&max8997->iolock); | ||
112 | ret = i2c_smbus_read_byte_data(i2c, reg); | ||
113 | if (ret >= 0) { | ||
114 | u8 old_val = ret & 0xff; | ||
115 | u8 new_val = (val & mask) | (old_val & (~mask)); | ||
116 | ret = i2c_smbus_write_byte_data(i2c, reg, new_val); | ||
117 | } | ||
118 | mutex_unlock(&max8997->iolock); | ||
119 | return ret; | ||
120 | } | ||
121 | EXPORT_SYMBOL_GPL(max8997_update_reg); | ||
122 | |||
123 | static int max8997_i2c_probe(struct i2c_client *i2c, | ||
124 | const struct i2c_device_id *id) | ||
125 | { | ||
126 | struct max8997_dev *max8997; | ||
127 | struct max8997_platform_data *pdata = i2c->dev.platform_data; | ||
128 | int ret = 0; | ||
129 | |||
130 | max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL); | ||
131 | if (max8997 == NULL) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | i2c_set_clientdata(i2c, max8997); | ||
135 | max8997->dev = &i2c->dev; | ||
136 | max8997->i2c = i2c; | ||
137 | max8997->type = id->driver_data; | ||
138 | |||
139 | if (!pdata) | ||
140 | goto err; | ||
141 | |||
142 | max8997->wakeup = pdata->wakeup; | ||
143 | |||
144 | mutex_init(&max8997->iolock); | ||
145 | |||
146 | max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC); | ||
147 | i2c_set_clientdata(max8997->rtc, max8997); | ||
148 | max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); | ||
149 | i2c_set_clientdata(max8997->haptic, max8997); | ||
150 | max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); | ||
151 | i2c_set_clientdata(max8997->muic, max8997); | ||
152 | |||
153 | pm_runtime_set_active(max8997->dev); | ||
154 | |||
155 | mfd_add_devices(max8997->dev, -1, max8997_devs, | ||
156 | ARRAY_SIZE(max8997_devs), | ||
157 | NULL, 0); | ||
158 | |||
159 | /* | ||
160 | * TODO: enable others (flash, muic, rtc, battery, ...) and | ||
161 | * check the return value | ||
162 | */ | ||
163 | |||
164 | if (ret < 0) | ||
165 | goto err_mfd; | ||
166 | |||
167 | return ret; | ||
168 | |||
169 | err_mfd: | ||
170 | mfd_remove_devices(max8997->dev); | ||
171 | i2c_unregister_device(max8997->muic); | ||
172 | i2c_unregister_device(max8997->haptic); | ||
173 | i2c_unregister_device(max8997->rtc); | ||
174 | err: | ||
175 | kfree(max8997); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int max8997_i2c_remove(struct i2c_client *i2c) | ||
180 | { | ||
181 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
182 | |||
183 | mfd_remove_devices(max8997->dev); | ||
184 | i2c_unregister_device(max8997->muic); | ||
185 | i2c_unregister_device(max8997->haptic); | ||
186 | i2c_unregister_device(max8997->rtc); | ||
187 | kfree(max8997); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static const struct i2c_device_id max8997_i2c_id[] = { | ||
193 | { "max8997", TYPE_MAX8997 }, | ||
194 | { "max8966", TYPE_MAX8966 }, | ||
195 | { } | ||
196 | }; | ||
197 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); | ||
198 | |||
199 | u8 max8997_dumpaddr_pmic[] = { | ||
200 | MAX8997_REG_INT1MSK, | ||
201 | MAX8997_REG_INT2MSK, | ||
202 | MAX8997_REG_INT3MSK, | ||
203 | MAX8997_REG_INT4MSK, | ||
204 | MAX8997_REG_MAINCON1, | ||
205 | MAX8997_REG_MAINCON2, | ||
206 | MAX8997_REG_BUCKRAMP, | ||
207 | MAX8997_REG_BUCK1CTRL, | ||
208 | MAX8997_REG_BUCK1DVS1, | ||
209 | MAX8997_REG_BUCK1DVS2, | ||
210 | MAX8997_REG_BUCK1DVS3, | ||
211 | MAX8997_REG_BUCK1DVS4, | ||
212 | MAX8997_REG_BUCK1DVS5, | ||
213 | MAX8997_REG_BUCK1DVS6, | ||
214 | MAX8997_REG_BUCK1DVS7, | ||
215 | MAX8997_REG_BUCK1DVS8, | ||
216 | MAX8997_REG_BUCK2CTRL, | ||
217 | MAX8997_REG_BUCK2DVS1, | ||
218 | MAX8997_REG_BUCK2DVS2, | ||
219 | MAX8997_REG_BUCK2DVS3, | ||
220 | MAX8997_REG_BUCK2DVS4, | ||
221 | MAX8997_REG_BUCK2DVS5, | ||
222 | MAX8997_REG_BUCK2DVS6, | ||
223 | MAX8997_REG_BUCK2DVS7, | ||
224 | MAX8997_REG_BUCK2DVS8, | ||
225 | MAX8997_REG_BUCK3CTRL, | ||
226 | MAX8997_REG_BUCK3DVS, | ||
227 | MAX8997_REG_BUCK4CTRL, | ||
228 | MAX8997_REG_BUCK4DVS, | ||
229 | MAX8997_REG_BUCK5CTRL, | ||
230 | MAX8997_REG_BUCK5DVS1, | ||
231 | MAX8997_REG_BUCK5DVS2, | ||
232 | MAX8997_REG_BUCK5DVS3, | ||
233 | MAX8997_REG_BUCK5DVS4, | ||
234 | MAX8997_REG_BUCK5DVS5, | ||
235 | MAX8997_REG_BUCK5DVS6, | ||
236 | MAX8997_REG_BUCK5DVS7, | ||
237 | MAX8997_REG_BUCK5DVS8, | ||
238 | MAX8997_REG_BUCK6CTRL, | ||
239 | MAX8997_REG_BUCK6BPSKIPCTRL, | ||
240 | MAX8997_REG_BUCK7CTRL, | ||
241 | MAX8997_REG_BUCK7DVS, | ||
242 | MAX8997_REG_LDO1CTRL, | ||
243 | MAX8997_REG_LDO2CTRL, | ||
244 | MAX8997_REG_LDO3CTRL, | ||
245 | MAX8997_REG_LDO4CTRL, | ||
246 | MAX8997_REG_LDO5CTRL, | ||
247 | MAX8997_REG_LDO6CTRL, | ||
248 | MAX8997_REG_LDO7CTRL, | ||
249 | MAX8997_REG_LDO8CTRL, | ||
250 | MAX8997_REG_LDO9CTRL, | ||
251 | MAX8997_REG_LDO10CTRL, | ||
252 | MAX8997_REG_LDO11CTRL, | ||
253 | MAX8997_REG_LDO12CTRL, | ||
254 | MAX8997_REG_LDO13CTRL, | ||
255 | MAX8997_REG_LDO14CTRL, | ||
256 | MAX8997_REG_LDO15CTRL, | ||
257 | MAX8997_REG_LDO16CTRL, | ||
258 | MAX8997_REG_LDO17CTRL, | ||
259 | MAX8997_REG_LDO18CTRL, | ||
260 | MAX8997_REG_LDO21CTRL, | ||
261 | MAX8997_REG_MBCCTRL1, | ||
262 | MAX8997_REG_MBCCTRL2, | ||
263 | MAX8997_REG_MBCCTRL3, | ||
264 | MAX8997_REG_MBCCTRL4, | ||
265 | MAX8997_REG_MBCCTRL5, | ||
266 | MAX8997_REG_MBCCTRL6, | ||
267 | MAX8997_REG_OTPCGHCVS, | ||
268 | MAX8997_REG_SAFEOUTCTRL, | ||
269 | MAX8997_REG_LBCNFG1, | ||
270 | MAX8997_REG_LBCNFG2, | ||
271 | MAX8997_REG_BBCCTRL, | ||
272 | |||
273 | MAX8997_REG_FLASH1_CUR, | ||
274 | MAX8997_REG_FLASH2_CUR, | ||
275 | MAX8997_REG_MOVIE_CUR, | ||
276 | MAX8997_REG_GSMB_CUR, | ||
277 | MAX8997_REG_BOOST_CNTL, | ||
278 | MAX8997_REG_LEN_CNTL, | ||
279 | MAX8997_REG_FLASH_CNTL, | ||
280 | MAX8997_REG_WDT_CNTL, | ||
281 | MAX8997_REG_MAXFLASH1, | ||
282 | MAX8997_REG_MAXFLASH2, | ||
283 | MAX8997_REG_FLASHSTATUSMASK, | ||
284 | |||
285 | MAX8997_REG_GPIOCNTL1, | ||
286 | MAX8997_REG_GPIOCNTL2, | ||
287 | MAX8997_REG_GPIOCNTL3, | ||
288 | MAX8997_REG_GPIOCNTL4, | ||
289 | MAX8997_REG_GPIOCNTL5, | ||
290 | MAX8997_REG_GPIOCNTL6, | ||
291 | MAX8997_REG_GPIOCNTL7, | ||
292 | MAX8997_REG_GPIOCNTL8, | ||
293 | MAX8997_REG_GPIOCNTL9, | ||
294 | MAX8997_REG_GPIOCNTL10, | ||
295 | MAX8997_REG_GPIOCNTL11, | ||
296 | MAX8997_REG_GPIOCNTL12, | ||
297 | |||
298 | MAX8997_REG_LDO1CONFIG, | ||
299 | MAX8997_REG_LDO2CONFIG, | ||
300 | MAX8997_REG_LDO3CONFIG, | ||
301 | MAX8997_REG_LDO4CONFIG, | ||
302 | MAX8997_REG_LDO5CONFIG, | ||
303 | MAX8997_REG_LDO6CONFIG, | ||
304 | MAX8997_REG_LDO7CONFIG, | ||
305 | MAX8997_REG_LDO8CONFIG, | ||
306 | MAX8997_REG_LDO9CONFIG, | ||
307 | MAX8997_REG_LDO10CONFIG, | ||
308 | MAX8997_REG_LDO11CONFIG, | ||
309 | MAX8997_REG_LDO12CONFIG, | ||
310 | MAX8997_REG_LDO13CONFIG, | ||
311 | MAX8997_REG_LDO14CONFIG, | ||
312 | MAX8997_REG_LDO15CONFIG, | ||
313 | MAX8997_REG_LDO16CONFIG, | ||
314 | MAX8997_REG_LDO17CONFIG, | ||
315 | MAX8997_REG_LDO18CONFIG, | ||
316 | MAX8997_REG_LDO21CONFIG, | ||
317 | |||
318 | MAX8997_REG_DVSOKTIMER1, | ||
319 | MAX8997_REG_DVSOKTIMER2, | ||
320 | MAX8997_REG_DVSOKTIMER4, | ||
321 | MAX8997_REG_DVSOKTIMER5, | ||
322 | }; | ||
323 | |||
324 | u8 max8997_dumpaddr_muic[] = { | ||
325 | MAX8997_MUIC_REG_INTMASK1, | ||
326 | MAX8997_MUIC_REG_INTMASK2, | ||
327 | MAX8997_MUIC_REG_INTMASK3, | ||
328 | MAX8997_MUIC_REG_CDETCTRL, | ||
329 | MAX8997_MUIC_REG_CONTROL1, | ||
330 | MAX8997_MUIC_REG_CONTROL2, | ||
331 | MAX8997_MUIC_REG_CONTROL3, | ||
332 | }; | ||
333 | |||
334 | u8 max8997_dumpaddr_haptic[] = { | ||
335 | MAX8997_HAPTIC_REG_CONF1, | ||
336 | MAX8997_HAPTIC_REG_CONF2, | ||
337 | MAX8997_HAPTIC_REG_DRVCONF, | ||
338 | MAX8997_HAPTIC_REG_CYCLECONF1, | ||
339 | MAX8997_HAPTIC_REG_CYCLECONF2, | ||
340 | MAX8997_HAPTIC_REG_SIGCONF1, | ||
341 | MAX8997_HAPTIC_REG_SIGCONF2, | ||
342 | MAX8997_HAPTIC_REG_SIGCONF3, | ||
343 | MAX8997_HAPTIC_REG_SIGCONF4, | ||
344 | MAX8997_HAPTIC_REG_SIGDC1, | ||
345 | MAX8997_HAPTIC_REG_SIGDC2, | ||
346 | MAX8997_HAPTIC_REG_SIGPWMDC1, | ||
347 | MAX8997_HAPTIC_REG_SIGPWMDC2, | ||
348 | MAX8997_HAPTIC_REG_SIGPWMDC3, | ||
349 | MAX8997_HAPTIC_REG_SIGPWMDC4, | ||
350 | }; | ||
351 | |||
352 | static int max8997_freeze(struct device *dev) | ||
353 | { | ||
354 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
355 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
356 | int i; | ||
357 | |||
358 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++) | ||
359 | max8997_read_reg(i2c, max8997_dumpaddr_pmic[i], | ||
360 | &max8997->reg_dump[i]); | ||
361 | |||
362 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++) | ||
363 | max8997_read_reg(i2c, max8997_dumpaddr_muic[i], | ||
364 | &max8997->reg_dump[i + MAX8997_REG_PMIC_END]); | ||
365 | |||
366 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++) | ||
367 | max8997_read_reg(i2c, max8997_dumpaddr_haptic[i], | ||
368 | &max8997->reg_dump[i + MAX8997_REG_PMIC_END + | ||
369 | MAX8997_MUIC_REG_END]); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int max8997_restore(struct device *dev) | ||
375 | { | ||
376 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
377 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
378 | int i; | ||
379 | |||
380 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++) | ||
381 | max8997_write_reg(i2c, max8997_dumpaddr_pmic[i], | ||
382 | max8997->reg_dump[i]); | ||
383 | |||
384 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++) | ||
385 | max8997_write_reg(i2c, max8997_dumpaddr_muic[i], | ||
386 | max8997->reg_dump[i + MAX8997_REG_PMIC_END]); | ||
387 | |||
388 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++) | ||
389 | max8997_write_reg(i2c, max8997_dumpaddr_haptic[i], | ||
390 | max8997->reg_dump[i + MAX8997_REG_PMIC_END + | ||
391 | MAX8997_MUIC_REG_END]); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | const struct dev_pm_ops max8997_pm = { | ||
397 | .freeze = max8997_freeze, | ||
398 | .restore = max8997_restore, | ||
399 | }; | ||
400 | |||
401 | static struct i2c_driver max8997_i2c_driver = { | ||
402 | .driver = { | ||
403 | .name = "max8997", | ||
404 | .owner = THIS_MODULE, | ||
405 | .pm = &max8997_pm, | ||
406 | }, | ||
407 | .probe = max8997_i2c_probe, | ||
408 | .remove = max8997_i2c_remove, | ||
409 | .id_table = max8997_i2c_id, | ||
410 | }; | ||
411 | |||
412 | static int __init max8997_i2c_init(void) | ||
413 | { | ||
414 | return i2c_add_driver(&max8997_i2c_driver); | ||
415 | } | ||
416 | /* init early so consumer devices can complete system boot */ | ||
417 | subsys_initcall(max8997_i2c_init); | ||
418 | |||
419 | static void __exit max8997_i2c_exit(void) | ||
420 | { | ||
421 | i2c_del_driver(&max8997_i2c_driver); | ||
422 | } | ||
423 | module_exit(max8997_i2c_exit); | ||
424 | |||
425 | MODULE_DESCRIPTION("MAXIM 8997 multi-function core driver"); | ||
426 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | ||
427 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index bbfe86732602..c00214257da2 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c | |||
@@ -233,7 +233,7 @@ struct max8998_reg_dump { | |||
233 | u8 val; | 233 | u8 val; |
234 | }; | 234 | }; |
235 | #define SAVE_ITEM(x) { .addr = (x), .val = 0x0, } | 235 | #define SAVE_ITEM(x) { .addr = (x), .val = 0x0, } |
236 | struct max8998_reg_dump max8998_dump[] = { | 236 | static struct max8998_reg_dump max8998_dump[] = { |
237 | SAVE_ITEM(MAX8998_REG_IRQM1), | 237 | SAVE_ITEM(MAX8998_REG_IRQM1), |
238 | SAVE_ITEM(MAX8998_REG_IRQM2), | 238 | SAVE_ITEM(MAX8998_REG_IRQM2), |
239 | SAVE_ITEM(MAX8998_REG_IRQM3), | 239 | SAVE_ITEM(MAX8998_REG_IRQM3), |
@@ -298,7 +298,7 @@ static int max8998_restore(struct device *dev) | |||
298 | return 0; | 298 | return 0; |
299 | } | 299 | } |
300 | 300 | ||
301 | const struct dev_pm_ops max8998_pm = { | 301 | static const struct dev_pm_ops max8998_pm = { |
302 | .suspend = max8998_suspend, | 302 | .suspend = max8998_suspend, |
303 | .resume = max8998_resume, | 303 | .resume = max8998_resume, |
304 | .freeze = max8998_freeze, | 304 | .freeze = max8998_freeze, |
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index b9fcaf0004da..668634e89e81 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c | |||
@@ -683,14 +683,13 @@ out: | |||
683 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | 683 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); |
684 | 684 | ||
685 | static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | 685 | static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, |
686 | const char *format, void *pdata, size_t pdata_size) | 686 | const char *format, void *pdata) |
687 | { | 687 | { |
688 | char buf[30]; | 688 | char buf[30]; |
689 | const char *name = mc13xxx_get_chipname(mc13xxx); | 689 | const char *name = mc13xxx_get_chipname(mc13xxx); |
690 | 690 | ||
691 | struct mfd_cell cell = { | 691 | struct mfd_cell cell = { |
692 | .platform_data = pdata, | 692 | .mfd_data = pdata, |
693 | .data_size = pdata_size, | ||
694 | }; | 693 | }; |
695 | 694 | ||
696 | /* there is no asnprintf in the kernel :-( */ | 695 | /* there is no asnprintf in the kernel :-( */ |
@@ -706,7 +705,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | |||
706 | 705 | ||
707 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) | 706 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) |
708 | { | 707 | { |
709 | return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); | 708 | return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL); |
710 | } | 709 | } |
711 | 710 | ||
712 | static int mc13xxx_probe(struct spi_device *spi) | 711 | static int mc13xxx_probe(struct spi_device *spi) |
@@ -764,13 +763,8 @@ err_revision: | |||
764 | mc13xxx_add_subdevice(mc13xxx, "%s-codec"); | 763 | mc13xxx_add_subdevice(mc13xxx, "%s-codec"); |
765 | 764 | ||
766 | if (pdata->flags & MC13XXX_USE_REGULATOR) { | 765 | if (pdata->flags & MC13XXX_USE_REGULATOR) { |
767 | struct mc13xxx_regulator_platform_data regulator_pdata = { | ||
768 | .num_regulators = pdata->num_regulators, | ||
769 | .regulators = pdata->regulators, | ||
770 | }; | ||
771 | |||
772 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", | 766 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", |
773 | ®ulator_pdata, sizeof(regulator_pdata)); | 767 | &pdata->regulators); |
774 | } | 768 | } |
775 | 769 | ||
776 | if (pdata->flags & MC13XXX_USE_RTC) | 770 | if (pdata->flags & MC13XXX_USE_RTC) |
@@ -779,10 +773,8 @@ err_revision: | |||
779 | if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) | 773 | if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) |
780 | mc13xxx_add_subdevice(mc13xxx, "%s-ts"); | 774 | mc13xxx_add_subdevice(mc13xxx, "%s-ts"); |
781 | 775 | ||
782 | if (pdata->flags & MC13XXX_USE_LED) { | 776 | if (pdata->flags & MC13XXX_USE_LED) |
783 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", | 777 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds); |
784 | pdata->leds, sizeof(*pdata->leds)); | ||
785 | } | ||
786 | 778 | ||
787 | return 0; | 779 | return 0; |
788 | } | 780 | } |
@@ -811,6 +803,7 @@ static const struct spi_device_id mc13xxx_device_id[] = { | |||
811 | /* sentinel */ | 803 | /* sentinel */ |
812 | } | 804 | } |
813 | }; | 805 | }; |
806 | MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); | ||
814 | 807 | ||
815 | static struct spi_driver mc13xxx_driver = { | 808 | static struct spi_driver mc13xxx_driver = { |
816 | .id_table = mc13xxx_device_id, | 809 | .id_table = mc13xxx_device_id, |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index d83ad0f141af..79eda0264fb2 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -18,6 +18,43 @@ | |||
18 | #include <linux/pm_runtime.h> | 18 | #include <linux/pm_runtime.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | 20 | ||
21 | int mfd_cell_enable(struct platform_device *pdev) | ||
22 | { | ||
23 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
24 | int err = 0; | ||
25 | |||
26 | /* only call enable hook if the cell wasn't previously enabled */ | ||
27 | if (atomic_inc_return(cell->usage_count) == 1) | ||
28 | err = cell->enable(pdev); | ||
29 | |||
30 | /* if the enable hook failed, decrement counter to allow retries */ | ||
31 | if (err) | ||
32 | atomic_dec(cell->usage_count); | ||
33 | |||
34 | return err; | ||
35 | } | ||
36 | EXPORT_SYMBOL(mfd_cell_enable); | ||
37 | |||
38 | int mfd_cell_disable(struct platform_device *pdev) | ||
39 | { | ||
40 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
41 | int err = 0; | ||
42 | |||
43 | /* only disable if no other clients are using it */ | ||
44 | if (atomic_dec_return(cell->usage_count) == 0) | ||
45 | err = cell->disable(pdev); | ||
46 | |||
47 | /* if the disable hook failed, increment to allow retries */ | ||
48 | if (err) | ||
49 | atomic_inc(cell->usage_count); | ||
50 | |||
51 | /* sanity check; did someone call disable too many times? */ | ||
52 | WARN_ON(atomic_read(cell->usage_count) < 0); | ||
53 | |||
54 | return err; | ||
55 | } | ||
56 | EXPORT_SYMBOL(mfd_cell_disable); | ||
57 | |||
21 | static int mfd_add_device(struct device *parent, int id, | 58 | static int mfd_add_device(struct device *parent, int id, |
22 | const struct mfd_cell *cell, | 59 | const struct mfd_cell *cell, |
23 | struct resource *mem_base, | 60 | struct resource *mem_base, |
@@ -37,14 +74,10 @@ static int mfd_add_device(struct device *parent, int id, | |||
37 | goto fail_device; | 74 | goto fail_device; |
38 | 75 | ||
39 | pdev->dev.parent = parent; | 76 | pdev->dev.parent = parent; |
40 | platform_set_drvdata(pdev, cell->driver_data); | ||
41 | 77 | ||
42 | if (cell->data_size) { | 78 | ret = platform_device_add_data(pdev, cell, sizeof(*cell)); |
43 | ret = platform_device_add_data(pdev, | 79 | if (ret) |
44 | cell->platform_data, cell->data_size); | 80 | goto fail_res; |
45 | if (ret) | ||
46 | goto fail_res; | ||
47 | } | ||
48 | 81 | ||
49 | for (r = 0; r < cell->num_resources; r++) { | 82 | for (r = 0; r < cell->num_resources; r++) { |
50 | res[r].name = cell->resources[r].name; | 83 | res[r].name = cell->resources[r].name; |
@@ -100,14 +133,22 @@ fail_alloc: | |||
100 | } | 133 | } |
101 | 134 | ||
102 | int mfd_add_devices(struct device *parent, int id, | 135 | int mfd_add_devices(struct device *parent, int id, |
103 | const struct mfd_cell *cells, int n_devs, | 136 | struct mfd_cell *cells, int n_devs, |
104 | struct resource *mem_base, | 137 | struct resource *mem_base, |
105 | int irq_base) | 138 | int irq_base) |
106 | { | 139 | { |
107 | int i; | 140 | int i; |
108 | int ret = 0; | 141 | int ret = 0; |
142 | atomic_t *cnts; | ||
143 | |||
144 | /* initialize reference counting for all cells */ | ||
145 | cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL); | ||
146 | if (!cnts) | ||
147 | return -ENOMEM; | ||
109 | 148 | ||
110 | for (i = 0; i < n_devs; i++) { | 149 | for (i = 0; i < n_devs; i++) { |
150 | atomic_set(&cnts[i], 0); | ||
151 | cells[i].usage_count = &cnts[i]; | ||
111 | ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); | 152 | ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); |
112 | if (ret) | 153 | if (ret) |
113 | break; | 154 | break; |
@@ -120,17 +161,89 @@ int mfd_add_devices(struct device *parent, int id, | |||
120 | } | 161 | } |
121 | EXPORT_SYMBOL(mfd_add_devices); | 162 | EXPORT_SYMBOL(mfd_add_devices); |
122 | 163 | ||
123 | static int mfd_remove_devices_fn(struct device *dev, void *unused) | 164 | static int mfd_remove_devices_fn(struct device *dev, void *c) |
124 | { | 165 | { |
125 | platform_device_unregister(to_platform_device(dev)); | 166 | struct platform_device *pdev = to_platform_device(dev); |
167 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
168 | atomic_t **usage_count = c; | ||
169 | |||
170 | /* find the base address of usage_count pointers (for freeing) */ | ||
171 | if (!*usage_count || (cell->usage_count < *usage_count)) | ||
172 | *usage_count = cell->usage_count; | ||
173 | |||
174 | platform_device_unregister(pdev); | ||
126 | return 0; | 175 | return 0; |
127 | } | 176 | } |
128 | 177 | ||
129 | void mfd_remove_devices(struct device *parent) | 178 | void mfd_remove_devices(struct device *parent) |
130 | { | 179 | { |
131 | device_for_each_child(parent, NULL, mfd_remove_devices_fn); | 180 | atomic_t *cnts = NULL; |
181 | |||
182 | device_for_each_child(parent, &cnts, mfd_remove_devices_fn); | ||
183 | kfree(cnts); | ||
132 | } | 184 | } |
133 | EXPORT_SYMBOL(mfd_remove_devices); | 185 | EXPORT_SYMBOL(mfd_remove_devices); |
134 | 186 | ||
187 | static int add_shared_platform_device(const char *cell, const char *name) | ||
188 | { | ||
189 | struct mfd_cell cell_entry; | ||
190 | struct device *dev; | ||
191 | struct platform_device *pdev; | ||
192 | int err; | ||
193 | |||
194 | /* check if we've already registered a device (don't fail if we have) */ | ||
195 | if (bus_find_device_by_name(&platform_bus_type, NULL, name)) | ||
196 | return 0; | ||
197 | |||
198 | /* fetch the parent cell's device (should already be registered!) */ | ||
199 | dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); | ||
200 | if (!dev) { | ||
201 | printk(KERN_ERR "failed to find device for cell %s\n", cell); | ||
202 | return -ENODEV; | ||
203 | } | ||
204 | pdev = to_platform_device(dev); | ||
205 | memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry)); | ||
206 | |||
207 | WARN_ON(!cell_entry.enable); | ||
208 | |||
209 | cell_entry.name = name; | ||
210 | err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0); | ||
211 | if (err) | ||
212 | dev_err(dev, "MFD add devices failed: %d\n", err); | ||
213 | return err; | ||
214 | } | ||
215 | |||
216 | int mfd_shared_platform_driver_register(struct platform_driver *drv, | ||
217 | const char *cellname) | ||
218 | { | ||
219 | int err; | ||
220 | |||
221 | err = add_shared_platform_device(cellname, drv->driver.name); | ||
222 | if (err) | ||
223 | printk(KERN_ERR "failed to add platform device %s\n", | ||
224 | drv->driver.name); | ||
225 | |||
226 | err = platform_driver_register(drv); | ||
227 | if (err) | ||
228 | printk(KERN_ERR "failed to add platform driver %s\n", | ||
229 | drv->driver.name); | ||
230 | |||
231 | return err; | ||
232 | } | ||
233 | EXPORT_SYMBOL(mfd_shared_platform_driver_register); | ||
234 | |||
235 | void mfd_shared_platform_driver_unregister(struct platform_driver *drv) | ||
236 | { | ||
237 | struct device *dev; | ||
238 | |||
239 | dev = bus_find_device_by_name(&platform_bus_type, NULL, | ||
240 | drv->driver.name); | ||
241 | if (dev) | ||
242 | platform_device_unregister(to_platform_device(dev)); | ||
243 | |||
244 | platform_driver_unregister(drv); | ||
245 | } | ||
246 | EXPORT_SYMBOL(mfd_shared_platform_driver_unregister); | ||
247 | |||
135 | MODULE_LICENSE("GPL"); | 248 | MODULE_LICENSE("GPL"); |
136 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); | 249 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); |
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 501ce13b693e..c1306ed43e3c 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #include <linux/pm.h> | ||
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
25 | 26 | ||
26 | #include <linux/mfd/pcf50633/core.h> | 27 | #include <linux/mfd/pcf50633/core.h> |
@@ -230,27 +231,26 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | |||
230 | } | 231 | } |
231 | } | 232 | } |
232 | 233 | ||
233 | #ifdef CONFIG_PM | 234 | #ifdef CONFIG_PM_SLEEP |
234 | static int pcf50633_suspend(struct i2c_client *client, pm_message_t state) | 235 | static int pcf50633_suspend(struct device *dev) |
235 | { | 236 | { |
236 | struct pcf50633 *pcf; | 237 | struct i2c_client *client = to_i2c_client(dev); |
237 | pcf = i2c_get_clientdata(client); | 238 | struct pcf50633 *pcf = i2c_get_clientdata(client); |
238 | 239 | ||
239 | return pcf50633_irq_suspend(pcf); | 240 | return pcf50633_irq_suspend(pcf); |
240 | } | 241 | } |
241 | 242 | ||
242 | static int pcf50633_resume(struct i2c_client *client) | 243 | static int pcf50633_resume(struct device *dev) |
243 | { | 244 | { |
244 | struct pcf50633 *pcf; | 245 | struct i2c_client *client = to_i2c_client(dev); |
245 | pcf = i2c_get_clientdata(client); | 246 | struct pcf50633 *pcf = i2c_get_clientdata(client); |
246 | 247 | ||
247 | return pcf50633_irq_resume(pcf); | 248 | return pcf50633_irq_resume(pcf); |
248 | } | 249 | } |
249 | #else | ||
250 | #define pcf50633_suspend NULL | ||
251 | #define pcf50633_resume NULL | ||
252 | #endif | 250 | #endif |
253 | 251 | ||
252 | static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume); | ||
253 | |||
254 | static int __devinit pcf50633_probe(struct i2c_client *client, | 254 | static int __devinit pcf50633_probe(struct i2c_client *client, |
255 | const struct i2c_device_id *ids) | 255 | const struct i2c_device_id *ids) |
256 | { | 256 | { |
@@ -360,16 +360,16 @@ static struct i2c_device_id pcf50633_id_table[] = { | |||
360 | {"pcf50633", 0x73}, | 360 | {"pcf50633", 0x73}, |
361 | {/* end of list */} | 361 | {/* end of list */} |
362 | }; | 362 | }; |
363 | MODULE_DEVICE_TABLE(i2c, pcf50633_id_table); | ||
363 | 364 | ||
364 | static struct i2c_driver pcf50633_driver = { | 365 | static struct i2c_driver pcf50633_driver = { |
365 | .driver = { | 366 | .driver = { |
366 | .name = "pcf50633", | 367 | .name = "pcf50633", |
368 | .pm = &pcf50633_pm, | ||
367 | }, | 369 | }, |
368 | .id_table = pcf50633_id_table, | 370 | .id_table = pcf50633_id_table, |
369 | .probe = pcf50633_probe, | 371 | .probe = pcf50633_probe, |
370 | .remove = __devexit_p(pcf50633_remove), | 372 | .remove = __devexit_p(pcf50633_remove), |
371 | .suspend = pcf50633_suspend, | ||
372 | .resume = pcf50633_resume, | ||
373 | }; | 373 | }; |
374 | 374 | ||
375 | static int __init pcf50633_init(void) | 375 | static int __init pcf50633_init(void) |
diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 50922975bda3..193c940225b5 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c | |||
@@ -61,12 +61,12 @@ static struct mfd_cell rdc321x_sb_cells[] = { | |||
61 | .name = "rdc321x-wdt", | 61 | .name = "rdc321x-wdt", |
62 | .resources = rdc321x_wdt_resource, | 62 | .resources = rdc321x_wdt_resource, |
63 | .num_resources = ARRAY_SIZE(rdc321x_wdt_resource), | 63 | .num_resources = ARRAY_SIZE(rdc321x_wdt_resource), |
64 | .driver_data = &rdc321x_wdt_pdata, | 64 | .mfd_data = &rdc321x_wdt_pdata, |
65 | }, { | 65 | }, { |
66 | .name = "rdc321x-gpio", | 66 | .name = "rdc321x-gpio", |
67 | .resources = rdc321x_gpio_resources, | 67 | .resources = rdc321x_gpio_resources, |
68 | .num_resources = ARRAY_SIZE(rdc321x_gpio_resources), | 68 | .num_resources = ARRAY_SIZE(rdc321x_gpio_resources), |
69 | .driver_data = &rdc321x_gpio_pdata, | 69 | .mfd_data = &rdc321x_gpio_pdata, |
70 | }, | 70 | }, |
71 | }; | 71 | }; |
72 | 72 | ||
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index 0a7df44a93c0..53a63024bf11 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c | |||
@@ -146,9 +146,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
146 | } | 146 | } |
147 | 147 | ||
148 | memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); | 148 | memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); |
149 | priv->cell_mmc.driver_data = mmc_data; | 149 | priv->cell_mmc.mfd_data = mmc_data; |
150 | priv->cell_mmc.platform_data = &priv->cell_mmc; | ||
151 | priv->cell_mmc.data_size = sizeof(priv->cell_mmc); | ||
152 | 150 | ||
153 | platform_set_drvdata(pdev, priv); | 151 | platform_set_drvdata(pdev, priv); |
154 | 152 | ||
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 9caeb4ac6ea6..af57fc706a4c 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c | |||
@@ -170,7 +170,7 @@ static struct mfd_cell t7l66xb_cells[] = { | |||
170 | .name = "tmio-mmc", | 170 | .name = "tmio-mmc", |
171 | .enable = t7l66xb_mmc_enable, | 171 | .enable = t7l66xb_mmc_enable, |
172 | .disable = t7l66xb_mmc_disable, | 172 | .disable = t7l66xb_mmc_disable, |
173 | .driver_data = &t7166xb_mmc_data, | 173 | .mfd_data = &t7166xb_mmc_data, |
174 | .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), | 174 | .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), |
175 | .resources = t7l66xb_mmc_resources, | 175 | .resources = t7l66xb_mmc_resources, |
176 | }, | 176 | }, |
@@ -383,16 +383,7 @@ static int t7l66xb_probe(struct platform_device *dev) | |||
383 | 383 | ||
384 | t7l66xb_attach_irq(dev); | 384 | t7l66xb_attach_irq(dev); |
385 | 385 | ||
386 | t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; | 386 | t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data; |
387 | t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = | ||
388 | &t7l66xb_cells[T7L66XB_CELL_NAND]; | ||
389 | t7l66xb_cells[T7L66XB_CELL_NAND].data_size = | ||
390 | sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); | ||
391 | |||
392 | t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = | ||
393 | &t7l66xb_cells[T7L66XB_CELL_MMC]; | ||
394 | t7l66xb_cells[T7L66XB_CELL_MMC].data_size = | ||
395 | sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); | ||
396 | 387 | ||
397 | ret = mfd_add_devices(&dev->dev, dev->id, | 388 | ret = mfd_add_devices(&dev->dev, dev->id, |
398 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), | 389 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), |
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 6315f63f017d..b006f7cee952 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c | |||
@@ -131,7 +131,7 @@ static struct mfd_cell tc6387xb_cells[] = { | |||
131 | .name = "tmio-mmc", | 131 | .name = "tmio-mmc", |
132 | .enable = tc6387xb_mmc_enable, | 132 | .enable = tc6387xb_mmc_enable, |
133 | .disable = tc6387xb_mmc_disable, | 133 | .disable = tc6387xb_mmc_disable, |
134 | .driver_data = &tc6387xb_mmc_data, | 134 | .mfd_data = &tc6387xb_mmc_data, |
135 | .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), | 135 | .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), |
136 | .resources = tc6387xb_mmc_resources, | 136 | .resources = tc6387xb_mmc_resources, |
137 | }, | 137 | }, |
@@ -190,11 +190,6 @@ static int __devinit tc6387xb_probe(struct platform_device *dev) | |||
190 | 190 | ||
191 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); | 191 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); |
192 | 192 | ||
193 | tc6387xb_cells[TC6387XB_CELL_MMC].platform_data = | ||
194 | &tc6387xb_cells[TC6387XB_CELL_MMC]; | ||
195 | tc6387xb_cells[TC6387XB_CELL_MMC].data_size = | ||
196 | sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]); | ||
197 | |||
198 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, | 193 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, |
199 | ARRAY_SIZE(tc6387xb_cells), iomem, irq); | 194 | ARRAY_SIZE(tc6387xb_cells), iomem, irq); |
200 | 195 | ||
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 9a238633a54d..3d62ded86a8f 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -393,7 +393,7 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { | |||
393 | .name = "tmio-mmc", | 393 | .name = "tmio-mmc", |
394 | .enable = tc6393xb_mmc_enable, | 394 | .enable = tc6393xb_mmc_enable, |
395 | .resume = tc6393xb_mmc_resume, | 395 | .resume = tc6393xb_mmc_resume, |
396 | .driver_data = &tc6393xb_mmc_data, | 396 | .mfd_data = &tc6393xb_mmc_data, |
397 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), | 397 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), |
398 | .resources = tc6393xb_mmc_resources, | 398 | .resources = tc6393xb_mmc_resources, |
399 | }, | 399 | }, |
@@ -693,27 +693,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
693 | goto err_setup; | 693 | goto err_setup; |
694 | } | 694 | } |
695 | 695 | ||
696 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; | 696 | tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data; |
697 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = | 697 | tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data; |
698 | &tc6393xb_cells[TC6393XB_CELL_NAND]; | ||
699 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = | ||
700 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); | ||
701 | |||
702 | tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = | ||
703 | &tc6393xb_cells[TC6393XB_CELL_MMC]; | ||
704 | tc6393xb_cells[TC6393XB_CELL_MMC].data_size = | ||
705 | sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); | ||
706 | |||
707 | tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data = | ||
708 | &tc6393xb_cells[TC6393XB_CELL_OHCI]; | ||
709 | tc6393xb_cells[TC6393XB_CELL_OHCI].data_size = | ||
710 | sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]); | ||
711 | |||
712 | tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data; | ||
713 | tc6393xb_cells[TC6393XB_CELL_FB].platform_data = | ||
714 | &tc6393xb_cells[TC6393XB_CELL_FB]; | ||
715 | tc6393xb_cells[TC6393XB_CELL_FB].data_size = | ||
716 | sizeof(tc6393xb_cells[TC6393XB_CELL_FB]); | ||
717 | 698 | ||
718 | ret = mfd_add_devices(&dev->dev, dev->id, | 699 | ret = mfd_add_devices(&dev->dev, dev->id, |
719 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), | 700 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), |
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 6ad8a7f8d390..94c6c8afad12 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c | |||
@@ -384,8 +384,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { | |||
384 | .name = "timb-dma", | 384 | .name = "timb-dma", |
385 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 385 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
386 | .resources = timberdale_dma_resources, | 386 | .resources = timberdale_dma_resources, |
387 | .platform_data = &timb_dma_platform_data, | 387 | .mfd_data = &timb_dma_platform_data, |
388 | .data_size = sizeof(timb_dma_platform_data), | ||
389 | }, | 388 | }, |
390 | { | 389 | { |
391 | .name = "timb-uart", | 390 | .name = "timb-uart", |
@@ -396,43 +395,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { | |||
396 | .name = "xiic-i2c", | 395 | .name = "xiic-i2c", |
397 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), | 396 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), |
398 | .resources = timberdale_xiic_resources, | 397 | .resources = timberdale_xiic_resources, |
399 | .platform_data = &timberdale_xiic_platform_data, | 398 | .mfd_data = &timberdale_xiic_platform_data, |
400 | .data_size = sizeof(timberdale_xiic_platform_data), | ||
401 | }, | 399 | }, |
402 | { | 400 | { |
403 | .name = "timb-gpio", | 401 | .name = "timb-gpio", |
404 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 402 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
405 | .resources = timberdale_gpio_resources, | 403 | .resources = timberdale_gpio_resources, |
406 | .platform_data = &timberdale_gpio_platform_data, | 404 | .mfd_data = &timberdale_gpio_platform_data, |
407 | .data_size = sizeof(timberdale_gpio_platform_data), | ||
408 | }, | 405 | }, |
409 | { | 406 | { |
410 | .name = "timb-video", | 407 | .name = "timb-video", |
411 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | 408 | .num_resources = ARRAY_SIZE(timberdale_video_resources), |
412 | .resources = timberdale_video_resources, | 409 | .resources = timberdale_video_resources, |
413 | .platform_data = &timberdale_video_platform_data, | 410 | .mfd_data = &timberdale_video_platform_data, |
414 | .data_size = sizeof(timberdale_video_platform_data), | ||
415 | }, | 411 | }, |
416 | { | 412 | { |
417 | .name = "timb-radio", | 413 | .name = "timb-radio", |
418 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 414 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
419 | .resources = timberdale_radio_resources, | 415 | .resources = timberdale_radio_resources, |
420 | .platform_data = &timberdale_radio_platform_data, | 416 | .mfd_data = &timberdale_radio_platform_data, |
421 | .data_size = sizeof(timberdale_radio_platform_data), | ||
422 | }, | 417 | }, |
423 | { | 418 | { |
424 | .name = "xilinx_spi", | 419 | .name = "xilinx_spi", |
425 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 420 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
426 | .resources = timberdale_spi_resources, | 421 | .resources = timberdale_spi_resources, |
427 | .platform_data = &timberdale_xspi_platform_data, | 422 | .mfd_data = &timberdale_xspi_platform_data, |
428 | .data_size = sizeof(timberdale_xspi_platform_data), | ||
429 | }, | 423 | }, |
430 | { | 424 | { |
431 | .name = "ks8842", | 425 | .name = "ks8842", |
432 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 426 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
433 | .resources = timberdale_eth_resources, | 427 | .resources = timberdale_eth_resources, |
434 | .platform_data = &timberdale_ks8842_platform_data, | 428 | .mfd_data = &timberdale_ks8842_platform_data, |
435 | .data_size = sizeof(timberdale_ks8842_platform_data) | ||
436 | }, | 429 | }, |
437 | }; | 430 | }; |
438 | 431 | ||
@@ -441,8 +434,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { | |||
441 | .name = "timb-dma", | 434 | .name = "timb-dma", |
442 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 435 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
443 | .resources = timberdale_dma_resources, | 436 | .resources = timberdale_dma_resources, |
444 | .platform_data = &timb_dma_platform_data, | 437 | .mfd_data = &timb_dma_platform_data, |
445 | .data_size = sizeof(timb_dma_platform_data), | ||
446 | }, | 438 | }, |
447 | { | 439 | { |
448 | .name = "timb-uart", | 440 | .name = "timb-uart", |
@@ -458,15 +450,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { | |||
458 | .name = "xiic-i2c", | 450 | .name = "xiic-i2c", |
459 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), | 451 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), |
460 | .resources = timberdale_xiic_resources, | 452 | .resources = timberdale_xiic_resources, |
461 | .platform_data = &timberdale_xiic_platform_data, | 453 | .mfd_data = &timberdale_xiic_platform_data, |
462 | .data_size = sizeof(timberdale_xiic_platform_data), | ||
463 | }, | 454 | }, |
464 | { | 455 | { |
465 | .name = "timb-gpio", | 456 | .name = "timb-gpio", |
466 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 457 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
467 | .resources = timberdale_gpio_resources, | 458 | .resources = timberdale_gpio_resources, |
468 | .platform_data = &timberdale_gpio_platform_data, | 459 | .mfd_data = &timberdale_gpio_platform_data, |
469 | .data_size = sizeof(timberdale_gpio_platform_data), | ||
470 | }, | 460 | }, |
471 | { | 461 | { |
472 | .name = "timb-mlogicore", | 462 | .name = "timb-mlogicore", |
@@ -477,29 +467,25 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { | |||
477 | .name = "timb-video", | 467 | .name = "timb-video", |
478 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | 468 | .num_resources = ARRAY_SIZE(timberdale_video_resources), |
479 | .resources = timberdale_video_resources, | 469 | .resources = timberdale_video_resources, |
480 | .platform_data = &timberdale_video_platform_data, | 470 | .mfd_data = &timberdale_video_platform_data, |
481 | .data_size = sizeof(timberdale_video_platform_data), | ||
482 | }, | 471 | }, |
483 | { | 472 | { |
484 | .name = "timb-radio", | 473 | .name = "timb-radio", |
485 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 474 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
486 | .resources = timberdale_radio_resources, | 475 | .resources = timberdale_radio_resources, |
487 | .platform_data = &timberdale_radio_platform_data, | 476 | .mfd_data = &timberdale_radio_platform_data, |
488 | .data_size = sizeof(timberdale_radio_platform_data), | ||
489 | }, | 477 | }, |
490 | { | 478 | { |
491 | .name = "xilinx_spi", | 479 | .name = "xilinx_spi", |
492 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 480 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
493 | .resources = timberdale_spi_resources, | 481 | .resources = timberdale_spi_resources, |
494 | .platform_data = &timberdale_xspi_platform_data, | 482 | .mfd_data = &timberdale_xspi_platform_data, |
495 | .data_size = sizeof(timberdale_xspi_platform_data), | ||
496 | }, | 483 | }, |
497 | { | 484 | { |
498 | .name = "ks8842", | 485 | .name = "ks8842", |
499 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 486 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
500 | .resources = timberdale_eth_resources, | 487 | .resources = timberdale_eth_resources, |
501 | .platform_data = &timberdale_ks8842_platform_data, | 488 | .mfd_data = &timberdale_ks8842_platform_data, |
502 | .data_size = sizeof(timberdale_ks8842_platform_data) | ||
503 | }, | 489 | }, |
504 | }; | 490 | }; |
505 | 491 | ||
@@ -508,8 +494,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { | |||
508 | .name = "timb-dma", | 494 | .name = "timb-dma", |
509 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 495 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
510 | .resources = timberdale_dma_resources, | 496 | .resources = timberdale_dma_resources, |
511 | .platform_data = &timb_dma_platform_data, | 497 | .mfd_data = &timb_dma_platform_data, |
512 | .data_size = sizeof(timb_dma_platform_data), | ||
513 | }, | 498 | }, |
514 | { | 499 | { |
515 | .name = "timb-uart", | 500 | .name = "timb-uart", |
@@ -520,36 +505,31 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { | |||
520 | .name = "xiic-i2c", | 505 | .name = "xiic-i2c", |
521 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), | 506 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), |
522 | .resources = timberdale_xiic_resources, | 507 | .resources = timberdale_xiic_resources, |
523 | .platform_data = &timberdale_xiic_platform_data, | 508 | .mfd_data = &timberdale_xiic_platform_data, |
524 | .data_size = sizeof(timberdale_xiic_platform_data), | ||
525 | }, | 509 | }, |
526 | { | 510 | { |
527 | .name = "timb-gpio", | 511 | .name = "timb-gpio", |
528 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 512 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
529 | .resources = timberdale_gpio_resources, | 513 | .resources = timberdale_gpio_resources, |
530 | .platform_data = &timberdale_gpio_platform_data, | 514 | .mfd_data = &timberdale_gpio_platform_data, |
531 | .data_size = sizeof(timberdale_gpio_platform_data), | ||
532 | }, | 515 | }, |
533 | { | 516 | { |
534 | .name = "timb-video", | 517 | .name = "timb-video", |
535 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | 518 | .num_resources = ARRAY_SIZE(timberdale_video_resources), |
536 | .resources = timberdale_video_resources, | 519 | .resources = timberdale_video_resources, |
537 | .platform_data = &timberdale_video_platform_data, | 520 | .mfd_data = &timberdale_video_platform_data, |
538 | .data_size = sizeof(timberdale_video_platform_data), | ||
539 | }, | 521 | }, |
540 | { | 522 | { |
541 | .name = "timb-radio", | 523 | .name = "timb-radio", |
542 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 524 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
543 | .resources = timberdale_radio_resources, | 525 | .resources = timberdale_radio_resources, |
544 | .platform_data = &timberdale_radio_platform_data, | 526 | .mfd_data = &timberdale_radio_platform_data, |
545 | .data_size = sizeof(timberdale_radio_platform_data), | ||
546 | }, | 527 | }, |
547 | { | 528 | { |
548 | .name = "xilinx_spi", | 529 | .name = "xilinx_spi", |
549 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 530 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
550 | .resources = timberdale_spi_resources, | 531 | .resources = timberdale_spi_resources, |
551 | .platform_data = &timberdale_xspi_platform_data, | 532 | .mfd_data = &timberdale_xspi_platform_data, |
552 | .data_size = sizeof(timberdale_xspi_platform_data), | ||
553 | }, | 533 | }, |
554 | }; | 534 | }; |
555 | 535 | ||
@@ -558,8 +538,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { | |||
558 | .name = "timb-dma", | 538 | .name = "timb-dma", |
559 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 539 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
560 | .resources = timberdale_dma_resources, | 540 | .resources = timberdale_dma_resources, |
561 | .platform_data = &timb_dma_platform_data, | 541 | .mfd_data = &timb_dma_platform_data, |
562 | .data_size = sizeof(timb_dma_platform_data), | ||
563 | }, | 542 | }, |
564 | { | 543 | { |
565 | .name = "timb-uart", | 544 | .name = "timb-uart", |
@@ -570,43 +549,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { | |||
570 | .name = "ocores-i2c", | 549 | .name = "ocores-i2c", |
571 | .num_resources = ARRAY_SIZE(timberdale_ocores_resources), | 550 | .num_resources = ARRAY_SIZE(timberdale_ocores_resources), |
572 | .resources = timberdale_ocores_resources, | 551 | .resources = timberdale_ocores_resources, |
573 | .platform_data = &timberdale_ocores_platform_data, | 552 | .mfd_data = &timberdale_ocores_platform_data, |
574 | .data_size = sizeof(timberdale_ocores_platform_data), | ||
575 | }, | 553 | }, |
576 | { | 554 | { |
577 | .name = "timb-gpio", | 555 | .name = "timb-gpio", |
578 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 556 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
579 | .resources = timberdale_gpio_resources, | 557 | .resources = timberdale_gpio_resources, |
580 | .platform_data = &timberdale_gpio_platform_data, | 558 | .mfd_data = &timberdale_gpio_platform_data, |
581 | .data_size = sizeof(timberdale_gpio_platform_data), | ||
582 | }, | 559 | }, |
583 | { | 560 | { |
584 | .name = "timb-video", | 561 | .name = "timb-video", |
585 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | 562 | .num_resources = ARRAY_SIZE(timberdale_video_resources), |
586 | .resources = timberdale_video_resources, | 563 | .resources = timberdale_video_resources, |
587 | .platform_data = &timberdale_video_platform_data, | 564 | .mfd_data = &timberdale_video_platform_data, |
588 | .data_size = sizeof(timberdale_video_platform_data), | ||
589 | }, | 565 | }, |
590 | { | 566 | { |
591 | .name = "timb-radio", | 567 | .name = "timb-radio", |
592 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 568 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
593 | .resources = timberdale_radio_resources, | 569 | .resources = timberdale_radio_resources, |
594 | .platform_data = &timberdale_radio_platform_data, | 570 | .mfd_data = &timberdale_radio_platform_data, |
595 | .data_size = sizeof(timberdale_radio_platform_data), | ||
596 | }, | 571 | }, |
597 | { | 572 | { |
598 | .name = "xilinx_spi", | 573 | .name = "xilinx_spi", |
599 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 574 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
600 | .resources = timberdale_spi_resources, | 575 | .resources = timberdale_spi_resources, |
601 | .platform_data = &timberdale_xspi_platform_data, | 576 | .mfd_data = &timberdale_xspi_platform_data, |
602 | .data_size = sizeof(timberdale_xspi_platform_data), | ||
603 | }, | 577 | }, |
604 | { | 578 | { |
605 | .name = "ks8842", | 579 | .name = "ks8842", |
606 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 580 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
607 | .resources = timberdale_eth_resources, | 581 | .resources = timberdale_eth_resources, |
608 | .platform_data = &timberdale_ks8842_platform_data, | 582 | .mfd_data = &timberdale_ks8842_platform_data, |
609 | .data_size = sizeof(timberdale_ks8842_platform_data) | ||
610 | }, | 583 | }, |
611 | }; | 584 | }; |
612 | 585 | ||
diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c new file mode 100644 index 000000000000..46d8205646b6 --- /dev/null +++ b/drivers/mfd/tps6105x.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Core driver for TPS61050/61052 boost converters, used for while LED | ||
3 | * driving, audio power amplification, white LED flash, and generic | ||
4 | * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in) | ||
5 | * and a flash synchronization pin to synchronize flash events when used as | ||
6 | * flashgun. | ||
7 | * | ||
8 | * Copyright (C) 2011 ST-Ericsson SA | ||
9 | * Written on behalf of Linaro for ST-Ericsson | ||
10 | * | ||
11 | * Author: Linus Walleij <linus.walleij@linaro.org> | ||
12 | * | ||
13 | * License terms: GNU General Public License (GPL) version 2 | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/regulator/driver.h> | ||
25 | #include <linux/mfd/core.h> | ||
26 | #include <linux/mfd/tps6105x.h> | ||
27 | |||
28 | int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value) | ||
29 | { | ||
30 | int ret; | ||
31 | |||
32 | ret = mutex_lock_interruptible(&tps6105x->lock); | ||
33 | if (ret) | ||
34 | return ret; | ||
35 | ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value); | ||
36 | mutex_unlock(&tps6105x->lock); | ||
37 | if (ret < 0) | ||
38 | return ret; | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | EXPORT_SYMBOL(tps6105x_set); | ||
43 | |||
44 | int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf) | ||
45 | { | ||
46 | int ret; | ||
47 | |||
48 | ret = mutex_lock_interruptible(&tps6105x->lock); | ||
49 | if (ret) | ||
50 | return ret; | ||
51 | ret = i2c_smbus_read_byte_data(tps6105x->client, reg); | ||
52 | mutex_unlock(&tps6105x->lock); | ||
53 | if (ret < 0) | ||
54 | return ret; | ||
55 | |||
56 | *buf = ret; | ||
57 | return 0; | ||
58 | } | ||
59 | EXPORT_SYMBOL(tps6105x_get); | ||
60 | |||
61 | /* | ||
62 | * Masks off the bits in the mask and sets the bits in the bitvalues | ||
63 | * parameter in one atomic operation | ||
64 | */ | ||
65 | int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg, | ||
66 | u8 bitmask, u8 bitvalues) | ||
67 | { | ||
68 | int ret; | ||
69 | u8 regval; | ||
70 | |||
71 | ret = mutex_lock_interruptible(&tps6105x->lock); | ||
72 | if (ret) | ||
73 | return ret; | ||
74 | ret = i2c_smbus_read_byte_data(tps6105x->client, reg); | ||
75 | if (ret < 0) | ||
76 | goto fail; | ||
77 | regval = ret; | ||
78 | regval = (~bitmask & regval) | (bitmask & bitvalues); | ||
79 | ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval); | ||
80 | fail: | ||
81 | mutex_unlock(&tps6105x->lock); | ||
82 | if (ret < 0) | ||
83 | return ret; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL(tps6105x_mask_and_set); | ||
88 | |||
89 | static int __devinit tps6105x_startup(struct tps6105x *tps6105x) | ||
90 | { | ||
91 | int ret; | ||
92 | u8 regval; | ||
93 | |||
94 | ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); | ||
95 | if (ret) | ||
96 | return ret; | ||
97 | switch (regval >> TPS6105X_REG0_MODE_SHIFT) { | ||
98 | case TPS6105X_REG0_MODE_SHUTDOWN: | ||
99 | dev_info(&tps6105x->client->dev, | ||
100 | "TPS6105x found in SHUTDOWN mode\n"); | ||
101 | break; | ||
102 | case TPS6105X_REG0_MODE_TORCH: | ||
103 | dev_info(&tps6105x->client->dev, | ||
104 | "TPS6105x found in TORCH mode\n"); | ||
105 | break; | ||
106 | case TPS6105X_REG0_MODE_TORCH_FLASH: | ||
107 | dev_info(&tps6105x->client->dev, | ||
108 | "TPS6105x found in FLASH mode\n"); | ||
109 | break; | ||
110 | case TPS6105X_REG0_MODE_VOLTAGE: | ||
111 | dev_info(&tps6105x->client->dev, | ||
112 | "TPS6105x found in VOLTAGE mode\n"); | ||
113 | break; | ||
114 | default: | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * MFD cells - we have one cell which is selected operation | ||
123 | * mode, and we always have a GPIO cell. | ||
124 | */ | ||
125 | static struct mfd_cell tps6105x_cells[] = { | ||
126 | { | ||
127 | /* name will be runtime assigned */ | ||
128 | .id = -1, | ||
129 | }, | ||
130 | { | ||
131 | .name = "tps6105x-gpio", | ||
132 | .id = -1, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | static int __devinit tps6105x_probe(struct i2c_client *client, | ||
137 | const struct i2c_device_id *id) | ||
138 | { | ||
139 | struct tps6105x *tps6105x; | ||
140 | struct tps6105x_platform_data *pdata; | ||
141 | int ret; | ||
142 | int i; | ||
143 | |||
144 | tps6105x = kmalloc(sizeof(*tps6105x), GFP_KERNEL); | ||
145 | if (!tps6105x) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | i2c_set_clientdata(client, tps6105x); | ||
149 | tps6105x->client = client; | ||
150 | pdata = client->dev.platform_data; | ||
151 | tps6105x->pdata = pdata; | ||
152 | mutex_init(&tps6105x->lock); | ||
153 | |||
154 | ret = tps6105x_startup(tps6105x); | ||
155 | if (ret) { | ||
156 | dev_err(&client->dev, "chip initialization failed\n"); | ||
157 | goto fail; | ||
158 | } | ||
159 | |||
160 | /* Remove warning texts when you implement new cell drivers */ | ||
161 | switch (pdata->mode) { | ||
162 | case TPS6105X_MODE_SHUTDOWN: | ||
163 | dev_info(&client->dev, | ||
164 | "present, not used for anything, only GPIO\n"); | ||
165 | break; | ||
166 | case TPS6105X_MODE_TORCH: | ||
167 | tps6105x_cells[0].name = "tps6105x-leds"; | ||
168 | dev_warn(&client->dev, | ||
169 | "torch mode is unsupported\n"); | ||
170 | break; | ||
171 | case TPS6105X_MODE_TORCH_FLASH: | ||
172 | tps6105x_cells[0].name = "tps6105x-flash"; | ||
173 | dev_warn(&client->dev, | ||
174 | "flash mode is unsupported\n"); | ||
175 | break; | ||
176 | case TPS6105X_MODE_VOLTAGE: | ||
177 | tps6105x_cells[0].name ="tps6105x-regulator"; | ||
178 | break; | ||
179 | default: | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | /* Set up and register the platform devices. */ | ||
184 | for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) { | ||
185 | /* One state holder for all drivers, this is simple */ | ||
186 | tps6105x_cells[i].mfd_data = tps6105x; | ||
187 | } | ||
188 | |||
189 | ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, | ||
190 | ARRAY_SIZE(tps6105x_cells), NULL, 0); | ||
191 | if (ret) | ||
192 | goto fail; | ||
193 | |||
194 | return 0; | ||
195 | |||
196 | fail: | ||
197 | kfree(tps6105x); | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static int __devexit tps6105x_remove(struct i2c_client *client) | ||
202 | { | ||
203 | struct tps6105x *tps6105x = i2c_get_clientdata(client); | ||
204 | |||
205 | mfd_remove_devices(&client->dev); | ||
206 | |||
207 | /* Put chip in shutdown mode */ | ||
208 | tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, | ||
209 | TPS6105X_REG0_MODE_MASK, | ||
210 | TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); | ||
211 | |||
212 | kfree(tps6105x); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static const struct i2c_device_id tps6105x_id[] = { | ||
217 | { "tps61050", 0 }, | ||
218 | { "tps61052", 0 }, | ||
219 | { } | ||
220 | }; | ||
221 | MODULE_DEVICE_TABLE(i2c, tps6105x_id); | ||
222 | |||
223 | static struct i2c_driver tps6105x_driver = { | ||
224 | .driver = { | ||
225 | .name = "tps6105x", | ||
226 | }, | ||
227 | .probe = tps6105x_probe, | ||
228 | .remove = __devexit_p(tps6105x_remove), | ||
229 | .id_table = tps6105x_id, | ||
230 | }; | ||
231 | |||
232 | static int __init tps6105x_init(void) | ||
233 | { | ||
234 | return i2c_add_driver(&tps6105x_driver); | ||
235 | } | ||
236 | subsys_initcall(tps6105x_init); | ||
237 | |||
238 | static void __exit tps6105x_exit(void) | ||
239 | { | ||
240 | i2c_del_driver(&tps6105x_driver); | ||
241 | } | ||
242 | module_exit(tps6105x_exit); | ||
243 | |||
244 | MODULE_AUTHOR("Linus Walleij"); | ||
245 | MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver"); | ||
246 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index e9018d1394ee..0aa9186aec19 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
@@ -288,12 +288,10 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, | |||
288 | return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask); | 288 | return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask); |
289 | } | 289 | } |
290 | 290 | ||
291 | static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) | 291 | static int tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) |
292 | { | 292 | { |
293 | int ret; | ||
294 | |||
295 | if (!gpio_base) | 293 | if (!gpio_base) |
296 | return; | 294 | return 0; |
297 | 295 | ||
298 | tps6586x->gpio.owner = THIS_MODULE; | 296 | tps6586x->gpio.owner = THIS_MODULE; |
299 | tps6586x->gpio.label = tps6586x->client->name; | 297 | tps6586x->gpio.label = tps6586x->client->name; |
@@ -307,9 +305,7 @@ static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) | |||
307 | tps6586x->gpio.set = tps6586x_gpio_set; | 305 | tps6586x->gpio.set = tps6586x_gpio_set; |
308 | tps6586x->gpio.get = tps6586x_gpio_get; | 306 | tps6586x->gpio.get = tps6586x_gpio_get; |
309 | 307 | ||
310 | ret = gpiochip_add(&tps6586x->gpio); | 308 | return gpiochip_add(&tps6586x->gpio); |
311 | if (ret) | ||
312 | dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret); | ||
313 | } | 309 | } |
314 | 310 | ||
315 | static int __remove_subdev(struct device *dev, void *unused) | 311 | static int __remove_subdev(struct device *dev, void *unused) |
@@ -517,17 +513,28 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
517 | } | 513 | } |
518 | } | 514 | } |
519 | 515 | ||
516 | ret = tps6586x_gpio_init(tps6586x, pdata->gpio_base); | ||
517 | if (ret) { | ||
518 | dev_err(&client->dev, "GPIO registration failed: %d\n", ret); | ||
519 | goto err_gpio_init; | ||
520 | } | ||
521 | |||
520 | ret = tps6586x_add_subdevs(tps6586x, pdata); | 522 | ret = tps6586x_add_subdevs(tps6586x, pdata); |
521 | if (ret) { | 523 | if (ret) { |
522 | dev_err(&client->dev, "add devices failed: %d\n", ret); | 524 | dev_err(&client->dev, "add devices failed: %d\n", ret); |
523 | goto err_add_devs; | 525 | goto err_add_devs; |
524 | } | 526 | } |
525 | 527 | ||
526 | tps6586x_gpio_init(tps6586x, pdata->gpio_base); | ||
527 | |||
528 | return 0; | 528 | return 0; |
529 | 529 | ||
530 | err_add_devs: | 530 | err_add_devs: |
531 | if (pdata->gpio_base) { | ||
532 | ret = gpiochip_remove(&tps6586x->gpio); | ||
533 | if (ret) | ||
534 | dev_err(&client->dev, "Can't remove gpio chip: %d\n", | ||
535 | ret); | ||
536 | } | ||
537 | err_gpio_init: | ||
531 | if (client->irq) | 538 | if (client->irq) |
532 | free_irq(client->irq, tps6586x); | 539 | free_irq(client->irq, tps6586x); |
533 | err_irq_init: | 540 | err_irq_init: |
@@ -587,4 +594,3 @@ module_exit(tps6586x_exit); | |||
587 | MODULE_DESCRIPTION("TPS6586X core driver"); | 594 | MODULE_DESCRIPTION("TPS6586X core driver"); |
588 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | 595 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); |
589 | MODULE_LICENSE("GPL"); | 596 | MODULE_LICENSE("GPL"); |
590 | |||
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index a35fa7dcbf53..960b5bed7f52 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -721,13 +721,13 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
721 | 721 | ||
722 | } | 722 | } |
723 | 723 | ||
724 | if (twl_has_watchdog()) { | 724 | if (twl_has_watchdog() && twl_class_is_4030()) { |
725 | child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); | 725 | child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); |
726 | if (IS_ERR(child)) | 726 | if (IS_ERR(child)) |
727 | return PTR_ERR(child); | 727 | return PTR_ERR(child); |
728 | } | 728 | } |
729 | 729 | ||
730 | if (twl_has_pwrbutton()) { | 730 | if (twl_has_pwrbutton() && twl_class_is_4030()) { |
731 | child = add_child(1, "twl4030_pwrbutton", | 731 | child = add_child(1, "twl4030_pwrbutton", |
732 | NULL, 0, true, pdata->irq_base + 8 + 0, 0); | 732 | NULL, 0, true, pdata->irq_base + 8 + 0, 0); |
733 | if (IS_ERR(child)) | 733 | if (IS_ERR(child)) |
@@ -864,6 +864,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
864 | child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3); | 864 | child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3); |
865 | if (IS_ERR(child)) | 865 | if (IS_ERR(child)) |
866 | return PTR_ERR(child); | 866 | return PTR_ERR(child); |
867 | |||
868 | child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg); | ||
869 | if (IS_ERR(child)) | ||
870 | return PTR_ERR(child); | ||
867 | } | 871 | } |
868 | 872 | ||
869 | if (twl_has_bci() && pdata->bci && | 873 | if (twl_has_bci() && pdata->bci && |
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c index 9a4b196d6deb..c02fded316c9 100644 --- a/drivers/mfd/twl4030-codec.c +++ b/drivers/mfd/twl4030-codec.c | |||
@@ -208,15 +208,13 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
208 | if (pdata->audio) { | 208 | if (pdata->audio) { |
209 | cell = &codec->cells[childs]; | 209 | cell = &codec->cells[childs]; |
210 | cell->name = "twl4030-codec"; | 210 | cell->name = "twl4030-codec"; |
211 | cell->platform_data = pdata->audio; | 211 | cell->mfd_data = pdata->audio; |
212 | cell->data_size = sizeof(*pdata->audio); | ||
213 | childs++; | 212 | childs++; |
214 | } | 213 | } |
215 | if (pdata->vibra) { | 214 | if (pdata->vibra) { |
216 | cell = &codec->cells[childs]; | 215 | cell = &codec->cells[childs]; |
217 | cell->name = "twl4030-vibra"; | 216 | cell->name = "twl4030-vibra"; |
218 | cell->platform_data = pdata->vibra; | 217 | cell->mfd_data = pdata->vibra; |
219 | cell->data_size = sizeof(*pdata->vibra); | ||
220 | childs++; | 218 | childs++; |
221 | } | 219 | } |
222 | 220 | ||
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c new file mode 100644 index 000000000000..3941ddcf15fe --- /dev/null +++ b/drivers/mfd/twl4030-madc.c | |||
@@ -0,0 +1,802 @@ | |||
1 | /* | ||
2 | * | ||
3 | * TWL4030 MADC module driver-This driver monitors the real time | ||
4 | * conversion of analog signals like battery temperature, | ||
5 | * battery type, battery level etc. | ||
6 | * | ||
7 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
8 | * J Keerthy <j-keerthy@ti.com> | ||
9 | * | ||
10 | * Based on twl4030-madc.c | ||
11 | * Copyright (C) 2008 Nokia Corporation | ||
12 | * Mikko Ylinen <mikko.k.ylinen@nokia.com> | ||
13 | * | ||
14 | * Amit Kucheria <amit.kucheria@canonical.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * version 2 as published by the Free Software Foundation. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, but | ||
21 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
23 | * General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
28 | * 02110-1301 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/init.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/i2c/twl.h> | ||
40 | #include <linux/i2c/twl4030-madc.h> | ||
41 | #include <linux/module.h> | ||
42 | #include <linux/stddef.h> | ||
43 | #include <linux/mutex.h> | ||
44 | #include <linux/bitops.h> | ||
45 | #include <linux/jiffies.h> | ||
46 | #include <linux/types.h> | ||
47 | #include <linux/gfp.h> | ||
48 | #include <linux/err.h> | ||
49 | |||
50 | /* | ||
51 | * struct twl4030_madc_data - a container for madc info | ||
52 | * @dev - pointer to device structure for madc | ||
53 | * @lock - mutex protecting this data structure | ||
54 | * @requests - Array of request struct corresponding to SW1, SW2 and RT | ||
55 | * @imr - Interrupt mask register of MADC | ||
56 | * @isr - Interrupt status register of MADC | ||
57 | */ | ||
58 | struct twl4030_madc_data { | ||
59 | struct device *dev; | ||
60 | struct mutex lock; /* mutex protecting this data structure */ | ||
61 | struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; | ||
62 | int imr; | ||
63 | int isr; | ||
64 | }; | ||
65 | |||
66 | static struct twl4030_madc_data *twl4030_madc; | ||
67 | |||
68 | struct twl4030_prescale_divider_ratios { | ||
69 | s16 numerator; | ||
70 | s16 denominator; | ||
71 | }; | ||
72 | |||
73 | static const struct twl4030_prescale_divider_ratios | ||
74 | twl4030_divider_ratios[16] = { | ||
75 | {1, 1}, /* CHANNEL 0 No Prescaler */ | ||
76 | {1, 1}, /* CHANNEL 1 No Prescaler */ | ||
77 | {6, 10}, /* CHANNEL 2 */ | ||
78 | {6, 10}, /* CHANNEL 3 */ | ||
79 | {6, 10}, /* CHANNEL 4 */ | ||
80 | {6, 10}, /* CHANNEL 5 */ | ||
81 | {6, 10}, /* CHANNEL 6 */ | ||
82 | {6, 10}, /* CHANNEL 7 */ | ||
83 | {3, 14}, /* CHANNEL 8 */ | ||
84 | {1, 3}, /* CHANNEL 9 */ | ||
85 | {1, 1}, /* CHANNEL 10 No Prescaler */ | ||
86 | {15, 100}, /* CHANNEL 11 */ | ||
87 | {1, 4}, /* CHANNEL 12 */ | ||
88 | {1, 1}, /* CHANNEL 13 Reserved channels */ | ||
89 | {1, 1}, /* CHANNEL 14 Reseved channels */ | ||
90 | {5, 11}, /* CHANNEL 15 */ | ||
91 | }; | ||
92 | |||
93 | |||
94 | /* | ||
95 | * Conversion table from -3 to 55 degree Celcius | ||
96 | */ | ||
97 | static int therm_tbl[] = { | ||
98 | 30800, 29500, 28300, 27100, | ||
99 | 26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900, | ||
100 | 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100, | ||
101 | 11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310, | ||
102 | 8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830, | ||
103 | 5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170, | ||
104 | 4040, 3910, 3790, 3670, 3550 | ||
105 | }; | ||
106 | |||
107 | /* | ||
108 | * Structure containing the registers | ||
109 | * of different conversion methods supported by MADC. | ||
110 | * Hardware or RT real time conversion request initiated by external host | ||
111 | * processor for RT Signal conversions. | ||
112 | * External host processors can also request for non RT conversions | ||
113 | * SW1 and SW2 software conversions also called asynchronous or GPC request. | ||
114 | */ | ||
115 | static | ||
116 | const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { | ||
117 | [TWL4030_MADC_RT] = { | ||
118 | .sel = TWL4030_MADC_RTSELECT_LSB, | ||
119 | .avg = TWL4030_MADC_RTAVERAGE_LSB, | ||
120 | .rbase = TWL4030_MADC_RTCH0_LSB, | ||
121 | }, | ||
122 | [TWL4030_MADC_SW1] = { | ||
123 | .sel = TWL4030_MADC_SW1SELECT_LSB, | ||
124 | .avg = TWL4030_MADC_SW1AVERAGE_LSB, | ||
125 | .rbase = TWL4030_MADC_GPCH0_LSB, | ||
126 | .ctrl = TWL4030_MADC_CTRL_SW1, | ||
127 | }, | ||
128 | [TWL4030_MADC_SW2] = { | ||
129 | .sel = TWL4030_MADC_SW2SELECT_LSB, | ||
130 | .avg = TWL4030_MADC_SW2AVERAGE_LSB, | ||
131 | .rbase = TWL4030_MADC_GPCH0_LSB, | ||
132 | .ctrl = TWL4030_MADC_CTRL_SW2, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | /* | ||
137 | * Function to read a particular channel value. | ||
138 | * @madc - pointer to struct twl4030_madc_data | ||
139 | * @reg - lsb of ADC Channel | ||
140 | * If the i2c read fails it returns an error else returns 0. | ||
141 | */ | ||
142 | static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) | ||
143 | { | ||
144 | u8 msb, lsb; | ||
145 | int ret; | ||
146 | /* | ||
147 | * For each ADC channel, we have MSB and LSB register pair. MSB address | ||
148 | * is always LSB address+1. reg parameter is the address of LSB register | ||
149 | */ | ||
150 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1); | ||
151 | if (ret) { | ||
152 | dev_err(madc->dev, "unable to read MSB register 0x%X\n", | ||
153 | reg + 1); | ||
154 | return ret; | ||
155 | } | ||
156 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg); | ||
157 | if (ret) { | ||
158 | dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | return (int)(((msb << 8) | lsb) >> 6); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Return battery temperature | ||
167 | * Or < 0 on failure. | ||
168 | */ | ||
169 | static int twl4030battery_temperature(int raw_volt) | ||
170 | { | ||
171 | u8 val; | ||
172 | int temp, curr, volt, res, ret; | ||
173 | |||
174 | volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R; | ||
175 | /* Getting and calculating the supply current in micro ampers */ | ||
176 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, | ||
177 | REG_BCICTL2); | ||
178 | if (ret < 0) | ||
179 | return ret; | ||
180 | curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10; | ||
181 | /* Getting and calculating the thermistor resistance in ohms */ | ||
182 | res = volt * 1000 / curr; | ||
183 | /* calculating temperature */ | ||
184 | for (temp = 58; temp >= 0; temp--) { | ||
185 | int actual = therm_tbl[temp]; | ||
186 | |||
187 | if ((actual - res) >= 0) | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | return temp + 1; | ||
192 | } | ||
193 | |||
194 | static int twl4030battery_current(int raw_volt) | ||
195 | { | ||
196 | int ret; | ||
197 | u8 val; | ||
198 | |||
199 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, | ||
200 | TWL4030_BCI_BCICTL1); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */ | ||
204 | return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1; | ||
205 | else /* slope of 0.88 mV/mA */ | ||
206 | return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2; | ||
207 | } | ||
208 | /* | ||
209 | * Function to read channel values | ||
210 | * @madc - pointer to twl4030_madc_data struct | ||
211 | * @reg_base - Base address of the first channel | ||
212 | * @Channels - 16 bit bitmap. If the bit is set, channel value is read | ||
213 | * @buf - The channel values are stored here. if read fails error | ||
214 | * value is stored | ||
215 | * Returns the number of successfully read channels. | ||
216 | */ | ||
217 | static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, | ||
218 | u8 reg_base, unsigned | ||
219 | long channels, int *buf) | ||
220 | { | ||
221 | int count = 0, count_req = 0, i; | ||
222 | u8 reg; | ||
223 | |||
224 | for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) { | ||
225 | reg = reg_base + 2 * i; | ||
226 | buf[i] = twl4030_madc_channel_raw_read(madc, reg); | ||
227 | if (buf[i] < 0) { | ||
228 | dev_err(madc->dev, | ||
229 | "Unable to read register 0x%X\n", reg); | ||
230 | count_req++; | ||
231 | continue; | ||
232 | } | ||
233 | switch (i) { | ||
234 | case 10: | ||
235 | buf[i] = twl4030battery_current(buf[i]); | ||
236 | if (buf[i] < 0) { | ||
237 | dev_err(madc->dev, "err reading current\n"); | ||
238 | count_req++; | ||
239 | } else { | ||
240 | count++; | ||
241 | buf[i] = buf[i] - 750; | ||
242 | } | ||
243 | break; | ||
244 | case 1: | ||
245 | buf[i] = twl4030battery_temperature(buf[i]); | ||
246 | if (buf[i] < 0) { | ||
247 | dev_err(madc->dev, "err reading temperature\n"); | ||
248 | count_req++; | ||
249 | } else { | ||
250 | buf[i] -= 3; | ||
251 | count++; | ||
252 | } | ||
253 | break; | ||
254 | default: | ||
255 | count++; | ||
256 | /* Analog Input (V) = conv_result * step_size / R | ||
257 | * conv_result = decimal value of 10-bit conversion | ||
258 | * result | ||
259 | * step size = 1.5 / (2 ^ 10 -1) | ||
260 | * R = Prescaler ratio for input channels. | ||
261 | * Result given in mV hence multiplied by 1000. | ||
262 | */ | ||
263 | buf[i] = (buf[i] * 3 * 1000 * | ||
264 | twl4030_divider_ratios[i].denominator) | ||
265 | / (2 * 1023 * | ||
266 | twl4030_divider_ratios[i].numerator); | ||
267 | } | ||
268 | } | ||
269 | if (count_req) | ||
270 | dev_err(madc->dev, "%d channel conversion failed\n", count_req); | ||
271 | |||
272 | return count; | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Enables irq. | ||
277 | * @madc - pointer to twl4030_madc_data struct | ||
278 | * @id - irq number to be enabled | ||
279 | * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 | ||
280 | * corresponding to RT, SW1, SW2 conversion requests. | ||
281 | * If the i2c read fails it returns an error else returns 0. | ||
282 | */ | ||
283 | static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id) | ||
284 | { | ||
285 | u8 val; | ||
286 | int ret; | ||
287 | |||
288 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); | ||
289 | if (ret) { | ||
290 | dev_err(madc->dev, "unable to read imr register 0x%X\n", | ||
291 | madc->imr); | ||
292 | return ret; | ||
293 | } | ||
294 | val &= ~(1 << id); | ||
295 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); | ||
296 | if (ret) { | ||
297 | dev_err(madc->dev, | ||
298 | "unable to write imr register 0x%X\n", madc->imr); | ||
299 | return ret; | ||
300 | |||
301 | } | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Disables irq. | ||
308 | * @madc - pointer to twl4030_madc_data struct | ||
309 | * @id - irq number to be disabled | ||
310 | * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 | ||
311 | * corresponding to RT, SW1, SW2 conversion requests. | ||
312 | * Returns error if i2c read/write fails. | ||
313 | */ | ||
314 | static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id) | ||
315 | { | ||
316 | u8 val; | ||
317 | int ret; | ||
318 | |||
319 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); | ||
320 | if (ret) { | ||
321 | dev_err(madc->dev, "unable to read imr register 0x%X\n", | ||
322 | madc->imr); | ||
323 | return ret; | ||
324 | } | ||
325 | val |= (1 << id); | ||
326 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); | ||
327 | if (ret) { | ||
328 | dev_err(madc->dev, | ||
329 | "unable to write imr register 0x%X\n", madc->imr); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) | ||
337 | { | ||
338 | struct twl4030_madc_data *madc = _madc; | ||
339 | const struct twl4030_madc_conversion_method *method; | ||
340 | u8 isr_val, imr_val; | ||
341 | int i, len, ret; | ||
342 | struct twl4030_madc_request *r; | ||
343 | |||
344 | mutex_lock(&madc->lock); | ||
345 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr); | ||
346 | if (ret) { | ||
347 | dev_err(madc->dev, "unable to read isr register 0x%X\n", | ||
348 | madc->isr); | ||
349 | goto err_i2c; | ||
350 | } | ||
351 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr); | ||
352 | if (ret) { | ||
353 | dev_err(madc->dev, "unable to read imr register 0x%X\n", | ||
354 | madc->imr); | ||
355 | goto err_i2c; | ||
356 | } | ||
357 | isr_val &= ~imr_val; | ||
358 | for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { | ||
359 | if (!(isr_val & (1 << i))) | ||
360 | continue; | ||
361 | ret = twl4030_madc_disable_irq(madc, i); | ||
362 | if (ret < 0) | ||
363 | dev_dbg(madc->dev, "Disable interrupt failed%d\n", i); | ||
364 | madc->requests[i].result_pending = 1; | ||
365 | } | ||
366 | for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { | ||
367 | r = &madc->requests[i]; | ||
368 | /* No pending results for this method, move to next one */ | ||
369 | if (!r->result_pending) | ||
370 | continue; | ||
371 | method = &twl4030_conversion_methods[r->method]; | ||
372 | /* Read results */ | ||
373 | len = twl4030_madc_read_channels(madc, method->rbase, | ||
374 | r->channels, r->rbuf); | ||
375 | /* Return results to caller */ | ||
376 | if (r->func_cb != NULL) { | ||
377 | r->func_cb(len, r->channels, r->rbuf); | ||
378 | r->func_cb = NULL; | ||
379 | } | ||
380 | /* Free request */ | ||
381 | r->result_pending = 0; | ||
382 | r->active = 0; | ||
383 | } | ||
384 | mutex_unlock(&madc->lock); | ||
385 | |||
386 | return IRQ_HANDLED; | ||
387 | |||
388 | err_i2c: | ||
389 | /* | ||
390 | * In case of error check whichever request is active | ||
391 | * and service the same. | ||
392 | */ | ||
393 | for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { | ||
394 | r = &madc->requests[i]; | ||
395 | if (r->active == 0) | ||
396 | continue; | ||
397 | method = &twl4030_conversion_methods[r->method]; | ||
398 | /* Read results */ | ||
399 | len = twl4030_madc_read_channels(madc, method->rbase, | ||
400 | r->channels, r->rbuf); | ||
401 | /* Return results to caller */ | ||
402 | if (r->func_cb != NULL) { | ||
403 | r->func_cb(len, r->channels, r->rbuf); | ||
404 | r->func_cb = NULL; | ||
405 | } | ||
406 | /* Free request */ | ||
407 | r->result_pending = 0; | ||
408 | r->active = 0; | ||
409 | } | ||
410 | mutex_unlock(&madc->lock); | ||
411 | |||
412 | return IRQ_HANDLED; | ||
413 | } | ||
414 | |||
415 | static int twl4030_madc_set_irq(struct twl4030_madc_data *madc, | ||
416 | struct twl4030_madc_request *req) | ||
417 | { | ||
418 | struct twl4030_madc_request *p; | ||
419 | int ret; | ||
420 | |||
421 | p = &madc->requests[req->method]; | ||
422 | memcpy(p, req, sizeof(*req)); | ||
423 | ret = twl4030_madc_enable_irq(madc, req->method); | ||
424 | if (ret < 0) { | ||
425 | dev_err(madc->dev, "enable irq failed!!\n"); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * Function which enables the madc conversion | ||
434 | * by writing to the control register. | ||
435 | * @madc - pointer to twl4030_madc_data struct | ||
436 | * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1 | ||
437 | * corresponding to RT SW1 or SW2 conversion methods. | ||
438 | * Returns 0 if succeeds else a negative error value | ||
439 | */ | ||
440 | static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc, | ||
441 | int conv_method) | ||
442 | { | ||
443 | const struct twl4030_madc_conversion_method *method; | ||
444 | int ret = 0; | ||
445 | method = &twl4030_conversion_methods[conv_method]; | ||
446 | switch (conv_method) { | ||
447 | case TWL4030_MADC_SW1: | ||
448 | case TWL4030_MADC_SW2: | ||
449 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, | ||
450 | TWL4030_MADC_SW_START, method->ctrl); | ||
451 | if (ret) { | ||
452 | dev_err(madc->dev, | ||
453 | "unable to write ctrl register 0x%X\n", | ||
454 | method->ctrl); | ||
455 | return ret; | ||
456 | } | ||
457 | break; | ||
458 | default: | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Function that waits for conversion to be ready | ||
467 | * @madc - pointer to twl4030_madc_data struct | ||
468 | * @timeout_ms - timeout value in milliseconds | ||
469 | * @status_reg - ctrl register | ||
470 | * returns 0 if succeeds else a negative error value | ||
471 | */ | ||
472 | static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc, | ||
473 | unsigned int timeout_ms, | ||
474 | u8 status_reg) | ||
475 | { | ||
476 | unsigned long timeout; | ||
477 | int ret; | ||
478 | |||
479 | timeout = jiffies + msecs_to_jiffies(timeout_ms); | ||
480 | do { | ||
481 | u8 reg; | ||
482 | |||
483 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, ®, status_reg); | ||
484 | if (ret) { | ||
485 | dev_err(madc->dev, | ||
486 | "unable to read status register 0x%X\n", | ||
487 | status_reg); | ||
488 | return ret; | ||
489 | } | ||
490 | if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW)) | ||
491 | return 0; | ||
492 | usleep_range(500, 2000); | ||
493 | } while (!time_after(jiffies, timeout)); | ||
494 | dev_err(madc->dev, "conversion timeout!\n"); | ||
495 | |||
496 | return -EAGAIN; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * An exported function which can be called from other kernel drivers. | ||
501 | * @req twl4030_madc_request structure | ||
502 | * req->rbuf will be filled with read values of channels based on the | ||
503 | * channel index. If a particular channel reading fails there will | ||
504 | * be a negative error value in the corresponding array element. | ||
505 | * returns 0 if succeeds else error value | ||
506 | */ | ||
507 | int twl4030_madc_conversion(struct twl4030_madc_request *req) | ||
508 | { | ||
509 | const struct twl4030_madc_conversion_method *method; | ||
510 | u8 ch_msb, ch_lsb; | ||
511 | int ret; | ||
512 | |||
513 | if (!req) | ||
514 | return -EINVAL; | ||
515 | mutex_lock(&twl4030_madc->lock); | ||
516 | if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) { | ||
517 | ret = -EINVAL; | ||
518 | goto out; | ||
519 | } | ||
520 | /* Do we have a conversion request ongoing */ | ||
521 | if (twl4030_madc->requests[req->method].active) { | ||
522 | ret = -EBUSY; | ||
523 | goto out; | ||
524 | } | ||
525 | ch_msb = (req->channels >> 8) & 0xff; | ||
526 | ch_lsb = req->channels & 0xff; | ||
527 | method = &twl4030_conversion_methods[req->method]; | ||
528 | /* Select channels to be converted */ | ||
529 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1); | ||
530 | if (ret) { | ||
531 | dev_err(twl4030_madc->dev, | ||
532 | "unable to write sel register 0x%X\n", method->sel + 1); | ||
533 | return ret; | ||
534 | } | ||
535 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel); | ||
536 | if (ret) { | ||
537 | dev_err(twl4030_madc->dev, | ||
538 | "unable to write sel register 0x%X\n", method->sel + 1); | ||
539 | return ret; | ||
540 | } | ||
541 | /* Select averaging for all channels if do_avg is set */ | ||
542 | if (req->do_avg) { | ||
543 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, | ||
544 | ch_msb, method->avg + 1); | ||
545 | if (ret) { | ||
546 | dev_err(twl4030_madc->dev, | ||
547 | "unable to write avg register 0x%X\n", | ||
548 | method->avg + 1); | ||
549 | return ret; | ||
550 | } | ||
551 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, | ||
552 | ch_lsb, method->avg); | ||
553 | if (ret) { | ||
554 | dev_err(twl4030_madc->dev, | ||
555 | "unable to write sel reg 0x%X\n", | ||
556 | method->sel + 1); | ||
557 | return ret; | ||
558 | } | ||
559 | } | ||
560 | if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) { | ||
561 | ret = twl4030_madc_set_irq(twl4030_madc, req); | ||
562 | if (ret < 0) | ||
563 | goto out; | ||
564 | ret = twl4030_madc_start_conversion(twl4030_madc, req->method); | ||
565 | if (ret < 0) | ||
566 | goto out; | ||
567 | twl4030_madc->requests[req->method].active = 1; | ||
568 | ret = 0; | ||
569 | goto out; | ||
570 | } | ||
571 | /* With RT method we should not be here anymore */ | ||
572 | if (req->method == TWL4030_MADC_RT) { | ||
573 | ret = -EINVAL; | ||
574 | goto out; | ||
575 | } | ||
576 | ret = twl4030_madc_start_conversion(twl4030_madc, req->method); | ||
577 | if (ret < 0) | ||
578 | goto out; | ||
579 | twl4030_madc->requests[req->method].active = 1; | ||
580 | /* Wait until conversion is ready (ctrl register returns EOC) */ | ||
581 | ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl); | ||
582 | if (ret) { | ||
583 | twl4030_madc->requests[req->method].active = 0; | ||
584 | goto out; | ||
585 | } | ||
586 | ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, | ||
587 | req->channels, req->rbuf); | ||
588 | twl4030_madc->requests[req->method].active = 0; | ||
589 | |||
590 | out: | ||
591 | mutex_unlock(&twl4030_madc->lock); | ||
592 | |||
593 | return ret; | ||
594 | } | ||
595 | EXPORT_SYMBOL_GPL(twl4030_madc_conversion); | ||
596 | |||
597 | /* | ||
598 | * Return channel value | ||
599 | * Or < 0 on failure. | ||
600 | */ | ||
601 | int twl4030_get_madc_conversion(int channel_no) | ||
602 | { | ||
603 | struct twl4030_madc_request req; | ||
604 | int temp = 0; | ||
605 | int ret; | ||
606 | |||
607 | req.channels = (1 << channel_no); | ||
608 | req.method = TWL4030_MADC_SW2; | ||
609 | req.active = 0; | ||
610 | req.func_cb = NULL; | ||
611 | ret = twl4030_madc_conversion(&req); | ||
612 | if (ret < 0) | ||
613 | return ret; | ||
614 | if (req.rbuf[channel_no] > 0) | ||
615 | temp = req.rbuf[channel_no]; | ||
616 | |||
617 | return temp; | ||
618 | } | ||
619 | EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion); | ||
620 | |||
621 | /* | ||
622 | * Function to enable or disable bias current for | ||
623 | * main battery type reading or temperature sensing | ||
624 | * @madc - pointer to twl4030_madc_data struct | ||
625 | * @chan - can be one of the two values | ||
626 | * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading | ||
627 | * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature | ||
628 | * sensing | ||
629 | * @on - enable or disable chan. | ||
630 | */ | ||
631 | static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, | ||
632 | int chan, int on) | ||
633 | { | ||
634 | int ret; | ||
635 | u8 regval; | ||
636 | |||
637 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
638 | ®val, TWL4030_BCI_BCICTL1); | ||
639 | if (ret) { | ||
640 | dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X", | ||
641 | TWL4030_BCI_BCICTL1); | ||
642 | return ret; | ||
643 | } | ||
644 | if (on) | ||
645 | regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; | ||
646 | else | ||
647 | regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN; | ||
648 | ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
649 | regval, TWL4030_BCI_BCICTL1); | ||
650 | if (ret) { | ||
651 | dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n", | ||
652 | TWL4030_BCI_BCICTL1); | ||
653 | return ret; | ||
654 | } | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | /* | ||
660 | * Function that sets MADC software power on bit to enable MADC | ||
661 | * @madc - pointer to twl4030_madc_data struct | ||
662 | * @on - Enable or disable MADC software powen on bit. | ||
663 | * returns error if i2c read/write fails else 0 | ||
664 | */ | ||
665 | static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) | ||
666 | { | ||
667 | u8 regval; | ||
668 | int ret; | ||
669 | |||
670 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
671 | ®val, TWL4030_MADC_CTRL1); | ||
672 | if (ret) { | ||
673 | dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n", | ||
674 | TWL4030_MADC_CTRL1); | ||
675 | return ret; | ||
676 | } | ||
677 | if (on) | ||
678 | regval |= TWL4030_MADC_MADCON; | ||
679 | else | ||
680 | regval &= ~TWL4030_MADC_MADCON; | ||
681 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1); | ||
682 | if (ret) { | ||
683 | dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n", | ||
684 | TWL4030_MADC_CTRL1); | ||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | /* | ||
692 | * Initialize MADC and request for threaded irq | ||
693 | */ | ||
694 | static int __devinit twl4030_madc_probe(struct platform_device *pdev) | ||
695 | { | ||
696 | struct twl4030_madc_data *madc; | ||
697 | struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data; | ||
698 | int ret; | ||
699 | u8 regval; | ||
700 | |||
701 | if (!pdata) { | ||
702 | dev_err(&pdev->dev, "platform_data not available\n"); | ||
703 | return -EINVAL; | ||
704 | } | ||
705 | madc = kzalloc(sizeof(*madc), GFP_KERNEL); | ||
706 | if (!madc) | ||
707 | return -ENOMEM; | ||
708 | |||
709 | /* | ||
710 | * Phoenix provides 2 interrupt lines. The first one is connected to | ||
711 | * the OMAP. The other one can be connected to the other processor such | ||
712 | * as modem. Hence two separate ISR and IMR registers. | ||
713 | */ | ||
714 | madc->imr = (pdata->irq_line == 1) ? | ||
715 | TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; | ||
716 | madc->isr = (pdata->irq_line == 1) ? | ||
717 | TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2; | ||
718 | ret = twl4030_madc_set_power(madc, 1); | ||
719 | if (ret < 0) | ||
720 | goto err_power; | ||
721 | ret = twl4030_madc_set_current_generator(madc, 0, 1); | ||
722 | if (ret < 0) | ||
723 | goto err_current_generator; | ||
724 | |||
725 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
726 | ®val, TWL4030_BCI_BCICTL1); | ||
727 | if (ret) { | ||
728 | dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n", | ||
729 | TWL4030_BCI_BCICTL1); | ||
730 | goto err_i2c; | ||
731 | } | ||
732 | regval |= TWL4030_BCI_MESBAT; | ||
733 | ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
734 | regval, TWL4030_BCI_BCICTL1); | ||
735 | if (ret) { | ||
736 | dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n", | ||
737 | TWL4030_BCI_BCICTL1); | ||
738 | goto err_i2c; | ||
739 | } | ||
740 | platform_set_drvdata(pdev, madc); | ||
741 | mutex_init(&madc->lock); | ||
742 | ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL, | ||
743 | twl4030_madc_threaded_irq_handler, | ||
744 | IRQF_TRIGGER_RISING, "twl4030_madc", madc); | ||
745 | if (ret) { | ||
746 | dev_dbg(&pdev->dev, "could not request irq\n"); | ||
747 | goto err_irq; | ||
748 | } | ||
749 | twl4030_madc = madc; | ||
750 | return 0; | ||
751 | err_irq: | ||
752 | platform_set_drvdata(pdev, NULL); | ||
753 | err_i2c: | ||
754 | twl4030_madc_set_current_generator(madc, 0, 0); | ||
755 | err_current_generator: | ||
756 | twl4030_madc_set_power(madc, 0); | ||
757 | err_power: | ||
758 | kfree(madc); | ||
759 | |||
760 | return ret; | ||
761 | } | ||
762 | |||
763 | static int __devexit twl4030_madc_remove(struct platform_device *pdev) | ||
764 | { | ||
765 | struct twl4030_madc_data *madc = platform_get_drvdata(pdev); | ||
766 | |||
767 | free_irq(platform_get_irq(pdev, 0), madc); | ||
768 | platform_set_drvdata(pdev, NULL); | ||
769 | twl4030_madc_set_current_generator(madc, 0, 0); | ||
770 | twl4030_madc_set_power(madc, 0); | ||
771 | kfree(madc); | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static struct platform_driver twl4030_madc_driver = { | ||
777 | .probe = twl4030_madc_probe, | ||
778 | .remove = __exit_p(twl4030_madc_remove), | ||
779 | .driver = { | ||
780 | .name = "twl4030_madc", | ||
781 | .owner = THIS_MODULE, | ||
782 | }, | ||
783 | }; | ||
784 | |||
785 | static int __init twl4030_madc_init(void) | ||
786 | { | ||
787 | return platform_driver_register(&twl4030_madc_driver); | ||
788 | } | ||
789 | |||
790 | module_init(twl4030_madc_init); | ||
791 | |||
792 | static void __exit twl4030_madc_exit(void) | ||
793 | { | ||
794 | platform_driver_unregister(&twl4030_madc_driver); | ||
795 | } | ||
796 | |||
797 | module_exit(twl4030_madc_exit); | ||
798 | |||
799 | MODULE_DESCRIPTION("TWL4030 ADC driver"); | ||
800 | MODULE_LICENSE("GPL"); | ||
801 | MODULE_AUTHOR("J Keerthy"); | ||
802 | MODULE_ALIAS("platform:twl4030_madc"); | ||
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 92b85e28a15e..38ffbd50a0d2 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c | |||
@@ -60,6 +60,7 @@ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x | |||
60 | input_report_abs(idev, ABS_X, x); | 60 | input_report_abs(idev, ABS_X, x); |
61 | input_report_abs(idev, ABS_Y, y); | 61 | input_report_abs(idev, ABS_Y, y); |
62 | input_report_abs(idev, ABS_PRESSURE, pressure); | 62 | input_report_abs(idev, ABS_PRESSURE, pressure); |
63 | input_report_key(idev, BTN_TOUCH, 1); | ||
63 | input_sync(idev); | 64 | input_sync(idev); |
64 | } | 65 | } |
65 | 66 | ||
@@ -68,6 +69,7 @@ static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) | |||
68 | struct input_dev *idev = ts->idev; | 69 | struct input_dev *idev = ts->idev; |
69 | 70 | ||
70 | input_report_abs(idev, ABS_PRESSURE, 0); | 71 | input_report_abs(idev, ABS_PRESSURE, 0); |
72 | input_report_key(idev, BTN_TOUCH, 0); | ||
71 | input_sync(idev); | 73 | input_sync(idev); |
72 | } | 74 | } |
73 | 75 | ||
@@ -384,7 +386,8 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) | |||
384 | idev->open = ucb1x00_ts_open; | 386 | idev->open = ucb1x00_ts_open; |
385 | idev->close = ucb1x00_ts_close; | 387 | idev->close = ucb1x00_ts_close; |
386 | 388 | ||
387 | __set_bit(EV_ABS, idev->evbit); | 389 | idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); |
390 | idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
388 | 391 | ||
389 | input_set_drvdata(idev, ts); | 392 | input_set_drvdata(idev, ts); |
390 | 393 | ||
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index 348052aa5dbf..d698703dbd46 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c | |||
@@ -122,6 +122,7 @@ static struct pci_device_id vx855_pci_tbl[] = { | |||
122 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, | 122 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, |
123 | { 0, } | 123 | { 0, } |
124 | }; | 124 | }; |
125 | MODULE_DEVICE_TABLE(pci, vx855_pci_tbl); | ||
125 | 126 | ||
126 | static struct pci_driver vx855_pci_driver = { | 127 | static struct pci_driver vx855_pci_driver = { |
127 | .name = "vx855", | 128 | .name = "vx855", |
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index d2ecc2435736..529d65ba5353 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c | |||
@@ -38,7 +38,6 @@ static int wl1273_core_remove(struct i2c_client *client) | |||
38 | dev_dbg(&client->dev, "%s\n", __func__); | 38 | dev_dbg(&client->dev, "%s\n", __func__); |
39 | 39 | ||
40 | mfd_remove_devices(&client->dev); | 40 | mfd_remove_devices(&client->dev); |
41 | i2c_set_clientdata(client, NULL); | ||
42 | kfree(core); | 41 | kfree(core); |
43 | 42 | ||
44 | return 0; | 43 | return 0; |
@@ -79,8 +78,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, | |||
79 | 78 | ||
80 | cell = &core->cells[children]; | 79 | cell = &core->cells[children]; |
81 | cell->name = "wl1273_fm_radio"; | 80 | cell->name = "wl1273_fm_radio"; |
82 | cell->platform_data = &core; | 81 | cell->mfd_data = &core; |
83 | cell->data_size = sizeof(core); | ||
84 | children++; | 82 | children++; |
85 | 83 | ||
86 | if (pdata->children & WL1273_CODEC_CHILD) { | 84 | if (pdata->children & WL1273_CODEC_CHILD) { |
@@ -88,8 +86,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, | |||
88 | 86 | ||
89 | dev_dbg(&client->dev, "%s: Have codec.\n", __func__); | 87 | dev_dbg(&client->dev, "%s: Have codec.\n", __func__); |
90 | cell->name = "wl1273-codec"; | 88 | cell->name = "wl1273-codec"; |
91 | cell->platform_data = &core; | 89 | cell->mfd_data = &core; |
92 | cell->data_size = sizeof(core); | ||
93 | children++; | 90 | children++; |
94 | } | 91 | } |
95 | 92 | ||
@@ -104,7 +101,6 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, | |||
104 | return 0; | 101 | return 0; |
105 | 102 | ||
106 | err: | 103 | err: |
107 | i2c_set_clientdata(client, NULL); | ||
108 | pdata->free_resources(); | 104 | pdata->free_resources(); |
109 | kfree(core); | 105 | kfree(core); |
110 | 106 | ||
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index 3853fa8e7cc2..a06cbc739716 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c | |||
@@ -51,17 +51,25 @@ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, | |||
51 | int bytes, void *src) | 51 | int bytes, void *src) |
52 | { | 52 | { |
53 | struct i2c_client *i2c = wm831x->control_data; | 53 | struct i2c_client *i2c = wm831x->control_data; |
54 | unsigned char msg[bytes + 2]; | 54 | struct i2c_msg xfer[2]; |
55 | int ret; | 55 | int ret; |
56 | 56 | ||
57 | reg = cpu_to_be16(reg); | 57 | reg = cpu_to_be16(reg); |
58 | memcpy(&msg[0], ®, 2); | ||
59 | memcpy(&msg[2], src, bytes); | ||
60 | 58 | ||
61 | ret = i2c_master_send(i2c, msg, bytes + 2); | 59 | xfer[0].addr = i2c->addr; |
60 | xfer[0].flags = 0; | ||
61 | xfer[0].len = 2; | ||
62 | xfer[0].buf = (char *)® | ||
63 | |||
64 | xfer[1].addr = i2c->addr; | ||
65 | xfer[1].flags = I2C_M_NOSTART; | ||
66 | xfer[1].len = bytes; | ||
67 | xfer[1].buf = (char *)src; | ||
68 | |||
69 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
62 | if (ret < 0) | 70 | if (ret < 0) |
63 | return ret; | 71 | return ret; |
64 | if (ret < bytes + 2) | 72 | if (ret != 2) |
65 | return -EIO; | 73 | return -EIO; |
66 | 74 | ||
67 | return 0; | 75 | return 0; |
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index f7192d438aab..a5cd17e18d09 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c | |||
@@ -26,15 +26,6 @@ | |||
26 | 26 | ||
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | 28 | ||
29 | /* | ||
30 | * Since generic IRQs don't currently support interrupt controllers on | ||
31 | * interrupt driven buses we don't use genirq but instead provide an | ||
32 | * interface that looks very much like the standard ones. This leads | ||
33 | * to some bodges, including storing interrupt handler information in | ||
34 | * the static irq_data table we use to look up the data for individual | ||
35 | * interrupts, but hopefully won't last too long. | ||
36 | */ | ||
37 | |||
38 | struct wm831x_irq_data { | 29 | struct wm831x_irq_data { |
39 | int primary; | 30 | int primary; |
40 | int reg; | 31 | int reg; |
@@ -361,6 +352,10 @@ static void wm831x_irq_sync_unlock(struct irq_data *data) | |||
361 | /* If there's been a change in the mask write it back | 352 | /* If there's been a change in the mask write it back |
362 | * to the hardware. */ | 353 | * to the hardware. */ |
363 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { | 354 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { |
355 | dev_dbg(wm831x->dev, "IRQ mask sync: %x = %x\n", | ||
356 | WM831X_INTERRUPT_STATUS_1_MASK + i, | ||
357 | wm831x->irq_masks_cur[i]); | ||
358 | |||
364 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; | 359 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; |
365 | wm831x_reg_write(wm831x, | 360 | wm831x_reg_write(wm831x, |
366 | WM831X_INTERRUPT_STATUS_1_MASK + i, | 361 | WM831X_INTERRUPT_STATUS_1_MASK + i, |
@@ -371,7 +366,7 @@ static void wm831x_irq_sync_unlock(struct irq_data *data) | |||
371 | mutex_unlock(&wm831x->irq_lock); | 366 | mutex_unlock(&wm831x->irq_lock); |
372 | } | 367 | } |
373 | 368 | ||
374 | static void wm831x_irq_unmask(struct irq_data *data) | 369 | static void wm831x_irq_enable(struct irq_data *data) |
375 | { | 370 | { |
376 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); | 371 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
377 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, | 372 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, |
@@ -380,7 +375,7 @@ static void wm831x_irq_unmask(struct irq_data *data) | |||
380 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; | 375 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; |
381 | } | 376 | } |
382 | 377 | ||
383 | static void wm831x_irq_mask(struct irq_data *data) | 378 | static void wm831x_irq_disable(struct irq_data *data) |
384 | { | 379 | { |
385 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); | 380 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
386 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, | 381 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, |
@@ -426,8 +421,8 @@ static struct irq_chip wm831x_irq_chip = { | |||
426 | .name = "wm831x", | 421 | .name = "wm831x", |
427 | .irq_bus_lock = wm831x_irq_lock, | 422 | .irq_bus_lock = wm831x_irq_lock, |
428 | .irq_bus_sync_unlock = wm831x_irq_sync_unlock, | 423 | .irq_bus_sync_unlock = wm831x_irq_sync_unlock, |
429 | .irq_mask = wm831x_irq_mask, | 424 | .irq_disable = wm831x_irq_disable, |
430 | .irq_unmask = wm831x_irq_unmask, | 425 | .irq_enable = wm831x_irq_enable, |
431 | .irq_set_type = wm831x_irq_set_type, | 426 | .irq_set_type = wm831x_irq_set_type, |
432 | }; | 427 | }; |
433 | 428 | ||
@@ -449,6 +444,18 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
449 | goto out; | 444 | goto out; |
450 | } | 445 | } |
451 | 446 | ||
447 | /* The touch interrupts are visible in the primary register as | ||
448 | * an optimisation; open code this to avoid complicating the | ||
449 | * main handling loop and so we can also skip iterating the | ||
450 | * descriptors. | ||
451 | */ | ||
452 | if (primary & WM831X_TCHPD_INT) | ||
453 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); | ||
454 | if (primary & WM831X_TCHDATA_INT) | ||
455 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); | ||
456 | if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT)) | ||
457 | goto out; | ||
458 | |||
452 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { | 459 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { |
453 | int offset = wm831x_irqs[i].reg - 1; | 460 | int offset = wm831x_irqs[i].reg - 1; |
454 | 461 | ||
@@ -481,6 +488,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
481 | } | 488 | } |
482 | 489 | ||
483 | out: | 490 | out: |
491 | /* Touchscreen interrupts are handled specially in the driver */ | ||
492 | status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); | ||
493 | |||
484 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { | 494 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { |
485 | if (status_regs[i]) | 495 | if (status_regs[i]) |
486 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, | 496 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, |
@@ -517,6 +527,14 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
517 | return 0; | 527 | return 0; |
518 | } | 528 | } |
519 | 529 | ||
530 | if (pdata->irq_cmos) | ||
531 | i = 0; | ||
532 | else | ||
533 | i = WM831X_IRQ_OD; | ||
534 | |||
535 | wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, | ||
536 | WM831X_IRQ_OD, i); | ||
537 | |||
520 | /* Try to flag /IRQ as a wake source; there are a number of | 538 | /* Try to flag /IRQ as a wake source; there are a number of |
521 | * unconditional wake sources in the PMIC so this isn't | 539 | * unconditional wake sources in the PMIC so this isn't |
522 | * conditional but we don't actually care *too* much if it | 540 | * conditional but we don't actually care *too* much if it |
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 0a8f772be88c..eed8e4f7a5a1 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/pm.h> | ||
17 | #include <linux/spi/spi.h> | 18 | #include <linux/spi/spi.h> |
18 | 19 | ||
19 | #include <linux/mfd/wm831x/core.h> | 20 | #include <linux/mfd/wm831x/core.h> |
@@ -113,22 +114,27 @@ static int __devexit wm831x_spi_remove(struct spi_device *spi) | |||
113 | return 0; | 114 | return 0; |
114 | } | 115 | } |
115 | 116 | ||
116 | static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m) | 117 | static int wm831x_spi_suspend(struct device *dev) |
117 | { | 118 | { |
118 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | 119 | struct wm831x *wm831x = dev_get_drvdata(dev); |
119 | 120 | ||
120 | return wm831x_device_suspend(wm831x); | 121 | return wm831x_device_suspend(wm831x); |
121 | } | 122 | } |
122 | 123 | ||
124 | static const struct dev_pm_ops wm831x_spi_pm = { | ||
125 | .freeze = wm831x_spi_suspend, | ||
126 | .suspend = wm831x_spi_suspend, | ||
127 | }; | ||
128 | |||
123 | static struct spi_driver wm8310_spi_driver = { | 129 | static struct spi_driver wm8310_spi_driver = { |
124 | .driver = { | 130 | .driver = { |
125 | .name = "wm8310", | 131 | .name = "wm8310", |
126 | .bus = &spi_bus_type, | 132 | .bus = &spi_bus_type, |
127 | .owner = THIS_MODULE, | 133 | .owner = THIS_MODULE, |
134 | .pm = &wm831x_spi_pm, | ||
128 | }, | 135 | }, |
129 | .probe = wm831x_spi_probe, | 136 | .probe = wm831x_spi_probe, |
130 | .remove = __devexit_p(wm831x_spi_remove), | 137 | .remove = __devexit_p(wm831x_spi_remove), |
131 | .suspend = wm831x_spi_suspend, | ||
132 | }; | 138 | }; |
133 | 139 | ||
134 | static struct spi_driver wm8311_spi_driver = { | 140 | static struct spi_driver wm8311_spi_driver = { |
@@ -136,10 +142,10 @@ static struct spi_driver wm8311_spi_driver = { | |||
136 | .name = "wm8311", | 142 | .name = "wm8311", |
137 | .bus = &spi_bus_type, | 143 | .bus = &spi_bus_type, |
138 | .owner = THIS_MODULE, | 144 | .owner = THIS_MODULE, |
145 | .pm = &wm831x_spi_pm, | ||
139 | }, | 146 | }, |
140 | .probe = wm831x_spi_probe, | 147 | .probe = wm831x_spi_probe, |
141 | .remove = __devexit_p(wm831x_spi_remove), | 148 | .remove = __devexit_p(wm831x_spi_remove), |
142 | .suspend = wm831x_spi_suspend, | ||
143 | }; | 149 | }; |
144 | 150 | ||
145 | static struct spi_driver wm8312_spi_driver = { | 151 | static struct spi_driver wm8312_spi_driver = { |
@@ -147,10 +153,10 @@ static struct spi_driver wm8312_spi_driver = { | |||
147 | .name = "wm8312", | 153 | .name = "wm8312", |
148 | .bus = &spi_bus_type, | 154 | .bus = &spi_bus_type, |
149 | .owner = THIS_MODULE, | 155 | .owner = THIS_MODULE, |
156 | .pm = &wm831x_spi_pm, | ||
150 | }, | 157 | }, |
151 | .probe = wm831x_spi_probe, | 158 | .probe = wm831x_spi_probe, |
152 | .remove = __devexit_p(wm831x_spi_remove), | 159 | .remove = __devexit_p(wm831x_spi_remove), |
153 | .suspend = wm831x_spi_suspend, | ||
154 | }; | 160 | }; |
155 | 161 | ||
156 | static struct spi_driver wm8320_spi_driver = { | 162 | static struct spi_driver wm8320_spi_driver = { |
@@ -158,10 +164,10 @@ static struct spi_driver wm8320_spi_driver = { | |||
158 | .name = "wm8320", | 164 | .name = "wm8320", |
159 | .bus = &spi_bus_type, | 165 | .bus = &spi_bus_type, |
160 | .owner = THIS_MODULE, | 166 | .owner = THIS_MODULE, |
167 | .pm = &wm831x_spi_pm, | ||
161 | }, | 168 | }, |
162 | .probe = wm831x_spi_probe, | 169 | .probe = wm831x_spi_probe, |
163 | .remove = __devexit_p(wm831x_spi_remove), | 170 | .remove = __devexit_p(wm831x_spi_remove), |
164 | .suspend = wm831x_spi_suspend, | ||
165 | }; | 171 | }; |
166 | 172 | ||
167 | static struct spi_driver wm8321_spi_driver = { | 173 | static struct spi_driver wm8321_spi_driver = { |
@@ -169,10 +175,10 @@ static struct spi_driver wm8321_spi_driver = { | |||
169 | .name = "wm8321", | 175 | .name = "wm8321", |
170 | .bus = &spi_bus_type, | 176 | .bus = &spi_bus_type, |
171 | .owner = THIS_MODULE, | 177 | .owner = THIS_MODULE, |
178 | .pm = &wm831x_spi_pm, | ||
172 | }, | 179 | }, |
173 | .probe = wm831x_spi_probe, | 180 | .probe = wm831x_spi_probe, |
174 | .remove = __devexit_p(wm831x_spi_remove), | 181 | .remove = __devexit_p(wm831x_spi_remove), |
175 | .suspend = wm831x_spi_suspend, | ||
176 | }; | 182 | }; |
177 | 183 | ||
178 | static struct spi_driver wm8325_spi_driver = { | 184 | static struct spi_driver wm8325_spi_driver = { |
@@ -180,10 +186,10 @@ static struct spi_driver wm8325_spi_driver = { | |||
180 | .name = "wm8325", | 186 | .name = "wm8325", |
181 | .bus = &spi_bus_type, | 187 | .bus = &spi_bus_type, |
182 | .owner = THIS_MODULE, | 188 | .owner = THIS_MODULE, |
189 | .pm = &wm831x_spi_pm, | ||
183 | }, | 190 | }, |
184 | .probe = wm831x_spi_probe, | 191 | .probe = wm831x_spi_probe, |
185 | .remove = __devexit_p(wm831x_spi_remove), | 192 | .remove = __devexit_p(wm831x_spi_remove), |
186 | .suspend = wm831x_spi_suspend, | ||
187 | }; | 193 | }; |
188 | 194 | ||
189 | static struct spi_driver wm8326_spi_driver = { | 195 | static struct spi_driver wm8326_spi_driver = { |
@@ -191,10 +197,10 @@ static struct spi_driver wm8326_spi_driver = { | |||
191 | .name = "wm8326", | 197 | .name = "wm8326", |
192 | .bus = &spi_bus_type, | 198 | .bus = &spi_bus_type, |
193 | .owner = THIS_MODULE, | 199 | .owner = THIS_MODULE, |
200 | .pm = &wm831x_spi_pm, | ||
194 | }, | 201 | }, |
195 | .probe = wm831x_spi_probe, | 202 | .probe = wm831x_spi_probe, |
196 | .remove = __devexit_p(wm831x_spi_remove), | 203 | .remove = __devexit_p(wm831x_spi_remove), |
197 | .suspend = wm831x_spi_suspend, | ||
198 | }; | 204 | }; |
199 | 205 | ||
200 | static int __init wm831x_spi_init(void) | 206 | static int __init wm831x_spi_init(void) |
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 1bfef4846b07..3a6e78cb0384 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c | |||
@@ -245,7 +245,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400) | |||
245 | { | 245 | { |
246 | struct mfd_cell cell = { | 246 | struct mfd_cell cell = { |
247 | .name = "wm8400-codec", | 247 | .name = "wm8400-codec", |
248 | .driver_data = wm8400, | 248 | .mfd_data = wm8400, |
249 | }; | 249 | }; |
250 | 250 | ||
251 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); | 251 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); |
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index f4016a075fd6..e198d40292e7 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
@@ -40,10 +40,8 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, | |||
40 | return ret; | 40 | return ret; |
41 | 41 | ||
42 | for (i = 0; i < bytes / 2; i++) { | 42 | for (i = 0; i < bytes / 2; i++) { |
43 | buf[i] = be16_to_cpu(buf[i]); | ||
44 | |||
45 | dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", | 43 | dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", |
46 | buf[i], reg + i, reg + i); | 44 | be16_to_cpu(buf[i]), reg + i, reg + i); |
47 | } | 45 | } |
48 | 46 | ||
49 | return 0; | 47 | return 0; |
@@ -69,7 +67,7 @@ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) | |||
69 | if (ret < 0) | 67 | if (ret < 0) |
70 | return ret; | 68 | return ret; |
71 | else | 69 | else |
72 | return val; | 70 | return be16_to_cpu(val); |
73 | } | 71 | } |
74 | EXPORT_SYMBOL_GPL(wm8994_reg_read); | 72 | EXPORT_SYMBOL_GPL(wm8994_reg_read); |
75 | 73 | ||
@@ -79,7 +77,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read); | |||
79 | * @wm8994: Device to read from | 77 | * @wm8994: Device to read from |
80 | * @reg: First register | 78 | * @reg: First register |
81 | * @count: Number of registers | 79 | * @count: Number of registers |
82 | * @buf: Buffer to fill. | 80 | * @buf: Buffer to fill. The data will be returned big endian. |
83 | */ | 81 | */ |
84 | int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, | 82 | int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, |
85 | int count, u16 *buf) | 83 | int count, u16 *buf) |
@@ -97,9 +95,9 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, | |||
97 | EXPORT_SYMBOL_GPL(wm8994_bulk_read); | 95 | EXPORT_SYMBOL_GPL(wm8994_bulk_read); |
98 | 96 | ||
99 | static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, | 97 | static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, |
100 | int bytes, void *src) | 98 | int bytes, const void *src) |
101 | { | 99 | { |
102 | u16 *buf = src; | 100 | const u16 *buf = src; |
103 | int i; | 101 | int i; |
104 | 102 | ||
105 | BUG_ON(bytes % 2); | 103 | BUG_ON(bytes % 2); |
@@ -107,9 +105,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, | |||
107 | 105 | ||
108 | for (i = 0; i < bytes / 2; i++) { | 106 | for (i = 0; i < bytes / 2; i++) { |
109 | dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", | 107 | dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", |
110 | buf[i], reg + i, reg + i); | 108 | be16_to_cpu(buf[i]), reg + i, reg + i); |
111 | |||
112 | buf[i] = cpu_to_be16(buf[i]); | ||
113 | } | 109 | } |
114 | 110 | ||
115 | return wm8994->write_dev(wm8994, reg, bytes, src); | 111 | return wm8994->write_dev(wm8994, reg, bytes, src); |
@@ -127,6 +123,8 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, | |||
127 | { | 123 | { |
128 | int ret; | 124 | int ret; |
129 | 125 | ||
126 | val = cpu_to_be16(val); | ||
127 | |||
130 | mutex_lock(&wm8994->io_lock); | 128 | mutex_lock(&wm8994->io_lock); |
131 | 129 | ||
132 | ret = wm8994_write(wm8994, reg, 2, &val); | 130 | ret = wm8994_write(wm8994, reg, 2, &val); |
@@ -138,6 +136,29 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, | |||
138 | EXPORT_SYMBOL_GPL(wm8994_reg_write); | 136 | EXPORT_SYMBOL_GPL(wm8994_reg_write); |
139 | 137 | ||
140 | /** | 138 | /** |
139 | * wm8994_bulk_write: Write multiple WM8994 registers | ||
140 | * | ||
141 | * @wm8994: Device to write to | ||
142 | * @reg: First register | ||
143 | * @count: Number of registers | ||
144 | * @buf: Buffer to write from. Data must be big-endian formatted. | ||
145 | */ | ||
146 | int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, | ||
147 | int count, const u16 *buf) | ||
148 | { | ||
149 | int ret; | ||
150 | |||
151 | mutex_lock(&wm8994->io_lock); | ||
152 | |||
153 | ret = wm8994_write(wm8994, reg, count * 2, buf); | ||
154 | |||
155 | mutex_unlock(&wm8994->io_lock); | ||
156 | |||
157 | return ret; | ||
158 | } | ||
159 | EXPORT_SYMBOL_GPL(wm8994_bulk_write); | ||
160 | |||
161 | /** | ||
141 | * wm8994_set_bits: Set the value of a bitfield in a WM8994 register | 162 | * wm8994_set_bits: Set the value of a bitfield in a WM8994 register |
142 | * | 163 | * |
143 | * @wm8994: Device to write to. | 164 | * @wm8994: Device to write to. |
@@ -157,9 +178,13 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, | |||
157 | if (ret < 0) | 178 | if (ret < 0) |
158 | goto out; | 179 | goto out; |
159 | 180 | ||
181 | r = be16_to_cpu(r); | ||
182 | |||
160 | r &= ~mask; | 183 | r &= ~mask; |
161 | r |= val; | 184 | r |= val; |
162 | 185 | ||
186 | r = cpu_to_be16(r); | ||
187 | |||
163 | ret = wm8994_write(wm8994, reg, 2, &r); | 188 | ret = wm8994_write(wm8994, reg, 2, &r); |
164 | 189 | ||
165 | out: | 190 | out: |
@@ -271,6 +296,11 @@ static int wm8994_suspend(struct device *dev) | |||
271 | if (ret < 0) | 296 | if (ret < 0) |
272 | dev_err(dev, "Failed to save LDO registers: %d\n", ret); | 297 | dev_err(dev, "Failed to save LDO registers: %d\n", ret); |
273 | 298 | ||
299 | /* Explicitly put the device into reset in case regulators | ||
300 | * don't get disabled in order to ensure consistent restart. | ||
301 | */ | ||
302 | wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994); | ||
303 | |||
274 | wm8994->suspended = true; | 304 | wm8994->suspended = true; |
275 | 305 | ||
276 | ret = regulator_bulk_disable(wm8994->num_supplies, | 306 | ret = regulator_bulk_disable(wm8994->num_supplies, |
@@ -552,25 +582,29 @@ static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg, | |||
552 | return 0; | 582 | return 0; |
553 | } | 583 | } |
554 | 584 | ||
555 | /* Currently we allocate the write buffer on the stack; this is OK for | ||
556 | * small writes - if we need to do large writes this will need to be | ||
557 | * revised. | ||
558 | */ | ||
559 | static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, | 585 | static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, |
560 | int bytes, void *src) | 586 | int bytes, const void *src) |
561 | { | 587 | { |
562 | struct i2c_client *i2c = wm8994->control_data; | 588 | struct i2c_client *i2c = wm8994->control_data; |
563 | unsigned char msg[bytes + 2]; | 589 | struct i2c_msg xfer[2]; |
564 | int ret; | 590 | int ret; |
565 | 591 | ||
566 | reg = cpu_to_be16(reg); | 592 | reg = cpu_to_be16(reg); |
567 | memcpy(&msg[0], ®, 2); | ||
568 | memcpy(&msg[2], src, bytes); | ||
569 | 593 | ||
570 | ret = i2c_master_send(i2c, msg, bytes + 2); | 594 | xfer[0].addr = i2c->addr; |
595 | xfer[0].flags = 0; | ||
596 | xfer[0].len = 2; | ||
597 | xfer[0].buf = (char *)® | ||
598 | |||
599 | xfer[1].addr = i2c->addr; | ||
600 | xfer[1].flags = I2C_M_NOSTART; | ||
601 | xfer[1].len = bytes; | ||
602 | xfer[1].buf = (char *)src; | ||
603 | |||
604 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
571 | if (ret < 0) | 605 | if (ret < 0) |
572 | return ret; | 606 | return ret; |
573 | if (ret < bytes + 2) | 607 | if (ret != 2) |
574 | return -EIO; | 608 | return -EIO; |
575 | 609 | ||
576 | return 0; | 610 | return 0; |
@@ -612,7 +646,8 @@ static const struct i2c_device_id wm8994_i2c_id[] = { | |||
612 | }; | 646 | }; |
613 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); | 647 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); |
614 | 648 | ||
615 | UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL); | 649 | static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, |
650 | NULL); | ||
616 | 651 | ||
617 | static struct i2c_driver wm8994_i2c_driver = { | 652 | static struct i2c_driver wm8994_i2c_driver = { |
618 | .driver = { | 653 | .driver = { |
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 29e8faf9c01c..1e3bf4a2ff8e 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c | |||
@@ -182,7 +182,7 @@ static void wm8994_irq_sync_unlock(struct irq_data *data) | |||
182 | mutex_unlock(&wm8994->irq_lock); | 182 | mutex_unlock(&wm8994->irq_lock); |
183 | } | 183 | } |
184 | 184 | ||
185 | static void wm8994_irq_unmask(struct irq_data *data) | 185 | static void wm8994_irq_enable(struct irq_data *data) |
186 | { | 186 | { |
187 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); | 187 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); |
188 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, | 188 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, |
@@ -191,7 +191,7 @@ static void wm8994_irq_unmask(struct irq_data *data) | |||
191 | wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; | 191 | wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; |
192 | } | 192 | } |
193 | 193 | ||
194 | static void wm8994_irq_mask(struct irq_data *data) | 194 | static void wm8994_irq_disable(struct irq_data *data) |
195 | { | 195 | { |
196 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); | 196 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); |
197 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, | 197 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, |
@@ -204,8 +204,8 @@ static struct irq_chip wm8994_irq_chip = { | |||
204 | .name = "wm8994", | 204 | .name = "wm8994", |
205 | .irq_bus_lock = wm8994_irq_lock, | 205 | .irq_bus_lock = wm8994_irq_lock, |
206 | .irq_bus_sync_unlock = wm8994_irq_sync_unlock, | 206 | .irq_bus_sync_unlock = wm8994_irq_sync_unlock, |
207 | .irq_mask = wm8994_irq_mask, | 207 | .irq_disable = wm8994_irq_disable, |
208 | .irq_unmask = wm8994_irq_unmask, | 208 | .irq_enable = wm8994_irq_enable, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | /* The processing of the primary interrupt occurs in a thread so that | 211 | /* The processing of the primary interrupt occurs in a thread so that |
@@ -225,9 +225,11 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data) | |||
225 | return IRQ_NONE; | 225 | return IRQ_NONE; |
226 | } | 226 | } |
227 | 227 | ||
228 | /* Apply masking */ | 228 | /* Bit swap and apply masking */ |
229 | for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) | 229 | for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) { |
230 | status[i] = be16_to_cpu(status[i]); | ||
230 | status[i] &= ~wm8994->irq_masks_cur[i]; | 231 | status[i] &= ~wm8994->irq_masks_cur[i]; |
232 | } | ||
231 | 233 | ||
232 | /* Report */ | 234 | /* Report */ |
233 | for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) { | 235 | for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) { |