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 13*cdd8da8cSSylwester Nawrocki #include <linux/clk.h> 143cc72986SMark Brown #include <linux/delay.h> 1559db9691SMark Brown #include <linux/err.h> 163cc72986SMark Brown #include <linux/gpio.h> 173cc72986SMark Brown #include <linux/interrupt.h> 183cc72986SMark Brown #include <linux/mfd/core.h> 193cc72986SMark Brown #include <linux/module.h> 20d781009cSMark Brown #include <linux/of.h> 21d781009cSMark Brown #include <linux/of_device.h> 22d781009cSMark Brown #include <linux/of_gpio.h> 233cc72986SMark Brown #include <linux/pm_runtime.h> 243cc72986SMark Brown #include <linux/regmap.h> 253cc72986SMark Brown #include <linux/regulator/consumer.h> 265927467dSMark Brown #include <linux/regulator/machine.h> 273cc72986SMark Brown #include <linux/slab.h> 28ae05ea36SRichard Fitzgerald #include <linux/platform_device.h> 293cc72986SMark Brown 303cc72986SMark Brown #include <linux/mfd/arizona/core.h> 313cc72986SMark Brown #include <linux/mfd/arizona/registers.h> 323cc72986SMark Brown 333cc72986SMark Brown #include "arizona.h" 343cc72986SMark Brown 353762aedeSCharles Keepax static const char * const wm5102_core_supplies[] = { 363cc72986SMark Brown "AVDD", 373cc72986SMark Brown "DBVDD1", 383cc72986SMark Brown }; 393cc72986SMark Brown 403cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona) 413cc72986SMark Brown { 423cc72986SMark Brown int ret = 0; 433cc72986SMark Brown 443cc72986SMark Brown mutex_lock(&arizona->clk_lock); 453cc72986SMark Brown 463cc72986SMark Brown arizona->clk32k_ref++; 473cc72986SMark Brown 48247fa192SMark Brown if (arizona->clk32k_ref == 1) { 49247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 50247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 51247fa192SMark Brown ret = pm_runtime_get_sync(arizona->dev); 52247fa192SMark Brown if (ret != 0) 53*cdd8da8cSSylwester Nawrocki goto err_ref; 54*cdd8da8cSSylwester Nawrocki ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]); 55*cdd8da8cSSylwester Nawrocki if (ret != 0) 56*cdd8da8cSSylwester Nawrocki goto err_pm; 57*cdd8da8cSSylwester Nawrocki break; 58*cdd8da8cSSylwester Nawrocki case ARIZONA_32KZ_MCLK2: 59*cdd8da8cSSylwester Nawrocki ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]); 60*cdd8da8cSSylwester Nawrocki if (ret != 0) 61*cdd8da8cSSylwester Nawrocki goto err_ref; 62247fa192SMark Brown break; 63247fa192SMark Brown } 64247fa192SMark Brown 653cc72986SMark Brown ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 663cc72986SMark Brown ARIZONA_CLK_32K_ENA, 673cc72986SMark Brown ARIZONA_CLK_32K_ENA); 68247fa192SMark Brown } 693cc72986SMark Brown 70*cdd8da8cSSylwester Nawrocki err_pm: 71*cdd8da8cSSylwester Nawrocki pm_runtime_put_sync(arizona->dev); 72*cdd8da8cSSylwester Nawrocki err_ref: 733cc72986SMark Brown if (ret != 0) 743cc72986SMark Brown arizona->clk32k_ref--; 753cc72986SMark Brown 763cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 773cc72986SMark Brown 783cc72986SMark Brown return ret; 793cc72986SMark Brown } 803cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable); 813cc72986SMark Brown 823cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona) 833cc72986SMark Brown { 843cc72986SMark Brown mutex_lock(&arizona->clk_lock); 853cc72986SMark Brown 863cc72986SMark Brown BUG_ON(arizona->clk32k_ref <= 0); 873cc72986SMark Brown 883cc72986SMark Brown arizona->clk32k_ref--; 893cc72986SMark Brown 90247fa192SMark Brown if (arizona->clk32k_ref == 0) { 913cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 923cc72986SMark Brown ARIZONA_CLK_32K_ENA, 0); 933cc72986SMark Brown 94247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 95247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 96247fa192SMark Brown pm_runtime_put_sync(arizona->dev); 97*cdd8da8cSSylwester Nawrocki clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]); 98*cdd8da8cSSylwester Nawrocki break; 99*cdd8da8cSSylwester Nawrocki case ARIZONA_32KZ_MCLK2: 100*cdd8da8cSSylwester Nawrocki clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]); 101247fa192SMark Brown break; 102247fa192SMark Brown } 103247fa192SMark Brown } 104247fa192SMark Brown 1053cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 1063cc72986SMark Brown 107a260fba1SJavier Martinez Canillas return 0; 1083cc72986SMark Brown } 1093cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable); 1103cc72986SMark Brown 1113cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data) 1123cc72986SMark Brown { 1133cc72986SMark Brown struct arizona *arizona = data; 1143cc72986SMark Brown 1153cc72986SMark Brown dev_err(arizona->dev, "CLKGEN error\n"); 1163cc72986SMark Brown 1173cc72986SMark Brown return IRQ_HANDLED; 1183cc72986SMark Brown } 1193cc72986SMark Brown 1203cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data) 1213cc72986SMark Brown { 1223cc72986SMark Brown struct arizona *arizona = data; 1233cc72986SMark Brown unsigned int val; 1243cc72986SMark Brown int ret; 1253cc72986SMark Brown 1263cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, 1273cc72986SMark Brown &val); 1283cc72986SMark Brown if (ret != 0) { 1293cc72986SMark Brown dev_err(arizona->dev, "Failed to read underclock status: %d\n", 1303cc72986SMark Brown ret); 1313cc72986SMark Brown return IRQ_NONE; 1323cc72986SMark Brown } 1333cc72986SMark Brown 1343cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1353cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1363cc72986SMark Brown if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) 1373ebef34dSCharles Keepax dev_err(arizona->dev, "AIF2 underclocked\n"); 1383ebef34dSCharles Keepax if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) 1393cc72986SMark Brown dev_err(arizona->dev, "AIF1 underclocked\n"); 1406e440d27SCharles Keepax if (val & ARIZONA_ISRC3_UNDERCLOCKED_STS) 1416e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 underclocked\n"); 1423cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1433cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1443cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1453cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1463cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1473cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1483cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1493cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1503cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1513cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1523cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1533cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1543cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 155648a9880SMark Brown dev_err(arizona->dev, "Mixer dropped sample\n"); 1563cc72986SMark Brown 1573cc72986SMark Brown return IRQ_HANDLED; 1583cc72986SMark Brown } 1593cc72986SMark Brown 1603cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1613cc72986SMark Brown { 1623cc72986SMark Brown struct arizona *arizona = data; 1636887b042SRichard Fitzgerald unsigned int val[3]; 1643cc72986SMark Brown int ret; 1653cc72986SMark Brown 1663cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1676887b042SRichard Fitzgerald &val[0], 3); 1683cc72986SMark Brown if (ret != 0) { 1693cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1703cc72986SMark Brown ret); 1713cc72986SMark Brown return IRQ_NONE; 1723cc72986SMark Brown } 1733cc72986SMark Brown 1746887b042SRichard Fitzgerald switch (arizona->type) { 1756887b042SRichard Fitzgerald case WM8998: 1766887b042SRichard Fitzgerald case WM1814: 1776887b042SRichard Fitzgerald /* Some bits are shifted on WM8998, 1786887b042SRichard Fitzgerald * rearrange to match the standard bit layout 1796887b042SRichard Fitzgerald */ 1806887b042SRichard Fitzgerald val[0] = ((val[0] & 0x60e0) >> 1) | 1816887b042SRichard Fitzgerald ((val[0] & 0x1e00) >> 2) | 1826887b042SRichard Fitzgerald (val[0] & 0x000f); 1836887b042SRichard Fitzgerald break; 1846887b042SRichard Fitzgerald default: 1856887b042SRichard Fitzgerald break; 1866887b042SRichard Fitzgerald } 1876887b042SRichard Fitzgerald 1883cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1893cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1903cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1913cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1923cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1933cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1943cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1953cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1963cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1973cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1983cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1993cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 2003cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 2013cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 2023cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 2033cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 2043cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 2053cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 2063cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 2073cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 2083cc72986SMark Brown 2093cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 2103cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 2113cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 2123cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 2133cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 2143cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 2153cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 2163cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 2173cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 2183cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 2193cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 2203cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 2213cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 2223cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 2233cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 2243cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 2256e440d27SCharles Keepax if (val[1] & ARIZONA_ISRC3_OVERCLOCKED_STS) 2266e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 overclocked\n"); 2273cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 2283cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 2293cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 2303cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 2313cc72986SMark Brown 2326887b042SRichard Fitzgerald if (val[2] & ARIZONA_SPDIF_OVERCLOCKED_STS) 2336887b042SRichard Fitzgerald dev_err(arizona->dev, "SPDIF overclocked\n"); 2346887b042SRichard Fitzgerald 2353cc72986SMark Brown return IRQ_HANDLED; 2363cc72986SMark Brown } 2373cc72986SMark Brown 2389d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 2399d53dfdcSCharles Keepax int timeout, unsigned int reg, 2409d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2419d53dfdcSCharles Keepax { 2429d53dfdcSCharles Keepax unsigned int val = 0; 2439d53dfdcSCharles Keepax int ret, i; 2449d53dfdcSCharles Keepax 2459d53dfdcSCharles Keepax for (i = 0; i < timeout; i++) { 2469d53dfdcSCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2479d53dfdcSCharles Keepax if (ret != 0) { 2489d53dfdcSCharles Keepax dev_err(arizona->dev, "Failed to read reg %u: %d\n", 2499d53dfdcSCharles Keepax reg, ret); 2509d53dfdcSCharles Keepax continue; 2519d53dfdcSCharles Keepax } 2529d53dfdcSCharles Keepax 2539d53dfdcSCharles Keepax if ((val & mask) == target) 2549d53dfdcSCharles Keepax return 0; 2559d53dfdcSCharles Keepax 256b79a980fSLee Jones usleep_range(1000, 5000); 2579d53dfdcSCharles Keepax } 2589d53dfdcSCharles Keepax 2599d53dfdcSCharles Keepax dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); 2609d53dfdcSCharles Keepax return -ETIMEDOUT; 2619d53dfdcSCharles Keepax } 2629d53dfdcSCharles Keepax 2633cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2643cc72986SMark Brown { 2659d53dfdcSCharles Keepax int ret; 2663cc72986SMark Brown 2673cc72986SMark Brown /* 2683cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2693cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2703cc72986SMark Brown * runtime resume. 2713cc72986SMark Brown */ 2729d53dfdcSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, 2739d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2743cc72986SMark Brown 2759d53dfdcSCharles Keepax if (!ret) 2763cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2773cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2783cc72986SMark Brown 2793cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2803cc72986SMark Brown 2819d53dfdcSCharles Keepax return ret; 2823cc72986SMark Brown } 2833cc72986SMark Brown 2842229875dSCharles Keepax static inline void arizona_enable_reset(struct arizona *arizona) 2852229875dSCharles Keepax { 2862229875dSCharles Keepax if (arizona->pdata.reset) 2872229875dSCharles Keepax gpio_set_value_cansleep(arizona->pdata.reset, 0); 2882229875dSCharles Keepax } 2892229875dSCharles Keepax 2902229875dSCharles Keepax static void arizona_disable_reset(struct arizona *arizona) 2912229875dSCharles Keepax { 2922229875dSCharles Keepax if (arizona->pdata.reset) { 293121c075cSCharles Keepax switch (arizona->type) { 294121c075cSCharles Keepax case WM5110: 295121c075cSCharles Keepax case WM8280: 296121c075cSCharles Keepax /* Meet requirements for minimum reset duration */ 297b79a980fSLee Jones usleep_range(5000, 10000); 298121c075cSCharles Keepax break; 299121c075cSCharles Keepax default: 300121c075cSCharles Keepax break; 301121c075cSCharles Keepax } 302121c075cSCharles Keepax 3032229875dSCharles Keepax gpio_set_value_cansleep(arizona->pdata.reset, 1); 304b79a980fSLee Jones usleep_range(1000, 5000); 3052229875dSCharles Keepax } 3062229875dSCharles Keepax } 3072229875dSCharles Keepax 3083850e3eeSCharles Keepax struct arizona_sysclk_state { 3093850e3eeSCharles Keepax unsigned int fll; 3103850e3eeSCharles Keepax unsigned int sysclk; 3113850e3eeSCharles Keepax }; 3123850e3eeSCharles Keepax 3133850e3eeSCharles Keepax static int arizona_enable_freerun_sysclk(struct arizona *arizona, 3143850e3eeSCharles Keepax struct arizona_sysclk_state *state) 315e80436bbSCharles Keepax { 316e80436bbSCharles Keepax int ret, err; 317e80436bbSCharles Keepax 318e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 3193850e3eeSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &state->fll); 3200be068a0SCharles Keepax if (ret) { 321e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 322e80436bbSCharles Keepax ret); 323e80436bbSCharles Keepax return ret; 324e80436bbSCharles Keepax } 3253850e3eeSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 3263850e3eeSCharles Keepax &state->sysclk); 3270be068a0SCharles Keepax if (ret) { 328e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 329e80436bbSCharles Keepax ret); 330e80436bbSCharles Keepax return ret; 331e80436bbSCharles Keepax } 332e80436bbSCharles Keepax 333e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 334e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 335e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 3360be068a0SCharles Keepax if (ret) { 337e80436bbSCharles Keepax dev_err(arizona->dev, 338e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 339e80436bbSCharles Keepax ret); 340e80436bbSCharles Keepax return ret; 341e80436bbSCharles Keepax } 342e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, 343e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 344e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 3450be068a0SCharles Keepax if (ret) { 346e80436bbSCharles Keepax ret = -ETIMEDOUT; 347e80436bbSCharles Keepax goto err_fll; 348e80436bbSCharles Keepax } 349e80436bbSCharles Keepax 350e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 3510be068a0SCharles Keepax if (ret) { 352e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 353e80436bbSCharles Keepax goto err_fll; 354e80436bbSCharles Keepax } 355e80436bbSCharles Keepax 3563850e3eeSCharles Keepax return 0; 3573850e3eeSCharles Keepax 3583850e3eeSCharles Keepax err_fll: 3593850e3eeSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3603850e3eeSCharles Keepax if (err) 3613850e3eeSCharles Keepax dev_err(arizona->dev, 3623850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", err); 3633850e3eeSCharles Keepax 3643850e3eeSCharles Keepax return ret; 3653850e3eeSCharles Keepax } 3663850e3eeSCharles Keepax 3673850e3eeSCharles Keepax static int arizona_disable_freerun_sysclk(struct arizona *arizona, 3683850e3eeSCharles Keepax struct arizona_sysclk_state *state) 3693850e3eeSCharles Keepax { 3703850e3eeSCharles Keepax int ret; 3713850e3eeSCharles Keepax 3723850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 3733850e3eeSCharles Keepax state->sysclk); 3743850e3eeSCharles Keepax if (ret) { 3753850e3eeSCharles Keepax dev_err(arizona->dev, 3763850e3eeSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", ret); 3773850e3eeSCharles Keepax return ret; 3783850e3eeSCharles Keepax } 3793850e3eeSCharles Keepax 3803850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3813850e3eeSCharles Keepax if (ret) { 3823850e3eeSCharles Keepax dev_err(arizona->dev, 3833850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", ret); 3843850e3eeSCharles Keepax return ret; 3853850e3eeSCharles Keepax } 3863850e3eeSCharles Keepax 3873850e3eeSCharles Keepax return 0; 3883850e3eeSCharles Keepax } 3893850e3eeSCharles Keepax 3903850e3eeSCharles Keepax static int wm5102_apply_hardware_patch(struct arizona *arizona) 3913850e3eeSCharles Keepax { 3923850e3eeSCharles Keepax struct arizona_sysclk_state state; 3933850e3eeSCharles Keepax int err, ret; 3943850e3eeSCharles Keepax 3953850e3eeSCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 3963850e3eeSCharles Keepax if (ret) 3973850e3eeSCharles Keepax return ret; 3983850e3eeSCharles Keepax 399e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 400e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 401e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 4020be068a0SCharles Keepax if (ret) { 403e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 404e80436bbSCharles Keepax ret); 4053850e3eeSCharles Keepax goto err; 406e80436bbSCharles Keepax } 4073850e3eeSCharles Keepax 408e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 409e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 4100be068a0SCharles Keepax if (ret) { 411e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 412e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 413e80436bbSCharles Keepax ret = -ETIMEDOUT; 414e80436bbSCharles Keepax } 415e80436bbSCharles Keepax 4163850e3eeSCharles Keepax err: 4173850e3eeSCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 418e80436bbSCharles Keepax 4190be068a0SCharles Keepax return ret ?: err; 420e80436bbSCharles Keepax } 421e80436bbSCharles Keepax 422882bc468SCharles Keepax /* 423882bc468SCharles Keepax * Register patch to some of the CODECs internal write sequences 424882bc468SCharles Keepax * to ensure a clean exit from the low power sleep state. 425882bc468SCharles Keepax */ 4268019ff6cSNariman Poushin static const struct reg_sequence wm5110_sleep_patch[] = { 427882bc468SCharles Keepax { 0x337A, 0xC100 }, 428882bc468SCharles Keepax { 0x337B, 0x0041 }, 429882bc468SCharles Keepax { 0x3300, 0xA210 }, 430882bc468SCharles Keepax { 0x3301, 0x050C }, 431882bc468SCharles Keepax }; 432882bc468SCharles Keepax 433882bc468SCharles Keepax static int wm5110_apply_sleep_patch(struct arizona *arizona) 434882bc468SCharles Keepax { 435882bc468SCharles Keepax struct arizona_sysclk_state state; 436882bc468SCharles Keepax int err, ret; 437882bc468SCharles Keepax 438882bc468SCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 439882bc468SCharles Keepax if (ret) 440882bc468SCharles Keepax return ret; 441882bc468SCharles Keepax 442882bc468SCharles Keepax ret = regmap_multi_reg_write_bypassed(arizona->regmap, 443882bc468SCharles Keepax wm5110_sleep_patch, 444882bc468SCharles Keepax ARRAY_SIZE(wm5110_sleep_patch)); 445882bc468SCharles Keepax 446882bc468SCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 447882bc468SCharles Keepax 448882bc468SCharles Keepax return ret ?: err; 449882bc468SCharles Keepax } 450882bc468SCharles Keepax 4511c1c6bbaSCharles Keepax static int wm5102_clear_write_sequencer(struct arizona *arizona) 4521c1c6bbaSCharles Keepax { 4531c1c6bbaSCharles Keepax int ret; 4541c1c6bbaSCharles Keepax 4551c1c6bbaSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3, 4561c1c6bbaSCharles Keepax 0x0); 4571c1c6bbaSCharles Keepax if (ret) { 4581c1c6bbaSCharles Keepax dev_err(arizona->dev, 4591c1c6bbaSCharles Keepax "Failed to clear write sequencer state: %d\n", ret); 4601c1c6bbaSCharles Keepax return ret; 4611c1c6bbaSCharles Keepax } 4621c1c6bbaSCharles Keepax 4631c1c6bbaSCharles Keepax arizona_enable_reset(arizona); 4641c1c6bbaSCharles Keepax regulator_disable(arizona->dcvdd); 4651c1c6bbaSCharles Keepax 4661c1c6bbaSCharles Keepax msleep(20); 4671c1c6bbaSCharles Keepax 4681c1c6bbaSCharles Keepax ret = regulator_enable(arizona->dcvdd); 4691c1c6bbaSCharles Keepax if (ret) { 4701c1c6bbaSCharles Keepax dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret); 4711c1c6bbaSCharles Keepax return ret; 4721c1c6bbaSCharles Keepax } 4731c1c6bbaSCharles Keepax arizona_disable_reset(arizona); 4741c1c6bbaSCharles Keepax 4751c1c6bbaSCharles Keepax return 0; 4761c1c6bbaSCharles Keepax } 4771c1c6bbaSCharles Keepax 47848bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM 479e7811147SRichard Fitzgerald static int arizona_isolate_dcvdd(struct arizona *arizona) 480e7811147SRichard Fitzgerald { 481e7811147SRichard Fitzgerald int ret; 482e7811147SRichard Fitzgerald 483e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 484e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 485e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 486e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1); 487e7811147SRichard Fitzgerald if (ret != 0) 488e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", ret); 489e7811147SRichard Fitzgerald 490e7811147SRichard Fitzgerald return ret; 491e7811147SRichard Fitzgerald } 492e7811147SRichard Fitzgerald 493e7811147SRichard Fitzgerald static int arizona_connect_dcvdd(struct arizona *arizona) 494e7811147SRichard Fitzgerald { 495e7811147SRichard Fitzgerald int ret; 496e7811147SRichard Fitzgerald 497e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 498e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 499e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 0); 500e7811147SRichard Fitzgerald if (ret != 0) 501e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to connect DCVDD: %d\n", ret); 502e7811147SRichard Fitzgerald 503e7811147SRichard Fitzgerald return ret; 504e7811147SRichard Fitzgerald } 505e7811147SRichard Fitzgerald 506e3424273SRichard Fitzgerald static int arizona_is_jack_det_active(struct arizona *arizona) 507e3424273SRichard Fitzgerald { 508e3424273SRichard Fitzgerald unsigned int val; 509e3424273SRichard Fitzgerald int ret; 510e3424273SRichard Fitzgerald 511e3424273SRichard Fitzgerald ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val); 512e3424273SRichard Fitzgerald if (ret) { 513e3424273SRichard Fitzgerald dev_err(arizona->dev, 514e3424273SRichard Fitzgerald "Failed to check jack det status: %d\n", ret); 515e3424273SRichard Fitzgerald return ret; 516e3424273SRichard Fitzgerald } else if (val & ARIZONA_JD1_ENA) { 517e3424273SRichard Fitzgerald return 1; 518e3424273SRichard Fitzgerald } else { 519e3424273SRichard Fitzgerald return 0; 520e3424273SRichard Fitzgerald } 521e3424273SRichard Fitzgerald } 522e3424273SRichard Fitzgerald 5233cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 5243cc72986SMark Brown { 5253cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 5263cc72986SMark Brown int ret; 5273cc72986SMark Brown 528508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 529508c8299SMark Brown 530e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 531e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Re-enabling core supplies\n"); 532e6cb7341SCharles Keepax 533e6cb7341SCharles Keepax ret = regulator_bulk_enable(arizona->num_core_supplies, 534e6cb7341SCharles Keepax arizona->core_supplies); 535e6cb7341SCharles Keepax if (ret) { 536e6cb7341SCharles Keepax dev_err(dev, "Failed to enable core supplies: %d\n", 537e6cb7341SCharles Keepax ret); 538e6cb7341SCharles Keepax return ret; 539e6cb7341SCharles Keepax } 540e6cb7341SCharles Keepax } 541e6cb7341SCharles Keepax 54259db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 54359db9691SMark Brown if (ret != 0) { 54459db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 545e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) 546e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 547e6cb7341SCharles Keepax arizona->core_supplies); 54859db9691SMark Brown return ret; 54959db9691SMark Brown } 5503cc72986SMark Brown 551e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 552e6cb7341SCharles Keepax arizona_disable_reset(arizona); 553e6cb7341SCharles Keepax enable_irq(arizona->irq); 554e6cb7341SCharles Keepax arizona->has_fully_powered_off = false; 555e6cb7341SCharles Keepax } 556e6cb7341SCharles Keepax 5573cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 5583cc72986SMark Brown 5594c9bb8bcSCharles Keepax switch (arizona->type) { 5604c9bb8bcSCharles Keepax case WM5102: 5615927467dSMark Brown if (arizona->external_dcvdd) { 562e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 563e7811147SRichard Fitzgerald if (ret != 0) 5645927467dSMark Brown goto err; 5655927467dSMark Brown } 5665927467dSMark Brown 5674c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 5684c9bb8bcSCharles Keepax if (ret != 0) { 5694c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 5704c9bb8bcSCharles Keepax ret); 5714c9bb8bcSCharles Keepax goto err; 5724c9bb8bcSCharles Keepax } 573e80436bbSCharles Keepax 5740be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 5750be068a0SCharles Keepax if (ret) { 576e80436bbSCharles Keepax dev_err(arizona->dev, 577e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 578e80436bbSCharles Keepax ret); 579e80436bbSCharles Keepax goto err; 580e80436bbSCharles Keepax } 581e80436bbSCharles Keepax break; 58296129a0eSCharles Keepax case WM5110: 58396129a0eSCharles Keepax case WM8280: 58496129a0eSCharles Keepax ret = arizona_wait_for_boot(arizona); 58596129a0eSCharles Keepax if (ret) 58696129a0eSCharles Keepax goto err; 58796129a0eSCharles Keepax 58896129a0eSCharles Keepax if (arizona->external_dcvdd) { 589e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 590e7811147SRichard Fitzgerald if (ret != 0) 59196129a0eSCharles Keepax goto err; 59296129a0eSCharles Keepax } else { 59396129a0eSCharles Keepax /* 59496129a0eSCharles Keepax * As this is only called for the internal regulator 59596129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 59696129a0eSCharles Keepax * to request an exact range. 59796129a0eSCharles Keepax */ 59896129a0eSCharles Keepax ret = regulator_set_voltage(arizona->dcvdd, 59996129a0eSCharles Keepax 1200000, 1200000); 60096129a0eSCharles Keepax if (ret < 0) { 60196129a0eSCharles Keepax dev_err(arizona->dev, 60296129a0eSCharles Keepax "Failed to set resume voltage: %d\n", 60396129a0eSCharles Keepax ret); 60496129a0eSCharles Keepax goto err; 60596129a0eSCharles Keepax } 60696129a0eSCharles Keepax } 607e6cb7341SCharles Keepax 608e6cb7341SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 609e6cb7341SCharles Keepax if (ret) { 610e6cb7341SCharles Keepax dev_err(arizona->dev, 611e6cb7341SCharles Keepax "Failed to re-apply sleep patch: %d\n", 612e6cb7341SCharles Keepax ret); 613e6cb7341SCharles Keepax goto err; 614e6cb7341SCharles Keepax } 61596129a0eSCharles Keepax break; 616ea1f3339SRichard Fitzgerald case WM1831: 617ea1f3339SRichard Fitzgerald case CS47L24: 618ea1f3339SRichard Fitzgerald ret = arizona_wait_for_boot(arizona); 619ea1f3339SRichard Fitzgerald if (ret != 0) 620ea1f3339SRichard Fitzgerald goto err; 621ea1f3339SRichard Fitzgerald break; 622e80436bbSCharles Keepax default: 62312bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 6243762aedeSCharles Keepax if (ret != 0) 62512bb68edSCharles Keepax goto err; 62612bb68edSCharles Keepax 6275927467dSMark Brown if (arizona->external_dcvdd) { 628e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 629e7811147SRichard Fitzgerald if (ret != 0) 6305927467dSMark Brown goto err; 6315927467dSMark Brown } 632e80436bbSCharles Keepax break; 6334c9bb8bcSCharles Keepax } 6344c9bb8bcSCharles Keepax 6359270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 6369270bdf5SMark Brown if (ret != 0) { 6379270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 6384816bd1cSMark Brown goto err; 6399270bdf5SMark Brown } 6403cc72986SMark Brown 6413cc72986SMark Brown return 0; 6424816bd1cSMark Brown 6434816bd1cSMark Brown err: 6444816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 6454816bd1cSMark Brown regulator_disable(arizona->dcvdd); 6464816bd1cSMark Brown return ret; 6473cc72986SMark Brown } 6483cc72986SMark Brown 6493cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 6503cc72986SMark Brown { 6513cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 652a05950a4SDan Carpenter int jd_active = 0; 6535927467dSMark Brown int ret; 6543cc72986SMark Brown 655508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 656508c8299SMark Brown 65796129a0eSCharles Keepax switch (arizona->type) { 65896129a0eSCharles Keepax case WM5110: 65996129a0eSCharles Keepax case WM8280: 660e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 661e3424273SRichard Fitzgerald if (jd_active < 0) 662e3424273SRichard Fitzgerald return jd_active; 663e3424273SRichard Fitzgerald 664e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 665e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 666e7811147SRichard Fitzgerald if (ret != 0) 667e7811147SRichard Fitzgerald return ret; 668e7811147SRichard Fitzgerald } else { 66996129a0eSCharles Keepax /* 67096129a0eSCharles Keepax * As this is only called for the internal regulator 67196129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 67296129a0eSCharles Keepax * to request an exact range. 67396129a0eSCharles Keepax */ 674e7811147SRichard Fitzgerald ret = regulator_set_voltage(arizona->dcvdd, 675e7811147SRichard Fitzgerald 1175000, 1175000); 67696129a0eSCharles Keepax if (ret < 0) { 67796129a0eSCharles Keepax dev_err(arizona->dev, 678e7811147SRichard Fitzgerald "Failed to set suspend voltage: %d\n", 679e7811147SRichard Fitzgerald ret); 680e6cb7341SCharles Keepax return ret; 681e6cb7341SCharles Keepax } 682e7811147SRichard Fitzgerald } 683e6cb7341SCharles Keepax break; 684e6cb7341SCharles Keepax case WM5102: 685e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 686e3424273SRichard Fitzgerald if (jd_active < 0) 687e3424273SRichard Fitzgerald return jd_active; 688e3424273SRichard Fitzgerald 689e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 690e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 691e7811147SRichard Fitzgerald if (ret != 0) 692e7811147SRichard Fitzgerald return ret; 693e7811147SRichard Fitzgerald } 694e7811147SRichard Fitzgerald 695e3424273SRichard Fitzgerald if (!jd_active) { 696e6cb7341SCharles Keepax ret = regmap_write(arizona->regmap, 697e6cb7341SCharles Keepax ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0); 698e6cb7341SCharles Keepax if (ret) { 699e6cb7341SCharles Keepax dev_err(arizona->dev, 700e6cb7341SCharles Keepax "Failed to clear write sequencer: %d\n", 70196129a0eSCharles Keepax ret); 70296129a0eSCharles Keepax return ret; 70396129a0eSCharles Keepax } 704e6cb7341SCharles Keepax } 70596129a0eSCharles Keepax break; 706ea1f3339SRichard Fitzgerald case WM1831: 707ea1f3339SRichard Fitzgerald case CS47L24: 708ea1f3339SRichard Fitzgerald break; 70996129a0eSCharles Keepax default: 710e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 711e3424273SRichard Fitzgerald if (jd_active < 0) 712e3424273SRichard Fitzgerald return jd_active; 713e3424273SRichard Fitzgerald 714e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 715e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 716e7811147SRichard Fitzgerald if (ret != 0) 717e7811147SRichard Fitzgerald return ret; 718e7811147SRichard Fitzgerald } 71996129a0eSCharles Keepax break; 72096129a0eSCharles Keepax } 7215927467dSMark Brown 7223cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 7233cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 724e293e847SCharles Keepax regulator_disable(arizona->dcvdd); 7253cc72986SMark Brown 726e6cb7341SCharles Keepax /* Allow us to completely power down if no jack detection */ 727e3424273SRichard Fitzgerald if (!jd_active) { 728e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Fully powering off\n"); 729e6cb7341SCharles Keepax 730e6cb7341SCharles Keepax arizona->has_fully_powered_off = true; 731e6cb7341SCharles Keepax 73211150929SCharles Keepax disable_irq_nosync(arizona->irq); 733e6cb7341SCharles Keepax arizona_enable_reset(arizona); 734e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 735e6cb7341SCharles Keepax arizona->core_supplies); 736e6cb7341SCharles Keepax } 737e6cb7341SCharles Keepax 7383cc72986SMark Brown return 0; 7393cc72986SMark Brown } 7403cc72986SMark Brown #endif 7413cc72986SMark Brown 742dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 74367c99296SMark Brown static int arizona_suspend(struct device *dev) 74467c99296SMark Brown { 74567c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 74667c99296SMark Brown 74767c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 74867c99296SMark Brown disable_irq(arizona->irq); 74967c99296SMark Brown 75067c99296SMark Brown return 0; 75167c99296SMark Brown } 75267c99296SMark Brown 75367c99296SMark Brown static int arizona_suspend_late(struct device *dev) 75467c99296SMark Brown { 75567c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 75667c99296SMark Brown 75767c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 75867c99296SMark Brown enable_irq(arizona->irq); 75967c99296SMark Brown 76067c99296SMark Brown return 0; 76167c99296SMark Brown } 76267c99296SMark Brown 763dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 764dc781d0eSMark Brown { 765dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 766dc781d0eSMark Brown 767dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 768dc781d0eSMark Brown disable_irq(arizona->irq); 769dc781d0eSMark Brown 770dc781d0eSMark Brown return 0; 771dc781d0eSMark Brown } 772dc781d0eSMark Brown 773dc781d0eSMark Brown static int arizona_resume(struct device *dev) 774dc781d0eSMark Brown { 775dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 776dc781d0eSMark Brown 777dc781d0eSMark Brown dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); 778dc781d0eSMark Brown enable_irq(arizona->irq); 779dc781d0eSMark Brown 780dc781d0eSMark Brown return 0; 781dc781d0eSMark Brown } 782dc781d0eSMark Brown #endif 783dc781d0eSMark Brown 7843cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 7853cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 7863cc72986SMark Brown arizona_runtime_resume, 7873cc72986SMark Brown NULL) 78867c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 789dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 79067c99296SMark Brown .suspend_late = arizona_suspend_late, 791dc781d0eSMark Brown .resume_noirq = arizona_resume_noirq, 792dc781d0eSMark Brown #endif 7933cc72986SMark Brown }; 7943cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 7953cc72986SMark Brown 796d781009cSMark Brown #ifdef CONFIG_OF 797942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev) 798d781009cSMark Brown { 799d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 800d781009cSMark Brown 801d781009cSMark Brown if (id) 802942786e6SLee Jones return (unsigned long)id->data; 803d781009cSMark Brown else 804d781009cSMark Brown return 0; 805d781009cSMark Brown } 806d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 807d781009cSMark Brown 808e4fcb1d6SCharles Keepax int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, 809e4fcb1d6SCharles Keepax bool mandatory) 810e4fcb1d6SCharles Keepax { 811e4fcb1d6SCharles Keepax int gpio; 812e4fcb1d6SCharles Keepax 813e4fcb1d6SCharles Keepax gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0); 814e4fcb1d6SCharles Keepax if (gpio < 0) { 815e4fcb1d6SCharles Keepax if (mandatory) 816e4fcb1d6SCharles Keepax dev_err(arizona->dev, 817e4fcb1d6SCharles Keepax "Mandatory DT gpio %s missing/malformed: %d\n", 818e4fcb1d6SCharles Keepax prop, gpio); 819e4fcb1d6SCharles Keepax 820e4fcb1d6SCharles Keepax gpio = 0; 821e4fcb1d6SCharles Keepax } 822e4fcb1d6SCharles Keepax 823e4fcb1d6SCharles Keepax return gpio; 824e4fcb1d6SCharles Keepax } 825e4fcb1d6SCharles Keepax EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); 826e4fcb1d6SCharles Keepax 827d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 828d781009cSMark Brown { 829e4fcb1d6SCharles Keepax struct arizona_pdata *pdata = &arizona->pdata; 830cc47aed9SInha Song struct property *prop; 831cc47aed9SInha Song const __be32 *cur; 832cc47aed9SInha Song u32 val; 833d781009cSMark Brown int ret, i; 834cc47aed9SInha Song int count = 0; 835d781009cSMark Brown 836e4fcb1d6SCharles Keepax pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); 837d781009cSMark Brown 838d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 839d781009cSMark Brown "wlf,gpio-defaults", 8403762aedeSCharles Keepax pdata->gpio_defaults, 8413762aedeSCharles Keepax ARRAY_SIZE(pdata->gpio_defaults)); 842d781009cSMark Brown if (ret >= 0) { 843d781009cSMark Brown /* 844d781009cSMark Brown * All values are literal except out of range values 845d781009cSMark Brown * which are chip default, translate into platform 846d781009cSMark Brown * data which uses 0 as chip default and out of range 847d781009cSMark Brown * as zero. 848d781009cSMark Brown */ 8493762aedeSCharles Keepax for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { 8503762aedeSCharles Keepax if (pdata->gpio_defaults[i] > 0xffff) 8513762aedeSCharles Keepax pdata->gpio_defaults[i] = 0; 8523762aedeSCharles Keepax else if (pdata->gpio_defaults[i] == 0) 8533762aedeSCharles Keepax pdata->gpio_defaults[i] = 0x10000; 854d781009cSMark Brown } 855d781009cSMark Brown } else { 856d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 857d781009cSMark Brown ret); 858d781009cSMark Brown } 859d781009cSMark Brown 860cc47aed9SInha Song of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop, 861cc47aed9SInha Song cur, val) { 8623762aedeSCharles Keepax if (count == ARRAY_SIZE(pdata->inmode)) 863cc47aed9SInha Song break; 864cc47aed9SInha Song 8653762aedeSCharles Keepax pdata->inmode[count] = val; 866cc47aed9SInha Song count++; 867cc47aed9SInha Song } 868cc47aed9SInha Song 869e7ad27caSCharles Keepax count = 0; 870e7ad27caSCharles Keepax of_property_for_each_u32(arizona->dev->of_node, "wlf,dmic-ref", prop, 871e7ad27caSCharles Keepax cur, val) { 8723762aedeSCharles Keepax if (count == ARRAY_SIZE(pdata->dmic_ref)) 873e7ad27caSCharles Keepax break; 874e7ad27caSCharles Keepax 8753762aedeSCharles Keepax pdata->dmic_ref[count] = val; 876e7ad27caSCharles Keepax count++; 877e7ad27caSCharles Keepax } 878e7ad27caSCharles Keepax 879f199d393SCharles Keepax count = 0; 880f199d393SCharles Keepax of_property_for_each_u32(arizona->dev->of_node, "wlf,out-mono", prop, 881f199d393SCharles Keepax cur, val) { 882f199d393SCharles Keepax if (count == ARRAY_SIZE(pdata->out_mono)) 883f199d393SCharles Keepax break; 884f199d393SCharles Keepax 885f199d393SCharles Keepax pdata->out_mono[count] = !!val; 886f199d393SCharles Keepax count++; 887f199d393SCharles Keepax } 888f199d393SCharles Keepax 889d781009cSMark Brown return 0; 890d781009cSMark Brown } 891d781009cSMark Brown 892d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 893d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 894d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 895e5d4ef0dSRichard Fitzgerald { .compatible = "wlf,wm8280", .data = (void *)WM8280 }, 896dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 8976887b042SRichard Fitzgerald { .compatible = "wlf,wm8998", .data = (void *)WM8998 }, 8986887b042SRichard Fitzgerald { .compatible = "wlf,wm1814", .data = (void *)WM1814 }, 899ea1f3339SRichard Fitzgerald { .compatible = "wlf,wm1831", .data = (void *)WM1831 }, 900ea1f3339SRichard Fitzgerald { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 }, 901d781009cSMark Brown {}, 902d781009cSMark Brown }; 903d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 904d781009cSMark Brown #else 905d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 906d781009cSMark Brown { 907d781009cSMark Brown return 0; 908d781009cSMark Brown } 909d781009cSMark Brown #endif 910d781009cSMark Brown 9115ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = { 9123cc72986SMark Brown { .name = "arizona-ldo1" }, 9133cc72986SMark Brown }; 9143cc72986SMark Brown 9153762aedeSCharles Keepax static const char * const wm5102_supplies[] = { 9165fc6c396SCharles Keepax "MICVDD", 91732dadef2SCharles Keepax "DBVDD2", 91832dadef2SCharles Keepax "DBVDD3", 91932dadef2SCharles Keepax "CPVDD", 92032dadef2SCharles Keepax "SPKVDDL", 92132dadef2SCharles Keepax "SPKVDDR", 92232dadef2SCharles Keepax }; 92332dadef2SCharles Keepax 9245ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = { 925d7768111SMark Brown { .name = "arizona-micsupp" }, 926f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9275fc6c396SCharles Keepax { 9285fc6c396SCharles Keepax .name = "arizona-extcon", 9295fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9305fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9315fc6c396SCharles Keepax }, 932503b1cacSMark Brown { .name = "arizona-haptics" }, 9333cc72986SMark Brown { .name = "arizona-pwm" }, 93432dadef2SCharles Keepax { 93532dadef2SCharles Keepax .name = "wm5102-codec", 93632dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 93732dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 93832dadef2SCharles Keepax }, 9393cc72986SMark Brown }; 9403cc72986SMark Brown 9415ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = { 942d7768111SMark Brown { .name = "arizona-micsupp" }, 943f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9445fc6c396SCharles Keepax { 9455fc6c396SCharles Keepax .name = "arizona-extcon", 9465fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9475fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9485fc6c396SCharles Keepax }, 949503b1cacSMark Brown { .name = "arizona-haptics" }, 950e102befeSMark Brown { .name = "arizona-pwm" }, 95132dadef2SCharles Keepax { 95232dadef2SCharles Keepax .name = "wm5110-codec", 95332dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 95432dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 95532dadef2SCharles Keepax }, 95632dadef2SCharles Keepax }; 95732dadef2SCharles Keepax 958ea1f3339SRichard Fitzgerald static const char * const cs47l24_supplies[] = { 959ea1f3339SRichard Fitzgerald "MICVDD", 960ea1f3339SRichard Fitzgerald "CPVDD", 961ea1f3339SRichard Fitzgerald "SPKVDD", 962ea1f3339SRichard Fitzgerald }; 963ea1f3339SRichard Fitzgerald 964ea1f3339SRichard Fitzgerald static const struct mfd_cell cs47l24_devs[] = { 965ea1f3339SRichard Fitzgerald { .name = "arizona-gpio" }, 966ea1f3339SRichard Fitzgerald { .name = "arizona-haptics" }, 967ea1f3339SRichard Fitzgerald { .name = "arizona-pwm" }, 968ea1f3339SRichard Fitzgerald { 969ea1f3339SRichard Fitzgerald .name = "cs47l24-codec", 970ea1f3339SRichard Fitzgerald .parent_supplies = cs47l24_supplies, 971ea1f3339SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(cs47l24_supplies), 972ea1f3339SRichard Fitzgerald }, 973ea1f3339SRichard Fitzgerald }; 974ea1f3339SRichard Fitzgerald 9753762aedeSCharles Keepax static const char * const wm8997_supplies[] = { 976996c2d4fSCharles Keepax "MICVDD", 97732dadef2SCharles Keepax "DBVDD2", 97832dadef2SCharles Keepax "CPVDD", 97932dadef2SCharles Keepax "SPKVDD", 980e102befeSMark Brown }; 981e102befeSMark Brown 9825ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = { 983dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 984f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9855fc6c396SCharles Keepax { 9865fc6c396SCharles Keepax .name = "arizona-extcon", 9875fc6c396SCharles Keepax .parent_supplies = wm8997_supplies, 9885fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9895fc6c396SCharles Keepax }, 990dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 991dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 99232dadef2SCharles Keepax { 99332dadef2SCharles Keepax .name = "wm8997-codec", 99432dadef2SCharles Keepax .parent_supplies = wm8997_supplies, 99532dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), 99632dadef2SCharles Keepax }, 997dc7d4863SCharles Keepax }; 998dc7d4863SCharles Keepax 9996887b042SRichard Fitzgerald static const struct mfd_cell wm8998_devs[] = { 1000f83c218cSCharles Keepax { .name = "arizona-micsupp" }, 1001f83c218cSCharles Keepax { .name = "arizona-gpio" }, 10026887b042SRichard Fitzgerald { 10036887b042SRichard Fitzgerald .name = "arizona-extcon", 10046887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 10056887b042SRichard Fitzgerald .num_parent_supplies = 1, /* We only need MICVDD */ 10066887b042SRichard Fitzgerald }, 10076887b042SRichard Fitzgerald { .name = "arizona-haptics" }, 10086887b042SRichard Fitzgerald { .name = "arizona-pwm" }, 10096887b042SRichard Fitzgerald { 10106887b042SRichard Fitzgerald .name = "wm8998-codec", 10116887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 10126887b042SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 10136887b042SRichard Fitzgerald }, 10146887b042SRichard Fitzgerald }; 10156887b042SRichard Fitzgerald 1016f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 10173cc72986SMark Brown { 1018*cdd8da8cSSylwester Nawrocki const char * const mclk_name[] = { "mclk1", "mclk2" }; 10193cc72986SMark Brown struct device *dev = arizona->dev; 1020ea1f3339SRichard Fitzgerald const char *type_name = NULL; 10216887b042SRichard Fitzgerald unsigned int reg, val, mask; 102262d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 1023ae05ea36SRichard Fitzgerald const struct mfd_cell *subdevs = NULL; 1024ae05ea36SRichard Fitzgerald int n_subdevs, ret, i; 10253cc72986SMark Brown 10263cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 10273cc72986SMark Brown mutex_init(&arizona->clk_lock); 10283cc72986SMark Brown 10293cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 10303cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 10313cc72986SMark Brown sizeof(arizona->pdata)); 103222d7dc8aSLee Jones else 103322d7dc8aSLee Jones arizona_of_get_core_pdata(arizona); 10343cc72986SMark Brown 1035*cdd8da8cSSylwester Nawrocki BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name)); 1036*cdd8da8cSSylwester Nawrocki for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) { 1037*cdd8da8cSSylwester Nawrocki arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]); 1038*cdd8da8cSSylwester Nawrocki if (IS_ERR(arizona->mclk[i])) { 1039*cdd8da8cSSylwester Nawrocki dev_info(arizona->dev, "Failed to get %s: %ld\n", 1040*cdd8da8cSSylwester Nawrocki mclk_name[i], PTR_ERR(arizona->mclk[i])); 1041*cdd8da8cSSylwester Nawrocki arizona->mclk[i] = NULL; 1042*cdd8da8cSSylwester Nawrocki } 1043*cdd8da8cSSylwester Nawrocki } 1044*cdd8da8cSSylwester Nawrocki 10453cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 10463cc72986SMark Brown 10473cc72986SMark Brown switch (arizona->type) { 10483cc72986SMark Brown case WM5102: 1049e102befeSMark Brown case WM5110: 1050e5d4ef0dSRichard Fitzgerald case WM8280: 1051dc7d4863SCharles Keepax case WM8997: 10526887b042SRichard Fitzgerald case WM8998: 10536887b042SRichard Fitzgerald case WM1814: 1054ea1f3339SRichard Fitzgerald case WM1831: 1055ea1f3339SRichard Fitzgerald case CS47L24: 10563cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 10573cc72986SMark Brown arizona->core_supplies[i].supply 10583cc72986SMark Brown = wm5102_core_supplies[i]; 10593cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 10603cc72986SMark Brown break; 10613cc72986SMark Brown default: 10623cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 10633cc72986SMark Brown arizona->type); 10643cc72986SMark Brown return -EINVAL; 10653cc72986SMark Brown } 10663cc72986SMark Brown 10674a8c475fSCharles Keepax /* Mark DCVDD as external, LDO1 driver will clear if internal */ 10684a8c475fSCharles Keepax arizona->external_dcvdd = true; 10694a8c475fSCharles Keepax 1070ea1f3339SRichard Fitzgerald switch (arizona->type) { 1071ea1f3339SRichard Fitzgerald case WM1831: 1072ea1f3339SRichard Fitzgerald case CS47L24: 1073ea1f3339SRichard Fitzgerald break; /* No LDO1 regulator */ 1074ea1f3339SRichard Fitzgerald default: 10753cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 10760848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 10773cc72986SMark Brown if (ret != 0) { 10783cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 10793cc72986SMark Brown return ret; 10803cc72986SMark Brown } 1081ea1f3339SRichard Fitzgerald break; 1082ea1f3339SRichard Fitzgerald } 10833cc72986SMark Brown 10843cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 10853cc72986SMark Brown arizona->core_supplies); 10863cc72986SMark Brown if (ret != 0) { 10873cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 10883cc72986SMark Brown ret); 10893cc72986SMark Brown goto err_early; 10903cc72986SMark Brown } 10913cc72986SMark Brown 10920c2d0ffbSCharles Keepax /** 10930c2d0ffbSCharles Keepax * Don't use devres here because the only device we have to get 10940c2d0ffbSCharles Keepax * against is the MFD device and DCVDD will likely be supplied by 10950c2d0ffbSCharles Keepax * one of its children. Meaning that the regulator will be 10960c2d0ffbSCharles Keepax * destroyed by the time devres calls regulator put. 10970c2d0ffbSCharles Keepax */ 1098e6021511SCharles Keepax arizona->dcvdd = regulator_get(arizona->dev, "DCVDD"); 109959db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 110059db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 110159db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 110259db9691SMark Brown goto err_early; 110359db9691SMark Brown } 110459db9691SMark Brown 110587d3af4aSMark Brown if (arizona->pdata.reset) { 110687d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 11075f056bf0SCharles Keepax ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset, 110887d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 110987d3af4aSMark Brown "arizona /RESET"); 111087d3af4aSMark Brown if (ret != 0) { 111187d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 1112e6021511SCharles Keepax goto err_dcvdd; 111387d3af4aSMark Brown } 111487d3af4aSMark Brown } 111587d3af4aSMark Brown 11163cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 11173cc72986SMark Brown arizona->core_supplies); 11183cc72986SMark Brown if (ret != 0) { 11193cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 11203cc72986SMark Brown ret); 1121e6021511SCharles Keepax goto err_dcvdd; 11223cc72986SMark Brown } 11233cc72986SMark Brown 112459db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 112559db9691SMark Brown if (ret != 0) { 112659db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 112759db9691SMark Brown goto err_enable; 112859db9691SMark Brown } 112959db9691SMark Brown 11302229875dSCharles Keepax arizona_disable_reset(arizona); 11313cc72986SMark Brown 11323cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 11333cc72986SMark Brown 1134ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 1135ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 1136ca76ceb8SMark Brown if (ret != 0) { 1137ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 1138ca76ceb8SMark Brown goto err_reset; 1139ca76ceb8SMark Brown } 1140ca76ceb8SMark Brown 1141ca76ceb8SMark Brown switch (reg) { 1142ca76ceb8SMark Brown case 0x5102: 1143ca76ceb8SMark Brown case 0x5110: 11446887b042SRichard Fitzgerald case 0x6349: 1145ea1f3339SRichard Fitzgerald case 0x6363: 1146dc7d4863SCharles Keepax case 0x8997: 1147ca76ceb8SMark Brown break; 1148ca76ceb8SMark Brown default: 1149ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 1150ca76ceb8SMark Brown goto err_reset; 1151ca76ceb8SMark Brown } 1152ca76ceb8SMark Brown 1153ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 1154ca76ceb8SMark Brown if (!arizona->pdata.reset) { 1155ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 1156ca76ceb8SMark Brown if (ret != 0) { 1157ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 1158ca76ceb8SMark Brown goto err_reset; 1159ca76ceb8SMark Brown } 1160ca76ceb8SMark Brown 1161b79a980fSLee Jones usleep_range(1000, 5000); 1162ca76ceb8SMark Brown } 1163ca76ceb8SMark Brown 1164ca76ceb8SMark Brown /* Ensure device startup is complete */ 1165ca76ceb8SMark Brown switch (arizona->type) { 1166ca76ceb8SMark Brown case WM5102: 116748018943SMark Brown ret = regmap_read(arizona->regmap, 116848018943SMark Brown ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); 11691c1c6bbaSCharles Keepax if (ret) { 1170ca76ceb8SMark Brown dev_err(dev, 1171ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 1172ca76ceb8SMark Brown ret); 11731c1c6bbaSCharles Keepax } else if (val & 0x01) { 11741c1c6bbaSCharles Keepax ret = wm5102_clear_write_sequencer(arizona); 11751c1c6bbaSCharles Keepax if (ret) 11761c1c6bbaSCharles Keepax return ret; 1177ca76ceb8SMark Brown } 1178ca76ceb8SMark Brown break; 11791c1c6bbaSCharles Keepax default: 11801c1c6bbaSCharles Keepax break; 11811c1c6bbaSCharles Keepax } 11821c1c6bbaSCharles Keepax 11831c1c6bbaSCharles Keepax ret = arizona_wait_for_boot(arizona); 11841c1c6bbaSCharles Keepax if (ret) { 11851c1c6bbaSCharles Keepax dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); 11861c1c6bbaSCharles Keepax goto err_reset; 1187ca76ceb8SMark Brown } 1188ca76ceb8SMark Brown 1189ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 11903cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 11913cc72986SMark Brown if (ret != 0) { 11923cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 119359db9691SMark Brown goto err_reset; 11943cc72986SMark Brown } 11953cc72986SMark Brown 11963cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 11973cc72986SMark Brown &arizona->rev); 11983cc72986SMark Brown if (ret != 0) { 11993cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 120059db9691SMark Brown goto err_reset; 12013cc72986SMark Brown } 12023cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 12033cc72986SMark Brown 12043cc72986SMark Brown switch (reg) { 12053cc72986SMark Brown case 0x5102: 1206b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5102)) { 12073cc72986SMark Brown type_name = "WM5102"; 12083cc72986SMark Brown if (arizona->type != WM5102) { 1209b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1210b61c1ec0SRichard Fitzgerald "WM5102 registered as %d\n", 12113cc72986SMark Brown arizona->type); 12123cc72986SMark Brown arizona->type = WM5102; 12133cc72986SMark Brown } 1214b61c1ec0SRichard Fitzgerald 121562d62b59SMark Brown apply_patch = wm5102_patch; 1216c6d6bfb1SMark Brown arizona->rev &= 0x7; 1217ae05ea36SRichard Fitzgerald subdevs = wm5102_devs; 1218ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5102_devs); 1219b61c1ec0SRichard Fitzgerald } 12203cc72986SMark Brown break; 1221e102befeSMark Brown case 0x5110: 1222b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5110)) { 1223e5d4ef0dSRichard Fitzgerald switch (arizona->type) { 1224e5d4ef0dSRichard Fitzgerald case WM5110: 1225e102befeSMark Brown type_name = "WM5110"; 1226e5d4ef0dSRichard Fitzgerald break; 1227e5d4ef0dSRichard Fitzgerald case WM8280: 1228e5d4ef0dSRichard Fitzgerald type_name = "WM8280"; 1229e5d4ef0dSRichard Fitzgerald break; 1230e5d4ef0dSRichard Fitzgerald default: 1231e5d4ef0dSRichard Fitzgerald type_name = "WM5110"; 1232b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1233b61c1ec0SRichard Fitzgerald "WM5110 registered as %d\n", 1234e102befeSMark Brown arizona->type); 1235e102befeSMark Brown arizona->type = WM5110; 1236e5d4ef0dSRichard Fitzgerald break; 1237e102befeSMark Brown } 1238b61c1ec0SRichard Fitzgerald 123962d62b59SMark Brown apply_patch = wm5110_patch; 1240ae05ea36SRichard Fitzgerald subdevs = wm5110_devs; 1241ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5110_devs); 1242b61c1ec0SRichard Fitzgerald } 1243e102befeSMark Brown break; 1244ea1f3339SRichard Fitzgerald case 0x6363: 1245ea1f3339SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_CS47L24)) { 1246ea1f3339SRichard Fitzgerald switch (arizona->type) { 1247ea1f3339SRichard Fitzgerald case CS47L24: 1248ea1f3339SRichard Fitzgerald type_name = "CS47L24"; 1249ea1f3339SRichard Fitzgerald break; 1250ea1f3339SRichard Fitzgerald 1251ea1f3339SRichard Fitzgerald case WM1831: 1252ea1f3339SRichard Fitzgerald type_name = "WM1831"; 1253ea1f3339SRichard Fitzgerald break; 1254ea1f3339SRichard Fitzgerald 1255ea1f3339SRichard Fitzgerald default: 1256ea1f3339SRichard Fitzgerald dev_warn(arizona->dev, 1257ea1f3339SRichard Fitzgerald "CS47L24 registered as %d\n", 1258ea1f3339SRichard Fitzgerald arizona->type); 1259ea1f3339SRichard Fitzgerald arizona->type = CS47L24; 1260ea1f3339SRichard Fitzgerald break; 1261ea1f3339SRichard Fitzgerald } 1262ea1f3339SRichard Fitzgerald 1263ea1f3339SRichard Fitzgerald apply_patch = cs47l24_patch; 1264ea1f3339SRichard Fitzgerald subdevs = cs47l24_devs; 1265ea1f3339SRichard Fitzgerald n_subdevs = ARRAY_SIZE(cs47l24_devs); 1266ea1f3339SRichard Fitzgerald } 1267ea1f3339SRichard Fitzgerald break; 1268dc7d4863SCharles Keepax case 0x8997: 1269b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8997)) { 1270dc7d4863SCharles Keepax type_name = "WM8997"; 1271dc7d4863SCharles Keepax if (arizona->type != WM8997) { 1272b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1273b61c1ec0SRichard Fitzgerald "WM8997 registered as %d\n", 1274dc7d4863SCharles Keepax arizona->type); 1275dc7d4863SCharles Keepax arizona->type = WM8997; 1276dc7d4863SCharles Keepax } 1277b61c1ec0SRichard Fitzgerald 1278dc7d4863SCharles Keepax apply_patch = wm8997_patch; 1279ae05ea36SRichard Fitzgerald subdevs = wm8997_devs; 1280ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8997_devs); 1281b61c1ec0SRichard Fitzgerald } 1282dc7d4863SCharles Keepax break; 12836887b042SRichard Fitzgerald case 0x6349: 1284b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8998)) { 12856887b042SRichard Fitzgerald switch (arizona->type) { 12866887b042SRichard Fitzgerald case WM8998: 12876887b042SRichard Fitzgerald type_name = "WM8998"; 12886887b042SRichard Fitzgerald break; 12896887b042SRichard Fitzgerald 12906887b042SRichard Fitzgerald case WM1814: 12916887b042SRichard Fitzgerald type_name = "WM1814"; 12926887b042SRichard Fitzgerald break; 12936887b042SRichard Fitzgerald 12946887b042SRichard Fitzgerald default: 12956887b042SRichard Fitzgerald type_name = "WM8998"; 1296b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1297b61c1ec0SRichard Fitzgerald "WM8998 registered as %d\n", 12986887b042SRichard Fitzgerald arizona->type); 12996887b042SRichard Fitzgerald arizona->type = WM8998; 13006887b042SRichard Fitzgerald } 13016887b042SRichard Fitzgerald 13026887b042SRichard Fitzgerald apply_patch = wm8998_patch; 1303ae05ea36SRichard Fitzgerald subdevs = wm8998_devs; 1304ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8998_devs); 1305b61c1ec0SRichard Fitzgerald } 13066887b042SRichard Fitzgerald break; 13073cc72986SMark Brown default: 13083cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 130959db9691SMark Brown goto err_reset; 13103cc72986SMark Brown } 13113cc72986SMark Brown 1312b61c1ec0SRichard Fitzgerald if (!subdevs) { 1313b61c1ec0SRichard Fitzgerald dev_err(arizona->dev, 1314b61c1ec0SRichard Fitzgerald "No kernel support for device ID %x\n", reg); 1315b61c1ec0SRichard Fitzgerald goto err_reset; 1316b61c1ec0SRichard Fitzgerald } 1317b61c1ec0SRichard Fitzgerald 13183cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 13193cc72986SMark Brown 132062d62b59SMark Brown if (apply_patch) { 132162d62b59SMark Brown ret = apply_patch(arizona); 132262d62b59SMark Brown if (ret != 0) { 132362d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 132462d62b59SMark Brown ret); 132562d62b59SMark Brown goto err_reset; 132662d62b59SMark Brown } 1327e80436bbSCharles Keepax 1328e80436bbSCharles Keepax switch (arizona->type) { 1329e80436bbSCharles Keepax case WM5102: 13300be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 13310be068a0SCharles Keepax if (ret) { 1332e80436bbSCharles Keepax dev_err(arizona->dev, 1333e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 1334e80436bbSCharles Keepax ret); 1335e80436bbSCharles Keepax goto err_reset; 1336e80436bbSCharles Keepax } 1337e80436bbSCharles Keepax break; 1338882bc468SCharles Keepax case WM5110: 1339882bc468SCharles Keepax case WM8280: 1340882bc468SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 1341882bc468SCharles Keepax if (ret) { 1342882bc468SCharles Keepax dev_err(arizona->dev, 1343882bc468SCharles Keepax "Failed to apply sleep patch: %d\n", 1344882bc468SCharles Keepax ret); 1345882bc468SCharles Keepax goto err_reset; 1346882bc468SCharles Keepax } 1347882bc468SCharles Keepax break; 1348e80436bbSCharles Keepax default: 1349e80436bbSCharles Keepax break; 1350e80436bbSCharles Keepax } 135162d62b59SMark Brown } 135262d62b59SMark Brown 13533cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 13543cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 13553cc72986SMark Brown continue; 13563cc72986SMark Brown 13573cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 13583cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 13593cc72986SMark Brown } 13603cc72986SMark Brown 13613cc72986SMark Brown /* Chip default */ 13623cc72986SMark Brown if (!arizona->pdata.clk32k_src) 13633cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 13643cc72986SMark Brown 13653cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 13663cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 13673cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 13683cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 13693cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 13703cc72986SMark Brown arizona->pdata.clk32k_src - 1); 1371767c6dc0SMark Brown arizona_clk32k_enable(arizona); 13723cc72986SMark Brown break; 13733cc72986SMark Brown case ARIZONA_32KZ_NONE: 13743cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 13753cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 13763cc72986SMark Brown break; 13773cc72986SMark Brown default: 13783cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 13793cc72986SMark Brown arizona->pdata.clk32k_src); 13803cc72986SMark Brown ret = -EINVAL; 138159db9691SMark Brown goto err_reset; 13823cc72986SMark Brown } 13833cc72986SMark Brown 13843d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 1385544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 1386544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 13873d91f828SMark Brown continue; 13883d91f828SMark Brown 1389544c7aadSMark Brown /* Apply default for bypass mode */ 1390544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 1391544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 1392544c7aadSMark Brown 13933d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 1394544c7aadSMark Brown 13953d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 13963d91f828SMark Brown 13973d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 13983d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 13993d91f828SMark Brown 14003d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 14013d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 14023d91f828SMark Brown 1403f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 14043d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 14053d91f828SMark Brown 1406544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 1407544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 1408544c7aadSMark Brown 14093d91f828SMark Brown regmap_update_bits(arizona->regmap, 14103d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 14113d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 141271d134b9SCharles Keepax ARIZONA_MICB1_EXT_CAP | 14133d91f828SMark Brown ARIZONA_MICB1_DISCH | 1414544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 14153d91f828SMark Brown ARIZONA_MICB1_RATE, val); 14163d91f828SMark Brown } 14173d91f828SMark Brown 14183cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 14193cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 14203cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 14213cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 1422fc027d13SRichard Fitzgerald if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC) 1423fc027d13SRichard Fitzgerald val |= 1 << ARIZONA_IN1_MODE_SHIFT; 14246887b042SRichard Fitzgerald 14256887b042SRichard Fitzgerald switch (arizona->type) { 14266887b042SRichard Fitzgerald case WM8998: 14276887b042SRichard Fitzgerald case WM1814: 14286887b042SRichard Fitzgerald regmap_update_bits(arizona->regmap, 14296887b042SRichard Fitzgerald ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8), 14306887b042SRichard Fitzgerald ARIZONA_IN1L_SRC_SE_MASK, 14316887b042SRichard Fitzgerald (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 14326887b042SRichard Fitzgerald << ARIZONA_IN1L_SRC_SE_SHIFT); 14336887b042SRichard Fitzgerald 14346887b042SRichard Fitzgerald regmap_update_bits(arizona->regmap, 14356887b042SRichard Fitzgerald ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8), 14366887b042SRichard Fitzgerald ARIZONA_IN1R_SRC_SE_MASK, 14376887b042SRichard Fitzgerald (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 14386887b042SRichard Fitzgerald << ARIZONA_IN1R_SRC_SE_SHIFT); 14396887b042SRichard Fitzgerald 14406887b042SRichard Fitzgerald mask = ARIZONA_IN1_DMIC_SUP_MASK | 14416887b042SRichard Fitzgerald ARIZONA_IN1_MODE_MASK; 14426887b042SRichard Fitzgerald break; 14436887b042SRichard Fitzgerald default: 1444fc027d13SRichard Fitzgerald if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 1445fc027d13SRichard Fitzgerald val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT; 14463cc72986SMark Brown 14476887b042SRichard Fitzgerald mask = ARIZONA_IN1_DMIC_SUP_MASK | 14486887b042SRichard Fitzgerald ARIZONA_IN1_MODE_MASK | 14496887b042SRichard Fitzgerald ARIZONA_IN1_SINGLE_ENDED_MASK; 14506887b042SRichard Fitzgerald break; 14516887b042SRichard Fitzgerald } 14526887b042SRichard Fitzgerald 14533cc72986SMark Brown regmap_update_bits(arizona->regmap, 14543cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 14556887b042SRichard Fitzgerald mask, val); 14563cc72986SMark Brown } 14573cc72986SMark Brown 14583cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 14593cc72986SMark Brown /* Default is 0 so noop with defaults */ 14603cc72986SMark Brown if (arizona->pdata.out_mono[i]) 14613cc72986SMark Brown val = ARIZONA_OUT1_MONO; 14623cc72986SMark Brown else 14633cc72986SMark Brown val = 0; 14643cc72986SMark Brown 14653cc72986SMark Brown regmap_update_bits(arizona->regmap, 14663cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 14673cc72986SMark Brown ARIZONA_OUT1_MONO, val); 14683cc72986SMark Brown } 14693cc72986SMark Brown 14703cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 14713cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 14723cc72986SMark Brown regmap_update_bits(arizona->regmap, 14732a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 14743cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 14753cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 14763cc72986SMark Brown arizona->pdata.spk_mute[i]); 14773cc72986SMark Brown 14783cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 14793cc72986SMark Brown regmap_update_bits(arizona->regmap, 14802a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 14813cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 14823cc72986SMark Brown arizona->pdata.spk_fmt[i]); 14833cc72986SMark Brown } 14843cc72986SMark Brown 148572e43164SCharles Keepax pm_runtime_set_active(arizona->dev); 148672e43164SCharles Keepax pm_runtime_enable(arizona->dev); 148772e43164SCharles Keepax 14883cc72986SMark Brown /* Set up for interrupts */ 14893cc72986SMark Brown ret = arizona_irq_init(arizona); 14903cc72986SMark Brown if (ret != 0) 1491d347792cSCharles Keepax goto err_pm; 14923cc72986SMark Brown 149372e43164SCharles Keepax pm_runtime_set_autosuspend_delay(arizona->dev, 100); 149472e43164SCharles Keepax pm_runtime_use_autosuspend(arizona->dev); 149572e43164SCharles Keepax 14963cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 14973cc72986SMark Brown arizona_clkgen_err, arizona); 14983cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 14993cc72986SMark Brown arizona_overclocked, arizona); 15003cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 15013cc72986SMark Brown arizona_underclocked, arizona); 15023cc72986SMark Brown 1503ae05ea36SRichard Fitzgerald ret = mfd_add_devices(arizona->dev, PLATFORM_DEVID_NONE, 1504ae05ea36SRichard Fitzgerald subdevs, n_subdevs, NULL, 0, NULL); 15053cc72986SMark Brown 1506ae05ea36SRichard Fitzgerald if (ret) { 15073cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 15083cc72986SMark Brown goto err_irq; 15093cc72986SMark Brown } 15103cc72986SMark Brown 15113cc72986SMark Brown return 0; 15123cc72986SMark Brown 15133cc72986SMark Brown err_irq: 15143cc72986SMark Brown arizona_irq_exit(arizona); 1515d347792cSCharles Keepax err_pm: 1516d347792cSCharles Keepax pm_runtime_disable(arizona->dev); 15173cc72986SMark Brown err_reset: 15182229875dSCharles Keepax arizona_enable_reset(arizona); 151959db9691SMark Brown regulator_disable(arizona->dcvdd); 15203cc72986SMark Brown err_enable: 15213a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 15223cc72986SMark Brown arizona->core_supplies); 1523e6021511SCharles Keepax err_dcvdd: 1524e6021511SCharles Keepax regulator_put(arizona->dcvdd); 15253cc72986SMark Brown err_early: 15263cc72986SMark Brown mfd_remove_devices(dev); 15273cc72986SMark Brown return ret; 15283cc72986SMark Brown } 15293cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 15303cc72986SMark Brown 15314740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 15323cc72986SMark Brown { 1533b804020aSCharles Keepax pm_runtime_disable(arizona->dev); 1534b804020aSCharles Keepax 1535df6b3352SCharles Keepax regulator_disable(arizona->dcvdd); 1536e6021511SCharles Keepax regulator_put(arizona->dcvdd); 1537df6b3352SCharles Keepax 15383cc72986SMark Brown mfd_remove_devices(arizona->dev); 15393cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 15403cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 15413cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 15423cc72986SMark Brown arizona_irq_exit(arizona); 15432229875dSCharles Keepax arizona_enable_reset(arizona); 1544df6b3352SCharles Keepax 15454420286eSCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 15461d017b6bSMark Brown arizona->core_supplies); 15473cc72986SMark Brown return 0; 15483cc72986SMark Brown } 15493cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1550