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> 193cc72986SMark Brown #include <linux/pm_runtime.h> 203cc72986SMark Brown #include <linux/regmap.h> 213cc72986SMark Brown #include <linux/regulator/consumer.h> 223cc72986SMark Brown #include <linux/slab.h> 233cc72986SMark Brown 243cc72986SMark Brown #include <linux/mfd/arizona/core.h> 253cc72986SMark Brown #include <linux/mfd/arizona/registers.h> 263cc72986SMark Brown 273cc72986SMark Brown #include "arizona.h" 283cc72986SMark Brown 293cc72986SMark Brown static const char *wm5102_core_supplies[] = { 303cc72986SMark Brown "AVDD", 313cc72986SMark Brown "DBVDD1", 323cc72986SMark Brown }; 333cc72986SMark Brown 343cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona) 353cc72986SMark Brown { 363cc72986SMark Brown int ret = 0; 373cc72986SMark Brown 383cc72986SMark Brown mutex_lock(&arizona->clk_lock); 393cc72986SMark Brown 403cc72986SMark Brown arizona->clk32k_ref++; 413cc72986SMark Brown 423cc72986SMark Brown if (arizona->clk32k_ref == 1) 433cc72986SMark Brown ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 443cc72986SMark Brown ARIZONA_CLK_32K_ENA, 453cc72986SMark Brown ARIZONA_CLK_32K_ENA); 463cc72986SMark Brown 473cc72986SMark Brown if (ret != 0) 483cc72986SMark Brown arizona->clk32k_ref--; 493cc72986SMark Brown 503cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 513cc72986SMark Brown 523cc72986SMark Brown return ret; 533cc72986SMark Brown } 543cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable); 553cc72986SMark Brown 563cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona) 573cc72986SMark Brown { 583cc72986SMark Brown int ret = 0; 593cc72986SMark Brown 603cc72986SMark Brown mutex_lock(&arizona->clk_lock); 613cc72986SMark Brown 623cc72986SMark Brown BUG_ON(arizona->clk32k_ref <= 0); 633cc72986SMark Brown 643cc72986SMark Brown arizona->clk32k_ref--; 653cc72986SMark Brown 663cc72986SMark Brown if (arizona->clk32k_ref == 0) 673cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 683cc72986SMark Brown ARIZONA_CLK_32K_ENA, 0); 693cc72986SMark Brown 703cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 713cc72986SMark Brown 723cc72986SMark Brown return ret; 733cc72986SMark Brown } 743cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable); 753cc72986SMark Brown 763cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data) 773cc72986SMark Brown { 783cc72986SMark Brown struct arizona *arizona = data; 793cc72986SMark Brown 803cc72986SMark Brown dev_err(arizona->dev, "CLKGEN error\n"); 813cc72986SMark Brown 823cc72986SMark Brown return IRQ_HANDLED; 833cc72986SMark Brown } 843cc72986SMark Brown 853cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data) 863cc72986SMark Brown { 873cc72986SMark Brown struct arizona *arizona = data; 883cc72986SMark Brown unsigned int val; 893cc72986SMark Brown int ret; 903cc72986SMark Brown 913cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, 923cc72986SMark Brown &val); 933cc72986SMark Brown if (ret != 0) { 943cc72986SMark Brown dev_err(arizona->dev, "Failed to read underclock status: %d\n", 953cc72986SMark Brown ret); 963cc72986SMark Brown return IRQ_NONE; 973cc72986SMark Brown } 983cc72986SMark Brown 993cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1003cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1013cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1023cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1033cc72986SMark Brown if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) 1043cc72986SMark Brown dev_err(arizona->dev, "AIF1 underclocked\n"); 1053cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1063cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1073cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1083cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1093cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1103cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1113cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1123cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1133cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1143cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1153cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1163cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1173cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 1183cc72986SMark Brown dev_err(arizona->dev, "Mixer underclocked\n"); 1193cc72986SMark Brown 1203cc72986SMark Brown return IRQ_HANDLED; 1213cc72986SMark Brown } 1223cc72986SMark Brown 1233cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1243cc72986SMark Brown { 1253cc72986SMark Brown struct arizona *arizona = data; 1263cc72986SMark Brown unsigned int val[2]; 1273cc72986SMark Brown int ret; 1283cc72986SMark Brown 1293cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1303cc72986SMark Brown &val[0], 2); 1313cc72986SMark Brown if (ret != 0) { 1323cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1333cc72986SMark Brown ret); 1343cc72986SMark Brown return IRQ_NONE; 1353cc72986SMark Brown } 1363cc72986SMark Brown 1373cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1383cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1393cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1403cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1413cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1423cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1433cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1443cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1453cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1463cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1473cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1483cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 1493cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 1503cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 1513cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 1523cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 1533cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 1543cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 1553cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 1563cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 1573cc72986SMark Brown 1583cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 1593cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 1603cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 1613cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 1623cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 1633cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 1643cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 1653cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 1663cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 1673cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 1683cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 1693cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 1703cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 1713cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 1723cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 1733cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 1743cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 1753cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 1763cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 1773cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 1783cc72986SMark Brown 1793cc72986SMark Brown return IRQ_HANDLED; 1803cc72986SMark Brown } 1813cc72986SMark Brown 1823cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 1833cc72986SMark Brown { 1843cc72986SMark Brown unsigned int reg; 1853cc72986SMark Brown int ret, i; 1863cc72986SMark Brown 1873cc72986SMark Brown /* 1883cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 1893cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 1903cc72986SMark Brown * runtime resume. 1913cc72986SMark Brown */ 1923cc72986SMark Brown for (i = 0; i < 5; i++) { 1933cc72986SMark Brown msleep(1); 1943cc72986SMark Brown 1953cc72986SMark Brown ret = regmap_read(arizona->regmap, 1963cc72986SMark Brown ARIZONA_INTERRUPT_RAW_STATUS_5, ®); 1973cc72986SMark Brown if (ret != 0) { 1983cc72986SMark Brown dev_err(arizona->dev, "Failed to read boot state: %d\n", 1993cc72986SMark Brown ret); 200*cfe775ceSMark Brown continue; 2013cc72986SMark Brown } 2023cc72986SMark Brown 2033cc72986SMark Brown if (reg & ARIZONA_BOOT_DONE_STS) 2043cc72986SMark Brown break; 2053cc72986SMark Brown } 2063cc72986SMark Brown 2073cc72986SMark Brown if (reg & ARIZONA_BOOT_DONE_STS) { 2083cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2093cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2103cc72986SMark Brown } else { 2113cc72986SMark Brown dev_err(arizona->dev, "Device boot timed out: %x\n", reg); 2123cc72986SMark Brown return -ETIMEDOUT; 2133cc72986SMark Brown } 2143cc72986SMark Brown 2153cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2163cc72986SMark Brown 2173cc72986SMark Brown return 0; 2183cc72986SMark Brown } 2193cc72986SMark Brown 2203cc72986SMark Brown #ifdef CONFIG_PM_RUNTIME 2213cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 2223cc72986SMark Brown { 2233cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 2243cc72986SMark Brown int ret; 2253cc72986SMark Brown 22659db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 22759db9691SMark Brown if (ret != 0) { 22859db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 22959db9691SMark Brown return ret; 23059db9691SMark Brown } 2313cc72986SMark Brown 2323cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 2333cc72986SMark Brown 2343cc72986SMark Brown ret = arizona_wait_for_boot(arizona); 2355879f571SMark Brown if (ret != 0) { 2365879f571SMark Brown regulator_disable(arizona->dcvdd); 2373cc72986SMark Brown return ret; 2385879f571SMark Brown } 2393cc72986SMark Brown 2403cc72986SMark Brown regcache_sync(arizona->regmap); 2413cc72986SMark Brown 2423cc72986SMark Brown return 0; 2433cc72986SMark Brown } 2443cc72986SMark Brown 2453cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 2463cc72986SMark Brown { 2473cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 2483cc72986SMark Brown 24959db9691SMark Brown regulator_disable(arizona->dcvdd); 2503cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 2513cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 2523cc72986SMark Brown 2533cc72986SMark Brown return 0; 2543cc72986SMark Brown } 2553cc72986SMark Brown #endif 2563cc72986SMark Brown 2573cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 2583cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 2593cc72986SMark Brown arizona_runtime_resume, 2603cc72986SMark Brown NULL) 2613cc72986SMark Brown }; 2623cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 2633cc72986SMark Brown 2643cc72986SMark Brown static struct mfd_cell early_devs[] = { 2653cc72986SMark Brown { .name = "arizona-ldo1" }, 2663cc72986SMark Brown }; 2673cc72986SMark Brown 2683cc72986SMark Brown static struct mfd_cell wm5102_devs[] = { 2693cc72986SMark Brown { .name = "arizona-extcon" }, 2703cc72986SMark Brown { .name = "arizona-gpio" }, 2713cc72986SMark Brown { .name = "arizona-micsupp" }, 2723cc72986SMark Brown { .name = "arizona-pwm" }, 2733cc72986SMark Brown { .name = "wm5102-codec" }, 2743cc72986SMark Brown }; 2753cc72986SMark Brown 2763cc72986SMark Brown int __devinit arizona_dev_init(struct arizona *arizona) 2773cc72986SMark Brown { 2783cc72986SMark Brown struct device *dev = arizona->dev; 2793cc72986SMark Brown const char *type_name; 2803cc72986SMark Brown unsigned int reg, val; 2813cc72986SMark Brown int ret, i; 2823cc72986SMark Brown 2833cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 2843cc72986SMark Brown mutex_init(&arizona->clk_lock); 2853cc72986SMark Brown 2863cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 2873cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 2883cc72986SMark Brown sizeof(arizona->pdata)); 2893cc72986SMark Brown 2903cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 2913cc72986SMark Brown 2923cc72986SMark Brown switch (arizona->type) { 2933cc72986SMark Brown case WM5102: 2943cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 2953cc72986SMark Brown arizona->core_supplies[i].supply 2963cc72986SMark Brown = wm5102_core_supplies[i]; 2973cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 2983cc72986SMark Brown break; 2993cc72986SMark Brown default: 3003cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 3013cc72986SMark Brown arizona->type); 3023cc72986SMark Brown return -EINVAL; 3033cc72986SMark Brown } 3043cc72986SMark Brown 3053cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 3063cc72986SMark Brown ARRAY_SIZE(early_devs), NULL, 0); 3073cc72986SMark Brown if (ret != 0) { 3083cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 3093cc72986SMark Brown return ret; 3103cc72986SMark Brown } 3113cc72986SMark Brown 3123cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 3133cc72986SMark Brown arizona->core_supplies); 3143cc72986SMark Brown if (ret != 0) { 3153cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 3163cc72986SMark Brown ret); 3173cc72986SMark Brown goto err_early; 3183cc72986SMark Brown } 3193cc72986SMark Brown 32059db9691SMark Brown arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD"); 32159db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 32259db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 32359db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 32459db9691SMark Brown goto err_early; 32559db9691SMark Brown } 32659db9691SMark Brown 3273cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 3283cc72986SMark Brown arizona->core_supplies); 3293cc72986SMark Brown if (ret != 0) { 3303cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 3313cc72986SMark Brown ret); 3323cc72986SMark Brown goto err_early; 3333cc72986SMark Brown } 3343cc72986SMark Brown 33559db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 33659db9691SMark Brown if (ret != 0) { 33759db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 33859db9691SMark Brown goto err_enable; 33959db9691SMark Brown } 34059db9691SMark Brown 3413cc72986SMark Brown if (arizona->pdata.reset) { 3423cc72986SMark Brown /* Start out with /RESET low to put the chip into reset */ 3433cc72986SMark Brown ret = gpio_request_one(arizona->pdata.reset, 3443cc72986SMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 3453cc72986SMark Brown "arizona /RESET"); 3463cc72986SMark Brown if (ret != 0) { 3473cc72986SMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 34859db9691SMark Brown goto err_dcvdd; 3493cc72986SMark Brown } 3503cc72986SMark Brown 3513cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 3523cc72986SMark Brown } 3533cc72986SMark Brown 3543cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 3553cc72986SMark Brown 3563cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 3573cc72986SMark Brown if (ret != 0) { 3583cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 35959db9691SMark Brown goto err_reset; 3603cc72986SMark Brown } 3613cc72986SMark Brown 3623cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 3633cc72986SMark Brown &arizona->rev); 3643cc72986SMark Brown if (ret != 0) { 3653cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 36659db9691SMark Brown goto err_reset; 3673cc72986SMark Brown } 3683cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 3693cc72986SMark Brown 3703cc72986SMark Brown switch (reg) { 3713cc72986SMark Brown case 0x5102: 3723cc72986SMark Brown type_name = "WM5102"; 3733cc72986SMark Brown if (arizona->type != WM5102) { 3743cc72986SMark Brown dev_err(arizona->dev, "WM5102 registered as %d\n", 3753cc72986SMark Brown arizona->type); 3763cc72986SMark Brown arizona->type = WM5102; 3773cc72986SMark Brown } 3783cc72986SMark Brown ret = wm5102_patch(arizona); 3793cc72986SMark Brown break; 3803cc72986SMark Brown 3813cc72986SMark Brown default: 3823cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 38359db9691SMark Brown goto err_reset; 3843cc72986SMark Brown } 3853cc72986SMark Brown 3863cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 3873cc72986SMark Brown 3883cc72986SMark Brown if (ret != 0) 3893cc72986SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", ret); 3903cc72986SMark Brown 3913cc72986SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 3923cc72986SMark Brown if (!arizona->pdata.reset) { 3933cc72986SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 3943cc72986SMark Brown if (ret != 0) { 3953cc72986SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 39659db9691SMark Brown goto err_reset; 3973cc72986SMark Brown } 3983cc72986SMark Brown } 3993cc72986SMark Brown 4003cc72986SMark Brown arizona_wait_for_boot(arizona); 4013cc72986SMark Brown 4023cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 4033cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 4043cc72986SMark Brown continue; 4053cc72986SMark Brown 4063cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 4073cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 4083cc72986SMark Brown } 4093cc72986SMark Brown 4103cc72986SMark Brown pm_runtime_set_autosuspend_delay(arizona->dev, 100); 4113cc72986SMark Brown pm_runtime_use_autosuspend(arizona->dev); 4123cc72986SMark Brown pm_runtime_enable(arizona->dev); 4133cc72986SMark Brown 4143cc72986SMark Brown /* Chip default */ 4153cc72986SMark Brown if (!arizona->pdata.clk32k_src) 4163cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 4173cc72986SMark Brown 4183cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 4193cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 4203cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 4213cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 4223cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 4233cc72986SMark Brown arizona->pdata.clk32k_src - 1); 4243cc72986SMark Brown break; 4253cc72986SMark Brown case ARIZONA_32KZ_NONE: 4263cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 4273cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 4283cc72986SMark Brown break; 4293cc72986SMark Brown default: 4303cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 4313cc72986SMark Brown arizona->pdata.clk32k_src); 4323cc72986SMark Brown ret = -EINVAL; 43359db9691SMark Brown goto err_reset; 4343cc72986SMark Brown } 4353cc72986SMark Brown 4363cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 4373cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 4383cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 4393cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 4403cc72986SMark Brown val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; 4413cc72986SMark Brown 4423cc72986SMark Brown regmap_update_bits(arizona->regmap, 4433cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 4443cc72986SMark Brown ARIZONA_IN1_DMIC_SUP_MASK | 4453cc72986SMark Brown ARIZONA_IN1_MODE_MASK, val); 4463cc72986SMark Brown } 4473cc72986SMark Brown 4483cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 4493cc72986SMark Brown /* Default is 0 so noop with defaults */ 4503cc72986SMark Brown if (arizona->pdata.out_mono[i]) 4513cc72986SMark Brown val = ARIZONA_OUT1_MONO; 4523cc72986SMark Brown else 4533cc72986SMark Brown val = 0; 4543cc72986SMark Brown 4553cc72986SMark Brown regmap_update_bits(arizona->regmap, 4563cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 4573cc72986SMark Brown ARIZONA_OUT1_MONO, val); 4583cc72986SMark Brown } 4593cc72986SMark Brown 4603cc72986SMark Brown BUILD_BUG_ON(ARIZONA_MAX_PDM_SPK > 1); 4613cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 4623cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 4633cc72986SMark Brown regmap_update_bits(arizona->regmap, 4643cc72986SMark Brown ARIZONA_PDM_SPK1_CTRL_1, 4653cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 4663cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 4673cc72986SMark Brown arizona->pdata.spk_mute[i]); 4683cc72986SMark Brown 4693cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 4703cc72986SMark Brown regmap_update_bits(arizona->regmap, 4713cc72986SMark Brown ARIZONA_PDM_SPK1_CTRL_2, 4723cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 4733cc72986SMark Brown arizona->pdata.spk_fmt[i]); 4743cc72986SMark Brown } 4753cc72986SMark Brown 4763cc72986SMark Brown /* Set up for interrupts */ 4773cc72986SMark Brown ret = arizona_irq_init(arizona); 4783cc72986SMark Brown if (ret != 0) 47959db9691SMark Brown goto err_reset; 4803cc72986SMark Brown 4813cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 4823cc72986SMark Brown arizona_clkgen_err, arizona); 4833cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 4843cc72986SMark Brown arizona_overclocked, arizona); 4853cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 4863cc72986SMark Brown arizona_underclocked, arizona); 4873cc72986SMark Brown 4883cc72986SMark Brown switch (arizona->type) { 4893cc72986SMark Brown case WM5102: 4903cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, 4913cc72986SMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0); 4923cc72986SMark Brown break; 4933cc72986SMark Brown } 4943cc72986SMark Brown 4953cc72986SMark Brown if (ret != 0) { 4963cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 4973cc72986SMark Brown goto err_irq; 4983cc72986SMark Brown } 4993cc72986SMark Brown 50059db9691SMark Brown #ifdef CONFIG_PM_RUNTIME 50159db9691SMark Brown regulator_disable(arizona->dcvdd); 50259db9691SMark Brown #endif 50359db9691SMark Brown 5043cc72986SMark Brown return 0; 5053cc72986SMark Brown 5063cc72986SMark Brown err_irq: 5073cc72986SMark Brown arizona_irq_exit(arizona); 5083cc72986SMark Brown err_reset: 5093cc72986SMark Brown if (arizona->pdata.reset) { 5103cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 5113cc72986SMark Brown gpio_free(arizona->pdata.reset); 5123cc72986SMark Brown } 51359db9691SMark Brown err_dcvdd: 51459db9691SMark Brown regulator_disable(arizona->dcvdd); 5153cc72986SMark Brown err_enable: 5163cc72986SMark Brown regulator_bulk_disable(ARRAY_SIZE(arizona->core_supplies), 5173cc72986SMark Brown arizona->core_supplies); 5183cc72986SMark Brown err_early: 5193cc72986SMark Brown mfd_remove_devices(dev); 5203cc72986SMark Brown return ret; 5213cc72986SMark Brown } 5223cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 5233cc72986SMark Brown 5243cc72986SMark Brown int __devexit arizona_dev_exit(struct arizona *arizona) 5253cc72986SMark Brown { 5263cc72986SMark Brown mfd_remove_devices(arizona->dev); 5273cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 5283cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 5293cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 5303cc72986SMark Brown pm_runtime_disable(arizona->dev); 5313cc72986SMark Brown arizona_irq_exit(arizona); 5323cc72986SMark Brown return 0; 5333cc72986SMark Brown } 5343cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 535