13cc72986SMark Brown /* 23cc72986SMark Brown * Arizona core driver 33cc72986SMark Brown * 43cc72986SMark Brown * Copyright 2012 Wolfson Microelectronics plc 53cc72986SMark Brown * 63cc72986SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 73cc72986SMark Brown * 83cc72986SMark Brown * This program is free software; you can redistribute it and/or modify 93cc72986SMark Brown * it under the terms of the GNU General Public License version 2 as 103cc72986SMark Brown * published by the Free Software Foundation. 113cc72986SMark Brown */ 123cc72986SMark Brown 133cc72986SMark Brown #include <linux/delay.h> 1459db9691SMark Brown #include <linux/err.h> 153cc72986SMark Brown #include <linux/gpio.h> 163cc72986SMark Brown #include <linux/interrupt.h> 173cc72986SMark Brown #include <linux/mfd/core.h> 183cc72986SMark Brown #include <linux/module.h> 19d781009cSMark Brown #include <linux/of.h> 20d781009cSMark Brown #include <linux/of_device.h> 21d781009cSMark Brown #include <linux/of_gpio.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> 273cc72986SMark Brown 283cc72986SMark Brown #include <linux/mfd/arizona/core.h> 293cc72986SMark Brown #include <linux/mfd/arizona/registers.h> 303cc72986SMark Brown 313cc72986SMark Brown #include "arizona.h" 323cc72986SMark Brown 333cc72986SMark Brown static const char *wm5102_core_supplies[] = { 343cc72986SMark Brown "AVDD", 353cc72986SMark Brown "DBVDD1", 363cc72986SMark Brown }; 373cc72986SMark Brown 383cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona) 393cc72986SMark Brown { 403cc72986SMark Brown int ret = 0; 413cc72986SMark Brown 423cc72986SMark Brown mutex_lock(&arizona->clk_lock); 433cc72986SMark Brown 443cc72986SMark Brown arizona->clk32k_ref++; 453cc72986SMark Brown 46247fa192SMark Brown if (arizona->clk32k_ref == 1) { 47247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 48247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 49247fa192SMark Brown ret = pm_runtime_get_sync(arizona->dev); 50247fa192SMark Brown if (ret != 0) 51247fa192SMark Brown goto out; 52247fa192SMark Brown break; 53247fa192SMark Brown } 54247fa192SMark Brown 553cc72986SMark Brown ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 563cc72986SMark Brown ARIZONA_CLK_32K_ENA, 573cc72986SMark Brown ARIZONA_CLK_32K_ENA); 58247fa192SMark Brown } 593cc72986SMark Brown 60247fa192SMark Brown out: 613cc72986SMark Brown if (ret != 0) 623cc72986SMark Brown arizona->clk32k_ref--; 633cc72986SMark Brown 643cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 653cc72986SMark Brown 663cc72986SMark Brown return ret; 673cc72986SMark Brown } 683cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable); 693cc72986SMark Brown 703cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona) 713cc72986SMark Brown { 723cc72986SMark Brown int ret = 0; 733cc72986SMark Brown 743cc72986SMark Brown mutex_lock(&arizona->clk_lock); 753cc72986SMark Brown 763cc72986SMark Brown BUG_ON(arizona->clk32k_ref <= 0); 773cc72986SMark Brown 783cc72986SMark Brown arizona->clk32k_ref--; 793cc72986SMark Brown 80247fa192SMark Brown if (arizona->clk32k_ref == 0) { 813cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 823cc72986SMark Brown ARIZONA_CLK_32K_ENA, 0); 833cc72986SMark Brown 84247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 85247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 86247fa192SMark Brown pm_runtime_put_sync(arizona->dev); 87247fa192SMark Brown break; 88247fa192SMark Brown } 89247fa192SMark Brown } 90247fa192SMark Brown 913cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 923cc72986SMark Brown 933cc72986SMark Brown return ret; 943cc72986SMark Brown } 953cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable); 963cc72986SMark Brown 973cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data) 983cc72986SMark Brown { 993cc72986SMark Brown struct arizona *arizona = data; 1003cc72986SMark Brown 1013cc72986SMark Brown dev_err(arizona->dev, "CLKGEN error\n"); 1023cc72986SMark Brown 1033cc72986SMark Brown return IRQ_HANDLED; 1043cc72986SMark Brown } 1053cc72986SMark Brown 1063cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data) 1073cc72986SMark Brown { 1083cc72986SMark Brown struct arizona *arizona = data; 1093cc72986SMark Brown unsigned int val; 1103cc72986SMark Brown int ret; 1113cc72986SMark Brown 1123cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, 1133cc72986SMark Brown &val); 1143cc72986SMark Brown if (ret != 0) { 1153cc72986SMark Brown dev_err(arizona->dev, "Failed to read underclock status: %d\n", 1163cc72986SMark Brown ret); 1173cc72986SMark Brown return IRQ_NONE; 1183cc72986SMark Brown } 1193cc72986SMark Brown 1203cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1213cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1223cc72986SMark Brown if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) 1233ebef34dSCharles Keepax dev_err(arizona->dev, "AIF2 underclocked\n"); 1243ebef34dSCharles Keepax if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) 1253cc72986SMark Brown dev_err(arizona->dev, "AIF1 underclocked\n"); 1266e440d27SCharles Keepax if (val & ARIZONA_ISRC3_UNDERCLOCKED_STS) 1276e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 underclocked\n"); 1283cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1293cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1303cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1313cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1323cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1333cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1343cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1353cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1363cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1373cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1383cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1393cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1403cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 141648a9880SMark Brown dev_err(arizona->dev, "Mixer dropped sample\n"); 1423cc72986SMark Brown 1433cc72986SMark Brown return IRQ_HANDLED; 1443cc72986SMark Brown } 1453cc72986SMark Brown 1463cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1473cc72986SMark Brown { 1483cc72986SMark Brown struct arizona *arizona = data; 1493cc72986SMark Brown unsigned int val[2]; 1503cc72986SMark Brown int ret; 1513cc72986SMark Brown 1523cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1533cc72986SMark Brown &val[0], 2); 1543cc72986SMark Brown if (ret != 0) { 1553cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1563cc72986SMark Brown ret); 1573cc72986SMark Brown return IRQ_NONE; 1583cc72986SMark Brown } 1593cc72986SMark Brown 1603cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1613cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1623cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1633cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1643cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1653cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1663cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1673cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1683cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1693cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1703cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1713cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 1723cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 1733cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 1743cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 1753cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 1763cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 1773cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 1783cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 1793cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 1803cc72986SMark Brown 1813cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 1823cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 1833cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 1843cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 1853cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 1863cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 1873cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 1883cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 1893cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 1903cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 1913cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 1923cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 1933cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 1943cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 1953cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 1963cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 1976e440d27SCharles Keepax if (val[1] & ARIZONA_ISRC3_OVERCLOCKED_STS) 1986e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 overclocked\n"); 1993cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 2003cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 2013cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 2023cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 2033cc72986SMark Brown 2043cc72986SMark Brown return IRQ_HANDLED; 2053cc72986SMark Brown } 2063cc72986SMark Brown 2079d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 2089d53dfdcSCharles Keepax int timeout, unsigned int reg, 2099d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2109d53dfdcSCharles Keepax { 2119d53dfdcSCharles Keepax unsigned int val = 0; 2129d53dfdcSCharles Keepax int ret, i; 2139d53dfdcSCharles Keepax 2149d53dfdcSCharles Keepax for (i = 0; i < timeout; i++) { 2159d53dfdcSCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2169d53dfdcSCharles Keepax if (ret != 0) { 2179d53dfdcSCharles Keepax dev_err(arizona->dev, "Failed to read reg %u: %d\n", 2189d53dfdcSCharles Keepax reg, ret); 2199d53dfdcSCharles Keepax continue; 2209d53dfdcSCharles Keepax } 2219d53dfdcSCharles Keepax 2229d53dfdcSCharles Keepax if ((val & mask) == target) 2239d53dfdcSCharles Keepax return 0; 2249d53dfdcSCharles Keepax 2259d53dfdcSCharles Keepax msleep(1); 2269d53dfdcSCharles Keepax } 2279d53dfdcSCharles Keepax 2289d53dfdcSCharles Keepax dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); 2299d53dfdcSCharles Keepax return -ETIMEDOUT; 2309d53dfdcSCharles Keepax } 2319d53dfdcSCharles Keepax 2323cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2333cc72986SMark Brown { 2349d53dfdcSCharles Keepax int ret; 2353cc72986SMark Brown 2363cc72986SMark Brown /* 2373cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2383cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2393cc72986SMark Brown * runtime resume. 2403cc72986SMark Brown */ 2419d53dfdcSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, 2429d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2433cc72986SMark Brown 2449d53dfdcSCharles Keepax if (!ret) 2453cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2463cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2473cc72986SMark Brown 2483cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2493cc72986SMark Brown 2509d53dfdcSCharles Keepax return ret; 2513cc72986SMark Brown } 2523cc72986SMark Brown 253e80436bbSCharles Keepax static int arizona_apply_hardware_patch(struct arizona* arizona) 254e80436bbSCharles Keepax { 255e80436bbSCharles Keepax unsigned int fll, sysclk; 256e80436bbSCharles Keepax int ret, err; 257e80436bbSCharles Keepax 258e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 259e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); 260e80436bbSCharles Keepax if (ret != 0) { 261e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 262e80436bbSCharles Keepax ret); 263e80436bbSCharles Keepax return ret; 264e80436bbSCharles Keepax } 265e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); 266e80436bbSCharles Keepax if (ret != 0) { 267e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 268e80436bbSCharles Keepax ret); 269e80436bbSCharles Keepax return ret; 270e80436bbSCharles Keepax } 271e80436bbSCharles Keepax 272e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 273e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 274e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 275e80436bbSCharles Keepax if (ret != 0) { 276e80436bbSCharles Keepax dev_err(arizona->dev, 277e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 278e80436bbSCharles Keepax ret); 279e80436bbSCharles Keepax return ret; 280e80436bbSCharles Keepax } 281e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, 282e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 283e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 284e80436bbSCharles Keepax if (ret != 0) { 285e80436bbSCharles Keepax ret = -ETIMEDOUT; 286e80436bbSCharles Keepax goto err_fll; 287e80436bbSCharles Keepax } 288e80436bbSCharles Keepax 289e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 290e80436bbSCharles Keepax if (ret != 0) { 291e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 292e80436bbSCharles Keepax goto err_fll; 293e80436bbSCharles Keepax } 294e80436bbSCharles Keepax 295e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 296e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 297e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 298e80436bbSCharles Keepax if (ret != 0) { 299e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 300e80436bbSCharles Keepax ret); 301e80436bbSCharles Keepax goto err_sysclk; 302e80436bbSCharles Keepax } 303e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 304e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 305e80436bbSCharles Keepax if (ret != 0) { 306e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 307e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 308e80436bbSCharles Keepax ret = -ETIMEDOUT; 309e80436bbSCharles Keepax } 310e80436bbSCharles Keepax 311e80436bbSCharles Keepax err_sysclk: 312e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); 313e80436bbSCharles Keepax if (err != 0) { 314e80436bbSCharles Keepax dev_err(arizona->dev, 315e80436bbSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", 316e80436bbSCharles Keepax err); 317e80436bbSCharles Keepax } 318e80436bbSCharles Keepax 319e80436bbSCharles Keepax err_fll: 320e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); 321e80436bbSCharles Keepax if (err != 0) { 322e80436bbSCharles Keepax dev_err(arizona->dev, 323e80436bbSCharles Keepax "Failed to re-apply old FLL settings: %d\n", 324e80436bbSCharles Keepax err); 325e80436bbSCharles Keepax } 326e80436bbSCharles Keepax 327e80436bbSCharles Keepax if (ret != 0) 328e80436bbSCharles Keepax return ret; 329e80436bbSCharles Keepax else 330e80436bbSCharles Keepax return err; 331e80436bbSCharles Keepax } 332e80436bbSCharles Keepax 3333cc72986SMark Brown #ifdef CONFIG_PM_RUNTIME 3343cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 3353cc72986SMark Brown { 3363cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 3373cc72986SMark Brown int ret; 3383cc72986SMark Brown 339508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 340508c8299SMark Brown 34159db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 34259db9691SMark Brown if (ret != 0) { 34359db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 34459db9691SMark Brown return ret; 34559db9691SMark Brown } 3463cc72986SMark Brown 3473cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 3483cc72986SMark Brown 3494c9bb8bcSCharles Keepax switch (arizona->type) { 3504c9bb8bcSCharles Keepax case WM5102: 3515927467dSMark Brown if (arizona->external_dcvdd) { 3525927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 3535927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 3545927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 0); 3555927467dSMark Brown if (ret != 0) { 3565927467dSMark Brown dev_err(arizona->dev, 3575927467dSMark Brown "Failed to connect DCVDD: %d\n", ret); 3585927467dSMark Brown goto err; 3595927467dSMark Brown } 3605927467dSMark Brown } 3615927467dSMark Brown 3624c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 3634c9bb8bcSCharles Keepax if (ret != 0) { 3644c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 3654c9bb8bcSCharles Keepax ret); 3664c9bb8bcSCharles Keepax goto err; 3674c9bb8bcSCharles Keepax } 368e80436bbSCharles Keepax 369e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 370e80436bbSCharles Keepax if (ret != 0) { 371e80436bbSCharles Keepax dev_err(arizona->dev, 372e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 373e80436bbSCharles Keepax ret); 374e80436bbSCharles Keepax goto err; 375e80436bbSCharles Keepax } 376e80436bbSCharles Keepax break; 377e80436bbSCharles Keepax default: 37812bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 37912bb68edSCharles Keepax if (ret != 0) { 38012bb68edSCharles Keepax goto err; 38112bb68edSCharles Keepax } 38212bb68edSCharles Keepax 3835927467dSMark Brown if (arizona->external_dcvdd) { 3845927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 3855927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 3865927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 0); 3875927467dSMark Brown if (ret != 0) { 3885927467dSMark Brown dev_err(arizona->dev, 3895927467dSMark Brown "Failed to connect DCVDD: %d\n", ret); 3905927467dSMark Brown goto err; 3915927467dSMark Brown } 3925927467dSMark Brown } 393e80436bbSCharles Keepax break; 3944c9bb8bcSCharles Keepax } 3954c9bb8bcSCharles Keepax 396d9d03496SCharles Keepax switch (arizona->type) { 397d9d03496SCharles Keepax case WM5102: 398d9d03496SCharles Keepax ret = wm5102_patch(arizona); 399d9d03496SCharles Keepax if (ret != 0) { 400d9d03496SCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 401d9d03496SCharles Keepax ret); 402d9d03496SCharles Keepax goto err; 403d9d03496SCharles Keepax } 404d9d03496SCharles Keepax default: 405d9d03496SCharles Keepax break; 406d9d03496SCharles Keepax } 407d9d03496SCharles Keepax 4089270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 4099270bdf5SMark Brown if (ret != 0) { 4109270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 4114816bd1cSMark Brown goto err; 4129270bdf5SMark Brown } 4133cc72986SMark Brown 4143cc72986SMark Brown return 0; 4154816bd1cSMark Brown 4164816bd1cSMark Brown err: 4174816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 4184816bd1cSMark Brown regulator_disable(arizona->dcvdd); 4194816bd1cSMark Brown return ret; 4203cc72986SMark Brown } 4213cc72986SMark Brown 4223cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 4233cc72986SMark Brown { 4243cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 4255927467dSMark Brown int ret; 4263cc72986SMark Brown 427508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 428508c8299SMark Brown 4295927467dSMark Brown if (arizona->external_dcvdd) { 4305927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 4315927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 4325927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 4335927467dSMark Brown ARIZONA_ISOLATE_DCVDD1); 4345927467dSMark Brown if (ret != 0) { 4355927467dSMark Brown dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", 4365927467dSMark Brown ret); 4375927467dSMark Brown return ret; 4385927467dSMark Brown } 4395927467dSMark Brown } 4405927467dSMark Brown 4413cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 4423cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 443e293e847SCharles Keepax regulator_disable(arizona->dcvdd); 4443cc72986SMark Brown 4453cc72986SMark Brown return 0; 4463cc72986SMark Brown } 4473cc72986SMark Brown #endif 4483cc72986SMark Brown 449dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 45067c99296SMark Brown static int arizona_suspend(struct device *dev) 45167c99296SMark Brown { 45267c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 45367c99296SMark Brown 45467c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 45567c99296SMark Brown disable_irq(arizona->irq); 45667c99296SMark Brown 45767c99296SMark Brown return 0; 45867c99296SMark Brown } 45967c99296SMark Brown 46067c99296SMark Brown static int arizona_suspend_late(struct device *dev) 46167c99296SMark Brown { 46267c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 46367c99296SMark Brown 46467c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 46567c99296SMark Brown enable_irq(arizona->irq); 46667c99296SMark Brown 46767c99296SMark Brown return 0; 46867c99296SMark Brown } 46967c99296SMark Brown 470dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 471dc781d0eSMark Brown { 472dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 473dc781d0eSMark Brown 474dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 475dc781d0eSMark Brown disable_irq(arizona->irq); 476dc781d0eSMark Brown 477dc781d0eSMark Brown return 0; 478dc781d0eSMark Brown } 479dc781d0eSMark Brown 480dc781d0eSMark Brown static int arizona_resume(struct device *dev) 481dc781d0eSMark Brown { 482dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 483dc781d0eSMark Brown 484dc781d0eSMark Brown dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); 485dc781d0eSMark Brown enable_irq(arizona->irq); 486dc781d0eSMark Brown 487dc781d0eSMark Brown return 0; 488dc781d0eSMark Brown } 489dc781d0eSMark Brown #endif 490dc781d0eSMark Brown 4913cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 4923cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 4933cc72986SMark Brown arizona_runtime_resume, 4943cc72986SMark Brown NULL) 49567c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 496dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 49767c99296SMark Brown .suspend_late = arizona_suspend_late, 498dc781d0eSMark Brown .resume_noirq = arizona_resume_noirq, 499dc781d0eSMark Brown #endif 5003cc72986SMark Brown }; 5013cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 5023cc72986SMark Brown 503d781009cSMark Brown #ifdef CONFIG_OF 504942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev) 505d781009cSMark Brown { 506d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 507d781009cSMark Brown 508d781009cSMark Brown if (id) 509942786e6SLee Jones return (unsigned long)id->data; 510d781009cSMark Brown else 511d781009cSMark Brown return 0; 512d781009cSMark Brown } 513d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 514d781009cSMark Brown 515e4fcb1d6SCharles Keepax int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, 516e4fcb1d6SCharles Keepax bool mandatory) 517e4fcb1d6SCharles Keepax { 518e4fcb1d6SCharles Keepax int gpio; 519e4fcb1d6SCharles Keepax 520e4fcb1d6SCharles Keepax gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0); 521e4fcb1d6SCharles Keepax if (gpio < 0) { 522e4fcb1d6SCharles Keepax if (mandatory) 523e4fcb1d6SCharles Keepax dev_err(arizona->dev, 524e4fcb1d6SCharles Keepax "Mandatory DT gpio %s missing/malformed: %d\n", 525e4fcb1d6SCharles Keepax prop, gpio); 526e4fcb1d6SCharles Keepax 527e4fcb1d6SCharles Keepax gpio = 0; 528e4fcb1d6SCharles Keepax } 529e4fcb1d6SCharles Keepax 530e4fcb1d6SCharles Keepax return gpio; 531e4fcb1d6SCharles Keepax } 532e4fcb1d6SCharles Keepax EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); 533e4fcb1d6SCharles Keepax 534d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 535d781009cSMark Brown { 536e4fcb1d6SCharles Keepax struct arizona_pdata *pdata = &arizona->pdata; 537*cc47aed9SInha Song struct property *prop; 538*cc47aed9SInha Song const __be32 *cur; 539*cc47aed9SInha Song u32 val; 540d781009cSMark Brown int ret, i; 541*cc47aed9SInha Song int count = 0; 542d781009cSMark Brown 543e4fcb1d6SCharles Keepax pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); 544d781009cSMark Brown 545d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 546d781009cSMark Brown "wlf,gpio-defaults", 547d781009cSMark Brown arizona->pdata.gpio_defaults, 548d781009cSMark Brown ARRAY_SIZE(arizona->pdata.gpio_defaults)); 549d781009cSMark Brown if (ret >= 0) { 550d781009cSMark Brown /* 551d781009cSMark Brown * All values are literal except out of range values 552d781009cSMark Brown * which are chip default, translate into platform 553d781009cSMark Brown * data which uses 0 as chip default and out of range 554d781009cSMark Brown * as zero. 555d781009cSMark Brown */ 556d781009cSMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 557d781009cSMark Brown if (arizona->pdata.gpio_defaults[i] > 0xffff) 558d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0; 55991c73935SCharles Keepax else if (arizona->pdata.gpio_defaults[i] == 0) 560d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0x10000; 561d781009cSMark Brown } 562d781009cSMark Brown } else { 563d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 564d781009cSMark Brown ret); 565d781009cSMark Brown } 566d781009cSMark Brown 567*cc47aed9SInha Song of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop, 568*cc47aed9SInha Song cur, val) { 569*cc47aed9SInha Song if (count == ARRAY_SIZE(arizona->pdata.inmode)) 570*cc47aed9SInha Song break; 571*cc47aed9SInha Song 572*cc47aed9SInha Song arizona->pdata.inmode[count] = val; 573*cc47aed9SInha Song count++; 574*cc47aed9SInha Song } 575*cc47aed9SInha Song 576d781009cSMark Brown return 0; 577d781009cSMark Brown } 578d781009cSMark Brown 579d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 580d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 581d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 582dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 583d781009cSMark Brown {}, 584d781009cSMark Brown }; 585d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 586d781009cSMark Brown #else 587d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 588d781009cSMark Brown { 589d781009cSMark Brown return 0; 590d781009cSMark Brown } 591d781009cSMark Brown #endif 592d781009cSMark Brown 5935ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = { 5943cc72986SMark Brown { .name = "arizona-ldo1" }, 5953cc72986SMark Brown }; 5963cc72986SMark Brown 59732dadef2SCharles Keepax static const char *wm5102_supplies[] = { 5985fc6c396SCharles Keepax "MICVDD", 59932dadef2SCharles Keepax "DBVDD2", 60032dadef2SCharles Keepax "DBVDD3", 60132dadef2SCharles Keepax "CPVDD", 60232dadef2SCharles Keepax "SPKVDDL", 60332dadef2SCharles Keepax "SPKVDDR", 60432dadef2SCharles Keepax }; 60532dadef2SCharles Keepax 6065ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = { 607d7768111SMark Brown { .name = "arizona-micsupp" }, 6085fc6c396SCharles Keepax { 6095fc6c396SCharles Keepax .name = "arizona-extcon", 6105fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 6115fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 6125fc6c396SCharles Keepax }, 6133cc72986SMark Brown { .name = "arizona-gpio" }, 614503b1cacSMark Brown { .name = "arizona-haptics" }, 6153cc72986SMark Brown { .name = "arizona-pwm" }, 61632dadef2SCharles Keepax { 61732dadef2SCharles Keepax .name = "wm5102-codec", 61832dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 61932dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 62032dadef2SCharles Keepax }, 6213cc72986SMark Brown }; 6223cc72986SMark Brown 6235ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = { 624d7768111SMark Brown { .name = "arizona-micsupp" }, 6255fc6c396SCharles Keepax { 6265fc6c396SCharles Keepax .name = "arizona-extcon", 6275fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 6285fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 6295fc6c396SCharles Keepax }, 630e102befeSMark Brown { .name = "arizona-gpio" }, 631503b1cacSMark Brown { .name = "arizona-haptics" }, 632e102befeSMark Brown { .name = "arizona-pwm" }, 63332dadef2SCharles Keepax { 63432dadef2SCharles Keepax .name = "wm5110-codec", 63532dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 63632dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 63732dadef2SCharles Keepax }, 63832dadef2SCharles Keepax }; 63932dadef2SCharles Keepax 64032dadef2SCharles Keepax static const char *wm8997_supplies[] = { 641996c2d4fSCharles Keepax "MICVDD", 64232dadef2SCharles Keepax "DBVDD2", 64332dadef2SCharles Keepax "CPVDD", 64432dadef2SCharles Keepax "SPKVDD", 645e102befeSMark Brown }; 646e102befeSMark Brown 6475ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = { 648dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 6495fc6c396SCharles Keepax { 6505fc6c396SCharles Keepax .name = "arizona-extcon", 6515fc6c396SCharles Keepax .parent_supplies = wm8997_supplies, 6525fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 6535fc6c396SCharles Keepax }, 654dc7d4863SCharles Keepax { .name = "arizona-gpio" }, 655dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 656dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 65732dadef2SCharles Keepax { 65832dadef2SCharles Keepax .name = "wm8997-codec", 65932dadef2SCharles Keepax .parent_supplies = wm8997_supplies, 66032dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), 66132dadef2SCharles Keepax }, 662dc7d4863SCharles Keepax }; 663dc7d4863SCharles Keepax 664f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 6653cc72986SMark Brown { 6663cc72986SMark Brown struct device *dev = arizona->dev; 6673cc72986SMark Brown const char *type_name; 6683cc72986SMark Brown unsigned int reg, val; 66962d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 6703cc72986SMark Brown int ret, i; 6713cc72986SMark Brown 6723cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 6733cc72986SMark Brown mutex_init(&arizona->clk_lock); 6743cc72986SMark Brown 6753cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 6763cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 6773cc72986SMark Brown sizeof(arizona->pdata)); 67822d7dc8aSLee Jones else 67922d7dc8aSLee Jones arizona_of_get_core_pdata(arizona); 6803cc72986SMark Brown 6813cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 6823cc72986SMark Brown 6833cc72986SMark Brown switch (arizona->type) { 6843cc72986SMark Brown case WM5102: 685e102befeSMark Brown case WM5110: 686dc7d4863SCharles Keepax case WM8997: 6873cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 6883cc72986SMark Brown arizona->core_supplies[i].supply 6893cc72986SMark Brown = wm5102_core_supplies[i]; 6903cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 6913cc72986SMark Brown break; 6923cc72986SMark Brown default: 6933cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 6943cc72986SMark Brown arizona->type); 6953cc72986SMark Brown return -EINVAL; 6963cc72986SMark Brown } 6973cc72986SMark Brown 6984a8c475fSCharles Keepax /* Mark DCVDD as external, LDO1 driver will clear if internal */ 6994a8c475fSCharles Keepax arizona->external_dcvdd = true; 7004a8c475fSCharles Keepax 7013cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 7020848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 7033cc72986SMark Brown if (ret != 0) { 7043cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 7053cc72986SMark Brown return ret; 7063cc72986SMark Brown } 7073cc72986SMark Brown 7083cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 7093cc72986SMark Brown arizona->core_supplies); 7103cc72986SMark Brown if (ret != 0) { 7113cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 7123cc72986SMark Brown ret); 7133cc72986SMark Brown goto err_early; 7143cc72986SMark Brown } 7153cc72986SMark Brown 7160c2d0ffbSCharles Keepax /** 7170c2d0ffbSCharles Keepax * Don't use devres here because the only device we have to get 7180c2d0ffbSCharles Keepax * against is the MFD device and DCVDD will likely be supplied by 7190c2d0ffbSCharles Keepax * one of its children. Meaning that the regulator will be 7200c2d0ffbSCharles Keepax * destroyed by the time devres calls regulator put. 7210c2d0ffbSCharles Keepax */ 722e6021511SCharles Keepax arizona->dcvdd = regulator_get(arizona->dev, "DCVDD"); 72359db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 72459db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 72559db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 72659db9691SMark Brown goto err_early; 72759db9691SMark Brown } 72859db9691SMark Brown 72987d3af4aSMark Brown if (arizona->pdata.reset) { 73087d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 73187d3af4aSMark Brown ret = gpio_request_one(arizona->pdata.reset, 73287d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 73387d3af4aSMark Brown "arizona /RESET"); 73487d3af4aSMark Brown if (ret != 0) { 73587d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 736e6021511SCharles Keepax goto err_dcvdd; 73787d3af4aSMark Brown } 73887d3af4aSMark Brown } 73987d3af4aSMark Brown 7403cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 7413cc72986SMark Brown arizona->core_supplies); 7423cc72986SMark Brown if (ret != 0) { 7433cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 7443cc72986SMark Brown ret); 745e6021511SCharles Keepax goto err_dcvdd; 7463cc72986SMark Brown } 7473cc72986SMark Brown 74859db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 74959db9691SMark Brown if (ret != 0) { 75059db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 75159db9691SMark Brown goto err_enable; 75259db9691SMark Brown } 75359db9691SMark Brown 754c25feaa5SCharles Keepax if (arizona->pdata.reset) { 7553cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 756c25feaa5SCharles Keepax msleep(1); 757c25feaa5SCharles Keepax } 7583cc72986SMark Brown 7593cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 7603cc72986SMark Brown 761ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 762ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 763ca76ceb8SMark Brown if (ret != 0) { 764ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 765ca76ceb8SMark Brown goto err_reset; 766ca76ceb8SMark Brown } 767ca76ceb8SMark Brown 768ca76ceb8SMark Brown switch (reg) { 769ca76ceb8SMark Brown case 0x5102: 770ca76ceb8SMark Brown case 0x5110: 771dc7d4863SCharles Keepax case 0x8997: 772ca76ceb8SMark Brown break; 773ca76ceb8SMark Brown default: 774ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 775ca76ceb8SMark Brown goto err_reset; 776ca76ceb8SMark Brown } 777ca76ceb8SMark Brown 778ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 779ca76ceb8SMark Brown if (!arizona->pdata.reset) { 780ca76ceb8SMark Brown regcache_mark_dirty(arizona->regmap); 781ca76ceb8SMark Brown 782ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 783ca76ceb8SMark Brown if (ret != 0) { 784ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 785ca76ceb8SMark Brown goto err_reset; 786ca76ceb8SMark Brown } 787ca76ceb8SMark Brown 788ca76ceb8SMark Brown msleep(1); 789ca76ceb8SMark Brown 790ca76ceb8SMark Brown ret = regcache_sync(arizona->regmap); 791ca76ceb8SMark Brown if (ret != 0) { 792ca76ceb8SMark Brown dev_err(dev, "Failed to sync device: %d\n", ret); 793ca76ceb8SMark Brown goto err_reset; 794ca76ceb8SMark Brown } 795ca76ceb8SMark Brown } 796ca76ceb8SMark Brown 797ca76ceb8SMark Brown /* Ensure device startup is complete */ 798ca76ceb8SMark Brown switch (arizona->type) { 799ca76ceb8SMark Brown case WM5102: 80048018943SMark Brown ret = regmap_read(arizona->regmap, 80148018943SMark Brown ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); 802ca76ceb8SMark Brown if (ret != 0) 803ca76ceb8SMark Brown dev_err(dev, 804ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 805ca76ceb8SMark Brown ret); 806ca76ceb8SMark Brown else if (val & 0x01) 807ca76ceb8SMark Brown break; 808ca76ceb8SMark Brown /* Fall through */ 809ca76ceb8SMark Brown default: 810ca76ceb8SMark Brown ret = arizona_wait_for_boot(arizona); 811ca76ceb8SMark Brown if (ret != 0) { 812ca76ceb8SMark Brown dev_err(arizona->dev, 813ca76ceb8SMark Brown "Device failed initial boot: %d\n", ret); 814ca76ceb8SMark Brown goto err_reset; 815ca76ceb8SMark Brown } 816ca76ceb8SMark Brown break; 817ca76ceb8SMark Brown } 818ca76ceb8SMark Brown 819ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 8203cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 8213cc72986SMark Brown if (ret != 0) { 8223cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 82359db9691SMark Brown goto err_reset; 8243cc72986SMark Brown } 8253cc72986SMark Brown 8263cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 8273cc72986SMark Brown &arizona->rev); 8283cc72986SMark Brown if (ret != 0) { 8293cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 83059db9691SMark Brown goto err_reset; 8313cc72986SMark Brown } 8323cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 8333cc72986SMark Brown 8343cc72986SMark Brown switch (reg) { 835863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102 8363cc72986SMark Brown case 0x5102: 8373cc72986SMark Brown type_name = "WM5102"; 8383cc72986SMark Brown if (arizona->type != WM5102) { 8393cc72986SMark Brown dev_err(arizona->dev, "WM5102 registered as %d\n", 8403cc72986SMark Brown arizona->type); 8413cc72986SMark Brown arizona->type = WM5102; 8423cc72986SMark Brown } 84362d62b59SMark Brown apply_patch = wm5102_patch; 844c6d6bfb1SMark Brown arizona->rev &= 0x7; 8453cc72986SMark Brown break; 846863df8d5SMark Brown #endif 847e102befeSMark Brown #ifdef CONFIG_MFD_WM5110 848e102befeSMark Brown case 0x5110: 849e102befeSMark Brown type_name = "WM5110"; 850e102befeSMark Brown if (arizona->type != WM5110) { 851e102befeSMark Brown dev_err(arizona->dev, "WM5110 registered as %d\n", 852e102befeSMark Brown arizona->type); 853e102befeSMark Brown arizona->type = WM5110; 854e102befeSMark Brown } 85562d62b59SMark Brown apply_patch = wm5110_patch; 856e102befeSMark Brown break; 857e102befeSMark Brown #endif 858dc7d4863SCharles Keepax #ifdef CONFIG_MFD_WM8997 859dc7d4863SCharles Keepax case 0x8997: 860dc7d4863SCharles Keepax type_name = "WM8997"; 861dc7d4863SCharles Keepax if (arizona->type != WM8997) { 862dc7d4863SCharles Keepax dev_err(arizona->dev, "WM8997 registered as %d\n", 863dc7d4863SCharles Keepax arizona->type); 864dc7d4863SCharles Keepax arizona->type = WM8997; 865dc7d4863SCharles Keepax } 866dc7d4863SCharles Keepax apply_patch = wm8997_patch; 867dc7d4863SCharles Keepax break; 868dc7d4863SCharles Keepax #endif 8693cc72986SMark Brown default: 8703cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 87159db9691SMark Brown goto err_reset; 8723cc72986SMark Brown } 8733cc72986SMark Brown 8743cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 8753cc72986SMark Brown 87662d62b59SMark Brown if (apply_patch) { 87762d62b59SMark Brown ret = apply_patch(arizona); 87862d62b59SMark Brown if (ret != 0) { 87962d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 88062d62b59SMark Brown ret); 88162d62b59SMark Brown goto err_reset; 88262d62b59SMark Brown } 883e80436bbSCharles Keepax 884e80436bbSCharles Keepax switch (arizona->type) { 885e80436bbSCharles Keepax case WM5102: 886e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 887e80436bbSCharles Keepax if (ret != 0) { 888e80436bbSCharles Keepax dev_err(arizona->dev, 889e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 890e80436bbSCharles Keepax ret); 891e80436bbSCharles Keepax goto err_reset; 892e80436bbSCharles Keepax } 893e80436bbSCharles Keepax break; 894e80436bbSCharles Keepax default: 895e80436bbSCharles Keepax break; 896e80436bbSCharles Keepax } 89762d62b59SMark Brown } 89862d62b59SMark Brown 8993cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 9003cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 9013cc72986SMark Brown continue; 9023cc72986SMark Brown 9033cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 9043cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 9053cc72986SMark Brown } 9063cc72986SMark Brown 9073cc72986SMark Brown pm_runtime_set_autosuspend_delay(arizona->dev, 100); 9083cc72986SMark Brown pm_runtime_use_autosuspend(arizona->dev); 9093cc72986SMark Brown pm_runtime_enable(arizona->dev); 9103cc72986SMark Brown 9113cc72986SMark Brown /* Chip default */ 9123cc72986SMark Brown if (!arizona->pdata.clk32k_src) 9133cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 9143cc72986SMark Brown 9153cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 9163cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 9173cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 9183cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 9193cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 9203cc72986SMark Brown arizona->pdata.clk32k_src - 1); 921767c6dc0SMark Brown arizona_clk32k_enable(arizona); 9223cc72986SMark Brown break; 9233cc72986SMark Brown case ARIZONA_32KZ_NONE: 9243cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 9253cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 9263cc72986SMark Brown break; 9273cc72986SMark Brown default: 9283cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 9293cc72986SMark Brown arizona->pdata.clk32k_src); 9303cc72986SMark Brown ret = -EINVAL; 93159db9691SMark Brown goto err_reset; 9323cc72986SMark Brown } 9333cc72986SMark Brown 9343d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 935544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 936544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 9373d91f828SMark Brown continue; 9383d91f828SMark Brown 939544c7aadSMark Brown /* Apply default for bypass mode */ 940544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 941544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 942544c7aadSMark Brown 9433d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 944544c7aadSMark Brown 9453d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 9463d91f828SMark Brown 9473d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 9483d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 9493d91f828SMark Brown 9503d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 9513d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 9523d91f828SMark Brown 953f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 9543d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 9553d91f828SMark Brown 956544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 957544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 958544c7aadSMark Brown 9593d91f828SMark Brown regmap_update_bits(arizona->regmap, 9603d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 9613d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 9623d91f828SMark Brown ARIZONA_MICB1_DISCH | 963544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 9643d91f828SMark Brown ARIZONA_MICB1_RATE, val); 9653d91f828SMark Brown } 9663d91f828SMark Brown 9673cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 9683cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 9693cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 9703cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 9713cc72986SMark Brown val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; 9723cc72986SMark Brown 9733cc72986SMark Brown regmap_update_bits(arizona->regmap, 9743cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 9753cc72986SMark Brown ARIZONA_IN1_DMIC_SUP_MASK | 9763cc72986SMark Brown ARIZONA_IN1_MODE_MASK, val); 9773cc72986SMark Brown } 9783cc72986SMark Brown 9793cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 9803cc72986SMark Brown /* Default is 0 so noop with defaults */ 9813cc72986SMark Brown if (arizona->pdata.out_mono[i]) 9823cc72986SMark Brown val = ARIZONA_OUT1_MONO; 9833cc72986SMark Brown else 9843cc72986SMark Brown val = 0; 9853cc72986SMark Brown 9863cc72986SMark Brown regmap_update_bits(arizona->regmap, 9873cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 9883cc72986SMark Brown ARIZONA_OUT1_MONO, val); 9893cc72986SMark Brown } 9903cc72986SMark Brown 9913cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 9923cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 9933cc72986SMark Brown regmap_update_bits(arizona->regmap, 9942a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 9953cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 9963cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 9973cc72986SMark Brown arizona->pdata.spk_mute[i]); 9983cc72986SMark Brown 9993cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 10003cc72986SMark Brown regmap_update_bits(arizona->regmap, 10012a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 10023cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 10033cc72986SMark Brown arizona->pdata.spk_fmt[i]); 10043cc72986SMark Brown } 10053cc72986SMark Brown 10063cc72986SMark Brown /* Set up for interrupts */ 10073cc72986SMark Brown ret = arizona_irq_init(arizona); 10083cc72986SMark Brown if (ret != 0) 100959db9691SMark Brown goto err_reset; 10103cc72986SMark Brown 10113cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 10123cc72986SMark Brown arizona_clkgen_err, arizona); 10133cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 10143cc72986SMark Brown arizona_overclocked, arizona); 10153cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 10163cc72986SMark Brown arizona_underclocked, arizona); 10173cc72986SMark Brown 10183cc72986SMark Brown switch (arizona->type) { 10193cc72986SMark Brown case WM5102: 10203cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, 10210848c94fSMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); 10223cc72986SMark Brown break; 1023e102befeSMark Brown case WM5110: 1024e102befeSMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, 102578566afdSCharles Keepax ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); 1026e102befeSMark Brown break; 1027dc7d4863SCharles Keepax case WM8997: 1028dc7d4863SCharles Keepax ret = mfd_add_devices(arizona->dev, -1, wm8997_devs, 1029dc7d4863SCharles Keepax ARRAY_SIZE(wm8997_devs), NULL, 0, NULL); 1030dc7d4863SCharles Keepax break; 10313cc72986SMark Brown } 10323cc72986SMark Brown 10333cc72986SMark Brown if (ret != 0) { 10343cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 10353cc72986SMark Brown goto err_irq; 10363cc72986SMark Brown } 10373cc72986SMark Brown 103859db9691SMark Brown #ifdef CONFIG_PM_RUNTIME 103959db9691SMark Brown regulator_disable(arizona->dcvdd); 104059db9691SMark Brown #endif 104159db9691SMark Brown 10423cc72986SMark Brown return 0; 10433cc72986SMark Brown 10443cc72986SMark Brown err_irq: 10453cc72986SMark Brown arizona_irq_exit(arizona); 10463cc72986SMark Brown err_reset: 10473cc72986SMark Brown if (arizona->pdata.reset) { 104887d3af4aSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 10493cc72986SMark Brown gpio_free(arizona->pdata.reset); 10503cc72986SMark Brown } 105159db9691SMark Brown regulator_disable(arizona->dcvdd); 10523cc72986SMark Brown err_enable: 10533a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 10543cc72986SMark Brown arizona->core_supplies); 1055e6021511SCharles Keepax err_dcvdd: 1056e6021511SCharles Keepax regulator_put(arizona->dcvdd); 10573cc72986SMark Brown err_early: 10583cc72986SMark Brown mfd_remove_devices(dev); 10593cc72986SMark Brown return ret; 10603cc72986SMark Brown } 10613cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 10623cc72986SMark Brown 10634740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 10643cc72986SMark Brown { 1065b804020aSCharles Keepax pm_runtime_disable(arizona->dev); 1066b804020aSCharles Keepax 1067df6b3352SCharles Keepax regulator_disable(arizona->dcvdd); 1068e6021511SCharles Keepax regulator_put(arizona->dcvdd); 1069df6b3352SCharles Keepax 10703cc72986SMark Brown mfd_remove_devices(arizona->dev); 10713cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 10723cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 10733cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 10743cc72986SMark Brown arizona_irq_exit(arizona); 10751d017b6bSMark Brown if (arizona->pdata.reset) 10761d017b6bSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 1077df6b3352SCharles Keepax 10784420286eSCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 10791d017b6bSMark Brown arizona->core_supplies); 10803cc72986SMark Brown return 0; 10813cc72986SMark Brown } 10823cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1083