diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/misc/twl6040-vibra.c | 21 | ||||
-rw-r--r-- | drivers/mfd/twl6040-core.c | 67 | ||||
-rw-r--r-- | drivers/mfd/wm8994-core.c | 27 | ||||
-rw-r--r-- | drivers/regulator/core.c | 64 | ||||
-rw-r--r-- | drivers/regulator/wm8994-regulator.c | 13 |
5 files changed, 161 insertions, 31 deletions
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 23855e12a30b..ad153a417eed 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c | |||
@@ -74,12 +74,12 @@ static irqreturn_t twl6040_vib_irq_handler(int irq, void *data) | |||
74 | if (status & TWL6040_VIBLOCDET) { | 74 | if (status & TWL6040_VIBLOCDET) { |
75 | dev_warn(info->dev, "Left Vibrator overcurrent detected\n"); | 75 | dev_warn(info->dev, "Left Vibrator overcurrent detected\n"); |
76 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, | 76 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, |
77 | TWL6040_VIBENAL); | 77 | TWL6040_VIBENA); |
78 | } | 78 | } |
79 | if (status & TWL6040_VIBROCDET) { | 79 | if (status & TWL6040_VIBROCDET) { |
80 | dev_warn(info->dev, "Right Vibrator overcurrent detected\n"); | 80 | dev_warn(info->dev, "Right Vibrator overcurrent detected\n"); |
81 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, | 81 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, |
82 | TWL6040_VIBENAR); | 82 | TWL6040_VIBENA); |
83 | } | 83 | } |
84 | 84 | ||
85 | return IRQ_HANDLED; | 85 | return IRQ_HANDLED; |
@@ -97,23 +97,23 @@ static void twl6040_vibra_enable(struct vibra_info *info) | |||
97 | } | 97 | } |
98 | 98 | ||
99 | twl6040_power(info->twl6040, 1); | 99 | twl6040_power(info->twl6040, 1); |
100 | if (twl6040->rev <= TWL6040_REV_ES1_1) { | 100 | if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) { |
101 | /* | 101 | /* |
102 | * ERRATA: Disable overcurrent protection for at least | 102 | * ERRATA: Disable overcurrent protection for at least |
103 | * 3ms when enabling vibrator drivers to avoid false | 103 | * 3ms when enabling vibrator drivers to avoid false |
104 | * overcurrent detection | 104 | * overcurrent detection |
105 | */ | 105 | */ |
106 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, | 106 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, |
107 | TWL6040_VIBENAL | TWL6040_VIBCTRLL); | 107 | TWL6040_VIBENA | TWL6040_VIBCTRL); |
108 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, | 108 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, |
109 | TWL6040_VIBENAR | TWL6040_VIBCTRLR); | 109 | TWL6040_VIBENA | TWL6040_VIBCTRL); |
110 | usleep_range(3000, 3500); | 110 | usleep_range(3000, 3500); |
111 | } | 111 | } |
112 | 112 | ||
113 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, | 113 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, |
114 | TWL6040_VIBENAL); | 114 | TWL6040_VIBENA); |
115 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, | 115 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, |
116 | TWL6040_VIBENAR); | 116 | TWL6040_VIBENA); |
117 | 117 | ||
118 | info->enabled = true; | 118 | info->enabled = true; |
119 | } | 119 | } |
@@ -201,6 +201,13 @@ static int vibra_play(struct input_dev *input, void *data, | |||
201 | struct vibra_info *info = input_get_drvdata(input); | 201 | struct vibra_info *info = input_get_drvdata(input); |
202 | int ret; | 202 | int ret; |
203 | 203 | ||
204 | /* Do not allow effect, while the routing is set to use audio */ | ||
205 | ret = twl6040_get_vibralr_status(info->twl6040); | ||
206 | if (ret & TWL6040_VIBSEL) { | ||
207 | dev_info(&input->dev, "Vibra is configured for audio\n"); | ||
208 | return -EBUSY; | ||
209 | } | ||
210 | |||
204 | info->weak_speed = effect->u.rumble.weak_magnitude; | 211 | info->weak_speed = effect->u.rumble.weak_magnitude; |
205 | info->strong_speed = effect->u.rumble.strong_magnitude; | 212 | info->strong_speed = effect->u.rumble.strong_magnitude; |
206 | info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1; | 213 | info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1; |
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 24d436c2fe4a..268f80fd0439 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <linux/mfd/core.h> | 34 | #include <linux/mfd/core.h> |
35 | #include <linux/mfd/twl6040.h> | 35 | #include <linux/mfd/twl6040.h> |
36 | 36 | ||
37 | static struct platform_device *twl6040_dev; | 37 | #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1) |
38 | 38 | ||
39 | int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) | 39 | int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) |
40 | { | 40 | { |
@@ -42,10 +42,16 @@ int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) | |||
42 | u8 val = 0; | 42 | u8 val = 0; |
43 | 43 | ||
44 | mutex_lock(&twl6040->io_mutex); | 44 | mutex_lock(&twl6040->io_mutex); |
45 | ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); | 45 | /* Vibra control registers from cache */ |
46 | if (ret < 0) { | 46 | if (unlikely(reg == TWL6040_REG_VIBCTLL || |
47 | mutex_unlock(&twl6040->io_mutex); | 47 | reg == TWL6040_REG_VIBCTLR)) { |
48 | return ret; | 48 | val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)]; |
49 | } else { | ||
50 | ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); | ||
51 | if (ret < 0) { | ||
52 | mutex_unlock(&twl6040->io_mutex); | ||
53 | return ret; | ||
54 | } | ||
49 | } | 55 | } |
50 | mutex_unlock(&twl6040->io_mutex); | 56 | mutex_unlock(&twl6040->io_mutex); |
51 | 57 | ||
@@ -59,6 +65,9 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val) | |||
59 | 65 | ||
60 | mutex_lock(&twl6040->io_mutex); | 66 | mutex_lock(&twl6040->io_mutex); |
61 | ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); | 67 | ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); |
68 | /* Cache the vibra control registers */ | ||
69 | if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR) | ||
70 | twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val; | ||
62 | mutex_unlock(&twl6040->io_mutex); | 71 | mutex_unlock(&twl6040->io_mutex); |
63 | 72 | ||
64 | return ret; | 73 | return ret; |
@@ -203,11 +212,11 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data) | |||
203 | if (intid & TWL6040_THINT) { | 212 | if (intid & TWL6040_THINT) { |
204 | status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); | 213 | status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); |
205 | if (status & TWL6040_TSHUTDET) { | 214 | if (status & TWL6040_TSHUTDET) { |
206 | dev_warn(&twl6040_dev->dev, | 215 | dev_warn(twl6040->dev, |
207 | "Thermal shutdown, powering-off"); | 216 | "Thermal shutdown, powering-off"); |
208 | twl6040_power(twl6040, 0); | 217 | twl6040_power(twl6040, 0); |
209 | } else { | 218 | } else { |
210 | dev_warn(&twl6040_dev->dev, | 219 | dev_warn(twl6040->dev, |
211 | "Leaving thermal shutdown, powering-on"); | 220 | "Leaving thermal shutdown, powering-on"); |
212 | twl6040_power(twl6040, 1); | 221 | twl6040_power(twl6040, 1); |
213 | } | 222 | } |
@@ -227,7 +236,7 @@ static int twl6040_power_up_completion(struct twl6040 *twl6040, | |||
227 | if (!time_left) { | 236 | if (!time_left) { |
228 | intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); | 237 | intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); |
229 | if (!(intid & TWL6040_READYINT)) { | 238 | if (!(intid & TWL6040_READYINT)) { |
230 | dev_err(&twl6040_dev->dev, | 239 | dev_err(twl6040->dev, |
231 | "timeout waiting for READYINT\n"); | 240 | "timeout waiting for READYINT\n"); |
232 | return -ETIMEDOUT; | 241 | return -ETIMEDOUT; |
233 | } | 242 | } |
@@ -255,7 +264,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) | |||
255 | /* wait for power-up completion */ | 264 | /* wait for power-up completion */ |
256 | ret = twl6040_power_up_completion(twl6040, naudint); | 265 | ret = twl6040_power_up_completion(twl6040, naudint); |
257 | if (ret) { | 266 | if (ret) { |
258 | dev_err(&twl6040_dev->dev, | 267 | dev_err(twl6040->dev, |
259 | "automatic power-down failed\n"); | 268 | "automatic power-down failed\n"); |
260 | twl6040->power_count = 0; | 269 | twl6040->power_count = 0; |
261 | goto out; | 270 | goto out; |
@@ -264,7 +273,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) | |||
264 | /* use manual power-up sequence */ | 273 | /* use manual power-up sequence */ |
265 | ret = twl6040_power_up(twl6040); | 274 | ret = twl6040_power_up(twl6040); |
266 | if (ret) { | 275 | if (ret) { |
267 | dev_err(&twl6040_dev->dev, | 276 | dev_err(twl6040->dev, |
268 | "manual power-up failed\n"); | 277 | "manual power-up failed\n"); |
269 | twl6040->power_count = 0; | 278 | twl6040->power_count = 0; |
270 | goto out; | 279 | goto out; |
@@ -276,7 +285,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) | |||
276 | } else { | 285 | } else { |
277 | /* already powered-down */ | 286 | /* already powered-down */ |
278 | if (!twl6040->power_count) { | 287 | if (!twl6040->power_count) { |
279 | dev_err(&twl6040_dev->dev, | 288 | dev_err(twl6040->dev, |
280 | "device is already powered-off\n"); | 289 | "device is already powered-off\n"); |
281 | ret = -EPERM; | 290 | ret = -EPERM; |
282 | goto out; | 291 | goto out; |
@@ -326,7 +335,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, | |||
326 | lppllctl &= ~TWL6040_LPLLFIN; | 335 | lppllctl &= ~TWL6040_LPLLFIN; |
327 | break; | 336 | break; |
328 | default: | 337 | default: |
329 | dev_err(&twl6040_dev->dev, | 338 | dev_err(twl6040->dev, |
330 | "freq_out %d not supported\n", freq_out); | 339 | "freq_out %d not supported\n", freq_out); |
331 | ret = -EINVAL; | 340 | ret = -EINVAL; |
332 | goto pll_out; | 341 | goto pll_out; |
@@ -347,7 +356,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, | |||
347 | hppllctl); | 356 | hppllctl); |
348 | break; | 357 | break; |
349 | default: | 358 | default: |
350 | dev_err(&twl6040_dev->dev, | 359 | dev_err(twl6040->dev, |
351 | "freq_in %d not supported\n", freq_in); | 360 | "freq_in %d not supported\n", freq_in); |
352 | ret = -EINVAL; | 361 | ret = -EINVAL; |
353 | goto pll_out; | 362 | goto pll_out; |
@@ -356,7 +365,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, | |||
356 | case TWL6040_SYSCLK_SEL_HPPLL: | 365 | case TWL6040_SYSCLK_SEL_HPPLL: |
357 | /* high-performance PLL can provide only 19.2 MHz */ | 366 | /* high-performance PLL can provide only 19.2 MHz */ |
358 | if (freq_out != 19200000) { | 367 | if (freq_out != 19200000) { |
359 | dev_err(&twl6040_dev->dev, | 368 | dev_err(twl6040->dev, |
360 | "freq_out %d not supported\n", freq_out); | 369 | "freq_out %d not supported\n", freq_out); |
361 | ret = -EINVAL; | 370 | ret = -EINVAL; |
362 | goto pll_out; | 371 | goto pll_out; |
@@ -389,7 +398,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, | |||
389 | TWL6040_HPLLENA; | 398 | TWL6040_HPLLENA; |
390 | break; | 399 | break; |
391 | default: | 400 | default: |
392 | dev_err(&twl6040_dev->dev, | 401 | dev_err(twl6040->dev, |
393 | "freq_in %d not supported\n", freq_in); | 402 | "freq_in %d not supported\n", freq_in); |
394 | ret = -EINVAL; | 403 | ret = -EINVAL; |
395 | goto pll_out; | 404 | goto pll_out; |
@@ -406,7 +415,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, | |||
406 | twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); | 415 | twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); |
407 | break; | 416 | break; |
408 | default: | 417 | default: |
409 | dev_err(&twl6040_dev->dev, "unknown pll id %d\n", pll_id); | 418 | dev_err(twl6040->dev, "unknown pll id %d\n", pll_id); |
410 | ret = -EINVAL; | 419 | ret = -EINVAL; |
411 | goto pll_out; | 420 | goto pll_out; |
412 | } | 421 | } |
@@ -435,6 +444,18 @@ unsigned int twl6040_get_sysclk(struct twl6040 *twl6040) | |||
435 | } | 444 | } |
436 | EXPORT_SYMBOL(twl6040_get_sysclk); | 445 | EXPORT_SYMBOL(twl6040_get_sysclk); |
437 | 446 | ||
447 | /* Get the combined status of the vibra control register */ | ||
448 | int twl6040_get_vibralr_status(struct twl6040 *twl6040) | ||
449 | { | ||
450 | u8 status; | ||
451 | |||
452 | status = twl6040->vibra_ctrl_cache[0] | twl6040->vibra_ctrl_cache[1]; | ||
453 | status &= (TWL6040_VIBENA | TWL6040_VIBSEL); | ||
454 | |||
455 | return status; | ||
456 | } | ||
457 | EXPORT_SYMBOL(twl6040_get_vibralr_status); | ||
458 | |||
438 | static struct resource twl6040_vibra_rsrc[] = { | 459 | static struct resource twl6040_vibra_rsrc[] = { |
439 | { | 460 | { |
440 | .flags = IORESOURCE_IRQ, | 461 | .flags = IORESOURCE_IRQ, |
@@ -471,9 +492,7 @@ static int __devinit twl6040_probe(struct platform_device *pdev) | |||
471 | 492 | ||
472 | platform_set_drvdata(pdev, twl6040); | 493 | platform_set_drvdata(pdev, twl6040); |
473 | 494 | ||
474 | twl6040_dev = pdev; | ||
475 | twl6040->dev = &pdev->dev; | 495 | twl6040->dev = &pdev->dev; |
476 | twl6040->audpwron = pdata->audpwron_gpio; | ||
477 | twl6040->irq = pdata->naudint_irq; | 496 | twl6040->irq = pdata->naudint_irq; |
478 | twl6040->irq_base = pdata->irq_base; | 497 | twl6040->irq_base = pdata->irq_base; |
479 | 498 | ||
@@ -483,6 +502,12 @@ static int __devinit twl6040_probe(struct platform_device *pdev) | |||
483 | 502 | ||
484 | twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); | 503 | twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); |
485 | 504 | ||
505 | /* ERRATA: Automatic power-up is not possible in ES1.0 */ | ||
506 | if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) | ||
507 | twl6040->audpwron = pdata->audpwron_gpio; | ||
508 | else | ||
509 | twl6040->audpwron = -EINVAL; | ||
510 | |||
486 | if (gpio_is_valid(twl6040->audpwron)) { | 511 | if (gpio_is_valid(twl6040->audpwron)) { |
487 | ret = gpio_request(twl6040->audpwron, "audpwron"); | 512 | ret = gpio_request(twl6040->audpwron, "audpwron"); |
488 | if (ret) | 513 | if (ret) |
@@ -493,10 +518,6 @@ static int __devinit twl6040_probe(struct platform_device *pdev) | |||
493 | goto gpio2_err; | 518 | goto gpio2_err; |
494 | } | 519 | } |
495 | 520 | ||
496 | /* ERRATA: Automatic power-up is not possible in ES1.0 */ | ||
497 | if (twl6040->rev == TWL6040_REV_ES1_0) | ||
498 | twl6040->audpwron = -EINVAL; | ||
499 | |||
500 | /* codec interrupt */ | 521 | /* codec interrupt */ |
501 | ret = twl6040_irq_init(twl6040); | 522 | ret = twl6040_irq_init(twl6040); |
502 | if (ret) | 523 | if (ret) |
@@ -566,7 +587,6 @@ gpio2_err: | |||
566 | gpio1_err: | 587 | gpio1_err: |
567 | platform_set_drvdata(pdev, NULL); | 588 | platform_set_drvdata(pdev, NULL); |
568 | kfree(twl6040); | 589 | kfree(twl6040); |
569 | twl6040_dev = NULL; | ||
570 | return ret; | 590 | return ret; |
571 | } | 591 | } |
572 | 592 | ||
@@ -586,7 +606,6 @@ static int __devexit twl6040_remove(struct platform_device *pdev) | |||
586 | mfd_remove_devices(&pdev->dev); | 606 | mfd_remove_devices(&pdev->dev); |
587 | platform_set_drvdata(pdev, NULL); | 607 | platform_set_drvdata(pdev, NULL); |
588 | kfree(twl6040); | 608 | kfree(twl6040); |
589 | twl6040_dev = NULL; | ||
590 | 609 | ||
591 | return 0; | 610 | return 0; |
592 | } | 611 | } |
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index bfde4e8ec638..b03be1d4e0ca 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
@@ -167,6 +167,18 @@ static struct mfd_cell wm8994_devs[] = { | |||
167 | * and should be handled via the standard regulator API supply | 167 | * and should be handled via the standard regulator API supply |
168 | * management. | 168 | * management. |
169 | */ | 169 | */ |
170 | static const char *wm1811_main_supplies[] = { | ||
171 | "DBVDD1", | ||
172 | "DBVDD2", | ||
173 | "DBVDD3", | ||
174 | "DCVDD", | ||
175 | "AVDD1", | ||
176 | "AVDD2", | ||
177 | "CPVDD", | ||
178 | "SPKVDD1", | ||
179 | "SPKVDD2", | ||
180 | }; | ||
181 | |||
170 | static const char *wm8994_main_supplies[] = { | 182 | static const char *wm8994_main_supplies[] = { |
171 | "DBVDD", | 183 | "DBVDD", |
172 | "DCVDD", | 184 | "DCVDD", |
@@ -329,6 +341,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
329 | } | 341 | } |
330 | 342 | ||
331 | switch (wm8994->type) { | 343 | switch (wm8994->type) { |
344 | case WM1811: | ||
345 | wm8994->num_supplies = ARRAY_SIZE(wm1811_main_supplies); | ||
346 | break; | ||
332 | case WM8994: | 347 | case WM8994: |
333 | wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); | 348 | wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); |
334 | break; | 349 | break; |
@@ -349,6 +364,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
349 | } | 364 | } |
350 | 365 | ||
351 | switch (wm8994->type) { | 366 | switch (wm8994->type) { |
367 | case WM1811: | ||
368 | for (i = 0; i < ARRAY_SIZE(wm1811_main_supplies); i++) | ||
369 | wm8994->supplies[i].supply = wm1811_main_supplies[i]; | ||
370 | break; | ||
352 | case WM8994: | 371 | case WM8994: |
353 | for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) | 372 | for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) |
354 | wm8994->supplies[i].supply = wm8994_main_supplies[i]; | 373 | wm8994->supplies[i].supply = wm8994_main_supplies[i]; |
@@ -382,6 +401,13 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
382 | goto err_enable; | 401 | goto err_enable; |
383 | } | 402 | } |
384 | switch (ret) { | 403 | switch (ret) { |
404 | case 0x1811: | ||
405 | devname = "WM1811"; | ||
406 | if (wm8994->type != WM1811) | ||
407 | dev_warn(wm8994->dev, "Device registered as type %d\n", | ||
408 | wm8994->type); | ||
409 | wm8994->type = WM1811; | ||
410 | break; | ||
385 | case 0x8994: | 411 | case 0x8994: |
386 | devname = "WM8994"; | 412 | devname = "WM8994"; |
387 | if (wm8994->type != WM8994) | 413 | if (wm8994->type != WM8994) |
@@ -539,6 +565,7 @@ static int wm8994_i2c_remove(struct i2c_client *i2c) | |||
539 | } | 565 | } |
540 | 566 | ||
541 | static const struct i2c_device_id wm8994_i2c_id[] = { | 567 | static const struct i2c_device_id wm8994_i2c_id[] = { |
568 | { "wm1811", WM1811 }, | ||
542 | { "wm8994", WM8994 }, | 569 | { "wm8994", WM8994 }, |
543 | { "wm8958", WM8958 }, | 570 | { "wm8958", WM8958 }, |
544 | { } | 571 | { } |
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d8e6a429e8ba..9e4c123c4028 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -1552,6 +1552,68 @@ int regulator_force_disable(struct regulator *regulator) | |||
1552 | } | 1552 | } |
1553 | EXPORT_SYMBOL_GPL(regulator_force_disable); | 1553 | EXPORT_SYMBOL_GPL(regulator_force_disable); |
1554 | 1554 | ||
1555 | static void regulator_disable_work(struct work_struct *work) | ||
1556 | { | ||
1557 | struct regulator_dev *rdev = container_of(work, struct regulator_dev, | ||
1558 | disable_work.work); | ||
1559 | int count, i, ret; | ||
1560 | |||
1561 | mutex_lock(&rdev->mutex); | ||
1562 | |||
1563 | BUG_ON(!rdev->deferred_disables); | ||
1564 | |||
1565 | count = rdev->deferred_disables; | ||
1566 | rdev->deferred_disables = 0; | ||
1567 | |||
1568 | for (i = 0; i < count; i++) { | ||
1569 | ret = _regulator_disable(rdev); | ||
1570 | if (ret != 0) | ||
1571 | rdev_err(rdev, "Deferred disable failed: %d\n", ret); | ||
1572 | } | ||
1573 | |||
1574 | mutex_unlock(&rdev->mutex); | ||
1575 | |||
1576 | if (rdev->supply) { | ||
1577 | for (i = 0; i < count; i++) { | ||
1578 | ret = regulator_disable(rdev->supply); | ||
1579 | if (ret != 0) { | ||
1580 | rdev_err(rdev, | ||
1581 | "Supply disable failed: %d\n", ret); | ||
1582 | } | ||
1583 | } | ||
1584 | } | ||
1585 | } | ||
1586 | |||
1587 | /** | ||
1588 | * regulator_disable_deferred - disable regulator output with delay | ||
1589 | * @regulator: regulator source | ||
1590 | * @ms: miliseconds until the regulator is disabled | ||
1591 | * | ||
1592 | * Execute regulator_disable() on the regulator after a delay. This | ||
1593 | * is intended for use with devices that require some time to quiesce. | ||
1594 | * | ||
1595 | * NOTE: this will only disable the regulator output if no other consumer | ||
1596 | * devices have it enabled, the regulator device supports disabling and | ||
1597 | * machine constraints permit this operation. | ||
1598 | */ | ||
1599 | int regulator_disable_deferred(struct regulator *regulator, int ms) | ||
1600 | { | ||
1601 | struct regulator_dev *rdev = regulator->rdev; | ||
1602 | int ret; | ||
1603 | |||
1604 | mutex_lock(&rdev->mutex); | ||
1605 | rdev->deferred_disables++; | ||
1606 | mutex_unlock(&rdev->mutex); | ||
1607 | |||
1608 | ret = schedule_delayed_work(&rdev->disable_work, | ||
1609 | msecs_to_jiffies(ms)); | ||
1610 | if (ret < 0) | ||
1611 | return ret; | ||
1612 | else | ||
1613 | return 0; | ||
1614 | } | ||
1615 | EXPORT_SYMBOL_GPL(regulator_disable_deferred); | ||
1616 | |||
1555 | static int _regulator_is_enabled(struct regulator_dev *rdev) | 1617 | static int _regulator_is_enabled(struct regulator_dev *rdev) |
1556 | { | 1618 | { |
1557 | /* If we don't know then assume that the regulator is always on */ | 1619 | /* If we don't know then assume that the regulator is always on */ |
@@ -2622,6 +2684,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, | |||
2622 | INIT_LIST_HEAD(&rdev->consumer_list); | 2684 | INIT_LIST_HEAD(&rdev->consumer_list); |
2623 | INIT_LIST_HEAD(&rdev->list); | 2685 | INIT_LIST_HEAD(&rdev->list); |
2624 | BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); | 2686 | BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); |
2687 | INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); | ||
2625 | 2688 | ||
2626 | /* preform any regulator specific init */ | 2689 | /* preform any regulator specific init */ |
2627 | if (init_data->regulator_init) { | 2690 | if (init_data->regulator_init) { |
@@ -2729,6 +2792,7 @@ void regulator_unregister(struct regulator_dev *rdev) | |||
2729 | #ifdef CONFIG_DEBUG_FS | 2792 | #ifdef CONFIG_DEBUG_FS |
2730 | debugfs_remove_recursive(rdev->debugfs); | 2793 | debugfs_remove_recursive(rdev->debugfs); |
2731 | #endif | 2794 | #endif |
2795 | flush_work_sync(&rdev->disable_work.work); | ||
2732 | WARN_ON(rdev->open_count); | 2796 | WARN_ON(rdev->open_count); |
2733 | unset_regulator_supplies(rdev); | 2797 | unset_regulator_supplies(rdev); |
2734 | list_del(&rdev->list); | 2798 | list_del(&rdev->list); |
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 1a6a690f24db..b87bf5c841f8 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c | |||
@@ -140,6 +140,14 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, | |||
140 | return (selector * 100000) + 900000; | 140 | return (selector * 100000) + 900000; |
141 | case WM8958: | 141 | case WM8958: |
142 | return (selector * 100000) + 1000000; | 142 | return (selector * 100000) + 1000000; |
143 | case WM1811: | ||
144 | switch (selector) { | ||
145 | case 0: | ||
146 | return -EINVAL; | ||
147 | default: | ||
148 | return (selector * 100000) + 950000; | ||
149 | } | ||
150 | break; | ||
143 | default: | 151 | default: |
144 | return -EINVAL; | 152 | return -EINVAL; |
145 | } | 153 | } |
@@ -170,6 +178,11 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, | |||
170 | case WM8958: | 178 | case WM8958: |
171 | selector = (min_uV - 1000000) / 100000; | 179 | selector = (min_uV - 1000000) / 100000; |
172 | break; | 180 | break; |
181 | case WM1811: | ||
182 | selector = (min_uV - 950000) / 100000; | ||
183 | if (selector == 0) | ||
184 | selector = 1; | ||
185 | break; | ||
173 | default: | 186 | default: |
174 | return -EINVAL; | 187 | return -EINVAL; |
175 | } | 188 | } |