diff options
Diffstat (limited to 'drivers/mfd/88pm860x-core.c')
-rw-r--r-- | drivers/mfd/88pm860x-core.c | 805 |
1 files changed, 567 insertions, 238 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"); |