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 13cdd8da8cSSylwester 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) 53cdd8da8cSSylwester Nawrocki goto err_ref; 54cdd8da8cSSylwester Nawrocki ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]); 55cdd8da8cSSylwester Nawrocki if (ret != 0) 56cdd8da8cSSylwester Nawrocki goto err_pm; 57cdd8da8cSSylwester Nawrocki break; 58cdd8da8cSSylwester Nawrocki case ARIZONA_32KZ_MCLK2: 59cdd8da8cSSylwester Nawrocki ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]); 60cdd8da8cSSylwester Nawrocki if (ret != 0) 61cdd8da8cSSylwester 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 70cdd8da8cSSylwester Nawrocki err_pm: 71cdd8da8cSSylwester Nawrocki pm_runtime_put_sync(arizona->dev); 72cdd8da8cSSylwester 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); 97cdd8da8cSSylwester Nawrocki clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]); 98cdd8da8cSSylwester Nawrocki break; 99cdd8da8cSSylwester Nawrocki case ARIZONA_32KZ_MCLK2: 100cdd8da8cSSylwester 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); 345*de4ea10aSCharles Keepax if (ret) 346e80436bbSCharles Keepax goto err_fll; 347e80436bbSCharles Keepax 348e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 3490be068a0SCharles Keepax if (ret) { 350e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 351e80436bbSCharles Keepax goto err_fll; 352e80436bbSCharles Keepax } 353e80436bbSCharles Keepax 3543850e3eeSCharles Keepax return 0; 3553850e3eeSCharles Keepax 3563850e3eeSCharles Keepax err_fll: 3573850e3eeSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3583850e3eeSCharles Keepax if (err) 3593850e3eeSCharles Keepax dev_err(arizona->dev, 3603850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", err); 3613850e3eeSCharles Keepax 3623850e3eeSCharles Keepax return ret; 3633850e3eeSCharles Keepax } 3643850e3eeSCharles Keepax 3653850e3eeSCharles Keepax static int arizona_disable_freerun_sysclk(struct arizona *arizona, 3663850e3eeSCharles Keepax struct arizona_sysclk_state *state) 3673850e3eeSCharles Keepax { 3683850e3eeSCharles Keepax int ret; 3693850e3eeSCharles Keepax 3703850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 3713850e3eeSCharles Keepax state->sysclk); 3723850e3eeSCharles Keepax if (ret) { 3733850e3eeSCharles Keepax dev_err(arizona->dev, 3743850e3eeSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", ret); 3753850e3eeSCharles Keepax return ret; 3763850e3eeSCharles Keepax } 3773850e3eeSCharles Keepax 3783850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3793850e3eeSCharles Keepax if (ret) { 3803850e3eeSCharles Keepax dev_err(arizona->dev, 3813850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", ret); 3823850e3eeSCharles Keepax return ret; 3833850e3eeSCharles Keepax } 3843850e3eeSCharles Keepax 3853850e3eeSCharles Keepax return 0; 3863850e3eeSCharles Keepax } 3873850e3eeSCharles Keepax 3883850e3eeSCharles Keepax static int wm5102_apply_hardware_patch(struct arizona *arizona) 3893850e3eeSCharles Keepax { 3903850e3eeSCharles Keepax struct arizona_sysclk_state state; 3913850e3eeSCharles Keepax int err, ret; 3923850e3eeSCharles Keepax 3933850e3eeSCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 3943850e3eeSCharles Keepax if (ret) 3953850e3eeSCharles Keepax return ret; 3963850e3eeSCharles Keepax 397e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 398e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 399e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 4000be068a0SCharles Keepax if (ret) { 401e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 402e80436bbSCharles Keepax ret); 4033850e3eeSCharles Keepax goto err; 404e80436bbSCharles Keepax } 4053850e3eeSCharles Keepax 406e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 407e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 408*de4ea10aSCharles Keepax if (ret) 409e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 410e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 411e80436bbSCharles Keepax 4123850e3eeSCharles Keepax err: 4133850e3eeSCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 414e80436bbSCharles Keepax 4150be068a0SCharles Keepax return ret ?: err; 416e80436bbSCharles Keepax } 417e80436bbSCharles Keepax 418882bc468SCharles Keepax /* 419882bc468SCharles Keepax * Register patch to some of the CODECs internal write sequences 420882bc468SCharles Keepax * to ensure a clean exit from the low power sleep state. 421882bc468SCharles Keepax */ 4228019ff6cSNariman Poushin static const struct reg_sequence wm5110_sleep_patch[] = { 423882bc468SCharles Keepax { 0x337A, 0xC100 }, 424882bc468SCharles Keepax { 0x337B, 0x0041 }, 425882bc468SCharles Keepax { 0x3300, 0xA210 }, 426882bc468SCharles Keepax { 0x3301, 0x050C }, 427882bc468SCharles Keepax }; 428882bc468SCharles Keepax 429882bc468SCharles Keepax static int wm5110_apply_sleep_patch(struct arizona *arizona) 430882bc468SCharles Keepax { 431882bc468SCharles Keepax struct arizona_sysclk_state state; 432882bc468SCharles Keepax int err, ret; 433882bc468SCharles Keepax 434882bc468SCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 435882bc468SCharles Keepax if (ret) 436882bc468SCharles Keepax return ret; 437882bc468SCharles Keepax 438882bc468SCharles Keepax ret = regmap_multi_reg_write_bypassed(arizona->regmap, 439882bc468SCharles Keepax wm5110_sleep_patch, 440882bc468SCharles Keepax ARRAY_SIZE(wm5110_sleep_patch)); 441882bc468SCharles Keepax 442882bc468SCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 443882bc468SCharles Keepax 444882bc468SCharles Keepax return ret ?: err; 445882bc468SCharles Keepax } 446882bc468SCharles Keepax 4471c1c6bbaSCharles Keepax static int wm5102_clear_write_sequencer(struct arizona *arizona) 4481c1c6bbaSCharles Keepax { 4491c1c6bbaSCharles Keepax int ret; 4501c1c6bbaSCharles Keepax 4511c1c6bbaSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3, 4521c1c6bbaSCharles Keepax 0x0); 4531c1c6bbaSCharles Keepax if (ret) { 4541c1c6bbaSCharles Keepax dev_err(arizona->dev, 4551c1c6bbaSCharles Keepax "Failed to clear write sequencer state: %d\n", ret); 4561c1c6bbaSCharles Keepax return ret; 4571c1c6bbaSCharles Keepax } 4581c1c6bbaSCharles Keepax 4591c1c6bbaSCharles Keepax arizona_enable_reset(arizona); 4601c1c6bbaSCharles Keepax regulator_disable(arizona->dcvdd); 4611c1c6bbaSCharles Keepax 4621c1c6bbaSCharles Keepax msleep(20); 4631c1c6bbaSCharles Keepax 4641c1c6bbaSCharles Keepax ret = regulator_enable(arizona->dcvdd); 4651c1c6bbaSCharles Keepax if (ret) { 4661c1c6bbaSCharles Keepax dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret); 4671c1c6bbaSCharles Keepax return ret; 4681c1c6bbaSCharles Keepax } 4691c1c6bbaSCharles Keepax arizona_disable_reset(arizona); 4701c1c6bbaSCharles Keepax 4711c1c6bbaSCharles Keepax return 0; 4721c1c6bbaSCharles Keepax } 4731c1c6bbaSCharles Keepax 47448bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM 475e7811147SRichard Fitzgerald static int arizona_isolate_dcvdd(struct arizona *arizona) 476e7811147SRichard Fitzgerald { 477e7811147SRichard Fitzgerald int ret; 478e7811147SRichard Fitzgerald 479e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 480e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 481e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 482e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1); 483e7811147SRichard Fitzgerald if (ret != 0) 484e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", ret); 485e7811147SRichard Fitzgerald 486e7811147SRichard Fitzgerald return ret; 487e7811147SRichard Fitzgerald } 488e7811147SRichard Fitzgerald 489e7811147SRichard Fitzgerald static int arizona_connect_dcvdd(struct arizona *arizona) 490e7811147SRichard Fitzgerald { 491e7811147SRichard Fitzgerald int ret; 492e7811147SRichard Fitzgerald 493e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 494e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 495e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 0); 496e7811147SRichard Fitzgerald if (ret != 0) 497e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to connect DCVDD: %d\n", ret); 498e7811147SRichard Fitzgerald 499e7811147SRichard Fitzgerald return ret; 500e7811147SRichard Fitzgerald } 501e7811147SRichard Fitzgerald 502e3424273SRichard Fitzgerald static int arizona_is_jack_det_active(struct arizona *arizona) 503e3424273SRichard Fitzgerald { 504e3424273SRichard Fitzgerald unsigned int val; 505e3424273SRichard Fitzgerald int ret; 506e3424273SRichard Fitzgerald 507e3424273SRichard Fitzgerald ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val); 508e3424273SRichard Fitzgerald if (ret) { 509e3424273SRichard Fitzgerald dev_err(arizona->dev, 510e3424273SRichard Fitzgerald "Failed to check jack det status: %d\n", ret); 511e3424273SRichard Fitzgerald return ret; 512e3424273SRichard Fitzgerald } else if (val & ARIZONA_JD1_ENA) { 513e3424273SRichard Fitzgerald return 1; 514e3424273SRichard Fitzgerald } else { 515e3424273SRichard Fitzgerald return 0; 516e3424273SRichard Fitzgerald } 517e3424273SRichard Fitzgerald } 518e3424273SRichard Fitzgerald 5193cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 5203cc72986SMark Brown { 5213cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 5223cc72986SMark Brown int ret; 5233cc72986SMark Brown 524508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 525508c8299SMark Brown 526e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 527e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Re-enabling core supplies\n"); 528e6cb7341SCharles Keepax 529e6cb7341SCharles Keepax ret = regulator_bulk_enable(arizona->num_core_supplies, 530e6cb7341SCharles Keepax arizona->core_supplies); 531e6cb7341SCharles Keepax if (ret) { 532e6cb7341SCharles Keepax dev_err(dev, "Failed to enable core supplies: %d\n", 533e6cb7341SCharles Keepax ret); 534e6cb7341SCharles Keepax return ret; 535e6cb7341SCharles Keepax } 536e6cb7341SCharles Keepax } 537e6cb7341SCharles Keepax 53859db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 53959db9691SMark Brown if (ret != 0) { 54059db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 541e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) 542e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 543e6cb7341SCharles Keepax arizona->core_supplies); 54459db9691SMark Brown return ret; 54559db9691SMark Brown } 5463cc72986SMark Brown 547e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 548e6cb7341SCharles Keepax arizona_disable_reset(arizona); 549e6cb7341SCharles Keepax enable_irq(arizona->irq); 550e6cb7341SCharles Keepax arizona->has_fully_powered_off = false; 551e6cb7341SCharles Keepax } 552e6cb7341SCharles Keepax 5533cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 5543cc72986SMark Brown 5554c9bb8bcSCharles Keepax switch (arizona->type) { 5564c9bb8bcSCharles Keepax case WM5102: 5575927467dSMark Brown if (arizona->external_dcvdd) { 558e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 559e7811147SRichard Fitzgerald if (ret != 0) 5605927467dSMark Brown goto err; 5615927467dSMark Brown } 5625927467dSMark Brown 5634c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 5644c9bb8bcSCharles Keepax if (ret != 0) { 5654c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 5664c9bb8bcSCharles Keepax ret); 5674c9bb8bcSCharles Keepax goto err; 5684c9bb8bcSCharles Keepax } 569e80436bbSCharles Keepax 5700be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 5710be068a0SCharles Keepax if (ret) { 572e80436bbSCharles Keepax dev_err(arizona->dev, 573e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 574e80436bbSCharles Keepax ret); 575e80436bbSCharles Keepax goto err; 576e80436bbSCharles Keepax } 577e80436bbSCharles Keepax break; 57896129a0eSCharles Keepax case WM5110: 57996129a0eSCharles Keepax case WM8280: 58096129a0eSCharles Keepax ret = arizona_wait_for_boot(arizona); 58196129a0eSCharles Keepax if (ret) 58296129a0eSCharles Keepax goto err; 58396129a0eSCharles Keepax 58496129a0eSCharles Keepax if (arizona->external_dcvdd) { 585e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 586e7811147SRichard Fitzgerald if (ret != 0) 58796129a0eSCharles Keepax goto err; 58896129a0eSCharles Keepax } else { 58996129a0eSCharles Keepax /* 59096129a0eSCharles Keepax * As this is only called for the internal regulator 59196129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 59296129a0eSCharles Keepax * to request an exact range. 59396129a0eSCharles Keepax */ 59496129a0eSCharles Keepax ret = regulator_set_voltage(arizona->dcvdd, 59596129a0eSCharles Keepax 1200000, 1200000); 59696129a0eSCharles Keepax if (ret < 0) { 59796129a0eSCharles Keepax dev_err(arizona->dev, 59896129a0eSCharles Keepax "Failed to set resume voltage: %d\n", 59996129a0eSCharles Keepax ret); 60096129a0eSCharles Keepax goto err; 60196129a0eSCharles Keepax } 60296129a0eSCharles Keepax } 603e6cb7341SCharles Keepax 604e6cb7341SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 605e6cb7341SCharles Keepax if (ret) { 606e6cb7341SCharles Keepax dev_err(arizona->dev, 607e6cb7341SCharles Keepax "Failed to re-apply sleep patch: %d\n", 608e6cb7341SCharles Keepax ret); 609e6cb7341SCharles Keepax goto err; 610e6cb7341SCharles Keepax } 61196129a0eSCharles Keepax break; 612ea1f3339SRichard Fitzgerald case WM1831: 613ea1f3339SRichard Fitzgerald case CS47L24: 614ea1f3339SRichard Fitzgerald ret = arizona_wait_for_boot(arizona); 615ea1f3339SRichard Fitzgerald if (ret != 0) 616ea1f3339SRichard Fitzgerald goto err; 617ea1f3339SRichard Fitzgerald break; 618e80436bbSCharles Keepax default: 61912bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 6203762aedeSCharles Keepax if (ret != 0) 62112bb68edSCharles Keepax goto err; 62212bb68edSCharles Keepax 6235927467dSMark Brown if (arizona->external_dcvdd) { 624e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 625e7811147SRichard Fitzgerald if (ret != 0) 6265927467dSMark Brown goto err; 6275927467dSMark Brown } 628e80436bbSCharles Keepax break; 6294c9bb8bcSCharles Keepax } 6304c9bb8bcSCharles Keepax 6319270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 6329270bdf5SMark Brown if (ret != 0) { 6339270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 6344816bd1cSMark Brown goto err; 6359270bdf5SMark Brown } 6363cc72986SMark Brown 6373cc72986SMark Brown return 0; 6384816bd1cSMark Brown 6394816bd1cSMark Brown err: 6404816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 6414816bd1cSMark Brown regulator_disable(arizona->dcvdd); 6424816bd1cSMark Brown return ret; 6433cc72986SMark Brown } 6443cc72986SMark Brown 6453cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 6463cc72986SMark Brown { 6473cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 648a05950a4SDan Carpenter int jd_active = 0; 6495927467dSMark Brown int ret; 6503cc72986SMark Brown 651508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 652508c8299SMark Brown 65396129a0eSCharles Keepax switch (arizona->type) { 65496129a0eSCharles Keepax case WM5110: 65596129a0eSCharles Keepax case WM8280: 656e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 657e3424273SRichard Fitzgerald if (jd_active < 0) 658e3424273SRichard Fitzgerald return jd_active; 659e3424273SRichard Fitzgerald 660e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 661e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 662e7811147SRichard Fitzgerald if (ret != 0) 663e7811147SRichard Fitzgerald return ret; 664e7811147SRichard Fitzgerald } else { 66596129a0eSCharles Keepax /* 66696129a0eSCharles Keepax * As this is only called for the internal regulator 66796129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 66896129a0eSCharles Keepax * to request an exact range. 66996129a0eSCharles Keepax */ 670e7811147SRichard Fitzgerald ret = regulator_set_voltage(arizona->dcvdd, 671e7811147SRichard Fitzgerald 1175000, 1175000); 67296129a0eSCharles Keepax if (ret < 0) { 67396129a0eSCharles Keepax dev_err(arizona->dev, 674e7811147SRichard Fitzgerald "Failed to set suspend voltage: %d\n", 675e7811147SRichard Fitzgerald ret); 676e6cb7341SCharles Keepax return ret; 677e6cb7341SCharles Keepax } 678e7811147SRichard Fitzgerald } 679e6cb7341SCharles Keepax break; 680e6cb7341SCharles Keepax case WM5102: 681e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 682e3424273SRichard Fitzgerald if (jd_active < 0) 683e3424273SRichard Fitzgerald return jd_active; 684e3424273SRichard Fitzgerald 685e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 686e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 687e7811147SRichard Fitzgerald if (ret != 0) 688e7811147SRichard Fitzgerald return ret; 689e7811147SRichard Fitzgerald } 690e7811147SRichard Fitzgerald 691e3424273SRichard Fitzgerald if (!jd_active) { 692e6cb7341SCharles Keepax ret = regmap_write(arizona->regmap, 693e6cb7341SCharles Keepax ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0); 694e6cb7341SCharles Keepax if (ret) { 695e6cb7341SCharles Keepax dev_err(arizona->dev, 696e6cb7341SCharles Keepax "Failed to clear write sequencer: %d\n", 69796129a0eSCharles Keepax ret); 69896129a0eSCharles Keepax return ret; 69996129a0eSCharles Keepax } 700e6cb7341SCharles Keepax } 70196129a0eSCharles Keepax break; 702ea1f3339SRichard Fitzgerald case WM1831: 703ea1f3339SRichard Fitzgerald case CS47L24: 704ea1f3339SRichard Fitzgerald break; 70596129a0eSCharles Keepax default: 706e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 707e3424273SRichard Fitzgerald if (jd_active < 0) 708e3424273SRichard Fitzgerald return jd_active; 709e3424273SRichard Fitzgerald 710e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 711e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 712e7811147SRichard Fitzgerald if (ret != 0) 713e7811147SRichard Fitzgerald return ret; 714e7811147SRichard Fitzgerald } 71596129a0eSCharles Keepax break; 71696129a0eSCharles Keepax } 7175927467dSMark Brown 7183cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 7193cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 720e293e847SCharles Keepax regulator_disable(arizona->dcvdd); 7213cc72986SMark Brown 722e6cb7341SCharles Keepax /* Allow us to completely power down if no jack detection */ 723e3424273SRichard Fitzgerald if (!jd_active) { 724e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Fully powering off\n"); 725e6cb7341SCharles Keepax 726e6cb7341SCharles Keepax arizona->has_fully_powered_off = true; 727e6cb7341SCharles Keepax 72811150929SCharles Keepax disable_irq_nosync(arizona->irq); 729e6cb7341SCharles Keepax arizona_enable_reset(arizona); 730e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 731e6cb7341SCharles Keepax arizona->core_supplies); 732e6cb7341SCharles Keepax } 733e6cb7341SCharles Keepax 7343cc72986SMark Brown return 0; 7353cc72986SMark Brown } 7363cc72986SMark Brown #endif 7373cc72986SMark Brown 738dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 73967c99296SMark Brown static int arizona_suspend(struct device *dev) 74067c99296SMark Brown { 74167c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 74267c99296SMark Brown 74367c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 74467c99296SMark Brown disable_irq(arizona->irq); 74567c99296SMark Brown 74667c99296SMark Brown return 0; 74767c99296SMark Brown } 74867c99296SMark Brown 7493612b27cSCharles Keepax static int arizona_suspend_noirq(struct device *dev) 75067c99296SMark Brown { 75167c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 75267c99296SMark Brown 75367c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 75467c99296SMark Brown enable_irq(arizona->irq); 75567c99296SMark Brown 75667c99296SMark Brown return 0; 75767c99296SMark Brown } 75867c99296SMark Brown 759dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 760dc781d0eSMark Brown { 761dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 762dc781d0eSMark Brown 763dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 764dc781d0eSMark Brown disable_irq(arizona->irq); 765dc781d0eSMark Brown 766dc781d0eSMark Brown return 0; 767dc781d0eSMark Brown } 768dc781d0eSMark Brown 769dc781d0eSMark Brown static int arizona_resume(struct device *dev) 770dc781d0eSMark Brown { 771dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 772dc781d0eSMark Brown 7733612b27cSCharles Keepax dev_dbg(arizona->dev, "Resume, reenabling IRQ\n"); 774dc781d0eSMark Brown enable_irq(arizona->irq); 775dc781d0eSMark Brown 776dc781d0eSMark Brown return 0; 777dc781d0eSMark Brown } 778dc781d0eSMark Brown #endif 779dc781d0eSMark Brown 7803cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 7813cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 7823cc72986SMark Brown arizona_runtime_resume, 7833cc72986SMark Brown NULL) 78467c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 7853612b27cSCharles Keepax SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq, 7863612b27cSCharles Keepax arizona_resume_noirq) 7873cc72986SMark Brown }; 7883cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 7893cc72986SMark Brown 790d781009cSMark Brown #ifdef CONFIG_OF 791942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev) 792d781009cSMark Brown { 793d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 794d781009cSMark Brown 795d781009cSMark Brown if (id) 796942786e6SLee Jones return (unsigned long)id->data; 797d781009cSMark Brown else 798d781009cSMark Brown return 0; 799d781009cSMark Brown } 800d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 801d781009cSMark Brown 802d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 803d781009cSMark Brown { 804e4fcb1d6SCharles Keepax struct arizona_pdata *pdata = &arizona->pdata; 805cc47aed9SInha Song struct property *prop; 806cc47aed9SInha Song const __be32 *cur; 807cc47aed9SInha Song u32 val; 808f4c05262SRichard Fitzgerald u32 pdm_val[ARIZONA_MAX_PDM_SPK]; 809d781009cSMark Brown int ret, i; 810cc47aed9SInha Song int count = 0; 811d781009cSMark Brown 8121961531dSCharles Keepax pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0); 813b8d336edSCharles Keepax if (pdata->reset == -EPROBE_DEFER) { 814b8d336edSCharles Keepax return pdata->reset; 815b8d336edSCharles Keepax } else if (pdata->reset < 0) { 8161961531dSCharles Keepax dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n", 8171961531dSCharles Keepax pdata->reset); 8181961531dSCharles Keepax 8191961531dSCharles Keepax pdata->reset = 0; 8201961531dSCharles Keepax } 821d781009cSMark Brown 822d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 823d781009cSMark Brown "wlf,gpio-defaults", 8243762aedeSCharles Keepax pdata->gpio_defaults, 8253762aedeSCharles Keepax ARRAY_SIZE(pdata->gpio_defaults)); 826d781009cSMark Brown if (ret >= 0) { 827d781009cSMark Brown /* 828d781009cSMark Brown * All values are literal except out of range values 829d781009cSMark Brown * which are chip default, translate into platform 830d781009cSMark Brown * data which uses 0 as chip default and out of range 831d781009cSMark Brown * as zero. 832d781009cSMark Brown */ 8333762aedeSCharles Keepax for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { 8343762aedeSCharles Keepax if (pdata->gpio_defaults[i] > 0xffff) 8353762aedeSCharles Keepax pdata->gpio_defaults[i] = 0; 8363762aedeSCharles Keepax else if (pdata->gpio_defaults[i] == 0) 8373762aedeSCharles Keepax pdata->gpio_defaults[i] = 0x10000; 838d781009cSMark Brown } 839d781009cSMark Brown } else { 840d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 841d781009cSMark Brown ret); 842d781009cSMark Brown } 843d781009cSMark Brown 844cc47aed9SInha Song of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop, 845cc47aed9SInha Song cur, val) { 8463762aedeSCharles Keepax if (count == ARRAY_SIZE(pdata->inmode)) 847cc47aed9SInha Song break; 848cc47aed9SInha Song 8493762aedeSCharles Keepax pdata->inmode[count] = val; 850cc47aed9SInha Song count++; 851cc47aed9SInha Song } 852cc47aed9SInha Song 853e7ad27caSCharles Keepax count = 0; 854e7ad27caSCharles Keepax of_property_for_each_u32(arizona->dev->of_node, "wlf,dmic-ref", prop, 855e7ad27caSCharles Keepax cur, val) { 8563762aedeSCharles Keepax if (count == ARRAY_SIZE(pdata->dmic_ref)) 857e7ad27caSCharles Keepax break; 858e7ad27caSCharles Keepax 8593762aedeSCharles Keepax pdata->dmic_ref[count] = val; 860e7ad27caSCharles Keepax count++; 861e7ad27caSCharles Keepax } 862e7ad27caSCharles Keepax 863f199d393SCharles Keepax count = 0; 864f199d393SCharles Keepax of_property_for_each_u32(arizona->dev->of_node, "wlf,out-mono", prop, 865f199d393SCharles Keepax cur, val) { 866f199d393SCharles Keepax if (count == ARRAY_SIZE(pdata->out_mono)) 867f199d393SCharles Keepax break; 868f199d393SCharles Keepax 869f199d393SCharles Keepax pdata->out_mono[count] = !!val; 870f199d393SCharles Keepax count++; 871f199d393SCharles Keepax } 872f199d393SCharles Keepax 873f4c05262SRichard Fitzgerald count = 0; 874f4c05262SRichard Fitzgerald of_property_for_each_u32(arizona->dev->of_node, 875f4c05262SRichard Fitzgerald "wlf,max-channels-clocked", 876f4c05262SRichard Fitzgerald prop, cur, val) { 877f4c05262SRichard Fitzgerald if (count == ARRAY_SIZE(pdata->max_channels_clocked)) 878f4c05262SRichard Fitzgerald break; 879f4c05262SRichard Fitzgerald 880f4c05262SRichard Fitzgerald pdata->max_channels_clocked[count] = val; 881f4c05262SRichard Fitzgerald count++; 882f4c05262SRichard Fitzgerald } 883f4c05262SRichard Fitzgerald 884f4c05262SRichard Fitzgerald ret = of_property_read_u32_array(arizona->dev->of_node, 885f4c05262SRichard Fitzgerald "wlf,spk-fmt", 886f4c05262SRichard Fitzgerald pdm_val, 887f4c05262SRichard Fitzgerald ARRAY_SIZE(pdm_val)); 888f4c05262SRichard Fitzgerald 889f4c05262SRichard Fitzgerald if (ret >= 0) 890f4c05262SRichard Fitzgerald for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count) 891f4c05262SRichard Fitzgerald pdata->spk_fmt[count] = pdm_val[count]; 892f4c05262SRichard Fitzgerald 893f4c05262SRichard Fitzgerald ret = of_property_read_u32_array(arizona->dev->of_node, 894f4c05262SRichard Fitzgerald "wlf,spk-mute", 895f4c05262SRichard Fitzgerald pdm_val, 896f4c05262SRichard Fitzgerald ARRAY_SIZE(pdm_val)); 897f4c05262SRichard Fitzgerald 898f4c05262SRichard Fitzgerald if (ret >= 0) 899f4c05262SRichard Fitzgerald for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count) 900f4c05262SRichard Fitzgerald pdata->spk_mute[count] = pdm_val[count]; 901f4c05262SRichard Fitzgerald 902d781009cSMark Brown return 0; 903d781009cSMark Brown } 904d781009cSMark Brown 905d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 906d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 907d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 908e5d4ef0dSRichard Fitzgerald { .compatible = "wlf,wm8280", .data = (void *)WM8280 }, 909dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 9106887b042SRichard Fitzgerald { .compatible = "wlf,wm8998", .data = (void *)WM8998 }, 9116887b042SRichard Fitzgerald { .compatible = "wlf,wm1814", .data = (void *)WM1814 }, 912ea1f3339SRichard Fitzgerald { .compatible = "wlf,wm1831", .data = (void *)WM1831 }, 913ea1f3339SRichard Fitzgerald { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 }, 914d781009cSMark Brown {}, 915d781009cSMark Brown }; 916d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 917d781009cSMark Brown #else 918d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 919d781009cSMark Brown { 920d781009cSMark Brown return 0; 921d781009cSMark Brown } 922d781009cSMark Brown #endif 923d781009cSMark Brown 9245ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = { 9253cc72986SMark Brown { .name = "arizona-ldo1" }, 9263cc72986SMark Brown }; 9273cc72986SMark Brown 9283762aedeSCharles Keepax static const char * const wm5102_supplies[] = { 9295fc6c396SCharles Keepax "MICVDD", 93032dadef2SCharles Keepax "DBVDD2", 93132dadef2SCharles Keepax "DBVDD3", 93232dadef2SCharles Keepax "CPVDD", 93332dadef2SCharles Keepax "SPKVDDL", 93432dadef2SCharles Keepax "SPKVDDR", 93532dadef2SCharles Keepax }; 93632dadef2SCharles Keepax 9375ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = { 938d7768111SMark Brown { .name = "arizona-micsupp" }, 939f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9405fc6c396SCharles Keepax { 9415fc6c396SCharles Keepax .name = "arizona-extcon", 9425fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9435fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9445fc6c396SCharles Keepax }, 945503b1cacSMark Brown { .name = "arizona-haptics" }, 9463cc72986SMark Brown { .name = "arizona-pwm" }, 94732dadef2SCharles Keepax { 94832dadef2SCharles Keepax .name = "wm5102-codec", 94932dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 95032dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 95132dadef2SCharles Keepax }, 9523cc72986SMark Brown }; 9533cc72986SMark Brown 9545ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = { 955d7768111SMark Brown { .name = "arizona-micsupp" }, 956f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9575fc6c396SCharles Keepax { 9585fc6c396SCharles Keepax .name = "arizona-extcon", 9595fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9605fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9615fc6c396SCharles Keepax }, 962503b1cacSMark Brown { .name = "arizona-haptics" }, 963e102befeSMark Brown { .name = "arizona-pwm" }, 96432dadef2SCharles Keepax { 96532dadef2SCharles Keepax .name = "wm5110-codec", 96632dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 96732dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 96832dadef2SCharles Keepax }, 96932dadef2SCharles Keepax }; 97032dadef2SCharles Keepax 971ea1f3339SRichard Fitzgerald static const char * const cs47l24_supplies[] = { 972ea1f3339SRichard Fitzgerald "MICVDD", 973ea1f3339SRichard Fitzgerald "CPVDD", 974ea1f3339SRichard Fitzgerald "SPKVDD", 975ea1f3339SRichard Fitzgerald }; 976ea1f3339SRichard Fitzgerald 977ea1f3339SRichard Fitzgerald static const struct mfd_cell cs47l24_devs[] = { 978ea1f3339SRichard Fitzgerald { .name = "arizona-gpio" }, 979ea1f3339SRichard Fitzgerald { .name = "arizona-haptics" }, 980ea1f3339SRichard Fitzgerald { .name = "arizona-pwm" }, 981ea1f3339SRichard Fitzgerald { 982ea1f3339SRichard Fitzgerald .name = "cs47l24-codec", 983ea1f3339SRichard Fitzgerald .parent_supplies = cs47l24_supplies, 984ea1f3339SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(cs47l24_supplies), 985ea1f3339SRichard Fitzgerald }, 986ea1f3339SRichard Fitzgerald }; 987ea1f3339SRichard Fitzgerald 9883762aedeSCharles Keepax static const char * const wm8997_supplies[] = { 989996c2d4fSCharles Keepax "MICVDD", 99032dadef2SCharles Keepax "DBVDD2", 99132dadef2SCharles Keepax "CPVDD", 99232dadef2SCharles Keepax "SPKVDD", 993e102befeSMark Brown }; 994e102befeSMark Brown 9955ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = { 996dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 997f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9985fc6c396SCharles Keepax { 9995fc6c396SCharles Keepax .name = "arizona-extcon", 10005fc6c396SCharles Keepax .parent_supplies = wm8997_supplies, 10015fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 10025fc6c396SCharles Keepax }, 1003dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 1004dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 100532dadef2SCharles Keepax { 100632dadef2SCharles Keepax .name = "wm8997-codec", 100732dadef2SCharles Keepax .parent_supplies = wm8997_supplies, 100832dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), 100932dadef2SCharles Keepax }, 1010dc7d4863SCharles Keepax }; 1011dc7d4863SCharles Keepax 10126887b042SRichard Fitzgerald static const struct mfd_cell wm8998_devs[] = { 1013f83c218cSCharles Keepax { .name = "arizona-micsupp" }, 1014f83c218cSCharles Keepax { .name = "arizona-gpio" }, 10156887b042SRichard Fitzgerald { 10166887b042SRichard Fitzgerald .name = "arizona-extcon", 10176887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 10186887b042SRichard Fitzgerald .num_parent_supplies = 1, /* We only need MICVDD */ 10196887b042SRichard Fitzgerald }, 10206887b042SRichard Fitzgerald { .name = "arizona-haptics" }, 10216887b042SRichard Fitzgerald { .name = "arizona-pwm" }, 10226887b042SRichard Fitzgerald { 10236887b042SRichard Fitzgerald .name = "wm8998-codec", 10246887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 10256887b042SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 10266887b042SRichard Fitzgerald }, 10276887b042SRichard Fitzgerald }; 10286887b042SRichard Fitzgerald 1029f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 10303cc72986SMark Brown { 1031cdd8da8cSSylwester Nawrocki const char * const mclk_name[] = { "mclk1", "mclk2" }; 10323cc72986SMark Brown struct device *dev = arizona->dev; 1033ea1f3339SRichard Fitzgerald const char *type_name = NULL; 10346887b042SRichard Fitzgerald unsigned int reg, val, mask; 103562d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 1036ae05ea36SRichard Fitzgerald const struct mfd_cell *subdevs = NULL; 1037ae05ea36SRichard Fitzgerald int n_subdevs, ret, i; 10383cc72986SMark Brown 10393cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 10403cc72986SMark Brown mutex_init(&arizona->clk_lock); 10413cc72986SMark Brown 1042b8d336edSCharles Keepax if (dev_get_platdata(arizona->dev)) { 10433cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 10443cc72986SMark Brown sizeof(arizona->pdata)); 1045b8d336edSCharles Keepax } else { 1046b8d336edSCharles Keepax ret = arizona_of_get_core_pdata(arizona); 1047b8d336edSCharles Keepax if (ret < 0) 1048b8d336edSCharles Keepax return ret; 1049b8d336edSCharles Keepax } 10503cc72986SMark Brown 1051cdd8da8cSSylwester Nawrocki BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name)); 1052cdd8da8cSSylwester Nawrocki for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) { 1053cdd8da8cSSylwester Nawrocki arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]); 1054cdd8da8cSSylwester Nawrocki if (IS_ERR(arizona->mclk[i])) { 1055cdd8da8cSSylwester Nawrocki dev_info(arizona->dev, "Failed to get %s: %ld\n", 1056cdd8da8cSSylwester Nawrocki mclk_name[i], PTR_ERR(arizona->mclk[i])); 1057cdd8da8cSSylwester Nawrocki arizona->mclk[i] = NULL; 1058cdd8da8cSSylwester Nawrocki } 1059cdd8da8cSSylwester Nawrocki } 1060cdd8da8cSSylwester Nawrocki 10613cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 10623cc72986SMark Brown 10633cc72986SMark Brown switch (arizona->type) { 10643cc72986SMark Brown case WM5102: 1065e102befeSMark Brown case WM5110: 1066e5d4ef0dSRichard Fitzgerald case WM8280: 1067dc7d4863SCharles Keepax case WM8997: 10686887b042SRichard Fitzgerald case WM8998: 10696887b042SRichard Fitzgerald case WM1814: 1070ea1f3339SRichard Fitzgerald case WM1831: 1071ea1f3339SRichard Fitzgerald case CS47L24: 10723cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 10733cc72986SMark Brown arizona->core_supplies[i].supply 10743cc72986SMark Brown = wm5102_core_supplies[i]; 10753cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 10763cc72986SMark Brown break; 10773cc72986SMark Brown default: 10783cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 10793cc72986SMark Brown arizona->type); 108075d8a2b0SCharles Keepax return -ENODEV; 10813cc72986SMark Brown } 10823cc72986SMark Brown 10834a8c475fSCharles Keepax /* Mark DCVDD as external, LDO1 driver will clear if internal */ 10844a8c475fSCharles Keepax arizona->external_dcvdd = true; 10854a8c475fSCharles Keepax 1086ea1f3339SRichard Fitzgerald switch (arizona->type) { 1087ea1f3339SRichard Fitzgerald case WM1831: 1088ea1f3339SRichard Fitzgerald case CS47L24: 1089ea1f3339SRichard Fitzgerald break; /* No LDO1 regulator */ 1090ea1f3339SRichard Fitzgerald default: 10913cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 10920848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 10933cc72986SMark Brown if (ret != 0) { 10943cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 10953cc72986SMark Brown return ret; 10963cc72986SMark Brown } 1097ea1f3339SRichard Fitzgerald break; 1098ea1f3339SRichard Fitzgerald } 10993cc72986SMark Brown 11003cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 11013cc72986SMark Brown arizona->core_supplies); 11023cc72986SMark Brown if (ret != 0) { 11033cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 11043cc72986SMark Brown ret); 11053cc72986SMark Brown goto err_early; 11063cc72986SMark Brown } 11073cc72986SMark Brown 11080c2d0ffbSCharles Keepax /** 11090c2d0ffbSCharles Keepax * Don't use devres here because the only device we have to get 11100c2d0ffbSCharles Keepax * against is the MFD device and DCVDD will likely be supplied by 11110c2d0ffbSCharles Keepax * one of its children. Meaning that the regulator will be 11120c2d0ffbSCharles Keepax * destroyed by the time devres calls regulator put. 11130c2d0ffbSCharles Keepax */ 1114e6021511SCharles Keepax arizona->dcvdd = regulator_get(arizona->dev, "DCVDD"); 111559db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 111659db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 111759db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 111859db9691SMark Brown goto err_early; 111959db9691SMark Brown } 112059db9691SMark Brown 112187d3af4aSMark Brown if (arizona->pdata.reset) { 112287d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 11235f056bf0SCharles Keepax ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset, 112487d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 112587d3af4aSMark Brown "arizona /RESET"); 112687d3af4aSMark Brown if (ret != 0) { 112787d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 1128e6021511SCharles Keepax goto err_dcvdd; 112987d3af4aSMark Brown } 113087d3af4aSMark Brown } 113187d3af4aSMark Brown 11323cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 11333cc72986SMark Brown arizona->core_supplies); 11343cc72986SMark Brown if (ret != 0) { 11353cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 11363cc72986SMark Brown ret); 1137e6021511SCharles Keepax goto err_dcvdd; 11383cc72986SMark Brown } 11393cc72986SMark Brown 114059db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 114159db9691SMark Brown if (ret != 0) { 114259db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 114359db9691SMark Brown goto err_enable; 114459db9691SMark Brown } 114559db9691SMark Brown 11462229875dSCharles Keepax arizona_disable_reset(arizona); 11473cc72986SMark Brown 11483cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 11493cc72986SMark Brown 1150ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 1151ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 1152ca76ceb8SMark Brown if (ret != 0) { 1153ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 1154ca76ceb8SMark Brown goto err_reset; 1155ca76ceb8SMark Brown } 1156ca76ceb8SMark Brown 1157ca76ceb8SMark Brown switch (reg) { 1158ca76ceb8SMark Brown case 0x5102: 1159ca76ceb8SMark Brown case 0x5110: 11606887b042SRichard Fitzgerald case 0x6349: 1161ea1f3339SRichard Fitzgerald case 0x6363: 1162dc7d4863SCharles Keepax case 0x8997: 1163ca76ceb8SMark Brown break; 1164ca76ceb8SMark Brown default: 1165ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 116675d8a2b0SCharles Keepax ret = -ENODEV; 1167ca76ceb8SMark Brown goto err_reset; 1168ca76ceb8SMark Brown } 1169ca76ceb8SMark Brown 1170ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 1171ca76ceb8SMark Brown if (!arizona->pdata.reset) { 1172ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 1173ca76ceb8SMark Brown if (ret != 0) { 1174ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 1175ca76ceb8SMark Brown goto err_reset; 1176ca76ceb8SMark Brown } 1177ca76ceb8SMark Brown 1178b79a980fSLee Jones usleep_range(1000, 5000); 1179ca76ceb8SMark Brown } 1180ca76ceb8SMark Brown 1181ca76ceb8SMark Brown /* Ensure device startup is complete */ 1182ca76ceb8SMark Brown switch (arizona->type) { 1183ca76ceb8SMark Brown case WM5102: 118448018943SMark Brown ret = regmap_read(arizona->regmap, 118548018943SMark Brown ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); 11861c1c6bbaSCharles Keepax if (ret) { 1187ca76ceb8SMark Brown dev_err(dev, 1188ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 1189ca76ceb8SMark Brown ret); 11901c1c6bbaSCharles Keepax } else if (val & 0x01) { 11911c1c6bbaSCharles Keepax ret = wm5102_clear_write_sequencer(arizona); 11921c1c6bbaSCharles Keepax if (ret) 11931c1c6bbaSCharles Keepax return ret; 1194ca76ceb8SMark Brown } 1195ca76ceb8SMark Brown break; 11961c1c6bbaSCharles Keepax default: 11971c1c6bbaSCharles Keepax break; 11981c1c6bbaSCharles Keepax } 11991c1c6bbaSCharles Keepax 12001c1c6bbaSCharles Keepax ret = arizona_wait_for_boot(arizona); 12011c1c6bbaSCharles Keepax if (ret) { 12021c1c6bbaSCharles Keepax dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); 12031c1c6bbaSCharles Keepax goto err_reset; 1204ca76ceb8SMark Brown } 1205ca76ceb8SMark Brown 1206ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 12073cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 12083cc72986SMark Brown if (ret != 0) { 12093cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 121059db9691SMark Brown goto err_reset; 12113cc72986SMark Brown } 12123cc72986SMark Brown 12133cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 12143cc72986SMark Brown &arizona->rev); 12153cc72986SMark Brown if (ret != 0) { 12163cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 121759db9691SMark Brown goto err_reset; 12183cc72986SMark Brown } 12193cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 12203cc72986SMark Brown 12213cc72986SMark Brown switch (reg) { 12223cc72986SMark Brown case 0x5102: 1223b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5102)) { 12243cc72986SMark Brown type_name = "WM5102"; 12253cc72986SMark Brown if (arizona->type != WM5102) { 1226b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1227b61c1ec0SRichard Fitzgerald "WM5102 registered as %d\n", 12283cc72986SMark Brown arizona->type); 12293cc72986SMark Brown arizona->type = WM5102; 12303cc72986SMark Brown } 1231b61c1ec0SRichard Fitzgerald 123262d62b59SMark Brown apply_patch = wm5102_patch; 1233c6d6bfb1SMark Brown arizona->rev &= 0x7; 1234ae05ea36SRichard Fitzgerald subdevs = wm5102_devs; 1235ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5102_devs); 1236b61c1ec0SRichard Fitzgerald } 12373cc72986SMark Brown break; 1238e102befeSMark Brown case 0x5110: 1239b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5110)) { 1240e5d4ef0dSRichard Fitzgerald switch (arizona->type) { 1241e5d4ef0dSRichard Fitzgerald case WM5110: 1242e102befeSMark Brown type_name = "WM5110"; 1243e5d4ef0dSRichard Fitzgerald break; 1244e5d4ef0dSRichard Fitzgerald case WM8280: 1245e5d4ef0dSRichard Fitzgerald type_name = "WM8280"; 1246e5d4ef0dSRichard Fitzgerald break; 1247e5d4ef0dSRichard Fitzgerald default: 1248e5d4ef0dSRichard Fitzgerald type_name = "WM5110"; 1249b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1250b61c1ec0SRichard Fitzgerald "WM5110 registered as %d\n", 1251e102befeSMark Brown arizona->type); 1252e102befeSMark Brown arizona->type = WM5110; 1253e5d4ef0dSRichard Fitzgerald break; 1254e102befeSMark Brown } 1255b61c1ec0SRichard Fitzgerald 125662d62b59SMark Brown apply_patch = wm5110_patch; 1257ae05ea36SRichard Fitzgerald subdevs = wm5110_devs; 1258ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5110_devs); 1259b61c1ec0SRichard Fitzgerald } 1260e102befeSMark Brown break; 1261ea1f3339SRichard Fitzgerald case 0x6363: 1262ea1f3339SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_CS47L24)) { 1263ea1f3339SRichard Fitzgerald switch (arizona->type) { 1264ea1f3339SRichard Fitzgerald case CS47L24: 1265ea1f3339SRichard Fitzgerald type_name = "CS47L24"; 1266ea1f3339SRichard Fitzgerald break; 1267ea1f3339SRichard Fitzgerald 1268ea1f3339SRichard Fitzgerald case WM1831: 1269ea1f3339SRichard Fitzgerald type_name = "WM1831"; 1270ea1f3339SRichard Fitzgerald break; 1271ea1f3339SRichard Fitzgerald 1272ea1f3339SRichard Fitzgerald default: 1273ea1f3339SRichard Fitzgerald dev_warn(arizona->dev, 1274ea1f3339SRichard Fitzgerald "CS47L24 registered as %d\n", 1275ea1f3339SRichard Fitzgerald arizona->type); 1276ea1f3339SRichard Fitzgerald arizona->type = CS47L24; 1277ea1f3339SRichard Fitzgerald break; 1278ea1f3339SRichard Fitzgerald } 1279ea1f3339SRichard Fitzgerald 1280ea1f3339SRichard Fitzgerald apply_patch = cs47l24_patch; 1281ea1f3339SRichard Fitzgerald subdevs = cs47l24_devs; 1282ea1f3339SRichard Fitzgerald n_subdevs = ARRAY_SIZE(cs47l24_devs); 1283ea1f3339SRichard Fitzgerald } 1284ea1f3339SRichard Fitzgerald break; 1285dc7d4863SCharles Keepax case 0x8997: 1286b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8997)) { 1287dc7d4863SCharles Keepax type_name = "WM8997"; 1288dc7d4863SCharles Keepax if (arizona->type != WM8997) { 1289b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1290b61c1ec0SRichard Fitzgerald "WM8997 registered as %d\n", 1291dc7d4863SCharles Keepax arizona->type); 1292dc7d4863SCharles Keepax arizona->type = WM8997; 1293dc7d4863SCharles Keepax } 1294b61c1ec0SRichard Fitzgerald 1295dc7d4863SCharles Keepax apply_patch = wm8997_patch; 1296ae05ea36SRichard Fitzgerald subdevs = wm8997_devs; 1297ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8997_devs); 1298b61c1ec0SRichard Fitzgerald } 1299dc7d4863SCharles Keepax break; 13006887b042SRichard Fitzgerald case 0x6349: 1301b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8998)) { 13026887b042SRichard Fitzgerald switch (arizona->type) { 13036887b042SRichard Fitzgerald case WM8998: 13046887b042SRichard Fitzgerald type_name = "WM8998"; 13056887b042SRichard Fitzgerald break; 13066887b042SRichard Fitzgerald 13076887b042SRichard Fitzgerald case WM1814: 13086887b042SRichard Fitzgerald type_name = "WM1814"; 13096887b042SRichard Fitzgerald break; 13106887b042SRichard Fitzgerald 13116887b042SRichard Fitzgerald default: 13126887b042SRichard Fitzgerald type_name = "WM8998"; 1313b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1314b61c1ec0SRichard Fitzgerald "WM8998 registered as %d\n", 13156887b042SRichard Fitzgerald arizona->type); 13166887b042SRichard Fitzgerald arizona->type = WM8998; 13176887b042SRichard Fitzgerald } 13186887b042SRichard Fitzgerald 13196887b042SRichard Fitzgerald apply_patch = wm8998_patch; 1320ae05ea36SRichard Fitzgerald subdevs = wm8998_devs; 1321ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8998_devs); 1322b61c1ec0SRichard Fitzgerald } 13236887b042SRichard Fitzgerald break; 13243cc72986SMark Brown default: 13253cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 132675d8a2b0SCharles Keepax ret = -ENODEV; 132759db9691SMark Brown goto err_reset; 13283cc72986SMark Brown } 13293cc72986SMark Brown 1330b61c1ec0SRichard Fitzgerald if (!subdevs) { 1331b61c1ec0SRichard Fitzgerald dev_err(arizona->dev, 1332b61c1ec0SRichard Fitzgerald "No kernel support for device ID %x\n", reg); 133375d8a2b0SCharles Keepax ret = -ENODEV; 1334b61c1ec0SRichard Fitzgerald goto err_reset; 1335b61c1ec0SRichard Fitzgerald } 1336b61c1ec0SRichard Fitzgerald 13373cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 13383cc72986SMark Brown 133962d62b59SMark Brown if (apply_patch) { 134062d62b59SMark Brown ret = apply_patch(arizona); 134162d62b59SMark Brown if (ret != 0) { 134262d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 134362d62b59SMark Brown ret); 134462d62b59SMark Brown goto err_reset; 134562d62b59SMark Brown } 1346e80436bbSCharles Keepax 1347e80436bbSCharles Keepax switch (arizona->type) { 1348e80436bbSCharles Keepax case WM5102: 13490be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 13500be068a0SCharles Keepax if (ret) { 1351e80436bbSCharles Keepax dev_err(arizona->dev, 1352e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 1353e80436bbSCharles Keepax ret); 1354e80436bbSCharles Keepax goto err_reset; 1355e80436bbSCharles Keepax } 1356e80436bbSCharles Keepax break; 1357882bc468SCharles Keepax case WM5110: 1358882bc468SCharles Keepax case WM8280: 1359882bc468SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 1360882bc468SCharles Keepax if (ret) { 1361882bc468SCharles Keepax dev_err(arizona->dev, 1362882bc468SCharles Keepax "Failed to apply sleep patch: %d\n", 1363882bc468SCharles Keepax ret); 1364882bc468SCharles Keepax goto err_reset; 1365882bc468SCharles Keepax } 1366882bc468SCharles Keepax break; 1367e80436bbSCharles Keepax default: 1368e80436bbSCharles Keepax break; 1369e80436bbSCharles Keepax } 137062d62b59SMark Brown } 137162d62b59SMark Brown 13723cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 13733cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 13743cc72986SMark Brown continue; 13753cc72986SMark Brown 13763cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 13773cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 13783cc72986SMark Brown } 13793cc72986SMark Brown 13803cc72986SMark Brown /* Chip default */ 13813cc72986SMark Brown if (!arizona->pdata.clk32k_src) 13823cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 13833cc72986SMark Brown 13843cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 13853cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 13863cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 13873cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 13883cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 13893cc72986SMark Brown arizona->pdata.clk32k_src - 1); 1390767c6dc0SMark Brown arizona_clk32k_enable(arizona); 13913cc72986SMark Brown break; 13923cc72986SMark Brown case ARIZONA_32KZ_NONE: 13933cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 13943cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 13953cc72986SMark Brown break; 13963cc72986SMark Brown default: 13973cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 13983cc72986SMark Brown arizona->pdata.clk32k_src); 13993cc72986SMark Brown ret = -EINVAL; 140059db9691SMark Brown goto err_reset; 14013cc72986SMark Brown } 14023cc72986SMark Brown 14033d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 1404544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 1405544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 14063d91f828SMark Brown continue; 14073d91f828SMark Brown 1408544c7aadSMark Brown /* Apply default for bypass mode */ 1409544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 1410544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 1411544c7aadSMark Brown 14123d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 1413544c7aadSMark Brown 14143d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 14153d91f828SMark Brown 14163d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 14173d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 14183d91f828SMark Brown 14193d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 14203d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 14213d91f828SMark Brown 1422f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 14233d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 14243d91f828SMark Brown 1425544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 1426544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 1427544c7aadSMark Brown 14283d91f828SMark Brown regmap_update_bits(arizona->regmap, 14293d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 14303d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 143171d134b9SCharles Keepax ARIZONA_MICB1_EXT_CAP | 14323d91f828SMark Brown ARIZONA_MICB1_DISCH | 1433544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 14343d91f828SMark Brown ARIZONA_MICB1_RATE, val); 14353d91f828SMark Brown } 14363d91f828SMark Brown 14373cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 14383cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 14393cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 14403cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 1441fc027d13SRichard Fitzgerald if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC) 1442fc027d13SRichard Fitzgerald val |= 1 << ARIZONA_IN1_MODE_SHIFT; 14436887b042SRichard Fitzgerald 14446887b042SRichard Fitzgerald switch (arizona->type) { 14456887b042SRichard Fitzgerald case WM8998: 14466887b042SRichard Fitzgerald case WM1814: 14476887b042SRichard Fitzgerald regmap_update_bits(arizona->regmap, 14486887b042SRichard Fitzgerald ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8), 14496887b042SRichard Fitzgerald ARIZONA_IN1L_SRC_SE_MASK, 14506887b042SRichard Fitzgerald (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 14516887b042SRichard Fitzgerald << ARIZONA_IN1L_SRC_SE_SHIFT); 14526887b042SRichard Fitzgerald 14536887b042SRichard Fitzgerald regmap_update_bits(arizona->regmap, 14546887b042SRichard Fitzgerald ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8), 14556887b042SRichard Fitzgerald ARIZONA_IN1R_SRC_SE_MASK, 14566887b042SRichard Fitzgerald (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 14576887b042SRichard Fitzgerald << ARIZONA_IN1R_SRC_SE_SHIFT); 14586887b042SRichard Fitzgerald 14596887b042SRichard Fitzgerald mask = ARIZONA_IN1_DMIC_SUP_MASK | 14606887b042SRichard Fitzgerald ARIZONA_IN1_MODE_MASK; 14616887b042SRichard Fitzgerald break; 14626887b042SRichard Fitzgerald default: 1463fc027d13SRichard Fitzgerald if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 1464fc027d13SRichard Fitzgerald val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT; 14653cc72986SMark Brown 14666887b042SRichard Fitzgerald mask = ARIZONA_IN1_DMIC_SUP_MASK | 14676887b042SRichard Fitzgerald ARIZONA_IN1_MODE_MASK | 14686887b042SRichard Fitzgerald ARIZONA_IN1_SINGLE_ENDED_MASK; 14696887b042SRichard Fitzgerald break; 14706887b042SRichard Fitzgerald } 14716887b042SRichard Fitzgerald 14723cc72986SMark Brown regmap_update_bits(arizona->regmap, 14733cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 14746887b042SRichard Fitzgerald mask, val); 14753cc72986SMark Brown } 14763cc72986SMark Brown 14773cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 14783cc72986SMark Brown /* Default is 0 so noop with defaults */ 14793cc72986SMark Brown if (arizona->pdata.out_mono[i]) 14803cc72986SMark Brown val = ARIZONA_OUT1_MONO; 14813cc72986SMark Brown else 14823cc72986SMark Brown val = 0; 14833cc72986SMark Brown 14843cc72986SMark Brown regmap_update_bits(arizona->regmap, 14853cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 14863cc72986SMark Brown ARIZONA_OUT1_MONO, val); 14873cc72986SMark Brown } 14883cc72986SMark Brown 14893cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 14903cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 14913cc72986SMark Brown regmap_update_bits(arizona->regmap, 14922a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 14933cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 14943cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 14953cc72986SMark Brown arizona->pdata.spk_mute[i]); 14963cc72986SMark Brown 14973cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 14983cc72986SMark Brown regmap_update_bits(arizona->regmap, 14992a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 15003cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 15013cc72986SMark Brown arizona->pdata.spk_fmt[i]); 15023cc72986SMark Brown } 15033cc72986SMark Brown 150472e43164SCharles Keepax pm_runtime_set_active(arizona->dev); 150572e43164SCharles Keepax pm_runtime_enable(arizona->dev); 150672e43164SCharles Keepax 15073cc72986SMark Brown /* Set up for interrupts */ 15083cc72986SMark Brown ret = arizona_irq_init(arizona); 15093cc72986SMark Brown if (ret != 0) 1510d347792cSCharles Keepax goto err_pm; 15113cc72986SMark Brown 151272e43164SCharles Keepax pm_runtime_set_autosuspend_delay(arizona->dev, 100); 151372e43164SCharles Keepax pm_runtime_use_autosuspend(arizona->dev); 151472e43164SCharles Keepax 15153cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 15163cc72986SMark Brown arizona_clkgen_err, arizona); 15173cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 15183cc72986SMark Brown arizona_overclocked, arizona); 15193cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 15203cc72986SMark Brown arizona_underclocked, arizona); 15213cc72986SMark Brown 1522ae05ea36SRichard Fitzgerald ret = mfd_add_devices(arizona->dev, PLATFORM_DEVID_NONE, 1523ae05ea36SRichard Fitzgerald subdevs, n_subdevs, NULL, 0, NULL); 15243cc72986SMark Brown 1525ae05ea36SRichard Fitzgerald if (ret) { 15263cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 15273cc72986SMark Brown goto err_irq; 15283cc72986SMark Brown } 15293cc72986SMark Brown 15303cc72986SMark Brown return 0; 15313cc72986SMark Brown 15323cc72986SMark Brown err_irq: 15333cc72986SMark Brown arizona_irq_exit(arizona); 1534d347792cSCharles Keepax err_pm: 1535d347792cSCharles Keepax pm_runtime_disable(arizona->dev); 15363cc72986SMark Brown err_reset: 15372229875dSCharles Keepax arizona_enable_reset(arizona); 153859db9691SMark Brown regulator_disable(arizona->dcvdd); 15393cc72986SMark Brown err_enable: 15403a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 15413cc72986SMark Brown arizona->core_supplies); 1542e6021511SCharles Keepax err_dcvdd: 1543e6021511SCharles Keepax regulator_put(arizona->dcvdd); 15443cc72986SMark Brown err_early: 15453cc72986SMark Brown mfd_remove_devices(dev); 15463cc72986SMark Brown return ret; 15473cc72986SMark Brown } 15483cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 15493cc72986SMark Brown 15504740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 15513cc72986SMark Brown { 1552fb36f77eSCharles Keepax disable_irq(arizona->irq); 1553b804020aSCharles Keepax pm_runtime_disable(arizona->dev); 1554b804020aSCharles Keepax 1555df6b3352SCharles Keepax regulator_disable(arizona->dcvdd); 1556e6021511SCharles Keepax regulator_put(arizona->dcvdd); 1557df6b3352SCharles Keepax 15583cc72986SMark Brown mfd_remove_devices(arizona->dev); 15593cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 15603cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 15613cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 15623cc72986SMark Brown arizona_irq_exit(arizona); 15632229875dSCharles Keepax arizona_enable_reset(arizona); 1564df6b3352SCharles Keepax 15654420286eSCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 15661d017b6bSMark Brown arizona->core_supplies); 15673cc72986SMark Brown return 0; 15683cc72986SMark Brown } 15693cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1570