diff options
Diffstat (limited to 'drivers/mfd')
37 files changed, 3692 insertions, 1348 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index b73f033b2c60..59d117e9fa31 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -11,50 +11,116 @@ | |||
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/err.h> | ||
14 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
15 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
16 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/irqdomain.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_platform.h> | ||
17 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/regmap.h> | ||
23 | #include <linux/slab.h> | ||
18 | #include <linux/mfd/core.h> | 24 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/88pm860x.h> | 25 | #include <linux/mfd/88pm860x.h> |
20 | #include <linux/regulator/machine.h> | 26 | #include <linux/regulator/machine.h> |
21 | 27 | ||
22 | #define INT_STATUS_NUM 3 | 28 | #define INT_STATUS_NUM 3 |
23 | 29 | ||
24 | static struct resource bk_resources[] __devinitdata = { | 30 | static struct resource bk0_resources[] __devinitdata = { |
25 | {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,}, | 31 | {2, 2, "duty cycle", IORESOURCE_REG, }, |
26 | {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,}, | 32 | {3, 3, "always on", IORESOURCE_REG, }, |
27 | {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, | 33 | {3, 3, "current", IORESOURCE_REG, }, |
28 | }; | 34 | }; |
29 | 35 | static struct resource bk1_resources[] __devinitdata = { | |
30 | static struct resource led_resources[] __devinitdata = { | 36 | {4, 4, "duty cycle", IORESOURCE_REG, }, |
31 | {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,}, | 37 | {5, 5, "always on", IORESOURCE_REG, }, |
32 | {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,}, | 38 | {5, 5, "current", IORESOURCE_REG, }, |
33 | {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,}, | 39 | }; |
34 | {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,}, | 40 | static struct resource bk2_resources[] __devinitdata = { |
35 | {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,}, | 41 | {6, 6, "duty cycle", IORESOURCE_REG, }, |
36 | {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, | 42 | {7, 7, "always on", IORESOURCE_REG, }, |
37 | }; | 43 | {5, 5, "current", IORESOURCE_REG, }, |
38 | 44 | }; | |
39 | static struct resource regulator_resources[] __devinitdata = { | 45 | |
40 | {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,}, | 46 | static struct resource led0_resources[] __devinitdata = { |
41 | {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,}, | 47 | /* RGB1 Red LED */ |
42 | {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,}, | 48 | {0xd, 0xd, "control", IORESOURCE_REG, }, |
43 | {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,}, | 49 | {0xc, 0xc, "blink", IORESOURCE_REG, }, |
44 | {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,}, | 50 | }; |
45 | {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,}, | 51 | static struct resource led1_resources[] __devinitdata = { |
46 | {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,}, | 52 | /* RGB1 Green LED */ |
47 | {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,}, | 53 | {0xe, 0xe, "control", IORESOURCE_REG, }, |
48 | {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,}, | 54 | {0xc, 0xc, "blink", IORESOURCE_REG, }, |
49 | {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,}, | 55 | }; |
50 | {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,}, | 56 | static struct resource led2_resources[] __devinitdata = { |
51 | {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,}, | 57 | /* RGB1 Blue LED */ |
52 | {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,}, | 58 | {0xf, 0xf, "control", IORESOURCE_REG, }, |
53 | {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,}, | 59 | {0xc, 0xc, "blink", IORESOURCE_REG, }, |
54 | {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,}, | 60 | }; |
55 | {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,}, | 61 | static struct resource led3_resources[] __devinitdata = { |
56 | {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,}, | 62 | /* RGB2 Red LED */ |
57 | {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, | 63 | {0x9, 0x9, "control", IORESOURCE_REG, }, |
64 | {0x8, 0x8, "blink", IORESOURCE_REG, }, | ||
65 | }; | ||
66 | static struct resource led4_resources[] __devinitdata = { | ||
67 | /* RGB2 Green LED */ | ||
68 | {0xa, 0xa, "control", IORESOURCE_REG, }, | ||
69 | {0x8, 0x8, "blink", IORESOURCE_REG, }, | ||
70 | }; | ||
71 | static struct resource led5_resources[] __devinitdata = { | ||
72 | /* RGB2 Blue LED */ | ||
73 | {0xb, 0xb, "control", IORESOURCE_REG, }, | ||
74 | {0x8, 0x8, "blink", IORESOURCE_REG, }, | ||
75 | }; | ||
76 | |||
77 | static struct resource buck1_resources[] __devinitdata = { | ||
78 | {0x24, 0x24, "buck set", IORESOURCE_REG, }, | ||
79 | }; | ||
80 | static struct resource buck2_resources[] __devinitdata = { | ||
81 | {0x25, 0x25, "buck set", IORESOURCE_REG, }, | ||
82 | }; | ||
83 | static struct resource buck3_resources[] __devinitdata = { | ||
84 | {0x26, 0x26, "buck set", IORESOURCE_REG, }, | ||
85 | }; | ||
86 | static struct resource ldo1_resources[] __devinitdata = { | ||
87 | {0x10, 0x10, "ldo set", IORESOURCE_REG, }, | ||
88 | }; | ||
89 | static struct resource ldo2_resources[] __devinitdata = { | ||
90 | {0x11, 0x11, "ldo set", IORESOURCE_REG, }, | ||
91 | }; | ||
92 | static struct resource ldo3_resources[] __devinitdata = { | ||
93 | {0x12, 0x12, "ldo set", IORESOURCE_REG, }, | ||
94 | }; | ||
95 | static struct resource ldo4_resources[] __devinitdata = { | ||
96 | {0x13, 0x13, "ldo set", IORESOURCE_REG, }, | ||
97 | }; | ||
98 | static struct resource ldo5_resources[] __devinitdata = { | ||
99 | {0x14, 0x14, "ldo set", IORESOURCE_REG, }, | ||
100 | }; | ||
101 | static struct resource ldo6_resources[] __devinitdata = { | ||
102 | {0x15, 0x15, "ldo set", IORESOURCE_REG, }, | ||
103 | }; | ||
104 | static struct resource ldo7_resources[] __devinitdata = { | ||
105 | {0x16, 0x16, "ldo set", IORESOURCE_REG, }, | ||
106 | }; | ||
107 | static struct resource ldo8_resources[] __devinitdata = { | ||
108 | {0x17, 0x17, "ldo set", IORESOURCE_REG, }, | ||
109 | }; | ||
110 | static struct resource ldo9_resources[] __devinitdata = { | ||
111 | {0x18, 0x18, "ldo set", IORESOURCE_REG, }, | ||
112 | }; | ||
113 | static struct resource ldo10_resources[] __devinitdata = { | ||
114 | {0x19, 0x19, "ldo set", IORESOURCE_REG, }, | ||
115 | }; | ||
116 | static struct resource ldo12_resources[] __devinitdata = { | ||
117 | {0x1a, 0x1a, "ldo set", IORESOURCE_REG, }, | ||
118 | }; | ||
119 | static struct resource ldo_vibrator_resources[] __devinitdata = { | ||
120 | {0x28, 0x28, "ldo set", IORESOURCE_REG, }, | ||
121 | }; | ||
122 | static struct resource ldo14_resources[] __devinitdata = { | ||
123 | {0x1b, 0x1b, "ldo set", IORESOURCE_REG, }, | ||
58 | }; | 124 | }; |
59 | 125 | ||
60 | static struct resource touch_resources[] __devinitdata = { | 126 | static struct resource touch_resources[] __devinitdata = { |
@@ -90,48 +156,145 @@ static struct resource charger_resources[] __devinitdata = { | |||
90 | {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, | 156 | {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, |
91 | }; | 157 | }; |
92 | 158 | ||
93 | static struct resource preg_resources[] __devinitdata = { | ||
94 | {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO,}, | ||
95 | }; | ||
96 | |||
97 | static struct resource rtc_resources[] __devinitdata = { | 159 | static struct resource rtc_resources[] __devinitdata = { |
98 | {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, | 160 | {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, |
99 | }; | 161 | }; |
100 | 162 | ||
101 | static struct mfd_cell bk_devs[] = { | 163 | static struct mfd_cell bk_devs[] __devinitdata = { |
102 | {"88pm860x-backlight", 0,}, | 164 | { |
103 | {"88pm860x-backlight", 1,}, | 165 | .name = "88pm860x-backlight", |
104 | {"88pm860x-backlight", 2,}, | 166 | .id = 0, |
105 | }; | 167 | .num_resources = ARRAY_SIZE(bk0_resources), |
106 | 168 | .resources = bk0_resources, | |
107 | static struct mfd_cell led_devs[] = { | 169 | }, { |
108 | {"88pm860x-led", 0,}, | 170 | .name = "88pm860x-backlight", |
109 | {"88pm860x-led", 1,}, | 171 | .id = 1, |
110 | {"88pm860x-led", 2,}, | 172 | .num_resources = ARRAY_SIZE(bk1_resources), |
111 | {"88pm860x-led", 3,}, | 173 | .resources = bk1_resources, |
112 | {"88pm860x-led", 4,}, | 174 | }, { |
113 | {"88pm860x-led", 5,}, | 175 | .name = "88pm860x-backlight", |
114 | }; | 176 | .id = 2, |
115 | 177 | .num_resources = ARRAY_SIZE(bk2_resources), | |
116 | static struct mfd_cell regulator_devs[] = { | 178 | .resources = bk2_resources, |
117 | {"88pm860x-regulator", 0,}, | 179 | }, |
118 | {"88pm860x-regulator", 1,}, | 180 | }; |
119 | {"88pm860x-regulator", 2,}, | 181 | |
120 | {"88pm860x-regulator", 3,}, | 182 | static struct mfd_cell led_devs[] __devinitdata = { |
121 | {"88pm860x-regulator", 4,}, | 183 | { |
122 | {"88pm860x-regulator", 5,}, | 184 | .name = "88pm860x-led", |
123 | {"88pm860x-regulator", 6,}, | 185 | .id = 0, |
124 | {"88pm860x-regulator", 7,}, | 186 | .num_resources = ARRAY_SIZE(led0_resources), |
125 | {"88pm860x-regulator", 8,}, | 187 | .resources = led0_resources, |
126 | {"88pm860x-regulator", 9,}, | 188 | }, { |
127 | {"88pm860x-regulator", 10,}, | 189 | .name = "88pm860x-led", |
128 | {"88pm860x-regulator", 11,}, | 190 | .id = 1, |
129 | {"88pm860x-regulator", 12,}, | 191 | .num_resources = ARRAY_SIZE(led1_resources), |
130 | {"88pm860x-regulator", 13,}, | 192 | .resources = led1_resources, |
131 | {"88pm860x-regulator", 14,}, | 193 | }, { |
132 | {"88pm860x-regulator", 15,}, | 194 | .name = "88pm860x-led", |
133 | {"88pm860x-regulator", 16,}, | 195 | .id = 2, |
134 | {"88pm860x-regulator", 17,}, | 196 | .num_resources = ARRAY_SIZE(led2_resources), |
197 | .resources = led2_resources, | ||
198 | }, { | ||
199 | .name = "88pm860x-led", | ||
200 | .id = 3, | ||
201 | .num_resources = ARRAY_SIZE(led3_resources), | ||
202 | .resources = led3_resources, | ||
203 | }, { | ||
204 | .name = "88pm860x-led", | ||
205 | .id = 4, | ||
206 | .num_resources = ARRAY_SIZE(led4_resources), | ||
207 | .resources = led4_resources, | ||
208 | }, { | ||
209 | .name = "88pm860x-led", | ||
210 | .id = 5, | ||
211 | .num_resources = ARRAY_SIZE(led5_resources), | ||
212 | .resources = led5_resources, | ||
213 | }, | ||
214 | }; | ||
215 | |||
216 | static struct mfd_cell reg_devs[] __devinitdata = { | ||
217 | { | ||
218 | .name = "88pm860x-regulator", | ||
219 | .id = 0, | ||
220 | .num_resources = ARRAY_SIZE(buck1_resources), | ||
221 | .resources = buck1_resources, | ||
222 | }, { | ||
223 | .name = "88pm860x-regulator", | ||
224 | .id = 1, | ||
225 | .num_resources = ARRAY_SIZE(buck2_resources), | ||
226 | .resources = buck2_resources, | ||
227 | }, { | ||
228 | .name = "88pm860x-regulator", | ||
229 | .id = 2, | ||
230 | .num_resources = ARRAY_SIZE(buck3_resources), | ||
231 | .resources = buck3_resources, | ||
232 | }, { | ||
233 | .name = "88pm860x-regulator", | ||
234 | .id = 3, | ||
235 | .num_resources = ARRAY_SIZE(ldo1_resources), | ||
236 | .resources = ldo1_resources, | ||
237 | }, { | ||
238 | .name = "88pm860x-regulator", | ||
239 | .id = 4, | ||
240 | .num_resources = ARRAY_SIZE(ldo2_resources), | ||
241 | .resources = ldo2_resources, | ||
242 | }, { | ||
243 | .name = "88pm860x-regulator", | ||
244 | .id = 5, | ||
245 | .num_resources = ARRAY_SIZE(ldo3_resources), | ||
246 | .resources = ldo3_resources, | ||
247 | }, { | ||
248 | .name = "88pm860x-regulator", | ||
249 | .id = 6, | ||
250 | .num_resources = ARRAY_SIZE(ldo4_resources), | ||
251 | .resources = ldo4_resources, | ||
252 | }, { | ||
253 | .name = "88pm860x-regulator", | ||
254 | .id = 7, | ||
255 | .num_resources = ARRAY_SIZE(ldo5_resources), | ||
256 | .resources = ldo5_resources, | ||
257 | }, { | ||
258 | .name = "88pm860x-regulator", | ||
259 | .id = 8, | ||
260 | .num_resources = ARRAY_SIZE(ldo6_resources), | ||
261 | .resources = ldo6_resources, | ||
262 | }, { | ||
263 | .name = "88pm860x-regulator", | ||
264 | .id = 9, | ||
265 | .num_resources = ARRAY_SIZE(ldo7_resources), | ||
266 | .resources = ldo7_resources, | ||
267 | }, { | ||
268 | .name = "88pm860x-regulator", | ||
269 | .id = 10, | ||
270 | .num_resources = ARRAY_SIZE(ldo8_resources), | ||
271 | .resources = ldo8_resources, | ||
272 | }, { | ||
273 | .name = "88pm860x-regulator", | ||
274 | .id = 11, | ||
275 | .num_resources = ARRAY_SIZE(ldo9_resources), | ||
276 | .resources = ldo9_resources, | ||
277 | }, { | ||
278 | .name = "88pm860x-regulator", | ||
279 | .id = 12, | ||
280 | .num_resources = ARRAY_SIZE(ldo10_resources), | ||
281 | .resources = ldo10_resources, | ||
282 | }, { | ||
283 | .name = "88pm860x-regulator", | ||
284 | .id = 13, | ||
285 | .num_resources = ARRAY_SIZE(ldo12_resources), | ||
286 | .resources = ldo12_resources, | ||
287 | }, { | ||
288 | .name = "88pm860x-regulator", | ||
289 | .id = 14, | ||
290 | .num_resources = ARRAY_SIZE(ldo_vibrator_resources), | ||
291 | .resources = ldo_vibrator_resources, | ||
292 | }, { | ||
293 | .name = "88pm860x-regulator", | ||
294 | .id = 15, | ||
295 | .num_resources = ARRAY_SIZE(ldo14_resources), | ||
296 | .resources = ldo14_resources, | ||
297 | }, | ||
135 | }; | 298 | }; |
136 | 299 | ||
137 | static struct mfd_cell touch_devs[] = { | 300 | static struct mfd_cell touch_devs[] = { |
@@ -360,15 +523,12 @@ static void pm860x_irq_sync_unlock(struct irq_data *data) | |||
360 | 523 | ||
361 | static void pm860x_irq_enable(struct irq_data *data) | 524 | static void pm860x_irq_enable(struct irq_data *data) |
362 | { | 525 | { |
363 | struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); | 526 | pm860x_irqs[data->hwirq].enable = pm860x_irqs[data->hwirq].offs; |
364 | pm860x_irqs[data->irq - chip->irq_base].enable | ||
365 | = pm860x_irqs[data->irq - chip->irq_base].offs; | ||
366 | } | 527 | } |
367 | 528 | ||
368 | static void pm860x_irq_disable(struct irq_data *data) | 529 | static void pm860x_irq_disable(struct irq_data *data) |
369 | { | 530 | { |
370 | struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); | 531 | pm860x_irqs[data->hwirq].enable = 0; |
371 | pm860x_irqs[data->irq - chip->irq_base].enable = 0; | ||
372 | } | 532 | } |
373 | 533 | ||
374 | static struct irq_chip pm860x_irq_chip = { | 534 | static struct irq_chip pm860x_irq_chip = { |
@@ -379,53 +539,25 @@ static struct irq_chip pm860x_irq_chip = { | |||
379 | .irq_disable = pm860x_irq_disable, | 539 | .irq_disable = pm860x_irq_disable, |
380 | }; | 540 | }; |
381 | 541 | ||
382 | static int __devinit device_gpadc_init(struct pm860x_chip *chip, | 542 | static int pm860x_irq_domain_map(struct irq_domain *d, unsigned int virq, |
383 | struct pm860x_platform_data *pdata) | 543 | irq_hw_number_t hw) |
384 | { | 544 | { |
385 | struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ | 545 | irq_set_chip_data(virq, d->host_data); |
386 | : chip->companion; | 546 | irq_set_chip_and_handler(virq, &pm860x_irq_chip, handle_edge_irq); |
387 | int data; | 547 | irq_set_nested_thread(virq, 1); |
388 | int ret; | 548 | #ifdef CONFIG_ARM |
389 | 549 | set_irq_flags(virq, IRQF_VALID); | |
390 | /* initialize GPADC without activating it */ | 550 | #else |
391 | 551 | irq_set_noprobe(virq); | |
392 | if (!pdata || !pdata->touch) | 552 | #endif |
393 | return -EINVAL; | 553 | return 0; |
394 | |||
395 | /* set GPADC MISC1 register */ | ||
396 | data = 0; | ||
397 | data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK; | ||
398 | data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK; | ||
399 | data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK; | ||
400 | data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK; | ||
401 | if (data) { | ||
402 | ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); | ||
403 | if (ret < 0) | ||
404 | goto out; | ||
405 | } | ||
406 | /* set tsi prebias time */ | ||
407 | if (pdata->touch->tsi_prebias) { | ||
408 | data = pdata->touch->tsi_prebias; | ||
409 | ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); | ||
410 | if (ret < 0) | ||
411 | goto out; | ||
412 | } | ||
413 | /* set prebias & prechg time of pen detect */ | ||
414 | data = 0; | ||
415 | data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK; | ||
416 | data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK; | ||
417 | if (data) { | ||
418 | ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); | ||
419 | if (ret < 0) | ||
420 | goto out; | ||
421 | } | ||
422 | |||
423 | ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, | ||
424 | PM8607_GPADC_EN, PM8607_GPADC_EN); | ||
425 | out: | ||
426 | return ret; | ||
427 | } | 554 | } |
428 | 555 | ||
556 | static struct irq_domain_ops pm860x_irq_domain_ops = { | ||
557 | .map = pm860x_irq_domain_map, | ||
558 | .xlate = irq_domain_xlate_onetwocell, | ||
559 | }; | ||
560 | |||
429 | static int __devinit device_irq_init(struct pm860x_chip *chip, | 561 | static int __devinit device_irq_init(struct pm860x_chip *chip, |
430 | struct pm860x_platform_data *pdata) | 562 | struct pm860x_platform_data *pdata) |
431 | { | 563 | { |
@@ -433,13 +565,9 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, | |||
433 | : chip->companion; | 565 | : chip->companion; |
434 | unsigned char status_buf[INT_STATUS_NUM]; | 566 | unsigned char status_buf[INT_STATUS_NUM]; |
435 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | 567 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; |
436 | int i, data, mask, ret = -EINVAL; | 568 | int data, mask, ret = -EINVAL; |
437 | int __irq; | 569 | int nr_irqs, irq_base = -1; |
438 | 570 | struct device_node *node = i2c->dev.of_node; | |
439 | if (!pdata || !pdata->irq_base) { | ||
440 | dev_warn(chip->dev, "No interrupt support on IRQ base\n"); | ||
441 | return -EINVAL; | ||
442 | } | ||
443 | 571 | ||
444 | mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR | 572 | mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR |
445 | | PM8607_B0_MISC1_INT_MASK; | 573 | | PM8607_B0_MISC1_INT_MASK; |
@@ -479,26 +607,24 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, | |||
479 | goto out; | 607 | goto out; |
480 | 608 | ||
481 | mutex_init(&chip->irq_lock); | 609 | mutex_init(&chip->irq_lock); |
482 | chip->irq_base = pdata->irq_base; | 610 | |
611 | if (pdata && pdata->irq_base) | ||
612 | irq_base = pdata->irq_base; | ||
613 | nr_irqs = ARRAY_SIZE(pm860x_irqs); | ||
614 | chip->irq_base = irq_alloc_descs(irq_base, 0, nr_irqs, 0); | ||
615 | if (chip->irq_base < 0) { | ||
616 | dev_err(&i2c->dev, "Failed to allocate interrupts, ret:%d\n", | ||
617 | chip->irq_base); | ||
618 | ret = -EBUSY; | ||
619 | goto out; | ||
620 | } | ||
621 | irq_domain_add_legacy(node, nr_irqs, chip->irq_base, 0, | ||
622 | &pm860x_irq_domain_ops, chip); | ||
483 | chip->core_irq = i2c->irq; | 623 | chip->core_irq = i2c->irq; |
484 | if (!chip->core_irq) | 624 | if (!chip->core_irq) |
485 | goto out; | 625 | goto out; |
486 | 626 | ||
487 | /* register IRQ by genirq */ | 627 | ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags | IRQF_ONESHOT, |
488 | for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { | ||
489 | __irq = i + chip->irq_base; | ||
490 | irq_set_chip_data(__irq, chip); | ||
491 | irq_set_chip_and_handler(__irq, &pm860x_irq_chip, | ||
492 | handle_edge_irq); | ||
493 | irq_set_nested_thread(__irq, 1); | ||
494 | #ifdef CONFIG_ARM | ||
495 | set_irq_flags(__irq, IRQF_VALID); | ||
496 | #else | ||
497 | irq_set_noprobe(__irq); | ||
498 | #endif | ||
499 | } | ||
500 | |||
501 | ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags, | ||
502 | "88pm860x", chip); | 628 | "88pm860x", chip); |
503 | if (ret) { | 629 | if (ret) { |
504 | dev_err(chip->dev, "Failed to request IRQ: %d\n", ret); | 630 | dev_err(chip->dev, "Failed to request IRQ: %d\n", ret); |
@@ -615,108 +741,122 @@ static void __devinit device_osc_init(struct i2c_client *i2c) | |||
615 | static void __devinit device_bk_init(struct pm860x_chip *chip, | 741 | static void __devinit device_bk_init(struct pm860x_chip *chip, |
616 | struct pm860x_platform_data *pdata) | 742 | struct pm860x_platform_data *pdata) |
617 | { | 743 | { |
618 | int ret; | 744 | int ret, i; |
619 | int i, j, id; | 745 | |
620 | 746 | if (pdata && pdata->backlight) { | |
621 | if ((pdata == NULL) || (pdata->backlight == NULL)) | 747 | if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) |
622 | return; | 748 | pdata->num_backlights = ARRAY_SIZE(bk_devs); |
623 | 749 | for (i = 0; i < pdata->num_backlights; i++) { | |
624 | if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) | 750 | bk_devs[i].platform_data = &pdata->backlight[i]; |
625 | pdata->num_backlights = ARRAY_SIZE(bk_devs); | 751 | bk_devs[i].pdata_size = |
626 | 752 | sizeof(struct pm860x_backlight_pdata); | |
627 | for (i = 0; i < pdata->num_backlights; i++) { | ||
628 | bk_devs[i].platform_data = &pdata->backlight[i]; | ||
629 | bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata); | ||
630 | |||
631 | for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { | ||
632 | id = bk_resources[j].start; | ||
633 | if (pdata->backlight[i].flags != id) | ||
634 | continue; | ||
635 | |||
636 | bk_devs[i].num_resources = 1; | ||
637 | bk_devs[i].resources = &bk_resources[j]; | ||
638 | ret = mfd_add_devices(chip->dev, 0, | ||
639 | &bk_devs[i], 1, | ||
640 | &bk_resources[j], 0, NULL); | ||
641 | if (ret < 0) { | ||
642 | dev_err(chip->dev, "Failed to add " | ||
643 | "backlight subdev\n"); | ||
644 | return; | ||
645 | } | ||
646 | } | 753 | } |
647 | } | 754 | } |
755 | ret = mfd_add_devices(chip->dev, 0, bk_devs, | ||
756 | ARRAY_SIZE(bk_devs), NULL, 0, NULL); | ||
757 | if (ret < 0) | ||
758 | dev_err(chip->dev, "Failed to add backlight subdev\n"); | ||
648 | } | 759 | } |
649 | 760 | ||
650 | static void __devinit device_led_init(struct pm860x_chip *chip, | 761 | static void __devinit device_led_init(struct pm860x_chip *chip, |
651 | struct pm860x_platform_data *pdata) | 762 | struct pm860x_platform_data *pdata) |
652 | { | 763 | { |
653 | int ret; | 764 | int ret, i; |
654 | int i, j, id; | 765 | |
655 | 766 | if (pdata && pdata->led) { | |
656 | if ((pdata == NULL) || (pdata->led == NULL)) | 767 | if (pdata->num_leds > ARRAY_SIZE(led_devs)) |
657 | return; | 768 | pdata->num_leds = ARRAY_SIZE(led_devs); |
658 | 769 | for (i = 0; i < pdata->num_leds; i++) { | |
659 | if (pdata->num_leds > ARRAY_SIZE(led_devs)) | 770 | led_devs[i].platform_data = &pdata->led[i]; |
660 | pdata->num_leds = ARRAY_SIZE(led_devs); | 771 | led_devs[i].pdata_size = |
661 | 772 | sizeof(struct pm860x_led_pdata); | |
662 | for (i = 0; i < pdata->num_leds; i++) { | ||
663 | led_devs[i].platform_data = &pdata->led[i]; | ||
664 | led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata); | ||
665 | |||
666 | for (j = 0; j < ARRAY_SIZE(led_devs); j++) { | ||
667 | id = led_resources[j].start; | ||
668 | if (pdata->led[i].flags != id) | ||
669 | continue; | ||
670 | |||
671 | led_devs[i].num_resources = 1; | ||
672 | led_devs[i].resources = &led_resources[j], | ||
673 | ret = mfd_add_devices(chip->dev, 0, | ||
674 | &led_devs[i], 1, | ||
675 | &led_resources[j], 0, NULL); | ||
676 | if (ret < 0) { | ||
677 | dev_err(chip->dev, "Failed to add " | ||
678 | "led subdev\n"); | ||
679 | return; | ||
680 | } | ||
681 | } | 773 | } |
682 | } | 774 | } |
775 | ret = mfd_add_devices(chip->dev, 0, led_devs, | ||
776 | ARRAY_SIZE(led_devs), NULL, 0, NULL); | ||
777 | if (ret < 0) { | ||
778 | dev_err(chip->dev, "Failed to add led subdev\n"); | ||
779 | return; | ||
780 | } | ||
683 | } | 781 | } |
684 | 782 | ||
685 | static void __devinit device_regulator_init(struct pm860x_chip *chip, | 783 | static void __devinit device_regulator_init(struct pm860x_chip *chip, |
686 | struct pm860x_platform_data *pdata) | 784 | struct pm860x_platform_data *pdata) |
687 | { | 785 | { |
688 | struct regulator_init_data *initdata; | ||
689 | int ret; | 786 | int ret; |
690 | int i, seq; | ||
691 | 787 | ||
692 | if ((pdata == NULL) || (pdata->regulator == NULL)) | 788 | if (pdata == NULL) |
789 | return; | ||
790 | if (pdata->buck1) { | ||
791 | reg_devs[0].platform_data = pdata->buck1; | ||
792 | reg_devs[0].pdata_size = sizeof(struct regulator_init_data); | ||
793 | } | ||
794 | if (pdata->buck2) { | ||
795 | reg_devs[1].platform_data = pdata->buck2; | ||
796 | reg_devs[1].pdata_size = sizeof(struct regulator_init_data); | ||
797 | } | ||
798 | if (pdata->buck3) { | ||
799 | reg_devs[2].platform_data = pdata->buck3; | ||
800 | reg_devs[2].pdata_size = sizeof(struct regulator_init_data); | ||
801 | } | ||
802 | if (pdata->ldo1) { | ||
803 | reg_devs[3].platform_data = pdata->ldo1; | ||
804 | reg_devs[3].pdata_size = sizeof(struct regulator_init_data); | ||
805 | } | ||
806 | if (pdata->ldo2) { | ||
807 | reg_devs[4].platform_data = pdata->ldo2; | ||
808 | reg_devs[4].pdata_size = sizeof(struct regulator_init_data); | ||
809 | } | ||
810 | if (pdata->ldo3) { | ||
811 | reg_devs[5].platform_data = pdata->ldo3; | ||
812 | reg_devs[5].pdata_size = sizeof(struct regulator_init_data); | ||
813 | } | ||
814 | if (pdata->ldo4) { | ||
815 | reg_devs[6].platform_data = pdata->ldo4; | ||
816 | reg_devs[6].pdata_size = sizeof(struct regulator_init_data); | ||
817 | } | ||
818 | if (pdata->ldo5) { | ||
819 | reg_devs[7].platform_data = pdata->ldo5; | ||
820 | reg_devs[7].pdata_size = sizeof(struct regulator_init_data); | ||
821 | } | ||
822 | if (pdata->ldo6) { | ||
823 | reg_devs[8].platform_data = pdata->ldo6; | ||
824 | reg_devs[8].pdata_size = sizeof(struct regulator_init_data); | ||
825 | } | ||
826 | if (pdata->ldo7) { | ||
827 | reg_devs[9].platform_data = pdata->ldo7; | ||
828 | reg_devs[9].pdata_size = sizeof(struct regulator_init_data); | ||
829 | } | ||
830 | if (pdata->ldo8) { | ||
831 | reg_devs[10].platform_data = pdata->ldo8; | ||
832 | reg_devs[10].pdata_size = sizeof(struct regulator_init_data); | ||
833 | } | ||
834 | if (pdata->ldo9) { | ||
835 | reg_devs[11].platform_data = pdata->ldo9; | ||
836 | reg_devs[11].pdata_size = sizeof(struct regulator_init_data); | ||
837 | } | ||
838 | if (pdata->ldo10) { | ||
839 | reg_devs[12].platform_data = pdata->ldo10; | ||
840 | reg_devs[12].pdata_size = sizeof(struct regulator_init_data); | ||
841 | } | ||
842 | if (pdata->ldo12) { | ||
843 | reg_devs[13].platform_data = pdata->ldo12; | ||
844 | reg_devs[13].pdata_size = sizeof(struct regulator_init_data); | ||
845 | } | ||
846 | if (pdata->ldo_vibrator) { | ||
847 | reg_devs[14].platform_data = pdata->ldo_vibrator; | ||
848 | reg_devs[14].pdata_size = sizeof(struct regulator_init_data); | ||
849 | } | ||
850 | if (pdata->ldo14) { | ||
851 | reg_devs[15].platform_data = pdata->ldo14; | ||
852 | reg_devs[15].pdata_size = sizeof(struct regulator_init_data); | ||
853 | } | ||
854 | ret = mfd_add_devices(chip->dev, 0, reg_devs, | ||
855 | ARRAY_SIZE(reg_devs), NULL, 0, NULL); | ||
856 | if (ret < 0) { | ||
857 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | ||
693 | return; | 858 | return; |
694 | |||
695 | if (pdata->num_regulators > ARRAY_SIZE(regulator_devs)) | ||
696 | pdata->num_regulators = ARRAY_SIZE(regulator_devs); | ||
697 | |||
698 | for (i = 0, seq = -1; i < pdata->num_regulators; i++) { | ||
699 | initdata = &pdata->regulator[i]; | ||
700 | seq = *(unsigned int *)initdata->driver_data; | ||
701 | if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) { | ||
702 | dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n", | ||
703 | seq, initdata->constraints.name); | ||
704 | goto out; | ||
705 | } | ||
706 | regulator_devs[i].platform_data = &pdata->regulator[i]; | ||
707 | regulator_devs[i].pdata_size = sizeof(struct regulator_init_data); | ||
708 | regulator_devs[i].num_resources = 1; | ||
709 | regulator_devs[i].resources = ®ulator_resources[seq]; | ||
710 | |||
711 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, | ||
712 | ®ulator_resources[seq], 0, NULL); | ||
713 | if (ret < 0) { | ||
714 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | ||
715 | goto out; | ||
716 | } | ||
717 | } | 859 | } |
718 | out: | ||
719 | return; | ||
720 | } | 860 | } |
721 | 861 | ||
722 | static void __devinit device_rtc_init(struct pm860x_chip *chip, | 862 | static void __devinit device_rtc_init(struct pm860x_chip *chip, |
@@ -785,10 +925,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip, | |||
785 | 925 | ||
786 | power_devs[2].platform_data = &preg_init_data; | 926 | power_devs[2].platform_data = &preg_init_data; |
787 | power_devs[2].pdata_size = sizeof(struct regulator_init_data); | 927 | power_devs[2].pdata_size = sizeof(struct regulator_init_data); |
788 | power_devs[2].num_resources = ARRAY_SIZE(preg_resources); | ||
789 | power_devs[2].resources = &preg_resources[0], | ||
790 | ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, | 928 | ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, |
791 | &preg_resources[0], chip->irq_base, NULL); | 929 | NULL, chip->irq_base, NULL); |
792 | if (ret < 0) | 930 | if (ret < 0) |
793 | dev_err(chip->dev, "Failed to add preg subdev\n"); | 931 | dev_err(chip->dev, "Failed to add preg subdev\n"); |
794 | } | 932 | } |
@@ -868,10 +1006,6 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, | |||
868 | goto out; | 1006 | goto out; |
869 | } | 1007 | } |
870 | 1008 | ||
871 | ret = device_gpadc_init(chip, pdata); | ||
872 | if (ret < 0) | ||
873 | goto out; | ||
874 | |||
875 | ret = device_irq_init(chip, pdata); | 1009 | ret = device_irq_init(chip, pdata); |
876 | if (ret < 0) | 1010 | if (ret < 0) |
877 | goto out; | 1011 | goto out; |
@@ -895,8 +1029,8 @@ static void __devinit device_8606_init(struct pm860x_chip *chip, | |||
895 | device_led_init(chip, pdata); | 1029 | device_led_init(chip, pdata); |
896 | } | 1030 | } |
897 | 1031 | ||
898 | int __devinit pm860x_device_init(struct pm860x_chip *chip, | 1032 | static int __devinit pm860x_device_init(struct pm860x_chip *chip, |
899 | struct pm860x_platform_data *pdata) | 1033 | struct pm860x_platform_data *pdata) |
900 | { | 1034 | { |
901 | chip->core_irq = 0; | 1035 | chip->core_irq = 0; |
902 | 1036 | ||
@@ -923,12 +1057,207 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, | |||
923 | return 0; | 1057 | return 0; |
924 | } | 1058 | } |
925 | 1059 | ||
926 | void __devexit pm860x_device_exit(struct pm860x_chip *chip) | 1060 | static void __devexit pm860x_device_exit(struct pm860x_chip *chip) |
927 | { | 1061 | { |
928 | device_irq_exit(chip); | 1062 | device_irq_exit(chip); |
929 | mfd_remove_devices(chip->dev); | 1063 | mfd_remove_devices(chip->dev); |
930 | } | 1064 | } |
931 | 1065 | ||
1066 | static int verify_addr(struct i2c_client *i2c) | ||
1067 | { | ||
1068 | unsigned short addr_8607[] = {0x30, 0x34}; | ||
1069 | unsigned short addr_8606[] = {0x10, 0x11}; | ||
1070 | int size, i; | ||
1071 | |||
1072 | if (i2c == NULL) | ||
1073 | return 0; | ||
1074 | size = ARRAY_SIZE(addr_8606); | ||
1075 | for (i = 0; i < size; i++) { | ||
1076 | if (i2c->addr == *(addr_8606 + i)) | ||
1077 | return CHIP_PM8606; | ||
1078 | } | ||
1079 | size = ARRAY_SIZE(addr_8607); | ||
1080 | for (i = 0; i < size; i++) { | ||
1081 | if (i2c->addr == *(addr_8607 + i)) | ||
1082 | return CHIP_PM8607; | ||
1083 | } | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | static struct regmap_config pm860x_regmap_config = { | ||
1088 | .reg_bits = 8, | ||
1089 | .val_bits = 8, | ||
1090 | }; | ||
1091 | |||
1092 | static int __devinit pm860x_dt_init(struct device_node *np, | ||
1093 | struct device *dev, | ||
1094 | struct pm860x_platform_data *pdata) | ||
1095 | { | ||
1096 | int ret; | ||
1097 | |||
1098 | if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL)) | ||
1099 | pdata->irq_mode = 1; | ||
1100 | ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr", | ||
1101 | &pdata->companion_addr); | ||
1102 | if (ret) { | ||
1103 | dev_err(dev, "Not found \"marvell,88pm860x-slave-addr\" " | ||
1104 | "property\n"); | ||
1105 | pdata->companion_addr = 0; | ||
1106 | } | ||
1107 | return 0; | ||
1108 | } | ||
1109 | |||
1110 | static int __devinit pm860x_probe(struct i2c_client *client, | ||
1111 | const struct i2c_device_id *id) | ||
1112 | { | ||
1113 | struct pm860x_platform_data *pdata = client->dev.platform_data; | ||
1114 | struct device_node *node = client->dev.of_node; | ||
1115 | struct pm860x_chip *chip; | ||
1116 | int ret; | ||
1117 | |||
1118 | if (node && !pdata) { | ||
1119 | /* parse DT to get platform data */ | ||
1120 | pdata = devm_kzalloc(&client->dev, | ||
1121 | sizeof(struct pm860x_platform_data), | ||
1122 | GFP_KERNEL); | ||
1123 | if (!pdata) | ||
1124 | return -ENOMEM; | ||
1125 | ret = pm860x_dt_init(node, &client->dev, pdata); | ||
1126 | if (ret) | ||
1127 | goto err; | ||
1128 | } else if (!pdata) { | ||
1129 | pr_info("No platform data in %s!\n", __func__); | ||
1130 | return -EINVAL; | ||
1131 | } | ||
1132 | |||
1133 | chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); | ||
1134 | if (chip == NULL) { | ||
1135 | ret = -ENOMEM; | ||
1136 | goto err; | ||
1137 | } | ||
1138 | |||
1139 | chip->id = verify_addr(client); | ||
1140 | chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); | ||
1141 | if (IS_ERR(chip->regmap)) { | ||
1142 | ret = PTR_ERR(chip->regmap); | ||
1143 | dev_err(&client->dev, "Failed to allocate register map: %d\n", | ||
1144 | ret); | ||
1145 | kfree(chip); | ||
1146 | return ret; | ||
1147 | } | ||
1148 | chip->client = client; | ||
1149 | i2c_set_clientdata(client, chip); | ||
1150 | chip->dev = &client->dev; | ||
1151 | dev_set_drvdata(chip->dev, chip); | ||
1152 | |||
1153 | /* | ||
1154 | * Both client and companion client shares same platform driver. | ||
1155 | * Driver distinguishes them by pdata->companion_addr. | ||
1156 | * pdata->companion_addr is only assigned if companion chip exists. | ||
1157 | * At the same time, the companion_addr shouldn't equal to client | ||
1158 | * address. | ||
1159 | */ | ||
1160 | if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { | ||
1161 | chip->companion_addr = pdata->companion_addr; | ||
1162 | chip->companion = i2c_new_dummy(chip->client->adapter, | ||
1163 | chip->companion_addr); | ||
1164 | chip->regmap_companion = regmap_init_i2c(chip->companion, | ||
1165 | &pm860x_regmap_config); | ||
1166 | if (IS_ERR(chip->regmap_companion)) { | ||
1167 | ret = PTR_ERR(chip->regmap_companion); | ||
1168 | dev_err(&chip->companion->dev, | ||
1169 | "Failed to allocate register map: %d\n", ret); | ||
1170 | return ret; | ||
1171 | } | ||
1172 | i2c_set_clientdata(chip->companion, chip); | ||
1173 | } | ||
1174 | |||
1175 | pm860x_device_init(chip, pdata); | ||
1176 | return 0; | ||
1177 | err: | ||
1178 | if (node) | ||
1179 | devm_kfree(&client->dev, pdata); | ||
1180 | return ret; | ||
1181 | } | ||
1182 | |||
1183 | static int __devexit pm860x_remove(struct i2c_client *client) | ||
1184 | { | ||
1185 | struct pm860x_chip *chip = i2c_get_clientdata(client); | ||
1186 | |||
1187 | pm860x_device_exit(chip); | ||
1188 | if (chip->companion) { | ||
1189 | regmap_exit(chip->regmap_companion); | ||
1190 | i2c_unregister_device(chip->companion); | ||
1191 | } | ||
1192 | regmap_exit(chip->regmap); | ||
1193 | kfree(chip); | ||
1194 | return 0; | ||
1195 | } | ||
1196 | |||
1197 | #ifdef CONFIG_PM_SLEEP | ||
1198 | static int pm860x_suspend(struct device *dev) | ||
1199 | { | ||
1200 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1201 | struct pm860x_chip *chip = i2c_get_clientdata(client); | ||
1202 | |||
1203 | if (device_may_wakeup(dev) && chip->wakeup_flag) | ||
1204 | enable_irq_wake(chip->core_irq); | ||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | static int pm860x_resume(struct device *dev) | ||
1209 | { | ||
1210 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1211 | struct pm860x_chip *chip = i2c_get_clientdata(client); | ||
1212 | |||
1213 | if (device_may_wakeup(dev) && chip->wakeup_flag) | ||
1214 | disable_irq_wake(chip->core_irq); | ||
1215 | return 0; | ||
1216 | } | ||
1217 | #endif | ||
1218 | |||
1219 | static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); | ||
1220 | |||
1221 | static const struct i2c_device_id pm860x_id_table[] = { | ||
1222 | { "88PM860x", 0 }, | ||
1223 | {} | ||
1224 | }; | ||
1225 | MODULE_DEVICE_TABLE(i2c, pm860x_id_table); | ||
1226 | |||
1227 | static const struct of_device_id pm860x_dt_ids[] = { | ||
1228 | { .compatible = "marvell,88pm860x", }, | ||
1229 | {}, | ||
1230 | }; | ||
1231 | MODULE_DEVICE_TABLE(of, pm860x_dt_ids); | ||
1232 | |||
1233 | static struct i2c_driver pm860x_driver = { | ||
1234 | .driver = { | ||
1235 | .name = "88PM860x", | ||
1236 | .owner = THIS_MODULE, | ||
1237 | .pm = &pm860x_pm_ops, | ||
1238 | .of_match_table = of_match_ptr(pm860x_dt_ids), | ||
1239 | }, | ||
1240 | .probe = pm860x_probe, | ||
1241 | .remove = __devexit_p(pm860x_remove), | ||
1242 | .id_table = pm860x_id_table, | ||
1243 | }; | ||
1244 | |||
1245 | static int __init pm860x_i2c_init(void) | ||
1246 | { | ||
1247 | int ret; | ||
1248 | ret = i2c_add_driver(&pm860x_driver); | ||
1249 | if (ret != 0) | ||
1250 | pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); | ||
1251 | return ret; | ||
1252 | } | ||
1253 | subsys_initcall(pm860x_i2c_init); | ||
1254 | |||
1255 | static void __exit pm860x_i2c_exit(void) | ||
1256 | { | ||
1257 | i2c_del_driver(&pm860x_driver); | ||
1258 | } | ||
1259 | module_exit(pm860x_i2c_exit); | ||
1260 | |||
932 | MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); | 1261 | MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); |
933 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | 1262 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); |
934 | MODULE_LICENSE("GPL"); | 1263 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index b2cfdc458561..ff8f803ce833 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c | |||
@@ -10,12 +10,9 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
15 | #include <linux/err.h> | ||
16 | #include <linux/regmap.h> | 14 | #include <linux/regmap.h> |
17 | #include <linux/mfd/88pm860x.h> | 15 | #include <linux/mfd/88pm860x.h> |
18 | #include <linux/slab.h> | ||
19 | 16 | ||
20 | int pm860x_reg_read(struct i2c_client *i2c, int reg) | 17 | int pm860x_reg_read(struct i2c_client *i2c, int reg) |
21 | { | 18 | { |
@@ -91,8 +88,18 @@ static int read_device(struct i2c_client *i2c, int reg, | |||
91 | unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; | 88 | unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; |
92 | unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; | 89 | unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; |
93 | struct i2c_adapter *adap = i2c->adapter; | 90 | struct i2c_adapter *adap = i2c->adapter; |
94 | struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0}, | 91 | struct i2c_msg msg[2] = { |
95 | {i2c->addr, I2C_M_RD, 0, msgbuf1}, | 92 | { |
93 | .addr = i2c->addr, | ||
94 | .flags = 0, | ||
95 | .len = 1, | ||
96 | .buf = msgbuf0 | ||
97 | }, | ||
98 | { .addr = i2c->addr, | ||
99 | .flags = I2C_M_RD, | ||
100 | .len = 0, | ||
101 | .buf = msgbuf1 | ||
102 | }, | ||
96 | }; | 103 | }; |
97 | int num = 1, ret = 0; | 104 | int num = 1, ret = 0; |
98 | 105 | ||
@@ -231,160 +238,3 @@ out: | |||
231 | return ret; | 238 | return ret; |
232 | } | 239 | } |
233 | EXPORT_SYMBOL(pm860x_page_set_bits); | 240 | EXPORT_SYMBOL(pm860x_page_set_bits); |
234 | |||
235 | static const struct i2c_device_id pm860x_id_table[] = { | ||
236 | { "88PM860x", 0 }, | ||
237 | {} | ||
238 | }; | ||
239 | MODULE_DEVICE_TABLE(i2c, pm860x_id_table); | ||
240 | |||
241 | static int verify_addr(struct i2c_client *i2c) | ||
242 | { | ||
243 | unsigned short addr_8607[] = {0x30, 0x34}; | ||
244 | unsigned short addr_8606[] = {0x10, 0x11}; | ||
245 | int size, i; | ||
246 | |||
247 | if (i2c == NULL) | ||
248 | return 0; | ||
249 | size = ARRAY_SIZE(addr_8606); | ||
250 | for (i = 0; i < size; i++) { | ||
251 | if (i2c->addr == *(addr_8606 + i)) | ||
252 | return CHIP_PM8606; | ||
253 | } | ||
254 | size = ARRAY_SIZE(addr_8607); | ||
255 | for (i = 0; i < size; i++) { | ||
256 | if (i2c->addr == *(addr_8607 + i)) | ||
257 | return CHIP_PM8607; | ||
258 | } | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static struct regmap_config pm860x_regmap_config = { | ||
263 | .reg_bits = 8, | ||
264 | .val_bits = 8, | ||
265 | }; | ||
266 | |||
267 | static int __devinit pm860x_probe(struct i2c_client *client, | ||
268 | const struct i2c_device_id *id) | ||
269 | { | ||
270 | struct pm860x_platform_data *pdata = client->dev.platform_data; | ||
271 | struct pm860x_chip *chip; | ||
272 | int ret; | ||
273 | |||
274 | if (!pdata) { | ||
275 | pr_info("No platform data in %s!\n", __func__); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); | ||
280 | if (chip == NULL) | ||
281 | return -ENOMEM; | ||
282 | |||
283 | chip->id = verify_addr(client); | ||
284 | chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); | ||
285 | if (IS_ERR(chip->regmap)) { | ||
286 | ret = PTR_ERR(chip->regmap); | ||
287 | dev_err(&client->dev, "Failed to allocate register map: %d\n", | ||
288 | ret); | ||
289 | kfree(chip); | ||
290 | return ret; | ||
291 | } | ||
292 | chip->client = client; | ||
293 | i2c_set_clientdata(client, chip); | ||
294 | chip->dev = &client->dev; | ||
295 | dev_set_drvdata(chip->dev, chip); | ||
296 | |||
297 | /* | ||
298 | * Both client and companion client shares same platform driver. | ||
299 | * Driver distinguishes them by pdata->companion_addr. | ||
300 | * pdata->companion_addr is only assigned if companion chip exists. | ||
301 | * At the same time, the companion_addr shouldn't equal to client | ||
302 | * address. | ||
303 | */ | ||
304 | if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { | ||
305 | chip->companion_addr = pdata->companion_addr; | ||
306 | chip->companion = i2c_new_dummy(chip->client->adapter, | ||
307 | chip->companion_addr); | ||
308 | chip->regmap_companion = regmap_init_i2c(chip->companion, | ||
309 | &pm860x_regmap_config); | ||
310 | if (IS_ERR(chip->regmap_companion)) { | ||
311 | ret = PTR_ERR(chip->regmap_companion); | ||
312 | dev_err(&chip->companion->dev, | ||
313 | "Failed to allocate register map: %d\n", ret); | ||
314 | return ret; | ||
315 | } | ||
316 | i2c_set_clientdata(chip->companion, chip); | ||
317 | } | ||
318 | |||
319 | pm860x_device_init(chip, pdata); | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int __devexit pm860x_remove(struct i2c_client *client) | ||
324 | { | ||
325 | struct pm860x_chip *chip = i2c_get_clientdata(client); | ||
326 | |||
327 | pm860x_device_exit(chip); | ||
328 | if (chip->companion) { | ||
329 | regmap_exit(chip->regmap_companion); | ||
330 | i2c_unregister_device(chip->companion); | ||
331 | } | ||
332 | regmap_exit(chip->regmap); | ||
333 | kfree(chip); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | #ifdef CONFIG_PM_SLEEP | ||
338 | static int pm860x_suspend(struct device *dev) | ||
339 | { | ||
340 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
341 | struct pm860x_chip *chip = i2c_get_clientdata(client); | ||
342 | |||
343 | if (device_may_wakeup(dev) && chip->wakeup_flag) | ||
344 | enable_irq_wake(chip->core_irq); | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int pm860x_resume(struct device *dev) | ||
349 | { | ||
350 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
351 | struct pm860x_chip *chip = i2c_get_clientdata(client); | ||
352 | |||
353 | if (device_may_wakeup(dev) && chip->wakeup_flag) | ||
354 | disable_irq_wake(chip->core_irq); | ||
355 | return 0; | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); | ||
360 | |||
361 | static struct i2c_driver pm860x_driver = { | ||
362 | .driver = { | ||
363 | .name = "88PM860x", | ||
364 | .owner = THIS_MODULE, | ||
365 | .pm = &pm860x_pm_ops, | ||
366 | }, | ||
367 | .probe = pm860x_probe, | ||
368 | .remove = __devexit_p(pm860x_remove), | ||
369 | .id_table = pm860x_id_table, | ||
370 | }; | ||
371 | |||
372 | static int __init pm860x_i2c_init(void) | ||
373 | { | ||
374 | int ret; | ||
375 | ret = i2c_add_driver(&pm860x_driver); | ||
376 | if (ret != 0) | ||
377 | pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); | ||
378 | return ret; | ||
379 | } | ||
380 | subsys_initcall(pm860x_i2c_init); | ||
381 | |||
382 | static void __exit pm860x_i2c_exit(void) | ||
383 | { | ||
384 | i2c_del_driver(&pm860x_driver); | ||
385 | } | ||
386 | module_exit(pm860x_i2c_exit); | ||
387 | |||
388 | MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x"); | ||
389 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | ||
390 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b1a146205c08..acab3ef8a310 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -298,16 +298,6 @@ config MFD_TWL4030_AUDIO | |||
298 | select MFD_CORE | 298 | select MFD_CORE |
299 | default n | 299 | default n |
300 | 300 | ||
301 | config TWL6030_PWM | ||
302 | tristate "TWL6030 PWM (Pulse Width Modulator) Support" | ||
303 | depends on TWL4030_CORE | ||
304 | select HAVE_PWM | ||
305 | depends on !PWM | ||
306 | default n | ||
307 | help | ||
308 | Say yes here if you want support for TWL6030 PWM. | ||
309 | This is used to control charging LED brightness. | ||
310 | |||
311 | config TWL6040_CORE | 301 | config TWL6040_CORE |
312 | bool "Support for TWL6040 audio codec" | 302 | bool "Support for TWL6040 audio codec" |
313 | depends on I2C=y && GENERIC_HARDIRQS | 303 | depends on I2C=y && GENERIC_HARDIRQS |
@@ -385,6 +375,18 @@ config MFD_T7L66XB | |||
385 | help | 375 | help |
386 | Support for Toshiba Mobile IO Controller T7L66XB | 376 | Support for Toshiba Mobile IO Controller T7L66XB |
387 | 377 | ||
378 | config MFD_SMSC | ||
379 | bool "Support for the SMSC ECE1099 series chips" | ||
380 | depends on I2C=y | ||
381 | select MFD_CORE | ||
382 | select REGMAP_I2C | ||
383 | help | ||
384 | If you say yes here you get support for the | ||
385 | ece1099 chips from SMSC. | ||
386 | |||
387 | To compile this driver as a module, choose M here: the | ||
388 | module will be called smsc. | ||
389 | |||
388 | config MFD_TC6387XB | 390 | config MFD_TC6387XB |
389 | bool "Support Toshiba TC6387XB" | 391 | bool "Support Toshiba TC6387XB" |
390 | depends on ARM && HAVE_CLK | 392 | depends on ARM && HAVE_CLK |
@@ -441,6 +443,23 @@ config MFD_DA9052_I2C | |||
441 | for accessing the device, additional drivers must be enabled in | 443 | for accessing the device, additional drivers must be enabled in |
442 | order to use the functionality of the device. | 444 | order to use the functionality of the device. |
443 | 445 | ||
446 | config MFD_DA9055 | ||
447 | bool "Dialog Semiconductor DA9055 PMIC Support" | ||
448 | select REGMAP_I2C | ||
449 | select REGMAP_IRQ | ||
450 | select PMIC_DA9055 | ||
451 | select MFD_CORE | ||
452 | depends on I2C=y | ||
453 | help | ||
454 | Say yes here for support of Dialog Semiconductor DA9055. This is | ||
455 | a Power Management IC. This driver provides common support for | ||
456 | accessing the device as well as the I2C interface to the chip itself. | ||
457 | Additional drivers must be enabled in order to use the functionality | ||
458 | of the device. | ||
459 | |||
460 | This driver can be built as a module. If built as a module it will be | ||
461 | called "da9055" | ||
462 | |||
444 | config PMIC_ADP5520 | 463 | config PMIC_ADP5520 |
445 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | 464 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" |
446 | depends on I2C=y | 465 | depends on I2C=y |
@@ -451,6 +470,16 @@ config PMIC_ADP5520 | |||
451 | individual components like LCD backlight, LEDs, GPIOs and Kepad | 470 | individual components like LCD backlight, LEDs, GPIOs and Kepad |
452 | under the corresponding menus. | 471 | under the corresponding menus. |
453 | 472 | ||
473 | config MFD_LP8788 | ||
474 | bool "Texas Instruments LP8788 Power Management Unit Driver" | ||
475 | depends on I2C=y | ||
476 | select MFD_CORE | ||
477 | select REGMAP_I2C | ||
478 | select IRQ_DOMAIN | ||
479 | help | ||
480 | TI LP8788 PMU supports regulators, battery charger, RTC, | ||
481 | ADC, backlight driver and current sinks. | ||
482 | |||
454 | config MFD_MAX77686 | 483 | config MFD_MAX77686 |
455 | bool "Maxim Semiconductor MAX77686 PMIC Support" | 484 | bool "Maxim Semiconductor MAX77686 PMIC Support" |
456 | depends on I2C=y && GENERIC_HARDIRQS | 485 | depends on I2C=y && GENERIC_HARDIRQS |
@@ -477,6 +506,18 @@ config MFD_MAX77693 | |||
477 | additional drivers must be enabled in order to use the functionality | 506 | additional drivers must be enabled in order to use the functionality |
478 | of the device. | 507 | of the device. |
479 | 508 | ||
509 | config MFD_MAX8907 | ||
510 | tristate "Maxim Semiconductor MAX8907 PMIC Support" | ||
511 | select MFD_CORE | ||
512 | depends on I2C=y && GENERIC_HARDIRQS | ||
513 | select REGMAP_I2C | ||
514 | select REGMAP_IRQ | ||
515 | help | ||
516 | Say yes here to support for Maxim Semiconductor MAX8907. This is | ||
517 | a Power Management IC. This driver provides common support for | ||
518 | accessing the device; additional drivers must be enabled in order | ||
519 | to use the functionality of the device. | ||
520 | |||
480 | config MFD_MAX8925 | 521 | config MFD_MAX8925 |
481 | bool "Maxim Semiconductor MAX8925 PMIC Support" | 522 | bool "Maxim Semiconductor MAX8925 PMIC Support" |
482 | depends on I2C=y && GENERIC_HARDIRQS | 523 | depends on I2C=y && GENERIC_HARDIRQS |
@@ -896,7 +937,7 @@ config MFD_WL1273_CORE | |||
896 | audio codec. | 937 | audio codec. |
897 | 938 | ||
898 | config MFD_OMAP_USB_HOST | 939 | config MFD_OMAP_USB_HOST |
899 | bool "Support OMAP USBHS core driver" | 940 | bool "Support OMAP USBHS core and TLL driver" |
900 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 | 941 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 |
901 | default y | 942 | default y |
902 | help | 943 | help |
@@ -985,13 +1026,13 @@ config MFD_STA2X11 | |||
985 | depends on STA2X11 | 1026 | depends on STA2X11 |
986 | select MFD_CORE | 1027 | select MFD_CORE |
987 | 1028 | ||
988 | config MFD_ANATOP | 1029 | config MFD_SYSCON |
989 | bool "Support for Freescale i.MX on-chip ANATOP controller" | 1030 | bool "System Controller Register R/W Based on Regmap" |
990 | depends on SOC_IMX6Q | 1031 | depends on OF |
1032 | select REGMAP_MMIO | ||
991 | help | 1033 | help |
992 | Select this option to enable Freescale i.MX on-chip ANATOP | 1034 | Select this option to enable accessing system control registers |
993 | MFD controller. This controller embeds regulator and | 1035 | via regmap. |
994 | thermal devices for Freescale i.MX platforms. | ||
995 | 1036 | ||
996 | config MFD_PALMAS | 1037 | config MFD_PALMAS |
997 | bool "Support for the TI Palmas series chips" | 1038 | bool "Support for the TI Palmas series chips" |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 79dd22d1dc3d..d8ccb630ddb0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -63,7 +63,6 @@ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o | |||
63 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o | 63 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o |
64 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | 64 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o |
65 | obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o | 65 | obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o |
66 | obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o | ||
67 | obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o | 66 | obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o |
68 | 67 | ||
69 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o | 68 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o |
@@ -77,6 +76,7 @@ obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o | |||
77 | obj-$(CONFIG_MCP) += mcp-core.o | 76 | obj-$(CONFIG_MCP) += mcp-core.o |
78 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o | 77 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o |
79 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o | 78 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o |
79 | obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o | ||
80 | obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o | 80 | obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o |
81 | 81 | ||
82 | ifeq ($(CONFIG_SA1100_ASSABET),y) | 82 | ifeq ($(CONFIG_SA1100_ASSABET),y) |
@@ -90,8 +90,14 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-core.o | |||
90 | obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o | 90 | obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o |
91 | obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o | 91 | obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o |
92 | 92 | ||
93 | obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o | ||
94 | |||
95 | da9055-objs := da9055-core.o da9055-i2c.o | ||
96 | obj-$(CONFIG_MFD_DA9055) += da9055.o | ||
97 | |||
93 | obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o | 98 | obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o |
94 | obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o | 99 | obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o |
100 | obj-$(CONFIG_MFD_MAX8907) += max8907.o | ||
95 | max8925-objs := max8925-core.o max8925-i2c.o | 101 | max8925-objs := max8925-core.o max8925-i2c.o |
96 | obj-$(CONFIG_MFD_MAX8925) += max8925.o | 102 | obj-$(CONFIG_MFD_MAX8925) += max8925.o |
97 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o | 103 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o |
@@ -120,7 +126,7 @@ obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o | |||
120 | obj-$(CONFIG_MFD_VX855) += vx855.o | 126 | obj-$(CONFIG_MFD_VX855) += vx855.o |
121 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o | 127 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o |
122 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o | 128 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o |
123 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o | 129 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o |
124 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o | 130 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o |
125 | obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o | 131 | obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o |
126 | obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o | 132 | obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o |
@@ -130,5 +136,5 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o | |||
130 | obj-$(CONFIG_MFD_PALMAS) += palmas.o | 136 | obj-$(CONFIG_MFD_PALMAS) += palmas.o |
131 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o | 137 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o |
132 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o | 138 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o |
133 | obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o | 139 | obj-$(CONFIG_MFD_SYSCON) += syscon.o |
134 | obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o | 140 | obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o |
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 01781ae5d0d7..2b3dde571a50 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | #include <linux/uaccess.h> | 22 | #include <linux/uaccess.h> |
23 | #include <linux/mfd/core.h> | 23 | #include <linux/mfd/core.h> |
24 | #include <linux/mfd/ab3100.h> | ||
24 | #include <linux/mfd/abx500.h> | 25 | #include <linux/mfd/abx500.h> |
25 | 26 | ||
26 | /* These are the only registers inside AB3100 used in this main file */ | 27 | /* These are the only registers inside AB3100 used in this main file */ |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 47adf800024e..1667c77b5cde 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -472,6 +472,22 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) | |||
472 | return IRQ_HANDLED; | 472 | return IRQ_HANDLED; |
473 | } | 473 | } |
474 | 474 | ||
475 | /** | ||
476 | * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ | ||
477 | * | ||
478 | * @ab8500: ab8500_irq controller to operate on. | ||
479 | * @irq: index of the interrupt requested in the chip IRQs | ||
480 | * | ||
481 | * Useful for drivers to request their own IRQs. | ||
482 | */ | ||
483 | static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) | ||
484 | { | ||
485 | if (!ab8500) | ||
486 | return -EINVAL; | ||
487 | |||
488 | return irq_create_mapping(ab8500->domain, irq); | ||
489 | } | ||
490 | |||
475 | static irqreturn_t ab8500_irq(int irq, void *dev) | 491 | static irqreturn_t ab8500_irq(int irq, void *dev) |
476 | { | 492 | { |
477 | struct ab8500 *ab8500 = dev; | 493 | struct ab8500 *ab8500 = dev; |
@@ -501,8 +517,9 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
501 | do { | 517 | do { |
502 | int bit = __ffs(value); | 518 | int bit = __ffs(value); |
503 | int line = i * 8 + bit; | 519 | int line = i * 8 + bit; |
520 | int virq = ab8500_irq_get_virq(ab8500, line); | ||
504 | 521 | ||
505 | handle_nested_irq(ab8500->irq_base + line); | 522 | handle_nested_irq(virq); |
506 | value &= ~(1 << bit); | 523 | value &= ~(1 << bit); |
507 | 524 | ||
508 | } while (value); | 525 | } while (value); |
@@ -511,23 +528,6 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
511 | return IRQ_HANDLED; | 528 | return IRQ_HANDLED; |
512 | } | 529 | } |
513 | 530 | ||
514 | /** | ||
515 | * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ | ||
516 | * | ||
517 | * @ab8500: ab8500_irq controller to operate on. | ||
518 | * @irq: index of the interrupt requested in the chip IRQs | ||
519 | * | ||
520 | * Useful for drivers to request their own IRQs. | ||
521 | */ | ||
522 | int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) | ||
523 | { | ||
524 | if (!ab8500) | ||
525 | return -EINVAL; | ||
526 | |||
527 | return irq_create_mapping(ab8500->domain, irq); | ||
528 | } | ||
529 | EXPORT_SYMBOL_GPL(ab8500_irq_get_virq); | ||
530 | |||
531 | static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, | 531 | static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, |
532 | irq_hw_number_t hwirq) | 532 | irq_hw_number_t hwirq) |
533 | { | 533 | { |
@@ -1076,6 +1076,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = { | |||
1076 | }, | 1076 | }, |
1077 | { | 1077 | { |
1078 | .name = "ab8500-codec", | 1078 | .name = "ab8500-codec", |
1079 | .of_compatible = "stericsson,ab8500-codec", | ||
1079 | }, | 1080 | }, |
1080 | }; | 1081 | }; |
1081 | 1082 | ||
diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c deleted file mode 100644 index 5576e07576de..000000000000 --- a/drivers/mfd/anatop-mfd.c +++ /dev/null | |||
@@ -1,124 +0,0 @@ | |||
1 | /* | ||
2 | * Anatop MFD driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org> | ||
5 | * Copyright (C) 2012 Linaro | ||
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 along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License as published by | ||
22 | * the Free Software Foundation; either version 2 of the License, or | ||
23 | * (at your option) any later version. | ||
24 | * | ||
25 | * This program is distributed in the hope that it will be useful, | ||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | * GNU General Public License for more details. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License along | ||
31 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
32 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/io.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/platform_device.h> | ||
39 | #include <linux/of.h> | ||
40 | #include <linux/of_platform.h> | ||
41 | #include <linux/of_address.h> | ||
42 | #include <linux/mfd/anatop.h> | ||
43 | |||
44 | u32 anatop_read_reg(struct anatop *adata, u32 addr) | ||
45 | { | ||
46 | return readl(adata->ioreg + addr); | ||
47 | } | ||
48 | EXPORT_SYMBOL_GPL(anatop_read_reg); | ||
49 | |||
50 | void anatop_write_reg(struct anatop *adata, u32 addr, u32 data, u32 mask) | ||
51 | { | ||
52 | u32 val; | ||
53 | |||
54 | data &= mask; | ||
55 | |||
56 | spin_lock(&adata->reglock); | ||
57 | val = readl(adata->ioreg + addr); | ||
58 | val &= ~mask; | ||
59 | val |= data; | ||
60 | writel(val, adata->ioreg + addr); | ||
61 | spin_unlock(&adata->reglock); | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(anatop_write_reg); | ||
64 | |||
65 | static const struct of_device_id of_anatop_match[] = { | ||
66 | { .compatible = "fsl,imx6q-anatop", }, | ||
67 | { }, | ||
68 | }; | ||
69 | |||
70 | static int __devinit of_anatop_probe(struct platform_device *pdev) | ||
71 | { | ||
72 | struct device *dev = &pdev->dev; | ||
73 | struct device_node *np = dev->of_node; | ||
74 | void *ioreg; | ||
75 | struct anatop *drvdata; | ||
76 | |||
77 | ioreg = of_iomap(np, 0); | ||
78 | if (!ioreg) | ||
79 | return -EADDRNOTAVAIL; | ||
80 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | ||
81 | if (!drvdata) | ||
82 | return -ENOMEM; | ||
83 | drvdata->ioreg = ioreg; | ||
84 | spin_lock_init(&drvdata->reglock); | ||
85 | platform_set_drvdata(pdev, drvdata); | ||
86 | of_platform_populate(np, NULL, NULL, dev); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int __devexit of_anatop_remove(struct platform_device *pdev) | ||
92 | { | ||
93 | struct anatop *drvdata; | ||
94 | drvdata = platform_get_drvdata(pdev); | ||
95 | iounmap(drvdata->ioreg); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static struct platform_driver anatop_of_driver = { | ||
101 | .driver = { | ||
102 | .name = "anatop-mfd", | ||
103 | .owner = THIS_MODULE, | ||
104 | .of_match_table = of_anatop_match, | ||
105 | }, | ||
106 | .probe = of_anatop_probe, | ||
107 | .remove = of_anatop_remove, | ||
108 | }; | ||
109 | |||
110 | static int __init anatop_init(void) | ||
111 | { | ||
112 | return platform_driver_register(&anatop_of_driver); | ||
113 | } | ||
114 | postcore_initcall(anatop_init); | ||
115 | |||
116 | static void __exit anatop_exit(void) | ||
117 | { | ||
118 | platform_driver_unregister(&anatop_of_driver); | ||
119 | } | ||
120 | module_exit(anatop_exit); | ||
121 | |||
122 | MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); | ||
123 | MODULE_DESCRIPTION("ANATOP MFD driver"); | ||
124 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 98ac345f468e..ef0f2d001df2 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c | |||
@@ -94,7 +94,8 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data) | |||
94 | static irqreturn_t arizona_irq_thread(int irq, void *data) | 94 | static irqreturn_t arizona_irq_thread(int irq, void *data) |
95 | { | 95 | { |
96 | struct arizona *arizona = data; | 96 | struct arizona *arizona = data; |
97 | int i, ret; | 97 | unsigned int val; |
98 | int ret; | ||
98 | 99 | ||
99 | ret = pm_runtime_get_sync(arizona->dev); | 100 | ret = pm_runtime_get_sync(arizona->dev); |
100 | if (ret < 0) { | 101 | if (ret < 0) { |
@@ -102,9 +103,20 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) | |||
102 | return IRQ_NONE; | 103 | return IRQ_NONE; |
103 | } | 104 | } |
104 | 105 | ||
105 | /* Check both domains */ | 106 | /* Always handle the AoD domain */ |
106 | for (i = 0; i < 2; i++) | 107 | handle_nested_irq(irq_find_mapping(arizona->virq, 0)); |
107 | handle_nested_irq(irq_find_mapping(arizona->virq, i)); | 108 | |
109 | /* | ||
110 | * Check if one of the main interrupts is asserted and only | ||
111 | * check that domain if it is. | ||
112 | */ | ||
113 | ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val); | ||
114 | if (ret == 0 && val & ARIZONA_IRQ1_STS) { | ||
115 | handle_nested_irq(irq_find_mapping(arizona->virq, 1)); | ||
116 | } else if (ret != 0) { | ||
117 | dev_err(arizona->dev, "Failed to read main IRQ status: %d\n", | ||
118 | ret); | ||
119 | } | ||
108 | 120 | ||
109 | pm_runtime_mark_last_busy(arizona->dev); | 121 | pm_runtime_mark_last_busy(arizona->dev); |
110 | pm_runtime_put_autosuspend(arizona->dev); | 122 | pm_runtime_put_autosuspend(arizona->dev); |
@@ -156,18 +168,36 @@ int arizona_irq_init(struct arizona *arizona) | |||
156 | int flags = IRQF_ONESHOT; | 168 | int flags = IRQF_ONESHOT; |
157 | int ret, i; | 169 | int ret, i; |
158 | const struct regmap_irq_chip *aod, *irq; | 170 | const struct regmap_irq_chip *aod, *irq; |
171 | bool ctrlif_error = true; | ||
159 | 172 | ||
160 | switch (arizona->type) { | 173 | switch (arizona->type) { |
161 | #ifdef CONFIG_MFD_WM5102 | 174 | #ifdef CONFIG_MFD_WM5102 |
162 | case WM5102: | 175 | case WM5102: |
163 | aod = &wm5102_aod; | 176 | aod = &wm5102_aod; |
164 | irq = &wm5102_irq; | 177 | irq = &wm5102_irq; |
178 | |||
179 | switch (arizona->rev) { | ||
180 | case 0: | ||
181 | ctrlif_error = false; | ||
182 | break; | ||
183 | default: | ||
184 | break; | ||
185 | } | ||
165 | break; | 186 | break; |
166 | #endif | 187 | #endif |
167 | #ifdef CONFIG_MFD_WM5110 | 188 | #ifdef CONFIG_MFD_WM5110 |
168 | case WM5110: | 189 | case WM5110: |
169 | aod = &wm5110_aod; | 190 | aod = &wm5110_aod; |
170 | irq = &wm5110_irq; | 191 | irq = &wm5110_irq; |
192 | |||
193 | switch (arizona->rev) { | ||
194 | case 0: | ||
195 | case 1: | ||
196 | ctrlif_error = false; | ||
197 | break; | ||
198 | default: | ||
199 | break; | ||
200 | } | ||
171 | break; | 201 | break; |
172 | #endif | 202 | #endif |
173 | default: | 203 | default: |
@@ -226,13 +256,17 @@ int arizona_irq_init(struct arizona *arizona) | |||
226 | } | 256 | } |
227 | 257 | ||
228 | /* Handle control interface errors in the core */ | 258 | /* Handle control interface errors in the core */ |
229 | i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR); | 259 | if (ctrlif_error) { |
230 | ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, IRQF_ONESHOT, | 260 | i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR); |
231 | "Control interface error", arizona); | 261 | ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, |
232 | if (ret != 0) { | 262 | IRQF_ONESHOT, |
233 | dev_err(arizona->dev, "Failed to request boot done %d: %d\n", | 263 | "Control interface error", arizona); |
234 | arizona->irq, ret); | 264 | if (ret != 0) { |
235 | goto err_ctrlif; | 265 | dev_err(arizona->dev, |
266 | "Failed to request CTRLIF_ERR %d: %d\n", | ||
267 | arizona->irq, ret); | ||
268 | goto err_ctrlif; | ||
269 | } | ||
236 | } | 270 | } |
237 | 271 | ||
238 | ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, | 272 | ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, |
diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c new file mode 100644 index 000000000000..ff6c77f392bd --- /dev/null +++ b/drivers/mfd/da9055-core.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
2 | * Device access for Dialog DA9055 PMICs. | ||
3 | * | ||
4 | * Copyright(c) 2012 Dialog Semiconductor Ltd. | ||
5 | * | ||
6 | * Author: David Dajun Chen <dchen@diasemi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/input.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/mutex.h> | ||
19 | |||
20 | #include <linux/mfd/core.h> | ||
21 | #include <linux/mfd/da9055/core.h> | ||
22 | #include <linux/mfd/da9055/pdata.h> | ||
23 | #include <linux/mfd/da9055/reg.h> | ||
24 | |||
25 | #define DA9055_IRQ_NONKEY_MASK 0x01 | ||
26 | #define DA9055_IRQ_ALM_MASK 0x02 | ||
27 | #define DA9055_IRQ_TICK_MASK 0x04 | ||
28 | #define DA9055_IRQ_ADC_MASK 0x08 | ||
29 | #define DA9055_IRQ_BUCK_ILIM_MASK 0x08 | ||
30 | |||
31 | static bool da9055_register_readable(struct device *dev, unsigned int reg) | ||
32 | { | ||
33 | switch (reg) { | ||
34 | case DA9055_REG_STATUS_A: | ||
35 | case DA9055_REG_STATUS_B: | ||
36 | case DA9055_REG_EVENT_A: | ||
37 | case DA9055_REG_EVENT_B: | ||
38 | case DA9055_REG_EVENT_C: | ||
39 | case DA9055_REG_IRQ_MASK_A: | ||
40 | case DA9055_REG_IRQ_MASK_B: | ||
41 | case DA9055_REG_IRQ_MASK_C: | ||
42 | |||
43 | case DA9055_REG_CONTROL_A: | ||
44 | case DA9055_REG_CONTROL_B: | ||
45 | case DA9055_REG_CONTROL_C: | ||
46 | case DA9055_REG_CONTROL_D: | ||
47 | case DA9055_REG_CONTROL_E: | ||
48 | |||
49 | case DA9055_REG_ADC_MAN: | ||
50 | case DA9055_REG_ADC_CONT: | ||
51 | case DA9055_REG_VSYS_MON: | ||
52 | case DA9055_REG_ADC_RES_L: | ||
53 | case DA9055_REG_ADC_RES_H: | ||
54 | case DA9055_REG_VSYS_RES: | ||
55 | case DA9055_REG_ADCIN1_RES: | ||
56 | case DA9055_REG_ADCIN2_RES: | ||
57 | case DA9055_REG_ADCIN3_RES: | ||
58 | |||
59 | case DA9055_REG_COUNT_S: | ||
60 | case DA9055_REG_COUNT_MI: | ||
61 | case DA9055_REG_COUNT_H: | ||
62 | case DA9055_REG_COUNT_D: | ||
63 | case DA9055_REG_COUNT_MO: | ||
64 | case DA9055_REG_COUNT_Y: | ||
65 | case DA9055_REG_ALARM_H: | ||
66 | case DA9055_REG_ALARM_D: | ||
67 | case DA9055_REG_ALARM_MI: | ||
68 | case DA9055_REG_ALARM_MO: | ||
69 | case DA9055_REG_ALARM_Y: | ||
70 | |||
71 | case DA9055_REG_GPIO0_1: | ||
72 | case DA9055_REG_GPIO2: | ||
73 | case DA9055_REG_GPIO_MODE0_2: | ||
74 | |||
75 | case DA9055_REG_BCORE_CONT: | ||
76 | case DA9055_REG_BMEM_CONT: | ||
77 | case DA9055_REG_LDO1_CONT: | ||
78 | case DA9055_REG_LDO2_CONT: | ||
79 | case DA9055_REG_LDO3_CONT: | ||
80 | case DA9055_REG_LDO4_CONT: | ||
81 | case DA9055_REG_LDO5_CONT: | ||
82 | case DA9055_REG_LDO6_CONT: | ||
83 | case DA9055_REG_BUCK_LIM: | ||
84 | case DA9055_REG_BCORE_MODE: | ||
85 | case DA9055_REG_VBCORE_A: | ||
86 | case DA9055_REG_VBMEM_A: | ||
87 | case DA9055_REG_VLDO1_A: | ||
88 | case DA9055_REG_VLDO2_A: | ||
89 | case DA9055_REG_VLDO3_A: | ||
90 | case DA9055_REG_VLDO4_A: | ||
91 | case DA9055_REG_VLDO5_A: | ||
92 | case DA9055_REG_VLDO6_A: | ||
93 | case DA9055_REG_VBCORE_B: | ||
94 | case DA9055_REG_VBMEM_B: | ||
95 | case DA9055_REG_VLDO1_B: | ||
96 | case DA9055_REG_VLDO2_B: | ||
97 | case DA9055_REG_VLDO3_B: | ||
98 | case DA9055_REG_VLDO4_B: | ||
99 | case DA9055_REG_VLDO5_B: | ||
100 | case DA9055_REG_VLDO6_B: | ||
101 | return true; | ||
102 | default: | ||
103 | return false; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | static bool da9055_register_writeable(struct device *dev, unsigned int reg) | ||
108 | { | ||
109 | switch (reg) { | ||
110 | case DA9055_REG_STATUS_A: | ||
111 | case DA9055_REG_STATUS_B: | ||
112 | case DA9055_REG_EVENT_A: | ||
113 | case DA9055_REG_EVENT_B: | ||
114 | case DA9055_REG_EVENT_C: | ||
115 | case DA9055_REG_IRQ_MASK_A: | ||
116 | case DA9055_REG_IRQ_MASK_B: | ||
117 | case DA9055_REG_IRQ_MASK_C: | ||
118 | |||
119 | case DA9055_REG_CONTROL_A: | ||
120 | case DA9055_REG_CONTROL_B: | ||
121 | case DA9055_REG_CONTROL_C: | ||
122 | case DA9055_REG_CONTROL_D: | ||
123 | case DA9055_REG_CONTROL_E: | ||
124 | |||
125 | case DA9055_REG_ADC_MAN: | ||
126 | case DA9055_REG_ADC_CONT: | ||
127 | case DA9055_REG_VSYS_MON: | ||
128 | case DA9055_REG_ADC_RES_L: | ||
129 | case DA9055_REG_ADC_RES_H: | ||
130 | case DA9055_REG_VSYS_RES: | ||
131 | case DA9055_REG_ADCIN1_RES: | ||
132 | case DA9055_REG_ADCIN2_RES: | ||
133 | case DA9055_REG_ADCIN3_RES: | ||
134 | |||
135 | case DA9055_REG_COUNT_S: | ||
136 | case DA9055_REG_COUNT_MI: | ||
137 | case DA9055_REG_COUNT_H: | ||
138 | case DA9055_REG_COUNT_D: | ||
139 | case DA9055_REG_COUNT_MO: | ||
140 | case DA9055_REG_COUNT_Y: | ||
141 | case DA9055_REG_ALARM_H: | ||
142 | case DA9055_REG_ALARM_D: | ||
143 | case DA9055_REG_ALARM_MI: | ||
144 | case DA9055_REG_ALARM_MO: | ||
145 | case DA9055_REG_ALARM_Y: | ||
146 | |||
147 | case DA9055_REG_GPIO0_1: | ||
148 | case DA9055_REG_GPIO2: | ||
149 | case DA9055_REG_GPIO_MODE0_2: | ||
150 | |||
151 | case DA9055_REG_BCORE_CONT: | ||
152 | case DA9055_REG_BMEM_CONT: | ||
153 | case DA9055_REG_LDO1_CONT: | ||
154 | case DA9055_REG_LDO2_CONT: | ||
155 | case DA9055_REG_LDO3_CONT: | ||
156 | case DA9055_REG_LDO4_CONT: | ||
157 | case DA9055_REG_LDO5_CONT: | ||
158 | case DA9055_REG_LDO6_CONT: | ||
159 | case DA9055_REG_BUCK_LIM: | ||
160 | case DA9055_REG_BCORE_MODE: | ||
161 | case DA9055_REG_VBCORE_A: | ||
162 | case DA9055_REG_VBMEM_A: | ||
163 | case DA9055_REG_VLDO1_A: | ||
164 | case DA9055_REG_VLDO2_A: | ||
165 | case DA9055_REG_VLDO3_A: | ||
166 | case DA9055_REG_VLDO4_A: | ||
167 | case DA9055_REG_VLDO5_A: | ||
168 | case DA9055_REG_VLDO6_A: | ||
169 | case DA9055_REG_VBCORE_B: | ||
170 | case DA9055_REG_VBMEM_B: | ||
171 | case DA9055_REG_VLDO1_B: | ||
172 | case DA9055_REG_VLDO2_B: | ||
173 | case DA9055_REG_VLDO3_B: | ||
174 | case DA9055_REG_VLDO4_B: | ||
175 | case DA9055_REG_VLDO5_B: | ||
176 | case DA9055_REG_VLDO6_B: | ||
177 | return true; | ||
178 | default: | ||
179 | return false; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | static bool da9055_register_volatile(struct device *dev, unsigned int reg) | ||
184 | { | ||
185 | switch (reg) { | ||
186 | case DA9055_REG_STATUS_A: | ||
187 | case DA9055_REG_STATUS_B: | ||
188 | case DA9055_REG_EVENT_A: | ||
189 | case DA9055_REG_EVENT_B: | ||
190 | case DA9055_REG_EVENT_C: | ||
191 | |||
192 | case DA9055_REG_CONTROL_A: | ||
193 | case DA9055_REG_CONTROL_E: | ||
194 | |||
195 | case DA9055_REG_ADC_MAN: | ||
196 | case DA9055_REG_ADC_RES_L: | ||
197 | case DA9055_REG_ADC_RES_H: | ||
198 | case DA9055_REG_VSYS_RES: | ||
199 | case DA9055_REG_ADCIN1_RES: | ||
200 | case DA9055_REG_ADCIN2_RES: | ||
201 | case DA9055_REG_ADCIN3_RES: | ||
202 | |||
203 | case DA9055_REG_COUNT_S: | ||
204 | case DA9055_REG_COUNT_MI: | ||
205 | case DA9055_REG_COUNT_H: | ||
206 | case DA9055_REG_COUNT_D: | ||
207 | case DA9055_REG_COUNT_MO: | ||
208 | case DA9055_REG_COUNT_Y: | ||
209 | case DA9055_REG_ALARM_MI: | ||
210 | |||
211 | case DA9055_REG_BCORE_CONT: | ||
212 | case DA9055_REG_BMEM_CONT: | ||
213 | case DA9055_REG_LDO1_CONT: | ||
214 | case DA9055_REG_LDO2_CONT: | ||
215 | case DA9055_REG_LDO3_CONT: | ||
216 | case DA9055_REG_LDO4_CONT: | ||
217 | case DA9055_REG_LDO5_CONT: | ||
218 | case DA9055_REG_LDO6_CONT: | ||
219 | return true; | ||
220 | default: | ||
221 | return false; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static struct regmap_irq da9055_irqs[] = { | ||
226 | [DA9055_IRQ_NONKEY] = { | ||
227 | .reg_offset = 0, | ||
228 | .mask = DA9055_IRQ_NONKEY_MASK, | ||
229 | }, | ||
230 | [DA9055_IRQ_ALARM] = { | ||
231 | .reg_offset = 0, | ||
232 | .mask = DA9055_IRQ_ALM_MASK, | ||
233 | }, | ||
234 | [DA9055_IRQ_TICK] = { | ||
235 | .reg_offset = 0, | ||
236 | .mask = DA9055_IRQ_TICK_MASK, | ||
237 | }, | ||
238 | [DA9055_IRQ_HWMON] = { | ||
239 | .reg_offset = 0, | ||
240 | .mask = DA9055_IRQ_ADC_MASK, | ||
241 | }, | ||
242 | [DA9055_IRQ_REGULATOR] = { | ||
243 | .reg_offset = 1, | ||
244 | .mask = DA9055_IRQ_BUCK_ILIM_MASK, | ||
245 | }, | ||
246 | }; | ||
247 | |||
248 | struct regmap_config da9055_regmap_config = { | ||
249 | .reg_bits = 8, | ||
250 | .val_bits = 8, | ||
251 | |||
252 | .cache_type = REGCACHE_RBTREE, | ||
253 | |||
254 | .max_register = DA9055_MAX_REGISTER_CNT, | ||
255 | .readable_reg = da9055_register_readable, | ||
256 | .writeable_reg = da9055_register_writeable, | ||
257 | .volatile_reg = da9055_register_volatile, | ||
258 | }; | ||
259 | EXPORT_SYMBOL_GPL(da9055_regmap_config); | ||
260 | |||
261 | static struct resource da9055_onkey_resource = { | ||
262 | .name = "ONKEY", | ||
263 | .start = DA9055_IRQ_NONKEY, | ||
264 | .end = DA9055_IRQ_NONKEY, | ||
265 | .flags = IORESOURCE_IRQ, | ||
266 | }; | ||
267 | |||
268 | static struct resource da9055_rtc_resource[] = { | ||
269 | { | ||
270 | .name = "ALM", | ||
271 | .start = DA9055_IRQ_ALARM, | ||
272 | .end = DA9055_IRQ_ALARM, | ||
273 | .flags = IORESOURCE_IRQ, | ||
274 | }, | ||
275 | { | ||
276 | .name = "TICK", | ||
277 | .start = DA9055_IRQ_TICK, | ||
278 | .end = DA9055_IRQ_TICK, | ||
279 | .flags = IORESOURCE_IRQ, | ||
280 | }, | ||
281 | }; | ||
282 | |||
283 | static struct resource da9055_hwmon_resource = { | ||
284 | .name = "HWMON", | ||
285 | .start = DA9055_IRQ_HWMON, | ||
286 | .end = DA9055_IRQ_HWMON, | ||
287 | .flags = IORESOURCE_IRQ, | ||
288 | }; | ||
289 | |||
290 | static struct resource da9055_ld05_6_resource = { | ||
291 | .name = "REGULATOR", | ||
292 | .start = DA9055_IRQ_REGULATOR, | ||
293 | .end = DA9055_IRQ_REGULATOR, | ||
294 | .flags = IORESOURCE_IRQ, | ||
295 | }; | ||
296 | |||
297 | static struct mfd_cell da9055_devs[] = { | ||
298 | { | ||
299 | .of_compatible = "dialog,da9055-gpio", | ||
300 | .name = "da9055-gpio", | ||
301 | }, | ||
302 | { | ||
303 | .of_compatible = "dialog,da9055-regulator", | ||
304 | .name = "da9055-regulator", | ||
305 | .id = 1, | ||
306 | }, | ||
307 | { | ||
308 | .of_compatible = "dialog,da9055-regulator", | ||
309 | .name = "da9055-regulator", | ||
310 | .id = 2, | ||
311 | }, | ||
312 | { | ||
313 | .of_compatible = "dialog,da9055-regulator", | ||
314 | .name = "da9055-regulator", | ||
315 | .id = 3, | ||
316 | }, | ||
317 | { | ||
318 | .of_compatible = "dialog,da9055-regulator", | ||
319 | .name = "da9055-regulator", | ||
320 | .id = 4, | ||
321 | }, | ||
322 | { | ||
323 | .of_compatible = "dialog,da9055-regulator", | ||
324 | .name = "da9055-regulator", | ||
325 | .id = 5, | ||
326 | }, | ||
327 | { | ||
328 | .of_compatible = "dialog,da9055-regulator", | ||
329 | .name = "da9055-regulator", | ||
330 | .id = 6, | ||
331 | }, | ||
332 | { | ||
333 | .of_compatible = "dialog,da9055-regulator", | ||
334 | .name = "da9055-regulator", | ||
335 | .id = 7, | ||
336 | .resources = &da9055_ld05_6_resource, | ||
337 | .num_resources = 1, | ||
338 | }, | ||
339 | { | ||
340 | .of_compatible = "dialog,da9055-regulator", | ||
341 | .name = "da9055-regulator", | ||
342 | .resources = &da9055_ld05_6_resource, | ||
343 | .num_resources = 1, | ||
344 | .id = 8, | ||
345 | }, | ||
346 | { | ||
347 | .of_compatible = "dialog,da9055-onkey", | ||
348 | .name = "da9055-onkey", | ||
349 | .resources = &da9055_onkey_resource, | ||
350 | .num_resources = 1, | ||
351 | }, | ||
352 | { | ||
353 | .of_compatible = "dialog,da9055-rtc", | ||
354 | .name = "da9055-rtc", | ||
355 | .resources = da9055_rtc_resource, | ||
356 | .num_resources = ARRAY_SIZE(da9055_rtc_resource), | ||
357 | }, | ||
358 | { | ||
359 | .of_compatible = "dialog,da9055-hwmon", | ||
360 | .name = "da9055-hwmon", | ||
361 | .resources = &da9055_hwmon_resource, | ||
362 | .num_resources = 1, | ||
363 | }, | ||
364 | { | ||
365 | .of_compatible = "dialog,da9055-watchdog", | ||
366 | .name = "da9055-watchdog", | ||
367 | }, | ||
368 | }; | ||
369 | |||
370 | static struct regmap_irq_chip da9055_regmap_irq_chip = { | ||
371 | .name = "da9055_irq", | ||
372 | .status_base = DA9055_REG_EVENT_A, | ||
373 | .mask_base = DA9055_REG_IRQ_MASK_A, | ||
374 | .ack_base = DA9055_REG_EVENT_A, | ||
375 | .num_regs = 3, | ||
376 | .irqs = da9055_irqs, | ||
377 | .num_irqs = ARRAY_SIZE(da9055_irqs), | ||
378 | }; | ||
379 | |||
380 | int __devinit da9055_device_init(struct da9055 *da9055) | ||
381 | { | ||
382 | struct da9055_pdata *pdata = da9055->dev->platform_data; | ||
383 | int ret; | ||
384 | |||
385 | if (pdata && pdata->init != NULL) | ||
386 | pdata->init(da9055); | ||
387 | |||
388 | if (!pdata || !pdata->irq_base) | ||
389 | da9055->irq_base = -1; | ||
390 | else | ||
391 | da9055->irq_base = pdata->irq_base; | ||
392 | |||
393 | ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, | ||
394 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | ||
395 | da9055->irq_base, &da9055_regmap_irq_chip, | ||
396 | &da9055->irq_data); | ||
397 | if (ret < 0) | ||
398 | return ret; | ||
399 | |||
400 | da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data); | ||
401 | |||
402 | ret = mfd_add_devices(da9055->dev, -1, | ||
403 | da9055_devs, ARRAY_SIZE(da9055_devs), | ||
404 | NULL, da9055->irq_base, NULL); | ||
405 | if (ret) | ||
406 | goto err; | ||
407 | |||
408 | return 0; | ||
409 | |||
410 | err: | ||
411 | mfd_remove_devices(da9055->dev); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | void __devexit da9055_device_exit(struct da9055 *da9055) | ||
416 | { | ||
417 | regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data); | ||
418 | mfd_remove_devices(da9055->dev); | ||
419 | } | ||
420 | |||
421 | MODULE_DESCRIPTION("Core support for the DA9055 PMIC"); | ||
422 | MODULE_LICENSE("GPL"); | ||
423 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | ||
diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c new file mode 100644 index 000000000000..88f6dca53bac --- /dev/null +++ b/drivers/mfd/da9055-i2c.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* I2C access for DA9055 PMICs. | ||
2 | * | ||
3 | * Copyright(c) 2012 Dialog Semiconductor Ltd. | ||
4 | * | ||
5 | * Author: David Dajun Chen <dchen@diasemi.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 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/err.h> | ||
18 | |||
19 | #include <linux/mfd/da9055/core.h> | ||
20 | |||
21 | static int __devinit da9055_i2c_probe(struct i2c_client *i2c, | ||
22 | const struct i2c_device_id *id) | ||
23 | { | ||
24 | struct da9055 *da9055; | ||
25 | int ret; | ||
26 | |||
27 | da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055), GFP_KERNEL); | ||
28 | if (!da9055) | ||
29 | return -ENOMEM; | ||
30 | |||
31 | da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config); | ||
32 | if (IS_ERR(da9055->regmap)) { | ||
33 | ret = PTR_ERR(da9055->regmap); | ||
34 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | ||
35 | ret); | ||
36 | return ret; | ||
37 | } | ||
38 | |||
39 | da9055->dev = &i2c->dev; | ||
40 | da9055->chip_irq = i2c->irq; | ||
41 | |||
42 | i2c_set_clientdata(i2c, da9055); | ||
43 | |||
44 | return da9055_device_init(da9055); | ||
45 | } | ||
46 | |||
47 | static int __devexit da9055_i2c_remove(struct i2c_client *i2c) | ||
48 | { | ||
49 | struct da9055 *da9055 = i2c_get_clientdata(i2c); | ||
50 | |||
51 | da9055_device_exit(da9055); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static struct i2c_device_id da9055_i2c_id[] = { | ||
57 | {"da9055-pmic", 0}, | ||
58 | { } | ||
59 | }; | ||
60 | |||
61 | static struct i2c_driver da9055_i2c_driver = { | ||
62 | .probe = da9055_i2c_probe, | ||
63 | .remove = __devexit_p(da9055_i2c_remove), | ||
64 | .id_table = da9055_i2c_id, | ||
65 | .driver = { | ||
66 | .name = "da9055", | ||
67 | .owner = THIS_MODULE, | ||
68 | }, | ||
69 | }; | ||
70 | |||
71 | static int __init da9055_i2c_init(void) | ||
72 | { | ||
73 | int ret; | ||
74 | |||
75 | ret = i2c_add_driver(&da9055_i2c_driver); | ||
76 | if (ret != 0) { | ||
77 | pr_err("DA9055 I2C registration failed %d\n", ret); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | subsys_initcall(da9055_i2c_init); | ||
84 | |||
85 | static void __exit da9055_i2c_exit(void) | ||
86 | { | ||
87 | i2c_del_driver(&da9055_i2c_driver); | ||
88 | } | ||
89 | module_exit(da9055_i2c_exit); | ||
90 | |||
91 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | ||
92 | MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC"); | ||
93 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 6b67edbdbd01..00b8b0f3dfb6 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
@@ -270,6 +270,8 @@ static struct { | |||
270 | struct prcmu_fw_version version; | 270 | struct prcmu_fw_version version; |
271 | } fw_info; | 271 | } fw_info; |
272 | 272 | ||
273 | static struct irq_domain *db8500_irq_domain; | ||
274 | |||
273 | /* | 275 | /* |
274 | * This vector maps irq numbers to the bits in the bit field used in | 276 | * This vector maps irq numbers to the bits in the bit field used in |
275 | * communication with the PRCMU firmware. | 277 | * communication with the PRCMU firmware. |
@@ -2624,7 +2626,7 @@ static void prcmu_irq_mask(struct irq_data *d) | |||
2624 | 2626 | ||
2625 | spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); | 2627 | spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); |
2626 | 2628 | ||
2627 | mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; | 2629 | mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->hwirq]; |
2628 | 2630 | ||
2629 | spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); | 2631 | spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); |
2630 | 2632 | ||
@@ -2638,7 +2640,7 @@ static void prcmu_irq_unmask(struct irq_data *d) | |||
2638 | 2640 | ||
2639 | spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); | 2641 | spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); |
2640 | 2642 | ||
2641 | mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; | 2643 | mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->hwirq]; |
2642 | 2644 | ||
2643 | spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); | 2645 | spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); |
2644 | 2646 | ||
@@ -2678,9 +2680,37 @@ static char *fw_project_name(u8 project) | |||
2678 | } | 2680 | } |
2679 | } | 2681 | } |
2680 | 2682 | ||
2683 | static int db8500_irq_map(struct irq_domain *d, unsigned int virq, | ||
2684 | irq_hw_number_t hwirq) | ||
2685 | { | ||
2686 | irq_set_chip_and_handler(virq, &prcmu_irq_chip, | ||
2687 | handle_simple_irq); | ||
2688 | set_irq_flags(virq, IRQF_VALID); | ||
2689 | |||
2690 | return 0; | ||
2691 | } | ||
2692 | |||
2693 | static struct irq_domain_ops db8500_irq_ops = { | ||
2694 | .map = db8500_irq_map, | ||
2695 | .xlate = irq_domain_xlate_twocell, | ||
2696 | }; | ||
2697 | |||
2698 | static int db8500_irq_init(struct device_node *np) | ||
2699 | { | ||
2700 | db8500_irq_domain = irq_domain_add_legacy( | ||
2701 | np, NUM_PRCMU_WAKEUPS, IRQ_PRCMU_BASE, | ||
2702 | 0, &db8500_irq_ops, NULL); | ||
2703 | |||
2704 | if (!db8500_irq_domain) { | ||
2705 | pr_err("Failed to create irqdomain\n"); | ||
2706 | return -ENOSYS; | ||
2707 | } | ||
2708 | |||
2709 | return 0; | ||
2710 | } | ||
2711 | |||
2681 | void __init db8500_prcmu_early_init(void) | 2712 | void __init db8500_prcmu_early_init(void) |
2682 | { | 2713 | { |
2683 | unsigned int i; | ||
2684 | if (cpu_is_u8500v2()) { | 2714 | if (cpu_is_u8500v2()) { |
2685 | void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); | 2715 | void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); |
2686 | 2716 | ||
@@ -2725,15 +2755,6 @@ void __init db8500_prcmu_early_init(void) | |||
2725 | 2755 | ||
2726 | INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); | 2756 | INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); |
2727 | 2757 | ||
2728 | /* Initalize irqs. */ | ||
2729 | for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) { | ||
2730 | unsigned int irq; | ||
2731 | |||
2732 | irq = IRQ_PRCMU_BASE + i; | ||
2733 | irq_set_chip_and_handler(irq, &prcmu_irq_chip, | ||
2734 | handle_simple_irq); | ||
2735 | set_irq_flags(irq, IRQF_VALID); | ||
2736 | } | ||
2737 | compute_armss_rate(); | 2758 | compute_armss_rate(); |
2738 | } | 2759 | } |
2739 | 2760 | ||
@@ -3041,6 +3062,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev) | |||
3041 | goto no_irq_return; | 3062 | goto no_irq_return; |
3042 | } | 3063 | } |
3043 | 3064 | ||
3065 | db8500_irq_init(np); | ||
3066 | |||
3044 | for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) { | 3067 | for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) { |
3045 | if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) { | 3068 | if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) { |
3046 | db8500_prcmu_devs[i].platform_data = ab8500_platdata; | 3069 | db8500_prcmu_devs[i].platform_data = ab8500_platdata; |
diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c new file mode 100644 index 000000000000..c84ded5f8ece --- /dev/null +++ b/drivers/mfd/lp8788-irq.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * TI LP8788 MFD - interrupt handler | ||
3 | * | ||
4 | * Copyright 2012 Texas Instruments | ||
5 | * | ||
6 | * Author: Milo(Woogyom) Kim <milo.kim@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/irqdomain.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/mfd/lp8788.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | /* register address */ | ||
25 | #define LP8788_INT_1 0x00 | ||
26 | #define LP8788_INTEN_1 0x03 | ||
27 | |||
28 | #define BASE_INTEN_ADDR LP8788_INTEN_1 | ||
29 | #define SIZE_REG 8 | ||
30 | #define NUM_REGS 3 | ||
31 | |||
32 | /* | ||
33 | * struct lp8788_irq_data | ||
34 | * @lp : used for accessing to lp8788 registers | ||
35 | * @irq_lock : mutex for enabling/disabling the interrupt | ||
36 | * @domain : IRQ domain for handling nested interrupt | ||
37 | * @enabled : status of enabled interrupt | ||
38 | */ | ||
39 | struct lp8788_irq_data { | ||
40 | struct lp8788 *lp; | ||
41 | struct mutex irq_lock; | ||
42 | struct irq_domain *domain; | ||
43 | int enabled[LP8788_INT_MAX]; | ||
44 | }; | ||
45 | |||
46 | static inline u8 _irq_to_addr(enum lp8788_int_id id) | ||
47 | { | ||
48 | return id / SIZE_REG; | ||
49 | } | ||
50 | |||
51 | static inline u8 _irq_to_enable_addr(enum lp8788_int_id id) | ||
52 | { | ||
53 | return _irq_to_addr(id) + BASE_INTEN_ADDR; | ||
54 | } | ||
55 | |||
56 | static inline u8 _irq_to_mask(enum lp8788_int_id id) | ||
57 | { | ||
58 | return 1 << (id % SIZE_REG); | ||
59 | } | ||
60 | |||
61 | static inline u8 _irq_to_val(enum lp8788_int_id id, int enable) | ||
62 | { | ||
63 | return enable << (id % SIZE_REG); | ||
64 | } | ||
65 | |||
66 | static void lp8788_irq_enable(struct irq_data *data) | ||
67 | { | ||
68 | struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); | ||
69 | irqd->enabled[data->hwirq] = 1; | ||
70 | } | ||
71 | |||
72 | static void lp8788_irq_disable(struct irq_data *data) | ||
73 | { | ||
74 | struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); | ||
75 | irqd->enabled[data->hwirq] = 0; | ||
76 | } | ||
77 | |||
78 | static void lp8788_irq_bus_lock(struct irq_data *data) | ||
79 | { | ||
80 | struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); | ||
81 | |||
82 | mutex_lock(&irqd->irq_lock); | ||
83 | } | ||
84 | |||
85 | static void lp8788_irq_bus_sync_unlock(struct irq_data *data) | ||
86 | { | ||
87 | struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); | ||
88 | enum lp8788_int_id irq = data->hwirq; | ||
89 | u8 addr, mask, val; | ||
90 | |||
91 | addr = _irq_to_enable_addr(irq); | ||
92 | mask = _irq_to_mask(irq); | ||
93 | val = _irq_to_val(irq, irqd->enabled[irq]); | ||
94 | |||
95 | lp8788_update_bits(irqd->lp, addr, mask, val); | ||
96 | |||
97 | mutex_unlock(&irqd->irq_lock); | ||
98 | } | ||
99 | |||
100 | static struct irq_chip lp8788_irq_chip = { | ||
101 | .name = "lp8788", | ||
102 | .irq_enable = lp8788_irq_enable, | ||
103 | .irq_disable = lp8788_irq_disable, | ||
104 | .irq_bus_lock = lp8788_irq_bus_lock, | ||
105 | .irq_bus_sync_unlock = lp8788_irq_bus_sync_unlock, | ||
106 | }; | ||
107 | |||
108 | static irqreturn_t lp8788_irq_handler(int irq, void *ptr) | ||
109 | { | ||
110 | struct lp8788_irq_data *irqd = ptr; | ||
111 | struct lp8788 *lp = irqd->lp; | ||
112 | u8 status[NUM_REGS], addr, mask; | ||
113 | bool handled; | ||
114 | int i; | ||
115 | |||
116 | if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS)) | ||
117 | return IRQ_NONE; | ||
118 | |||
119 | for (i = 0 ; i < LP8788_INT_MAX ; i++) { | ||
120 | addr = _irq_to_addr(i); | ||
121 | mask = _irq_to_mask(i); | ||
122 | |||
123 | /* reporting only if the irq is enabled */ | ||
124 | if (status[addr] & mask) { | ||
125 | handle_nested_irq(irq_find_mapping(irqd->domain, i)); | ||
126 | handled = true; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | return handled ? IRQ_HANDLED : IRQ_NONE; | ||
131 | } | ||
132 | |||
133 | static int lp8788_irq_map(struct irq_domain *d, unsigned int virq, | ||
134 | irq_hw_number_t hwirq) | ||
135 | { | ||
136 | struct lp8788_irq_data *irqd = d->host_data; | ||
137 | struct irq_chip *chip = &lp8788_irq_chip; | ||
138 | |||
139 | irq_set_chip_data(virq, irqd); | ||
140 | irq_set_chip_and_handler(virq, chip, handle_edge_irq); | ||
141 | irq_set_nested_thread(virq, 1); | ||
142 | |||
143 | #ifdef CONFIG_ARM | ||
144 | set_irq_flags(virq, IRQF_VALID); | ||
145 | #else | ||
146 | irq_set_noprobe(virq); | ||
147 | #endif | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static struct irq_domain_ops lp8788_domain_ops = { | ||
153 | .map = lp8788_irq_map, | ||
154 | }; | ||
155 | |||
156 | int lp8788_irq_init(struct lp8788 *lp, int irq) | ||
157 | { | ||
158 | struct lp8788_irq_data *irqd; | ||
159 | int ret; | ||
160 | |||
161 | if (irq <= 0) { | ||
162 | dev_warn(lp->dev, "invalid irq number: %d\n", irq); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | irqd = devm_kzalloc(lp->dev, sizeof(*irqd), GFP_KERNEL); | ||
167 | if (!irqd) | ||
168 | return -ENOMEM; | ||
169 | |||
170 | irqd->lp = lp; | ||
171 | irqd->domain = irq_domain_add_linear(lp->dev->of_node, LP8788_INT_MAX, | ||
172 | &lp8788_domain_ops, irqd); | ||
173 | if (!irqd->domain) { | ||
174 | dev_err(lp->dev, "failed to add irq domain err\n"); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | |||
178 | lp->irqdm = irqd->domain; | ||
179 | mutex_init(&irqd->irq_lock); | ||
180 | |||
181 | ret = request_threaded_irq(irq, NULL, lp8788_irq_handler, | ||
182 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
183 | "lp8788-irq", irqd); | ||
184 | if (ret) { | ||
185 | dev_err(lp->dev, "failed to create a thread for IRQ_N\n"); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | lp->irq = irq; | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | void lp8788_irq_exit(struct lp8788 *lp) | ||
195 | { | ||
196 | if (lp->irq) | ||
197 | free_irq(lp->irq, lp->irqdm); | ||
198 | } | ||
diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c new file mode 100644 index 000000000000..3e94a699833c --- /dev/null +++ b/drivers/mfd/lp8788.c | |||
@@ -0,0 +1,245 @@ | |||
1 | /* | ||
2 | * TI LP8788 MFD - core interface | ||
3 | * | ||
4 | * Copyright 2012 Texas Instruments | ||
5 | * | ||
6 | * Author: Milo(Woogyom) Kim <milo.kim@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/err.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/mfd/core.h> | ||
17 | #include <linux/mfd/lp8788.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #define MAX_LP8788_REGISTERS 0xA2 | ||
22 | |||
23 | #define MFD_DEV_SIMPLE(_name) \ | ||
24 | { \ | ||
25 | .name = LP8788_DEV_##_name, \ | ||
26 | } | ||
27 | |||
28 | #define MFD_DEV_WITH_ID(_name, _id) \ | ||
29 | { \ | ||
30 | .name = LP8788_DEV_##_name, \ | ||
31 | .id = _id, \ | ||
32 | } | ||
33 | |||
34 | #define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \ | ||
35 | { \ | ||
36 | .name = LP8788_DEV_##_name, \ | ||
37 | .resources = _resource, \ | ||
38 | .num_resources = num_resource, \ | ||
39 | } | ||
40 | |||
41 | static struct resource chg_irqs[] = { | ||
42 | /* Charger Interrupts */ | ||
43 | { | ||
44 | .start = LP8788_INT_CHG_INPUT_STATE, | ||
45 | .end = LP8788_INT_PRECHG_TIMEOUT, | ||
46 | .name = LP8788_CHG_IRQ, | ||
47 | .flags = IORESOURCE_IRQ, | ||
48 | }, | ||
49 | /* Power Routing Switch Interrupts */ | ||
50 | { | ||
51 | .start = LP8788_INT_ENTER_SYS_SUPPORT, | ||
52 | .end = LP8788_INT_EXIT_SYS_SUPPORT, | ||
53 | .name = LP8788_PRSW_IRQ, | ||
54 | .flags = IORESOURCE_IRQ, | ||
55 | }, | ||
56 | /* Battery Interrupts */ | ||
57 | { | ||
58 | .start = LP8788_INT_BATT_LOW, | ||
59 | .end = LP8788_INT_NO_BATT, | ||
60 | .name = LP8788_BATT_IRQ, | ||
61 | .flags = IORESOURCE_IRQ, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | static struct resource rtc_irqs[] = { | ||
66 | { | ||
67 | .start = LP8788_INT_RTC_ALARM1, | ||
68 | .end = LP8788_INT_RTC_ALARM2, | ||
69 | .name = LP8788_ALM_IRQ, | ||
70 | .flags = IORESOURCE_IRQ, | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | static struct mfd_cell lp8788_devs[] = { | ||
75 | /* 4 bucks */ | ||
76 | MFD_DEV_WITH_ID(BUCK, 1), | ||
77 | MFD_DEV_WITH_ID(BUCK, 2), | ||
78 | MFD_DEV_WITH_ID(BUCK, 3), | ||
79 | MFD_DEV_WITH_ID(BUCK, 4), | ||
80 | |||
81 | /* 12 digital ldos */ | ||
82 | MFD_DEV_WITH_ID(DLDO, 1), | ||
83 | MFD_DEV_WITH_ID(DLDO, 2), | ||
84 | MFD_DEV_WITH_ID(DLDO, 3), | ||
85 | MFD_DEV_WITH_ID(DLDO, 4), | ||
86 | MFD_DEV_WITH_ID(DLDO, 5), | ||
87 | MFD_DEV_WITH_ID(DLDO, 6), | ||
88 | MFD_DEV_WITH_ID(DLDO, 7), | ||
89 | MFD_DEV_WITH_ID(DLDO, 8), | ||
90 | MFD_DEV_WITH_ID(DLDO, 9), | ||
91 | MFD_DEV_WITH_ID(DLDO, 10), | ||
92 | MFD_DEV_WITH_ID(DLDO, 11), | ||
93 | MFD_DEV_WITH_ID(DLDO, 12), | ||
94 | |||
95 | /* 10 analog ldos */ | ||
96 | MFD_DEV_WITH_ID(ALDO, 1), | ||
97 | MFD_DEV_WITH_ID(ALDO, 2), | ||
98 | MFD_DEV_WITH_ID(ALDO, 3), | ||
99 | MFD_DEV_WITH_ID(ALDO, 4), | ||
100 | MFD_DEV_WITH_ID(ALDO, 5), | ||
101 | MFD_DEV_WITH_ID(ALDO, 6), | ||
102 | MFD_DEV_WITH_ID(ALDO, 7), | ||
103 | MFD_DEV_WITH_ID(ALDO, 8), | ||
104 | MFD_DEV_WITH_ID(ALDO, 9), | ||
105 | MFD_DEV_WITH_ID(ALDO, 10), | ||
106 | |||
107 | /* ADC */ | ||
108 | MFD_DEV_SIMPLE(ADC), | ||
109 | |||
110 | /* battery charger */ | ||
111 | MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)), | ||
112 | |||
113 | /* rtc */ | ||
114 | MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)), | ||
115 | |||
116 | /* backlight */ | ||
117 | MFD_DEV_SIMPLE(BACKLIGHT), | ||
118 | |||
119 | /* current sink for vibrator */ | ||
120 | MFD_DEV_SIMPLE(VIBRATOR), | ||
121 | |||
122 | /* current sink for keypad LED */ | ||
123 | MFD_DEV_SIMPLE(KEYLED), | ||
124 | }; | ||
125 | |||
126 | int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data) | ||
127 | { | ||
128 | int ret; | ||
129 | unsigned int val; | ||
130 | |||
131 | ret = regmap_read(lp->regmap, reg, &val); | ||
132 | if (ret < 0) { | ||
133 | dev_err(lp->dev, "failed to read 0x%.2x\n", reg); | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | *data = (u8)val; | ||
138 | return 0; | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(lp8788_read_byte); | ||
141 | |||
142 | int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count) | ||
143 | { | ||
144 | return regmap_bulk_read(lp->regmap, reg, data, count); | ||
145 | } | ||
146 | EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes); | ||
147 | |||
148 | int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data) | ||
149 | { | ||
150 | return regmap_write(lp->regmap, reg, data); | ||
151 | } | ||
152 | EXPORT_SYMBOL_GPL(lp8788_write_byte); | ||
153 | |||
154 | int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data) | ||
155 | { | ||
156 | return regmap_update_bits(lp->regmap, reg, mask, data); | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(lp8788_update_bits); | ||
159 | |||
160 | static int lp8788_platform_init(struct lp8788 *lp) | ||
161 | { | ||
162 | struct lp8788_platform_data *pdata = lp->pdata; | ||
163 | |||
164 | return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0; | ||
165 | } | ||
166 | |||
167 | static const struct regmap_config lp8788_regmap_config = { | ||
168 | .reg_bits = 8, | ||
169 | .val_bits = 8, | ||
170 | .max_register = MAX_LP8788_REGISTERS, | ||
171 | }; | ||
172 | |||
173 | static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) | ||
174 | { | ||
175 | struct lp8788 *lp; | ||
176 | struct lp8788_platform_data *pdata = cl->dev.platform_data; | ||
177 | int ret; | ||
178 | |||
179 | lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL); | ||
180 | if (!lp) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config); | ||
184 | if (IS_ERR(lp->regmap)) { | ||
185 | ret = PTR_ERR(lp->regmap); | ||
186 | dev_err(&cl->dev, "regmap init i2c err: %d\n", ret); | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | lp->pdata = pdata; | ||
191 | lp->dev = &cl->dev; | ||
192 | i2c_set_clientdata(cl, lp); | ||
193 | |||
194 | ret = lp8788_platform_init(lp); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | |||
198 | ret = lp8788_irq_init(lp, cl->irq); | ||
199 | if (ret) | ||
200 | return ret; | ||
201 | |||
202 | return mfd_add_devices(lp->dev, -1, lp8788_devs, | ||
203 | ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); | ||
204 | } | ||
205 | |||
206 | static int __devexit lp8788_remove(struct i2c_client *cl) | ||
207 | { | ||
208 | struct lp8788 *lp = i2c_get_clientdata(cl); | ||
209 | |||
210 | mfd_remove_devices(lp->dev); | ||
211 | lp8788_irq_exit(lp); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static const struct i2c_device_id lp8788_ids[] = { | ||
216 | {"lp8788", 0}, | ||
217 | { } | ||
218 | }; | ||
219 | MODULE_DEVICE_TABLE(i2c, lp8788_ids); | ||
220 | |||
221 | static struct i2c_driver lp8788_driver = { | ||
222 | .driver = { | ||
223 | .name = "lp8788", | ||
224 | .owner = THIS_MODULE, | ||
225 | }, | ||
226 | .probe = lp8788_probe, | ||
227 | .remove = __devexit_p(lp8788_remove), | ||
228 | .id_table = lp8788_ids, | ||
229 | }; | ||
230 | |||
231 | static int __init lp8788_init(void) | ||
232 | { | ||
233 | return i2c_add_driver(&lp8788_driver); | ||
234 | } | ||
235 | subsys_initcall(lp8788_init); | ||
236 | |||
237 | static void __exit lp8788_exit(void) | ||
238 | { | ||
239 | i2c_del_driver(&lp8788_driver); | ||
240 | } | ||
241 | module_exit(lp8788_exit); | ||
242 | |||
243 | MODULE_DESCRIPTION("TI LP8788 MFD Driver"); | ||
244 | MODULE_AUTHOR("Milo Kim"); | ||
245 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 092ad4b44b6d..a22544fe5319 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c | |||
@@ -49,6 +49,7 @@ | |||
49 | * document number TBD : DH89xxCC | 49 | * document number TBD : DH89xxCC |
50 | * document number TBD : Panther Point | 50 | * document number TBD : Panther Point |
51 | * document number TBD : Lynx Point | 51 | * document number TBD : Lynx Point |
52 | * document number TBD : Lynx Point-LP | ||
52 | */ | 53 | */ |
53 | 54 | ||
54 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 55 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -192,6 +193,7 @@ enum lpc_chipsets { | |||
192 | LPC_DH89XXCC, /* DH89xxCC */ | 193 | LPC_DH89XXCC, /* DH89xxCC */ |
193 | LPC_PPT, /* Panther Point */ | 194 | LPC_PPT, /* Panther Point */ |
194 | LPC_LPT, /* Lynx Point */ | 195 | LPC_LPT, /* Lynx Point */ |
196 | LPC_LPT_LP, /* Lynx Point-LP */ | ||
195 | }; | 197 | }; |
196 | 198 | ||
197 | struct lpc_ich_info lpc_chipset_info[] __devinitdata = { | 199 | struct lpc_ich_info lpc_chipset_info[] __devinitdata = { |
@@ -468,6 +470,10 @@ struct lpc_ich_info lpc_chipset_info[] __devinitdata = { | |||
468 | .name = "Lynx Point", | 470 | .name = "Lynx Point", |
469 | .iTCO_version = 2, | 471 | .iTCO_version = 2, |
470 | }, | 472 | }, |
473 | [LPC_LPT_LP] = { | ||
474 | .name = "Lynx Point_LP", | ||
475 | .iTCO_version = 2, | ||
476 | }, | ||
471 | }; | 477 | }; |
472 | 478 | ||
473 | /* | 479 | /* |
@@ -641,6 +647,14 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = { | |||
641 | { PCI_VDEVICE(INTEL, 0x8c5d), LPC_LPT}, | 647 | { PCI_VDEVICE(INTEL, 0x8c5d), LPC_LPT}, |
642 | { PCI_VDEVICE(INTEL, 0x8c5e), LPC_LPT}, | 648 | { PCI_VDEVICE(INTEL, 0x8c5e), LPC_LPT}, |
643 | { PCI_VDEVICE(INTEL, 0x8c5f), LPC_LPT}, | 649 | { PCI_VDEVICE(INTEL, 0x8c5f), LPC_LPT}, |
650 | { PCI_VDEVICE(INTEL, 0x9c40), LPC_LPT_LP}, | ||
651 | { PCI_VDEVICE(INTEL, 0x9c41), LPC_LPT_LP}, | ||
652 | { PCI_VDEVICE(INTEL, 0x9c42), LPC_LPT_LP}, | ||
653 | { PCI_VDEVICE(INTEL, 0x9c43), LPC_LPT_LP}, | ||
654 | { PCI_VDEVICE(INTEL, 0x9c44), LPC_LPT_LP}, | ||
655 | { PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP}, | ||
656 | { PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP}, | ||
657 | { PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP}, | ||
644 | { 0, }, /* End of list */ | 658 | { 0, }, /* End of list */ |
645 | }; | 659 | }; |
646 | MODULE_DEVICE_TABLE(pci, lpc_ich_ids); | 660 | MODULE_DEVICE_TABLE(pci, lpc_ich_ids); |
@@ -683,6 +697,30 @@ static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell, | |||
683 | cell->pdata_size = sizeof(struct lpc_ich_info); | 697 | cell->pdata_size = sizeof(struct lpc_ich_info); |
684 | } | 698 | } |
685 | 699 | ||
700 | /* | ||
701 | * We don't check for resource conflict globally. There are 2 or 3 independent | ||
702 | * GPIO groups and it's enough to have access to one of these to instantiate | ||
703 | * the device. | ||
704 | */ | ||
705 | static int __devinit lpc_ich_check_conflict_gpio(struct resource *res) | ||
706 | { | ||
707 | int ret; | ||
708 | u8 use_gpio = 0; | ||
709 | |||
710 | if (resource_size(res) >= 0x50 && | ||
711 | !acpi_check_region(res->start + 0x40, 0x10, "LPC ICH GPIO3")) | ||
712 | use_gpio |= 1 << 2; | ||
713 | |||
714 | if (!acpi_check_region(res->start + 0x30, 0x10, "LPC ICH GPIO2")) | ||
715 | use_gpio |= 1 << 1; | ||
716 | |||
717 | ret = acpi_check_region(res->start + 0x00, 0x30, "LPC ICH GPIO1"); | ||
718 | if (!ret) | ||
719 | use_gpio |= 1 << 0; | ||
720 | |||
721 | return use_gpio ? use_gpio : ret; | ||
722 | } | ||
723 | |||
686 | static int __devinit lpc_ich_init_gpio(struct pci_dev *dev, | 724 | static int __devinit lpc_ich_init_gpio(struct pci_dev *dev, |
687 | const struct pci_device_id *id) | 725 | const struct pci_device_id *id) |
688 | { | 726 | { |
@@ -740,12 +778,13 @@ gpe0_done: | |||
740 | break; | 778 | break; |
741 | } | 779 | } |
742 | 780 | ||
743 | ret = acpi_check_resource_conflict(res); | 781 | ret = lpc_ich_check_conflict_gpio(res); |
744 | if (ret) { | 782 | if (ret < 0) { |
745 | /* this isn't necessarily fatal for the GPIO */ | 783 | /* this isn't necessarily fatal for the GPIO */ |
746 | acpi_conflict = true; | 784 | acpi_conflict = true; |
747 | goto gpio_done; | 785 | goto gpio_done; |
748 | } | 786 | } |
787 | lpc_chipset_info[id->driver_data].use_gpio = ret; | ||
749 | lpc_ich_enable_gpio_space(dev); | 788 | lpc_ich_enable_gpio_space(dev); |
750 | 789 | ||
751 | lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); | 790 | lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); |
diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c new file mode 100644 index 000000000000..17f2593d82b8 --- /dev/null +++ b/drivers/mfd/max8907.c | |||
@@ -0,0 +1,351 @@ | |||
1 | /* | ||
2 | * max8907.c - mfd driver for MAX8907 | ||
3 | * | ||
4 | * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> | ||
5 | * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved. | ||
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 version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/err.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/mfd/core.h> | ||
18 | #include <linux/mfd/max8907.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/regmap.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | static struct mfd_cell max8907_cells[] = { | ||
25 | { .name = "max8907-regulator", }, | ||
26 | { .name = "max8907-rtc", }, | ||
27 | }; | ||
28 | |||
29 | static bool max8907_gen_is_volatile_reg(struct device *dev, unsigned int reg) | ||
30 | { | ||
31 | switch (reg) { | ||
32 | case MAX8907_REG_ON_OFF_IRQ1: | ||
33 | case MAX8907_REG_ON_OFF_STAT: | ||
34 | case MAX8907_REG_ON_OFF_IRQ2: | ||
35 | case MAX8907_REG_CHG_IRQ1: | ||
36 | case MAX8907_REG_CHG_IRQ2: | ||
37 | case MAX8907_REG_CHG_STAT: | ||
38 | return true; | ||
39 | default: | ||
40 | return false; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static bool max8907_gen_is_precious_reg(struct device *dev, unsigned int reg) | ||
45 | { | ||
46 | switch (reg) { | ||
47 | case MAX8907_REG_ON_OFF_IRQ1: | ||
48 | case MAX8907_REG_ON_OFF_IRQ2: | ||
49 | case MAX8907_REG_CHG_IRQ1: | ||
50 | case MAX8907_REG_CHG_IRQ2: | ||
51 | return true; | ||
52 | default: | ||
53 | return false; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | static bool max8907_gen_is_writeable_reg(struct device *dev, unsigned int reg) | ||
58 | { | ||
59 | return !max8907_gen_is_volatile_reg(dev, reg); | ||
60 | } | ||
61 | |||
62 | static const struct regmap_config max8907_regmap_gen_config = { | ||
63 | .reg_bits = 8, | ||
64 | .val_bits = 8, | ||
65 | .volatile_reg = max8907_gen_is_volatile_reg, | ||
66 | .precious_reg = max8907_gen_is_precious_reg, | ||
67 | .writeable_reg = max8907_gen_is_writeable_reg, | ||
68 | .max_register = MAX8907_REG_LDO20VOUT, | ||
69 | .cache_type = REGCACHE_RBTREE, | ||
70 | }; | ||
71 | |||
72 | static bool max8907_rtc_is_volatile_reg(struct device *dev, unsigned int reg) | ||
73 | { | ||
74 | if (reg <= MAX8907_REG_RTC_YEAR2) | ||
75 | return true; | ||
76 | |||
77 | switch (reg) { | ||
78 | case MAX8907_REG_RTC_STATUS: | ||
79 | case MAX8907_REG_RTC_IRQ: | ||
80 | return true; | ||
81 | default: | ||
82 | return false; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | static bool max8907_rtc_is_precious_reg(struct device *dev, unsigned int reg) | ||
87 | { | ||
88 | switch (reg) { | ||
89 | case MAX8907_REG_RTC_IRQ: | ||
90 | return true; | ||
91 | default: | ||
92 | return false; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static bool max8907_rtc_is_writeable_reg(struct device *dev, unsigned int reg) | ||
97 | { | ||
98 | switch (reg) { | ||
99 | case MAX8907_REG_RTC_STATUS: | ||
100 | case MAX8907_REG_RTC_IRQ: | ||
101 | return false; | ||
102 | default: | ||
103 | return true; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | static const struct regmap_config max8907_regmap_rtc_config = { | ||
108 | .reg_bits = 8, | ||
109 | .val_bits = 8, | ||
110 | .volatile_reg = max8907_rtc_is_volatile_reg, | ||
111 | .precious_reg = max8907_rtc_is_precious_reg, | ||
112 | .writeable_reg = max8907_rtc_is_writeable_reg, | ||
113 | .max_register = MAX8907_REG_MPL_CNTL, | ||
114 | .cache_type = REGCACHE_RBTREE, | ||
115 | }; | ||
116 | |||
117 | static const struct regmap_irq max8907_chg_irqs[] = { | ||
118 | { .reg_offset = 0, .mask = 1 << 0, }, | ||
119 | { .reg_offset = 0, .mask = 1 << 1, }, | ||
120 | { .reg_offset = 0, .mask = 1 << 2, }, | ||
121 | { .reg_offset = 1, .mask = 1 << 0, }, | ||
122 | { .reg_offset = 1, .mask = 1 << 1, }, | ||
123 | { .reg_offset = 1, .mask = 1 << 2, }, | ||
124 | { .reg_offset = 1, .mask = 1 << 3, }, | ||
125 | { .reg_offset = 1, .mask = 1 << 4, }, | ||
126 | { .reg_offset = 1, .mask = 1 << 5, }, | ||
127 | { .reg_offset = 1, .mask = 1 << 6, }, | ||
128 | { .reg_offset = 1, .mask = 1 << 7, }, | ||
129 | }; | ||
130 | |||
131 | static const struct regmap_irq_chip max8907_chg_irq_chip = { | ||
132 | .name = "max8907 chg", | ||
133 | .status_base = MAX8907_REG_CHG_IRQ1, | ||
134 | .mask_base = MAX8907_REG_CHG_IRQ1_MASK, | ||
135 | .wake_base = MAX8907_REG_CHG_IRQ1_MASK, | ||
136 | .irq_reg_stride = MAX8907_REG_CHG_IRQ2 - MAX8907_REG_CHG_IRQ1, | ||
137 | .num_regs = 2, | ||
138 | .irqs = max8907_chg_irqs, | ||
139 | .num_irqs = ARRAY_SIZE(max8907_chg_irqs), | ||
140 | }; | ||
141 | |||
142 | static const struct regmap_irq max8907_on_off_irqs[] = { | ||
143 | { .reg_offset = 0, .mask = 1 << 0, }, | ||
144 | { .reg_offset = 0, .mask = 1 << 1, }, | ||
145 | { .reg_offset = 0, .mask = 1 << 2, }, | ||
146 | { .reg_offset = 0, .mask = 1 << 3, }, | ||
147 | { .reg_offset = 0, .mask = 1 << 4, }, | ||
148 | { .reg_offset = 0, .mask = 1 << 5, }, | ||
149 | { .reg_offset = 0, .mask = 1 << 6, }, | ||
150 | { .reg_offset = 0, .mask = 1 << 7, }, | ||
151 | { .reg_offset = 1, .mask = 1 << 0, }, | ||
152 | { .reg_offset = 1, .mask = 1 << 1, }, | ||
153 | }; | ||
154 | |||
155 | static const struct regmap_irq_chip max8907_on_off_irq_chip = { | ||
156 | .name = "max8907 on_off", | ||
157 | .status_base = MAX8907_REG_ON_OFF_IRQ1, | ||
158 | .mask_base = MAX8907_REG_ON_OFF_IRQ1_MASK, | ||
159 | .irq_reg_stride = MAX8907_REG_ON_OFF_IRQ2 - MAX8907_REG_ON_OFF_IRQ1, | ||
160 | .num_regs = 2, | ||
161 | .irqs = max8907_on_off_irqs, | ||
162 | .num_irqs = ARRAY_SIZE(max8907_on_off_irqs), | ||
163 | }; | ||
164 | |||
165 | static const struct regmap_irq max8907_rtc_irqs[] = { | ||
166 | { .reg_offset = 0, .mask = 1 << 2, }, | ||
167 | { .reg_offset = 0, .mask = 1 << 3, }, | ||
168 | }; | ||
169 | |||
170 | static const struct regmap_irq_chip max8907_rtc_irq_chip = { | ||
171 | .name = "max8907 rtc", | ||
172 | .status_base = MAX8907_REG_RTC_IRQ, | ||
173 | .mask_base = MAX8907_REG_RTC_IRQ_MASK, | ||
174 | .num_regs = 1, | ||
175 | .irqs = max8907_rtc_irqs, | ||
176 | .num_irqs = ARRAY_SIZE(max8907_rtc_irqs), | ||
177 | }; | ||
178 | |||
179 | static struct max8907 *max8907_pm_off; | ||
180 | static void max8907_power_off(void) | ||
181 | { | ||
182 | regmap_update_bits(max8907_pm_off->regmap_gen, MAX8907_REG_RESET_CNFG, | ||
183 | MAX8907_MASK_POWER_OFF, MAX8907_MASK_POWER_OFF); | ||
184 | } | ||
185 | |||
186 | static __devinit int max8907_i2c_probe(struct i2c_client *i2c, | ||
187 | const struct i2c_device_id *id) | ||
188 | { | ||
189 | struct max8907 *max8907; | ||
190 | int ret; | ||
191 | struct max8907_platform_data *pdata = dev_get_platdata(&i2c->dev); | ||
192 | bool pm_off = false; | ||
193 | |||
194 | if (pdata) | ||
195 | pm_off = pdata->pm_off; | ||
196 | else if (i2c->dev.of_node) | ||
197 | pm_off = of_property_read_bool(i2c->dev.of_node, | ||
198 | "maxim,system-power-controller"); | ||
199 | |||
200 | max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL); | ||
201 | if (!max8907) { | ||
202 | ret = -ENOMEM; | ||
203 | goto err_alloc_drvdata; | ||
204 | } | ||
205 | |||
206 | max8907->dev = &i2c->dev; | ||
207 | dev_set_drvdata(max8907->dev, max8907); | ||
208 | |||
209 | max8907->i2c_gen = i2c; | ||
210 | i2c_set_clientdata(i2c, max8907); | ||
211 | max8907->regmap_gen = devm_regmap_init_i2c(i2c, | ||
212 | &max8907_regmap_gen_config); | ||
213 | if (IS_ERR(max8907->regmap_gen)) { | ||
214 | ret = PTR_ERR(max8907->regmap_gen); | ||
215 | dev_err(&i2c->dev, "gen regmap init failed: %d\n", ret); | ||
216 | goto err_regmap_gen; | ||
217 | } | ||
218 | |||
219 | max8907->i2c_rtc = i2c_new_dummy(i2c->adapter, MAX8907_RTC_I2C_ADDR); | ||
220 | if (!max8907->i2c_rtc) { | ||
221 | ret = -ENOMEM; | ||
222 | goto err_dummy_rtc; | ||
223 | } | ||
224 | i2c_set_clientdata(max8907->i2c_rtc, max8907); | ||
225 | max8907->regmap_rtc = devm_regmap_init_i2c(max8907->i2c_rtc, | ||
226 | &max8907_regmap_rtc_config); | ||
227 | if (IS_ERR(max8907->regmap_rtc)) { | ||
228 | ret = PTR_ERR(max8907->regmap_rtc); | ||
229 | dev_err(&i2c->dev, "rtc regmap init failed: %d\n", ret); | ||
230 | goto err_regmap_rtc; | ||
231 | } | ||
232 | |||
233 | irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN); | ||
234 | |||
235 | ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, | ||
236 | IRQF_ONESHOT | IRQF_SHARED, -1, | ||
237 | &max8907_chg_irq_chip, | ||
238 | &max8907->irqc_chg); | ||
239 | if (ret != 0) { | ||
240 | dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret); | ||
241 | goto err_irqc_chg; | ||
242 | } | ||
243 | ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, | ||
244 | IRQF_ONESHOT | IRQF_SHARED, -1, | ||
245 | &max8907_on_off_irq_chip, | ||
246 | &max8907->irqc_on_off); | ||
247 | if (ret != 0) { | ||
248 | dev_err(&i2c->dev, "failed to add on off irq chip: %d\n", ret); | ||
249 | goto err_irqc_on_off; | ||
250 | } | ||
251 | ret = regmap_add_irq_chip(max8907->regmap_rtc, max8907->i2c_gen->irq, | ||
252 | IRQF_ONESHOT | IRQF_SHARED, -1, | ||
253 | &max8907_rtc_irq_chip, | ||
254 | &max8907->irqc_rtc); | ||
255 | if (ret != 0) { | ||
256 | dev_err(&i2c->dev, "failed to add rtc irq chip: %d\n", ret); | ||
257 | goto err_irqc_rtc; | ||
258 | } | ||
259 | |||
260 | enable_irq(max8907->i2c_gen->irq); | ||
261 | |||
262 | ret = mfd_add_devices(max8907->dev, -1, max8907_cells, | ||
263 | ARRAY_SIZE(max8907_cells), NULL, 0, NULL); | ||
264 | if (ret != 0) { | ||
265 | dev_err(&i2c->dev, "failed to add MFD devices %d\n", ret); | ||
266 | goto err_add_devices; | ||
267 | } | ||
268 | |||
269 | if (pm_off && !pm_power_off) { | ||
270 | max8907_pm_off = max8907; | ||
271 | pm_power_off = max8907_power_off; | ||
272 | } | ||
273 | |||
274 | return 0; | ||
275 | |||
276 | err_add_devices: | ||
277 | regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); | ||
278 | err_irqc_rtc: | ||
279 | regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); | ||
280 | err_irqc_on_off: | ||
281 | regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); | ||
282 | err_irqc_chg: | ||
283 | err_regmap_rtc: | ||
284 | i2c_unregister_device(max8907->i2c_rtc); | ||
285 | err_dummy_rtc: | ||
286 | err_regmap_gen: | ||
287 | err_alloc_drvdata: | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | static __devexit int max8907_i2c_remove(struct i2c_client *i2c) | ||
292 | { | ||
293 | struct max8907 *max8907 = i2c_get_clientdata(i2c); | ||
294 | |||
295 | mfd_remove_devices(max8907->dev); | ||
296 | |||
297 | regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); | ||
298 | regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); | ||
299 | regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); | ||
300 | |||
301 | i2c_unregister_device(max8907->i2c_rtc); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | #ifdef CONFIG_OF | ||
307 | static struct of_device_id max8907_of_match[] = { | ||
308 | { .compatible = "maxim,max8907" }, | ||
309 | { }, | ||
310 | }; | ||
311 | MODULE_DEVICE_TABLE(of, max8907_of_match); | ||
312 | #endif | ||
313 | |||
314 | static const struct i2c_device_id max8907_i2c_id[] = { | ||
315 | {"max8907", 0}, | ||
316 | {} | ||
317 | }; | ||
318 | MODULE_DEVICE_TABLE(i2c, max8907_i2c_id); | ||
319 | |||
320 | static struct i2c_driver max8907_i2c_driver = { | ||
321 | .driver = { | ||
322 | .name = "max8907", | ||
323 | .owner = THIS_MODULE, | ||
324 | .of_match_table = of_match_ptr(max8907_of_match), | ||
325 | }, | ||
326 | .probe = max8907_i2c_probe, | ||
327 | .remove = max8907_i2c_remove, | ||
328 | .id_table = max8907_i2c_id, | ||
329 | }; | ||
330 | |||
331 | static int __init max8907_i2c_init(void) | ||
332 | { | ||
333 | int ret = -ENODEV; | ||
334 | |||
335 | ret = i2c_add_driver(&max8907_i2c_driver); | ||
336 | if (ret != 0) | ||
337 | pr_err("Failed to register I2C driver: %d\n", ret); | ||
338 | |||
339 | return ret; | ||
340 | } | ||
341 | subsys_initcall(max8907_i2c_init); | ||
342 | |||
343 | static void __exit max8907_i2c_exit(void) | ||
344 | { | ||
345 | i2c_del_driver(&max8907_i2c_driver); | ||
346 | } | ||
347 | module_exit(max8907_i2c_exit); | ||
348 | |||
349 | MODULE_DESCRIPTION("MAX8907 multi-function core driver"); | ||
350 | MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); | ||
351 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index ee53757beca7..9f54c04912f2 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c | |||
@@ -15,23 +15,20 @@ | |||
15 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/regulator/machine.h> | ||
18 | #include <linux/mfd/core.h> | 19 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/max8925.h> | 20 | #include <linux/mfd/max8925.h> |
20 | 21 | ||
21 | static struct resource backlight_resources[] = { | 22 | static struct resource bk_resources[] __devinitdata = { |
22 | { | 23 | { 0x84, 0x84, "mode control", IORESOURCE_REG, }, |
23 | .name = "max8925-backlight", | 24 | { 0x85, 0x85, "control", IORESOURCE_REG, }, |
24 | .start = MAX8925_WLED_MODE_CNTL, | ||
25 | .end = MAX8925_WLED_CNTL, | ||
26 | .flags = IORESOURCE_IO, | ||
27 | }, | ||
28 | }; | 25 | }; |
29 | 26 | ||
30 | static struct mfd_cell backlight_devs[] = { | 27 | static struct mfd_cell bk_devs[] __devinitdata = { |
31 | { | 28 | { |
32 | .name = "max8925-backlight", | 29 | .name = "max8925-backlight", |
33 | .num_resources = 1, | 30 | .num_resources = ARRAY_SIZE(bk_resources), |
34 | .resources = &backlight_resources[0], | 31 | .resources = &bk_resources[0], |
35 | .id = -1, | 32 | .id = -1, |
36 | }, | 33 | }, |
37 | }; | 34 | }; |
@@ -41,7 +38,7 @@ static struct resource touch_resources[] = { | |||
41 | .name = "max8925-tsc", | 38 | .name = "max8925-tsc", |
42 | .start = MAX8925_TSC_IRQ, | 39 | .start = MAX8925_TSC_IRQ, |
43 | .end = MAX8925_ADC_RES_END, | 40 | .end = MAX8925_ADC_RES_END, |
44 | .flags = IORESOURCE_IO, | 41 | .flags = IORESOURCE_REG, |
45 | }, | 42 | }, |
46 | }; | 43 | }; |
47 | 44 | ||
@@ -59,7 +56,7 @@ static struct resource power_supply_resources[] = { | |||
59 | .name = "max8925-power", | 56 | .name = "max8925-power", |
60 | .start = MAX8925_CHG_IRQ1, | 57 | .start = MAX8925_CHG_IRQ1, |
61 | .end = MAX8925_CHG_IRQ1_MASK, | 58 | .end = MAX8925_CHG_IRQ1_MASK, |
62 | .flags = IORESOURCE_IO, | 59 | .flags = IORESOURCE_REG, |
63 | }, | 60 | }, |
64 | }; | 61 | }; |
65 | 62 | ||
@@ -113,71 +110,215 @@ static struct mfd_cell onkey_devs[] = { | |||
113 | }, | 110 | }, |
114 | }; | 111 | }; |
115 | 112 | ||
116 | #define MAX8925_REG_RESOURCE(_start, _end) \ | 113 | static struct resource sd1_resources[] __devinitdata = { |
117 | { \ | 114 | {0x06, 0x06, "sdv", IORESOURCE_REG, }, |
118 | .start = MAX8925_##_start, \ | 115 | }; |
119 | .end = MAX8925_##_end, \ | ||
120 | .flags = IORESOURCE_IO, \ | ||
121 | } | ||
122 | 116 | ||
123 | static struct resource regulator_resources[] = { | 117 | static struct resource sd2_resources[] __devinitdata = { |
124 | MAX8925_REG_RESOURCE(SDCTL1, SDCTL1), | 118 | {0x09, 0x09, "sdv", IORESOURCE_REG, }, |
125 | MAX8925_REG_RESOURCE(SDCTL2, SDCTL2), | 119 | }; |
126 | MAX8925_REG_RESOURCE(SDCTL3, SDCTL3), | 120 | |
127 | MAX8925_REG_RESOURCE(LDOCTL1, LDOCTL1), | 121 | static struct resource sd3_resources[] __devinitdata = { |
128 | MAX8925_REG_RESOURCE(LDOCTL2, LDOCTL2), | 122 | {0x0c, 0x0c, "sdv", IORESOURCE_REG, }, |
129 | MAX8925_REG_RESOURCE(LDOCTL3, LDOCTL3), | 123 | }; |
130 | MAX8925_REG_RESOURCE(LDOCTL4, LDOCTL4), | 124 | |
131 | MAX8925_REG_RESOURCE(LDOCTL5, LDOCTL5), | 125 | static struct resource ldo1_resources[] __devinitdata = { |
132 | MAX8925_REG_RESOURCE(LDOCTL6, LDOCTL6), | 126 | {0x1a, 0x1a, "ldov", IORESOURCE_REG, }, |
133 | MAX8925_REG_RESOURCE(LDOCTL7, LDOCTL7), | 127 | }; |
134 | MAX8925_REG_RESOURCE(LDOCTL8, LDOCTL8), | 128 | |
135 | MAX8925_REG_RESOURCE(LDOCTL9, LDOCTL9), | 129 | static struct resource ldo2_resources[] __devinitdata = { |
136 | MAX8925_REG_RESOURCE(LDOCTL10, LDOCTL10), | 130 | {0x1e, 0x1e, "ldov", IORESOURCE_REG, }, |
137 | MAX8925_REG_RESOURCE(LDOCTL11, LDOCTL11), | 131 | }; |
138 | MAX8925_REG_RESOURCE(LDOCTL12, LDOCTL12), | 132 | |
139 | MAX8925_REG_RESOURCE(LDOCTL13, LDOCTL13), | 133 | static struct resource ldo3_resources[] __devinitdata = { |
140 | MAX8925_REG_RESOURCE(LDOCTL14, LDOCTL14), | 134 | {0x22, 0x22, "ldov", IORESOURCE_REG, }, |
141 | MAX8925_REG_RESOURCE(LDOCTL15, LDOCTL15), | 135 | }; |
142 | MAX8925_REG_RESOURCE(LDOCTL16, LDOCTL16), | 136 | |
143 | MAX8925_REG_RESOURCE(LDOCTL17, LDOCTL17), | 137 | static struct resource ldo4_resources[] __devinitdata = { |
144 | MAX8925_REG_RESOURCE(LDOCTL18, LDOCTL18), | 138 | {0x26, 0x26, "ldov", IORESOURCE_REG, }, |
145 | MAX8925_REG_RESOURCE(LDOCTL19, LDOCTL19), | 139 | }; |
146 | MAX8925_REG_RESOURCE(LDOCTL20, LDOCTL20), | 140 | |
147 | }; | 141 | static struct resource ldo5_resources[] __devinitdata = { |
148 | 142 | {0x2a, 0x2a, "ldov", IORESOURCE_REG, }, | |
149 | #define MAX8925_REG_DEVS(_id) \ | 143 | }; |
150 | { \ | 144 | |
151 | .name = "max8925-regulator", \ | 145 | static struct resource ldo6_resources[] __devinitdata = { |
152 | .num_resources = 1, \ | 146 | {0x2e, 0x2e, "ldov", IORESOURCE_REG, }, |
153 | .resources = ®ulator_resources[MAX8925_ID_##_id], \ | 147 | }; |
154 | .id = MAX8925_ID_##_id, \ | 148 | |
155 | } | 149 | static struct resource ldo7_resources[] __devinitdata = { |
150 | {0x32, 0x32, "ldov", IORESOURCE_REG, }, | ||
151 | }; | ||
152 | |||
153 | static struct resource ldo8_resources[] __devinitdata = { | ||
154 | {0x36, 0x36, "ldov", IORESOURCE_REG, }, | ||
155 | }; | ||
156 | |||
157 | static struct resource ldo9_resources[] __devinitdata = { | ||
158 | {0x3a, 0x3a, "ldov", IORESOURCE_REG, }, | ||
159 | }; | ||
160 | |||
161 | static struct resource ldo10_resources[] __devinitdata = { | ||
162 | {0x3e, 0x3e, "ldov", IORESOURCE_REG, }, | ||
163 | }; | ||
156 | 164 | ||
157 | static struct mfd_cell regulator_devs[] = { | 165 | static struct resource ldo11_resources[] __devinitdata = { |
158 | MAX8925_REG_DEVS(SD1), | 166 | {0x42, 0x42, "ldov", IORESOURCE_REG, }, |
159 | MAX8925_REG_DEVS(SD2), | 167 | }; |
160 | MAX8925_REG_DEVS(SD3), | 168 | |
161 | MAX8925_REG_DEVS(LDO1), | 169 | static struct resource ldo12_resources[] __devinitdata = { |
162 | MAX8925_REG_DEVS(LDO2), | 170 | {0x46, 0x46, "ldov", IORESOURCE_REG, }, |
163 | MAX8925_REG_DEVS(LDO3), | 171 | }; |
164 | MAX8925_REG_DEVS(LDO4), | 172 | |
165 | MAX8925_REG_DEVS(LDO5), | 173 | static struct resource ldo13_resources[] __devinitdata = { |
166 | MAX8925_REG_DEVS(LDO6), | 174 | {0x4a, 0x4a, "ldov", IORESOURCE_REG, }, |
167 | MAX8925_REG_DEVS(LDO7), | 175 | }; |
168 | MAX8925_REG_DEVS(LDO8), | 176 | |
169 | MAX8925_REG_DEVS(LDO9), | 177 | static struct resource ldo14_resources[] __devinitdata = { |
170 | MAX8925_REG_DEVS(LDO10), | 178 | {0x4e, 0x4e, "ldov", IORESOURCE_REG, }, |
171 | MAX8925_REG_DEVS(LDO11), | 179 | }; |
172 | MAX8925_REG_DEVS(LDO12), | 180 | |
173 | MAX8925_REG_DEVS(LDO13), | 181 | static struct resource ldo15_resources[] __devinitdata = { |
174 | MAX8925_REG_DEVS(LDO14), | 182 | {0x52, 0x52, "ldov", IORESOURCE_REG, }, |
175 | MAX8925_REG_DEVS(LDO15), | 183 | }; |
176 | MAX8925_REG_DEVS(LDO16), | 184 | |
177 | MAX8925_REG_DEVS(LDO17), | 185 | static struct resource ldo16_resources[] __devinitdata = { |
178 | MAX8925_REG_DEVS(LDO18), | 186 | {0x12, 0x12, "ldov", IORESOURCE_REG, }, |
179 | MAX8925_REG_DEVS(LDO19), | 187 | }; |
180 | MAX8925_REG_DEVS(LDO20), | 188 | |
189 | static struct resource ldo17_resources[] __devinitdata = { | ||
190 | {0x16, 0x16, "ldov", IORESOURCE_REG, }, | ||
191 | }; | ||
192 | |||
193 | static struct resource ldo18_resources[] __devinitdata = { | ||
194 | {0x74, 0x74, "ldov", IORESOURCE_REG, }, | ||
195 | }; | ||
196 | |||
197 | static struct resource ldo19_resources[] __devinitdata = { | ||
198 | {0x5e, 0x5e, "ldov", IORESOURCE_REG, }, | ||
199 | }; | ||
200 | |||
201 | static struct resource ldo20_resources[] __devinitdata = { | ||
202 | {0x9e, 0x9e, "ldov", IORESOURCE_REG, }, | ||
203 | }; | ||
204 | |||
205 | static struct mfd_cell reg_devs[] __devinitdata = { | ||
206 | { | ||
207 | .name = "max8925-regulator", | ||
208 | .id = 0, | ||
209 | .num_resources = ARRAY_SIZE(sd1_resources), | ||
210 | .resources = sd1_resources, | ||
211 | }, { | ||
212 | .name = "max8925-regulator", | ||
213 | .id = 1, | ||
214 | .num_resources = ARRAY_SIZE(sd2_resources), | ||
215 | .resources = sd2_resources, | ||
216 | }, { | ||
217 | .name = "max8925-regulator", | ||
218 | .id = 2, | ||
219 | .num_resources = ARRAY_SIZE(sd3_resources), | ||
220 | .resources = sd3_resources, | ||
221 | }, { | ||
222 | .name = "max8925-regulator", | ||
223 | .id = 3, | ||
224 | .num_resources = ARRAY_SIZE(ldo1_resources), | ||
225 | .resources = ldo1_resources, | ||
226 | }, { | ||
227 | .name = "max8925-regulator", | ||
228 | .id = 4, | ||
229 | .num_resources = ARRAY_SIZE(ldo2_resources), | ||
230 | .resources = ldo2_resources, | ||
231 | }, { | ||
232 | .name = "max8925-regulator", | ||
233 | .id = 5, | ||
234 | .num_resources = ARRAY_SIZE(ldo3_resources), | ||
235 | .resources = ldo3_resources, | ||
236 | }, { | ||
237 | .name = "max8925-regulator", | ||
238 | .id = 6, | ||
239 | .num_resources = ARRAY_SIZE(ldo4_resources), | ||
240 | .resources = ldo4_resources, | ||
241 | }, { | ||
242 | .name = "max8925-regulator", | ||
243 | .id = 7, | ||
244 | .num_resources = ARRAY_SIZE(ldo5_resources), | ||
245 | .resources = ldo5_resources, | ||
246 | }, { | ||
247 | .name = "max8925-regulator", | ||
248 | .id = 8, | ||
249 | .num_resources = ARRAY_SIZE(ldo6_resources), | ||
250 | .resources = ldo6_resources, | ||
251 | }, { | ||
252 | .name = "max8925-regulator", | ||
253 | .id = 9, | ||
254 | .num_resources = ARRAY_SIZE(ldo7_resources), | ||
255 | .resources = ldo7_resources, | ||
256 | }, { | ||
257 | .name = "max8925-regulator", | ||
258 | .id = 10, | ||
259 | .num_resources = ARRAY_SIZE(ldo8_resources), | ||
260 | .resources = ldo8_resources, | ||
261 | }, { | ||
262 | .name = "max8925-regulator", | ||
263 | .id = 11, | ||
264 | .num_resources = ARRAY_SIZE(ldo9_resources), | ||
265 | .resources = ldo9_resources, | ||
266 | }, { | ||
267 | .name = "max8925-regulator", | ||
268 | .id = 12, | ||
269 | .num_resources = ARRAY_SIZE(ldo10_resources), | ||
270 | .resources = ldo10_resources, | ||
271 | }, { | ||
272 | .name = "max8925-regulator", | ||
273 | .id = 13, | ||
274 | .num_resources = ARRAY_SIZE(ldo11_resources), | ||
275 | .resources = ldo11_resources, | ||
276 | }, { | ||
277 | .name = "max8925-regulator", | ||
278 | .id = 14, | ||
279 | .num_resources = ARRAY_SIZE(ldo12_resources), | ||
280 | .resources = ldo12_resources, | ||
281 | }, { | ||
282 | .name = "max8925-regulator", | ||
283 | .id = 15, | ||
284 | .num_resources = ARRAY_SIZE(ldo13_resources), | ||
285 | .resources = ldo13_resources, | ||
286 | }, { | ||
287 | .name = "max8925-regulator", | ||
288 | .id = 16, | ||
289 | .num_resources = ARRAY_SIZE(ldo14_resources), | ||
290 | .resources = ldo14_resources, | ||
291 | }, { | ||
292 | .name = "max8925-regulator", | ||
293 | .id = 17, | ||
294 | .num_resources = ARRAY_SIZE(ldo15_resources), | ||
295 | .resources = ldo15_resources, | ||
296 | }, { | ||
297 | .name = "max8925-regulator", | ||
298 | .id = 18, | ||
299 | .num_resources = ARRAY_SIZE(ldo16_resources), | ||
300 | .resources = ldo16_resources, | ||
301 | }, { | ||
302 | .name = "max8925-regulator", | ||
303 | .id = 19, | ||
304 | .num_resources = ARRAY_SIZE(ldo17_resources), | ||
305 | .resources = ldo17_resources, | ||
306 | }, { | ||
307 | .name = "max8925-regulator", | ||
308 | .id = 20, | ||
309 | .num_resources = ARRAY_SIZE(ldo18_resources), | ||
310 | .resources = ldo18_resources, | ||
311 | }, { | ||
312 | .name = "max8925-regulator", | ||
313 | .id = 21, | ||
314 | .num_resources = ARRAY_SIZE(ldo19_resources), | ||
315 | .resources = ldo19_resources, | ||
316 | }, { | ||
317 | .name = "max8925-regulator", | ||
318 | .id = 22, | ||
319 | .num_resources = ARRAY_SIZE(ldo20_resources), | ||
320 | .resources = ldo20_resources, | ||
321 | }, | ||
181 | }; | 322 | }; |
182 | 323 | ||
183 | enum { | 324 | enum { |
@@ -547,7 +688,7 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, | |||
547 | goto tsc_irq; | 688 | goto tsc_irq; |
548 | } | 689 | } |
549 | 690 | ||
550 | ret = request_threaded_irq(irq, NULL, max8925_irq, flags, | 691 | ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT, |
551 | "max8925", chip); | 692 | "max8925", chip); |
552 | if (ret) { | 693 | if (ret) { |
553 | dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); | 694 | dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); |
@@ -565,7 +706,7 @@ tsc_irq: | |||
565 | chip->tsc_irq = pdata->tsc_irq; | 706 | chip->tsc_irq = pdata->tsc_irq; |
566 | 707 | ||
567 | ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq, | 708 | ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq, |
568 | flags, "max8925-tsc", chip); | 709 | flags | IRQF_ONESHOT, "max8925-tsc", chip); |
569 | if (ret) { | 710 | if (ret) { |
570 | dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret); | 711 | dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret); |
571 | chip->tsc_irq = 0; | 712 | chip->tsc_irq = 0; |
@@ -573,6 +714,113 @@ tsc_irq: | |||
573 | return 0; | 714 | return 0; |
574 | } | 715 | } |
575 | 716 | ||
717 | static void __devinit init_regulator(struct max8925_chip *chip, | ||
718 | struct max8925_platform_data *pdata) | ||
719 | { | ||
720 | int ret; | ||
721 | |||
722 | if (!pdata) | ||
723 | return; | ||
724 | if (pdata->sd1) { | ||
725 | reg_devs[0].platform_data = pdata->sd1; | ||
726 | reg_devs[0].pdata_size = sizeof(struct regulator_init_data); | ||
727 | } | ||
728 | if (pdata->sd2) { | ||
729 | reg_devs[1].platform_data = pdata->sd2; | ||
730 | reg_devs[1].pdata_size = sizeof(struct regulator_init_data); | ||
731 | } | ||
732 | if (pdata->sd3) { | ||
733 | reg_devs[2].platform_data = pdata->sd3; | ||
734 | reg_devs[2].pdata_size = sizeof(struct regulator_init_data); | ||
735 | } | ||
736 | if (pdata->ldo1) { | ||
737 | reg_devs[3].platform_data = pdata->ldo1; | ||
738 | reg_devs[3].pdata_size = sizeof(struct regulator_init_data); | ||
739 | } | ||
740 | if (pdata->ldo2) { | ||
741 | reg_devs[4].platform_data = pdata->ldo2; | ||
742 | reg_devs[4].pdata_size = sizeof(struct regulator_init_data); | ||
743 | } | ||
744 | if (pdata->ldo3) { | ||
745 | reg_devs[5].platform_data = pdata->ldo3; | ||
746 | reg_devs[5].pdata_size = sizeof(struct regulator_init_data); | ||
747 | } | ||
748 | if (pdata->ldo4) { | ||
749 | reg_devs[6].platform_data = pdata->ldo4; | ||
750 | reg_devs[6].pdata_size = sizeof(struct regulator_init_data); | ||
751 | } | ||
752 | if (pdata->ldo5) { | ||
753 | reg_devs[7].platform_data = pdata->ldo5; | ||
754 | reg_devs[7].pdata_size = sizeof(struct regulator_init_data); | ||
755 | } | ||
756 | if (pdata->ldo6) { | ||
757 | reg_devs[8].platform_data = pdata->ldo6; | ||
758 | reg_devs[8].pdata_size = sizeof(struct regulator_init_data); | ||
759 | } | ||
760 | if (pdata->ldo7) { | ||
761 | reg_devs[9].platform_data = pdata->ldo7; | ||
762 | reg_devs[9].pdata_size = sizeof(struct regulator_init_data); | ||
763 | } | ||
764 | if (pdata->ldo8) { | ||
765 | reg_devs[10].platform_data = pdata->ldo8; | ||
766 | reg_devs[10].pdata_size = sizeof(struct regulator_init_data); | ||
767 | } | ||
768 | if (pdata->ldo9) { | ||
769 | reg_devs[11].platform_data = pdata->ldo9; | ||
770 | reg_devs[11].pdata_size = sizeof(struct regulator_init_data); | ||
771 | } | ||
772 | if (pdata->ldo10) { | ||
773 | reg_devs[12].platform_data = pdata->ldo10; | ||
774 | reg_devs[12].pdata_size = sizeof(struct regulator_init_data); | ||
775 | } | ||
776 | if (pdata->ldo11) { | ||
777 | reg_devs[13].platform_data = pdata->ldo11; | ||
778 | reg_devs[13].pdata_size = sizeof(struct regulator_init_data); | ||
779 | } | ||
780 | if (pdata->ldo12) { | ||
781 | reg_devs[14].platform_data = pdata->ldo12; | ||
782 | reg_devs[14].pdata_size = sizeof(struct regulator_init_data); | ||
783 | } | ||
784 | if (pdata->ldo13) { | ||
785 | reg_devs[15].platform_data = pdata->ldo13; | ||
786 | reg_devs[15].pdata_size = sizeof(struct regulator_init_data); | ||
787 | } | ||
788 | if (pdata->ldo14) { | ||
789 | reg_devs[16].platform_data = pdata->ldo14; | ||
790 | reg_devs[16].pdata_size = sizeof(struct regulator_init_data); | ||
791 | } | ||
792 | if (pdata->ldo15) { | ||
793 | reg_devs[17].platform_data = pdata->ldo15; | ||
794 | reg_devs[17].pdata_size = sizeof(struct regulator_init_data); | ||
795 | } | ||
796 | if (pdata->ldo16) { | ||
797 | reg_devs[18].platform_data = pdata->ldo16; | ||
798 | reg_devs[18].pdata_size = sizeof(struct regulator_init_data); | ||
799 | } | ||
800 | if (pdata->ldo17) { | ||
801 | reg_devs[19].platform_data = pdata->ldo17; | ||
802 | reg_devs[19].pdata_size = sizeof(struct regulator_init_data); | ||
803 | } | ||
804 | if (pdata->ldo18) { | ||
805 | reg_devs[20].platform_data = pdata->ldo18; | ||
806 | reg_devs[20].pdata_size = sizeof(struct regulator_init_data); | ||
807 | } | ||
808 | if (pdata->ldo19) { | ||
809 | reg_devs[21].platform_data = pdata->ldo19; | ||
810 | reg_devs[21].pdata_size = sizeof(struct regulator_init_data); | ||
811 | } | ||
812 | if (pdata->ldo20) { | ||
813 | reg_devs[22].platform_data = pdata->ldo20; | ||
814 | reg_devs[22].pdata_size = sizeof(struct regulator_init_data); | ||
815 | } | ||
816 | ret = mfd_add_devices(chip->dev, 0, reg_devs, ARRAY_SIZE(reg_devs), | ||
817 | NULL, 0, NULL); | ||
818 | if (ret < 0) { | ||
819 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | ||
820 | return; | ||
821 | } | ||
822 | } | ||
823 | |||
576 | int __devinit max8925_device_init(struct max8925_chip *chip, | 824 | int __devinit max8925_device_init(struct max8925_chip *chip, |
577 | struct max8925_platform_data *pdata) | 825 | struct max8925_platform_data *pdata) |
578 | { | 826 | { |
@@ -612,24 +860,17 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
612 | goto out_dev; | 860 | goto out_dev; |
613 | } | 861 | } |
614 | 862 | ||
615 | if (pdata) { | 863 | init_regulator(chip, pdata); |
616 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], | ||
617 | ARRAY_SIZE(regulator_devs), | ||
618 | ®ulator_resources[0], 0, NULL); | ||
619 | if (ret < 0) { | ||
620 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | ||
621 | goto out_dev; | ||
622 | } | ||
623 | } | ||
624 | 864 | ||
625 | if (pdata && pdata->backlight) { | 865 | if (pdata && pdata->backlight) { |
626 | ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], | 866 | bk_devs[0].platform_data = &pdata->backlight; |
627 | ARRAY_SIZE(backlight_devs), | 867 | bk_devs[0].pdata_size = sizeof(struct max8925_backlight_pdata); |
628 | &backlight_resources[0], 0, NULL); | 868 | } |
629 | if (ret < 0) { | 869 | ret = mfd_add_devices(chip->dev, 0, bk_devs, ARRAY_SIZE(bk_devs), |
630 | dev_err(chip->dev, "Failed to add backlight subdev\n"); | 870 | NULL, 0, NULL); |
631 | goto out_dev; | 871 | if (ret < 0) { |
632 | } | 872 | dev_err(chip->dev, "Failed to add backlight subdev\n"); |
873 | goto out_dev; | ||
633 | } | 874 | } |
634 | 875 | ||
635 | if (pdata && pdata->power) { | 876 | if (pdata && pdata->power) { |
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 1ec79b54bd2f..1aba0238f426 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c | |||
@@ -676,7 +676,6 @@ int mc13xxx_common_init(struct mc13xxx *mc13xxx, | |||
676 | err_mask: | 676 | err_mask: |
677 | err_revision: | 677 | err_revision: |
678 | mc13xxx_unlock(mc13xxx); | 678 | mc13xxx_unlock(mc13xxx); |
679 | kfree(mc13xxx); | ||
680 | return ret; | 679 | return ret; |
681 | } | 680 | } |
682 | 681 | ||
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 41088ecbb2a9..23cec57c02ba 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
26 | #include <linux/dma-mapping.h> | 25 | #include <linux/dma-mapping.h> |
27 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
@@ -36,63 +35,6 @@ | |||
36 | 35 | ||
37 | /* OMAP USBHOST Register addresses */ | 36 | /* OMAP USBHOST Register addresses */ |
38 | 37 | ||
39 | /* TLL Register Set */ | ||
40 | #define OMAP_USBTLL_REVISION (0x00) | ||
41 | #define OMAP_USBTLL_SYSCONFIG (0x10) | ||
42 | #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) | ||
43 | #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) | ||
44 | #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
45 | #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) | ||
46 | #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) | ||
47 | |||
48 | #define OMAP_USBTLL_SYSSTATUS (0x14) | ||
49 | #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) | ||
50 | |||
51 | #define OMAP_USBTLL_IRQSTATUS (0x18) | ||
52 | #define OMAP_USBTLL_IRQENABLE (0x1C) | ||
53 | |||
54 | #define OMAP_TLL_SHARED_CONF (0x30) | ||
55 | #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) | ||
56 | #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) | ||
57 | #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) | ||
58 | #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) | ||
59 | #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) | ||
60 | |||
61 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) | ||
62 | #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 | ||
63 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) | ||
64 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) | ||
65 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) | ||
66 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) | ||
67 | #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) | ||
68 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) | ||
69 | |||
70 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 | ||
71 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 | ||
72 | #define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 | ||
73 | #define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 | ||
74 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 | ||
75 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 | ||
76 | #define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 | ||
77 | #define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 | ||
78 | #define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA | ||
79 | #define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB | ||
80 | |||
81 | #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) | ||
82 | #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) | ||
83 | #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) | ||
84 | #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) | ||
85 | #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) | ||
86 | #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) | ||
87 | #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) | ||
88 | #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) | ||
89 | #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) | ||
90 | |||
91 | #define OMAP_TLL_CHANNEL_COUNT 3 | ||
92 | #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) | ||
93 | #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) | ||
94 | #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) | ||
95 | |||
96 | /* UHH Register Set */ | 38 | /* UHH Register Set */ |
97 | #define OMAP_UHH_REVISION (0x00) | 39 | #define OMAP_UHH_REVISION (0x00) |
98 | #define OMAP_UHH_SYSCONFIG (0x10) | 40 | #define OMAP_UHH_SYSCONFIG (0x10) |
@@ -132,8 +74,6 @@ | |||
132 | #define OMAP4_P2_MODE_TLL (1 << 18) | 74 | #define OMAP4_P2_MODE_TLL (1 << 18) |
133 | #define OMAP4_P2_MODE_HSIC (3 << 18) | 75 | #define OMAP4_P2_MODE_HSIC (3 << 18) |
134 | 76 | ||
135 | #define OMAP_REV2_TLL_CHANNEL_COUNT 2 | ||
136 | |||
137 | #define OMAP_UHH_DEBUG_CSR (0x44) | 77 | #define OMAP_UHH_DEBUG_CSR (0x44) |
138 | 78 | ||
139 | /* Values of UHH_REVISION - Note: these are not given in the TRM */ | 79 | /* Values of UHH_REVISION - Note: these are not given in the TRM */ |
@@ -153,15 +93,12 @@ struct usbhs_hcd_omap { | |||
153 | struct clk *xclk60mhsp2_ck; | 93 | struct clk *xclk60mhsp2_ck; |
154 | struct clk *utmi_p1_fck; | 94 | struct clk *utmi_p1_fck; |
155 | struct clk *usbhost_p1_fck; | 95 | struct clk *usbhost_p1_fck; |
156 | struct clk *usbtll_p1_fck; | ||
157 | struct clk *utmi_p2_fck; | 96 | struct clk *utmi_p2_fck; |
158 | struct clk *usbhost_p2_fck; | 97 | struct clk *usbhost_p2_fck; |
159 | struct clk *usbtll_p2_fck; | ||
160 | struct clk *init_60m_fclk; | 98 | struct clk *init_60m_fclk; |
161 | struct clk *ehci_logic_fck; | 99 | struct clk *ehci_logic_fck; |
162 | 100 | ||
163 | void __iomem *uhh_base; | 101 | void __iomem *uhh_base; |
164 | void __iomem *tll_base; | ||
165 | 102 | ||
166 | struct usbhs_omap_platform_data platdata; | 103 | struct usbhs_omap_platform_data platdata; |
167 | 104 | ||
@@ -336,93 +273,6 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode) | |||
336 | } | 273 | } |
337 | } | 274 | } |
338 | 275 | ||
339 | /* | ||
340 | * convert the port-mode enum to a value we can use in the FSLSMODE | ||
341 | * field of USBTLL_CHANNEL_CONF | ||
342 | */ | ||
343 | static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | ||
344 | { | ||
345 | switch (mode) { | ||
346 | case OMAP_USBHS_PORT_MODE_UNUSED: | ||
347 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: | ||
348 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
349 | |||
350 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: | ||
351 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; | ||
352 | |||
353 | case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: | ||
354 | return OMAP_TLL_FSLSMODE_3PIN_PHY; | ||
355 | |||
356 | case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: | ||
357 | return OMAP_TLL_FSLSMODE_4PIN_PHY; | ||
358 | |||
359 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: | ||
360 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; | ||
361 | |||
362 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: | ||
363 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; | ||
364 | |||
365 | case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: | ||
366 | return OMAP_TLL_FSLSMODE_3PIN_TLL; | ||
367 | |||
368 | case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: | ||
369 | return OMAP_TLL_FSLSMODE_4PIN_TLL; | ||
370 | |||
371 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: | ||
372 | return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; | ||
373 | |||
374 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: | ||
375 | return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; | ||
376 | default: | ||
377 | pr_warning("Invalid port mode, using default\n"); | ||
378 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) | ||
383 | { | ||
384 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
385 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
386 | unsigned reg; | ||
387 | int i; | ||
388 | |||
389 | /* Program Common TLL register */ | ||
390 | reg = usbhs_read(omap->tll_base, OMAP_TLL_SHARED_CONF); | ||
391 | reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | ||
392 | | OMAP_TLL_SHARED_CONF_USB_DIVRATION); | ||
393 | reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; | ||
394 | reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; | ||
395 | |||
396 | usbhs_write(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); | ||
397 | |||
398 | /* Enable channels now */ | ||
399 | for (i = 0; i < tll_channel_count; i++) { | ||
400 | reg = usbhs_read(omap->tll_base, | ||
401 | OMAP_TLL_CHANNEL_CONF(i)); | ||
402 | |||
403 | if (is_ohci_port(pdata->port_mode[i])) { | ||
404 | reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) | ||
405 | << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; | ||
406 | reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; | ||
407 | } else if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_TLL) { | ||
408 | |||
409 | /* Disable AutoIdle, BitStuffing and use SDR Mode */ | ||
410 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | ||
411 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | ||
412 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); | ||
413 | |||
414 | } else | ||
415 | continue; | ||
416 | |||
417 | reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; | ||
418 | usbhs_write(omap->tll_base, | ||
419 | OMAP_TLL_CHANNEL_CONF(i), reg); | ||
420 | |||
421 | usbhs_writeb(omap->tll_base, | ||
422 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | static int usbhs_runtime_resume(struct device *dev) | 276 | static int usbhs_runtime_resume(struct device *dev) |
427 | { | 277 | { |
428 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 278 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
@@ -436,19 +286,17 @@ static int usbhs_runtime_resume(struct device *dev) | |||
436 | return -ENODEV; | 286 | return -ENODEV; |
437 | } | 287 | } |
438 | 288 | ||
289 | omap_tll_enable(); | ||
439 | spin_lock_irqsave(&omap->lock, flags); | 290 | spin_lock_irqsave(&omap->lock, flags); |
440 | 291 | ||
441 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) | 292 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) |
442 | clk_enable(omap->ehci_logic_fck); | 293 | clk_enable(omap->ehci_logic_fck); |
443 | 294 | ||
444 | if (is_ehci_tll_mode(pdata->port_mode[0])) { | 295 | if (is_ehci_tll_mode(pdata->port_mode[0])) |
445 | clk_enable(omap->usbhost_p1_fck); | 296 | clk_enable(omap->usbhost_p1_fck); |
446 | clk_enable(omap->usbtll_p1_fck); | 297 | if (is_ehci_tll_mode(pdata->port_mode[1])) |
447 | } | ||
448 | if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
449 | clk_enable(omap->usbhost_p2_fck); | 298 | clk_enable(omap->usbhost_p2_fck); |
450 | clk_enable(omap->usbtll_p2_fck); | 299 | |
451 | } | ||
452 | clk_enable(omap->utmi_p1_fck); | 300 | clk_enable(omap->utmi_p1_fck); |
453 | clk_enable(omap->utmi_p2_fck); | 301 | clk_enable(omap->utmi_p2_fck); |
454 | 302 | ||
@@ -472,14 +320,11 @@ static int usbhs_runtime_suspend(struct device *dev) | |||
472 | 320 | ||
473 | spin_lock_irqsave(&omap->lock, flags); | 321 | spin_lock_irqsave(&omap->lock, flags); |
474 | 322 | ||
475 | if (is_ehci_tll_mode(pdata->port_mode[0])) { | 323 | if (is_ehci_tll_mode(pdata->port_mode[0])) |
476 | clk_disable(omap->usbhost_p1_fck); | 324 | clk_disable(omap->usbhost_p1_fck); |
477 | clk_disable(omap->usbtll_p1_fck); | 325 | if (is_ehci_tll_mode(pdata->port_mode[1])) |
478 | } | ||
479 | if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
480 | clk_disable(omap->usbhost_p2_fck); | 326 | clk_disable(omap->usbhost_p2_fck); |
481 | clk_disable(omap->usbtll_p2_fck); | 327 | |
482 | } | ||
483 | clk_disable(omap->utmi_p2_fck); | 328 | clk_disable(omap->utmi_p2_fck); |
484 | clk_disable(omap->utmi_p1_fck); | 329 | clk_disable(omap->utmi_p1_fck); |
485 | 330 | ||
@@ -487,6 +332,7 @@ static int usbhs_runtime_suspend(struct device *dev) | |||
487 | clk_disable(omap->ehci_logic_fck); | 332 | clk_disable(omap->ehci_logic_fck); |
488 | 333 | ||
489 | spin_unlock_irqrestore(&omap->lock, flags); | 334 | spin_unlock_irqrestore(&omap->lock, flags); |
335 | omap_tll_disable(); | ||
490 | 336 | ||
491 | return 0; | 337 | return 0; |
492 | } | 338 | } |
@@ -500,8 +346,6 @@ static void omap_usbhs_init(struct device *dev) | |||
500 | 346 | ||
501 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | 347 | dev_dbg(dev, "starting TI HSUSB Controller\n"); |
502 | 348 | ||
503 | pm_runtime_get_sync(dev); | ||
504 | |||
505 | if (pdata->ehci_data->phy_reset) { | 349 | if (pdata->ehci_data->phy_reset) { |
506 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 350 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) |
507 | gpio_request_one(pdata->ehci_data->reset_gpio_port[0], | 351 | gpio_request_one(pdata->ehci_data->reset_gpio_port[0], |
@@ -515,6 +359,7 @@ static void omap_usbhs_init(struct device *dev) | |||
515 | udelay(10); | 359 | udelay(10); |
516 | } | 360 | } |
517 | 361 | ||
362 | pm_runtime_get_sync(dev); | ||
518 | spin_lock_irqsave(&omap->lock, flags); | 363 | spin_lock_irqsave(&omap->lock, flags); |
519 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | 364 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); |
520 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); | 365 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); |
@@ -580,22 +425,9 @@ static void omap_usbhs_init(struct device *dev) | |||
580 | usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); | 425 | usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); |
581 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | 426 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); |
582 | 427 | ||
583 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | ||
584 | is_ehci_tll_mode(pdata->port_mode[1]) || | ||
585 | is_ehci_tll_mode(pdata->port_mode[2]) || | ||
586 | (is_ohci_port(pdata->port_mode[0])) || | ||
587 | (is_ohci_port(pdata->port_mode[1])) || | ||
588 | (is_ohci_port(pdata->port_mode[2]))) { | ||
589 | |||
590 | /* Enable UTMI mode for required TLL channels */ | ||
591 | if (is_omap_usbhs_rev2(omap)) | ||
592 | usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); | ||
593 | else | ||
594 | usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); | ||
595 | } | ||
596 | |||
597 | spin_unlock_irqrestore(&omap->lock, flags); | 428 | spin_unlock_irqrestore(&omap->lock, flags); |
598 | 429 | ||
430 | pm_runtime_put_sync(dev); | ||
599 | if (pdata->ehci_data->phy_reset) { | 431 | if (pdata->ehci_data->phy_reset) { |
600 | /* Hold the PHY in RESET for enough time till | 432 | /* Hold the PHY in RESET for enough time till |
601 | * PHY is settled and ready | 433 | * PHY is settled and ready |
@@ -610,8 +442,6 @@ static void omap_usbhs_init(struct device *dev) | |||
610 | gpio_set_value_cansleep | 442 | gpio_set_value_cansleep |
611 | (pdata->ehci_data->reset_gpio_port[1], 1); | 443 | (pdata->ehci_data->reset_gpio_port[1], 1); |
612 | } | 444 | } |
613 | |||
614 | pm_runtime_put_sync(dev); | ||
615 | } | 445 | } |
616 | 446 | ||
617 | static void omap_usbhs_deinit(struct device *dev) | 447 | static void omap_usbhs_deinit(struct device *dev) |
@@ -714,32 +544,18 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) | |||
714 | goto err_xclk60mhsp2_ck; | 544 | goto err_xclk60mhsp2_ck; |
715 | } | 545 | } |
716 | 546 | ||
717 | omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); | ||
718 | if (IS_ERR(omap->usbtll_p1_fck)) { | ||
719 | ret = PTR_ERR(omap->usbtll_p1_fck); | ||
720 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
721 | goto err_usbhost_p1_fck; | ||
722 | } | ||
723 | |||
724 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); | 547 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); |
725 | if (IS_ERR(omap->usbhost_p2_fck)) { | 548 | if (IS_ERR(omap->usbhost_p2_fck)) { |
726 | ret = PTR_ERR(omap->usbhost_p2_fck); | 549 | ret = PTR_ERR(omap->usbhost_p2_fck); |
727 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); | 550 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); |
728 | goto err_usbtll_p1_fck; | 551 | goto err_usbhost_p1_fck; |
729 | } | ||
730 | |||
731 | omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); | ||
732 | if (IS_ERR(omap->usbtll_p2_fck)) { | ||
733 | ret = PTR_ERR(omap->usbtll_p2_fck); | ||
734 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
735 | goto err_usbhost_p2_fck; | ||
736 | } | 552 | } |
737 | 553 | ||
738 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); | 554 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); |
739 | if (IS_ERR(omap->init_60m_fclk)) { | 555 | if (IS_ERR(omap->init_60m_fclk)) { |
740 | ret = PTR_ERR(omap->init_60m_fclk); | 556 | ret = PTR_ERR(omap->init_60m_fclk); |
741 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); | 557 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); |
742 | goto err_usbtll_p2_fck; | 558 | goto err_usbhost_p2_fck; |
743 | } | 559 | } |
744 | 560 | ||
745 | if (is_ehci_phy_mode(pdata->port_mode[0])) { | 561 | if (is_ehci_phy_mode(pdata->port_mode[0])) { |
@@ -785,20 +601,6 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) | |||
785 | goto err_init_60m_fclk; | 601 | goto err_init_60m_fclk; |
786 | } | 602 | } |
787 | 603 | ||
788 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); | ||
789 | if (!res) { | ||
790 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
791 | ret = -ENODEV; | ||
792 | goto err_tll; | ||
793 | } | ||
794 | |||
795 | omap->tll_base = ioremap(res->start, resource_size(res)); | ||
796 | if (!omap->tll_base) { | ||
797 | dev_err(dev, "TLL ioremap failed\n"); | ||
798 | ret = -ENOMEM; | ||
799 | goto err_tll; | ||
800 | } | ||
801 | |||
802 | platform_set_drvdata(pdev, omap); | 604 | platform_set_drvdata(pdev, omap); |
803 | 605 | ||
804 | omap_usbhs_init(dev); | 606 | omap_usbhs_init(dev); |
@@ -812,23 +614,14 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) | |||
812 | 614 | ||
813 | err_alloc: | 615 | err_alloc: |
814 | omap_usbhs_deinit(&pdev->dev); | 616 | omap_usbhs_deinit(&pdev->dev); |
815 | iounmap(omap->tll_base); | ||
816 | |||
817 | err_tll: | ||
818 | iounmap(omap->uhh_base); | 617 | iounmap(omap->uhh_base); |
819 | 618 | ||
820 | err_init_60m_fclk: | 619 | err_init_60m_fclk: |
821 | clk_put(omap->init_60m_fclk); | 620 | clk_put(omap->init_60m_fclk); |
822 | 621 | ||
823 | err_usbtll_p2_fck: | ||
824 | clk_put(omap->usbtll_p2_fck); | ||
825 | |||
826 | err_usbhost_p2_fck: | 622 | err_usbhost_p2_fck: |
827 | clk_put(omap->usbhost_p2_fck); | 623 | clk_put(omap->usbhost_p2_fck); |
828 | 624 | ||
829 | err_usbtll_p1_fck: | ||
830 | clk_put(omap->usbtll_p1_fck); | ||
831 | |||
832 | err_usbhost_p1_fck: | 625 | err_usbhost_p1_fck: |
833 | clk_put(omap->usbhost_p1_fck); | 626 | clk_put(omap->usbhost_p1_fck); |
834 | 627 | ||
@@ -864,12 +657,9 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) | |||
864 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | 657 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); |
865 | 658 | ||
866 | omap_usbhs_deinit(&pdev->dev); | 659 | omap_usbhs_deinit(&pdev->dev); |
867 | iounmap(omap->tll_base); | ||
868 | iounmap(omap->uhh_base); | 660 | iounmap(omap->uhh_base); |
869 | clk_put(omap->init_60m_fclk); | 661 | clk_put(omap->init_60m_fclk); |
870 | clk_put(omap->usbtll_p2_fck); | ||
871 | clk_put(omap->usbhost_p2_fck); | 662 | clk_put(omap->usbhost_p2_fck); |
872 | clk_put(omap->usbtll_p1_fck); | ||
873 | clk_put(omap->usbhost_p1_fck); | 663 | clk_put(omap->usbhost_p1_fck); |
874 | clk_put(omap->xclk60mhsp2_ck); | 664 | clk_put(omap->xclk60mhsp2_ck); |
875 | clk_put(omap->utmi_p2_fck); | 665 | clk_put(omap->utmi_p2_fck); |
@@ -910,8 +700,10 @@ static int __init omap_usbhs_drvinit(void) | |||
910 | * init before ehci and ohci drivers; | 700 | * init before ehci and ohci drivers; |
911 | * The usbhs core driver should be initialized much before | 701 | * The usbhs core driver should be initialized much before |
912 | * the omap ehci and ohci probe functions are called. | 702 | * the omap ehci and ohci probe functions are called. |
703 | * This usbhs core driver should be initialized after | ||
704 | * usb tll driver | ||
913 | */ | 705 | */ |
914 | fs_initcall(omap_usbhs_drvinit); | 706 | fs_initcall_sync(omap_usbhs_drvinit); |
915 | 707 | ||
916 | static void __exit omap_usbhs_drvexit(void) | 708 | static void __exit omap_usbhs_drvexit(void) |
917 | { | 709 | { |
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c new file mode 100644 index 000000000000..4b7757b84301 --- /dev/null +++ b/drivers/mfd/omap-usb-tll.c | |||
@@ -0,0 +1,471 @@ | |||
1 | /** | ||
2 | * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * Author: Keshava Munegowda <keshava_mgowda@ti.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 version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <plat/usb.h> | ||
29 | #include <linux/pm_runtime.h> | ||
30 | |||
31 | #define USBTLL_DRIVER_NAME "usbhs_tll" | ||
32 | |||
33 | /* TLL Register Set */ | ||
34 | #define OMAP_USBTLL_REVISION (0x00) | ||
35 | #define OMAP_USBTLL_SYSCONFIG (0x10) | ||
36 | #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) | ||
37 | #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) | ||
38 | #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
39 | #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) | ||
40 | #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) | ||
41 | |||
42 | #define OMAP_USBTLL_SYSSTATUS (0x14) | ||
43 | #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) | ||
44 | |||
45 | #define OMAP_USBTLL_IRQSTATUS (0x18) | ||
46 | #define OMAP_USBTLL_IRQENABLE (0x1C) | ||
47 | |||
48 | #define OMAP_TLL_SHARED_CONF (0x30) | ||
49 | #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) | ||
50 | #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) | ||
51 | #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) | ||
52 | #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) | ||
53 | #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) | ||
54 | |||
55 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) | ||
56 | #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 | ||
57 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) | ||
58 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) | ||
59 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) | ||
60 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) | ||
61 | #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) | ||
62 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) | ||
63 | |||
64 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 | ||
65 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 | ||
66 | #define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 | ||
67 | #define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 | ||
68 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 | ||
69 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 | ||
70 | #define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 | ||
71 | #define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 | ||
72 | #define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA | ||
73 | #define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB | ||
74 | |||
75 | #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) | ||
76 | #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) | ||
77 | #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) | ||
78 | #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) | ||
79 | #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) | ||
80 | #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) | ||
81 | #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) | ||
82 | #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) | ||
83 | #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) | ||
84 | |||
85 | #define OMAP_REV2_TLL_CHANNEL_COUNT 2 | ||
86 | #define OMAP_TLL_CHANNEL_COUNT 3 | ||
87 | #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) | ||
88 | #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) | ||
89 | #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) | ||
90 | |||
91 | /* Values of USBTLL_REVISION - Note: these are not given in the TRM */ | ||
92 | #define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ | ||
93 | #define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ | ||
94 | #define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ | ||
95 | |||
96 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) | ||
97 | |||
98 | struct usbtll_omap { | ||
99 | struct clk *usbtll_p1_fck; | ||
100 | struct clk *usbtll_p2_fck; | ||
101 | struct usbtll_omap_platform_data platdata; | ||
102 | /* secure the register updates */ | ||
103 | spinlock_t lock; | ||
104 | }; | ||
105 | |||
106 | /*-------------------------------------------------------------------------*/ | ||
107 | |||
108 | const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; | ||
109 | struct platform_device *tll_pdev; | ||
110 | |||
111 | /*-------------------------------------------------------------------------*/ | ||
112 | |||
113 | static inline void usbtll_write(void __iomem *base, u32 reg, u32 val) | ||
114 | { | ||
115 | __raw_writel(val, base + reg); | ||
116 | } | ||
117 | |||
118 | static inline u32 usbtll_read(void __iomem *base, u32 reg) | ||
119 | { | ||
120 | return __raw_readl(base + reg); | ||
121 | } | ||
122 | |||
123 | static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val) | ||
124 | { | ||
125 | __raw_writeb(val, base + reg); | ||
126 | } | ||
127 | |||
128 | static inline u8 usbtll_readb(void __iomem *base, u8 reg) | ||
129 | { | ||
130 | return __raw_readb(base + reg); | ||
131 | } | ||
132 | |||
133 | /*-------------------------------------------------------------------------*/ | ||
134 | |||
135 | static bool is_ohci_port(enum usbhs_omap_port_mode pmode) | ||
136 | { | ||
137 | switch (pmode) { | ||
138 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: | ||
139 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: | ||
140 | case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: | ||
141 | case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: | ||
142 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: | ||
143 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: | ||
144 | case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: | ||
145 | case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: | ||
146 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: | ||
147 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: | ||
148 | return true; | ||
149 | |||
150 | default: | ||
151 | return false; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * convert the port-mode enum to a value we can use in the FSLSMODE | ||
157 | * field of USBTLL_CHANNEL_CONF | ||
158 | */ | ||
159 | static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | ||
160 | { | ||
161 | switch (mode) { | ||
162 | case OMAP_USBHS_PORT_MODE_UNUSED: | ||
163 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: | ||
164 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
165 | |||
166 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: | ||
167 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; | ||
168 | |||
169 | case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: | ||
170 | return OMAP_TLL_FSLSMODE_3PIN_PHY; | ||
171 | |||
172 | case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: | ||
173 | return OMAP_TLL_FSLSMODE_4PIN_PHY; | ||
174 | |||
175 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: | ||
176 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; | ||
177 | |||
178 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: | ||
179 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; | ||
180 | |||
181 | case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: | ||
182 | return OMAP_TLL_FSLSMODE_3PIN_TLL; | ||
183 | |||
184 | case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: | ||
185 | return OMAP_TLL_FSLSMODE_4PIN_TLL; | ||
186 | |||
187 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: | ||
188 | return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; | ||
189 | |||
190 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: | ||
191 | return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; | ||
192 | default: | ||
193 | pr_warn("Invalid port mode, using default\n"); | ||
194 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * usbtll_omap_probe - initialize TI-based HCDs | ||
200 | * | ||
201 | * Allocates basic resources for this USB host controller. | ||
202 | */ | ||
203 | static int __devinit usbtll_omap_probe(struct platform_device *pdev) | ||
204 | { | ||
205 | struct device *dev = &pdev->dev; | ||
206 | struct usbtll_omap_platform_data *pdata = dev->platform_data; | ||
207 | void __iomem *base; | ||
208 | struct resource *res; | ||
209 | struct usbtll_omap *tll; | ||
210 | unsigned reg; | ||
211 | unsigned long flags; | ||
212 | int ret = 0; | ||
213 | int i, ver, count; | ||
214 | |||
215 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); | ||
216 | |||
217 | tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL); | ||
218 | if (!tll) { | ||
219 | dev_err(dev, "Memory allocation failed\n"); | ||
220 | ret = -ENOMEM; | ||
221 | goto end; | ||
222 | } | ||
223 | |||
224 | spin_lock_init(&tll->lock); | ||
225 | |||
226 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) | ||
227 | tll->platdata.port_mode[i] = pdata->port_mode[i]; | ||
228 | |||
229 | tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); | ||
230 | if (IS_ERR(tll->usbtll_p1_fck)) { | ||
231 | ret = PTR_ERR(tll->usbtll_p1_fck); | ||
232 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
233 | goto err_tll; | ||
234 | } | ||
235 | |||
236 | tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); | ||
237 | if (IS_ERR(tll->usbtll_p2_fck)) { | ||
238 | ret = PTR_ERR(tll->usbtll_p2_fck); | ||
239 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
240 | goto err_usbtll_p1_fck; | ||
241 | } | ||
242 | |||
243 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
244 | if (!res) { | ||
245 | dev_err(dev, "usb tll get resource failed\n"); | ||
246 | ret = -ENODEV; | ||
247 | goto err_usbtll_p2_fck; | ||
248 | } | ||
249 | |||
250 | base = ioremap(res->start, resource_size(res)); | ||
251 | if (!base) { | ||
252 | dev_err(dev, "TLL ioremap failed\n"); | ||
253 | ret = -ENOMEM; | ||
254 | goto err_usbtll_p2_fck; | ||
255 | } | ||
256 | |||
257 | platform_set_drvdata(pdev, tll); | ||
258 | pm_runtime_enable(dev); | ||
259 | pm_runtime_get_sync(dev); | ||
260 | |||
261 | spin_lock_irqsave(&tll->lock, flags); | ||
262 | |||
263 | ver = usbtll_read(base, OMAP_USBTLL_REVISION); | ||
264 | switch (ver) { | ||
265 | case OMAP_USBTLL_REV1: | ||
266 | case OMAP_USBTLL_REV2: | ||
267 | count = OMAP_TLL_CHANNEL_COUNT; | ||
268 | break; | ||
269 | case OMAP_USBTLL_REV3: | ||
270 | count = OMAP_REV2_TLL_CHANNEL_COUNT; | ||
271 | break; | ||
272 | default: | ||
273 | dev_err(dev, "TLL version failed\n"); | ||
274 | ret = -ENODEV; | ||
275 | goto err_ioremap; | ||
276 | } | ||
277 | |||
278 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | ||
279 | is_ehci_tll_mode(pdata->port_mode[1]) || | ||
280 | is_ehci_tll_mode(pdata->port_mode[2]) || | ||
281 | is_ohci_port(pdata->port_mode[0]) || | ||
282 | is_ohci_port(pdata->port_mode[1]) || | ||
283 | is_ohci_port(pdata->port_mode[2])) { | ||
284 | |||
285 | /* Program Common TLL register */ | ||
286 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); | ||
287 | reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | ||
288 | | OMAP_TLL_SHARED_CONF_USB_DIVRATION); | ||
289 | reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; | ||
290 | reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; | ||
291 | |||
292 | usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); | ||
293 | |||
294 | /* Enable channels now */ | ||
295 | for (i = 0; i < count; i++) { | ||
296 | reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); | ||
297 | |||
298 | if (is_ohci_port(pdata->port_mode[i])) { | ||
299 | reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) | ||
300 | << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; | ||
301 | reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; | ||
302 | } else if (pdata->port_mode[i] == | ||
303 | OMAP_EHCI_PORT_MODE_TLL) { | ||
304 | /* | ||
305 | * Disable AutoIdle, BitStuffing | ||
306 | * and use SDR Mode | ||
307 | */ | ||
308 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | ||
309 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | ||
310 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); | ||
311 | } else { | ||
312 | continue; | ||
313 | } | ||
314 | reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; | ||
315 | usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg); | ||
316 | |||
317 | usbtll_writeb(base, | ||
318 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i), | ||
319 | 0xbe); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | err_ioremap: | ||
324 | spin_unlock_irqrestore(&tll->lock, flags); | ||
325 | iounmap(base); | ||
326 | pm_runtime_put_sync(dev); | ||
327 | tll_pdev = pdev; | ||
328 | if (!ret) | ||
329 | goto end; | ||
330 | pm_runtime_disable(dev); | ||
331 | |||
332 | err_usbtll_p2_fck: | ||
333 | clk_put(tll->usbtll_p2_fck); | ||
334 | |||
335 | err_usbtll_p1_fck: | ||
336 | clk_put(tll->usbtll_p1_fck); | ||
337 | |||
338 | err_tll: | ||
339 | kfree(tll); | ||
340 | |||
341 | end: | ||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | /** | ||
346 | * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs | ||
347 | * @pdev: USB Host Controller being removed | ||
348 | * | ||
349 | * Reverses the effect of usbtll_omap_probe(). | ||
350 | */ | ||
351 | static int __devexit usbtll_omap_remove(struct platform_device *pdev) | ||
352 | { | ||
353 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | ||
354 | |||
355 | clk_put(tll->usbtll_p2_fck); | ||
356 | clk_put(tll->usbtll_p1_fck); | ||
357 | pm_runtime_disable(&pdev->dev); | ||
358 | kfree(tll); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int usbtll_runtime_resume(struct device *dev) | ||
363 | { | ||
364 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
365 | struct usbtll_omap_platform_data *pdata = &tll->platdata; | ||
366 | unsigned long flags; | ||
367 | |||
368 | dev_dbg(dev, "usbtll_runtime_resume\n"); | ||
369 | |||
370 | if (!pdata) { | ||
371 | dev_dbg(dev, "missing platform_data\n"); | ||
372 | return -ENODEV; | ||
373 | } | ||
374 | |||
375 | spin_lock_irqsave(&tll->lock, flags); | ||
376 | |||
377 | if (is_ehci_tll_mode(pdata->port_mode[0])) | ||
378 | clk_enable(tll->usbtll_p1_fck); | ||
379 | |||
380 | if (is_ehci_tll_mode(pdata->port_mode[1])) | ||
381 | clk_enable(tll->usbtll_p2_fck); | ||
382 | |||
383 | spin_unlock_irqrestore(&tll->lock, flags); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int usbtll_runtime_suspend(struct device *dev) | ||
389 | { | ||
390 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
391 | struct usbtll_omap_platform_data *pdata = &tll->platdata; | ||
392 | unsigned long flags; | ||
393 | |||
394 | dev_dbg(dev, "usbtll_runtime_suspend\n"); | ||
395 | |||
396 | if (!pdata) { | ||
397 | dev_dbg(dev, "missing platform_data\n"); | ||
398 | return -ENODEV; | ||
399 | } | ||
400 | |||
401 | spin_lock_irqsave(&tll->lock, flags); | ||
402 | |||
403 | if (is_ehci_tll_mode(pdata->port_mode[0])) | ||
404 | clk_disable(tll->usbtll_p1_fck); | ||
405 | |||
406 | if (is_ehci_tll_mode(pdata->port_mode[1])) | ||
407 | clk_disable(tll->usbtll_p2_fck); | ||
408 | |||
409 | spin_unlock_irqrestore(&tll->lock, flags); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static const struct dev_pm_ops usbtllomap_dev_pm_ops = { | ||
415 | SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, | ||
416 | usbtll_runtime_resume, | ||
417 | NULL) | ||
418 | }; | ||
419 | |||
420 | static struct platform_driver usbtll_omap_driver = { | ||
421 | .driver = { | ||
422 | .name = (char *)usbtll_driver_name, | ||
423 | .owner = THIS_MODULE, | ||
424 | .pm = &usbtllomap_dev_pm_ops, | ||
425 | }, | ||
426 | .probe = usbtll_omap_probe, | ||
427 | .remove = __devexit_p(usbtll_omap_remove), | ||
428 | }; | ||
429 | |||
430 | int omap_tll_enable(void) | ||
431 | { | ||
432 | if (!tll_pdev) { | ||
433 | pr_err("missing omap usbhs tll platform_data\n"); | ||
434 | return -ENODEV; | ||
435 | } | ||
436 | return pm_runtime_get_sync(&tll_pdev->dev); | ||
437 | } | ||
438 | EXPORT_SYMBOL_GPL(omap_tll_enable); | ||
439 | |||
440 | int omap_tll_disable(void) | ||
441 | { | ||
442 | if (!tll_pdev) { | ||
443 | pr_err("missing omap usbhs tll platform_data\n"); | ||
444 | return -ENODEV; | ||
445 | } | ||
446 | return pm_runtime_put_sync(&tll_pdev->dev); | ||
447 | } | ||
448 | EXPORT_SYMBOL_GPL(omap_tll_disable); | ||
449 | |||
450 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | ||
451 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | ||
452 | MODULE_LICENSE("GPL v2"); | ||
453 | MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); | ||
454 | |||
455 | static int __init omap_usbtll_drvinit(void) | ||
456 | { | ||
457 | return platform_driver_register(&usbtll_omap_driver); | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * init before usbhs core driver; | ||
462 | * The usbtll driver should be initialized before | ||
463 | * the usbhs core driver probe function is called. | ||
464 | */ | ||
465 | fs_initcall(omap_usbtll_drvinit); | ||
466 | |||
467 | static void __exit omap_usbtll_drvexit(void) | ||
468 | { | ||
469 | platform_driver_unregister(&usbtll_omap_driver); | ||
470 | } | ||
471 | module_exit(omap_usbtll_drvexit); | ||
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index a345f9bb7b47..4f8d6e6b19aa 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c | |||
@@ -23,60 +23,7 @@ | |||
23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
24 | #include <linux/mfd/core.h> | 24 | #include <linux/mfd/core.h> |
25 | #include <linux/mfd/palmas.h> | 25 | #include <linux/mfd/palmas.h> |
26 | 26 | #include <linux/of_platform.h> | |
27 | static const struct resource gpadc_resource[] = { | ||
28 | { | ||
29 | .name = "EOC_SW", | ||
30 | .start = PALMAS_GPADC_EOC_SW_IRQ, | ||
31 | .end = PALMAS_GPADC_EOC_SW_IRQ, | ||
32 | .flags = IORESOURCE_IRQ, | ||
33 | } | ||
34 | }; | ||
35 | |||
36 | static const struct resource usb_resource[] = { | ||
37 | { | ||
38 | .name = "ID", | ||
39 | .start = PALMAS_ID_OTG_IRQ, | ||
40 | .end = PALMAS_ID_OTG_IRQ, | ||
41 | .flags = IORESOURCE_IRQ, | ||
42 | }, | ||
43 | { | ||
44 | .name = "ID_WAKEUP", | ||
45 | .start = PALMAS_ID_IRQ, | ||
46 | .end = PALMAS_ID_IRQ, | ||
47 | .flags = IORESOURCE_IRQ, | ||
48 | }, | ||
49 | { | ||
50 | .name = "VBUS", | ||
51 | .start = PALMAS_VBUS_OTG_IRQ, | ||
52 | .end = PALMAS_VBUS_OTG_IRQ, | ||
53 | .flags = IORESOURCE_IRQ, | ||
54 | }, | ||
55 | { | ||
56 | .name = "VBUS_WAKEUP", | ||
57 | .start = PALMAS_VBUS_IRQ, | ||
58 | .end = PALMAS_VBUS_IRQ, | ||
59 | .flags = IORESOURCE_IRQ, | ||
60 | }, | ||
61 | }; | ||
62 | |||
63 | static const struct resource rtc_resource[] = { | ||
64 | { | ||
65 | .name = "RTC_ALARM", | ||
66 | .start = PALMAS_RTC_ALARM_IRQ, | ||
67 | .end = PALMAS_RTC_ALARM_IRQ, | ||
68 | .flags = IORESOURCE_IRQ, | ||
69 | }, | ||
70 | }; | ||
71 | |||
72 | static const struct resource pwron_resource[] = { | ||
73 | { | ||
74 | .name = "PWRON_BUTTON", | ||
75 | .start = PALMAS_PWRON_IRQ, | ||
76 | .end = PALMAS_PWRON_IRQ, | ||
77 | .flags = IORESOURCE_IRQ, | ||
78 | }, | ||
79 | }; | ||
80 | 27 | ||
81 | enum palmas_ids { | 28 | enum palmas_ids { |
82 | PALMAS_PMIC_ID, | 29 | PALMAS_PMIC_ID, |
@@ -111,20 +58,14 @@ static const struct mfd_cell palmas_children[] = { | |||
111 | }, | 58 | }, |
112 | { | 59 | { |
113 | .name = "palmas-rtc", | 60 | .name = "palmas-rtc", |
114 | .num_resources = ARRAY_SIZE(rtc_resource), | ||
115 | .resources = rtc_resource, | ||
116 | .id = PALMAS_RTC_ID, | 61 | .id = PALMAS_RTC_ID, |
117 | }, | 62 | }, |
118 | { | 63 | { |
119 | .name = "palmas-pwrbutton", | 64 | .name = "palmas-pwrbutton", |
120 | .num_resources = ARRAY_SIZE(pwron_resource), | ||
121 | .resources = pwron_resource, | ||
122 | .id = PALMAS_PWRBUTTON_ID, | 65 | .id = PALMAS_PWRBUTTON_ID, |
123 | }, | 66 | }, |
124 | { | 67 | { |
125 | .name = "palmas-gpadc", | 68 | .name = "palmas-gpadc", |
126 | .num_resources = ARRAY_SIZE(gpadc_resource), | ||
127 | .resources = gpadc_resource, | ||
128 | .id = PALMAS_GPADC_ID, | 69 | .id = PALMAS_GPADC_ID, |
129 | }, | 70 | }, |
130 | { | 71 | { |
@@ -141,8 +82,6 @@ static const struct mfd_cell palmas_children[] = { | |||
141 | }, | 82 | }, |
142 | { | 83 | { |
143 | .name = "palmas-usb", | 84 | .name = "palmas-usb", |
144 | .num_resources = ARRAY_SIZE(usb_resource), | ||
145 | .resources = usb_resource, | ||
146 | .id = PALMAS_USB_ID, | 85 | .id = PALMAS_USB_ID, |
147 | } | 86 | } |
148 | }; | 87 | }; |
@@ -308,17 +247,56 @@ static struct regmap_irq_chip palmas_irq_chip = { | |||
308 | PALMAS_INT1_MASK), | 247 | PALMAS_INT1_MASK), |
309 | }; | 248 | }; |
310 | 249 | ||
250 | static void __devinit palmas_dt_to_pdata(struct device_node *node, | ||
251 | struct palmas_platform_data *pdata) | ||
252 | { | ||
253 | int ret; | ||
254 | u32 prop; | ||
255 | |||
256 | ret = of_property_read_u32(node, "ti,mux_pad1", &prop); | ||
257 | if (!ret) { | ||
258 | pdata->mux_from_pdata = 1; | ||
259 | pdata->pad1 = prop; | ||
260 | } | ||
261 | |||
262 | ret = of_property_read_u32(node, "ti,mux_pad2", &prop); | ||
263 | if (!ret) { | ||
264 | pdata->mux_from_pdata = 1; | ||
265 | pdata->pad2 = prop; | ||
266 | } | ||
267 | |||
268 | /* The default for this register is all masked */ | ||
269 | ret = of_property_read_u32(node, "ti,power_ctrl", &prop); | ||
270 | if (!ret) | ||
271 | pdata->power_ctrl = prop; | ||
272 | else | ||
273 | pdata->power_ctrl = PALMAS_POWER_CTRL_NSLEEP_MASK | | ||
274 | PALMAS_POWER_CTRL_ENABLE1_MASK | | ||
275 | PALMAS_POWER_CTRL_ENABLE2_MASK; | ||
276 | } | ||
277 | |||
311 | static int __devinit palmas_i2c_probe(struct i2c_client *i2c, | 278 | static int __devinit palmas_i2c_probe(struct i2c_client *i2c, |
312 | const struct i2c_device_id *id) | 279 | const struct i2c_device_id *id) |
313 | { | 280 | { |
314 | struct palmas *palmas; | 281 | struct palmas *palmas; |
315 | struct palmas_platform_data *pdata; | 282 | struct palmas_platform_data *pdata; |
283 | struct device_node *node = i2c->dev.of_node; | ||
316 | int ret = 0, i; | 284 | int ret = 0, i; |
317 | unsigned int reg, addr; | 285 | unsigned int reg, addr; |
318 | int slave; | 286 | int slave; |
319 | struct mfd_cell *children; | 287 | struct mfd_cell *children; |
320 | 288 | ||
321 | pdata = dev_get_platdata(&i2c->dev); | 289 | pdata = dev_get_platdata(&i2c->dev); |
290 | |||
291 | if (node && !pdata) { | ||
292 | pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); | ||
293 | |||
294 | if (!pdata) | ||
295 | return -ENOMEM; | ||
296 | |||
297 | palmas_dt_to_pdata(node, pdata); | ||
298 | } | ||
299 | |||
322 | if (!pdata) | 300 | if (!pdata) |
323 | return -EINVAL; | 301 | return -EINVAL; |
324 | 302 | ||
@@ -364,7 +342,7 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, | |||
364 | regmap_write(palmas->regmap[slave], addr, reg); | 342 | regmap_write(palmas->regmap[slave], addr, reg); |
365 | 343 | ||
366 | ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq, | 344 | ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq, |
367 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip, | 345 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, 0, &palmas_irq_chip, |
368 | &palmas->irq_data); | 346 | &palmas->irq_data); |
369 | if (ret < 0) | 347 | if (ret < 0) |
370 | goto err; | 348 | goto err; |
@@ -377,11 +355,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, | |||
377 | reg = pdata->pad1; | 355 | reg = pdata->pad1; |
378 | ret = regmap_write(palmas->regmap[slave], addr, reg); | 356 | ret = regmap_write(palmas->regmap[slave], addr, reg); |
379 | if (ret) | 357 | if (ret) |
380 | goto err; | 358 | goto err_irq; |
381 | } else { | 359 | } else { |
382 | ret = regmap_read(palmas->regmap[slave], addr, ®); | 360 | ret = regmap_read(palmas->regmap[slave], addr, ®); |
383 | if (ret) | 361 | if (ret) |
384 | goto err; | 362 | goto err_irq; |
385 | } | 363 | } |
386 | 364 | ||
387 | if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0)) | 365 | if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0)) |
@@ -412,11 +390,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, | |||
412 | reg = pdata->pad2; | 390 | reg = pdata->pad2; |
413 | ret = regmap_write(palmas->regmap[slave], addr, reg); | 391 | ret = regmap_write(palmas->regmap[slave], addr, reg); |
414 | if (ret) | 392 | if (ret) |
415 | goto err; | 393 | goto err_irq; |
416 | } else { | 394 | } else { |
417 | ret = regmap_read(palmas->regmap[slave], addr, ®); | 395 | ret = regmap_read(palmas->regmap[slave], addr, ®); |
418 | if (ret) | 396 | if (ret) |
419 | goto err; | 397 | goto err_irq; |
420 | } | 398 | } |
421 | 399 | ||
422 | if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4)) | 400 | if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4)) |
@@ -439,18 +417,43 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, | |||
439 | 417 | ||
440 | ret = regmap_write(palmas->regmap[slave], addr, reg); | 418 | ret = regmap_write(palmas->regmap[slave], addr, reg); |
441 | if (ret) | 419 | if (ret) |
442 | goto err; | 420 | goto err_irq; |
421 | |||
422 | /* | ||
423 | * If we are probing with DT do this the DT way and return here | ||
424 | * otherwise continue and add devices using mfd helpers. | ||
425 | */ | ||
426 | if (node) { | ||
427 | ret = of_platform_populate(node, NULL, NULL, &i2c->dev); | ||
428 | if (ret < 0) | ||
429 | goto err_irq; | ||
430 | else | ||
431 | return ret; | ||
432 | } | ||
443 | 433 | ||
444 | children = kmemdup(palmas_children, sizeof(palmas_children), | 434 | children = kmemdup(palmas_children, sizeof(palmas_children), |
445 | GFP_KERNEL); | 435 | GFP_KERNEL); |
446 | if (!children) { | 436 | if (!children) { |
447 | ret = -ENOMEM; | 437 | ret = -ENOMEM; |
448 | goto err; | 438 | goto err_irq; |
449 | } | 439 | } |
450 | 440 | ||
451 | children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata; | 441 | children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata; |
452 | children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata); | 442 | children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata); |
453 | 443 | ||
444 | children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata; | ||
445 | children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata); | ||
446 | |||
447 | children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata; | ||
448 | children[PALMAS_RESOURCE_ID].pdata_size = | ||
449 | sizeof(*pdata->resource_pdata); | ||
450 | |||
451 | children[PALMAS_USB_ID].platform_data = pdata->usb_pdata; | ||
452 | children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata); | ||
453 | |||
454 | children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata; | ||
455 | children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata); | ||
456 | |||
454 | ret = mfd_add_devices(palmas->dev, -1, | 457 | ret = mfd_add_devices(palmas->dev, -1, |
455 | children, ARRAY_SIZE(palmas_children), | 458 | children, ARRAY_SIZE(palmas_children), |
456 | NULL, regmap_irq_chip_get_base(palmas->irq_data), | 459 | NULL, regmap_irq_chip_get_base(palmas->irq_data), |
@@ -458,13 +461,15 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, | |||
458 | kfree(children); | 461 | kfree(children); |
459 | 462 | ||
460 | if (ret < 0) | 463 | if (ret < 0) |
461 | goto err; | 464 | goto err_devices; |
462 | 465 | ||
463 | return ret; | 466 | return ret; |
464 | 467 | ||
465 | err: | 468 | err_devices: |
466 | mfd_remove_devices(palmas->dev); | 469 | mfd_remove_devices(palmas->dev); |
467 | kfree(palmas); | 470 | err_irq: |
471 | regmap_del_irq_chip(palmas->irq, palmas->irq_data); | ||
472 | err: | ||
468 | return ret; | 473 | return ret; |
469 | } | 474 | } |
470 | 475 | ||
diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c index fa6f80fad5f1..fe00cdd6f83d 100644 --- a/drivers/mfd/rc5t583-irq.c +++ b/drivers/mfd/rc5t583-irq.c | |||
@@ -255,7 +255,7 @@ static irqreturn_t rc5t583_irq(int irq, void *data) | |||
255 | { | 255 | { |
256 | struct rc5t583 *rc5t583 = data; | 256 | struct rc5t583 *rc5t583 = data; |
257 | uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS]; | 257 | uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS]; |
258 | uint8_t master_int; | 258 | uint8_t master_int = 0; |
259 | int i; | 259 | int i; |
260 | int ret; | 260 | int ret; |
261 | unsigned int rtc_int_sts = 0; | 261 | unsigned int rtc_int_sts = 0; |
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index ff61efc76ce2..f1a024ecdb1e 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c | |||
@@ -85,7 +85,7 @@ static int __rc5t583_set_ext_pwrreq1_control(struct device *dev, | |||
85 | int id, int ext_pwr, int slots) | 85 | int id, int ext_pwr, int slots) |
86 | { | 86 | { |
87 | int ret; | 87 | int ret; |
88 | uint8_t sleepseq_val; | 88 | uint8_t sleepseq_val = 0; |
89 | unsigned int en_bit; | 89 | unsigned int en_bit; |
90 | unsigned int slot_bit; | 90 | unsigned int slot_bit; |
91 | 91 | ||
diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c new file mode 100644 index 000000000000..24ae3d8421c5 --- /dev/null +++ b/drivers/mfd/smsc-ece1099.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * TI SMSC MFD Driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * | ||
6 | * Author: Sourav Poddar <sourav.poddar@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; GPL v2. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/gpio.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/mfd/core.h> | ||
25 | #include <linux/mfd/smsc.h> | ||
26 | #include <linux/of_platform.h> | ||
27 | |||
28 | static struct regmap_config smsc_regmap_config = { | ||
29 | .reg_bits = 8, | ||
30 | .val_bits = 8, | ||
31 | .max_register = SMSC_VEN_ID_H, | ||
32 | .cache_type = REGCACHE_RBTREE, | ||
33 | }; | ||
34 | |||
35 | static int smsc_i2c_probe(struct i2c_client *i2c, | ||
36 | const struct i2c_device_id *id) | ||
37 | { | ||
38 | struct smsc *smsc; | ||
39 | int devid, rev, venid_l, venid_h; | ||
40 | int ret = 0; | ||
41 | |||
42 | smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc), | ||
43 | GFP_KERNEL); | ||
44 | if (!smsc) { | ||
45 | dev_err(&i2c->dev, "smsc mfd driver memory allocation failed\n"); | ||
46 | return -ENOMEM; | ||
47 | } | ||
48 | |||
49 | smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config); | ||
50 | if (IS_ERR(smsc->regmap)) { | ||
51 | ret = PTR_ERR(smsc->regmap); | ||
52 | goto err; | ||
53 | } | ||
54 | |||
55 | i2c_set_clientdata(i2c, smsc); | ||
56 | smsc->dev = &i2c->dev; | ||
57 | |||
58 | #ifdef CONFIG_OF | ||
59 | of_property_read_u32(i2c->dev.of_node, "clock", &smsc->clk); | ||
60 | #endif | ||
61 | |||
62 | regmap_read(smsc->regmap, SMSC_DEV_ID, &devid); | ||
63 | regmap_read(smsc->regmap, SMSC_DEV_REV, &rev); | ||
64 | regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l); | ||
65 | regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h); | ||
66 | |||
67 | dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n", | ||
68 | devid, rev, (venid_h << 8) | venid_l); | ||
69 | |||
70 | ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk); | ||
71 | if (ret) | ||
72 | goto err; | ||
73 | |||
74 | #ifdef CONFIG_OF | ||
75 | if (i2c->dev.of_node) | ||
76 | ret = of_platform_populate(i2c->dev.of_node, | ||
77 | NULL, NULL, &i2c->dev); | ||
78 | #endif | ||
79 | |||
80 | err: | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | static int smsc_i2c_remove(struct i2c_client *i2c) | ||
85 | { | ||
86 | struct smsc *smsc = i2c_get_clientdata(i2c); | ||
87 | |||
88 | mfd_remove_devices(smsc->dev); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static const struct i2c_device_id smsc_i2c_id[] = { | ||
94 | { "smscece1099", 0}, | ||
95 | {}, | ||
96 | }; | ||
97 | MODULE_DEVICE_TABLE(i2c, smsc_i2c_id); | ||
98 | |||
99 | static struct i2c_driver smsc_i2c_driver = { | ||
100 | .driver = { | ||
101 | .name = "smsc", | ||
102 | .owner = THIS_MODULE, | ||
103 | }, | ||
104 | .probe = smsc_i2c_probe, | ||
105 | .remove = smsc_i2c_remove, | ||
106 | .id_table = smsc_i2c_id, | ||
107 | }; | ||
108 | |||
109 | module_i2c_driver(smsc_i2c_driver); | ||
110 | |||
111 | MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); | ||
112 | MODULE_DESCRIPTION("SMSC chip multi-function driver"); | ||
113 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c new file mode 100644 index 000000000000..65fe609026cc --- /dev/null +++ b/drivers/mfd/syscon.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * System Control Driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Freescale Semiconductor, Inc. | ||
5 | * Copyright (C) 2012 Linaro Ltd. | ||
6 | * | ||
7 | * Author: Dong Aisheng <dong.aisheng@linaro.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/err.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/regmap.h> | ||
23 | |||
24 | static struct platform_driver syscon_driver; | ||
25 | |||
26 | struct syscon { | ||
27 | struct device *dev; | ||
28 | void __iomem *base; | ||
29 | struct regmap *regmap; | ||
30 | }; | ||
31 | |||
32 | static int syscon_match(struct device *dev, void *data) | ||
33 | { | ||
34 | struct syscon *syscon = dev_get_drvdata(dev); | ||
35 | struct device_node *dn = data; | ||
36 | |||
37 | return (syscon->dev->of_node == dn) ? 1 : 0; | ||
38 | } | ||
39 | |||
40 | struct regmap *syscon_node_to_regmap(struct device_node *np) | ||
41 | { | ||
42 | struct syscon *syscon; | ||
43 | struct device *dev; | ||
44 | |||
45 | dev = driver_find_device(&syscon_driver.driver, NULL, np, | ||
46 | syscon_match); | ||
47 | if (!dev) | ||
48 | return ERR_PTR(-EPROBE_DEFER); | ||
49 | |||
50 | syscon = dev_get_drvdata(dev); | ||
51 | |||
52 | return syscon->regmap; | ||
53 | } | ||
54 | EXPORT_SYMBOL_GPL(syscon_node_to_regmap); | ||
55 | |||
56 | struct regmap *syscon_regmap_lookup_by_compatible(const char *s) | ||
57 | { | ||
58 | struct device_node *syscon_np; | ||
59 | struct regmap *regmap; | ||
60 | |||
61 | syscon_np = of_find_compatible_node(NULL, NULL, s); | ||
62 | if (!syscon_np) | ||
63 | return ERR_PTR(-ENODEV); | ||
64 | |||
65 | regmap = syscon_node_to_regmap(syscon_np); | ||
66 | of_node_put(syscon_np); | ||
67 | |||
68 | return regmap; | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); | ||
71 | |||
72 | struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, | ||
73 | const char *property) | ||
74 | { | ||
75 | struct device_node *syscon_np; | ||
76 | struct regmap *regmap; | ||
77 | |||
78 | syscon_np = of_parse_phandle(np, property, 0); | ||
79 | if (!syscon_np) | ||
80 | return ERR_PTR(-ENODEV); | ||
81 | |||
82 | regmap = syscon_node_to_regmap(syscon_np); | ||
83 | of_node_put(syscon_np); | ||
84 | |||
85 | return regmap; | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); | ||
88 | |||
89 | static const struct of_device_id of_syscon_match[] = { | ||
90 | { .compatible = "syscon", }, | ||
91 | { }, | ||
92 | }; | ||
93 | |||
94 | static struct regmap_config syscon_regmap_config = { | ||
95 | .reg_bits = 32, | ||
96 | .val_bits = 32, | ||
97 | .reg_stride = 4, | ||
98 | }; | ||
99 | |||
100 | static int __devinit syscon_probe(struct platform_device *pdev) | ||
101 | { | ||
102 | struct device *dev = &pdev->dev; | ||
103 | struct device_node *np = dev->of_node; | ||
104 | struct syscon *syscon; | ||
105 | struct resource res; | ||
106 | int ret; | ||
107 | |||
108 | if (!np) | ||
109 | return -ENOENT; | ||
110 | |||
111 | syscon = devm_kzalloc(dev, sizeof(struct syscon), | ||
112 | GFP_KERNEL); | ||
113 | if (!syscon) | ||
114 | return -ENOMEM; | ||
115 | |||
116 | syscon->base = of_iomap(np, 0); | ||
117 | if (!syscon->base) | ||
118 | return -EADDRNOTAVAIL; | ||
119 | |||
120 | ret = of_address_to_resource(np, 0, &res); | ||
121 | if (ret) | ||
122 | return ret; | ||
123 | |||
124 | syscon_regmap_config.max_register = res.end - res.start - 3; | ||
125 | syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, | ||
126 | &syscon_regmap_config); | ||
127 | if (IS_ERR(syscon->regmap)) { | ||
128 | dev_err(dev, "regmap init failed\n"); | ||
129 | return PTR_ERR(syscon->regmap); | ||
130 | } | ||
131 | |||
132 | syscon->dev = dev; | ||
133 | platform_set_drvdata(pdev, syscon); | ||
134 | |||
135 | dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n", | ||
136 | res.start, res.end); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int __devexit syscon_remove(struct platform_device *pdev) | ||
142 | { | ||
143 | struct syscon *syscon; | ||
144 | |||
145 | syscon = platform_get_drvdata(pdev); | ||
146 | iounmap(syscon->base); | ||
147 | platform_set_drvdata(pdev, NULL); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static struct platform_driver syscon_driver = { | ||
153 | .driver = { | ||
154 | .name = "syscon", | ||
155 | .owner = THIS_MODULE, | ||
156 | .of_match_table = of_syscon_match, | ||
157 | }, | ||
158 | .probe = syscon_probe, | ||
159 | .remove = __devexit_p(syscon_remove), | ||
160 | }; | ||
161 | |||
162 | static int __init syscon_init(void) | ||
163 | { | ||
164 | return platform_driver_register(&syscon_driver); | ||
165 | } | ||
166 | postcore_initcall(syscon_init); | ||
167 | |||
168 | static void __exit syscon_exit(void) | ||
169 | { | ||
170 | platform_driver_unregister(&syscon_driver); | ||
171 | } | ||
172 | module_exit(syscon_exit); | ||
173 | |||
174 | MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>"); | ||
175 | MODULE_DESCRIPTION("System Control driver"); | ||
176 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index b56ba6b43294..8f4c853ca116 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
@@ -9,8 +9,10 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include <linux/irq.h> | 11 | #include <linux/irq.h> |
12 | #include <linux/irqdomain.h> | ||
12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
13 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
15 | #include <linux/of.h> | ||
14 | #include <linux/mfd/core.h> | 16 | #include <linux/mfd/core.h> |
15 | #include <linux/mfd/tc3589x.h> | 17 | #include <linux/mfd/tc3589x.h> |
16 | 18 | ||
@@ -145,6 +147,7 @@ static struct mfd_cell tc3589x_dev_gpio[] = { | |||
145 | .name = "tc3589x-gpio", | 147 | .name = "tc3589x-gpio", |
146 | .num_resources = ARRAY_SIZE(gpio_resources), | 148 | .num_resources = ARRAY_SIZE(gpio_resources), |
147 | .resources = &gpio_resources[0], | 149 | .resources = &gpio_resources[0], |
150 | .of_compatible = "tc3589x-gpio", | ||
148 | }, | 151 | }, |
149 | }; | 152 | }; |
150 | 153 | ||
@@ -153,6 +156,7 @@ static struct mfd_cell tc3589x_dev_keypad[] = { | |||
153 | .name = "tc3589x-keypad", | 156 | .name = "tc3589x-keypad", |
154 | .num_resources = ARRAY_SIZE(keypad_resources), | 157 | .num_resources = ARRAY_SIZE(keypad_resources), |
155 | .resources = &keypad_resources[0], | 158 | .resources = &keypad_resources[0], |
159 | .of_compatible = "tc3589x-keypad", | ||
156 | }, | 160 | }, |
157 | }; | 161 | }; |
158 | 162 | ||
@@ -168,8 +172,9 @@ again: | |||
168 | 172 | ||
169 | while (status) { | 173 | while (status) { |
170 | int bit = __ffs(status); | 174 | int bit = __ffs(status); |
175 | int virq = irq_create_mapping(tc3589x->domain, bit); | ||
171 | 176 | ||
172 | handle_nested_irq(tc3589x->irq_base + bit); | 177 | handle_nested_irq(virq); |
173 | status &= ~(1 << bit); | 178 | status &= ~(1 << bit); |
174 | } | 179 | } |
175 | 180 | ||
@@ -186,38 +191,60 @@ again: | |||
186 | return IRQ_HANDLED; | 191 | return IRQ_HANDLED; |
187 | } | 192 | } |
188 | 193 | ||
189 | static int tc3589x_irq_init(struct tc3589x *tc3589x) | 194 | static int tc3589x_irq_map(struct irq_domain *d, unsigned int virq, |
195 | irq_hw_number_t hwirq) | ||
190 | { | 196 | { |
191 | int base = tc3589x->irq_base; | 197 | struct tc3589x *tc3589x = d->host_data; |
192 | int irq; | ||
193 | 198 | ||
194 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | 199 | irq_set_chip_data(virq, tc3589x); |
195 | irq_set_chip_data(irq, tc3589x); | 200 | irq_set_chip_and_handler(virq, &dummy_irq_chip, |
196 | irq_set_chip_and_handler(irq, &dummy_irq_chip, | 201 | handle_edge_irq); |
197 | handle_edge_irq); | 202 | irq_set_nested_thread(virq, 1); |
198 | irq_set_nested_thread(irq, 1); | ||
199 | #ifdef CONFIG_ARM | 203 | #ifdef CONFIG_ARM |
200 | set_irq_flags(irq, IRQF_VALID); | 204 | set_irq_flags(virq, IRQF_VALID); |
201 | #else | 205 | #else |
202 | irq_set_noprobe(irq); | 206 | irq_set_noprobe(virq); |
203 | #endif | 207 | #endif |
204 | } | ||
205 | 208 | ||
206 | return 0; | 209 | return 0; |
207 | } | 210 | } |
208 | 211 | ||
209 | static void tc3589x_irq_remove(struct tc3589x *tc3589x) | 212 | static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq) |
210 | { | 213 | { |
211 | int base = tc3589x->irq_base; | ||
212 | int irq; | ||
213 | |||
214 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | ||
215 | #ifdef CONFIG_ARM | 214 | #ifdef CONFIG_ARM |
216 | set_irq_flags(irq, 0); | 215 | set_irq_flags(virq, 0); |
217 | #endif | 216 | #endif |
218 | irq_set_chip_and_handler(irq, NULL, NULL); | 217 | irq_set_chip_and_handler(virq, NULL, NULL); |
219 | irq_set_chip_data(irq, NULL); | 218 | irq_set_chip_data(virq, NULL); |
219 | } | ||
220 | |||
221 | static struct irq_domain_ops tc3589x_irq_ops = { | ||
222 | .map = tc3589x_irq_map, | ||
223 | .unmap = tc3589x_irq_unmap, | ||
224 | .xlate = irq_domain_xlate_twocell, | ||
225 | }; | ||
226 | |||
227 | static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np) | ||
228 | { | ||
229 | int base = tc3589x->irq_base; | ||
230 | |||
231 | if (base) { | ||
232 | tc3589x->domain = irq_domain_add_legacy( | ||
233 | NULL, TC3589x_NR_INTERNAL_IRQS, base, | ||
234 | 0, &tc3589x_irq_ops, tc3589x); | ||
235 | } | ||
236 | else { | ||
237 | tc3589x->domain = irq_domain_add_linear( | ||
238 | np, TC3589x_NR_INTERNAL_IRQS, | ||
239 | &tc3589x_irq_ops, tc3589x); | ||
220 | } | 240 | } |
241 | |||
242 | if (!tc3589x->domain) { | ||
243 | dev_err(tc3589x->dev, "Failed to create irqdomain\n"); | ||
244 | return -ENOSYS; | ||
245 | } | ||
246 | |||
247 | return 0; | ||
221 | } | 248 | } |
222 | 249 | ||
223 | static int tc3589x_chip_init(struct tc3589x *tc3589x) | 250 | static int tc3589x_chip_init(struct tc3589x *tc3589x) |
@@ -263,7 +290,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | |||
263 | if (blocks & TC3589x_BLOCK_GPIO) { | 290 | if (blocks & TC3589x_BLOCK_GPIO) { |
264 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, | 291 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, |
265 | ARRAY_SIZE(tc3589x_dev_gpio), NULL, | 292 | ARRAY_SIZE(tc3589x_dev_gpio), NULL, |
266 | tc3589x->irq_base, NULL); | 293 | tc3589x->irq_base, tc3589x->domain); |
267 | if (ret) { | 294 | if (ret) { |
268 | dev_err(tc3589x->dev, "failed to add gpio child\n"); | 295 | dev_err(tc3589x->dev, "failed to add gpio child\n"); |
269 | return ret; | 296 | return ret; |
@@ -274,7 +301,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | |||
274 | if (blocks & TC3589x_BLOCK_KEYPAD) { | 301 | if (blocks & TC3589x_BLOCK_KEYPAD) { |
275 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, | 302 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, |
276 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, | 303 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, |
277 | tc3589x->irq_base, NULL); | 304 | tc3589x->irq_base, tc3589x->domain); |
278 | if (ret) { | 305 | if (ret) { |
279 | dev_err(tc3589x->dev, "failed to keypad child\n"); | 306 | dev_err(tc3589x->dev, "failed to keypad child\n"); |
280 | return ret; | 307 | return ret; |
@@ -285,13 +312,47 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | |||
285 | return ret; | 312 | return ret; |
286 | } | 313 | } |
287 | 314 | ||
315 | static int tc3589x_of_probe(struct device_node *np, | ||
316 | struct tc3589x_platform_data *pdata) | ||
317 | { | ||
318 | struct device_node *child; | ||
319 | |||
320 | for_each_child_of_node(np, child) { | ||
321 | if (!strcmp(child->name, "tc3589x_gpio")) { | ||
322 | pdata->block |= TC3589x_BLOCK_GPIO; | ||
323 | } | ||
324 | if (!strcmp(child->name, "tc3589x_keypad")) { | ||
325 | pdata->block |= TC3589x_BLOCK_KEYPAD; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
288 | static int __devinit tc3589x_probe(struct i2c_client *i2c, | 332 | static int __devinit tc3589x_probe(struct i2c_client *i2c, |
289 | const struct i2c_device_id *id) | 333 | const struct i2c_device_id *id) |
290 | { | 334 | { |
291 | struct tc3589x_platform_data *pdata = i2c->dev.platform_data; | 335 | struct tc3589x_platform_data *pdata = i2c->dev.platform_data; |
336 | struct device_node *np = i2c->dev.of_node; | ||
292 | struct tc3589x *tc3589x; | 337 | struct tc3589x *tc3589x; |
293 | int ret; | 338 | int ret; |
294 | 339 | ||
340 | if (!pdata) { | ||
341 | if (np) { | ||
342 | pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); | ||
343 | if (!pdata) | ||
344 | return -ENOMEM; | ||
345 | |||
346 | ret = tc3589x_of_probe(np, pdata); | ||
347 | if (ret) | ||
348 | return ret; | ||
349 | } | ||
350 | else { | ||
351 | dev_err(&i2c->dev, "No platform data or DT found\n"); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | } | ||
355 | |||
295 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | 356 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
296 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | 357 | | I2C_FUNC_SMBUS_I2C_BLOCK)) |
297 | return -EIO; | 358 | return -EIO; |
@@ -314,7 +375,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, | |||
314 | if (ret) | 375 | if (ret) |
315 | goto out_free; | 376 | goto out_free; |
316 | 377 | ||
317 | ret = tc3589x_irq_init(tc3589x); | 378 | ret = tc3589x_irq_init(tc3589x, np); |
318 | if (ret) | 379 | if (ret) |
319 | goto out_free; | 380 | goto out_free; |
320 | 381 | ||
@@ -323,7 +384,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, | |||
323 | "tc3589x", tc3589x); | 384 | "tc3589x", tc3589x); |
324 | if (ret) { | 385 | if (ret) { |
325 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); | 386 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); |
326 | goto out_removeirq; | 387 | goto out_free; |
327 | } | 388 | } |
328 | 389 | ||
329 | ret = tc3589x_device_init(tc3589x); | 390 | ret = tc3589x_device_init(tc3589x); |
@@ -336,8 +397,6 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, | |||
336 | 397 | ||
337 | out_freeirq: | 398 | out_freeirq: |
338 | free_irq(tc3589x->i2c->irq, tc3589x); | 399 | free_irq(tc3589x->i2c->irq, tc3589x); |
339 | out_removeirq: | ||
340 | tc3589x_irq_remove(tc3589x); | ||
341 | out_free: | 400 | out_free: |
342 | kfree(tc3589x); | 401 | kfree(tc3589x); |
343 | return ret; | 402 | return ret; |
@@ -350,7 +409,6 @@ static int __devexit tc3589x_remove(struct i2c_client *client) | |||
350 | mfd_remove_devices(tc3589x->dev); | 409 | mfd_remove_devices(tc3589x->dev); |
351 | 410 | ||
352 | free_irq(tc3589x->i2c->irq, tc3589x); | 411 | free_irq(tc3589x->i2c->irq, tc3589x); |
353 | tc3589x_irq_remove(tc3589x); | ||
354 | 412 | ||
355 | kfree(tc3589x); | 413 | kfree(tc3589x); |
356 | 414 | ||
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 50fd87c87a1c..074ae32b0d2a 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c | |||
@@ -236,7 +236,7 @@ static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq, | |||
236 | 236 | ||
237 | static bool is_volatile_reg(struct device *dev, unsigned int reg) | 237 | static bool is_volatile_reg(struct device *dev, unsigned int reg) |
238 | { | 238 | { |
239 | if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS)) | 239 | if (reg == TPS65090_INT_STS) |
240 | return true; | 240 | return true; |
241 | else | 241 | else |
242 | return false; | 242 | return false; |
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index a95e9421b735..3fb32e655254 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c | |||
@@ -34,6 +34,9 @@ static struct mfd_cell tps65217s[] = { | |||
34 | { | 34 | { |
35 | .name = "tps65217-pmic", | 35 | .name = "tps65217-pmic", |
36 | }, | 36 | }, |
37 | { | ||
38 | .name = "tps65217-bl", | ||
39 | }, | ||
37 | }; | 40 | }; |
38 | 41 | ||
39 | /** | 42 | /** |
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 345960ca2fd8..467464368773 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
@@ -30,6 +30,10 @@ | |||
30 | #include <linux/mfd/core.h> | 30 | #include <linux/mfd/core.h> |
31 | #include <linux/mfd/tps6586x.h> | 31 | #include <linux/mfd/tps6586x.h> |
32 | 32 | ||
33 | #define TPS6586X_SUPPLYENE 0x14 | ||
34 | #define EXITSLREQ_BIT BIT(1) | ||
35 | #define SLEEP_MODE_BIT BIT(3) | ||
36 | |||
33 | /* interrupt control registers */ | 37 | /* interrupt control registers */ |
34 | #define TPS6586X_INT_ACK1 0xb5 | 38 | #define TPS6586X_INT_ACK1 0xb5 |
35 | #define TPS6586X_INT_ACK2 0xb6 | 39 | #define TPS6586X_INT_ACK2 0xb6 |
@@ -422,6 +426,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien | |||
422 | pdata->subdevs = devs; | 426 | pdata->subdevs = devs; |
423 | pdata->gpio_base = -1; | 427 | pdata->gpio_base = -1; |
424 | pdata->irq_base = -1; | 428 | pdata->irq_base = -1; |
429 | pdata->pm_off = of_property_read_bool(np, "ti,system-power-controller"); | ||
425 | 430 | ||
426 | return pdata; | 431 | return pdata; |
427 | } | 432 | } |
@@ -454,6 +459,15 @@ static const struct regmap_config tps6586x_regmap_config = { | |||
454 | .cache_type = REGCACHE_RBTREE, | 459 | .cache_type = REGCACHE_RBTREE, |
455 | }; | 460 | }; |
456 | 461 | ||
462 | static struct device *tps6586x_dev; | ||
463 | static void tps6586x_power_off(void) | ||
464 | { | ||
465 | if (tps6586x_clr_bits(tps6586x_dev, TPS6586X_SUPPLYENE, EXITSLREQ_BIT)) | ||
466 | return; | ||
467 | |||
468 | tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT); | ||
469 | } | ||
470 | |||
457 | static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | 471 | static int __devinit tps6586x_i2c_probe(struct i2c_client *client, |
458 | const struct i2c_device_id *id) | 472 | const struct i2c_device_id *id) |
459 | { | 473 | { |
@@ -519,6 +533,11 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
519 | goto err_add_devs; | 533 | goto err_add_devs; |
520 | } | 534 | } |
521 | 535 | ||
536 | if (pdata->pm_off && !pm_power_off) { | ||
537 | tps6586x_dev = &client->dev; | ||
538 | pm_power_off = tps6586x_power_off; | ||
539 | } | ||
540 | |||
522 | return 0; | 541 | return 0; |
523 | 542 | ||
524 | err_add_devs: | 543 | err_add_devs: |
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index d3ce4d569deb..0d79ce2b5014 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c | |||
@@ -24,6 +24,14 @@ | |||
24 | #include <linux/mfd/tps65910.h> | 24 | #include <linux/mfd/tps65910.h> |
25 | #include <linux/of_device.h> | 25 | #include <linux/of_device.h> |
26 | 26 | ||
27 | static struct resource rtc_resources[] = { | ||
28 | { | ||
29 | .start = TPS65910_IRQ_RTC_ALARM, | ||
30 | .end = TPS65910_IRQ_RTC_ALARM, | ||
31 | .flags = IORESOURCE_IRQ, | ||
32 | } | ||
33 | }; | ||
34 | |||
27 | static struct mfd_cell tps65910s[] = { | 35 | static struct mfd_cell tps65910s[] = { |
28 | { | 36 | { |
29 | .name = "tps65910-gpio", | 37 | .name = "tps65910-gpio", |
@@ -33,6 +41,8 @@ static struct mfd_cell tps65910s[] = { | |||
33 | }, | 41 | }, |
34 | { | 42 | { |
35 | .name = "tps65910-rtc", | 43 | .name = "tps65910-rtc", |
44 | .num_resources = ARRAY_SIZE(rtc_resources), | ||
45 | .resources = &rtc_resources[0], | ||
36 | }, | 46 | }, |
37 | { | 47 | { |
38 | .name = "tps65910-power", | 48 | .name = "tps65910-power", |
@@ -198,6 +208,8 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, | |||
198 | 208 | ||
199 | board_info->irq = client->irq; | 209 | board_info->irq = client->irq; |
200 | board_info->irq_base = -1; | 210 | board_info->irq_base = -1; |
211 | board_info->pm_off = of_property_read_bool(np, | ||
212 | "ti,system-power-controller"); | ||
201 | 213 | ||
202 | return board_info; | 214 | return board_info; |
203 | } | 215 | } |
@@ -210,6 +222,21 @@ struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, | |||
210 | } | 222 | } |
211 | #endif | 223 | #endif |
212 | 224 | ||
225 | static struct i2c_client *tps65910_i2c_client; | ||
226 | static void tps65910_power_off(void) | ||
227 | { | ||
228 | struct tps65910 *tps65910; | ||
229 | |||
230 | tps65910 = dev_get_drvdata(&tps65910_i2c_client->dev); | ||
231 | |||
232 | if (tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, | ||
233 | DEVCTRL_PWR_OFF_MASK) < 0) | ||
234 | return; | ||
235 | |||
236 | tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, | ||
237 | DEVCTRL_DEV_ON_MASK); | ||
238 | } | ||
239 | |||
213 | static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, | 240 | static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, |
214 | const struct i2c_device_id *id) | 241 | const struct i2c_device_id *id) |
215 | { | 242 | { |
@@ -267,6 +294,11 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, | |||
267 | tps65910_ck32k_init(tps65910, pmic_plat_data); | 294 | tps65910_ck32k_init(tps65910, pmic_plat_data); |
268 | tps65910_sleepinit(tps65910, pmic_plat_data); | 295 | tps65910_sleepinit(tps65910, pmic_plat_data); |
269 | 296 | ||
297 | if (pmic_plat_data->pm_off && !pm_power_off) { | ||
298 | tps65910_i2c_client = i2c; | ||
299 | pm_power_off = tps65910_power_off; | ||
300 | } | ||
301 | |||
270 | return ret; | 302 | return ret; |
271 | } | 303 | } |
272 | 304 | ||
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 9d3a0bc1a65f..4ae642320205 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -63,70 +63,6 @@ | |||
63 | 63 | ||
64 | #define DRIVER_NAME "twl" | 64 | #define DRIVER_NAME "twl" |
65 | 65 | ||
66 | #if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE) | ||
67 | #define twl_has_keypad() true | ||
68 | #else | ||
69 | #define twl_has_keypad() false | ||
70 | #endif | ||
71 | |||
72 | #if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE) | ||
73 | #define twl_has_gpio() true | ||
74 | #else | ||
75 | #define twl_has_gpio() false | ||
76 | #endif | ||
77 | |||
78 | #if defined(CONFIG_REGULATOR_TWL4030) \ | ||
79 | || defined(CONFIG_REGULATOR_TWL4030_MODULE) | ||
80 | #define twl_has_regulator() true | ||
81 | #else | ||
82 | #define twl_has_regulator() false | ||
83 | #endif | ||
84 | |||
85 | #if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) | ||
86 | #define twl_has_madc() true | ||
87 | #else | ||
88 | #define twl_has_madc() false | ||
89 | #endif | ||
90 | |||
91 | #ifdef CONFIG_TWL4030_POWER | ||
92 | #define twl_has_power() true | ||
93 | #else | ||
94 | #define twl_has_power() false | ||
95 | #endif | ||
96 | |||
97 | #if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE) | ||
98 | #define twl_has_rtc() true | ||
99 | #else | ||
100 | #define twl_has_rtc() false | ||
101 | #endif | ||
102 | |||
103 | #if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\ | ||
104 | defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE) | ||
105 | #define twl_has_usb() true | ||
106 | #else | ||
107 | #define twl_has_usb() false | ||
108 | #endif | ||
109 | |||
110 | #if defined(CONFIG_TWL4030_WATCHDOG) || \ | ||
111 | defined(CONFIG_TWL4030_WATCHDOG_MODULE) | ||
112 | #define twl_has_watchdog() true | ||
113 | #else | ||
114 | #define twl_has_watchdog() false | ||
115 | #endif | ||
116 | |||
117 | #if defined(CONFIG_MFD_TWL4030_AUDIO) || \ | ||
118 | defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) | ||
119 | #define twl_has_codec() true | ||
120 | #else | ||
121 | #define twl_has_codec() false | ||
122 | #endif | ||
123 | |||
124 | #if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE) | ||
125 | #define twl_has_bci() true | ||
126 | #else | ||
127 | #define twl_has_bci() false | ||
128 | #endif | ||
129 | |||
130 | /* Triton Core internal information (BEGIN) */ | 66 | /* Triton Core internal information (BEGIN) */ |
131 | 67 | ||
132 | /* Last - for index max*/ | 68 | /* Last - for index max*/ |
@@ -134,13 +70,6 @@ | |||
134 | 70 | ||
135 | #define TWL_NUM_SLAVES 4 | 71 | #define TWL_NUM_SLAVES 4 |
136 | 72 | ||
137 | #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ | ||
138 | || defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE) | ||
139 | #define twl_has_pwrbutton() true | ||
140 | #else | ||
141 | #define twl_has_pwrbutton() false | ||
142 | #endif | ||
143 | |||
144 | #define SUB_CHIP_ID0 0 | 73 | #define SUB_CHIP_ID0 0 |
145 | #define SUB_CHIP_ID1 1 | 74 | #define SUB_CHIP_ID1 1 |
146 | #define SUB_CHIP_ID2 2 | 75 | #define SUB_CHIP_ID2 2 |
@@ -552,6 +481,38 @@ int twl_get_version(void) | |||
552 | } | 481 | } |
553 | EXPORT_SYMBOL_GPL(twl_get_version); | 482 | EXPORT_SYMBOL_GPL(twl_get_version); |
554 | 483 | ||
484 | /** | ||
485 | * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate. | ||
486 | * | ||
487 | * Api to get the TWL HFCLK rate based on BOOT_CFG register. | ||
488 | */ | ||
489 | int twl_get_hfclk_rate(void) | ||
490 | { | ||
491 | u8 ctrl; | ||
492 | int rate; | ||
493 | |||
494 | twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT); | ||
495 | |||
496 | switch (ctrl & 0x3) { | ||
497 | case HFCLK_FREQ_19p2_MHZ: | ||
498 | rate = 19200000; | ||
499 | break; | ||
500 | case HFCLK_FREQ_26_MHZ: | ||
501 | rate = 26000000; | ||
502 | break; | ||
503 | case HFCLK_FREQ_38p4_MHZ: | ||
504 | rate = 38400000; | ||
505 | break; | ||
506 | default: | ||
507 | pr_err("TWL4030: HFCLK is not configured\n"); | ||
508 | rate = -EINVAL; | ||
509 | break; | ||
510 | } | ||
511 | |||
512 | return rate; | ||
513 | } | ||
514 | EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); | ||
515 | |||
555 | static struct device * | 516 | static struct device * |
556 | add_numbered_child(unsigned chip, const char *name, int num, | 517 | add_numbered_child(unsigned chip, const char *name, int num, |
557 | void *pdata, unsigned pdata_len, | 518 | void *pdata, unsigned pdata_len, |
@@ -669,7 +630,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
669 | struct device *child; | 630 | struct device *child; |
670 | unsigned sub_chip_id; | 631 | unsigned sub_chip_id; |
671 | 632 | ||
672 | if (twl_has_gpio() && pdata->gpio) { | 633 | if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) { |
673 | child = add_child(SUB_CHIP_ID1, "twl4030_gpio", | 634 | child = add_child(SUB_CHIP_ID1, "twl4030_gpio", |
674 | pdata->gpio, sizeof(*pdata->gpio), | 635 | pdata->gpio, sizeof(*pdata->gpio), |
675 | false, irq_base + GPIO_INTR_OFFSET, 0); | 636 | false, irq_base + GPIO_INTR_OFFSET, 0); |
@@ -677,7 +638,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
677 | return PTR_ERR(child); | 638 | return PTR_ERR(child); |
678 | } | 639 | } |
679 | 640 | ||
680 | if (twl_has_keypad() && pdata->keypad) { | 641 | if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) { |
681 | child = add_child(SUB_CHIP_ID2, "twl4030_keypad", | 642 | child = add_child(SUB_CHIP_ID2, "twl4030_keypad", |
682 | pdata->keypad, sizeof(*pdata->keypad), | 643 | pdata->keypad, sizeof(*pdata->keypad), |
683 | true, irq_base + KEYPAD_INTR_OFFSET, 0); | 644 | true, irq_base + KEYPAD_INTR_OFFSET, 0); |
@@ -685,7 +646,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
685 | return PTR_ERR(child); | 646 | return PTR_ERR(child); |
686 | } | 647 | } |
687 | 648 | ||
688 | if (twl_has_madc() && pdata->madc) { | 649 | if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc) { |
689 | child = add_child(2, "twl4030_madc", | 650 | child = add_child(2, "twl4030_madc", |
690 | pdata->madc, sizeof(*pdata->madc), | 651 | pdata->madc, sizeof(*pdata->madc), |
691 | true, irq_base + MADC_INTR_OFFSET, 0); | 652 | true, irq_base + MADC_INTR_OFFSET, 0); |
@@ -693,7 +654,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
693 | return PTR_ERR(child); | 654 | return PTR_ERR(child); |
694 | } | 655 | } |
695 | 656 | ||
696 | if (twl_has_rtc()) { | 657 | if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) { |
697 | /* | 658 | /* |
698 | * REVISIT platform_data here currently might expose the | 659 | * REVISIT platform_data here currently might expose the |
699 | * "msecure" line ... but for now we just expect board | 660 | * "msecure" line ... but for now we just expect board |
@@ -709,7 +670,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
709 | return PTR_ERR(child); | 670 | return PTR_ERR(child); |
710 | } | 671 | } |
711 | 672 | ||
712 | if (twl_has_usb() && pdata->usb && twl_class_is_4030()) { | 673 | if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { |
674 | child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0, | ||
675 | false, 0, 0); | ||
676 | if (IS_ERR(child)) | ||
677 | return PTR_ERR(child); | ||
678 | } | ||
679 | |||
680 | if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && | ||
681 | twl_class_is_4030()) { | ||
713 | 682 | ||
714 | static struct regulator_consumer_supply usb1v5 = { | 683 | static struct regulator_consumer_supply usb1v5 = { |
715 | .supply = "usb1v5", | 684 | .supply = "usb1v5", |
@@ -723,7 +692,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
723 | }; | 692 | }; |
724 | 693 | ||
725 | /* First add the regulators so that they can be used by transceiver */ | 694 | /* First add the regulators so that they can be used by transceiver */ |
726 | if (twl_has_regulator()) { | 695 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { |
727 | /* this is a template that gets copied */ | 696 | /* this is a template that gets copied */ |
728 | struct regulator_init_data usb_fixed = { | 697 | struct regulator_init_data usb_fixed = { |
729 | .constraints.valid_modes_mask = | 698 | .constraints.valid_modes_mask = |
@@ -765,18 +734,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
765 | return PTR_ERR(child); | 734 | return PTR_ERR(child); |
766 | 735 | ||
767 | /* we need to connect regulators to this transceiver */ | 736 | /* we need to connect regulators to this transceiver */ |
768 | if (twl_has_regulator() && child) { | 737 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { |
769 | usb1v5.dev_name = dev_name(child); | 738 | usb1v5.dev_name = dev_name(child); |
770 | usb1v8.dev_name = dev_name(child); | 739 | usb1v8.dev_name = dev_name(child); |
771 | usb3v1[0].dev_name = dev_name(child); | 740 | usb3v1[0].dev_name = dev_name(child); |
772 | } | 741 | } |
773 | } | 742 | } |
774 | if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { | 743 | if (IS_ENABLED(CONFIG_TWL6030_USB) && pdata->usb && |
744 | twl_class_is_6030()) { | ||
775 | 745 | ||
776 | static struct regulator_consumer_supply usb3v3; | 746 | static struct regulator_consumer_supply usb3v3; |
777 | int regulator; | 747 | int regulator; |
778 | 748 | ||
779 | if (twl_has_regulator()) { | 749 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { |
780 | /* this is a template that gets copied */ | 750 | /* this is a template that gets copied */ |
781 | struct regulator_init_data usb_fixed = { | 751 | struct regulator_init_data usb_fixed = { |
782 | .constraints.valid_modes_mask = | 752 | .constraints.valid_modes_mask = |
@@ -813,9 +783,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
813 | if (IS_ERR(child)) | 783 | if (IS_ERR(child)) |
814 | return PTR_ERR(child); | 784 | return PTR_ERR(child); |
815 | /* we need to connect regulators to this transceiver */ | 785 | /* we need to connect regulators to this transceiver */ |
816 | if (twl_has_regulator() && child) | 786 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) |
817 | usb3v3.dev_name = dev_name(child); | 787 | usb3v3.dev_name = dev_name(child); |
818 | } else if (twl_has_regulator() && twl_class_is_6030()) { | 788 | } else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && |
789 | twl_class_is_6030()) { | ||
819 | if (features & TWL6025_SUBCLASS) | 790 | if (features & TWL6025_SUBCLASS) |
820 | child = add_regulator(TWL6025_REG_LDOUSB, | 791 | child = add_regulator(TWL6025_REG_LDOUSB, |
821 | pdata->ldousb, features); | 792 | pdata->ldousb, features); |
@@ -827,20 +798,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
827 | return PTR_ERR(child); | 798 | return PTR_ERR(child); |
828 | } | 799 | } |
829 | 800 | ||
830 | if (twl_has_watchdog() && twl_class_is_4030()) { | 801 | if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { |
831 | child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); | 802 | child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); |
832 | if (IS_ERR(child)) | 803 | if (IS_ERR(child)) |
833 | return PTR_ERR(child); | 804 | return PTR_ERR(child); |
834 | } | 805 | } |
835 | 806 | ||
836 | if (twl_has_pwrbutton() && twl_class_is_4030()) { | 807 | if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { |
837 | child = add_child(1, "twl4030_pwrbutton", | 808 | child = add_child(1, "twl4030_pwrbutton", |
838 | NULL, 0, true, irq_base + 8 + 0, 0); | 809 | NULL, 0, true, irq_base + 8 + 0, 0); |
839 | if (IS_ERR(child)) | 810 | if (IS_ERR(child)) |
840 | return PTR_ERR(child); | 811 | return PTR_ERR(child); |
841 | } | 812 | } |
842 | 813 | ||
843 | if (twl_has_codec() && pdata->audio && twl_class_is_4030()) { | 814 | if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && |
815 | twl_class_is_4030()) { | ||
844 | sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; | 816 | sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; |
845 | child = add_child(sub_chip_id, "twl4030-audio", | 817 | child = add_child(sub_chip_id, "twl4030-audio", |
846 | pdata->audio, sizeof(*pdata->audio), | 818 | pdata->audio, sizeof(*pdata->audio), |
@@ -850,7 +822,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
850 | } | 822 | } |
851 | 823 | ||
852 | /* twl4030 regulators */ | 824 | /* twl4030 regulators */ |
853 | if (twl_has_regulator() && twl_class_is_4030()) { | 825 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) { |
854 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, | 826 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, |
855 | features); | 827 | features); |
856 | if (IS_ERR(child)) | 828 | if (IS_ERR(child)) |
@@ -905,7 +877,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
905 | } | 877 | } |
906 | 878 | ||
907 | /* maybe add LDOs that are omitted on cost-reduced parts */ | 879 | /* maybe add LDOs that are omitted on cost-reduced parts */ |
908 | if (twl_has_regulator() && !(features & TPS_SUBSET) | 880 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET) |
909 | && twl_class_is_4030()) { | 881 | && twl_class_is_4030()) { |
910 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, | 882 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, |
911 | features); | 883 | features); |
@@ -939,7 +911,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
939 | } | 911 | } |
940 | 912 | ||
941 | /* twl6030 regulators */ | 913 | /* twl6030 regulators */ |
942 | if (twl_has_regulator() && twl_class_is_6030() && | 914 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && |
943 | !(features & TWL6025_SUBCLASS)) { | 915 | !(features & TWL6025_SUBCLASS)) { |
944 | child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, | 916 | child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, |
945 | features); | 917 | features); |
@@ -1013,7 +985,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
1013 | } | 985 | } |
1014 | 986 | ||
1015 | /* 6030 and 6025 share this regulator */ | 987 | /* 6030 and 6025 share this regulator */ |
1016 | if (twl_has_regulator() && twl_class_is_6030()) { | 988 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030()) { |
1017 | child = add_regulator(TWL6030_REG_VANA, pdata->vana, | 989 | child = add_regulator(TWL6030_REG_VANA, pdata->vana, |
1018 | features); | 990 | features); |
1019 | if (IS_ERR(child)) | 991 | if (IS_ERR(child)) |
@@ -1021,7 +993,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
1021 | } | 993 | } |
1022 | 994 | ||
1023 | /* twl6025 regulators */ | 995 | /* twl6025 regulators */ |
1024 | if (twl_has_regulator() && twl_class_is_6030() && | 996 | if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && |
1025 | (features & TWL6025_SUBCLASS)) { | 997 | (features & TWL6025_SUBCLASS)) { |
1026 | child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5, | 998 | child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5, |
1027 | features); | 999 | features); |
@@ -1080,7 +1052,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
1080 | 1052 | ||
1081 | } | 1053 | } |
1082 | 1054 | ||
1083 | if (twl_has_bci() && pdata->bci && | 1055 | if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && |
1084 | !(features & (TPS_SUBSET | TWL5031))) { | 1056 | !(features & (TPS_SUBSET | TWL5031))) { |
1085 | child = add_child(3, "twl4030_bci", | 1057 | child = add_child(3, "twl4030_bci", |
1086 | pdata->bci, sizeof(*pdata->bci), false, | 1058 | pdata->bci, sizeof(*pdata->bci), false, |
@@ -1295,7 +1267,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1295 | } | 1267 | } |
1296 | 1268 | ||
1297 | /* load power event scripts */ | 1269 | /* load power event scripts */ |
1298 | if (twl_has_power() && pdata->power) | 1270 | if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) |
1299 | twl4030_power_init(pdata->power); | 1271 | twl4030_power_init(pdata->power); |
1300 | 1272 | ||
1301 | /* Maybe init the T2 Interrupt subsystem */ | 1273 | /* Maybe init the T2 Interrupt subsystem */ |
diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 77c9acb14583..5c11acf9e0fd 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/of.h> | ||
32 | #include <linux/of_platform.h> | ||
31 | #include <linux/i2c/twl.h> | 33 | #include <linux/i2c/twl.h> |
32 | #include <linux/mfd/core.h> | 34 | #include <linux/mfd/core.h> |
33 | #include <linux/mfd/twl4030-audio.h> | 35 | #include <linux/mfd/twl4030-audio.h> |
@@ -156,47 +158,70 @@ unsigned int twl4030_audio_get_mclk(void) | |||
156 | } | 158 | } |
157 | EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); | 159 | EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); |
158 | 160 | ||
161 | static bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata, | ||
162 | struct device_node *node) | ||
163 | { | ||
164 | if (pdata && pdata->codec) | ||
165 | return true; | ||
166 | |||
167 | if (of_find_node_by_name(node, "codec")) | ||
168 | return true; | ||
169 | |||
170 | return false; | ||
171 | } | ||
172 | |||
173 | static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata, | ||
174 | struct device_node *node) | ||
175 | { | ||
176 | int vibra; | ||
177 | |||
178 | if (pdata && pdata->vibra) | ||
179 | return true; | ||
180 | |||
181 | if (!of_property_read_u32(node, "ti,enable-vibra", &vibra) && vibra) | ||
182 | return true; | ||
183 | |||
184 | return false; | ||
185 | } | ||
186 | |||
159 | static int __devinit twl4030_audio_probe(struct platform_device *pdev) | 187 | static int __devinit twl4030_audio_probe(struct platform_device *pdev) |
160 | { | 188 | { |
161 | struct twl4030_audio *audio; | 189 | struct twl4030_audio *audio; |
162 | struct twl4030_audio_data *pdata = pdev->dev.platform_data; | 190 | struct twl4030_audio_data *pdata = pdev->dev.platform_data; |
191 | struct device_node *node = pdev->dev.of_node; | ||
163 | struct mfd_cell *cell = NULL; | 192 | struct mfd_cell *cell = NULL; |
164 | int ret, childs = 0; | 193 | int ret, childs = 0; |
165 | u8 val; | 194 | u8 val; |
166 | 195 | ||
167 | if (!pdata) { | 196 | if (!pdata && !node) { |
168 | dev_err(&pdev->dev, "Platform data is missing\n"); | 197 | dev_err(&pdev->dev, "Platform data is missing\n"); |
169 | return -EINVAL; | 198 | return -EINVAL; |
170 | } | 199 | } |
171 | 200 | ||
201 | audio = devm_kzalloc(&pdev->dev, sizeof(struct twl4030_audio), | ||
202 | GFP_KERNEL); | ||
203 | if (!audio) | ||
204 | return -ENOMEM; | ||
205 | |||
206 | mutex_init(&audio->mutex); | ||
207 | audio->audio_mclk = twl_get_hfclk_rate(); | ||
208 | |||
172 | /* Configure APLL_INFREQ and disable APLL if enabled */ | 209 | /* Configure APLL_INFREQ and disable APLL if enabled */ |
173 | val = 0; | 210 | switch (audio->audio_mclk) { |
174 | switch (pdata->audio_mclk) { | ||
175 | case 19200000: | 211 | case 19200000: |
176 | val |= TWL4030_APLL_INFREQ_19200KHZ; | 212 | val = TWL4030_APLL_INFREQ_19200KHZ; |
177 | break; | 213 | break; |
178 | case 26000000: | 214 | case 26000000: |
179 | val |= TWL4030_APLL_INFREQ_26000KHZ; | 215 | val = TWL4030_APLL_INFREQ_26000KHZ; |
180 | break; | 216 | break; |
181 | case 38400000: | 217 | case 38400000: |
182 | val |= TWL4030_APLL_INFREQ_38400KHZ; | 218 | val = TWL4030_APLL_INFREQ_38400KHZ; |
183 | break; | 219 | break; |
184 | default: | 220 | default: |
185 | dev_err(&pdev->dev, "Invalid audio_mclk\n"); | 221 | dev_err(&pdev->dev, "Invalid audio_mclk\n"); |
186 | return -EINVAL; | 222 | return -EINVAL; |
187 | } | 223 | } |
188 | twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | 224 | twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, val, TWL4030_REG_APLL_CTL); |
189 | val, TWL4030_REG_APLL_CTL); | ||
190 | |||
191 | audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL); | ||
192 | if (!audio) | ||
193 | return -ENOMEM; | ||
194 | |||
195 | platform_set_drvdata(pdev, audio); | ||
196 | |||
197 | twl4030_audio_dev = pdev; | ||
198 | mutex_init(&audio->mutex); | ||
199 | audio->audio_mclk = pdata->audio_mclk; | ||
200 | 225 | ||
201 | /* Codec power */ | 226 | /* Codec power */ |
202 | audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE; | 227 | audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE; |
@@ -206,21 +231,28 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) | |||
206 | audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL; | 231 | audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL; |
207 | audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN; | 232 | audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN; |
208 | 233 | ||
209 | if (pdata->codec) { | 234 | if (twl4030_audio_has_codec(pdata, node)) { |
210 | cell = &audio->cells[childs]; | 235 | cell = &audio->cells[childs]; |
211 | cell->name = "twl4030-codec"; | 236 | cell->name = "twl4030-codec"; |
212 | cell->platform_data = pdata->codec; | 237 | if (pdata) { |
213 | cell->pdata_size = sizeof(*pdata->codec); | 238 | cell->platform_data = pdata->codec; |
239 | cell->pdata_size = sizeof(*pdata->codec); | ||
240 | } | ||
214 | childs++; | 241 | childs++; |
215 | } | 242 | } |
216 | if (pdata->vibra) { | 243 | if (twl4030_audio_has_vibra(pdata, node)) { |
217 | cell = &audio->cells[childs]; | 244 | cell = &audio->cells[childs]; |
218 | cell->name = "twl4030-vibra"; | 245 | cell->name = "twl4030-vibra"; |
219 | cell->platform_data = pdata->vibra; | 246 | if (pdata) { |
220 | cell->pdata_size = sizeof(*pdata->vibra); | 247 | cell->platform_data = pdata->vibra; |
248 | cell->pdata_size = sizeof(*pdata->vibra); | ||
249 | } | ||
221 | childs++; | 250 | childs++; |
222 | } | 251 | } |
223 | 252 | ||
253 | platform_set_drvdata(pdev, audio); | ||
254 | twl4030_audio_dev = pdev; | ||
255 | |||
224 | if (childs) | 256 | if (childs) |
225 | ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, | 257 | ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, |
226 | childs, NULL, 0, NULL); | 258 | childs, NULL, 0, NULL); |
@@ -229,39 +261,42 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) | |||
229 | ret = -ENODEV; | 261 | ret = -ENODEV; |
230 | } | 262 | } |
231 | 263 | ||
232 | if (!ret) | 264 | if (ret) { |
233 | return 0; | 265 | platform_set_drvdata(pdev, NULL); |
266 | twl4030_audio_dev = NULL; | ||
267 | } | ||
234 | 268 | ||
235 | platform_set_drvdata(pdev, NULL); | ||
236 | kfree(audio); | ||
237 | twl4030_audio_dev = NULL; | ||
238 | return ret; | 269 | return ret; |
239 | } | 270 | } |
240 | 271 | ||
241 | static int __devexit twl4030_audio_remove(struct platform_device *pdev) | 272 | static int __devexit twl4030_audio_remove(struct platform_device *pdev) |
242 | { | 273 | { |
243 | struct twl4030_audio *audio = platform_get_drvdata(pdev); | ||
244 | |||
245 | mfd_remove_devices(&pdev->dev); | 274 | mfd_remove_devices(&pdev->dev); |
246 | platform_set_drvdata(pdev, NULL); | 275 | platform_set_drvdata(pdev, NULL); |
247 | kfree(audio); | ||
248 | twl4030_audio_dev = NULL; | 276 | twl4030_audio_dev = NULL; |
249 | 277 | ||
250 | return 0; | 278 | return 0; |
251 | } | 279 | } |
252 | 280 | ||
253 | MODULE_ALIAS("platform:twl4030-audio"); | 281 | static const struct of_device_id twl4030_audio_of_match[] = { |
282 | {.compatible = "ti,twl4030-audio", }, | ||
283 | { }, | ||
284 | }; | ||
285 | MODULE_DEVICE_TABLE(of, twl4030_audio_of_match); | ||
254 | 286 | ||
255 | static struct platform_driver twl4030_audio_driver = { | 287 | static struct platform_driver twl4030_audio_driver = { |
256 | .probe = twl4030_audio_probe, | ||
257 | .remove = __devexit_p(twl4030_audio_remove), | ||
258 | .driver = { | 288 | .driver = { |
259 | .owner = THIS_MODULE, | 289 | .owner = THIS_MODULE, |
260 | .name = "twl4030-audio", | 290 | .name = "twl4030-audio", |
291 | .of_match_table = twl4030_audio_of_match, | ||
261 | }, | 292 | }, |
293 | .probe = twl4030_audio_probe, | ||
294 | .remove = __devexit_p(twl4030_audio_remove), | ||
262 | }; | 295 | }; |
263 | 296 | ||
264 | module_platform_driver(twl4030_audio_driver); | 297 | module_platform_driver(twl4030_audio_driver); |
265 | 298 | ||
266 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); | 299 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); |
300 | MODULE_DESCRIPTION("TWL4030 audio block MFD driver"); | ||
267 | MODULE_LICENSE("GPL"); | 301 | MODULE_LICENSE("GPL"); |
302 | MODULE_ALIAS("platform:twl4030-audio"); | ||
diff --git a/drivers/mfd/twl6030-pwm.c b/drivers/mfd/twl6030-pwm.c deleted file mode 100644 index e8fee147678d..000000000000 --- a/drivers/mfd/twl6030-pwm.c +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * twl6030_pwm.c | ||
3 | * Driver for PHOENIX (TWL6030) Pulse Width Modulator | ||
4 | * | ||
5 | * Copyright (C) 2010 Texas Instruments | ||
6 | * Author: Hemanth V <hemanthv@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/i2c/twl.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #define LED_PWM_CTRL1 0xF4 | ||
27 | #define LED_PWM_CTRL2 0xF5 | ||
28 | |||
29 | /* Max value for CTRL1 register */ | ||
30 | #define PWM_CTRL1_MAX 255 | ||
31 | |||
32 | /* Pull down disable */ | ||
33 | #define PWM_CTRL2_DIS_PD (1 << 6) | ||
34 | |||
35 | /* Current control 2.5 milli Amps */ | ||
36 | #define PWM_CTRL2_CURR_02 (2 << 4) | ||
37 | |||
38 | /* LED supply source */ | ||
39 | #define PWM_CTRL2_SRC_VAC (1 << 2) | ||
40 | |||
41 | /* LED modes */ | ||
42 | #define PWM_CTRL2_MODE_HW (0 << 0) | ||
43 | #define PWM_CTRL2_MODE_SW (1 << 0) | ||
44 | #define PWM_CTRL2_MODE_DIS (2 << 0) | ||
45 | |||
46 | #define PWM_CTRL2_MODE_MASK 0x3 | ||
47 | |||
48 | struct pwm_device { | ||
49 | const char *label; | ||
50 | unsigned int pwm_id; | ||
51 | }; | ||
52 | |||
53 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | ||
54 | { | ||
55 | u8 duty_cycle; | ||
56 | int ret; | ||
57 | |||
58 | if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) | ||
59 | return -EINVAL; | ||
60 | |||
61 | duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; | ||
62 | |||
63 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); | ||
64 | |||
65 | if (ret < 0) { | ||
66 | pr_err("%s: Failed to configure PWM, Error %d\n", | ||
67 | pwm->label, ret); | ||
68 | return ret; | ||
69 | } | ||
70 | return 0; | ||
71 | } | ||
72 | EXPORT_SYMBOL(pwm_config); | ||
73 | |||
74 | int pwm_enable(struct pwm_device *pwm) | ||
75 | { | ||
76 | u8 val; | ||
77 | int ret; | ||
78 | |||
79 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); | ||
80 | if (ret < 0) { | ||
81 | pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | /* Change mode to software control */ | ||
86 | val &= ~PWM_CTRL2_MODE_MASK; | ||
87 | val |= PWM_CTRL2_MODE_SW; | ||
88 | |||
89 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); | ||
90 | if (ret < 0) { | ||
91 | pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); | ||
96 | return 0; | ||
97 | } | ||
98 | EXPORT_SYMBOL(pwm_enable); | ||
99 | |||
100 | void pwm_disable(struct pwm_device *pwm) | ||
101 | { | ||
102 | u8 val; | ||
103 | int ret; | ||
104 | |||
105 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); | ||
106 | if (ret < 0) { | ||
107 | pr_err("%s: Failed to disable PWM, Error %d\n", | ||
108 | pwm->label, ret); | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | val &= ~PWM_CTRL2_MODE_MASK; | ||
113 | val |= PWM_CTRL2_MODE_HW; | ||
114 | |||
115 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); | ||
116 | if (ret < 0) { | ||
117 | pr_err("%s: Failed to disable PWM, Error %d\n", | ||
118 | pwm->label, ret); | ||
119 | return; | ||
120 | } | ||
121 | return; | ||
122 | } | ||
123 | EXPORT_SYMBOL(pwm_disable); | ||
124 | |||
125 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
126 | { | ||
127 | u8 val; | ||
128 | int ret; | ||
129 | struct pwm_device *pwm; | ||
130 | |||
131 | pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); | ||
132 | if (pwm == NULL) { | ||
133 | pr_err("%s: failed to allocate memory\n", label); | ||
134 | return NULL; | ||
135 | } | ||
136 | |||
137 | pwm->label = label; | ||
138 | pwm->pwm_id = pwm_id; | ||
139 | |||
140 | /* Configure PWM */ | ||
141 | val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | | ||
142 | PWM_CTRL2_MODE_HW; | ||
143 | |||
144 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); | ||
145 | |||
146 | if (ret < 0) { | ||
147 | pr_err("%s: Failed to configure PWM, Error %d\n", | ||
148 | pwm->label, ret); | ||
149 | |||
150 | kfree(pwm); | ||
151 | return NULL; | ||
152 | } | ||
153 | |||
154 | return pwm; | ||
155 | } | ||
156 | EXPORT_SYMBOL(pwm_request); | ||
157 | |||
158 | void pwm_free(struct pwm_device *pwm) | ||
159 | { | ||
160 | pwm_disable(pwm); | ||
161 | kfree(pwm); | ||
162 | } | ||
163 | EXPORT_SYMBOL(pwm_free); | ||
164 | |||
165 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 3dca5c195a20..3f2a1cf02fc0 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c | |||
@@ -584,7 +584,7 @@ static int __devinit twl6040_probe(struct i2c_client *client, | |||
584 | goto irq_init_err; | 584 | goto irq_init_err; |
585 | 585 | ||
586 | ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, | 586 | ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, |
587 | NULL, twl6040_naudint_handler, 0, | 587 | NULL, twl6040_naudint_handler, IRQF_ONESHOT, |
588 | "twl6040_irq_ready", twl6040); | 588 | "twl6040_irq_ready", twl6040); |
589 | if (ret) { | 589 | if (ret) { |
590 | dev_err(twl6040->dev, "READY IRQ request failed: %d\n", | 590 | dev_err(twl6040->dev, "READY IRQ request failed: %d\n", |
@@ -631,6 +631,21 @@ static int __devinit twl6040_probe(struct i2c_client *client, | |||
631 | children++; | 631 | children++; |
632 | } | 632 | } |
633 | 633 | ||
634 | /* | ||
635 | * Enable the GPO driver in the following cases: | ||
636 | * DT booted kernel or legacy boot with valid gpo platform_data | ||
637 | */ | ||
638 | if (!pdata || (pdata && pdata->gpo)) { | ||
639 | cell = &twl6040->cells[children]; | ||
640 | cell->name = "twl6040-gpo"; | ||
641 | |||
642 | if (pdata) { | ||
643 | cell->platform_data = pdata->gpo; | ||
644 | cell->pdata_size = sizeof(*pdata->gpo); | ||
645 | } | ||
646 | children++; | ||
647 | } | ||
648 | |||
634 | ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, | 649 | ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, |
635 | NULL, 0, NULL); | 650 | NULL, 0, NULL); |
636 | if (ret) | 651 | if (ret) |
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index bd8782c8896b..adda6b10b90d 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c | |||
@@ -133,15 +133,109 @@ static const struct reg_default wm5110_reva_patch[] = { | |||
133 | { 0x209, 0x002A }, | 133 | { 0x209, 0x002A }, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static const struct reg_default wm5110_revb_patch[] = { | ||
137 | { 0x80, 0x3 }, | ||
138 | { 0x36e, 0x0210 }, | ||
139 | { 0x370, 0x0210 }, | ||
140 | { 0x372, 0x0210 }, | ||
141 | { 0x374, 0x0210 }, | ||
142 | { 0x376, 0x0210 }, | ||
143 | { 0x378, 0x0210 }, | ||
144 | { 0x36d, 0x0028 }, | ||
145 | { 0x36f, 0x0028 }, | ||
146 | { 0x371, 0x0028 }, | ||
147 | { 0x373, 0x0028 }, | ||
148 | { 0x375, 0x0028 }, | ||
149 | { 0x377, 0x0028 }, | ||
150 | { 0x280, 0x2002 }, | ||
151 | { 0x44, 0x20 }, | ||
152 | { 0x45, 0x40 }, | ||
153 | { 0x46, 0x60 }, | ||
154 | { 0x47, 0x80 }, | ||
155 | { 0x48, 0xa0 }, | ||
156 | { 0x51, 0x13 }, | ||
157 | { 0x52, 0x33 }, | ||
158 | { 0x53, 0x53 }, | ||
159 | { 0x54, 0x73 }, | ||
160 | { 0x55, 0x93 }, | ||
161 | { 0x56, 0xb3 }, | ||
162 | { 0xc30, 0x3e3e }, | ||
163 | { 0xc31, 0x3e }, | ||
164 | { 0xc32, 0x3e3e }, | ||
165 | { 0xc33, 0x3e3e }, | ||
166 | { 0xc34, 0x3e3e }, | ||
167 | { 0xc35, 0x3e3e }, | ||
168 | { 0xc36, 0x3e3e }, | ||
169 | { 0xc37, 0x3e3e }, | ||
170 | { 0xc38, 0x3e3e }, | ||
171 | { 0xc39, 0x3e3e }, | ||
172 | { 0xc3a, 0x3e3e }, | ||
173 | { 0xc3b, 0x3e3e }, | ||
174 | { 0xc3c, 0x3e }, | ||
175 | { 0x201, 0x18a5 }, | ||
176 | { 0x202, 0x4100 }, | ||
177 | { 0x460, 0x0c40 }, | ||
178 | { 0x461, 0x8000 }, | ||
179 | { 0x462, 0x0c41 }, | ||
180 | { 0x463, 0x4820 }, | ||
181 | { 0x464, 0x0c41 }, | ||
182 | { 0x465, 0x4040 }, | ||
183 | { 0x466, 0x0841 }, | ||
184 | { 0x467, 0x3940 }, | ||
185 | { 0x468, 0x0841 }, | ||
186 | { 0x469, 0x2030 }, | ||
187 | { 0x46a, 0x0842 }, | ||
188 | { 0x46b, 0x1990 }, | ||
189 | { 0x46c, 0x08c2 }, | ||
190 | { 0x46d, 0x1450 }, | ||
191 | { 0x46e, 0x08c6 }, | ||
192 | { 0x46f, 0x1020 }, | ||
193 | { 0x470, 0x08c6 }, | ||
194 | { 0x471, 0x0cd0 }, | ||
195 | { 0x472, 0x08c6 }, | ||
196 | { 0x473, 0x0a30 }, | ||
197 | { 0x474, 0x0442 }, | ||
198 | { 0x475, 0x0660 }, | ||
199 | { 0x476, 0x0446 }, | ||
200 | { 0x477, 0x0510 }, | ||
201 | { 0x478, 0x04c6 }, | ||
202 | { 0x479, 0x0400 }, | ||
203 | { 0x47a, 0x04ce }, | ||
204 | { 0x47b, 0x0330 }, | ||
205 | { 0x47c, 0x05df }, | ||
206 | { 0x47d, 0x0001 }, | ||
207 | { 0x47e, 0x07ff }, | ||
208 | { 0x2db, 0x0a00 }, | ||
209 | { 0x2dd, 0x0023 }, | ||
210 | { 0x2df, 0x0102 }, | ||
211 | { 0x2ef, 0x924 }, | ||
212 | { 0x2f0, 0x924 }, | ||
213 | { 0x2f1, 0x924 }, | ||
214 | { 0x2f2, 0x924 }, | ||
215 | { 0x2f3, 0x924 }, | ||
216 | { 0x2f4, 0x924 }, | ||
217 | { 0x2eb, 0x60 }, | ||
218 | { 0x2ec, 0x60 }, | ||
219 | { 0x2ed, 0x60 }, | ||
220 | { 0x4f2, 0x33e }, | ||
221 | { 0x458, 0x0000 }, | ||
222 | { 0x15a, 0x0003 }, | ||
223 | { 0x80, 0x0 }, | ||
224 | }; | ||
225 | |||
136 | /* We use a function so we can use ARRAY_SIZE() */ | 226 | /* We use a function so we can use ARRAY_SIZE() */ |
137 | int wm5110_patch(struct arizona *arizona) | 227 | int wm5110_patch(struct arizona *arizona) |
138 | { | 228 | { |
139 | switch (arizona->rev) { | 229 | switch (arizona->rev) { |
140 | case 0: | 230 | case 0: |
141 | case 1: | ||
142 | return regmap_register_patch(arizona->regmap, | 231 | return regmap_register_patch(arizona->regmap, |
143 | wm5110_reva_patch, | 232 | wm5110_reva_patch, |
144 | ARRAY_SIZE(wm5110_reva_patch)); | 233 | ARRAY_SIZE(wm5110_reva_patch)); |
234 | case 1: | ||
235 | return regmap_register_patch(arizona->regmap, | ||
236 | wm5110_revb_patch, | ||
237 | ARRAY_SIZE(wm5110_revb_patch)); | ||
238 | |||
145 | default: | 239 | default: |
146 | return 0; | 240 | return 0; |
147 | } | 241 | } |
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 301731035940..521340a708d3 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
@@ -614,18 +614,11 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, | |||
614 | } | 614 | } |
615 | EXPORT_SYMBOL_GPL(wm831x_set_bits); | 615 | EXPORT_SYMBOL_GPL(wm831x_set_bits); |
616 | 616 | ||
617 | static struct resource wm831x_io_parent = { | ||
618 | .start = 0, | ||
619 | .end = 0xffffffff, | ||
620 | .flags = IORESOURCE_IO, | ||
621 | }; | ||
622 | |||
623 | static struct resource wm831x_dcdc1_resources[] = { | 617 | static struct resource wm831x_dcdc1_resources[] = { |
624 | { | 618 | { |
625 | .parent = &wm831x_io_parent, | ||
626 | .start = WM831X_DC1_CONTROL_1, | 619 | .start = WM831X_DC1_CONTROL_1, |
627 | .end = WM831X_DC1_DVS_CONTROL, | 620 | .end = WM831X_DC1_DVS_CONTROL, |
628 | .flags = IORESOURCE_IO, | 621 | .flags = IORESOURCE_REG, |
629 | }, | 622 | }, |
630 | { | 623 | { |
631 | .name = "UV", | 624 | .name = "UV", |
@@ -644,10 +637,9 @@ static struct resource wm831x_dcdc1_resources[] = { | |||
644 | 637 | ||
645 | static struct resource wm831x_dcdc2_resources[] = { | 638 | static struct resource wm831x_dcdc2_resources[] = { |
646 | { | 639 | { |
647 | .parent = &wm831x_io_parent, | ||
648 | .start = WM831X_DC2_CONTROL_1, | 640 | .start = WM831X_DC2_CONTROL_1, |
649 | .end = WM831X_DC2_DVS_CONTROL, | 641 | .end = WM831X_DC2_DVS_CONTROL, |
650 | .flags = IORESOURCE_IO, | 642 | .flags = IORESOURCE_REG, |
651 | }, | 643 | }, |
652 | { | 644 | { |
653 | .name = "UV", | 645 | .name = "UV", |
@@ -665,10 +657,9 @@ static struct resource wm831x_dcdc2_resources[] = { | |||
665 | 657 | ||
666 | static struct resource wm831x_dcdc3_resources[] = { | 658 | static struct resource wm831x_dcdc3_resources[] = { |
667 | { | 659 | { |
668 | .parent = &wm831x_io_parent, | ||
669 | .start = WM831X_DC3_CONTROL_1, | 660 | .start = WM831X_DC3_CONTROL_1, |
670 | .end = WM831X_DC3_SLEEP_CONTROL, | 661 | .end = WM831X_DC3_SLEEP_CONTROL, |
671 | .flags = IORESOURCE_IO, | 662 | .flags = IORESOURCE_REG, |
672 | }, | 663 | }, |
673 | { | 664 | { |
674 | .name = "UV", | 665 | .name = "UV", |
@@ -680,10 +671,9 @@ static struct resource wm831x_dcdc3_resources[] = { | |||
680 | 671 | ||
681 | static struct resource wm831x_dcdc4_resources[] = { | 672 | static struct resource wm831x_dcdc4_resources[] = { |
682 | { | 673 | { |
683 | .parent = &wm831x_io_parent, | ||
684 | .start = WM831X_DC4_CONTROL, | 674 | .start = WM831X_DC4_CONTROL, |
685 | .end = WM831X_DC4_SLEEP_CONTROL, | 675 | .end = WM831X_DC4_SLEEP_CONTROL, |
686 | .flags = IORESOURCE_IO, | 676 | .flags = IORESOURCE_REG, |
687 | }, | 677 | }, |
688 | { | 678 | { |
689 | .name = "UV", | 679 | .name = "UV", |
@@ -695,10 +685,9 @@ static struct resource wm831x_dcdc4_resources[] = { | |||
695 | 685 | ||
696 | static struct resource wm8320_dcdc4_buck_resources[] = { | 686 | static struct resource wm8320_dcdc4_buck_resources[] = { |
697 | { | 687 | { |
698 | .parent = &wm831x_io_parent, | ||
699 | .start = WM831X_DC4_CONTROL, | 688 | .start = WM831X_DC4_CONTROL, |
700 | .end = WM832X_DC4_SLEEP_CONTROL, | 689 | .end = WM832X_DC4_SLEEP_CONTROL, |
701 | .flags = IORESOURCE_IO, | 690 | .flags = IORESOURCE_REG, |
702 | }, | 691 | }, |
703 | { | 692 | { |
704 | .name = "UV", | 693 | .name = "UV", |
@@ -718,10 +707,9 @@ static struct resource wm831x_gpio_resources[] = { | |||
718 | 707 | ||
719 | static struct resource wm831x_isink1_resources[] = { | 708 | static struct resource wm831x_isink1_resources[] = { |
720 | { | 709 | { |
721 | .parent = &wm831x_io_parent, | ||
722 | .start = WM831X_CURRENT_SINK_1, | 710 | .start = WM831X_CURRENT_SINK_1, |
723 | .end = WM831X_CURRENT_SINK_1, | 711 | .end = WM831X_CURRENT_SINK_1, |
724 | .flags = IORESOURCE_IO, | 712 | .flags = IORESOURCE_REG, |
725 | }, | 713 | }, |
726 | { | 714 | { |
727 | .start = WM831X_IRQ_CS1, | 715 | .start = WM831X_IRQ_CS1, |
@@ -732,10 +720,9 @@ static struct resource wm831x_isink1_resources[] = { | |||
732 | 720 | ||
733 | static struct resource wm831x_isink2_resources[] = { | 721 | static struct resource wm831x_isink2_resources[] = { |
734 | { | 722 | { |
735 | .parent = &wm831x_io_parent, | ||
736 | .start = WM831X_CURRENT_SINK_2, | 723 | .start = WM831X_CURRENT_SINK_2, |
737 | .end = WM831X_CURRENT_SINK_2, | 724 | .end = WM831X_CURRENT_SINK_2, |
738 | .flags = IORESOURCE_IO, | 725 | .flags = IORESOURCE_REG, |
739 | }, | 726 | }, |
740 | { | 727 | { |
741 | .start = WM831X_IRQ_CS2, | 728 | .start = WM831X_IRQ_CS2, |
@@ -746,10 +733,9 @@ static struct resource wm831x_isink2_resources[] = { | |||
746 | 733 | ||
747 | static struct resource wm831x_ldo1_resources[] = { | 734 | static struct resource wm831x_ldo1_resources[] = { |
748 | { | 735 | { |
749 | .parent = &wm831x_io_parent, | ||
750 | .start = WM831X_LDO1_CONTROL, | 736 | .start = WM831X_LDO1_CONTROL, |
751 | .end = WM831X_LDO1_SLEEP_CONTROL, | 737 | .end = WM831X_LDO1_SLEEP_CONTROL, |
752 | .flags = IORESOURCE_IO, | 738 | .flags = IORESOURCE_REG, |
753 | }, | 739 | }, |
754 | { | 740 | { |
755 | .name = "UV", | 741 | .name = "UV", |
@@ -761,10 +747,9 @@ static struct resource wm831x_ldo1_resources[] = { | |||
761 | 747 | ||
762 | static struct resource wm831x_ldo2_resources[] = { | 748 | static struct resource wm831x_ldo2_resources[] = { |
763 | { | 749 | { |
764 | .parent = &wm831x_io_parent, | ||
765 | .start = WM831X_LDO2_CONTROL, | 750 | .start = WM831X_LDO2_CONTROL, |
766 | .end = WM831X_LDO2_SLEEP_CONTROL, | 751 | .end = WM831X_LDO2_SLEEP_CONTROL, |
767 | .flags = IORESOURCE_IO, | 752 | .flags = IORESOURCE_REG, |
768 | }, | 753 | }, |
769 | { | 754 | { |
770 | .name = "UV", | 755 | .name = "UV", |
@@ -776,10 +761,9 @@ static struct resource wm831x_ldo2_resources[] = { | |||
776 | 761 | ||
777 | static struct resource wm831x_ldo3_resources[] = { | 762 | static struct resource wm831x_ldo3_resources[] = { |
778 | { | 763 | { |
779 | .parent = &wm831x_io_parent, | ||
780 | .start = WM831X_LDO3_CONTROL, | 764 | .start = WM831X_LDO3_CONTROL, |
781 | .end = WM831X_LDO3_SLEEP_CONTROL, | 765 | .end = WM831X_LDO3_SLEEP_CONTROL, |
782 | .flags = IORESOURCE_IO, | 766 | .flags = IORESOURCE_REG, |
783 | }, | 767 | }, |
784 | { | 768 | { |
785 | .name = "UV", | 769 | .name = "UV", |
@@ -791,10 +775,9 @@ static struct resource wm831x_ldo3_resources[] = { | |||
791 | 775 | ||
792 | static struct resource wm831x_ldo4_resources[] = { | 776 | static struct resource wm831x_ldo4_resources[] = { |
793 | { | 777 | { |
794 | .parent = &wm831x_io_parent, | ||
795 | .start = WM831X_LDO4_CONTROL, | 778 | .start = WM831X_LDO4_CONTROL, |
796 | .end = WM831X_LDO4_SLEEP_CONTROL, | 779 | .end = WM831X_LDO4_SLEEP_CONTROL, |
797 | .flags = IORESOURCE_IO, | 780 | .flags = IORESOURCE_REG, |
798 | }, | 781 | }, |
799 | { | 782 | { |
800 | .name = "UV", | 783 | .name = "UV", |
@@ -806,10 +789,9 @@ static struct resource wm831x_ldo4_resources[] = { | |||
806 | 789 | ||
807 | static struct resource wm831x_ldo5_resources[] = { | 790 | static struct resource wm831x_ldo5_resources[] = { |
808 | { | 791 | { |
809 | .parent = &wm831x_io_parent, | ||
810 | .start = WM831X_LDO5_CONTROL, | 792 | .start = WM831X_LDO5_CONTROL, |
811 | .end = WM831X_LDO5_SLEEP_CONTROL, | 793 | .end = WM831X_LDO5_SLEEP_CONTROL, |
812 | .flags = IORESOURCE_IO, | 794 | .flags = IORESOURCE_REG, |
813 | }, | 795 | }, |
814 | { | 796 | { |
815 | .name = "UV", | 797 | .name = "UV", |
@@ -821,10 +803,9 @@ static struct resource wm831x_ldo5_resources[] = { | |||
821 | 803 | ||
822 | static struct resource wm831x_ldo6_resources[] = { | 804 | static struct resource wm831x_ldo6_resources[] = { |
823 | { | 805 | { |
824 | .parent = &wm831x_io_parent, | ||
825 | .start = WM831X_LDO6_CONTROL, | 806 | .start = WM831X_LDO6_CONTROL, |
826 | .end = WM831X_LDO6_SLEEP_CONTROL, | 807 | .end = WM831X_LDO6_SLEEP_CONTROL, |
827 | .flags = IORESOURCE_IO, | 808 | .flags = IORESOURCE_REG, |
828 | }, | 809 | }, |
829 | { | 810 | { |
830 | .name = "UV", | 811 | .name = "UV", |
@@ -836,10 +817,9 @@ static struct resource wm831x_ldo6_resources[] = { | |||
836 | 817 | ||
837 | static struct resource wm831x_ldo7_resources[] = { | 818 | static struct resource wm831x_ldo7_resources[] = { |
838 | { | 819 | { |
839 | .parent = &wm831x_io_parent, | ||
840 | .start = WM831X_LDO7_CONTROL, | 820 | .start = WM831X_LDO7_CONTROL, |
841 | .end = WM831X_LDO7_SLEEP_CONTROL, | 821 | .end = WM831X_LDO7_SLEEP_CONTROL, |
842 | .flags = IORESOURCE_IO, | 822 | .flags = IORESOURCE_REG, |
843 | }, | 823 | }, |
844 | { | 824 | { |
845 | .name = "UV", | 825 | .name = "UV", |
@@ -851,10 +831,9 @@ static struct resource wm831x_ldo7_resources[] = { | |||
851 | 831 | ||
852 | static struct resource wm831x_ldo8_resources[] = { | 832 | static struct resource wm831x_ldo8_resources[] = { |
853 | { | 833 | { |
854 | .parent = &wm831x_io_parent, | ||
855 | .start = WM831X_LDO8_CONTROL, | 834 | .start = WM831X_LDO8_CONTROL, |
856 | .end = WM831X_LDO8_SLEEP_CONTROL, | 835 | .end = WM831X_LDO8_SLEEP_CONTROL, |
857 | .flags = IORESOURCE_IO, | 836 | .flags = IORESOURCE_REG, |
858 | }, | 837 | }, |
859 | { | 838 | { |
860 | .name = "UV", | 839 | .name = "UV", |
@@ -866,10 +845,9 @@ static struct resource wm831x_ldo8_resources[] = { | |||
866 | 845 | ||
867 | static struct resource wm831x_ldo9_resources[] = { | 846 | static struct resource wm831x_ldo9_resources[] = { |
868 | { | 847 | { |
869 | .parent = &wm831x_io_parent, | ||
870 | .start = WM831X_LDO9_CONTROL, | 848 | .start = WM831X_LDO9_CONTROL, |
871 | .end = WM831X_LDO9_SLEEP_CONTROL, | 849 | .end = WM831X_LDO9_SLEEP_CONTROL, |
872 | .flags = IORESOURCE_IO, | 850 | .flags = IORESOURCE_REG, |
873 | }, | 851 | }, |
874 | { | 852 | { |
875 | .name = "UV", | 853 | .name = "UV", |
@@ -881,10 +859,9 @@ static struct resource wm831x_ldo9_resources[] = { | |||
881 | 859 | ||
882 | static struct resource wm831x_ldo10_resources[] = { | 860 | static struct resource wm831x_ldo10_resources[] = { |
883 | { | 861 | { |
884 | .parent = &wm831x_io_parent, | ||
885 | .start = WM831X_LDO10_CONTROL, | 862 | .start = WM831X_LDO10_CONTROL, |
886 | .end = WM831X_LDO10_SLEEP_CONTROL, | 863 | .end = WM831X_LDO10_SLEEP_CONTROL, |
887 | .flags = IORESOURCE_IO, | 864 | .flags = IORESOURCE_REG, |
888 | }, | 865 | }, |
889 | { | 866 | { |
890 | .name = "UV", | 867 | .name = "UV", |
@@ -896,10 +873,9 @@ static struct resource wm831x_ldo10_resources[] = { | |||
896 | 873 | ||
897 | static struct resource wm831x_ldo11_resources[] = { | 874 | static struct resource wm831x_ldo11_resources[] = { |
898 | { | 875 | { |
899 | .parent = &wm831x_io_parent, | ||
900 | .start = WM831X_LDO11_ON_CONTROL, | 876 | .start = WM831X_LDO11_ON_CONTROL, |
901 | .end = WM831X_LDO11_SLEEP_CONTROL, | 877 | .end = WM831X_LDO11_SLEEP_CONTROL, |
902 | .flags = IORESOURCE_IO, | 878 | .flags = IORESOURCE_REG, |
903 | }, | 879 | }, |
904 | }; | 880 | }; |
905 | 881 | ||
@@ -998,19 +974,17 @@ static struct resource wm831x_rtc_resources[] = { | |||
998 | 974 | ||
999 | static struct resource wm831x_status1_resources[] = { | 975 | static struct resource wm831x_status1_resources[] = { |
1000 | { | 976 | { |
1001 | .parent = &wm831x_io_parent, | ||
1002 | .start = WM831X_STATUS_LED_1, | 977 | .start = WM831X_STATUS_LED_1, |
1003 | .end = WM831X_STATUS_LED_1, | 978 | .end = WM831X_STATUS_LED_1, |
1004 | .flags = IORESOURCE_IO, | 979 | .flags = IORESOURCE_REG, |
1005 | }, | 980 | }, |
1006 | }; | 981 | }; |
1007 | 982 | ||
1008 | static struct resource wm831x_status2_resources[] = { | 983 | static struct resource wm831x_status2_resources[] = { |
1009 | { | 984 | { |
1010 | .parent = &wm831x_io_parent, | ||
1011 | .start = WM831X_STATUS_LED_2, | 985 | .start = WM831X_STATUS_LED_2, |
1012 | .end = WM831X_STATUS_LED_2, | 986 | .end = WM831X_STATUS_LED_2, |
1013 | .flags = IORESOURCE_IO, | 987 | .flags = IORESOURCE_REG, |
1014 | }, | 988 | }, |
1015 | }; | 989 | }; |
1016 | 990 | ||
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 2febf88cfce8..3d6d9beb18d4 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
@@ -390,7 +390,7 @@ static const __devinitdata struct reg_default wm8958_reva_patch[] = { | |||
390 | 390 | ||
391 | static const __devinitdata struct reg_default wm1811_reva_patch[] = { | 391 | static const __devinitdata struct reg_default wm1811_reva_patch[] = { |
392 | { 0x102, 0x3 }, | 392 | { 0x102, 0x3 }, |
393 | { 0x56, 0x7 }, | 393 | { 0x56, 0xc07 }, |
394 | { 0x5d, 0x7e }, | 394 | { 0x5d, 0x7e }, |
395 | { 0x5e, 0x0 }, | 395 | { 0x5e, 0x0 }, |
396 | { 0x102, 0x0 }, | 396 | { 0x102, 0x0 }, |
diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c index 52e9e2944940..2fbce9c5950b 100644 --- a/drivers/mfd/wm8994-regmap.c +++ b/drivers/mfd/wm8994-regmap.c | |||
@@ -1136,7 +1136,7 @@ static bool wm1811_volatile_register(struct device *dev, unsigned int reg) | |||
1136 | 1136 | ||
1137 | switch (reg) { | 1137 | switch (reg) { |
1138 | case WM8994_GPIO_6: | 1138 | case WM8994_GPIO_6: |
1139 | if (wm8994->revision > 1) | 1139 | if (wm8994->cust_id > 1 || wm8994->revision > 1) |
1140 | return true; | 1140 | return true; |
1141 | else | 1141 | else |
1142 | return false; | 1142 | return false; |