diff options
author | Charles Keepax <ckeepax@opensource.wolfsonmicro.com> | 2013-03-26 14:46:15 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-04-08 09:21:01 -0400 |
commit | e80436bbb241abbf2168c65622fb98d9378432fa (patch) | |
tree | d6588ca690f6a87f9bf3e4b8bd02178249e5ff25 /drivers/mfd | |
parent | 9d53dfdc82503b819f7b854e627a555cc65224e3 (diff) |
mfd: arizona: Add a hardware patch mechanism
This patch adds facilities for apply a register patch contained within
the chip using the write sequencer.
Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/arizona-core.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index b09b119d4966..d6b40df64c4a 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
@@ -242,6 +242,90 @@ static int arizona_wait_for_boot(struct arizona *arizona) | |||
242 | return ret; | 242 | return ret; |
243 | } | 243 | } |
244 | 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; | ||
264 | } | ||
265 | |||
266 | /* Start up SYSCLK using the FLL in free running mode */ | ||
267 | ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, | ||
268 | ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); | ||
269 | if (ret != 0) { | ||
270 | dev_err(arizona->dev, | ||
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; | ||
281 | } | ||
282 | |||
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 | } | ||
288 | |||
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; | ||
327 | } | ||
328 | |||
245 | #ifdef CONFIG_PM_RUNTIME | 329 | #ifdef CONFIG_PM_RUNTIME |
246 | static int arizona_runtime_resume(struct device *dev) | 330 | static int arizona_runtime_resume(struct device *dev) |
247 | { | 331 | { |
@@ -271,6 +355,17 @@ static int arizona_runtime_resume(struct device *dev) | |||
271 | ret); | 355 | ret); |
272 | goto err; | 356 | goto err; |
273 | } | 357 | } |
358 | |||
359 | ret = arizona_apply_hardware_patch(arizona); | ||
360 | if (ret != 0) { | ||
361 | dev_err(arizona->dev, | ||
362 | "Failed to apply hardware patch: %d\n", | ||
363 | ret); | ||
364 | goto err; | ||
365 | } | ||
366 | break; | ||
367 | default: | ||
368 | break; | ||
274 | } | 369 | } |
275 | 370 | ||
276 | ret = regcache_sync(arizona->regmap); | 371 | ret = regcache_sync(arizona->regmap); |
@@ -513,6 +608,20 @@ int arizona_dev_init(struct arizona *arizona) | |||
513 | ret); | 608 | ret); |
514 | goto err_reset; | 609 | goto err_reset; |
515 | } | 610 | } |
611 | |||
612 | switch (arizona->type) { | ||
613 | case WM5102: | ||
614 | ret = arizona_apply_hardware_patch(arizona); | ||
615 | if (ret != 0) { | ||
616 | dev_err(arizona->dev, | ||
617 | "Failed to apply hardware patch: %d\n", | ||
618 | ret); | ||
619 | goto err_reset; | ||
620 | } | ||
621 | break; | ||
622 | default: | ||
623 | break; | ||
624 | } | ||
516 | } | 625 | } |
517 | 626 | ||
518 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 627 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { |