diff options
Diffstat (limited to 'drivers/mfd/arizona-core.c')
-rw-r--r-- | drivers/mfd/arizona-core.c | 267 |
1 files changed, 222 insertions, 45 deletions
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index b562c7bf8a46..6ab03043fd60 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
@@ -39,11 +39,21 @@ int arizona_clk32k_enable(struct arizona *arizona) | |||
39 | 39 | ||
40 | arizona->clk32k_ref++; | 40 | arizona->clk32k_ref++; |
41 | 41 | ||
42 | if (arizona->clk32k_ref == 1) | 42 | if (arizona->clk32k_ref == 1) { |
43 | switch (arizona->pdata.clk32k_src) { | ||
44 | case ARIZONA_32KZ_MCLK1: | ||
45 | ret = pm_runtime_get_sync(arizona->dev); | ||
46 | if (ret != 0) | ||
47 | goto out; | ||
48 | break; | ||
49 | } | ||
50 | |||
43 | ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 51 | ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
44 | ARIZONA_CLK_32K_ENA, | 52 | ARIZONA_CLK_32K_ENA, |
45 | ARIZONA_CLK_32K_ENA); | 53 | ARIZONA_CLK_32K_ENA); |
54 | } | ||
46 | 55 | ||
56 | out: | ||
47 | if (ret != 0) | 57 | if (ret != 0) |
48 | arizona->clk32k_ref--; | 58 | arizona->clk32k_ref--; |
49 | 59 | ||
@@ -63,10 +73,17 @@ int arizona_clk32k_disable(struct arizona *arizona) | |||
63 | 73 | ||
64 | arizona->clk32k_ref--; | 74 | arizona->clk32k_ref--; |
65 | 75 | ||
66 | if (arizona->clk32k_ref == 0) | 76 | if (arizona->clk32k_ref == 0) { |
67 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 77 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
68 | ARIZONA_CLK_32K_ENA, 0); | 78 | ARIZONA_CLK_32K_ENA, 0); |
69 | 79 | ||
80 | switch (arizona->pdata.clk32k_src) { | ||
81 | case ARIZONA_32KZ_MCLK1: | ||
82 | pm_runtime_put_sync(arizona->dev); | ||
83 | break; | ||
84 | } | ||
85 | } | ||
86 | |||
70 | mutex_unlock(&arizona->clk_lock); | 87 | mutex_unlock(&arizona->clk_lock); |
71 | 88 | ||
72 | return ret; | 89 | return ret; |
@@ -179,42 +196,134 @@ static irqreturn_t arizona_overclocked(int irq, void *data) | |||
179 | return IRQ_HANDLED; | 196 | return IRQ_HANDLED; |
180 | } | 197 | } |
181 | 198 | ||
182 | static int arizona_wait_for_boot(struct arizona *arizona) | 199 | static int arizona_poll_reg(struct arizona *arizona, |
200 | int timeout, unsigned int reg, | ||
201 | unsigned int mask, unsigned int target) | ||
183 | { | 202 | { |
184 | unsigned int reg; | 203 | unsigned int val = 0; |
185 | int ret, i; | 204 | int ret, i; |
186 | 205 | ||
206 | for (i = 0; i < timeout; i++) { | ||
207 | ret = regmap_read(arizona->regmap, reg, &val); | ||
208 | if (ret != 0) { | ||
209 | dev_err(arizona->dev, "Failed to read reg %u: %d\n", | ||
210 | reg, ret); | ||
211 | continue; | ||
212 | } | ||
213 | |||
214 | if ((val & mask) == target) | ||
215 | return 0; | ||
216 | |||
217 | msleep(1); | ||
218 | } | ||
219 | |||
220 | dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); | ||
221 | return -ETIMEDOUT; | ||
222 | } | ||
223 | |||
224 | static int arizona_wait_for_boot(struct arizona *arizona) | ||
225 | { | ||
226 | int ret; | ||
227 | |||
187 | /* | 228 | /* |
188 | * We can't use an interrupt as we need to runtime resume to do so, | 229 | * We can't use an interrupt as we need to runtime resume to do so, |
189 | * we won't race with the interrupt handler as it'll be blocked on | 230 | * we won't race with the interrupt handler as it'll be blocked on |
190 | * runtime resume. | 231 | * runtime resume. |
191 | */ | 232 | */ |
192 | for (i = 0; i < 5; i++) { | 233 | ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, |
193 | msleep(1); | 234 | ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); |
194 | 235 | ||
195 | ret = regmap_read(arizona->regmap, | 236 | if (!ret) |
196 | ARIZONA_INTERRUPT_RAW_STATUS_5, ®); | 237 | regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, |
197 | if (ret != 0) { | 238 | ARIZONA_BOOT_DONE_STS); |
198 | dev_err(arizona->dev, "Failed to read boot state: %d\n", | ||
199 | ret); | ||
200 | continue; | ||
201 | } | ||
202 | 239 | ||
203 | if (reg & ARIZONA_BOOT_DONE_STS) | 240 | pm_runtime_mark_last_busy(arizona->dev); |
204 | break; | 241 | |
242 | return ret; | ||
243 | } | ||
244 | |||
245 | static int arizona_apply_hardware_patch(struct arizona* arizona) | ||
246 | { | ||
247 | unsigned int fll, sysclk; | ||
248 | int ret, err; | ||
249 | |||
250 | regcache_cache_bypass(arizona->regmap, true); | ||
251 | |||
252 | /* Cache existing FLL and SYSCLK settings */ | ||
253 | ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); | ||
254 | if (ret != 0) { | ||
255 | dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", | ||
256 | ret); | ||
257 | return ret; | ||
258 | } | ||
259 | ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); | ||
260 | if (ret != 0) { | ||
261 | dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", | ||
262 | ret); | ||
263 | return ret; | ||
205 | } | 264 | } |
206 | 265 | ||
207 | if (reg & ARIZONA_BOOT_DONE_STS) { | 266 | /* Start up SYSCLK using the FLL in free running mode */ |
208 | regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, | 267 | ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, |
209 | ARIZONA_BOOT_DONE_STS); | 268 | ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); |
210 | } else { | 269 | if (ret != 0) { |
211 | dev_err(arizona->dev, "Device boot timed out: %x\n", reg); | 270 | dev_err(arizona->dev, |
212 | return -ETIMEDOUT; | 271 | "Failed to start FLL in freerunning mode: %d\n", |
272 | ret); | ||
273 | return ret; | ||
274 | } | ||
275 | ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, | ||
276 | ARIZONA_FLL1_CLOCK_OK_STS, | ||
277 | ARIZONA_FLL1_CLOCK_OK_STS); | ||
278 | if (ret != 0) { | ||
279 | ret = -ETIMEDOUT; | ||
280 | goto err_fll; | ||
213 | } | 281 | } |
214 | 282 | ||
215 | pm_runtime_mark_last_busy(arizona->dev); | 283 | ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); |
284 | if (ret != 0) { | ||
285 | dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); | ||
286 | goto err_fll; | ||
287 | } | ||
216 | 288 | ||
217 | return 0; | 289 | /* Start the write sequencer and wait for it to finish */ |
290 | ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | ||
291 | ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); | ||
292 | if (ret != 0) { | ||
293 | dev_err(arizona->dev, "Failed to start write sequencer: %d\n", | ||
294 | ret); | ||
295 | goto err_sysclk; | ||
296 | } | ||
297 | ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, | ||
298 | ARIZONA_WSEQ_BUSY, 0); | ||
299 | if (ret != 0) { | ||
300 | regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | ||
301 | ARIZONA_WSEQ_ABORT); | ||
302 | ret = -ETIMEDOUT; | ||
303 | } | ||
304 | |||
305 | err_sysclk: | ||
306 | err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); | ||
307 | if (err != 0) { | ||
308 | dev_err(arizona->dev, | ||
309 | "Failed to re-apply old SYSCLK settings: %d\n", | ||
310 | err); | ||
311 | } | ||
312 | |||
313 | err_fll: | ||
314 | err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); | ||
315 | if (err != 0) { | ||
316 | dev_err(arizona->dev, | ||
317 | "Failed to re-apply old FLL settings: %d\n", | ||
318 | err); | ||
319 | } | ||
320 | |||
321 | regcache_cache_bypass(arizona->regmap, false); | ||
322 | |||
323 | if (ret != 0) | ||
324 | return ret; | ||
325 | else | ||
326 | return err; | ||
218 | } | 327 | } |
219 | 328 | ||
220 | #ifdef CONFIG_PM_RUNTIME | 329 | #ifdef CONFIG_PM_RUNTIME |
@@ -233,20 +342,44 @@ static int arizona_runtime_resume(struct device *dev) | |||
233 | 342 | ||
234 | regcache_cache_only(arizona->regmap, false); | 343 | regcache_cache_only(arizona->regmap, false); |
235 | 344 | ||
236 | ret = arizona_wait_for_boot(arizona); | 345 | switch (arizona->type) { |
237 | if (ret != 0) { | 346 | case WM5102: |
238 | regulator_disable(arizona->dcvdd); | 347 | ret = wm5102_patch(arizona); |
239 | return ret; | 348 | if (ret != 0) { |
349 | dev_err(arizona->dev, "Failed to apply patch: %d\n", | ||
350 | ret); | ||
351 | goto err; | ||
352 | } | ||
353 | |||
354 | ret = arizona_apply_hardware_patch(arizona); | ||
355 | if (ret != 0) { | ||
356 | dev_err(arizona->dev, | ||
357 | "Failed to apply hardware patch: %d\n", | ||
358 | ret); | ||
359 | goto err; | ||
360 | } | ||
361 | break; | ||
362 | default: | ||
363 | ret = arizona_wait_for_boot(arizona); | ||
364 | if (ret != 0) { | ||
365 | goto err; | ||
366 | } | ||
367 | |||
368 | break; | ||
240 | } | 369 | } |
241 | 370 | ||
242 | ret = regcache_sync(arizona->regmap); | 371 | ret = regcache_sync(arizona->regmap); |
243 | if (ret != 0) { | 372 | if (ret != 0) { |
244 | dev_err(arizona->dev, "Failed to restore register cache\n"); | 373 | dev_err(arizona->dev, "Failed to restore register cache\n"); |
245 | regulator_disable(arizona->dcvdd); | 374 | goto err; |
246 | return ret; | ||
247 | } | 375 | } |
248 | 376 | ||
249 | return 0; | 377 | return 0; |
378 | |||
379 | err: | ||
380 | regcache_cache_only(arizona->regmap, true); | ||
381 | regulator_disable(arizona->dcvdd); | ||
382 | return ret; | ||
250 | } | 383 | } |
251 | 384 | ||
252 | static int arizona_runtime_suspend(struct device *dev) | 385 | static int arizona_runtime_suspend(struct device *dev) |
@@ -371,6 +504,17 @@ int arizona_dev_init(struct arizona *arizona) | |||
371 | goto err_early; | 504 | goto err_early; |
372 | } | 505 | } |
373 | 506 | ||
507 | if (arizona->pdata.reset) { | ||
508 | /* Start out with /RESET low to put the chip into reset */ | ||
509 | ret = gpio_request_one(arizona->pdata.reset, | ||
510 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | ||
511 | "arizona /RESET"); | ||
512 | if (ret != 0) { | ||
513 | dev_err(dev, "Failed to request /RESET: %d\n", ret); | ||
514 | goto err_early; | ||
515 | } | ||
516 | } | ||
517 | |||
374 | ret = regulator_bulk_enable(arizona->num_core_supplies, | 518 | ret = regulator_bulk_enable(arizona->num_core_supplies, |
375 | arizona->core_supplies); | 519 | arizona->core_supplies); |
376 | if (ret != 0) { | 520 | if (ret != 0) { |
@@ -386,16 +530,8 @@ int arizona_dev_init(struct arizona *arizona) | |||
386 | } | 530 | } |
387 | 531 | ||
388 | if (arizona->pdata.reset) { | 532 | if (arizona->pdata.reset) { |
389 | /* Start out with /RESET low to put the chip into reset */ | ||
390 | ret = gpio_request_one(arizona->pdata.reset, | ||
391 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | ||
392 | "arizona /RESET"); | ||
393 | if (ret != 0) { | ||
394 | dev_err(dev, "Failed to request /RESET: %d\n", ret); | ||
395 | goto err_dcvdd; | ||
396 | } | ||
397 | |||
398 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | 533 | gpio_set_value_cansleep(arizona->pdata.reset, 1); |
534 | msleep(1); | ||
399 | } | 535 | } |
400 | 536 | ||
401 | regcache_cache_only(arizona->regmap, false); | 537 | regcache_cache_only(arizona->regmap, false); |
@@ -424,6 +560,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
424 | arizona->type = WM5102; | 560 | arizona->type = WM5102; |
425 | } | 561 | } |
426 | apply_patch = wm5102_patch; | 562 | apply_patch = wm5102_patch; |
563 | arizona->rev &= 0x7; | ||
427 | break; | 564 | break; |
428 | #endif | 565 | #endif |
429 | #ifdef CONFIG_MFD_WM5110 | 566 | #ifdef CONFIG_MFD_WM5110 |
@@ -454,6 +591,8 @@ int arizona_dev_init(struct arizona *arizona) | |||
454 | goto err_reset; | 591 | goto err_reset; |
455 | } | 592 | } |
456 | 593 | ||
594 | msleep(1); | ||
595 | |||
457 | ret = regcache_sync(arizona->regmap); | 596 | ret = regcache_sync(arizona->regmap); |
458 | if (ret != 0) { | 597 | if (ret != 0) { |
459 | dev_err(dev, "Failed to sync device: %d\n", ret); | 598 | dev_err(dev, "Failed to sync device: %d\n", ret); |
@@ -461,10 +600,24 @@ int arizona_dev_init(struct arizona *arizona) | |||
461 | } | 600 | } |
462 | } | 601 | } |
463 | 602 | ||
464 | ret = arizona_wait_for_boot(arizona); | 603 | switch (arizona->type) { |
465 | if (ret != 0) { | 604 | case WM5102: |
466 | dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); | 605 | ret = regmap_read(arizona->regmap, 0x19, &val); |
467 | goto err_reset; | 606 | if (ret != 0) |
607 | dev_err(dev, | ||
608 | "Failed to check write sequencer state: %d\n", | ||
609 | ret); | ||
610 | else if (val & 0x01) | ||
611 | break; | ||
612 | /* Fall through */ | ||
613 | default: | ||
614 | ret = arizona_wait_for_boot(arizona); | ||
615 | if (ret != 0) { | ||
616 | dev_err(arizona->dev, | ||
617 | "Device failed initial boot: %d\n", ret); | ||
618 | goto err_reset; | ||
619 | } | ||
620 | break; | ||
468 | } | 621 | } |
469 | 622 | ||
470 | if (apply_patch) { | 623 | if (apply_patch) { |
@@ -474,6 +627,20 @@ int arizona_dev_init(struct arizona *arizona) | |||
474 | ret); | 627 | ret); |
475 | goto err_reset; | 628 | goto err_reset; |
476 | } | 629 | } |
630 | |||
631 | switch (arizona->type) { | ||
632 | case WM5102: | ||
633 | ret = arizona_apply_hardware_patch(arizona); | ||
634 | if (ret != 0) { | ||
635 | dev_err(arizona->dev, | ||
636 | "Failed to apply hardware patch: %d\n", | ||
637 | ret); | ||
638 | goto err_reset; | ||
639 | } | ||
640 | break; | ||
641 | default: | ||
642 | break; | ||
643 | } | ||
477 | } | 644 | } |
478 | 645 | ||
479 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 646 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { |
@@ -498,6 +665,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
498 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 665 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
499 | ARIZONA_CLK_32K_SRC_MASK, | 666 | ARIZONA_CLK_32K_SRC_MASK, |
500 | arizona->pdata.clk32k_src - 1); | 667 | arizona->pdata.clk32k_src - 1); |
668 | arizona_clk32k_enable(arizona); | ||
501 | break; | 669 | break; |
502 | case ARIZONA_32KZ_NONE: | 670 | case ARIZONA_32KZ_NONE: |
503 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 671 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
@@ -511,10 +679,16 @@ int arizona_dev_init(struct arizona *arizona) | |||
511 | } | 679 | } |
512 | 680 | ||
513 | for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { | 681 | for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { |
514 | if (!arizona->pdata.micbias[i].mV) | 682 | if (!arizona->pdata.micbias[i].mV && |
683 | !arizona->pdata.micbias[i].bypass) | ||
515 | continue; | 684 | continue; |
516 | 685 | ||
686 | /* Apply default for bypass mode */ | ||
687 | if (!arizona->pdata.micbias[i].mV) | ||
688 | arizona->pdata.micbias[i].mV = 2800; | ||
689 | |||
517 | val = (arizona->pdata.micbias[i].mV - 1500) / 100; | 690 | val = (arizona->pdata.micbias[i].mV - 1500) / 100; |
691 | |||
518 | val <<= ARIZONA_MICB1_LVL_SHIFT; | 692 | val <<= ARIZONA_MICB1_LVL_SHIFT; |
519 | 693 | ||
520 | if (arizona->pdata.micbias[i].ext_cap) | 694 | if (arizona->pdata.micbias[i].ext_cap) |
@@ -526,10 +700,14 @@ int arizona_dev_init(struct arizona *arizona) | |||
526 | if (arizona->pdata.micbias[i].fast_start) | 700 | if (arizona->pdata.micbias[i].fast_start) |
527 | val |= ARIZONA_MICB1_RATE; | 701 | val |= ARIZONA_MICB1_RATE; |
528 | 702 | ||
703 | if (arizona->pdata.micbias[i].bypass) | ||
704 | val |= ARIZONA_MICB1_BYPASS; | ||
705 | |||
529 | regmap_update_bits(arizona->regmap, | 706 | regmap_update_bits(arizona->regmap, |
530 | ARIZONA_MIC_BIAS_CTRL_1 + i, | 707 | ARIZONA_MIC_BIAS_CTRL_1 + i, |
531 | ARIZONA_MICB1_LVL_MASK | | 708 | ARIZONA_MICB1_LVL_MASK | |
532 | ARIZONA_MICB1_DISCH | | 709 | ARIZONA_MICB1_DISCH | |
710 | ARIZONA_MICB1_BYPASS | | ||
533 | ARIZONA_MICB1_RATE, val); | 711 | ARIZONA_MICB1_RATE, val); |
534 | } | 712 | } |
535 | 713 | ||
@@ -610,10 +788,9 @@ err_irq: | |||
610 | arizona_irq_exit(arizona); | 788 | arizona_irq_exit(arizona); |
611 | err_reset: | 789 | err_reset: |
612 | if (arizona->pdata.reset) { | 790 | if (arizona->pdata.reset) { |
613 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | 791 | gpio_set_value_cansleep(arizona->pdata.reset, 0); |
614 | gpio_free(arizona->pdata.reset); | 792 | gpio_free(arizona->pdata.reset); |
615 | } | 793 | } |
616 | err_dcvdd: | ||
617 | regulator_disable(arizona->dcvdd); | 794 | regulator_disable(arizona->dcvdd); |
618 | err_enable: | 795 | err_enable: |
619 | regulator_bulk_disable(arizona->num_core_supplies, | 796 | regulator_bulk_disable(arizona->num_core_supplies, |