13cc72986SMark Brown /* 23cc72986SMark Brown * Arizona core driver 33cc72986SMark Brown * 43cc72986SMark Brown * Copyright 2012 Wolfson Microelectronics plc 53cc72986SMark Brown * 63cc72986SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 73cc72986SMark Brown * 83cc72986SMark Brown * This program is free software; you can redistribute it and/or modify 93cc72986SMark Brown * it under the terms of the GNU General Public License version 2 as 103cc72986SMark Brown * published by the Free Software Foundation. 113cc72986SMark Brown */ 123cc72986SMark Brown 133cc72986SMark Brown #include <linux/delay.h> 1459db9691SMark Brown #include <linux/err.h> 153cc72986SMark Brown #include <linux/gpio.h> 163cc72986SMark Brown #include <linux/interrupt.h> 173cc72986SMark Brown #include <linux/mfd/core.h> 183cc72986SMark Brown #include <linux/module.h> 193cc72986SMark Brown #include <linux/pm_runtime.h> 203cc72986SMark Brown #include <linux/regmap.h> 213cc72986SMark Brown #include <linux/regulator/consumer.h> 223cc72986SMark Brown #include <linux/slab.h> 233cc72986SMark Brown 243cc72986SMark Brown #include <linux/mfd/arizona/core.h> 253cc72986SMark Brown #include <linux/mfd/arizona/registers.h> 263cc72986SMark Brown 273cc72986SMark Brown #include "arizona.h" 283cc72986SMark Brown 293cc72986SMark Brown static const char *wm5102_core_supplies[] = { 303cc72986SMark Brown "AVDD", 313cc72986SMark Brown "DBVDD1", 323cc72986SMark Brown }; 333cc72986SMark Brown 343cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona) 353cc72986SMark Brown { 363cc72986SMark Brown int ret = 0; 373cc72986SMark Brown 383cc72986SMark Brown mutex_lock(&arizona->clk_lock); 393cc72986SMark Brown 403cc72986SMark Brown arizona->clk32k_ref++; 413cc72986SMark Brown 42247fa192SMark Brown if (arizona->clk32k_ref == 1) { 43247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 44247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 45247fa192SMark Brown ret = pm_runtime_get_sync(arizona->dev); 46247fa192SMark Brown if (ret != 0) 47247fa192SMark Brown goto out; 48247fa192SMark Brown break; 49247fa192SMark Brown } 50247fa192SMark Brown 513cc72986SMark Brown ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 523cc72986SMark Brown ARIZONA_CLK_32K_ENA, 533cc72986SMark Brown ARIZONA_CLK_32K_ENA); 54247fa192SMark Brown } 553cc72986SMark Brown 56247fa192SMark Brown out: 573cc72986SMark Brown if (ret != 0) 583cc72986SMark Brown arizona->clk32k_ref--; 593cc72986SMark Brown 603cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 613cc72986SMark Brown 623cc72986SMark Brown return ret; 633cc72986SMark Brown } 643cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable); 653cc72986SMark Brown 663cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona) 673cc72986SMark Brown { 683cc72986SMark Brown int ret = 0; 693cc72986SMark Brown 703cc72986SMark Brown mutex_lock(&arizona->clk_lock); 713cc72986SMark Brown 723cc72986SMark Brown BUG_ON(arizona->clk32k_ref <= 0); 733cc72986SMark Brown 743cc72986SMark Brown arizona->clk32k_ref--; 753cc72986SMark Brown 76247fa192SMark Brown if (arizona->clk32k_ref == 0) { 773cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 783cc72986SMark Brown ARIZONA_CLK_32K_ENA, 0); 793cc72986SMark Brown 80247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 81247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 82247fa192SMark Brown pm_runtime_put_sync(arizona->dev); 83247fa192SMark Brown break; 84247fa192SMark Brown } 85247fa192SMark Brown } 86247fa192SMark Brown 873cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 883cc72986SMark Brown 893cc72986SMark Brown return ret; 903cc72986SMark Brown } 913cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable); 923cc72986SMark Brown 933cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data) 943cc72986SMark Brown { 953cc72986SMark Brown struct arizona *arizona = data; 963cc72986SMark Brown 973cc72986SMark Brown dev_err(arizona->dev, "CLKGEN error\n"); 983cc72986SMark Brown 993cc72986SMark Brown return IRQ_HANDLED; 1003cc72986SMark Brown } 1013cc72986SMark Brown 1023cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data) 1033cc72986SMark Brown { 1043cc72986SMark Brown struct arizona *arizona = data; 1053cc72986SMark Brown unsigned int val; 1063cc72986SMark Brown int ret; 1073cc72986SMark Brown 1083cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, 1093cc72986SMark Brown &val); 1103cc72986SMark Brown if (ret != 0) { 1113cc72986SMark Brown dev_err(arizona->dev, "Failed to read underclock status: %d\n", 1123cc72986SMark Brown ret); 1133cc72986SMark Brown return IRQ_NONE; 1143cc72986SMark Brown } 1153cc72986SMark Brown 1163cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1173cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1183cc72986SMark Brown if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) 1193ebef34dSCharles Keepax dev_err(arizona->dev, "AIF2 underclocked\n"); 1203ebef34dSCharles Keepax if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) 1213cc72986SMark Brown dev_err(arizona->dev, "AIF1 underclocked\n"); 1223cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1233cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1243cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1253cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1263cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1273cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1283cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1293cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1303cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1313cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1323cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1333cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1343cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 135648a9880SMark Brown dev_err(arizona->dev, "Mixer dropped sample\n"); 1363cc72986SMark Brown 1373cc72986SMark Brown return IRQ_HANDLED; 1383cc72986SMark Brown } 1393cc72986SMark Brown 1403cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1413cc72986SMark Brown { 1423cc72986SMark Brown struct arizona *arizona = data; 1433cc72986SMark Brown unsigned int val[2]; 1443cc72986SMark Brown int ret; 1453cc72986SMark Brown 1463cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1473cc72986SMark Brown &val[0], 2); 1483cc72986SMark Brown if (ret != 0) { 1493cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1503cc72986SMark Brown ret); 1513cc72986SMark Brown return IRQ_NONE; 1523cc72986SMark Brown } 1533cc72986SMark Brown 1543cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1553cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1563cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1573cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1583cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1593cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1603cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1613cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1623cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1633cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1643cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1653cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 1663cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 1673cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 1683cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 1693cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 1703cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 1713cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 1723cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 1733cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 1743cc72986SMark Brown 1753cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 1763cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 1773cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 1783cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 1793cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 1803cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 1813cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 1823cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 1833cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 1843cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 1853cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 1863cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 1873cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 1883cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 1893cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 1903cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 1913cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 1923cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 1933cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 1943cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 1953cc72986SMark Brown 1963cc72986SMark Brown return IRQ_HANDLED; 1973cc72986SMark Brown } 1983cc72986SMark Brown 1999d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 2009d53dfdcSCharles Keepax int timeout, unsigned int reg, 2019d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2029d53dfdcSCharles Keepax { 2039d53dfdcSCharles Keepax unsigned int val = 0; 2049d53dfdcSCharles Keepax int ret, i; 2059d53dfdcSCharles Keepax 2069d53dfdcSCharles Keepax for (i = 0; i < timeout; i++) { 2079d53dfdcSCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2089d53dfdcSCharles Keepax if (ret != 0) { 2099d53dfdcSCharles Keepax dev_err(arizona->dev, "Failed to read reg %u: %d\n", 2109d53dfdcSCharles Keepax reg, ret); 2119d53dfdcSCharles Keepax continue; 2129d53dfdcSCharles Keepax } 2139d53dfdcSCharles Keepax 2149d53dfdcSCharles Keepax if ((val & mask) == target) 2159d53dfdcSCharles Keepax return 0; 2169d53dfdcSCharles Keepax 2179d53dfdcSCharles Keepax msleep(1); 2189d53dfdcSCharles Keepax } 2199d53dfdcSCharles Keepax 2209d53dfdcSCharles Keepax dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); 2219d53dfdcSCharles Keepax return -ETIMEDOUT; 2229d53dfdcSCharles Keepax } 2239d53dfdcSCharles Keepax 2243cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2253cc72986SMark Brown { 2269d53dfdcSCharles Keepax int ret; 2273cc72986SMark Brown 2283cc72986SMark Brown /* 2293cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2303cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2313cc72986SMark Brown * runtime resume. 2323cc72986SMark Brown */ 2339d53dfdcSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, 2349d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2353cc72986SMark Brown 2369d53dfdcSCharles Keepax if (!ret) 2373cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2383cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2393cc72986SMark Brown 2403cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2413cc72986SMark Brown 2429d53dfdcSCharles Keepax return ret; 2433cc72986SMark Brown } 2443cc72986SMark Brown 245e80436bbSCharles Keepax static int arizona_apply_hardware_patch(struct arizona* arizona) 246e80436bbSCharles Keepax { 247e80436bbSCharles Keepax unsigned int fll, sysclk; 248e80436bbSCharles Keepax int ret, err; 249e80436bbSCharles Keepax 250e80436bbSCharles Keepax regcache_cache_bypass(arizona->regmap, true); 251e80436bbSCharles Keepax 252e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 253e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); 254e80436bbSCharles Keepax if (ret != 0) { 255e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 256e80436bbSCharles Keepax ret); 257e80436bbSCharles Keepax return ret; 258e80436bbSCharles Keepax } 259e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); 260e80436bbSCharles Keepax if (ret != 0) { 261e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 262e80436bbSCharles Keepax ret); 263e80436bbSCharles Keepax return ret; 264e80436bbSCharles Keepax } 265e80436bbSCharles Keepax 266e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 267e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 268e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 269e80436bbSCharles Keepax if (ret != 0) { 270e80436bbSCharles Keepax dev_err(arizona->dev, 271e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 272e80436bbSCharles Keepax ret); 273e80436bbSCharles Keepax return ret; 274e80436bbSCharles Keepax } 275e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, 276e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 277e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 278e80436bbSCharles Keepax if (ret != 0) { 279e80436bbSCharles Keepax ret = -ETIMEDOUT; 280e80436bbSCharles Keepax goto err_fll; 281e80436bbSCharles Keepax } 282e80436bbSCharles Keepax 283e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 284e80436bbSCharles Keepax if (ret != 0) { 285e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 286e80436bbSCharles Keepax goto err_fll; 287e80436bbSCharles Keepax } 288e80436bbSCharles Keepax 289e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 290e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 291e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 292e80436bbSCharles Keepax if (ret != 0) { 293e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 294e80436bbSCharles Keepax ret); 295e80436bbSCharles Keepax goto err_sysclk; 296e80436bbSCharles Keepax } 297e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 298e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 299e80436bbSCharles Keepax if (ret != 0) { 300e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 301e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 302e80436bbSCharles Keepax ret = -ETIMEDOUT; 303e80436bbSCharles Keepax } 304e80436bbSCharles Keepax 305e80436bbSCharles Keepax err_sysclk: 306e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); 307e80436bbSCharles Keepax if (err != 0) { 308e80436bbSCharles Keepax dev_err(arizona->dev, 309e80436bbSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", 310e80436bbSCharles Keepax err); 311e80436bbSCharles Keepax } 312e80436bbSCharles Keepax 313e80436bbSCharles Keepax err_fll: 314e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); 315e80436bbSCharles Keepax if (err != 0) { 316e80436bbSCharles Keepax dev_err(arizona->dev, 317e80436bbSCharles Keepax "Failed to re-apply old FLL settings: %d\n", 318e80436bbSCharles Keepax err); 319e80436bbSCharles Keepax } 320e80436bbSCharles Keepax 321e80436bbSCharles Keepax regcache_cache_bypass(arizona->regmap, false); 322e80436bbSCharles Keepax 323e80436bbSCharles Keepax if (ret != 0) 324e80436bbSCharles Keepax return ret; 325e80436bbSCharles Keepax else 326e80436bbSCharles Keepax return err; 327e80436bbSCharles Keepax } 328e80436bbSCharles Keepax 3293cc72986SMark Brown #ifdef CONFIG_PM_RUNTIME 3303cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 3313cc72986SMark Brown { 3323cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 3333cc72986SMark Brown int ret; 3343cc72986SMark Brown 335508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 336508c8299SMark Brown 33759db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 33859db9691SMark Brown if (ret != 0) { 33959db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 34059db9691SMark Brown return ret; 34159db9691SMark Brown } 3423cc72986SMark Brown 3433cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 3443cc72986SMark Brown 3454c9bb8bcSCharles Keepax switch (arizona->type) { 3464c9bb8bcSCharles Keepax case WM5102: 3474c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 3484c9bb8bcSCharles Keepax if (ret != 0) { 3494c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 3504c9bb8bcSCharles Keepax ret); 3514c9bb8bcSCharles Keepax goto err; 3524c9bb8bcSCharles Keepax } 353e80436bbSCharles Keepax 354e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 355e80436bbSCharles Keepax if (ret != 0) { 356e80436bbSCharles Keepax dev_err(arizona->dev, 357e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 358e80436bbSCharles Keepax ret); 359e80436bbSCharles Keepax goto err; 360e80436bbSCharles Keepax } 361e80436bbSCharles Keepax break; 362e80436bbSCharles Keepax default: 36312bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 36412bb68edSCharles Keepax if (ret != 0) { 36512bb68edSCharles Keepax goto err; 36612bb68edSCharles Keepax } 36712bb68edSCharles Keepax 368e80436bbSCharles Keepax break; 3694c9bb8bcSCharles Keepax } 3704c9bb8bcSCharles Keepax 3719270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 3729270bdf5SMark Brown if (ret != 0) { 3739270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 3744816bd1cSMark Brown goto err; 3759270bdf5SMark Brown } 3763cc72986SMark Brown 3773cc72986SMark Brown return 0; 3784816bd1cSMark Brown 3794816bd1cSMark Brown err: 3804816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 3814816bd1cSMark Brown regulator_disable(arizona->dcvdd); 3824816bd1cSMark Brown return ret; 3833cc72986SMark Brown } 3843cc72986SMark Brown 3853cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 3863cc72986SMark Brown { 3873cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 3883cc72986SMark Brown 389508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 390508c8299SMark Brown 39159db9691SMark Brown regulator_disable(arizona->dcvdd); 3923cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 3933cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 3943cc72986SMark Brown 3953cc72986SMark Brown return 0; 3963cc72986SMark Brown } 3973cc72986SMark Brown #endif 3983cc72986SMark Brown 399dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 400dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 401dc781d0eSMark Brown { 402dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 403dc781d0eSMark Brown 404dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 405dc781d0eSMark Brown disable_irq(arizona->irq); 406dc781d0eSMark Brown 407dc781d0eSMark Brown return 0; 408dc781d0eSMark Brown } 409dc781d0eSMark Brown 410dc781d0eSMark Brown static int arizona_resume(struct device *dev) 411dc781d0eSMark Brown { 412dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 413dc781d0eSMark Brown 414dc781d0eSMark Brown dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); 415dc781d0eSMark Brown enable_irq(arizona->irq); 416dc781d0eSMark Brown 417dc781d0eSMark Brown return 0; 418dc781d0eSMark Brown } 419dc781d0eSMark Brown #endif 420dc781d0eSMark Brown 4213cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 4223cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 4233cc72986SMark Brown arizona_runtime_resume, 4243cc72986SMark Brown NULL) 425dc781d0eSMark Brown SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume) 426dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 427dc781d0eSMark Brown .resume_noirq = arizona_resume_noirq, 428dc781d0eSMark Brown #endif 4293cc72986SMark Brown }; 4303cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 4313cc72986SMark Brown 4323cc72986SMark Brown static struct mfd_cell early_devs[] = { 4333cc72986SMark Brown { .name = "arizona-ldo1" }, 4343cc72986SMark Brown }; 4353cc72986SMark Brown 4363cc72986SMark Brown static struct mfd_cell wm5102_devs[] = { 437d7768111SMark Brown { .name = "arizona-micsupp" }, 4383cc72986SMark Brown { .name = "arizona-extcon" }, 4393cc72986SMark Brown { .name = "arizona-gpio" }, 440503b1cacSMark Brown { .name = "arizona-haptics" }, 4413cc72986SMark Brown { .name = "arizona-pwm" }, 4423cc72986SMark Brown { .name = "wm5102-codec" }, 4433cc72986SMark Brown }; 4443cc72986SMark Brown 445e102befeSMark Brown static struct mfd_cell wm5110_devs[] = { 446d7768111SMark Brown { .name = "arizona-micsupp" }, 447e102befeSMark Brown { .name = "arizona-extcon" }, 448e102befeSMark Brown { .name = "arizona-gpio" }, 449503b1cacSMark Brown { .name = "arizona-haptics" }, 450e102befeSMark Brown { .name = "arizona-pwm" }, 451e102befeSMark Brown { .name = "wm5110-codec" }, 452e102befeSMark Brown }; 453e102befeSMark Brown 454f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 4553cc72986SMark Brown { 4563cc72986SMark Brown struct device *dev = arizona->dev; 4573cc72986SMark Brown const char *type_name; 4583cc72986SMark Brown unsigned int reg, val; 45962d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 4603cc72986SMark Brown int ret, i; 4613cc72986SMark Brown 4623cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 4633cc72986SMark Brown mutex_init(&arizona->clk_lock); 4643cc72986SMark Brown 4653cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 4663cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 4673cc72986SMark Brown sizeof(arizona->pdata)); 4683cc72986SMark Brown 4693cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 4703cc72986SMark Brown 4713cc72986SMark Brown switch (arizona->type) { 4723cc72986SMark Brown case WM5102: 473e102befeSMark Brown case WM5110: 4743cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 4753cc72986SMark Brown arizona->core_supplies[i].supply 4763cc72986SMark Brown = wm5102_core_supplies[i]; 4773cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 4783cc72986SMark Brown break; 4793cc72986SMark Brown default: 4803cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 4813cc72986SMark Brown arizona->type); 4823cc72986SMark Brown return -EINVAL; 4833cc72986SMark Brown } 4843cc72986SMark Brown 4853cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 4860848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 4873cc72986SMark Brown if (ret != 0) { 4883cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 4893cc72986SMark Brown return ret; 4903cc72986SMark Brown } 4913cc72986SMark Brown 4923cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 4933cc72986SMark Brown arizona->core_supplies); 4943cc72986SMark Brown if (ret != 0) { 4953cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 4963cc72986SMark Brown ret); 4973cc72986SMark Brown goto err_early; 4983cc72986SMark Brown } 4993cc72986SMark Brown 50059db9691SMark Brown arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD"); 50159db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 50259db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 50359db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 50459db9691SMark Brown goto err_early; 50559db9691SMark Brown } 50659db9691SMark Brown 50787d3af4aSMark Brown if (arizona->pdata.reset) { 50887d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 50987d3af4aSMark Brown ret = gpio_request_one(arizona->pdata.reset, 51087d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 51187d3af4aSMark Brown "arizona /RESET"); 51287d3af4aSMark Brown if (ret != 0) { 51387d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 51487d3af4aSMark Brown goto err_early; 51587d3af4aSMark Brown } 51687d3af4aSMark Brown } 51787d3af4aSMark Brown 5183cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 5193cc72986SMark Brown arizona->core_supplies); 5203cc72986SMark Brown if (ret != 0) { 5213cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 5223cc72986SMark Brown ret); 5233cc72986SMark Brown goto err_early; 5243cc72986SMark Brown } 5253cc72986SMark Brown 52659db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 52759db9691SMark Brown if (ret != 0) { 52859db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 52959db9691SMark Brown goto err_enable; 53059db9691SMark Brown } 53159db9691SMark Brown 532c25feaa5SCharles Keepax if (arizona->pdata.reset) { 5333cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 534c25feaa5SCharles Keepax msleep(1); 535c25feaa5SCharles Keepax } 5363cc72986SMark Brown 5373cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 5383cc72986SMark Brown 539*ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 540*ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 541*ca76ceb8SMark Brown if (ret != 0) { 542*ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 543*ca76ceb8SMark Brown goto err_reset; 544*ca76ceb8SMark Brown } 545*ca76ceb8SMark Brown 546*ca76ceb8SMark Brown switch (reg) { 547*ca76ceb8SMark Brown case 0x5102: 548*ca76ceb8SMark Brown case 0x5110: 549*ca76ceb8SMark Brown break; 550*ca76ceb8SMark Brown default: 551*ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 552*ca76ceb8SMark Brown goto err_reset; 553*ca76ceb8SMark Brown } 554*ca76ceb8SMark Brown 555*ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 556*ca76ceb8SMark Brown if (!arizona->pdata.reset) { 557*ca76ceb8SMark Brown regcache_mark_dirty(arizona->regmap); 558*ca76ceb8SMark Brown 559*ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 560*ca76ceb8SMark Brown if (ret != 0) { 561*ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 562*ca76ceb8SMark Brown goto err_reset; 563*ca76ceb8SMark Brown } 564*ca76ceb8SMark Brown 565*ca76ceb8SMark Brown msleep(1); 566*ca76ceb8SMark Brown 567*ca76ceb8SMark Brown ret = regcache_sync(arizona->regmap); 568*ca76ceb8SMark Brown if (ret != 0) { 569*ca76ceb8SMark Brown dev_err(dev, "Failed to sync device: %d\n", ret); 570*ca76ceb8SMark Brown goto err_reset; 571*ca76ceb8SMark Brown } 572*ca76ceb8SMark Brown } 573*ca76ceb8SMark Brown 574*ca76ceb8SMark Brown /* Ensure device startup is complete */ 575*ca76ceb8SMark Brown switch (arizona->type) { 576*ca76ceb8SMark Brown case WM5102: 577*ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, 0x19, &val); 578*ca76ceb8SMark Brown if (ret != 0) 579*ca76ceb8SMark Brown dev_err(dev, 580*ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 581*ca76ceb8SMark Brown ret); 582*ca76ceb8SMark Brown else if (val & 0x01) 583*ca76ceb8SMark Brown break; 584*ca76ceb8SMark Brown /* Fall through */ 585*ca76ceb8SMark Brown default: 586*ca76ceb8SMark Brown ret = arizona_wait_for_boot(arizona); 587*ca76ceb8SMark Brown if (ret != 0) { 588*ca76ceb8SMark Brown dev_err(arizona->dev, 589*ca76ceb8SMark Brown "Device failed initial boot: %d\n", ret); 590*ca76ceb8SMark Brown goto err_reset; 591*ca76ceb8SMark Brown } 592*ca76ceb8SMark Brown break; 593*ca76ceb8SMark Brown } 594*ca76ceb8SMark Brown 595*ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 5963cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 5973cc72986SMark Brown if (ret != 0) { 5983cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 59959db9691SMark Brown goto err_reset; 6003cc72986SMark Brown } 6013cc72986SMark Brown 6023cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 6033cc72986SMark Brown &arizona->rev); 6043cc72986SMark Brown if (ret != 0) { 6053cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 60659db9691SMark Brown goto err_reset; 6073cc72986SMark Brown } 6083cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 6093cc72986SMark Brown 6103cc72986SMark Brown switch (reg) { 611863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102 6123cc72986SMark Brown case 0x5102: 6133cc72986SMark Brown type_name = "WM5102"; 6143cc72986SMark Brown if (arizona->type != WM5102) { 6153cc72986SMark Brown dev_err(arizona->dev, "WM5102 registered as %d\n", 6163cc72986SMark Brown arizona->type); 6173cc72986SMark Brown arizona->type = WM5102; 6183cc72986SMark Brown } 61962d62b59SMark Brown apply_patch = wm5102_patch; 620c6d6bfb1SMark Brown arizona->rev &= 0x7; 6213cc72986SMark Brown break; 622863df8d5SMark Brown #endif 623e102befeSMark Brown #ifdef CONFIG_MFD_WM5110 624e102befeSMark Brown case 0x5110: 625e102befeSMark Brown type_name = "WM5110"; 626e102befeSMark Brown if (arizona->type != WM5110) { 627e102befeSMark Brown dev_err(arizona->dev, "WM5110 registered as %d\n", 628e102befeSMark Brown arizona->type); 629e102befeSMark Brown arizona->type = WM5110; 630e102befeSMark Brown } 63162d62b59SMark Brown apply_patch = wm5110_patch; 632e102befeSMark Brown break; 633e102befeSMark Brown #endif 6343cc72986SMark Brown default: 6353cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 63659db9691SMark Brown goto err_reset; 6373cc72986SMark Brown } 6383cc72986SMark Brown 6393cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 6403cc72986SMark Brown 64162d62b59SMark Brown if (apply_patch) { 64262d62b59SMark Brown ret = apply_patch(arizona); 64362d62b59SMark Brown if (ret != 0) { 64462d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 64562d62b59SMark Brown ret); 64662d62b59SMark Brown goto err_reset; 64762d62b59SMark Brown } 648e80436bbSCharles Keepax 649e80436bbSCharles Keepax switch (arizona->type) { 650e80436bbSCharles Keepax case WM5102: 651e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 652e80436bbSCharles Keepax if (ret != 0) { 653e80436bbSCharles Keepax dev_err(arizona->dev, 654e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 655e80436bbSCharles Keepax ret); 656e80436bbSCharles Keepax goto err_reset; 657e80436bbSCharles Keepax } 658e80436bbSCharles Keepax break; 659e80436bbSCharles Keepax default: 660e80436bbSCharles Keepax break; 661e80436bbSCharles Keepax } 66262d62b59SMark Brown } 66362d62b59SMark Brown 6643cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 6653cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 6663cc72986SMark Brown continue; 6673cc72986SMark Brown 6683cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 6693cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 6703cc72986SMark Brown } 6713cc72986SMark Brown 6723cc72986SMark Brown pm_runtime_set_autosuspend_delay(arizona->dev, 100); 6733cc72986SMark Brown pm_runtime_use_autosuspend(arizona->dev); 6743cc72986SMark Brown pm_runtime_enable(arizona->dev); 6753cc72986SMark Brown 6763cc72986SMark Brown /* Chip default */ 6773cc72986SMark Brown if (!arizona->pdata.clk32k_src) 6783cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 6793cc72986SMark Brown 6803cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 6813cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 6823cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 6833cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 6843cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 6853cc72986SMark Brown arizona->pdata.clk32k_src - 1); 686767c6dc0SMark Brown arizona_clk32k_enable(arizona); 6873cc72986SMark Brown break; 6883cc72986SMark Brown case ARIZONA_32KZ_NONE: 6893cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 6903cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 6913cc72986SMark Brown break; 6923cc72986SMark Brown default: 6933cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 6943cc72986SMark Brown arizona->pdata.clk32k_src); 6953cc72986SMark Brown ret = -EINVAL; 69659db9691SMark Brown goto err_reset; 6973cc72986SMark Brown } 6983cc72986SMark Brown 6993d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 700544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 701544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 7023d91f828SMark Brown continue; 7033d91f828SMark Brown 704544c7aadSMark Brown /* Apply default for bypass mode */ 705544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 706544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 707544c7aadSMark Brown 7083d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 709544c7aadSMark Brown 7103d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 7113d91f828SMark Brown 7123d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 7133d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 7143d91f828SMark Brown 7153d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 7163d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 7173d91f828SMark Brown 7183d91f828SMark Brown if (arizona->pdata.micbias[i].fast_start) 7193d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 7203d91f828SMark Brown 721544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 722544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 723544c7aadSMark Brown 7243d91f828SMark Brown regmap_update_bits(arizona->regmap, 7253d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 7263d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 7273d91f828SMark Brown ARIZONA_MICB1_DISCH | 728544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 7293d91f828SMark Brown ARIZONA_MICB1_RATE, val); 7303d91f828SMark Brown } 7313d91f828SMark Brown 7323cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 7333cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 7343cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 7353cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 7363cc72986SMark Brown val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; 7373cc72986SMark Brown 7383cc72986SMark Brown regmap_update_bits(arizona->regmap, 7393cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 7403cc72986SMark Brown ARIZONA_IN1_DMIC_SUP_MASK | 7413cc72986SMark Brown ARIZONA_IN1_MODE_MASK, val); 7423cc72986SMark Brown } 7433cc72986SMark Brown 7443cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 7453cc72986SMark Brown /* Default is 0 so noop with defaults */ 7463cc72986SMark Brown if (arizona->pdata.out_mono[i]) 7473cc72986SMark Brown val = ARIZONA_OUT1_MONO; 7483cc72986SMark Brown else 7493cc72986SMark Brown val = 0; 7503cc72986SMark Brown 7513cc72986SMark Brown regmap_update_bits(arizona->regmap, 7523cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 7533cc72986SMark Brown ARIZONA_OUT1_MONO, val); 7543cc72986SMark Brown } 7553cc72986SMark Brown 7563cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 7573cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 7583cc72986SMark Brown regmap_update_bits(arizona->regmap, 7592a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 7603cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 7613cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 7623cc72986SMark Brown arizona->pdata.spk_mute[i]); 7633cc72986SMark Brown 7643cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 7653cc72986SMark Brown regmap_update_bits(arizona->regmap, 7662a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 7673cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 7683cc72986SMark Brown arizona->pdata.spk_fmt[i]); 7693cc72986SMark Brown } 7703cc72986SMark Brown 7713cc72986SMark Brown /* Set up for interrupts */ 7723cc72986SMark Brown ret = arizona_irq_init(arizona); 7733cc72986SMark Brown if (ret != 0) 77459db9691SMark Brown goto err_reset; 7753cc72986SMark Brown 7763cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 7773cc72986SMark Brown arizona_clkgen_err, arizona); 7783cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 7793cc72986SMark Brown arizona_overclocked, arizona); 7803cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 7813cc72986SMark Brown arizona_underclocked, arizona); 7823cc72986SMark Brown 7833cc72986SMark Brown switch (arizona->type) { 7843cc72986SMark Brown case WM5102: 7853cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, 7860848c94fSMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); 7873cc72986SMark Brown break; 788e102befeSMark Brown case WM5110: 789e102befeSMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, 79078566afdSCharles Keepax ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); 791e102befeSMark Brown break; 7923cc72986SMark Brown } 7933cc72986SMark Brown 7943cc72986SMark Brown if (ret != 0) { 7953cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 7963cc72986SMark Brown goto err_irq; 7973cc72986SMark Brown } 7983cc72986SMark Brown 79959db9691SMark Brown #ifdef CONFIG_PM_RUNTIME 80059db9691SMark Brown regulator_disable(arizona->dcvdd); 80159db9691SMark Brown #endif 80259db9691SMark Brown 8033cc72986SMark Brown return 0; 8043cc72986SMark Brown 8053cc72986SMark Brown err_irq: 8063cc72986SMark Brown arizona_irq_exit(arizona); 8073cc72986SMark Brown err_reset: 8083cc72986SMark Brown if (arizona->pdata.reset) { 80987d3af4aSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 8103cc72986SMark Brown gpio_free(arizona->pdata.reset); 8113cc72986SMark Brown } 81259db9691SMark Brown regulator_disable(arizona->dcvdd); 8133cc72986SMark Brown err_enable: 8143a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 8153cc72986SMark Brown arizona->core_supplies); 8163cc72986SMark Brown err_early: 8173cc72986SMark Brown mfd_remove_devices(dev); 8183cc72986SMark Brown return ret; 8193cc72986SMark Brown } 8203cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 8213cc72986SMark Brown 8224740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 8233cc72986SMark Brown { 8243cc72986SMark Brown mfd_remove_devices(arizona->dev); 8253cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 8263cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 8273cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 8283cc72986SMark Brown pm_runtime_disable(arizona->dev); 8293cc72986SMark Brown arizona_irq_exit(arizona); 8303cc72986SMark Brown return 0; 8313cc72986SMark Brown } 8323cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 833