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> 16c1860466SCharles Keepax #include <linux/gpio/consumer.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> 223cc72986SMark Brown #include <linux/pm_runtime.h> 233cc72986SMark Brown #include <linux/regmap.h> 243cc72986SMark Brown #include <linux/regulator/consumer.h> 255927467dSMark Brown #include <linux/regulator/machine.h> 263cc72986SMark Brown #include <linux/slab.h> 27*f99fea94SCharles Keepax #include <linux/ktime.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 238ef84f885SCharles Keepax #define ARIZONA_REG_POLL_DELAY_US 7500 239ef84f885SCharles Keepax 240*f99fea94SCharles Keepax static inline bool arizona_poll_reg_delay(ktime_t timeout) 241*f99fea94SCharles Keepax { 242*f99fea94SCharles Keepax if (ktime_compare(ktime_get(), timeout) > 0) 243*f99fea94SCharles Keepax return false; 244*f99fea94SCharles Keepax 245*f99fea94SCharles Keepax usleep_range(ARIZONA_REG_POLL_DELAY_US / 2, ARIZONA_REG_POLL_DELAY_US); 246*f99fea94SCharles Keepax 247*f99fea94SCharles Keepax return true; 248*f99fea94SCharles Keepax } 249*f99fea94SCharles Keepax 2509d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 251ef84f885SCharles Keepax int timeout_ms, unsigned int reg, 2529d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2539d53dfdcSCharles Keepax { 254*f99fea94SCharles Keepax ktime_t timeout = ktime_add_us(ktime_get(), timeout_ms * USEC_PER_MSEC); 2559d53dfdcSCharles Keepax unsigned int val = 0; 256ef84f885SCharles Keepax int ret; 2579d53dfdcSCharles Keepax 258*f99fea94SCharles Keepax do { 259*f99fea94SCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2609d53dfdcSCharles Keepax 261*f99fea94SCharles Keepax if ((val & mask) == target) 262*f99fea94SCharles Keepax return 0; 263*f99fea94SCharles Keepax } while (arizona_poll_reg_delay(timeout)); 264*f99fea94SCharles Keepax 265*f99fea94SCharles Keepax if (ret) { 266*f99fea94SCharles Keepax dev_err(arizona->dev, "Failed polling reg 0x%x: %d\n", 267*f99fea94SCharles Keepax reg, ret); 268ef84f885SCharles Keepax return ret; 2699d53dfdcSCharles Keepax } 2709d53dfdcSCharles Keepax 271*f99fea94SCharles Keepax dev_err(arizona->dev, "Polling reg 0x%x timed out: %x\n", reg, val); 272*f99fea94SCharles Keepax return -ETIMEDOUT; 273*f99fea94SCharles Keepax } 274*f99fea94SCharles Keepax 2753cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2763cc72986SMark Brown { 2779d53dfdcSCharles Keepax int ret; 2783cc72986SMark Brown 2793cc72986SMark Brown /* 2803cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2813cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2823cc72986SMark Brown * runtime resume. 2833cc72986SMark Brown */ 284ef84f885SCharles Keepax ret = arizona_poll_reg(arizona, 30, ARIZONA_INTERRUPT_RAW_STATUS_5, 2859d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2863cc72986SMark Brown 2879d53dfdcSCharles Keepax if (!ret) 2883cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2893cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2903cc72986SMark Brown 2913cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2923cc72986SMark Brown 2939d53dfdcSCharles Keepax return ret; 2943cc72986SMark Brown } 2953cc72986SMark Brown 2962229875dSCharles Keepax static inline void arizona_enable_reset(struct arizona *arizona) 2972229875dSCharles Keepax { 2982229875dSCharles Keepax if (arizona->pdata.reset) 299c1860466SCharles Keepax gpiod_set_raw_value_cansleep(arizona->pdata.reset, 0); 3002229875dSCharles Keepax } 3012229875dSCharles Keepax 3022229875dSCharles Keepax static void arizona_disable_reset(struct arizona *arizona) 3032229875dSCharles Keepax { 3042229875dSCharles Keepax if (arizona->pdata.reset) { 305121c075cSCharles Keepax switch (arizona->type) { 306121c075cSCharles Keepax case WM5110: 307121c075cSCharles Keepax case WM8280: 308121c075cSCharles Keepax /* Meet requirements for minimum reset duration */ 309b79a980fSLee Jones usleep_range(5000, 10000); 310121c075cSCharles Keepax break; 311121c075cSCharles Keepax default: 312121c075cSCharles Keepax break; 313121c075cSCharles Keepax } 314121c075cSCharles Keepax 315c1860466SCharles Keepax gpiod_set_raw_value_cansleep(arizona->pdata.reset, 1); 316b79a980fSLee Jones usleep_range(1000, 5000); 3172229875dSCharles Keepax } 3182229875dSCharles Keepax } 3192229875dSCharles Keepax 3203850e3eeSCharles Keepax struct arizona_sysclk_state { 3213850e3eeSCharles Keepax unsigned int fll; 3223850e3eeSCharles Keepax unsigned int sysclk; 3233850e3eeSCharles Keepax }; 3243850e3eeSCharles Keepax 3253850e3eeSCharles Keepax static int arizona_enable_freerun_sysclk(struct arizona *arizona, 3263850e3eeSCharles Keepax struct arizona_sysclk_state *state) 327e80436bbSCharles Keepax { 328e80436bbSCharles Keepax int ret, err; 329e80436bbSCharles Keepax 330e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 3313850e3eeSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &state->fll); 3320be068a0SCharles Keepax if (ret) { 333e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 334e80436bbSCharles Keepax ret); 335e80436bbSCharles Keepax return ret; 336e80436bbSCharles Keepax } 3373850e3eeSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 3383850e3eeSCharles Keepax &state->sysclk); 3390be068a0SCharles Keepax if (ret) { 340e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 341e80436bbSCharles Keepax ret); 342e80436bbSCharles Keepax return ret; 343e80436bbSCharles Keepax } 344e80436bbSCharles Keepax 345e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 346e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 347e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 3480be068a0SCharles Keepax if (ret) { 349e80436bbSCharles Keepax dev_err(arizona->dev, 350e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 351e80436bbSCharles Keepax ret); 352e80436bbSCharles Keepax return ret; 353e80436bbSCharles Keepax } 354ef84f885SCharles Keepax ret = arizona_poll_reg(arizona, 180, ARIZONA_INTERRUPT_RAW_STATUS_5, 355e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 356e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 357de4ea10aSCharles Keepax if (ret) 358e80436bbSCharles Keepax goto err_fll; 359e80436bbSCharles Keepax 360e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 3610be068a0SCharles Keepax if (ret) { 362e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 363e80436bbSCharles Keepax goto err_fll; 364e80436bbSCharles Keepax } 365e80436bbSCharles Keepax 3663850e3eeSCharles Keepax return 0; 3673850e3eeSCharles Keepax 3683850e3eeSCharles Keepax err_fll: 3693850e3eeSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3703850e3eeSCharles Keepax if (err) 3713850e3eeSCharles Keepax dev_err(arizona->dev, 3723850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", err); 3733850e3eeSCharles Keepax 3743850e3eeSCharles Keepax return ret; 3753850e3eeSCharles Keepax } 3763850e3eeSCharles Keepax 3773850e3eeSCharles Keepax static int arizona_disable_freerun_sysclk(struct arizona *arizona, 3783850e3eeSCharles Keepax struct arizona_sysclk_state *state) 3793850e3eeSCharles Keepax { 3803850e3eeSCharles Keepax int ret; 3813850e3eeSCharles Keepax 3823850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 3833850e3eeSCharles Keepax state->sysclk); 3843850e3eeSCharles Keepax if (ret) { 3853850e3eeSCharles Keepax dev_err(arizona->dev, 3863850e3eeSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", ret); 3873850e3eeSCharles Keepax return ret; 3883850e3eeSCharles Keepax } 3893850e3eeSCharles Keepax 3903850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3913850e3eeSCharles Keepax if (ret) { 3923850e3eeSCharles Keepax dev_err(arizona->dev, 3933850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", ret); 3943850e3eeSCharles Keepax return ret; 3953850e3eeSCharles Keepax } 3963850e3eeSCharles Keepax 3973850e3eeSCharles Keepax return 0; 3983850e3eeSCharles Keepax } 3993850e3eeSCharles Keepax 4003850e3eeSCharles Keepax static int wm5102_apply_hardware_patch(struct arizona *arizona) 4013850e3eeSCharles Keepax { 4023850e3eeSCharles Keepax struct arizona_sysclk_state state; 4033850e3eeSCharles Keepax int err, ret; 4043850e3eeSCharles Keepax 4053850e3eeSCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 4063850e3eeSCharles Keepax if (ret) 4073850e3eeSCharles Keepax return ret; 4083850e3eeSCharles Keepax 409e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 410e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 411e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 4120be068a0SCharles Keepax if (ret) { 413e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 414e80436bbSCharles Keepax ret); 4153850e3eeSCharles Keepax goto err; 416e80436bbSCharles Keepax } 4173850e3eeSCharles Keepax 418ef84f885SCharles Keepax ret = arizona_poll_reg(arizona, 30, ARIZONA_WRITE_SEQUENCER_CTRL_1, 419e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 420de4ea10aSCharles Keepax if (ret) 421e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 422e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 423e80436bbSCharles Keepax 4243850e3eeSCharles Keepax err: 4253850e3eeSCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 426e80436bbSCharles Keepax 4270be068a0SCharles Keepax return ret ?: err; 428e80436bbSCharles Keepax } 429e80436bbSCharles Keepax 430882bc468SCharles Keepax /* 431882bc468SCharles Keepax * Register patch to some of the CODECs internal write sequences 432882bc468SCharles Keepax * to ensure a clean exit from the low power sleep state. 433882bc468SCharles Keepax */ 4348019ff6cSNariman Poushin static const struct reg_sequence wm5110_sleep_patch[] = { 435882bc468SCharles Keepax { 0x337A, 0xC100 }, 436882bc468SCharles Keepax { 0x337B, 0x0041 }, 437882bc468SCharles Keepax { 0x3300, 0xA210 }, 438882bc468SCharles Keepax { 0x3301, 0x050C }, 439882bc468SCharles Keepax }; 440882bc468SCharles Keepax 441882bc468SCharles Keepax static int wm5110_apply_sleep_patch(struct arizona *arizona) 442882bc468SCharles Keepax { 443882bc468SCharles Keepax struct arizona_sysclk_state state; 444882bc468SCharles Keepax int err, ret; 445882bc468SCharles Keepax 446882bc468SCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 447882bc468SCharles Keepax if (ret) 448882bc468SCharles Keepax return ret; 449882bc468SCharles Keepax 450882bc468SCharles Keepax ret = regmap_multi_reg_write_bypassed(arizona->regmap, 451882bc468SCharles Keepax wm5110_sleep_patch, 452882bc468SCharles Keepax ARRAY_SIZE(wm5110_sleep_patch)); 453882bc468SCharles Keepax 454882bc468SCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 455882bc468SCharles Keepax 456882bc468SCharles Keepax return ret ?: err; 457882bc468SCharles Keepax } 458882bc468SCharles Keepax 4591c1c6bbaSCharles Keepax static int wm5102_clear_write_sequencer(struct arizona *arizona) 4601c1c6bbaSCharles Keepax { 4611c1c6bbaSCharles Keepax int ret; 4621c1c6bbaSCharles Keepax 4631c1c6bbaSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3, 4641c1c6bbaSCharles Keepax 0x0); 4651c1c6bbaSCharles Keepax if (ret) { 4661c1c6bbaSCharles Keepax dev_err(arizona->dev, 4671c1c6bbaSCharles Keepax "Failed to clear write sequencer state: %d\n", ret); 4681c1c6bbaSCharles Keepax return ret; 4691c1c6bbaSCharles Keepax } 4701c1c6bbaSCharles Keepax 4711c1c6bbaSCharles Keepax arizona_enable_reset(arizona); 4721c1c6bbaSCharles Keepax regulator_disable(arizona->dcvdd); 4731c1c6bbaSCharles Keepax 4741c1c6bbaSCharles Keepax msleep(20); 4751c1c6bbaSCharles Keepax 4761c1c6bbaSCharles Keepax ret = regulator_enable(arizona->dcvdd); 4771c1c6bbaSCharles Keepax if (ret) { 4781c1c6bbaSCharles Keepax dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret); 4791c1c6bbaSCharles Keepax return ret; 4801c1c6bbaSCharles Keepax } 4811c1c6bbaSCharles Keepax arizona_disable_reset(arizona); 4821c1c6bbaSCharles Keepax 4831c1c6bbaSCharles Keepax return 0; 4841c1c6bbaSCharles Keepax } 4851c1c6bbaSCharles Keepax 48648bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM 487e7811147SRichard Fitzgerald static int arizona_isolate_dcvdd(struct arizona *arizona) 488e7811147SRichard Fitzgerald { 489e7811147SRichard Fitzgerald int ret; 490e7811147SRichard Fitzgerald 491e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 492e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 493e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 494e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1); 495e7811147SRichard Fitzgerald if (ret != 0) 496e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", ret); 497e7811147SRichard Fitzgerald 498e7811147SRichard Fitzgerald return ret; 499e7811147SRichard Fitzgerald } 500e7811147SRichard Fitzgerald 501e7811147SRichard Fitzgerald static int arizona_connect_dcvdd(struct arizona *arizona) 502e7811147SRichard Fitzgerald { 503e7811147SRichard Fitzgerald int ret; 504e7811147SRichard Fitzgerald 505e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 506e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 507e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 0); 508e7811147SRichard Fitzgerald if (ret != 0) 509e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to connect DCVDD: %d\n", ret); 510e7811147SRichard Fitzgerald 511e7811147SRichard Fitzgerald return ret; 512e7811147SRichard Fitzgerald } 513e7811147SRichard Fitzgerald 514e3424273SRichard Fitzgerald static int arizona_is_jack_det_active(struct arizona *arizona) 515e3424273SRichard Fitzgerald { 516e3424273SRichard Fitzgerald unsigned int val; 517e3424273SRichard Fitzgerald int ret; 518e3424273SRichard Fitzgerald 519e3424273SRichard Fitzgerald ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val); 520e3424273SRichard Fitzgerald if (ret) { 521e3424273SRichard Fitzgerald dev_err(arizona->dev, 522e3424273SRichard Fitzgerald "Failed to check jack det status: %d\n", ret); 523e3424273SRichard Fitzgerald return ret; 524e3424273SRichard Fitzgerald } else if (val & ARIZONA_JD1_ENA) { 525e3424273SRichard Fitzgerald return 1; 526e3424273SRichard Fitzgerald } else { 527e3424273SRichard Fitzgerald return 0; 528e3424273SRichard Fitzgerald } 529e3424273SRichard Fitzgerald } 530e3424273SRichard Fitzgerald 5313cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 5323cc72986SMark Brown { 5333cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 5343cc72986SMark Brown int ret; 5353cc72986SMark Brown 536508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 537508c8299SMark Brown 538e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 539e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Re-enabling core supplies\n"); 540e6cb7341SCharles Keepax 541e6cb7341SCharles Keepax ret = regulator_bulk_enable(arizona->num_core_supplies, 542e6cb7341SCharles Keepax arizona->core_supplies); 543e6cb7341SCharles Keepax if (ret) { 544e6cb7341SCharles Keepax dev_err(dev, "Failed to enable core supplies: %d\n", 545e6cb7341SCharles Keepax ret); 546e6cb7341SCharles Keepax return ret; 547e6cb7341SCharles Keepax } 548e6cb7341SCharles Keepax } 549e6cb7341SCharles Keepax 55059db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 55159db9691SMark Brown if (ret != 0) { 55259db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 553e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) 554e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 555e6cb7341SCharles Keepax arizona->core_supplies); 55659db9691SMark Brown return ret; 55759db9691SMark Brown } 5583cc72986SMark Brown 559e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 560e6cb7341SCharles Keepax arizona_disable_reset(arizona); 561e6cb7341SCharles Keepax enable_irq(arizona->irq); 562e6cb7341SCharles Keepax arizona->has_fully_powered_off = false; 563e6cb7341SCharles Keepax } 564e6cb7341SCharles Keepax 5653cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 5663cc72986SMark Brown 5674c9bb8bcSCharles Keepax switch (arizona->type) { 5684c9bb8bcSCharles Keepax case WM5102: 5695927467dSMark Brown if (arizona->external_dcvdd) { 570e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 571e7811147SRichard Fitzgerald if (ret != 0) 5725927467dSMark Brown goto err; 5735927467dSMark Brown } 5745927467dSMark Brown 5754c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 5764c9bb8bcSCharles Keepax if (ret != 0) { 5774c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 5784c9bb8bcSCharles Keepax ret); 5794c9bb8bcSCharles Keepax goto err; 5804c9bb8bcSCharles Keepax } 581e80436bbSCharles Keepax 5820be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 5830be068a0SCharles Keepax if (ret) { 584e80436bbSCharles Keepax dev_err(arizona->dev, 585e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 586e80436bbSCharles Keepax ret); 587e80436bbSCharles Keepax goto err; 588e80436bbSCharles Keepax } 589e80436bbSCharles Keepax break; 59096129a0eSCharles Keepax case WM5110: 59196129a0eSCharles Keepax case WM8280: 59296129a0eSCharles Keepax ret = arizona_wait_for_boot(arizona); 59396129a0eSCharles Keepax if (ret) 59496129a0eSCharles Keepax goto err; 59596129a0eSCharles Keepax 59696129a0eSCharles Keepax if (arizona->external_dcvdd) { 597e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 598e7811147SRichard Fitzgerald if (ret != 0) 59996129a0eSCharles Keepax goto err; 60096129a0eSCharles Keepax } else { 60196129a0eSCharles Keepax /* 60296129a0eSCharles Keepax * As this is only called for the internal regulator 60396129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 60496129a0eSCharles Keepax * to request an exact range. 60596129a0eSCharles Keepax */ 60696129a0eSCharles Keepax ret = regulator_set_voltage(arizona->dcvdd, 60796129a0eSCharles Keepax 1200000, 1200000); 60896129a0eSCharles Keepax if (ret < 0) { 60996129a0eSCharles Keepax dev_err(arizona->dev, 61096129a0eSCharles Keepax "Failed to set resume voltage: %d\n", 61196129a0eSCharles Keepax ret); 61296129a0eSCharles Keepax goto err; 61396129a0eSCharles Keepax } 61496129a0eSCharles Keepax } 615e6cb7341SCharles Keepax 616e6cb7341SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 617e6cb7341SCharles Keepax if (ret) { 618e6cb7341SCharles Keepax dev_err(arizona->dev, 619e6cb7341SCharles Keepax "Failed to re-apply sleep patch: %d\n", 620e6cb7341SCharles Keepax ret); 621e6cb7341SCharles Keepax goto err; 622e6cb7341SCharles Keepax } 62396129a0eSCharles Keepax break; 624ea1f3339SRichard Fitzgerald case WM1831: 625ea1f3339SRichard Fitzgerald case CS47L24: 626ea1f3339SRichard Fitzgerald ret = arizona_wait_for_boot(arizona); 627ea1f3339SRichard Fitzgerald if (ret != 0) 628ea1f3339SRichard Fitzgerald goto err; 629ea1f3339SRichard Fitzgerald break; 630e80436bbSCharles Keepax default: 63112bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 6323762aedeSCharles Keepax if (ret != 0) 63312bb68edSCharles Keepax goto err; 63412bb68edSCharles Keepax 6355927467dSMark Brown if (arizona->external_dcvdd) { 636e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 637e7811147SRichard Fitzgerald if (ret != 0) 6385927467dSMark Brown goto err; 6395927467dSMark Brown } 640e80436bbSCharles Keepax break; 6414c9bb8bcSCharles Keepax } 6424c9bb8bcSCharles Keepax 6439270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 6449270bdf5SMark Brown if (ret != 0) { 6459270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 6464816bd1cSMark Brown goto err; 6479270bdf5SMark Brown } 6483cc72986SMark Brown 6493cc72986SMark Brown return 0; 6504816bd1cSMark Brown 6514816bd1cSMark Brown err: 6524816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 6534816bd1cSMark Brown regulator_disable(arizona->dcvdd); 6544816bd1cSMark Brown return ret; 6553cc72986SMark Brown } 6563cc72986SMark Brown 6573cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 6583cc72986SMark Brown { 6593cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 660a05950a4SDan Carpenter int jd_active = 0; 6615927467dSMark Brown int ret; 6623cc72986SMark Brown 663508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 664508c8299SMark Brown 66596129a0eSCharles Keepax switch (arizona->type) { 66696129a0eSCharles Keepax case WM5110: 66796129a0eSCharles Keepax case WM8280: 668e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 669e3424273SRichard Fitzgerald if (jd_active < 0) 670e3424273SRichard Fitzgerald return jd_active; 671e3424273SRichard Fitzgerald 672e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 673e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 674e7811147SRichard Fitzgerald if (ret != 0) 675e7811147SRichard Fitzgerald return ret; 676e7811147SRichard Fitzgerald } else { 67796129a0eSCharles Keepax /* 67896129a0eSCharles Keepax * As this is only called for the internal regulator 67996129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 68096129a0eSCharles Keepax * to request an exact range. 68196129a0eSCharles Keepax */ 682e7811147SRichard Fitzgerald ret = regulator_set_voltage(arizona->dcvdd, 683e7811147SRichard Fitzgerald 1175000, 1175000); 68496129a0eSCharles Keepax if (ret < 0) { 68596129a0eSCharles Keepax dev_err(arizona->dev, 686e7811147SRichard Fitzgerald "Failed to set suspend voltage: %d\n", 687e7811147SRichard Fitzgerald ret); 688e6cb7341SCharles Keepax return ret; 689e6cb7341SCharles Keepax } 690e7811147SRichard Fitzgerald } 691e6cb7341SCharles Keepax break; 692e6cb7341SCharles Keepax case WM5102: 693e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 694e3424273SRichard Fitzgerald if (jd_active < 0) 695e3424273SRichard Fitzgerald return jd_active; 696e3424273SRichard Fitzgerald 697e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 698e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 699e7811147SRichard Fitzgerald if (ret != 0) 700e7811147SRichard Fitzgerald return ret; 701e7811147SRichard Fitzgerald } 702e7811147SRichard Fitzgerald 703e3424273SRichard Fitzgerald if (!jd_active) { 704e6cb7341SCharles Keepax ret = regmap_write(arizona->regmap, 705e6cb7341SCharles Keepax ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0); 706e6cb7341SCharles Keepax if (ret) { 707e6cb7341SCharles Keepax dev_err(arizona->dev, 708e6cb7341SCharles Keepax "Failed to clear write sequencer: %d\n", 70996129a0eSCharles Keepax ret); 71096129a0eSCharles Keepax return ret; 71196129a0eSCharles Keepax } 712e6cb7341SCharles Keepax } 71396129a0eSCharles Keepax break; 714ea1f3339SRichard Fitzgerald case WM1831: 715ea1f3339SRichard Fitzgerald case CS47L24: 716ea1f3339SRichard Fitzgerald break; 71796129a0eSCharles Keepax default: 718e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 719e3424273SRichard Fitzgerald if (jd_active < 0) 720e3424273SRichard Fitzgerald return jd_active; 721e3424273SRichard Fitzgerald 722e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 723e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 724e7811147SRichard Fitzgerald if (ret != 0) 725e7811147SRichard Fitzgerald return ret; 726e7811147SRichard Fitzgerald } 72796129a0eSCharles Keepax break; 72896129a0eSCharles Keepax } 7295927467dSMark Brown 7303cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 7313cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 732e293e847SCharles Keepax regulator_disable(arizona->dcvdd); 7333cc72986SMark Brown 734e6cb7341SCharles Keepax /* Allow us to completely power down if no jack detection */ 735e3424273SRichard Fitzgerald if (!jd_active) { 736e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Fully powering off\n"); 737e6cb7341SCharles Keepax 738e6cb7341SCharles Keepax arizona->has_fully_powered_off = true; 739e6cb7341SCharles Keepax 74011150929SCharles Keepax disable_irq_nosync(arizona->irq); 741e6cb7341SCharles Keepax arizona_enable_reset(arizona); 742e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 743e6cb7341SCharles Keepax arizona->core_supplies); 744e6cb7341SCharles Keepax } 745e6cb7341SCharles Keepax 7463cc72986SMark Brown return 0; 7473cc72986SMark Brown } 7483cc72986SMark Brown #endif 7493cc72986SMark Brown 750dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 75167c99296SMark Brown static int arizona_suspend(struct device *dev) 75267c99296SMark Brown { 75367c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 75467c99296SMark Brown 75567c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 75667c99296SMark Brown disable_irq(arizona->irq); 75767c99296SMark Brown 75867c99296SMark Brown return 0; 75967c99296SMark Brown } 76067c99296SMark Brown 7613612b27cSCharles Keepax static int arizona_suspend_noirq(struct device *dev) 76267c99296SMark Brown { 76367c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 76467c99296SMark Brown 76567c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 76667c99296SMark Brown enable_irq(arizona->irq); 76767c99296SMark Brown 76867c99296SMark Brown return 0; 76967c99296SMark Brown } 77067c99296SMark Brown 771dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 772dc781d0eSMark Brown { 773dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 774dc781d0eSMark Brown 775dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 776dc781d0eSMark Brown disable_irq(arizona->irq); 777dc781d0eSMark Brown 778dc781d0eSMark Brown return 0; 779dc781d0eSMark Brown } 780dc781d0eSMark Brown 781dc781d0eSMark Brown static int arizona_resume(struct device *dev) 782dc781d0eSMark Brown { 783dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 784dc781d0eSMark Brown 7853612b27cSCharles Keepax dev_dbg(arizona->dev, "Resume, reenabling IRQ\n"); 786dc781d0eSMark Brown enable_irq(arizona->irq); 787dc781d0eSMark Brown 788dc781d0eSMark Brown return 0; 789dc781d0eSMark Brown } 790dc781d0eSMark Brown #endif 791dc781d0eSMark Brown 7923cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 7933cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 7943cc72986SMark Brown arizona_runtime_resume, 7953cc72986SMark Brown NULL) 79667c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 7973612b27cSCharles Keepax SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq, 7983612b27cSCharles Keepax arizona_resume_noirq) 7993cc72986SMark Brown }; 8003cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 8013cc72986SMark Brown 802d781009cSMark Brown #ifdef CONFIG_OF 803942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev) 804d781009cSMark Brown { 805d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 806d781009cSMark Brown 807d781009cSMark Brown if (id) 808942786e6SLee Jones return (unsigned long)id->data; 809d781009cSMark Brown else 810d781009cSMark Brown return 0; 811d781009cSMark Brown } 812d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 813d781009cSMark Brown 814d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 815d781009cSMark Brown { 816e4fcb1d6SCharles Keepax struct arizona_pdata *pdata = &arizona->pdata; 817d781009cSMark Brown int ret, i; 818d781009cSMark Brown 819c1860466SCharles Keepax /* Handle old non-standard DT binding */ 820c1860466SCharles Keepax pdata->reset = devm_gpiod_get_from_of_node(arizona->dev, 821c1860466SCharles Keepax arizona->dev->of_node, 822c1860466SCharles Keepax "wlf,reset", 0, 823c1860466SCharles Keepax GPIOD_OUT_LOW, 824c1860466SCharles Keepax "arizona /RESET"); 825c1860466SCharles Keepax if (IS_ERR(pdata->reset)) { 826c1860466SCharles Keepax ret = PTR_ERR(pdata->reset); 8271961531dSCharles Keepax 828c1860466SCharles Keepax /* 829c1860466SCharles Keepax * Reset missing will be caught when other binding is read 830c1860466SCharles Keepax * but all other errors imply this binding is in use but has 831c1860466SCharles Keepax * encountered a problem so should be handled. 832c1860466SCharles Keepax */ 833c1860466SCharles Keepax if (ret == -EPROBE_DEFER) 834c1860466SCharles Keepax return ret; 835c1860466SCharles Keepax else if (ret != -ENOENT && ret != -ENOSYS) 836c1860466SCharles Keepax dev_err(arizona->dev, "Reset GPIO malformed: %d\n", 837c1860466SCharles Keepax ret); 838c1860466SCharles Keepax 839c1860466SCharles Keepax pdata->reset = NULL; 8401961531dSCharles Keepax } 841d781009cSMark Brown 842d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 843d781009cSMark Brown "wlf,gpio-defaults", 8443762aedeSCharles Keepax pdata->gpio_defaults, 8453762aedeSCharles Keepax ARRAY_SIZE(pdata->gpio_defaults)); 846d781009cSMark Brown if (ret >= 0) { 847d781009cSMark Brown /* 848d781009cSMark Brown * All values are literal except out of range values 849d781009cSMark Brown * which are chip default, translate into platform 850d781009cSMark Brown * data which uses 0 as chip default and out of range 851d781009cSMark Brown * as zero. 852d781009cSMark Brown */ 8533762aedeSCharles Keepax for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { 8543762aedeSCharles Keepax if (pdata->gpio_defaults[i] > 0xffff) 8553762aedeSCharles Keepax pdata->gpio_defaults[i] = 0; 8563762aedeSCharles Keepax else if (pdata->gpio_defaults[i] == 0) 8573762aedeSCharles Keepax pdata->gpio_defaults[i] = 0x10000; 858d781009cSMark Brown } 859d781009cSMark Brown } else { 860d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 861d781009cSMark Brown ret); 862d781009cSMark Brown } 863d781009cSMark Brown 864d781009cSMark Brown return 0; 865d781009cSMark Brown } 866d781009cSMark Brown 867d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 868d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 869d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 870e5d4ef0dSRichard Fitzgerald { .compatible = "wlf,wm8280", .data = (void *)WM8280 }, 871dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 8726887b042SRichard Fitzgerald { .compatible = "wlf,wm8998", .data = (void *)WM8998 }, 8736887b042SRichard Fitzgerald { .compatible = "wlf,wm1814", .data = (void *)WM1814 }, 874ea1f3339SRichard Fitzgerald { .compatible = "wlf,wm1831", .data = (void *)WM1831 }, 875ea1f3339SRichard Fitzgerald { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 }, 876d781009cSMark Brown {}, 877d781009cSMark Brown }; 878d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 879d781009cSMark Brown #else 880d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 881d781009cSMark Brown { 882d781009cSMark Brown return 0; 883d781009cSMark Brown } 884d781009cSMark Brown #endif 885d781009cSMark Brown 8865ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = { 8873cc72986SMark Brown { .name = "arizona-ldo1" }, 8883cc72986SMark Brown }; 8893cc72986SMark Brown 8903762aedeSCharles Keepax static const char * const wm5102_supplies[] = { 8915fc6c396SCharles Keepax "MICVDD", 89232dadef2SCharles Keepax "DBVDD2", 89332dadef2SCharles Keepax "DBVDD3", 89432dadef2SCharles Keepax "CPVDD", 89532dadef2SCharles Keepax "SPKVDDL", 89632dadef2SCharles Keepax "SPKVDDR", 89732dadef2SCharles Keepax }; 89832dadef2SCharles Keepax 8995ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = { 900d7768111SMark Brown { .name = "arizona-micsupp" }, 901f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9025fc6c396SCharles Keepax { 9035fc6c396SCharles Keepax .name = "arizona-extcon", 9045fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9055fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9065fc6c396SCharles Keepax }, 907503b1cacSMark Brown { .name = "arizona-haptics" }, 9083cc72986SMark Brown { .name = "arizona-pwm" }, 90932dadef2SCharles Keepax { 91032dadef2SCharles Keepax .name = "wm5102-codec", 91132dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 91232dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 91332dadef2SCharles Keepax }, 9143cc72986SMark Brown }; 9153cc72986SMark Brown 9165ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = { 917d7768111SMark Brown { .name = "arizona-micsupp" }, 918f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9195fc6c396SCharles Keepax { 9205fc6c396SCharles Keepax .name = "arizona-extcon", 9215fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9225fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9235fc6c396SCharles Keepax }, 924503b1cacSMark Brown { .name = "arizona-haptics" }, 925e102befeSMark Brown { .name = "arizona-pwm" }, 92632dadef2SCharles Keepax { 92732dadef2SCharles Keepax .name = "wm5110-codec", 92832dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 92932dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 93032dadef2SCharles Keepax }, 93132dadef2SCharles Keepax }; 93232dadef2SCharles Keepax 933ea1f3339SRichard Fitzgerald static const char * const cs47l24_supplies[] = { 934ea1f3339SRichard Fitzgerald "MICVDD", 935ea1f3339SRichard Fitzgerald "CPVDD", 936ea1f3339SRichard Fitzgerald "SPKVDD", 937ea1f3339SRichard Fitzgerald }; 938ea1f3339SRichard Fitzgerald 939ea1f3339SRichard Fitzgerald static const struct mfd_cell cs47l24_devs[] = { 940ea1f3339SRichard Fitzgerald { .name = "arizona-gpio" }, 941ea1f3339SRichard Fitzgerald { .name = "arizona-haptics" }, 942ea1f3339SRichard Fitzgerald { .name = "arizona-pwm" }, 943ea1f3339SRichard Fitzgerald { 944ea1f3339SRichard Fitzgerald .name = "cs47l24-codec", 945ea1f3339SRichard Fitzgerald .parent_supplies = cs47l24_supplies, 946ea1f3339SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(cs47l24_supplies), 947ea1f3339SRichard Fitzgerald }, 948ea1f3339SRichard Fitzgerald }; 949ea1f3339SRichard Fitzgerald 9503762aedeSCharles Keepax static const char * const wm8997_supplies[] = { 951996c2d4fSCharles Keepax "MICVDD", 95232dadef2SCharles Keepax "DBVDD2", 95332dadef2SCharles Keepax "CPVDD", 95432dadef2SCharles Keepax "SPKVDD", 955e102befeSMark Brown }; 956e102befeSMark Brown 9575ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = { 958dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 959f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9605fc6c396SCharles Keepax { 9615fc6c396SCharles Keepax .name = "arizona-extcon", 9625fc6c396SCharles Keepax .parent_supplies = wm8997_supplies, 9635fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9645fc6c396SCharles Keepax }, 965dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 966dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 96732dadef2SCharles Keepax { 96832dadef2SCharles Keepax .name = "wm8997-codec", 96932dadef2SCharles Keepax .parent_supplies = wm8997_supplies, 97032dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), 97132dadef2SCharles Keepax }, 972dc7d4863SCharles Keepax }; 973dc7d4863SCharles Keepax 9746887b042SRichard Fitzgerald static const struct mfd_cell wm8998_devs[] = { 975f83c218cSCharles Keepax { .name = "arizona-micsupp" }, 976f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9776887b042SRichard Fitzgerald { 9786887b042SRichard Fitzgerald .name = "arizona-extcon", 9796887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 9806887b042SRichard Fitzgerald .num_parent_supplies = 1, /* We only need MICVDD */ 9816887b042SRichard Fitzgerald }, 9826887b042SRichard Fitzgerald { .name = "arizona-haptics" }, 9836887b042SRichard Fitzgerald { .name = "arizona-pwm" }, 9846887b042SRichard Fitzgerald { 9856887b042SRichard Fitzgerald .name = "wm8998-codec", 9866887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 9876887b042SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 9886887b042SRichard Fitzgerald }, 9896887b042SRichard Fitzgerald }; 9906887b042SRichard Fitzgerald 991f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 9923cc72986SMark Brown { 993cdd8da8cSSylwester Nawrocki const char * const mclk_name[] = { "mclk1", "mclk2" }; 9943cc72986SMark Brown struct device *dev = arizona->dev; 995ea1f3339SRichard Fitzgerald const char *type_name = NULL; 9966000c99eSCharles Keepax unsigned int reg, val; 99762d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 998ae05ea36SRichard Fitzgerald const struct mfd_cell *subdevs = NULL; 999ae05ea36SRichard Fitzgerald int n_subdevs, ret, i; 10003cc72986SMark Brown 10013cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 10023cc72986SMark Brown mutex_init(&arizona->clk_lock); 10033cc72986SMark Brown 1004b8d336edSCharles Keepax if (dev_get_platdata(arizona->dev)) { 10053cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 10063cc72986SMark Brown sizeof(arizona->pdata)); 1007b8d336edSCharles Keepax } else { 1008b8d336edSCharles Keepax ret = arizona_of_get_core_pdata(arizona); 1009b8d336edSCharles Keepax if (ret < 0) 1010b8d336edSCharles Keepax return ret; 1011b8d336edSCharles Keepax } 10123cc72986SMark Brown 1013cdd8da8cSSylwester Nawrocki BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name)); 1014cdd8da8cSSylwester Nawrocki for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) { 1015cdd8da8cSSylwester Nawrocki arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]); 1016cdd8da8cSSylwester Nawrocki if (IS_ERR(arizona->mclk[i])) { 1017cdd8da8cSSylwester Nawrocki dev_info(arizona->dev, "Failed to get %s: %ld\n", 1018cdd8da8cSSylwester Nawrocki mclk_name[i], PTR_ERR(arizona->mclk[i])); 1019cdd8da8cSSylwester Nawrocki arizona->mclk[i] = NULL; 1020cdd8da8cSSylwester Nawrocki } 1021cdd8da8cSSylwester Nawrocki } 1022cdd8da8cSSylwester Nawrocki 10233cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 10243cc72986SMark Brown 10253cc72986SMark Brown switch (arizona->type) { 10263cc72986SMark Brown case WM5102: 1027e102befeSMark Brown case WM5110: 1028e5d4ef0dSRichard Fitzgerald case WM8280: 1029dc7d4863SCharles Keepax case WM8997: 10306887b042SRichard Fitzgerald case WM8998: 10316887b042SRichard Fitzgerald case WM1814: 1032ea1f3339SRichard Fitzgerald case WM1831: 1033ea1f3339SRichard Fitzgerald case CS47L24: 10343cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 10353cc72986SMark Brown arizona->core_supplies[i].supply 10363cc72986SMark Brown = wm5102_core_supplies[i]; 10373cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 10383cc72986SMark Brown break; 10393cc72986SMark Brown default: 10403cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 10413cc72986SMark Brown arizona->type); 104275d8a2b0SCharles Keepax return -ENODEV; 10433cc72986SMark Brown } 10443cc72986SMark Brown 10454a8c475fSCharles Keepax /* Mark DCVDD as external, LDO1 driver will clear if internal */ 10464a8c475fSCharles Keepax arizona->external_dcvdd = true; 10474a8c475fSCharles Keepax 1048ea1f3339SRichard Fitzgerald switch (arizona->type) { 1049ea1f3339SRichard Fitzgerald case WM1831: 1050ea1f3339SRichard Fitzgerald case CS47L24: 1051ea1f3339SRichard Fitzgerald break; /* No LDO1 regulator */ 1052ea1f3339SRichard Fitzgerald default: 10533cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 10540848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 10553cc72986SMark Brown if (ret != 0) { 10563cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 10573cc72986SMark Brown return ret; 10583cc72986SMark Brown } 1059ea1f3339SRichard Fitzgerald break; 1060ea1f3339SRichard Fitzgerald } 10613cc72986SMark Brown 10623cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 10633cc72986SMark Brown arizona->core_supplies); 10643cc72986SMark Brown if (ret != 0) { 10653cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 10663cc72986SMark Brown ret); 10673cc72986SMark Brown goto err_early; 10683cc72986SMark Brown } 10693cc72986SMark Brown 10700c2d0ffbSCharles Keepax /** 10710c2d0ffbSCharles Keepax * Don't use devres here because the only device we have to get 10720c2d0ffbSCharles Keepax * against is the MFD device and DCVDD will likely be supplied by 10730c2d0ffbSCharles Keepax * one of its children. Meaning that the regulator will be 10740c2d0ffbSCharles Keepax * destroyed by the time devres calls regulator put. 10750c2d0ffbSCharles Keepax */ 1076e6021511SCharles Keepax arizona->dcvdd = regulator_get(arizona->dev, "DCVDD"); 107759db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 107859db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 107959db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 108059db9691SMark Brown goto err_early; 108159db9691SMark Brown } 108259db9691SMark Brown 1083c1860466SCharles Keepax if (!arizona->pdata.reset) { 108487d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 1085c1860466SCharles Keepax arizona->pdata.reset = devm_gpiod_get(arizona->dev, "reset", 1086c1860466SCharles Keepax GPIOD_OUT_LOW); 1087c1860466SCharles Keepax if (IS_ERR(arizona->pdata.reset)) { 1088c1860466SCharles Keepax ret = PTR_ERR(arizona->pdata.reset); 1089c1860466SCharles Keepax if (ret == -EPROBE_DEFER) 1090e6021511SCharles Keepax goto err_dcvdd; 1091c1860466SCharles Keepax 1092c1860466SCharles Keepax dev_err(arizona->dev, 1093c1860466SCharles Keepax "Reset GPIO missing/malformed: %d\n", ret); 1094c1860466SCharles Keepax 1095c1860466SCharles Keepax arizona->pdata.reset = NULL; 109687d3af4aSMark Brown } 109787d3af4aSMark Brown } 109887d3af4aSMark Brown 10993cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 11003cc72986SMark Brown arizona->core_supplies); 11013cc72986SMark Brown if (ret != 0) { 11023cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 11033cc72986SMark Brown ret); 1104e6021511SCharles Keepax goto err_dcvdd; 11053cc72986SMark Brown } 11063cc72986SMark Brown 110759db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 110859db9691SMark Brown if (ret != 0) { 110959db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 111059db9691SMark Brown goto err_enable; 111159db9691SMark Brown } 111259db9691SMark Brown 11132229875dSCharles Keepax arizona_disable_reset(arizona); 11143cc72986SMark Brown 11153cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 11163cc72986SMark Brown 1117ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 1118ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 1119ca76ceb8SMark Brown if (ret != 0) { 1120ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 1121ca76ceb8SMark Brown goto err_reset; 1122ca76ceb8SMark Brown } 1123ca76ceb8SMark Brown 1124ca76ceb8SMark Brown switch (reg) { 1125ca76ceb8SMark Brown case 0x5102: 1126ca76ceb8SMark Brown case 0x5110: 11276887b042SRichard Fitzgerald case 0x6349: 1128ea1f3339SRichard Fitzgerald case 0x6363: 1129dc7d4863SCharles Keepax case 0x8997: 1130ca76ceb8SMark Brown break; 1131ca76ceb8SMark Brown default: 1132ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 113375d8a2b0SCharles Keepax ret = -ENODEV; 1134ca76ceb8SMark Brown goto err_reset; 1135ca76ceb8SMark Brown } 1136ca76ceb8SMark Brown 1137ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 1138ca76ceb8SMark Brown if (!arizona->pdata.reset) { 1139ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 1140ca76ceb8SMark Brown if (ret != 0) { 1141ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 1142ca76ceb8SMark Brown goto err_reset; 1143ca76ceb8SMark Brown } 1144ca76ceb8SMark Brown 1145b79a980fSLee Jones usleep_range(1000, 5000); 1146ca76ceb8SMark Brown } 1147ca76ceb8SMark Brown 1148ca76ceb8SMark Brown /* Ensure device startup is complete */ 1149ca76ceb8SMark Brown switch (arizona->type) { 1150ca76ceb8SMark Brown case WM5102: 115148018943SMark Brown ret = regmap_read(arizona->regmap, 115248018943SMark Brown ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); 11531c1c6bbaSCharles Keepax if (ret) { 1154ca76ceb8SMark Brown dev_err(dev, 1155ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 1156ca76ceb8SMark Brown ret); 11571c1c6bbaSCharles Keepax } else if (val & 0x01) { 11581c1c6bbaSCharles Keepax ret = wm5102_clear_write_sequencer(arizona); 11591c1c6bbaSCharles Keepax if (ret) 11601c1c6bbaSCharles Keepax return ret; 1161ca76ceb8SMark Brown } 1162ca76ceb8SMark Brown break; 11631c1c6bbaSCharles Keepax default: 11641c1c6bbaSCharles Keepax break; 11651c1c6bbaSCharles Keepax } 11661c1c6bbaSCharles Keepax 11671c1c6bbaSCharles Keepax ret = arizona_wait_for_boot(arizona); 11681c1c6bbaSCharles Keepax if (ret) { 11691c1c6bbaSCharles Keepax dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); 11701c1c6bbaSCharles Keepax goto err_reset; 1171ca76ceb8SMark Brown } 1172ca76ceb8SMark Brown 1173ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 11743cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 11753cc72986SMark Brown if (ret != 0) { 11763cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 117759db9691SMark Brown goto err_reset; 11783cc72986SMark Brown } 11793cc72986SMark Brown 11803cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 11813cc72986SMark Brown &arizona->rev); 11823cc72986SMark Brown if (ret != 0) { 11833cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 118459db9691SMark Brown goto err_reset; 11853cc72986SMark Brown } 11863cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 11873cc72986SMark Brown 11883cc72986SMark Brown switch (reg) { 11893cc72986SMark Brown case 0x5102: 1190b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5102)) { 11913cc72986SMark Brown type_name = "WM5102"; 11923cc72986SMark Brown if (arizona->type != WM5102) { 1193b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1194b61c1ec0SRichard Fitzgerald "WM5102 registered as %d\n", 11953cc72986SMark Brown arizona->type); 11963cc72986SMark Brown arizona->type = WM5102; 11973cc72986SMark Brown } 1198b61c1ec0SRichard Fitzgerald 119962d62b59SMark Brown apply_patch = wm5102_patch; 1200c6d6bfb1SMark Brown arizona->rev &= 0x7; 1201ae05ea36SRichard Fitzgerald subdevs = wm5102_devs; 1202ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5102_devs); 1203b61c1ec0SRichard Fitzgerald } 12043cc72986SMark Brown break; 1205e102befeSMark Brown case 0x5110: 1206b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5110)) { 1207e5d4ef0dSRichard Fitzgerald switch (arizona->type) { 1208e5d4ef0dSRichard Fitzgerald case WM5110: 1209e102befeSMark Brown type_name = "WM5110"; 1210e5d4ef0dSRichard Fitzgerald break; 1211e5d4ef0dSRichard Fitzgerald case WM8280: 1212e5d4ef0dSRichard Fitzgerald type_name = "WM8280"; 1213e5d4ef0dSRichard Fitzgerald break; 1214e5d4ef0dSRichard Fitzgerald default: 1215e5d4ef0dSRichard Fitzgerald type_name = "WM5110"; 1216b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1217b61c1ec0SRichard Fitzgerald "WM5110 registered as %d\n", 1218e102befeSMark Brown arizona->type); 1219e102befeSMark Brown arizona->type = WM5110; 1220e5d4ef0dSRichard Fitzgerald break; 1221e102befeSMark Brown } 1222b61c1ec0SRichard Fitzgerald 122362d62b59SMark Brown apply_patch = wm5110_patch; 1224ae05ea36SRichard Fitzgerald subdevs = wm5110_devs; 1225ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5110_devs); 1226b61c1ec0SRichard Fitzgerald } 1227e102befeSMark Brown break; 1228ea1f3339SRichard Fitzgerald case 0x6363: 1229ea1f3339SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_CS47L24)) { 1230ea1f3339SRichard Fitzgerald switch (arizona->type) { 1231ea1f3339SRichard Fitzgerald case CS47L24: 1232ea1f3339SRichard Fitzgerald type_name = "CS47L24"; 1233ea1f3339SRichard Fitzgerald break; 1234ea1f3339SRichard Fitzgerald 1235ea1f3339SRichard Fitzgerald case WM1831: 1236ea1f3339SRichard Fitzgerald type_name = "WM1831"; 1237ea1f3339SRichard Fitzgerald break; 1238ea1f3339SRichard Fitzgerald 1239ea1f3339SRichard Fitzgerald default: 1240ea1f3339SRichard Fitzgerald dev_warn(arizona->dev, 1241ea1f3339SRichard Fitzgerald "CS47L24 registered as %d\n", 1242ea1f3339SRichard Fitzgerald arizona->type); 1243ea1f3339SRichard Fitzgerald arizona->type = CS47L24; 1244ea1f3339SRichard Fitzgerald break; 1245ea1f3339SRichard Fitzgerald } 1246ea1f3339SRichard Fitzgerald 1247ea1f3339SRichard Fitzgerald apply_patch = cs47l24_patch; 1248ea1f3339SRichard Fitzgerald subdevs = cs47l24_devs; 1249ea1f3339SRichard Fitzgerald n_subdevs = ARRAY_SIZE(cs47l24_devs); 1250ea1f3339SRichard Fitzgerald } 1251ea1f3339SRichard Fitzgerald break; 1252dc7d4863SCharles Keepax case 0x8997: 1253b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8997)) { 1254dc7d4863SCharles Keepax type_name = "WM8997"; 1255dc7d4863SCharles Keepax if (arizona->type != WM8997) { 1256b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1257b61c1ec0SRichard Fitzgerald "WM8997 registered as %d\n", 1258dc7d4863SCharles Keepax arizona->type); 1259dc7d4863SCharles Keepax arizona->type = WM8997; 1260dc7d4863SCharles Keepax } 1261b61c1ec0SRichard Fitzgerald 1262dc7d4863SCharles Keepax apply_patch = wm8997_patch; 1263ae05ea36SRichard Fitzgerald subdevs = wm8997_devs; 1264ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8997_devs); 1265b61c1ec0SRichard Fitzgerald } 1266dc7d4863SCharles Keepax break; 12676887b042SRichard Fitzgerald case 0x6349: 1268b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8998)) { 12696887b042SRichard Fitzgerald switch (arizona->type) { 12706887b042SRichard Fitzgerald case WM8998: 12716887b042SRichard Fitzgerald type_name = "WM8998"; 12726887b042SRichard Fitzgerald break; 12736887b042SRichard Fitzgerald 12746887b042SRichard Fitzgerald case WM1814: 12756887b042SRichard Fitzgerald type_name = "WM1814"; 12766887b042SRichard Fitzgerald break; 12776887b042SRichard Fitzgerald 12786887b042SRichard Fitzgerald default: 12796887b042SRichard Fitzgerald type_name = "WM8998"; 1280b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1281b61c1ec0SRichard Fitzgerald "WM8998 registered as %d\n", 12826887b042SRichard Fitzgerald arizona->type); 12836887b042SRichard Fitzgerald arizona->type = WM8998; 12846887b042SRichard Fitzgerald } 12856887b042SRichard Fitzgerald 12866887b042SRichard Fitzgerald apply_patch = wm8998_patch; 1287ae05ea36SRichard Fitzgerald subdevs = wm8998_devs; 1288ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8998_devs); 1289b61c1ec0SRichard Fitzgerald } 12906887b042SRichard Fitzgerald break; 12913cc72986SMark Brown default: 12923cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 129375d8a2b0SCharles Keepax ret = -ENODEV; 129459db9691SMark Brown goto err_reset; 12953cc72986SMark Brown } 12963cc72986SMark Brown 1297b61c1ec0SRichard Fitzgerald if (!subdevs) { 1298b61c1ec0SRichard Fitzgerald dev_err(arizona->dev, 1299b61c1ec0SRichard Fitzgerald "No kernel support for device ID %x\n", reg); 130075d8a2b0SCharles Keepax ret = -ENODEV; 1301b61c1ec0SRichard Fitzgerald goto err_reset; 1302b61c1ec0SRichard Fitzgerald } 1303b61c1ec0SRichard Fitzgerald 13043cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 13053cc72986SMark Brown 130662d62b59SMark Brown if (apply_patch) { 130762d62b59SMark Brown ret = apply_patch(arizona); 130862d62b59SMark Brown if (ret != 0) { 130962d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 131062d62b59SMark Brown ret); 131162d62b59SMark Brown goto err_reset; 131262d62b59SMark Brown } 1313e80436bbSCharles Keepax 1314e80436bbSCharles Keepax switch (arizona->type) { 1315e80436bbSCharles Keepax case WM5102: 13160be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 13170be068a0SCharles Keepax if (ret) { 1318e80436bbSCharles Keepax dev_err(arizona->dev, 1319e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 1320e80436bbSCharles Keepax ret); 1321e80436bbSCharles Keepax goto err_reset; 1322e80436bbSCharles Keepax } 1323e80436bbSCharles Keepax break; 1324882bc468SCharles Keepax case WM5110: 1325882bc468SCharles Keepax case WM8280: 1326882bc468SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 1327882bc468SCharles Keepax if (ret) { 1328882bc468SCharles Keepax dev_err(arizona->dev, 1329882bc468SCharles Keepax "Failed to apply sleep patch: %d\n", 1330882bc468SCharles Keepax ret); 1331882bc468SCharles Keepax goto err_reset; 1332882bc468SCharles Keepax } 1333882bc468SCharles Keepax break; 1334e80436bbSCharles Keepax default: 1335e80436bbSCharles Keepax break; 1336e80436bbSCharles Keepax } 133762d62b59SMark Brown } 133862d62b59SMark Brown 13393cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 13403cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 13413cc72986SMark Brown continue; 13423cc72986SMark Brown 13433cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 13443cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 13453cc72986SMark Brown } 13463cc72986SMark Brown 13473cc72986SMark Brown /* Chip default */ 13483cc72986SMark Brown if (!arizona->pdata.clk32k_src) 13493cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 13503cc72986SMark Brown 13513cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 13523cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 13533cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 13543cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 13553cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 13563cc72986SMark Brown arizona->pdata.clk32k_src - 1); 1357767c6dc0SMark Brown arizona_clk32k_enable(arizona); 13583cc72986SMark Brown break; 13593cc72986SMark Brown case ARIZONA_32KZ_NONE: 13603cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 13613cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 13623cc72986SMark Brown break; 13633cc72986SMark Brown default: 13643cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 13653cc72986SMark Brown arizona->pdata.clk32k_src); 13663cc72986SMark Brown ret = -EINVAL; 136759db9691SMark Brown goto err_reset; 13683cc72986SMark Brown } 13693cc72986SMark Brown 13703d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 1371544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 1372544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 13733d91f828SMark Brown continue; 13743d91f828SMark Brown 1375544c7aadSMark Brown /* Apply default for bypass mode */ 1376544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 1377544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 1378544c7aadSMark Brown 13793d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 1380544c7aadSMark Brown 13813d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 13823d91f828SMark Brown 13833d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 13843d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 13853d91f828SMark Brown 13863d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 13873d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 13883d91f828SMark Brown 1389f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 13903d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 13913d91f828SMark Brown 1392544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 1393544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 1394544c7aadSMark Brown 13953d91f828SMark Brown regmap_update_bits(arizona->regmap, 13963d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 13973d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 139871d134b9SCharles Keepax ARIZONA_MICB1_EXT_CAP | 13993d91f828SMark Brown ARIZONA_MICB1_DISCH | 1400544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 14013d91f828SMark Brown ARIZONA_MICB1_RATE, val); 14023d91f828SMark Brown } 14033d91f828SMark Brown 140472e43164SCharles Keepax pm_runtime_set_active(arizona->dev); 140572e43164SCharles Keepax pm_runtime_enable(arizona->dev); 140672e43164SCharles Keepax 14073cc72986SMark Brown /* Set up for interrupts */ 14083cc72986SMark Brown ret = arizona_irq_init(arizona); 14093cc72986SMark Brown if (ret != 0) 1410d347792cSCharles Keepax goto err_pm; 14113cc72986SMark Brown 141272e43164SCharles Keepax pm_runtime_set_autosuspend_delay(arizona->dev, 100); 141372e43164SCharles Keepax pm_runtime_use_autosuspend(arizona->dev); 141472e43164SCharles Keepax 14153cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 14163cc72986SMark Brown arizona_clkgen_err, arizona); 14173cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 14183cc72986SMark Brown arizona_overclocked, arizona); 14193cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 14203cc72986SMark Brown arizona_underclocked, arizona); 14213cc72986SMark Brown 1422ae05ea36SRichard Fitzgerald ret = mfd_add_devices(arizona->dev, PLATFORM_DEVID_NONE, 1423ae05ea36SRichard Fitzgerald subdevs, n_subdevs, NULL, 0, NULL); 14243cc72986SMark Brown 1425ae05ea36SRichard Fitzgerald if (ret) { 14263cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 14273cc72986SMark Brown goto err_irq; 14283cc72986SMark Brown } 14293cc72986SMark Brown 14303cc72986SMark Brown return 0; 14313cc72986SMark Brown 14323cc72986SMark Brown err_irq: 14333cc72986SMark Brown arizona_irq_exit(arizona); 1434d347792cSCharles Keepax err_pm: 1435d347792cSCharles Keepax pm_runtime_disable(arizona->dev); 14363cc72986SMark Brown err_reset: 14372229875dSCharles Keepax arizona_enable_reset(arizona); 143859db9691SMark Brown regulator_disable(arizona->dcvdd); 14393cc72986SMark Brown err_enable: 14403a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 14413cc72986SMark Brown arizona->core_supplies); 1442e6021511SCharles Keepax err_dcvdd: 1443e6021511SCharles Keepax regulator_put(arizona->dcvdd); 14443cc72986SMark Brown err_early: 14453cc72986SMark Brown mfd_remove_devices(dev); 14463cc72986SMark Brown return ret; 14473cc72986SMark Brown } 14483cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 14493cc72986SMark Brown 14504740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 14513cc72986SMark Brown { 1452fb36f77eSCharles Keepax disable_irq(arizona->irq); 1453b804020aSCharles Keepax pm_runtime_disable(arizona->dev); 1454b804020aSCharles Keepax 1455df6b3352SCharles Keepax regulator_disable(arizona->dcvdd); 1456e6021511SCharles Keepax regulator_put(arizona->dcvdd); 1457df6b3352SCharles Keepax 14583cc72986SMark Brown mfd_remove_devices(arizona->dev); 14593cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 14603cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 14613cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 14623cc72986SMark Brown arizona_irq_exit(arizona); 14632229875dSCharles Keepax arizona_enable_reset(arizona); 1464df6b3352SCharles Keepax 14654420286eSCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 14661d017b6bSMark Brown arizona->core_supplies); 14673cc72986SMark Brown return 0; 14683cc72986SMark Brown } 14693cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1470