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"); 1263cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1273cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1283cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1293cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1303cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1313cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1323cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1333cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1343cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1353cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1363cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1373cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1383cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 139648a9880SMark Brown dev_err(arizona->dev, "Mixer dropped sample\n"); 1403cc72986SMark Brown 1413cc72986SMark Brown return IRQ_HANDLED; 1423cc72986SMark Brown } 1433cc72986SMark Brown 1443cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1453cc72986SMark Brown { 1463cc72986SMark Brown struct arizona *arizona = data; 1473cc72986SMark Brown unsigned int val[2]; 1483cc72986SMark Brown int ret; 1493cc72986SMark Brown 1503cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1513cc72986SMark Brown &val[0], 2); 1523cc72986SMark Brown if (ret != 0) { 1533cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1543cc72986SMark Brown ret); 1553cc72986SMark Brown return IRQ_NONE; 1563cc72986SMark Brown } 1573cc72986SMark Brown 1583cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1593cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1603cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1613cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1623cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1633cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1643cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1653cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1663cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1673cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1683cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1693cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 1703cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 1713cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 1723cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 1733cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 1743cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 1753cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 1763cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 1773cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 1783cc72986SMark Brown 1793cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 1803cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 1813cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 1823cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 1833cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 1843cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 1853cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 1863cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 1873cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 1883cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 1893cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 1903cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 1913cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 1923cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 1933cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 1943cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 1953cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 1963cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 1973cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 1983cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 1993cc72986SMark Brown 2003cc72986SMark Brown return IRQ_HANDLED; 2013cc72986SMark Brown } 2023cc72986SMark Brown 2039d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 2049d53dfdcSCharles Keepax int timeout, unsigned int reg, 2059d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2069d53dfdcSCharles Keepax { 2079d53dfdcSCharles Keepax unsigned int val = 0; 2089d53dfdcSCharles Keepax int ret, i; 2099d53dfdcSCharles Keepax 2109d53dfdcSCharles Keepax for (i = 0; i < timeout; i++) { 2119d53dfdcSCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2129d53dfdcSCharles Keepax if (ret != 0) { 2139d53dfdcSCharles Keepax dev_err(arizona->dev, "Failed to read reg %u: %d\n", 2149d53dfdcSCharles Keepax reg, ret); 2159d53dfdcSCharles Keepax continue; 2169d53dfdcSCharles Keepax } 2179d53dfdcSCharles Keepax 2189d53dfdcSCharles Keepax if ((val & mask) == target) 2199d53dfdcSCharles Keepax return 0; 2209d53dfdcSCharles Keepax 2219d53dfdcSCharles Keepax msleep(1); 2229d53dfdcSCharles Keepax } 2239d53dfdcSCharles Keepax 2249d53dfdcSCharles Keepax dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); 2259d53dfdcSCharles Keepax return -ETIMEDOUT; 2269d53dfdcSCharles Keepax } 2279d53dfdcSCharles Keepax 2283cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2293cc72986SMark Brown { 2309d53dfdcSCharles Keepax int ret; 2313cc72986SMark Brown 2323cc72986SMark Brown /* 2333cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2343cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2353cc72986SMark Brown * runtime resume. 2363cc72986SMark Brown */ 2379d53dfdcSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, 2389d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2393cc72986SMark Brown 2409d53dfdcSCharles Keepax if (!ret) 2413cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2423cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2433cc72986SMark Brown 2443cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2453cc72986SMark Brown 2469d53dfdcSCharles Keepax return ret; 2473cc72986SMark Brown } 2483cc72986SMark Brown 249e80436bbSCharles Keepax static int arizona_apply_hardware_patch(struct arizona* arizona) 250e80436bbSCharles Keepax { 251e80436bbSCharles Keepax unsigned int fll, sysclk; 252e80436bbSCharles Keepax int ret, err; 253e80436bbSCharles Keepax 254e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 255e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); 256e80436bbSCharles Keepax if (ret != 0) { 257e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 258e80436bbSCharles Keepax ret); 259e80436bbSCharles Keepax return ret; 260e80436bbSCharles Keepax } 261e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); 262e80436bbSCharles Keepax if (ret != 0) { 263e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 264e80436bbSCharles Keepax ret); 265e80436bbSCharles Keepax return ret; 266e80436bbSCharles Keepax } 267e80436bbSCharles Keepax 268e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 269e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 270e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 271e80436bbSCharles Keepax if (ret != 0) { 272e80436bbSCharles Keepax dev_err(arizona->dev, 273e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 274e80436bbSCharles Keepax ret); 275e80436bbSCharles Keepax return ret; 276e80436bbSCharles Keepax } 277e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, 278e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 279e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 280e80436bbSCharles Keepax if (ret != 0) { 281e80436bbSCharles Keepax ret = -ETIMEDOUT; 282e80436bbSCharles Keepax goto err_fll; 283e80436bbSCharles Keepax } 284e80436bbSCharles Keepax 285e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 286e80436bbSCharles Keepax if (ret != 0) { 287e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 288e80436bbSCharles Keepax goto err_fll; 289e80436bbSCharles Keepax } 290e80436bbSCharles Keepax 291e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 292e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 293e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 294e80436bbSCharles Keepax if (ret != 0) { 295e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 296e80436bbSCharles Keepax ret); 297e80436bbSCharles Keepax goto err_sysclk; 298e80436bbSCharles Keepax } 299e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 300e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 301e80436bbSCharles Keepax if (ret != 0) { 302e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 303e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 304e80436bbSCharles Keepax ret = -ETIMEDOUT; 305e80436bbSCharles Keepax } 306e80436bbSCharles Keepax 307e80436bbSCharles Keepax err_sysclk: 308e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); 309e80436bbSCharles Keepax if (err != 0) { 310e80436bbSCharles Keepax dev_err(arizona->dev, 311e80436bbSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", 312e80436bbSCharles Keepax err); 313e80436bbSCharles Keepax } 314e80436bbSCharles Keepax 315e80436bbSCharles Keepax err_fll: 316e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); 317e80436bbSCharles Keepax if (err != 0) { 318e80436bbSCharles Keepax dev_err(arizona->dev, 319e80436bbSCharles Keepax "Failed to re-apply old FLL settings: %d\n", 320e80436bbSCharles Keepax err); 321e80436bbSCharles Keepax } 322e80436bbSCharles Keepax 323e80436bbSCharles Keepax if (ret != 0) 324e80436bbSCharles Keepax return ret; 325e80436bbSCharles Keepax else 326e80436bbSCharles Keepax return err; 327e80436bbSCharles Keepax } 328e80436bbSCharles Keepax 3293cc72986SMark Brown #ifdef CONFIG_PM_RUNTIME 3303cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 3313cc72986SMark Brown { 3323cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 3333cc72986SMark Brown int ret; 3343cc72986SMark Brown 335508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 336508c8299SMark Brown 33759db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 33859db9691SMark Brown if (ret != 0) { 33959db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 34059db9691SMark Brown return ret; 34159db9691SMark Brown } 3423cc72986SMark Brown 3433cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 3443cc72986SMark Brown 3454c9bb8bcSCharles Keepax switch (arizona->type) { 3464c9bb8bcSCharles Keepax case WM5102: 3475927467dSMark Brown if (arizona->external_dcvdd) { 3485927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 3495927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 3505927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 0); 3515927467dSMark Brown if (ret != 0) { 3525927467dSMark Brown dev_err(arizona->dev, 3535927467dSMark Brown "Failed to connect DCVDD: %d\n", ret); 3545927467dSMark Brown goto err; 3555927467dSMark Brown } 3565927467dSMark Brown } 3575927467dSMark Brown 3584c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 3594c9bb8bcSCharles Keepax if (ret != 0) { 3604c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 3614c9bb8bcSCharles Keepax ret); 3624c9bb8bcSCharles Keepax goto err; 3634c9bb8bcSCharles Keepax } 364e80436bbSCharles Keepax 365e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 366e80436bbSCharles Keepax if (ret != 0) { 367e80436bbSCharles Keepax dev_err(arizona->dev, 368e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 369e80436bbSCharles Keepax ret); 370e80436bbSCharles Keepax goto err; 371e80436bbSCharles Keepax } 372e80436bbSCharles Keepax break; 373e80436bbSCharles Keepax default: 37412bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 37512bb68edSCharles Keepax if (ret != 0) { 37612bb68edSCharles Keepax goto err; 37712bb68edSCharles Keepax } 37812bb68edSCharles Keepax 3795927467dSMark Brown if (arizona->external_dcvdd) { 3805927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 3815927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 3825927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 0); 3835927467dSMark Brown if (ret != 0) { 3845927467dSMark Brown dev_err(arizona->dev, 3855927467dSMark Brown "Failed to connect DCVDD: %d\n", ret); 3865927467dSMark Brown goto err; 3875927467dSMark Brown } 3885927467dSMark Brown } 389e80436bbSCharles Keepax break; 3904c9bb8bcSCharles Keepax } 3914c9bb8bcSCharles Keepax 392d9d03496SCharles Keepax switch (arizona->type) { 393d9d03496SCharles Keepax case WM5102: 394d9d03496SCharles Keepax ret = wm5102_patch(arizona); 395d9d03496SCharles Keepax if (ret != 0) { 396d9d03496SCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 397d9d03496SCharles Keepax ret); 398d9d03496SCharles Keepax goto err; 399d9d03496SCharles Keepax } 400d9d03496SCharles Keepax default: 401d9d03496SCharles Keepax break; 402d9d03496SCharles Keepax } 403d9d03496SCharles Keepax 4049270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 4059270bdf5SMark Brown if (ret != 0) { 4069270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 4074816bd1cSMark Brown goto err; 4089270bdf5SMark Brown } 4093cc72986SMark Brown 4103cc72986SMark Brown return 0; 4114816bd1cSMark Brown 4124816bd1cSMark Brown err: 4134816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 4144816bd1cSMark Brown regulator_disable(arizona->dcvdd); 4154816bd1cSMark Brown return ret; 4163cc72986SMark Brown } 4173cc72986SMark Brown 4183cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 4193cc72986SMark Brown { 4203cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 4215927467dSMark Brown int ret; 4223cc72986SMark Brown 423508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 424508c8299SMark Brown 4255927467dSMark Brown if (arizona->external_dcvdd) { 4265927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 4275927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 4285927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 4295927467dSMark Brown ARIZONA_ISOLATE_DCVDD1); 4305927467dSMark Brown if (ret != 0) { 4315927467dSMark Brown dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", 4325927467dSMark Brown ret); 4335927467dSMark Brown return ret; 4345927467dSMark Brown } 4355927467dSMark Brown } 4365927467dSMark Brown 4373cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 4383cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 439e293e847SCharles Keepax regulator_disable(arizona->dcvdd); 4403cc72986SMark Brown 4413cc72986SMark Brown return 0; 4423cc72986SMark Brown } 4433cc72986SMark Brown #endif 4443cc72986SMark Brown 445dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 44667c99296SMark Brown static int arizona_suspend(struct device *dev) 44767c99296SMark Brown { 44867c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 44967c99296SMark Brown 45067c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 45167c99296SMark Brown disable_irq(arizona->irq); 45267c99296SMark Brown 45367c99296SMark Brown return 0; 45467c99296SMark Brown } 45567c99296SMark Brown 45667c99296SMark Brown static int arizona_suspend_late(struct device *dev) 45767c99296SMark Brown { 45867c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 45967c99296SMark Brown 46067c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 46167c99296SMark Brown enable_irq(arizona->irq); 46267c99296SMark Brown 46367c99296SMark Brown return 0; 46467c99296SMark Brown } 46567c99296SMark Brown 466dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 467dc781d0eSMark Brown { 468dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 469dc781d0eSMark Brown 470dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 471dc781d0eSMark Brown disable_irq(arizona->irq); 472dc781d0eSMark Brown 473dc781d0eSMark Brown return 0; 474dc781d0eSMark Brown } 475dc781d0eSMark Brown 476dc781d0eSMark Brown static int arizona_resume(struct device *dev) 477dc781d0eSMark Brown { 478dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 479dc781d0eSMark Brown 480dc781d0eSMark Brown dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); 481dc781d0eSMark Brown enable_irq(arizona->irq); 482dc781d0eSMark Brown 483dc781d0eSMark Brown return 0; 484dc781d0eSMark Brown } 485dc781d0eSMark Brown #endif 486dc781d0eSMark Brown 4873cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 4883cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 4893cc72986SMark Brown arizona_runtime_resume, 4903cc72986SMark Brown NULL) 49167c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 492dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 49367c99296SMark Brown .suspend_late = arizona_suspend_late, 494dc781d0eSMark Brown .resume_noirq = arizona_resume_noirq, 495dc781d0eSMark Brown #endif 4963cc72986SMark Brown }; 4973cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 4983cc72986SMark Brown 499d781009cSMark Brown #ifdef CONFIG_OF 500942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev) 501d781009cSMark Brown { 502d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 503d781009cSMark Brown 504d781009cSMark Brown if (id) 505942786e6SLee Jones return (unsigned long)id->data; 506d781009cSMark Brown else 507d781009cSMark Brown return 0; 508d781009cSMark Brown } 509d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 510d781009cSMark Brown 511e4fcb1d6SCharles Keepax int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, 512e4fcb1d6SCharles Keepax bool mandatory) 513e4fcb1d6SCharles Keepax { 514e4fcb1d6SCharles Keepax int gpio; 515e4fcb1d6SCharles Keepax 516e4fcb1d6SCharles Keepax gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0); 517e4fcb1d6SCharles Keepax if (gpio < 0) { 518e4fcb1d6SCharles Keepax if (mandatory) 519e4fcb1d6SCharles Keepax dev_err(arizona->dev, 520e4fcb1d6SCharles Keepax "Mandatory DT gpio %s missing/malformed: %d\n", 521e4fcb1d6SCharles Keepax prop, gpio); 522e4fcb1d6SCharles Keepax 523e4fcb1d6SCharles Keepax gpio = 0; 524e4fcb1d6SCharles Keepax } 525e4fcb1d6SCharles Keepax 526e4fcb1d6SCharles Keepax return gpio; 527e4fcb1d6SCharles Keepax } 528e4fcb1d6SCharles Keepax EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); 529e4fcb1d6SCharles Keepax 530d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 531d781009cSMark Brown { 532e4fcb1d6SCharles Keepax struct arizona_pdata *pdata = &arizona->pdata; 533d781009cSMark Brown int ret, i; 534d781009cSMark Brown 535e4fcb1d6SCharles Keepax pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); 536d781009cSMark Brown 537d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 538d781009cSMark Brown "wlf,gpio-defaults", 539d781009cSMark Brown arizona->pdata.gpio_defaults, 540d781009cSMark Brown ARRAY_SIZE(arizona->pdata.gpio_defaults)); 541d781009cSMark Brown if (ret >= 0) { 542d781009cSMark Brown /* 543d781009cSMark Brown * All values are literal except out of range values 544d781009cSMark Brown * which are chip default, translate into platform 545d781009cSMark Brown * data which uses 0 as chip default and out of range 546d781009cSMark Brown * as zero. 547d781009cSMark Brown */ 548d781009cSMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 549d781009cSMark Brown if (arizona->pdata.gpio_defaults[i] > 0xffff) 550d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0; 55191c73935SCharles Keepax else if (arizona->pdata.gpio_defaults[i] == 0) 552d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0x10000; 553d781009cSMark Brown } 554d781009cSMark Brown } else { 555d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 556d781009cSMark Brown ret); 557d781009cSMark Brown } 558d781009cSMark Brown 559d781009cSMark Brown return 0; 560d781009cSMark Brown } 561d781009cSMark Brown 562d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 563d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 564d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 565dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 566d781009cSMark Brown {}, 567d781009cSMark Brown }; 568d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 569d781009cSMark Brown #else 570d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 571d781009cSMark Brown { 572d781009cSMark Brown return 0; 573d781009cSMark Brown } 574d781009cSMark Brown #endif 575d781009cSMark Brown 5765ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = { 5773cc72986SMark Brown { .name = "arizona-ldo1" }, 5783cc72986SMark Brown }; 5793cc72986SMark Brown 58032dadef2SCharles Keepax static const char *wm5102_supplies[] = { 58132dadef2SCharles Keepax "DBVDD2", 58232dadef2SCharles Keepax "DBVDD3", 58332dadef2SCharles Keepax "CPVDD", 58432dadef2SCharles Keepax "SPKVDDL", 58532dadef2SCharles Keepax "SPKVDDR", 586058c8901SCharles Keepax "MICVDD", 58732dadef2SCharles Keepax }; 58832dadef2SCharles Keepax 5895ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = { 590d7768111SMark Brown { .name = "arizona-micsupp" }, 5913cc72986SMark Brown { .name = "arizona-extcon" }, 5923cc72986SMark Brown { .name = "arizona-gpio" }, 593503b1cacSMark Brown { .name = "arizona-haptics" }, 5943cc72986SMark Brown { .name = "arizona-pwm" }, 59532dadef2SCharles Keepax { 59632dadef2SCharles Keepax .name = "wm5102-codec", 59732dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 59832dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 59932dadef2SCharles Keepax }, 6003cc72986SMark Brown }; 6013cc72986SMark Brown 6025ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = { 603d7768111SMark Brown { .name = "arizona-micsupp" }, 604e102befeSMark Brown { .name = "arizona-extcon" }, 605e102befeSMark Brown { .name = "arizona-gpio" }, 606503b1cacSMark Brown { .name = "arizona-haptics" }, 607e102befeSMark Brown { .name = "arizona-pwm" }, 60832dadef2SCharles Keepax { 60932dadef2SCharles Keepax .name = "wm5110-codec", 61032dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 61132dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 61232dadef2SCharles Keepax }, 61332dadef2SCharles Keepax }; 61432dadef2SCharles Keepax 61532dadef2SCharles Keepax static const char *wm8997_supplies[] = { 616*996c2d4fSCharles Keepax "MICVDD", 61732dadef2SCharles Keepax "DBVDD2", 61832dadef2SCharles Keepax "CPVDD", 61932dadef2SCharles Keepax "SPKVDD", 620e102befeSMark Brown }; 621e102befeSMark Brown 6225ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = { 623dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 624dc7d4863SCharles Keepax { .name = "arizona-extcon" }, 625dc7d4863SCharles Keepax { .name = "arizona-gpio" }, 626dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 627dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 62832dadef2SCharles Keepax { 62932dadef2SCharles Keepax .name = "wm8997-codec", 63032dadef2SCharles Keepax .parent_supplies = wm8997_supplies, 63132dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), 63232dadef2SCharles Keepax }, 633dc7d4863SCharles Keepax }; 634dc7d4863SCharles Keepax 635f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 6363cc72986SMark Brown { 6373cc72986SMark Brown struct device *dev = arizona->dev; 6383cc72986SMark Brown const char *type_name; 6393cc72986SMark Brown unsigned int reg, val; 64062d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 6413cc72986SMark Brown int ret, i; 6423cc72986SMark Brown 6433cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 6443cc72986SMark Brown mutex_init(&arizona->clk_lock); 6453cc72986SMark Brown 6463cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 6473cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 6483cc72986SMark Brown sizeof(arizona->pdata)); 64922d7dc8aSLee Jones else 65022d7dc8aSLee Jones arizona_of_get_core_pdata(arizona); 6513cc72986SMark Brown 6523cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 6533cc72986SMark Brown 6543cc72986SMark Brown switch (arizona->type) { 6553cc72986SMark Brown case WM5102: 656e102befeSMark Brown case WM5110: 657dc7d4863SCharles Keepax case WM8997: 6583cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 6593cc72986SMark Brown arizona->core_supplies[i].supply 6603cc72986SMark Brown = wm5102_core_supplies[i]; 6613cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 6623cc72986SMark Brown break; 6633cc72986SMark Brown default: 6643cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 6653cc72986SMark Brown arizona->type); 6663cc72986SMark Brown return -EINVAL; 6673cc72986SMark Brown } 6683cc72986SMark Brown 6694a8c475fSCharles Keepax /* Mark DCVDD as external, LDO1 driver will clear if internal */ 6704a8c475fSCharles Keepax arizona->external_dcvdd = true; 6714a8c475fSCharles Keepax 6723cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 6730848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 6743cc72986SMark Brown if (ret != 0) { 6753cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 6763cc72986SMark Brown return ret; 6773cc72986SMark Brown } 6783cc72986SMark Brown 6793cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 6803cc72986SMark Brown arizona->core_supplies); 6813cc72986SMark Brown if (ret != 0) { 6823cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 6833cc72986SMark Brown ret); 6843cc72986SMark Brown goto err_early; 6853cc72986SMark Brown } 6863cc72986SMark Brown 6870c2d0ffbSCharles Keepax /** 6880c2d0ffbSCharles Keepax * Don't use devres here because the only device we have to get 6890c2d0ffbSCharles Keepax * against is the MFD device and DCVDD will likely be supplied by 6900c2d0ffbSCharles Keepax * one of its children. Meaning that the regulator will be 6910c2d0ffbSCharles Keepax * destroyed by the time devres calls regulator put. 6920c2d0ffbSCharles Keepax */ 693e6021511SCharles Keepax arizona->dcvdd = regulator_get(arizona->dev, "DCVDD"); 69459db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 69559db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 69659db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 69759db9691SMark Brown goto err_early; 69859db9691SMark Brown } 69959db9691SMark Brown 70087d3af4aSMark Brown if (arizona->pdata.reset) { 70187d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 70287d3af4aSMark Brown ret = gpio_request_one(arizona->pdata.reset, 70387d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 70487d3af4aSMark Brown "arizona /RESET"); 70587d3af4aSMark Brown if (ret != 0) { 70687d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 707e6021511SCharles Keepax goto err_dcvdd; 70887d3af4aSMark Brown } 70987d3af4aSMark Brown } 71087d3af4aSMark Brown 7113cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 7123cc72986SMark Brown arizona->core_supplies); 7133cc72986SMark Brown if (ret != 0) { 7143cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 7153cc72986SMark Brown ret); 716e6021511SCharles Keepax goto err_dcvdd; 7173cc72986SMark Brown } 7183cc72986SMark Brown 71959db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 72059db9691SMark Brown if (ret != 0) { 72159db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 72259db9691SMark Brown goto err_enable; 72359db9691SMark Brown } 72459db9691SMark Brown 725c25feaa5SCharles Keepax if (arizona->pdata.reset) { 7263cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 727c25feaa5SCharles Keepax msleep(1); 728c25feaa5SCharles Keepax } 7293cc72986SMark Brown 7303cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 7313cc72986SMark Brown 732ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 733ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 734ca76ceb8SMark Brown if (ret != 0) { 735ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 736ca76ceb8SMark Brown goto err_reset; 737ca76ceb8SMark Brown } 738ca76ceb8SMark Brown 739ca76ceb8SMark Brown switch (reg) { 740ca76ceb8SMark Brown case 0x5102: 741ca76ceb8SMark Brown case 0x5110: 742dc7d4863SCharles Keepax case 0x8997: 743ca76ceb8SMark Brown break; 744ca76ceb8SMark Brown default: 745ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 746ca76ceb8SMark Brown goto err_reset; 747ca76ceb8SMark Brown } 748ca76ceb8SMark Brown 749ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 750ca76ceb8SMark Brown if (!arizona->pdata.reset) { 751ca76ceb8SMark Brown regcache_mark_dirty(arizona->regmap); 752ca76ceb8SMark Brown 753ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 754ca76ceb8SMark Brown if (ret != 0) { 755ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 756ca76ceb8SMark Brown goto err_reset; 757ca76ceb8SMark Brown } 758ca76ceb8SMark Brown 759ca76ceb8SMark Brown msleep(1); 760ca76ceb8SMark Brown 761ca76ceb8SMark Brown ret = regcache_sync(arizona->regmap); 762ca76ceb8SMark Brown if (ret != 0) { 763ca76ceb8SMark Brown dev_err(dev, "Failed to sync device: %d\n", ret); 764ca76ceb8SMark Brown goto err_reset; 765ca76ceb8SMark Brown } 766ca76ceb8SMark Brown } 767ca76ceb8SMark Brown 768ca76ceb8SMark Brown /* Ensure device startup is complete */ 769ca76ceb8SMark Brown switch (arizona->type) { 770ca76ceb8SMark Brown case WM5102: 771ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, 0x19, &val); 772ca76ceb8SMark Brown if (ret != 0) 773ca76ceb8SMark Brown dev_err(dev, 774ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 775ca76ceb8SMark Brown ret); 776ca76ceb8SMark Brown else if (val & 0x01) 777ca76ceb8SMark Brown break; 778ca76ceb8SMark Brown /* Fall through */ 779ca76ceb8SMark Brown default: 780ca76ceb8SMark Brown ret = arizona_wait_for_boot(arizona); 781ca76ceb8SMark Brown if (ret != 0) { 782ca76ceb8SMark Brown dev_err(arizona->dev, 783ca76ceb8SMark Brown "Device failed initial boot: %d\n", ret); 784ca76ceb8SMark Brown goto err_reset; 785ca76ceb8SMark Brown } 786ca76ceb8SMark Brown break; 787ca76ceb8SMark Brown } 788ca76ceb8SMark Brown 789ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 7903cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 7913cc72986SMark Brown if (ret != 0) { 7923cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 79359db9691SMark Brown goto err_reset; 7943cc72986SMark Brown } 7953cc72986SMark Brown 7963cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 7973cc72986SMark Brown &arizona->rev); 7983cc72986SMark Brown if (ret != 0) { 7993cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 80059db9691SMark Brown goto err_reset; 8013cc72986SMark Brown } 8023cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 8033cc72986SMark Brown 8043cc72986SMark Brown switch (reg) { 805863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102 8063cc72986SMark Brown case 0x5102: 8073cc72986SMark Brown type_name = "WM5102"; 8083cc72986SMark Brown if (arizona->type != WM5102) { 8093cc72986SMark Brown dev_err(arizona->dev, "WM5102 registered as %d\n", 8103cc72986SMark Brown arizona->type); 8113cc72986SMark Brown arizona->type = WM5102; 8123cc72986SMark Brown } 81362d62b59SMark Brown apply_patch = wm5102_patch; 814c6d6bfb1SMark Brown arizona->rev &= 0x7; 8153cc72986SMark Brown break; 816863df8d5SMark Brown #endif 817e102befeSMark Brown #ifdef CONFIG_MFD_WM5110 818e102befeSMark Brown case 0x5110: 819e102befeSMark Brown type_name = "WM5110"; 820e102befeSMark Brown if (arizona->type != WM5110) { 821e102befeSMark Brown dev_err(arizona->dev, "WM5110 registered as %d\n", 822e102befeSMark Brown arizona->type); 823e102befeSMark Brown arizona->type = WM5110; 824e102befeSMark Brown } 82562d62b59SMark Brown apply_patch = wm5110_patch; 826e102befeSMark Brown break; 827e102befeSMark Brown #endif 828dc7d4863SCharles Keepax #ifdef CONFIG_MFD_WM8997 829dc7d4863SCharles Keepax case 0x8997: 830dc7d4863SCharles Keepax type_name = "WM8997"; 831dc7d4863SCharles Keepax if (arizona->type != WM8997) { 832dc7d4863SCharles Keepax dev_err(arizona->dev, "WM8997 registered as %d\n", 833dc7d4863SCharles Keepax arizona->type); 834dc7d4863SCharles Keepax arizona->type = WM8997; 835dc7d4863SCharles Keepax } 836dc7d4863SCharles Keepax apply_patch = wm8997_patch; 837dc7d4863SCharles Keepax break; 838dc7d4863SCharles Keepax #endif 8393cc72986SMark Brown default: 8403cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 84159db9691SMark Brown goto err_reset; 8423cc72986SMark Brown } 8433cc72986SMark Brown 8443cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 8453cc72986SMark Brown 84662d62b59SMark Brown if (apply_patch) { 84762d62b59SMark Brown ret = apply_patch(arizona); 84862d62b59SMark Brown if (ret != 0) { 84962d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 85062d62b59SMark Brown ret); 85162d62b59SMark Brown goto err_reset; 85262d62b59SMark Brown } 853e80436bbSCharles Keepax 854e80436bbSCharles Keepax switch (arizona->type) { 855e80436bbSCharles Keepax case WM5102: 856e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 857e80436bbSCharles Keepax if (ret != 0) { 858e80436bbSCharles Keepax dev_err(arizona->dev, 859e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 860e80436bbSCharles Keepax ret); 861e80436bbSCharles Keepax goto err_reset; 862e80436bbSCharles Keepax } 863e80436bbSCharles Keepax break; 864e80436bbSCharles Keepax default: 865e80436bbSCharles Keepax break; 866e80436bbSCharles Keepax } 86762d62b59SMark Brown } 86862d62b59SMark Brown 8693cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 8703cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 8713cc72986SMark Brown continue; 8723cc72986SMark Brown 8733cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 8743cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 8753cc72986SMark Brown } 8763cc72986SMark Brown 8773cc72986SMark Brown pm_runtime_set_autosuspend_delay(arizona->dev, 100); 8783cc72986SMark Brown pm_runtime_use_autosuspend(arizona->dev); 8793cc72986SMark Brown pm_runtime_enable(arizona->dev); 8803cc72986SMark Brown 8813cc72986SMark Brown /* Chip default */ 8823cc72986SMark Brown if (!arizona->pdata.clk32k_src) 8833cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 8843cc72986SMark Brown 8853cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 8863cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 8873cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 8883cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 8893cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 8903cc72986SMark Brown arizona->pdata.clk32k_src - 1); 891767c6dc0SMark Brown arizona_clk32k_enable(arizona); 8923cc72986SMark Brown break; 8933cc72986SMark Brown case ARIZONA_32KZ_NONE: 8943cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 8953cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 8963cc72986SMark Brown break; 8973cc72986SMark Brown default: 8983cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 8993cc72986SMark Brown arizona->pdata.clk32k_src); 9003cc72986SMark Brown ret = -EINVAL; 90159db9691SMark Brown goto err_reset; 9023cc72986SMark Brown } 9033cc72986SMark Brown 9043d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 905544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 906544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 9073d91f828SMark Brown continue; 9083d91f828SMark Brown 909544c7aadSMark Brown /* Apply default for bypass mode */ 910544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 911544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 912544c7aadSMark Brown 9133d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 914544c7aadSMark Brown 9153d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 9163d91f828SMark Brown 9173d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 9183d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 9193d91f828SMark Brown 9203d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 9213d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 9223d91f828SMark Brown 923f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 9243d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 9253d91f828SMark Brown 926544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 927544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 928544c7aadSMark Brown 9293d91f828SMark Brown regmap_update_bits(arizona->regmap, 9303d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 9313d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 9323d91f828SMark Brown ARIZONA_MICB1_DISCH | 933544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 9343d91f828SMark Brown ARIZONA_MICB1_RATE, val); 9353d91f828SMark Brown } 9363d91f828SMark Brown 9373cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 9383cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 9393cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 9403cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 9413cc72986SMark Brown val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; 9423cc72986SMark Brown 9433cc72986SMark Brown regmap_update_bits(arizona->regmap, 9443cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 9453cc72986SMark Brown ARIZONA_IN1_DMIC_SUP_MASK | 9463cc72986SMark Brown ARIZONA_IN1_MODE_MASK, val); 9473cc72986SMark Brown } 9483cc72986SMark Brown 9493cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 9503cc72986SMark Brown /* Default is 0 so noop with defaults */ 9513cc72986SMark Brown if (arizona->pdata.out_mono[i]) 9523cc72986SMark Brown val = ARIZONA_OUT1_MONO; 9533cc72986SMark Brown else 9543cc72986SMark Brown val = 0; 9553cc72986SMark Brown 9563cc72986SMark Brown regmap_update_bits(arizona->regmap, 9573cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 9583cc72986SMark Brown ARIZONA_OUT1_MONO, val); 9593cc72986SMark Brown } 9603cc72986SMark Brown 9613cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 9623cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 9633cc72986SMark Brown regmap_update_bits(arizona->regmap, 9642a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 9653cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 9663cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 9673cc72986SMark Brown arizona->pdata.spk_mute[i]); 9683cc72986SMark Brown 9693cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 9703cc72986SMark Brown regmap_update_bits(arizona->regmap, 9712a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 9723cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 9733cc72986SMark Brown arizona->pdata.spk_fmt[i]); 9743cc72986SMark Brown } 9753cc72986SMark Brown 9763cc72986SMark Brown /* Set up for interrupts */ 9773cc72986SMark Brown ret = arizona_irq_init(arizona); 9783cc72986SMark Brown if (ret != 0) 97959db9691SMark Brown goto err_reset; 9803cc72986SMark Brown 9813cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 9823cc72986SMark Brown arizona_clkgen_err, arizona); 9833cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 9843cc72986SMark Brown arizona_overclocked, arizona); 9853cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 9863cc72986SMark Brown arizona_underclocked, arizona); 9873cc72986SMark Brown 9883cc72986SMark Brown switch (arizona->type) { 9893cc72986SMark Brown case WM5102: 9903cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, 9910848c94fSMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); 9923cc72986SMark Brown break; 993e102befeSMark Brown case WM5110: 994e102befeSMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, 99578566afdSCharles Keepax ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); 996e102befeSMark Brown break; 997dc7d4863SCharles Keepax case WM8997: 998dc7d4863SCharles Keepax ret = mfd_add_devices(arizona->dev, -1, wm8997_devs, 999dc7d4863SCharles Keepax ARRAY_SIZE(wm8997_devs), NULL, 0, NULL); 1000dc7d4863SCharles Keepax break; 10013cc72986SMark Brown } 10023cc72986SMark Brown 10033cc72986SMark Brown if (ret != 0) { 10043cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 10053cc72986SMark Brown goto err_irq; 10063cc72986SMark Brown } 10073cc72986SMark Brown 100859db9691SMark Brown #ifdef CONFIG_PM_RUNTIME 100959db9691SMark Brown regulator_disable(arizona->dcvdd); 101059db9691SMark Brown #endif 101159db9691SMark Brown 10123cc72986SMark Brown return 0; 10133cc72986SMark Brown 10143cc72986SMark Brown err_irq: 10153cc72986SMark Brown arizona_irq_exit(arizona); 10163cc72986SMark Brown err_reset: 10173cc72986SMark Brown if (arizona->pdata.reset) { 101887d3af4aSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 10193cc72986SMark Brown gpio_free(arizona->pdata.reset); 10203cc72986SMark Brown } 102159db9691SMark Brown regulator_disable(arizona->dcvdd); 10223cc72986SMark Brown err_enable: 10233a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 10243cc72986SMark Brown arizona->core_supplies); 1025e6021511SCharles Keepax err_dcvdd: 1026e6021511SCharles Keepax regulator_put(arizona->dcvdd); 10273cc72986SMark Brown err_early: 10283cc72986SMark Brown mfd_remove_devices(dev); 10293cc72986SMark Brown return ret; 10303cc72986SMark Brown } 10313cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 10323cc72986SMark Brown 10334740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 10343cc72986SMark Brown { 1035b804020aSCharles Keepax pm_runtime_disable(arizona->dev); 1036b804020aSCharles Keepax 1037df6b3352SCharles Keepax regulator_disable(arizona->dcvdd); 1038e6021511SCharles Keepax regulator_put(arizona->dcvdd); 1039df6b3352SCharles Keepax 10403cc72986SMark Brown mfd_remove_devices(arizona->dev); 10413cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 10423cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 10433cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 10443cc72986SMark Brown arizona_irq_exit(arizona); 10451d017b6bSMark Brown if (arizona->pdata.reset) 10461d017b6bSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 1047df6b3352SCharles Keepax 10484420286eSCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 10491d017b6bSMark Brown arizona->core_supplies); 10503cc72986SMark Brown return 0; 10513cc72986SMark Brown } 10523cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1053