16387f866SBrian Austin /* 26387f866SBrian Austin * cs35l35.c -- CS35L35 ALSA SoC audio driver 36387f866SBrian Austin * 46387f866SBrian Austin * Copyright 2017 Cirrus Logic, Inc. 56387f866SBrian Austin * 66387f866SBrian Austin * Author: Brian Austin <brian.austin@cirrus.com> 76387f866SBrian Austin * 86387f866SBrian Austin * This program is free software; you can redistribute it and/or modify 96387f866SBrian Austin * it under the terms of the GNU General Public License version 2 as 106387f866SBrian Austin * published by the Free Software Foundation. 116387f866SBrian Austin * 126387f866SBrian Austin */ 136387f866SBrian Austin 146387f866SBrian Austin #include <linux/module.h> 156387f866SBrian Austin #include <linux/moduleparam.h> 166387f866SBrian Austin #include <linux/version.h> 176387f866SBrian Austin #include <linux/kernel.h> 186387f866SBrian Austin #include <linux/init.h> 196387f866SBrian Austin #include <linux/delay.h> 206387f866SBrian Austin #include <linux/i2c.h> 216387f866SBrian Austin #include <linux/slab.h> 226387f866SBrian Austin #include <linux/platform_device.h> 236387f866SBrian Austin #include <linux/regulator/consumer.h> 246387f866SBrian Austin #include <linux/gpio/consumer.h> 256387f866SBrian Austin #include <linux/of_device.h> 266387f866SBrian Austin #include <linux/of_gpio.h> 276387f866SBrian Austin #include <linux/regmap.h> 286387f866SBrian Austin #include <sound/core.h> 296387f866SBrian Austin #include <sound/pcm.h> 306387f866SBrian Austin #include <sound/pcm_params.h> 316387f866SBrian Austin #include <sound/soc.h> 326387f866SBrian Austin #include <sound/soc-dapm.h> 336387f866SBrian Austin #include <linux/gpio.h> 346387f866SBrian Austin #include <sound/initval.h> 356387f866SBrian Austin #include <sound/tlv.h> 366387f866SBrian Austin #include <sound/cs35l35.h> 376387f866SBrian Austin #include <linux/of_irq.h> 386387f866SBrian Austin #include <linux/completion.h> 396387f866SBrian Austin 406387f866SBrian Austin #include "cs35l35.h" 416387f866SBrian Austin 426387f866SBrian Austin /* 436387f866SBrian Austin * Some fields take zero as a valid value so use a high bit flag that won't 446387f866SBrian Austin * get written to the device to mark those. 456387f866SBrian Austin */ 466387f866SBrian Austin #define CS35L35_VALID_PDATA 0x80000000 476387f866SBrian Austin 486387f866SBrian Austin static const struct reg_default cs35l35_reg[] = { 496387f866SBrian Austin {CS35L35_PWRCTL1, 0x01}, 506387f866SBrian Austin {CS35L35_PWRCTL2, 0x11}, 516387f866SBrian Austin {CS35L35_PWRCTL3, 0x00}, 526387f866SBrian Austin {CS35L35_CLK_CTL1, 0x04}, 53fbeea237SCharles Keepax {CS35L35_CLK_CTL2, 0x12}, 546387f866SBrian Austin {CS35L35_CLK_CTL3, 0xCF}, 556387f866SBrian Austin {CS35L35_SP_FMT_CTL1, 0x20}, 566387f866SBrian Austin {CS35L35_SP_FMT_CTL2, 0x00}, 576387f866SBrian Austin {CS35L35_SP_FMT_CTL3, 0x02}, 586387f866SBrian Austin {CS35L35_MAG_COMP_CTL, 0x00}, 596387f866SBrian Austin {CS35L35_AMP_INP_DRV_CTL, 0x01}, 606387f866SBrian Austin {CS35L35_AMP_DIG_VOL_CTL, 0x12}, 616387f866SBrian Austin {CS35L35_AMP_DIG_VOL, 0x00}, 626387f866SBrian Austin {CS35L35_ADV_DIG_VOL, 0x00}, 636387f866SBrian Austin {CS35L35_PROTECT_CTL, 0x06}, 646387f866SBrian Austin {CS35L35_AMP_GAIN_AUD_CTL, 0x13}, 656387f866SBrian Austin {CS35L35_AMP_GAIN_PDM_CTL, 0x00}, 666387f866SBrian Austin {CS35L35_AMP_GAIN_ADV_CTL, 0x00}, 676387f866SBrian Austin {CS35L35_GPI_CTL, 0x00}, 686387f866SBrian Austin {CS35L35_BST_CVTR_V_CTL, 0x00}, 696387f866SBrian Austin {CS35L35_BST_PEAK_I, 0x07}, 706387f866SBrian Austin {CS35L35_BST_RAMP_CTL, 0x85}, 716387f866SBrian Austin {CS35L35_BST_CONV_COEF_1, 0x24}, 726387f866SBrian Austin {CS35L35_BST_CONV_COEF_2, 0x24}, 73fbeea237SCharles Keepax {CS35L35_BST_CONV_SLOPE_COMP, 0x4E}, 746387f866SBrian Austin {CS35L35_BST_CONV_SW_FREQ, 0x04}, 756387f866SBrian Austin {CS35L35_CLASS_H_CTL, 0x0B}, 766387f866SBrian Austin {CS35L35_CLASS_H_HEADRM_CTL, 0x0B}, 776387f866SBrian Austin {CS35L35_CLASS_H_RELEASE_RATE, 0x08}, 786387f866SBrian Austin {CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41}, 796387f866SBrian Austin {CS35L35_CLASS_H_VP_CTL, 0xC5}, 806387f866SBrian Austin {CS35L35_VPBR_CTL, 0x0A}, 81fbeea237SCharles Keepax {CS35L35_VPBR_VOL_CTL, 0x90}, 826387f866SBrian Austin {CS35L35_VPBR_TIMING_CTL, 0x6A}, 83fbeea237SCharles Keepax {CS35L35_VPBR_MODE_VOL_CTL, 0x00}, 846387f866SBrian Austin {CS35L35_SPKR_MON_CTL, 0xC0}, 856387f866SBrian Austin {CS35L35_IMON_SCALE_CTL, 0x30}, 866387f866SBrian Austin {CS35L35_AUDIN_RXLOC_CTL, 0x00}, 876387f866SBrian Austin {CS35L35_ADVIN_RXLOC_CTL, 0x80}, 886387f866SBrian Austin {CS35L35_VMON_TXLOC_CTL, 0x00}, 896387f866SBrian Austin {CS35L35_IMON_TXLOC_CTL, 0x80}, 906387f866SBrian Austin {CS35L35_VPMON_TXLOC_CTL, 0x04}, 916387f866SBrian Austin {CS35L35_VBSTMON_TXLOC_CTL, 0x84}, 926387f866SBrian Austin {CS35L35_VPBR_STATUS_TXLOC_CTL, 0x04}, 936387f866SBrian Austin {CS35L35_ZERO_FILL_LOC_CTL, 0x00}, 946387f866SBrian Austin {CS35L35_AUDIN_DEPTH_CTL, 0x0F}, 956387f866SBrian Austin {CS35L35_SPKMON_DEPTH_CTL, 0x0F}, 966387f866SBrian Austin {CS35L35_SUPMON_DEPTH_CTL, 0x0F}, 976387f866SBrian Austin {CS35L35_ZEROFILL_DEPTH_CTL, 0x00}, 986387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH1, 0x02}, 996387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH2, 0x80}, 1006387f866SBrian Austin {CS35L35_PROT_RELEASE_CTL, 0x00}, 1016387f866SBrian Austin {CS35L35_DIAG_MODE_REG_LOCK, 0x00}, 1026387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_1, 0x40}, 1036387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_2, 0x00}, 1046387f866SBrian Austin {CS35L35_INT_MASK_1, 0xFF}, 1056387f866SBrian Austin {CS35L35_INT_MASK_2, 0xFF}, 1066387f866SBrian Austin {CS35L35_INT_MASK_3, 0xFF}, 1076387f866SBrian Austin {CS35L35_INT_MASK_4, 0xFF}, 1086387f866SBrian Austin 1096387f866SBrian Austin }; 1106387f866SBrian Austin 1116387f866SBrian Austin static bool cs35l35_volatile_register(struct device *dev, unsigned int reg) 1126387f866SBrian Austin { 1136387f866SBrian Austin switch (reg) { 1146387f866SBrian Austin case CS35L35_INT_STATUS_1: 1156387f866SBrian Austin case CS35L35_INT_STATUS_2: 1166387f866SBrian Austin case CS35L35_INT_STATUS_3: 1176387f866SBrian Austin case CS35L35_INT_STATUS_4: 1186387f866SBrian Austin case CS35L35_PLL_STATUS: 1196387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1206387f866SBrian Austin return true; 1216387f866SBrian Austin default: 1226387f866SBrian Austin return false; 1236387f866SBrian Austin } 1246387f866SBrian Austin } 1256387f866SBrian Austin 1266387f866SBrian Austin static bool cs35l35_readable_register(struct device *dev, unsigned int reg) 1276387f866SBrian Austin { 1286387f866SBrian Austin switch (reg) { 1296387f866SBrian Austin case CS35L35_DEVID_AB ... CS35L35_PWRCTL3: 1306387f866SBrian Austin case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3: 1316387f866SBrian Austin case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL: 1326387f866SBrian Austin case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I: 1336387f866SBrian Austin case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ: 1346387f866SBrian Austin case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL: 1356387f866SBrian Austin case CS35L35_CLASS_H_STATUS: 1366387f866SBrian Austin case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL: 1376387f866SBrian Austin case CS35L35_VPBR_ATTEN_STATUS: 1386387f866SBrian Austin case CS35L35_SPKR_MON_CTL: 1396387f866SBrian Austin case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL: 1406387f866SBrian Austin case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL: 1416387f866SBrian Austin case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2: 1426387f866SBrian Austin case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS: 1436387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1446387f866SBrian Austin return true; 1456387f866SBrian Austin default: 1466387f866SBrian Austin return false; 1476387f866SBrian Austin } 1486387f866SBrian Austin } 1496387f866SBrian Austin 1506387f866SBrian Austin static bool cs35l35_precious_register(struct device *dev, unsigned int reg) 1516387f866SBrian Austin { 1526387f866SBrian Austin switch (reg) { 1536387f866SBrian Austin case CS35L35_INT_STATUS_1: 1546387f866SBrian Austin case CS35L35_INT_STATUS_2: 1556387f866SBrian Austin case CS35L35_INT_STATUS_3: 1566387f866SBrian Austin case CS35L35_INT_STATUS_4: 1576387f866SBrian Austin case CS35L35_PLL_STATUS: 1586387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1596387f866SBrian Austin return true; 1606387f866SBrian Austin default: 1616387f866SBrian Austin return false; 1626387f866SBrian Austin } 1636387f866SBrian Austin } 1646387f866SBrian Austin 165*dc43f46aSCharles Keepax static void cs35l35_reset(struct cs35l35_private *cs35l35) 166*dc43f46aSCharles Keepax { 167*dc43f46aSCharles Keepax gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 168*dc43f46aSCharles Keepax usleep_range(2000, 2100); 169*dc43f46aSCharles Keepax gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); 170*dc43f46aSCharles Keepax usleep_range(1000, 1100); 171*dc43f46aSCharles Keepax } 172*dc43f46aSCharles Keepax 17377b329d1SCharles Keepax static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) 17477b329d1SCharles Keepax { 17577b329d1SCharles Keepax int ret; 17677b329d1SCharles Keepax 17777b329d1SCharles Keepax if (cs35l35->pdata.ext_bst) { 17877b329d1SCharles Keepax usleep_range(5000, 5500); 17977b329d1SCharles Keepax return 0; 18077b329d1SCharles Keepax } 18177b329d1SCharles Keepax 18277b329d1SCharles Keepax reinit_completion(&cs35l35->pdn_done); 18377b329d1SCharles Keepax 18477b329d1SCharles Keepax ret = wait_for_completion_timeout(&cs35l35->pdn_done, 18577b329d1SCharles Keepax msecs_to_jiffies(100)); 18677b329d1SCharles Keepax if (ret == 0) { 18777b329d1SCharles Keepax dev_err(cs35l35->dev, "PDN_DONE did not complete\n"); 18877b329d1SCharles Keepax return -ETIMEDOUT; 18977b329d1SCharles Keepax } 19077b329d1SCharles Keepax 19177b329d1SCharles Keepax return 0; 19277b329d1SCharles Keepax } 19377b329d1SCharles Keepax 1946387f866SBrian Austin static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, 1956387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 1966387f866SBrian Austin { 1976387f866SBrian Austin struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 1986387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 1996387f866SBrian Austin int ret = 0; 2006387f866SBrian Austin 2016387f866SBrian Austin switch (event) { 2026387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 2036387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 2046387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 2056387f866SBrian Austin 0 << CS35L35_MCLK_DIS_SHIFT); 2066387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2076387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 2086387f866SBrian Austin 0 << CS35L35_DISCHG_FILT_SHIFT); 2096387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2106387f866SBrian Austin CS35L35_PDN_ALL_MASK, 0); 2116387f866SBrian Austin break; 2126387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 2136387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2146387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 2156387f866SBrian Austin 1 << CS35L35_DISCHG_FILT_SHIFT); 2166387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2176387f866SBrian Austin CS35L35_PDN_ALL_MASK, 1); 2186387f866SBrian Austin 2192c84afb5SCharles Keepax /* Already muted, so disable volume ramp for faster shutdown */ 2202c84afb5SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 2212c84afb5SCharles Keepax CS35L35_AMP_DIGSFT_MASK, 0); 2222c84afb5SCharles Keepax 22377b329d1SCharles Keepax ret = cs35l35_wait_for_pdn(cs35l35); 2246387f866SBrian Austin 2256387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 2266387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 2276387f866SBrian Austin 1 << CS35L35_MCLK_DIS_SHIFT); 2282c84afb5SCharles Keepax 2292c84afb5SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 2302c84afb5SCharles Keepax CS35L35_AMP_DIGSFT_MASK, 2312c84afb5SCharles Keepax 1 << CS35L35_AMP_DIGSFT_SHIFT); 2326387f866SBrian Austin break; 2336387f866SBrian Austin default: 2346387f866SBrian Austin dev_err(codec->dev, "Invalid event = 0x%x\n", event); 2356387f866SBrian Austin ret = -EINVAL; 2366387f866SBrian Austin } 2376387f866SBrian Austin return ret; 2386387f866SBrian Austin } 2396387f866SBrian Austin 2406387f866SBrian Austin static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w, 2416387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 2426387f866SBrian Austin { 2436387f866SBrian Austin struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 2446387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 2456387f866SBrian Austin unsigned int reg[4]; 2466387f866SBrian Austin int i; 2476387f866SBrian Austin 2486387f866SBrian Austin switch (event) { 2496387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 2506387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 2516387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2526387f866SBrian Austin CS35L35_PDN_BST_MASK, 2536387f866SBrian Austin 0 << CS35L35_PDN_BST_FETON_SHIFT); 2546387f866SBrian Austin else 2556387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2566387f866SBrian Austin CS35L35_PDN_BST_MASK, 2576387f866SBrian Austin 0 << CS35L35_PDN_BST_FETOFF_SHIFT); 2586387f866SBrian Austin break; 2596387f866SBrian Austin case SND_SOC_DAPM_POST_PMU: 2606387f866SBrian Austin usleep_range(5000, 5100); 2616387f866SBrian Austin /* If in PDM mode we must use VP for Voltage control */ 2626387f866SBrian Austin if (cs35l35->pdm_mode) 2636387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 2646387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 2656387f866SBrian Austin CS35L35_BST_CTL_MASK, 2666387f866SBrian Austin 0 << CS35L35_BST_CTL_SHIFT); 2676387f866SBrian Austin 2686387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 2696387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 0); 2706387f866SBrian Austin 2716387f866SBrian Austin for (i = 0; i < 2; i++) 2726387f866SBrian Austin regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1, 2736387f866SBrian Austin ®, ARRAY_SIZE(reg)); 2746387f866SBrian Austin 2756387f866SBrian Austin break; 2766387f866SBrian Austin case SND_SOC_DAPM_PRE_PMD: 2776387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 2786387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 2796387f866SBrian Austin 1 << CS35L35_AMP_MUTE_SHIFT); 2806387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 2816387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2826387f866SBrian Austin CS35L35_PDN_BST_MASK, 2836387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 2846387f866SBrian Austin else 2856387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2866387f866SBrian Austin CS35L35_PDN_BST_MASK, 2876387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 2886387f866SBrian Austin break; 2896387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 2906387f866SBrian Austin usleep_range(5000, 5100); 2916387f866SBrian Austin /* 2926387f866SBrian Austin * If PDM mode we should switch back to pdata value 2936387f866SBrian Austin * for Voltage control when we go down 2946387f866SBrian Austin */ 2956387f866SBrian Austin if (cs35l35->pdm_mode) 2966387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 2976387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 2986387f866SBrian Austin CS35L35_BST_CTL_MASK, 2996387f866SBrian Austin cs35l35->pdata.bst_vctl 3006387f866SBrian Austin << CS35L35_BST_CTL_SHIFT); 3016387f866SBrian Austin 3026387f866SBrian Austin break; 3036387f866SBrian Austin default: 3046387f866SBrian Austin dev_err(codec->dev, "Invalid event = 0x%x\n", event); 3056387f866SBrian Austin } 3066387f866SBrian Austin return 0; 3076387f866SBrian Austin } 3086387f866SBrian Austin 3096387f866SBrian Austin static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); 3106387f866SBrian Austin static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); 3116387f866SBrian Austin 3126387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_aud_controls[] = { 3136387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL, 3146387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 3156387f866SBrian Austin SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0, 3166387f866SBrian Austin amp_gain_tlv), 3176387f866SBrian Austin SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0, 3186387f866SBrian Austin amp_gain_tlv), 3196387f866SBrian Austin }; 3206387f866SBrian Austin 3216387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_adv_controls[] = { 3226387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL, 3236387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 3246387f866SBrian Austin SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0, 3256387f866SBrian Austin amp_gain_tlv), 3266387f866SBrian Austin }; 3276387f866SBrian Austin 3286387f866SBrian Austin static const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = { 3296387f866SBrian Austin SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1, 3306387f866SBrian Austin cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU | 3316387f866SBrian Austin SND_SOC_DAPM_POST_PMD), 3326387f866SBrian Austin SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1), 3336387f866SBrian Austin 3346387f866SBrian Austin SND_SOC_DAPM_OUTPUT("SPK"), 3356387f866SBrian Austin 3366387f866SBrian Austin SND_SOC_DAPM_INPUT("VP"), 3376387f866SBrian Austin SND_SOC_DAPM_INPUT("VBST"), 3386387f866SBrian Austin SND_SOC_DAPM_INPUT("ISENSE"), 3396387f866SBrian Austin SND_SOC_DAPM_INPUT("VSENSE"), 3406387f866SBrian Austin 3416387f866SBrian Austin SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1), 3426387f866SBrian Austin SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1), 3436387f866SBrian Austin SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1), 3446387f866SBrian Austin SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1), 3456387f866SBrian Austin SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1), 3466387f866SBrian Austin 3476387f866SBrian Austin SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0, 3486387f866SBrian Austin cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU | 3496387f866SBrian Austin SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU | 3506387f866SBrian Austin SND_SOC_DAPM_PRE_PMD), 3516387f866SBrian Austin }; 3526387f866SBrian Austin 3536387f866SBrian Austin static const struct snd_soc_dapm_route cs35l35_audio_map[] = { 3546387f866SBrian Austin {"VPMON ADC", NULL, "VP"}, 3556387f866SBrian Austin {"VBSTMON ADC", NULL, "VBST"}, 3566387f866SBrian Austin {"IMON ADC", NULL, "ISENSE"}, 3576387f866SBrian Austin {"VMON ADC", NULL, "VSENSE"}, 3586387f866SBrian Austin {"SDOUT", NULL, "IMON ADC"}, 3596387f866SBrian Austin {"SDOUT", NULL, "VMON ADC"}, 3606387f866SBrian Austin {"SDOUT", NULL, "VBSTMON ADC"}, 3616387f866SBrian Austin {"SDOUT", NULL, "VPMON ADC"}, 3626387f866SBrian Austin {"AMP Capture", NULL, "SDOUT"}, 3636387f866SBrian Austin 3646387f866SBrian Austin {"SDIN", NULL, "AMP Playback"}, 3656387f866SBrian Austin {"CLASS H", NULL, "SDIN"}, 3666387f866SBrian Austin {"Main AMP", NULL, "CLASS H"}, 3676387f866SBrian Austin {"SPK", NULL, "Main AMP"}, 3686387f866SBrian Austin }; 3696387f866SBrian Austin 3706387f866SBrian Austin static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 3716387f866SBrian Austin { 3726387f866SBrian Austin struct snd_soc_codec *codec = codec_dai->codec; 3736387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 3746387f866SBrian Austin 3756387f866SBrian Austin switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 3766387f866SBrian Austin case SND_SOC_DAIFMT_CBM_CFM: 3776387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 3786387f866SBrian Austin CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT); 3796387f866SBrian Austin cs35l35->slave_mode = false; 3806387f866SBrian Austin break; 3816387f866SBrian Austin case SND_SOC_DAIFMT_CBS_CFS: 3826387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 3836387f866SBrian Austin CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT); 3846387f866SBrian Austin cs35l35->slave_mode = true; 3856387f866SBrian Austin break; 3866387f866SBrian Austin default: 3876387f866SBrian Austin return -EINVAL; 3886387f866SBrian Austin } 3896387f866SBrian Austin 3906387f866SBrian Austin switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 3916387f866SBrian Austin case SND_SOC_DAIFMT_I2S: 3926387f866SBrian Austin cs35l35->i2s_mode = true; 3936387f866SBrian Austin cs35l35->pdm_mode = false; 3946387f866SBrian Austin break; 3956387f866SBrian Austin case SND_SOC_DAIFMT_PDM: 3966387f866SBrian Austin cs35l35->pdm_mode = true; 3976387f866SBrian Austin cs35l35->i2s_mode = false; 3986387f866SBrian Austin break; 3996387f866SBrian Austin default: 4006387f866SBrian Austin return -EINVAL; 4016387f866SBrian Austin } 4026387f866SBrian Austin 4036387f866SBrian Austin return 0; 4046387f866SBrian Austin } 4056387f866SBrian Austin 4066387f866SBrian Austin struct cs35l35_sysclk_config { 4076387f866SBrian Austin int sysclk; 4086387f866SBrian Austin int srate; 4096387f866SBrian Austin u8 clk_cfg; 4106387f866SBrian Austin }; 4116387f866SBrian Austin 4126387f866SBrian Austin static struct cs35l35_sysclk_config cs35l35_clk_ctl[] = { 4136387f866SBrian Austin 4146387f866SBrian Austin /* SYSCLK, Sample Rate, Serial Port Cfg */ 4156387f866SBrian Austin {5644800, 44100, 0x00}, 4166387f866SBrian Austin {5644800, 88200, 0x40}, 4176387f866SBrian Austin {6144000, 48000, 0x10}, 4186387f866SBrian Austin {6144000, 96000, 0x50}, 4196387f866SBrian Austin {11289600, 44100, 0x01}, 4206387f866SBrian Austin {11289600, 88200, 0x41}, 4216387f866SBrian Austin {11289600, 176400, 0x81}, 4226387f866SBrian Austin {12000000, 44100, 0x03}, 4236387f866SBrian Austin {12000000, 48000, 0x13}, 4246387f866SBrian Austin {12000000, 88200, 0x43}, 4256387f866SBrian Austin {12000000, 96000, 0x53}, 4266387f866SBrian Austin {12000000, 176400, 0x83}, 4276387f866SBrian Austin {12000000, 192000, 0x93}, 4286387f866SBrian Austin {12288000, 48000, 0x11}, 4296387f866SBrian Austin {12288000, 96000, 0x51}, 4306387f866SBrian Austin {12288000, 192000, 0x91}, 4316387f866SBrian Austin {13000000, 44100, 0x07}, 4326387f866SBrian Austin {13000000, 48000, 0x17}, 4336387f866SBrian Austin {13000000, 88200, 0x47}, 4346387f866SBrian Austin {13000000, 96000, 0x57}, 4356387f866SBrian Austin {13000000, 176400, 0x87}, 4366387f866SBrian Austin {13000000, 192000, 0x97}, 4376387f866SBrian Austin {22579200, 44100, 0x02}, 4386387f866SBrian Austin {22579200, 88200, 0x42}, 4396387f866SBrian Austin {22579200, 176400, 0x82}, 4406387f866SBrian Austin {24000000, 44100, 0x0B}, 4416387f866SBrian Austin {24000000, 48000, 0x1B}, 4426387f866SBrian Austin {24000000, 88200, 0x4B}, 4436387f866SBrian Austin {24000000, 96000, 0x5B}, 4446387f866SBrian Austin {24000000, 176400, 0x8B}, 4456387f866SBrian Austin {24000000, 192000, 0x9B}, 4466387f866SBrian Austin {24576000, 48000, 0x12}, 4476387f866SBrian Austin {24576000, 96000, 0x52}, 4486387f866SBrian Austin {24576000, 192000, 0x92}, 4496387f866SBrian Austin {26000000, 44100, 0x0F}, 4506387f866SBrian Austin {26000000, 48000, 0x1F}, 4516387f866SBrian Austin {26000000, 88200, 0x4F}, 4526387f866SBrian Austin {26000000, 96000, 0x5F}, 4536387f866SBrian Austin {26000000, 176400, 0x8F}, 4546387f866SBrian Austin {26000000, 192000, 0x9F}, 4556387f866SBrian Austin }; 4566387f866SBrian Austin 4576387f866SBrian Austin static int cs35l35_get_clk_config(int sysclk, int srate) 4586387f866SBrian Austin { 4596387f866SBrian Austin int i; 4606387f866SBrian Austin 4616387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) { 4626387f866SBrian Austin if (cs35l35_clk_ctl[i].sysclk == sysclk && 4636387f866SBrian Austin cs35l35_clk_ctl[i].srate == srate) 4646387f866SBrian Austin return cs35l35_clk_ctl[i].clk_cfg; 4656387f866SBrian Austin } 4666387f866SBrian Austin return -EINVAL; 4676387f866SBrian Austin } 4686387f866SBrian Austin 4696387f866SBrian Austin static int cs35l35_hw_params(struct snd_pcm_substream *substream, 4706387f866SBrian Austin struct snd_pcm_hw_params *params, 4716387f866SBrian Austin struct snd_soc_dai *dai) 4726387f866SBrian Austin { 4736387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 4746387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 4756387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 4766387f866SBrian Austin int srate = params_rate(params); 4776387f866SBrian Austin int ret = 0; 4786387f866SBrian Austin u8 sp_sclks; 4796387f866SBrian Austin int audin_format; 4806387f866SBrian Austin int errata_chk; 4816387f866SBrian Austin 4826387f866SBrian Austin int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate); 4836387f866SBrian Austin 4846387f866SBrian Austin if (clk_ctl < 0) { 4856387f866SBrian Austin dev_err(codec->dev, "Invalid CLK:Rate %d:%d\n", 4866387f866SBrian Austin cs35l35->sysclk, srate); 4876387f866SBrian Austin return -EINVAL; 4886387f866SBrian Austin } 4896387f866SBrian Austin 4906387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2, 4916387f866SBrian Austin CS35L35_CLK_CTL2_MASK, clk_ctl); 4926387f866SBrian Austin if (ret != 0) { 4936387f866SBrian Austin dev_err(codec->dev, "Failed to set port config %d\n", ret); 4946387f866SBrian Austin return ret; 4956387f866SBrian Austin } 4966387f866SBrian Austin 4976387f866SBrian Austin /* 4986387f866SBrian Austin * Rev A0 Errata 4996387f866SBrian Austin * When configured for the weak-drive detection path (CH_WKFET_DIS = 0) 5006387f866SBrian Austin * the Class H algorithm does not enable weak-drive operation for 5016387f866SBrian Austin * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10 5026387f866SBrian Austin */ 5036387f866SBrian Austin errata_chk = clk_ctl & CS35L35_SP_RATE_MASK; 5046387f866SBrian Austin 5056387f866SBrian Austin if (classh->classh_wk_fet_disable == 0x00 && 5066387f866SBrian Austin (errata_chk == 0x01 || errata_chk == 0x03)) { 5076387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 5086387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 5096387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 5106387f866SBrian Austin 0 << CS35L35_CH_WKFET_DEL_SHIFT); 5116387f866SBrian Austin if (ret != 0) { 5126387f866SBrian Austin dev_err(codec->dev, "Failed to set fet config %d\n", 5136387f866SBrian Austin ret); 5146387f866SBrian Austin return ret; 5156387f866SBrian Austin } 5166387f866SBrian Austin } 5176387f866SBrian Austin 5186387f866SBrian Austin /* 5196387f866SBrian Austin * You can pull more Monitor data from the SDOUT pin than going to SDIN 5206387f866SBrian Austin * Just make sure your SCLK is fast enough to fill the frame 5216387f866SBrian Austin */ 5226387f866SBrian Austin if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5236387f866SBrian Austin switch (params_width(params)) { 5246387f866SBrian Austin case 8: 5256387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_8; 5266387f866SBrian Austin break; 5276387f866SBrian Austin case 16: 5286387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_16; 5296387f866SBrian Austin break; 5306387f866SBrian Austin case 24: 5316387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_24; 5326387f866SBrian Austin break; 5336387f866SBrian Austin default: 5346387f866SBrian Austin dev_err(codec->dev, "Unsupported Width %d\n", 5356387f866SBrian Austin params_width(params)); 5366387f866SBrian Austin return -EINVAL; 5376387f866SBrian Austin } 5386387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 5396387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 5406387f866SBrian Austin CS35L35_AUDIN_DEPTH_MASK, 5416387f866SBrian Austin audin_format << 5426387f866SBrian Austin CS35L35_AUDIN_DEPTH_SHIFT); 5436387f866SBrian Austin if (cs35l35->pdata.stereo) { 5446387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 5456387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 5466387f866SBrian Austin CS35L35_ADVIN_DEPTH_MASK, 5476387f866SBrian Austin audin_format << 5486387f866SBrian Austin CS35L35_ADVIN_DEPTH_SHIFT); 5496387f866SBrian Austin } 5506387f866SBrian Austin } 5516387f866SBrian Austin 5526387f866SBrian Austin if (cs35l35->i2s_mode) { 5536387f866SBrian Austin /* We have to take the SCLK to derive num sclks 5546387f866SBrian Austin * to configure the CLOCK_CTL3 register correctly 5556387f866SBrian Austin */ 5566387f866SBrian Austin if ((cs35l35->sclk / srate) % 4) { 5576387f866SBrian Austin dev_err(codec->dev, "Unsupported sclk/fs ratio %d:%d\n", 5586387f866SBrian Austin cs35l35->sclk, srate); 5596387f866SBrian Austin return -EINVAL; 5606387f866SBrian Austin } 5616387f866SBrian Austin sp_sclks = ((cs35l35->sclk / srate) / 4) - 1; 5626387f866SBrian Austin 5636387f866SBrian Austin /* Only certain ratios are supported in I2S Slave Mode */ 5646387f866SBrian Austin if (cs35l35->slave_mode) { 5656387f866SBrian Austin switch (sp_sclks) { 5666387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 5676387f866SBrian Austin case CS35L35_SP_SCLKS_48FS: 5686387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 5696387f866SBrian Austin break; 5706387f866SBrian Austin default: 5716387f866SBrian Austin dev_err(codec->dev, "ratio not supported\n"); 5726387f866SBrian Austin return -EINVAL; 573f3a612a6Skbuild test robot } 5746387f866SBrian Austin } else { 5756387f866SBrian Austin /* Only certain ratios supported in I2S MASTER Mode */ 5766387f866SBrian Austin switch (sp_sclks) { 5776387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 5786387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 5796387f866SBrian Austin break; 5806387f866SBrian Austin default: 5816387f866SBrian Austin dev_err(codec->dev, "ratio not supported\n"); 5826387f866SBrian Austin return -EINVAL; 583f3a612a6Skbuild test robot } 5846387f866SBrian Austin } 5856387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 5866387f866SBrian Austin CS35L35_CLK_CTL3, 5876387f866SBrian Austin CS35L35_SP_SCLKS_MASK, sp_sclks << 5886387f866SBrian Austin CS35L35_SP_SCLKS_SHIFT); 5896387f866SBrian Austin if (ret != 0) { 5906387f866SBrian Austin dev_err(codec->dev, "Failed to set fsclk %d\n", ret); 5916387f866SBrian Austin return ret; 5926387f866SBrian Austin } 5936387f866SBrian Austin } 5946387f866SBrian Austin 5956387f866SBrian Austin return ret; 5966387f866SBrian Austin } 5976387f866SBrian Austin 5986387f866SBrian Austin static const unsigned int cs35l35_src_rates[] = { 5996387f866SBrian Austin 44100, 48000, 88200, 96000, 176400, 192000 6006387f866SBrian Austin }; 6016387f866SBrian Austin 6026387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_constraints = { 6036387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_src_rates), 6046387f866SBrian Austin .list = cs35l35_src_rates, 6056387f866SBrian Austin }; 6066387f866SBrian Austin 6076387f866SBrian Austin static int cs35l35_pcm_startup(struct snd_pcm_substream *substream, 6086387f866SBrian Austin struct snd_soc_dai *dai) 6096387f866SBrian Austin { 6106387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 6116387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 6126387f866SBrian Austin 6136387f866SBrian Austin if (!substream->runtime) 6146387f866SBrian Austin return 0; 6156387f866SBrian Austin 6166387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 6176387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints); 6186387f866SBrian Austin 6196387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 6206387f866SBrian Austin CS35L35_PDM_MODE_MASK, 6216387f866SBrian Austin 0 << CS35L35_PDM_MODE_SHIFT); 6226387f866SBrian Austin 6236387f866SBrian Austin return 0; 6246387f866SBrian Austin } 6256387f866SBrian Austin 6266387f866SBrian Austin static const unsigned int cs35l35_pdm_rates[] = { 6276387f866SBrian Austin 44100, 48000, 88200, 96000 6286387f866SBrian Austin }; 6296387f866SBrian Austin 6306387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = { 6316387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_pdm_rates), 6326387f866SBrian Austin .list = cs35l35_pdm_rates, 6336387f866SBrian Austin }; 6346387f866SBrian Austin 6356387f866SBrian Austin static int cs35l35_pdm_startup(struct snd_pcm_substream *substream, 6366387f866SBrian Austin struct snd_soc_dai *dai) 6376387f866SBrian Austin { 6386387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 6396387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 6406387f866SBrian Austin 6416387f866SBrian Austin if (!substream->runtime) 6426387f866SBrian Austin return 0; 6436387f866SBrian Austin 6446387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 6456387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, 6466387f866SBrian Austin &cs35l35_pdm_constraints); 6476387f866SBrian Austin 6486387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 6496387f866SBrian Austin CS35L35_PDM_MODE_MASK, 6506387f866SBrian Austin 1 << CS35L35_PDM_MODE_SHIFT); 6516387f866SBrian Austin 6526387f866SBrian Austin return 0; 6536387f866SBrian Austin } 6546387f866SBrian Austin 6556387f866SBrian Austin static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai, 6566387f866SBrian Austin int clk_id, unsigned int freq, int dir) 6576387f866SBrian Austin { 6586387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 6596387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 6606387f866SBrian Austin 6616387f866SBrian Austin /* Need the SCLK Frequency regardless of sysclk source for I2S */ 6626387f866SBrian Austin cs35l35->sclk = freq; 6636387f866SBrian Austin 6646387f866SBrian Austin return 0; 6656387f866SBrian Austin } 6666387f866SBrian Austin 6676387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_ops = { 6686387f866SBrian Austin .startup = cs35l35_pcm_startup, 6696387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 6706387f866SBrian Austin .hw_params = cs35l35_hw_params, 6716387f866SBrian Austin .set_sysclk = cs35l35_dai_set_sysclk, 6726387f866SBrian Austin }; 6736387f866SBrian Austin 6746387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_pdm_ops = { 6756387f866SBrian Austin .startup = cs35l35_pdm_startup, 6766387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 6776387f866SBrian Austin .hw_params = cs35l35_hw_params, 6786387f866SBrian Austin }; 6796387f866SBrian Austin 6806387f866SBrian Austin static struct snd_soc_dai_driver cs35l35_dai[] = { 6816387f866SBrian Austin { 6826387f866SBrian Austin .name = "cs35l35-pcm", 6836387f866SBrian Austin .id = 0, 6846387f866SBrian Austin .playback = { 6856387f866SBrian Austin .stream_name = "AMP Playback", 6866387f866SBrian Austin .channels_min = 1, 6876387f866SBrian Austin .channels_max = 8, 6886387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 6896387f866SBrian Austin .formats = CS35L35_FORMATS, 6906387f866SBrian Austin }, 6916387f866SBrian Austin .capture = { 6926387f866SBrian Austin .stream_name = "AMP Capture", 6936387f866SBrian Austin .channels_min = 1, 6946387f866SBrian Austin .channels_max = 8, 6956387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 6966387f866SBrian Austin .formats = CS35L35_FORMATS, 6976387f866SBrian Austin }, 6986387f866SBrian Austin .ops = &cs35l35_ops, 6996387f866SBrian Austin .symmetric_rates = 1, 7006387f866SBrian Austin }, 7016387f866SBrian Austin { 7026387f866SBrian Austin .name = "cs35l35-pdm", 7036387f866SBrian Austin .id = 1, 7046387f866SBrian Austin .playback = { 7056387f866SBrian Austin .stream_name = "PDM Playback", 7066387f866SBrian Austin .channels_min = 1, 7076387f866SBrian Austin .channels_max = 2, 7086387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 7096387f866SBrian Austin .formats = CS35L35_FORMATS, 7106387f866SBrian Austin }, 7116387f866SBrian Austin .ops = &cs35l35_pdm_ops, 7126387f866SBrian Austin }, 7136387f866SBrian Austin }; 7146387f866SBrian Austin 7156387f866SBrian Austin static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec, 7166387f866SBrian Austin int clk_id, int source, unsigned int freq, 7176387f866SBrian Austin int dir) 7186387f866SBrian Austin { 7196387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 7206387f866SBrian Austin int clksrc; 7216387f866SBrian Austin int ret = 0; 7226387f866SBrian Austin 7236387f866SBrian Austin switch (clk_id) { 7246387f866SBrian Austin case 0: 7256387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_MCLK; 7266387f866SBrian Austin break; 7276387f866SBrian Austin case 1: 7286387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_SCLK; 7296387f866SBrian Austin break; 7306387f866SBrian Austin case 2: 7316387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_PDM; 7326387f866SBrian Austin break; 7336387f866SBrian Austin default: 7346387f866SBrian Austin dev_err(codec->dev, "Invalid CLK Source\n"); 7356387f866SBrian Austin return -EINVAL; 736f3a612a6Skbuild test robot } 7376387f866SBrian Austin 7386387f866SBrian Austin switch (freq) { 7396387f866SBrian Austin case 5644800: 7406387f866SBrian Austin case 6144000: 7416387f866SBrian Austin case 11289600: 7426387f866SBrian Austin case 12000000: 7436387f866SBrian Austin case 12288000: 7446387f866SBrian Austin case 13000000: 7456387f866SBrian Austin case 22579200: 7466387f866SBrian Austin case 24000000: 7476387f866SBrian Austin case 24576000: 7486387f866SBrian Austin case 26000000: 7496387f866SBrian Austin cs35l35->sysclk = freq; 7506387f866SBrian Austin break; 7516387f866SBrian Austin default: 7526387f866SBrian Austin dev_err(codec->dev, "Invalid CLK Frequency Input : %d\n", freq); 7536387f866SBrian Austin return -EINVAL; 7546387f866SBrian Austin } 7556387f866SBrian Austin 7566387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 7576387f866SBrian Austin CS35L35_CLK_SOURCE_MASK, 7586387f866SBrian Austin clksrc << CS35L35_CLK_SOURCE_SHIFT); 7596387f866SBrian Austin if (ret != 0) { 7606387f866SBrian Austin dev_err(codec->dev, "Failed to set sysclk %d\n", ret); 7616387f866SBrian Austin return ret; 7626387f866SBrian Austin } 7636387f866SBrian Austin 7646387f866SBrian Austin return ret; 7656387f866SBrian Austin } 7666387f866SBrian Austin 7676387f866SBrian Austin static int cs35l35_codec_probe(struct snd_soc_codec *codec) 7686387f866SBrian Austin { 7696387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 7706387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 7716387f866SBrian Austin struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; 7726387f866SBrian Austin int ret; 7736387f866SBrian Austin 7746387f866SBrian Austin /* Set Platform Data */ 7756387f866SBrian Austin if (cs35l35->pdata.bst_vctl) 7766387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, 7776387f866SBrian Austin CS35L35_BST_CTL_MASK, 7786387f866SBrian Austin cs35l35->pdata.bst_vctl); 7796387f866SBrian Austin 7806387f866SBrian Austin if (cs35l35->pdata.bst_ipk) 7816387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I, 7826387f866SBrian Austin CS35L35_BST_IPK_MASK, 7836387f866SBrian Austin cs35l35->pdata.bst_ipk << 7846387f866SBrian Austin CS35L35_BST_IPK_SHIFT); 7856387f866SBrian Austin 7866387f866SBrian Austin if (cs35l35->pdata.gain_zc) 7876387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 7886387f866SBrian Austin CS35L35_AMP_GAIN_ZC_MASK, 7896387f866SBrian Austin cs35l35->pdata.gain_zc << 7906387f866SBrian Austin CS35L35_AMP_GAIN_ZC_SHIFT); 7916387f866SBrian Austin 7926387f866SBrian Austin if (cs35l35->pdata.aud_channel) 7936387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 7946387f866SBrian Austin CS35L35_AUDIN_RXLOC_CTL, 7956387f866SBrian Austin CS35L35_AUD_IN_LR_MASK, 7966387f866SBrian Austin cs35l35->pdata.aud_channel << 7976387f866SBrian Austin CS35L35_AUD_IN_LR_SHIFT); 7986387f866SBrian Austin 7996387f866SBrian Austin if (cs35l35->pdata.stereo) { 8006387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8016387f866SBrian Austin CS35L35_ADVIN_RXLOC_CTL, 8026387f866SBrian Austin CS35L35_ADV_IN_LR_MASK, 8036387f866SBrian Austin cs35l35->pdata.adv_channel << 8046387f866SBrian Austin CS35L35_ADV_IN_LR_SHIFT); 8056387f866SBrian Austin if (cs35l35->pdata.shared_bst) 8066387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL, 8076387f866SBrian Austin CS35L35_CH_STEREO_MASK, 8086387f866SBrian Austin 1 << CS35L35_CH_STEREO_SHIFT); 8096387f866SBrian Austin ret = snd_soc_add_codec_controls(codec, cs35l35_adv_controls, 8106387f866SBrian Austin ARRAY_SIZE(cs35l35_adv_controls)); 8116387f866SBrian Austin if (ret) 8126387f866SBrian Austin return ret; 8136387f866SBrian Austin } 8146387f866SBrian Austin 8156387f866SBrian Austin if (cs35l35->pdata.sp_drv_str) 8166387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 8176387f866SBrian Austin CS35L35_SP_DRV_MASK, 8186387f866SBrian Austin cs35l35->pdata.sp_drv_str << 8196387f866SBrian Austin CS35L35_SP_DRV_SHIFT); 8208d45f2d2SCharles Keepax if (cs35l35->pdata.sp_drv_unused) 8218d45f2d2SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3, 8228d45f2d2SCharles Keepax CS35L35_SP_I2S_DRV_MASK, 8238d45f2d2SCharles Keepax cs35l35->pdata.sp_drv_unused << 8248d45f2d2SCharles Keepax CS35L35_SP_I2S_DRV_SHIFT); 8256387f866SBrian Austin 8266387f866SBrian Austin if (classh->classh_algo_enable) { 8276387f866SBrian Austin if (classh->classh_bst_override) 8286387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8296387f866SBrian Austin CS35L35_CLASS_H_CTL, 8306387f866SBrian Austin CS35L35_CH_BST_OVR_MASK, 8316387f866SBrian Austin classh->classh_bst_override << 8326387f866SBrian Austin CS35L35_CH_BST_OVR_SHIFT); 8336387f866SBrian Austin if (classh->classh_bst_max_limit) 8346387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8356387f866SBrian Austin CS35L35_CLASS_H_CTL, 8366387f866SBrian Austin CS35L35_CH_BST_LIM_MASK, 8376387f866SBrian Austin classh->classh_bst_max_limit << 8386387f866SBrian Austin CS35L35_CH_BST_LIM_SHIFT); 8396387f866SBrian Austin if (classh->classh_mem_depth) 8406387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8416387f866SBrian Austin CS35L35_CLASS_H_CTL, 8426387f866SBrian Austin CS35L35_CH_MEM_DEPTH_MASK, 8436387f866SBrian Austin classh->classh_mem_depth << 8446387f866SBrian Austin CS35L35_CH_MEM_DEPTH_SHIFT); 8456387f866SBrian Austin if (classh->classh_headroom) 8466387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8476387f866SBrian Austin CS35L35_CLASS_H_HEADRM_CTL, 8486387f866SBrian Austin CS35L35_CH_HDRM_CTL_MASK, 8496387f866SBrian Austin classh->classh_headroom << 8506387f866SBrian Austin CS35L35_CH_HDRM_CTL_SHIFT); 8516387f866SBrian Austin if (classh->classh_release_rate) 8526387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8536387f866SBrian Austin CS35L35_CLASS_H_RELEASE_RATE, 8546387f866SBrian Austin CS35L35_CH_REL_RATE_MASK, 8556387f866SBrian Austin classh->classh_release_rate << 8566387f866SBrian Austin CS35L35_CH_REL_RATE_SHIFT); 8576387f866SBrian Austin if (classh->classh_wk_fet_disable) 8586387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8596387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 8606387f866SBrian Austin CS35L35_CH_WKFET_DIS_MASK, 8616387f866SBrian Austin classh->classh_wk_fet_disable << 8626387f866SBrian Austin CS35L35_CH_WKFET_DIS_SHIFT); 8636387f866SBrian Austin if (classh->classh_wk_fet_delay) 8646387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8656387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 8666387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 8676387f866SBrian Austin classh->classh_wk_fet_delay << 8686387f866SBrian Austin CS35L35_CH_WKFET_DEL_SHIFT); 8696387f866SBrian Austin if (classh->classh_wk_fet_thld) 8706387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8716387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 8726387f866SBrian Austin CS35L35_CH_WKFET_THLD_MASK, 8736387f866SBrian Austin classh->classh_wk_fet_thld << 8746387f866SBrian Austin CS35L35_CH_WKFET_THLD_SHIFT); 8756387f866SBrian Austin if (classh->classh_vpch_auto) 8766387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8776387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 8786387f866SBrian Austin CS35L35_CH_VP_AUTO_MASK, 8796387f866SBrian Austin classh->classh_vpch_auto << 8806387f866SBrian Austin CS35L35_CH_VP_AUTO_SHIFT); 8816387f866SBrian Austin if (classh->classh_vpch_rate) 8826387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8836387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 8846387f866SBrian Austin CS35L35_CH_VP_RATE_MASK, 8856387f866SBrian Austin classh->classh_vpch_rate << 8866387f866SBrian Austin CS35L35_CH_VP_RATE_SHIFT); 8876387f866SBrian Austin if (classh->classh_vpch_man) 8886387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8896387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 8906387f866SBrian Austin CS35L35_CH_VP_MAN_MASK, 8916387f866SBrian Austin classh->classh_vpch_man << 8926387f866SBrian Austin CS35L35_CH_VP_MAN_SHIFT); 8936387f866SBrian Austin } 8946387f866SBrian Austin 8956387f866SBrian Austin if (monitor_config->is_present) { 8966387f866SBrian Austin if (monitor_config->vmon_specs) { 8976387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8986387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 8996387f866SBrian Austin CS35L35_VMON_DEPTH_MASK, 9006387f866SBrian Austin monitor_config->vmon_dpth << 9016387f866SBrian Austin CS35L35_VMON_DEPTH_SHIFT); 9026387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9036387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 9046387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9056387f866SBrian Austin monitor_config->vmon_loc << 9066387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9076387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9086387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 9096387f866SBrian Austin CS35L35_MON_FRM_MASK, 9106387f866SBrian Austin monitor_config->vmon_frm << 9116387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 9126387f866SBrian Austin } 9136387f866SBrian Austin if (monitor_config->imon_specs) { 9146387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9156387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 9166387f866SBrian Austin CS35L35_IMON_DEPTH_MASK, 9176387f866SBrian Austin monitor_config->imon_dpth << 9186387f866SBrian Austin CS35L35_IMON_DEPTH_SHIFT); 9196387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9206387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 9216387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9226387f866SBrian Austin monitor_config->imon_loc << 9236387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9246387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9256387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 9266387f866SBrian Austin CS35L35_MON_FRM_MASK, 9276387f866SBrian Austin monitor_config->imon_frm << 9286387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 92906bdf385SCharles Keepax regmap_update_bits(cs35l35->regmap, 93006bdf385SCharles Keepax CS35L35_IMON_SCALE_CTL, 93106bdf385SCharles Keepax CS35L35_IMON_SCALE_MASK, 93206bdf385SCharles Keepax monitor_config->imon_scale << 93306bdf385SCharles Keepax CS35L35_IMON_SCALE_SHIFT); 9346387f866SBrian Austin } 9356387f866SBrian Austin if (monitor_config->vpmon_specs) { 9366387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9376387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 9386387f866SBrian Austin CS35L35_VPMON_DEPTH_MASK, 9396387f866SBrian Austin monitor_config->vpmon_dpth << 9406387f866SBrian Austin CS35L35_VPMON_DEPTH_SHIFT); 9416387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9426387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 9436387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9446387f866SBrian Austin monitor_config->vpmon_loc << 9456387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9466387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9476387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 9486387f866SBrian Austin CS35L35_MON_FRM_MASK, 9496387f866SBrian Austin monitor_config->vpmon_frm << 9506387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 9516387f866SBrian Austin } 9526387f866SBrian Austin if (monitor_config->vbstmon_specs) { 9536387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9546387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 9556387f866SBrian Austin CS35L35_VBSTMON_DEPTH_MASK, 9566387f866SBrian Austin monitor_config->vpmon_dpth << 9576387f866SBrian Austin CS35L35_VBSTMON_DEPTH_SHIFT); 9586387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9596387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 9606387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9616387f866SBrian Austin monitor_config->vbstmon_loc << 9626387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9636387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9646387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 9656387f866SBrian Austin CS35L35_MON_FRM_MASK, 9666387f866SBrian Austin monitor_config->vbstmon_frm << 9676387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 9686387f866SBrian Austin } 9696387f866SBrian Austin if (monitor_config->vpbrstat_specs) { 9706387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9716387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 9726387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_MASK, 9736387f866SBrian Austin monitor_config->vpbrstat_dpth << 9746387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_SHIFT); 9756387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9766387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 9776387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9786387f866SBrian Austin monitor_config->vpbrstat_loc << 9796387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9806387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9816387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 9826387f866SBrian Austin CS35L35_MON_FRM_MASK, 9836387f866SBrian Austin monitor_config->vpbrstat_frm << 9846387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 9856387f866SBrian Austin } 9866387f866SBrian Austin if (monitor_config->zerofill_specs) { 9876387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9886387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 9896387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_MASK, 9906387f866SBrian Austin monitor_config->zerofill_dpth << 9916387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_SHIFT); 9926387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9936387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 9946387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9956387f866SBrian Austin monitor_config->zerofill_loc << 9966387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9976387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9986387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 9996387f866SBrian Austin CS35L35_MON_FRM_MASK, 10006387f866SBrian Austin monitor_config->zerofill_frm << 10016387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10026387f866SBrian Austin } 10036387f866SBrian Austin } 10046387f866SBrian Austin 1005bfe41c67SDan Carpenter return 0; 10066387f866SBrian Austin } 10076387f866SBrian Austin 10086387f866SBrian Austin static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = { 10096387f866SBrian Austin .probe = cs35l35_codec_probe, 10106387f866SBrian Austin .set_sysclk = cs35l35_codec_set_sysclk, 10116387f866SBrian Austin .component_driver = { 10126387f866SBrian Austin .dapm_widgets = cs35l35_dapm_widgets, 10136387f866SBrian Austin .num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets), 10146387f866SBrian Austin 10156387f866SBrian Austin .dapm_routes = cs35l35_audio_map, 10166387f866SBrian Austin .num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map), 10176387f866SBrian Austin 10186387f866SBrian Austin .controls = cs35l35_aud_controls, 10196387f866SBrian Austin .num_controls = ARRAY_SIZE(cs35l35_aud_controls), 10206387f866SBrian Austin }, 10216387f866SBrian Austin 10226387f866SBrian Austin }; 10236387f866SBrian Austin 10246387f866SBrian Austin static struct regmap_config cs35l35_regmap = { 10256387f866SBrian Austin .reg_bits = 8, 10266387f866SBrian Austin .val_bits = 8, 10276387f866SBrian Austin 10286387f866SBrian Austin .max_register = CS35L35_MAX_REGISTER, 10296387f866SBrian Austin .reg_defaults = cs35l35_reg, 10306387f866SBrian Austin .num_reg_defaults = ARRAY_SIZE(cs35l35_reg), 10316387f866SBrian Austin .volatile_reg = cs35l35_volatile_register, 10326387f866SBrian Austin .readable_reg = cs35l35_readable_register, 10336387f866SBrian Austin .precious_reg = cs35l35_precious_register, 10346387f866SBrian Austin .cache_type = REGCACHE_RBTREE, 10356387f866SBrian Austin }; 10366387f866SBrian Austin 10376387f866SBrian Austin static irqreturn_t cs35l35_irq(int irq, void *data) 10386387f866SBrian Austin { 10396387f866SBrian Austin struct cs35l35_private *cs35l35 = data; 10406387f866SBrian Austin unsigned int sticky1, sticky2, sticky3, sticky4; 10416387f866SBrian Austin unsigned int mask1, mask2, mask3, mask4, current1; 10426387f866SBrian Austin 10436387f866SBrian Austin /* ack the irq by reading all status registers */ 10446387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4); 10456387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3); 10466387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2); 10476387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1); 10486387f866SBrian Austin 10496387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4); 10506387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3); 10516387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2); 10526387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1); 10536387f866SBrian Austin 10546387f866SBrian Austin /* Check to see if unmasked bits are active */ 10556387f866SBrian Austin if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) 10566387f866SBrian Austin && !(sticky4 & ~mask4)) 10576387f866SBrian Austin return IRQ_NONE; 10586387f866SBrian Austin 10596387f866SBrian Austin if (sticky2 & CS35L35_PDN_DONE) 10606387f866SBrian Austin complete(&cs35l35->pdn_done); 10616387f866SBrian Austin 10626387f866SBrian Austin /* read the current values */ 10636387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, ¤t1); 10646387f866SBrian Austin 10656387f866SBrian Austin /* handle the interrupts */ 10666387f866SBrian Austin if (sticky1 & CS35L35_CAL_ERR) { 10675d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "Calibration Error\n"); 10686387f866SBrian Austin 10696387f866SBrian Austin /* error is no longer asserted; safe to reset */ 10706387f866SBrian Austin if (!(current1 & CS35L35_CAL_ERR)) { 10716387f866SBrian Austin pr_debug("%s : Cal error release\n", __func__); 10726387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10736387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 10746387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 10756387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10766387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 10776387f866SBrian Austin CS35L35_CAL_ERR_RLS, 10786387f866SBrian Austin CS35L35_CAL_ERR_RLS); 10796387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10806387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 10816387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 10826387f866SBrian Austin } 10836387f866SBrian Austin } 10846387f866SBrian Austin 10856387f866SBrian Austin if (sticky1 & CS35L35_AMP_SHORT) { 10865d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "AMP Short Error\n"); 10876387f866SBrian Austin /* error is no longer asserted; safe to reset */ 10886387f866SBrian Austin if (!(current1 & CS35L35_AMP_SHORT)) { 10895d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Amp short error release\n"); 10906387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10916387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 10926387f866SBrian Austin CS35L35_SHORT_RLS, 0); 10936387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10946387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 10956387f866SBrian Austin CS35L35_SHORT_RLS, 10966387f866SBrian Austin CS35L35_SHORT_RLS); 10976387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10986387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 10996387f866SBrian Austin CS35L35_SHORT_RLS, 0); 11006387f866SBrian Austin } 11016387f866SBrian Austin } 11026387f866SBrian Austin 11036387f866SBrian Austin if (sticky1 & CS35L35_OTW) { 11045d3d0ad6SCharles Keepax dev_warn(cs35l35->dev, "Over temperature warning\n"); 11056387f866SBrian Austin 11066387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11076387f866SBrian Austin if (!(current1 & CS35L35_OTW)) { 11085d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Over temperature warn release\n"); 11096387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11106387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11116387f866SBrian Austin CS35L35_OTW_RLS, 0); 11126387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11136387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11146387f866SBrian Austin CS35L35_OTW_RLS, 11156387f866SBrian Austin CS35L35_OTW_RLS); 11166387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11176387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11186387f866SBrian Austin CS35L35_OTW_RLS, 0); 11196387f866SBrian Austin } 11206387f866SBrian Austin } 11216387f866SBrian Austin 11226387f866SBrian Austin if (sticky1 & CS35L35_OTE) { 11235d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "Over temperature error\n"); 11246387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11256387f866SBrian Austin if (!(current1 & CS35L35_OTE)) { 11265d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Over temperature error release\n"); 11276387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11286387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11296387f866SBrian Austin CS35L35_OTE_RLS, 0); 11306387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11316387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11326387f866SBrian Austin CS35L35_OTE_RLS, 11336387f866SBrian Austin CS35L35_OTE_RLS); 11346387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11356387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11366387f866SBrian Austin CS35L35_OTE_RLS, 0); 11376387f866SBrian Austin } 11386387f866SBrian Austin } 11396387f866SBrian Austin 11406387f866SBrian Austin if (sticky3 & CS35L35_BST_HIGH) { 11415d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "VBST error: powering off!\n"); 11426387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 11436387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 11446387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 11456387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 11466387f866SBrian Austin } 11476387f866SBrian Austin 11486387f866SBrian Austin if (sticky3 & CS35L35_LBST_SHORT) { 11495d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "LBST error: powering off!\n"); 11506387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 11516387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 11526387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 11536387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 11546387f866SBrian Austin } 11556387f866SBrian Austin 11566387f866SBrian Austin if (sticky2 & CS35L35_VPBR_ERR) 11575d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n"); 11586387f866SBrian Austin 11596387f866SBrian Austin if (sticky4 & CS35L35_VMON_OVFL) 11605d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: VMON overflow\n"); 11616387f866SBrian Austin 11626387f866SBrian Austin if (sticky4 & CS35L35_IMON_OVFL) 11635d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: IMON overflow\n"); 11646387f866SBrian Austin 11656387f866SBrian Austin return IRQ_HANDLED; 11666387f866SBrian Austin } 11676387f866SBrian Austin 11686387f866SBrian Austin 11696387f866SBrian Austin static int cs35l35_handle_of_data(struct i2c_client *i2c_client, 11706387f866SBrian Austin struct cs35l35_platform_data *pdata) 11716387f866SBrian Austin { 11726387f866SBrian Austin struct device_node *np = i2c_client->dev.of_node; 11736387f866SBrian Austin struct device_node *classh, *signal_format; 11746387f866SBrian Austin struct classh_cfg *classh_config = &pdata->classh_algo; 11756387f866SBrian Austin struct monitor_cfg *monitor_config = &pdata->mon_cfg; 11766387f866SBrian Austin unsigned int val32 = 0; 117706bdf385SCharles Keepax u8 monitor_array[4]; 117806bdf385SCharles Keepax const int imon_array_size = ARRAY_SIZE(monitor_array); 117906bdf385SCharles Keepax const int mon_array_size = imon_array_size - 1; 11806387f866SBrian Austin int ret = 0; 11816387f866SBrian Austin 11826387f866SBrian Austin if (!np) 11836387f866SBrian Austin return 0; 11846387f866SBrian Austin 11856387f866SBrian Austin pdata->bst_pdn_fet_on = of_property_read_bool(np, 11866387f866SBrian Austin "cirrus,boost-pdn-fet-on"); 11876387f866SBrian Austin 11886387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32); 11896387f866SBrian Austin if (ret >= 0) { 11906387f866SBrian Austin if (val32 < 2600 || val32 > 9000) { 11916387f866SBrian Austin dev_err(&i2c_client->dev, 11926387f866SBrian Austin "Invalid Boost Voltage %d mV\n", val32); 11936387f866SBrian Austin return -EINVAL; 11946387f866SBrian Austin } 11956387f866SBrian Austin pdata->bst_vctl = ((val32 - 2600) / 100) + 1; 11966387f866SBrian Austin } 11976387f866SBrian Austin 11986387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32); 11996387f866SBrian Austin if (ret >= 0) { 12006387f866SBrian Austin if (val32 < 1680 || val32 > 4480) { 12016387f866SBrian Austin dev_err(&i2c_client->dev, 12026387f866SBrian Austin "Invalid Boost Peak Current %u mA\n", val32); 12036387f866SBrian Austin return -EINVAL; 12046387f866SBrian Austin } 12056387f866SBrian Austin 12066387f866SBrian Austin pdata->bst_ipk = (val32 - 1680) / 110; 12076387f866SBrian Austin } 12086387f866SBrian Austin 12096387f866SBrian Austin if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) 12106387f866SBrian Austin pdata->sp_drv_str = val32; 12118d45f2d2SCharles Keepax if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0) 12128d45f2d2SCharles Keepax pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA; 12136387f866SBrian Austin 12146387f866SBrian Austin pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); 12156387f866SBrian Austin 12166387f866SBrian Austin if (pdata->stereo) { 12176387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,audio-channel", &val32); 12186387f866SBrian Austin if (ret >= 0) 12196387f866SBrian Austin pdata->aud_channel = val32; 12206387f866SBrian Austin 12216387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,advisory-channel", 12226387f866SBrian Austin &val32); 12236387f866SBrian Austin if (ret >= 0) 12246387f866SBrian Austin pdata->adv_channel = val32; 12256387f866SBrian Austin 12266387f866SBrian Austin pdata->shared_bst = of_property_read_bool(np, 12276387f866SBrian Austin "cirrus,shared-boost"); 12286387f866SBrian Austin } 12296387f866SBrian Austin 123077b329d1SCharles Keepax pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost"); 123177b329d1SCharles Keepax 12326387f866SBrian Austin pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); 12336387f866SBrian Austin 12346387f866SBrian Austin classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); 12356387f866SBrian Austin classh_config->classh_algo_enable = classh ? true : false; 12366387f866SBrian Austin 12376387f866SBrian Austin if (classh_config->classh_algo_enable) { 12386387f866SBrian Austin classh_config->classh_bst_override = 12396387f866SBrian Austin of_property_read_bool(np, "cirrus,classh-bst-overide"); 12406387f866SBrian Austin 12416387f866SBrian Austin ret = of_property_read_u32(classh, 12426387f866SBrian Austin "cirrus,classh-bst-max-limit", 12436387f866SBrian Austin &val32); 12446387f866SBrian Austin if (ret >= 0) { 12456387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 12466387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 12476387f866SBrian Austin } 12486387f866SBrian Austin 12496387f866SBrian Austin ret = of_property_read_u32(classh, 12506387f866SBrian Austin "cirrus,classh-bst-max-limit", 12516387f866SBrian Austin &val32); 12526387f866SBrian Austin if (ret >= 0) { 12536387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 12546387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 12556387f866SBrian Austin } 12566387f866SBrian Austin 12576387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-mem-depth", 12586387f866SBrian Austin &val32); 12596387f866SBrian Austin if (ret >= 0) { 12606387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 12616387f866SBrian Austin classh_config->classh_mem_depth = val32; 12626387f866SBrian Austin } 12636387f866SBrian Austin 12646387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-release-rate", 12656387f866SBrian Austin &val32); 12666387f866SBrian Austin if (ret >= 0) 12676387f866SBrian Austin classh_config->classh_release_rate = val32; 12686387f866SBrian Austin 12696387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-headroom", 12706387f866SBrian Austin &val32); 12716387f866SBrian Austin if (ret >= 0) { 12726387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 12736387f866SBrian Austin classh_config->classh_headroom = val32; 12746387f866SBrian Austin } 12756387f866SBrian Austin 12766387f866SBrian Austin ret = of_property_read_u32(classh, 12776387f866SBrian Austin "cirrus,classh-wk-fet-disable", 12786387f866SBrian Austin &val32); 12796387f866SBrian Austin if (ret >= 0) 12806387f866SBrian Austin classh_config->classh_wk_fet_disable = val32; 12816387f866SBrian Austin 12826387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay", 12836387f866SBrian Austin &val32); 12846387f866SBrian Austin if (ret >= 0) { 12856387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 12866387f866SBrian Austin classh_config->classh_wk_fet_delay = val32; 12876387f866SBrian Austin } 12886387f866SBrian Austin 12896387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld", 12906387f866SBrian Austin &val32); 12916387f866SBrian Austin if (ret >= 0) 12926387f866SBrian Austin classh_config->classh_wk_fet_thld = val32; 12936387f866SBrian Austin 12946387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto", 12956387f866SBrian Austin &val32); 12966387f866SBrian Austin if (ret >= 0) { 12976387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 12986387f866SBrian Austin classh_config->classh_vpch_auto = val32; 12996387f866SBrian Austin } 13006387f866SBrian Austin 13016387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate", 13026387f866SBrian Austin &val32); 13036387f866SBrian Austin if (ret >= 0) { 13046387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13056387f866SBrian Austin classh_config->classh_vpch_rate = val32; 13066387f866SBrian Austin } 13076387f866SBrian Austin 13086387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-man", 13096387f866SBrian Austin &val32); 13106387f866SBrian Austin if (ret >= 0) 13116387f866SBrian Austin classh_config->classh_vpch_man = val32; 13126387f866SBrian Austin } 13136387f866SBrian Austin of_node_put(classh); 13146387f866SBrian Austin 13156387f866SBrian Austin /* frame depth location */ 13166387f866SBrian Austin signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format"); 13176387f866SBrian Austin monitor_config->is_present = signal_format ? true : false; 13186387f866SBrian Austin if (monitor_config->is_present) { 13196387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,imon", 132006bdf385SCharles Keepax monitor_array, imon_array_size); 13216387f866SBrian Austin if (!ret) { 13226387f866SBrian Austin monitor_config->imon_specs = true; 13236387f866SBrian Austin monitor_config->imon_dpth = monitor_array[0]; 13246387f866SBrian Austin monitor_config->imon_loc = monitor_array[1]; 13256387f866SBrian Austin monitor_config->imon_frm = monitor_array[2]; 132606bdf385SCharles Keepax monitor_config->imon_scale = monitor_array[3]; 13276387f866SBrian Austin } 13286387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vmon", 132906bdf385SCharles Keepax monitor_array, mon_array_size); 13306387f866SBrian Austin if (!ret) { 13316387f866SBrian Austin monitor_config->vmon_specs = true; 13326387f866SBrian Austin monitor_config->vmon_dpth = monitor_array[0]; 13336387f866SBrian Austin monitor_config->vmon_loc = monitor_array[1]; 13346387f866SBrian Austin monitor_config->vmon_frm = monitor_array[2]; 13356387f866SBrian Austin } 13366387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpmon", 133706bdf385SCharles Keepax monitor_array, mon_array_size); 13386387f866SBrian Austin if (!ret) { 13396387f866SBrian Austin monitor_config->vpmon_specs = true; 13406387f866SBrian Austin monitor_config->vpmon_dpth = monitor_array[0]; 13416387f866SBrian Austin monitor_config->vpmon_loc = monitor_array[1]; 13426387f866SBrian Austin monitor_config->vpmon_frm = monitor_array[2]; 13436387f866SBrian Austin } 13446387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon", 134506bdf385SCharles Keepax monitor_array, mon_array_size); 13466387f866SBrian Austin if (!ret) { 13476387f866SBrian Austin monitor_config->vbstmon_specs = true; 13486387f866SBrian Austin monitor_config->vbstmon_dpth = monitor_array[0]; 13496387f866SBrian Austin monitor_config->vbstmon_loc = monitor_array[1]; 13506387f866SBrian Austin monitor_config->vbstmon_frm = monitor_array[2]; 13516387f866SBrian Austin } 13526387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat", 135306bdf385SCharles Keepax monitor_array, mon_array_size); 13546387f866SBrian Austin if (!ret) { 13556387f866SBrian Austin monitor_config->vpbrstat_specs = true; 13566387f866SBrian Austin monitor_config->vpbrstat_dpth = monitor_array[0]; 13576387f866SBrian Austin monitor_config->vpbrstat_loc = monitor_array[1]; 13586387f866SBrian Austin monitor_config->vpbrstat_frm = monitor_array[2]; 13596387f866SBrian Austin } 13606387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,zerofill", 136106bdf385SCharles Keepax monitor_array, mon_array_size); 13626387f866SBrian Austin if (!ret) { 13636387f866SBrian Austin monitor_config->zerofill_specs = true; 13646387f866SBrian Austin monitor_config->zerofill_dpth = monitor_array[0]; 13656387f866SBrian Austin monitor_config->zerofill_loc = monitor_array[1]; 13666387f866SBrian Austin monitor_config->zerofill_frm = monitor_array[2]; 13676387f866SBrian Austin } 13686387f866SBrian Austin } 13696387f866SBrian Austin of_node_put(signal_format); 13706387f866SBrian Austin 13716387f866SBrian Austin return 0; 13726387f866SBrian Austin } 13736387f866SBrian Austin 13746387f866SBrian Austin /* Errata Rev A0 */ 13756387f866SBrian Austin static const struct reg_sequence cs35l35_errata_patch[] = { 13766387f866SBrian Austin 13776387f866SBrian Austin { 0x7F, 0x99 }, 13786387f866SBrian Austin { 0x00, 0x99 }, 13796387f866SBrian Austin { 0x52, 0x22 }, 13806387f866SBrian Austin { 0x04, 0x14 }, 13816387f866SBrian Austin { 0x6D, 0x44 }, 13826387f866SBrian Austin { 0x24, 0x10 }, 13836387f866SBrian Austin { 0x58, 0xC4 }, 13846387f866SBrian Austin { 0x00, 0x98 }, 13856387f866SBrian Austin { 0x18, 0x08 }, 13866387f866SBrian Austin { 0x00, 0x00 }, 13876387f866SBrian Austin { 0x7F, 0x00 }, 13886387f866SBrian Austin }; 13896387f866SBrian Austin 13906387f866SBrian Austin static int cs35l35_i2c_probe(struct i2c_client *i2c_client, 13916387f866SBrian Austin const struct i2c_device_id *id) 13926387f866SBrian Austin { 13936387f866SBrian Austin struct cs35l35_private *cs35l35; 13941f758cd9SCharles Keepax struct device *dev = &i2c_client->dev; 13951f758cd9SCharles Keepax struct cs35l35_platform_data *pdata = dev_get_platdata(dev); 13966387f866SBrian Austin int i; 13976387f866SBrian Austin int ret; 13986387f866SBrian Austin unsigned int devid = 0; 13996387f866SBrian Austin unsigned int reg; 14006387f866SBrian Austin 14011f758cd9SCharles Keepax cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL); 14026387f866SBrian Austin if (!cs35l35) 14036387f866SBrian Austin return -ENOMEM; 14046387f866SBrian Austin 14055d3d0ad6SCharles Keepax cs35l35->dev = dev; 14065d3d0ad6SCharles Keepax 14076387f866SBrian Austin i2c_set_clientdata(i2c_client, cs35l35); 14086387f866SBrian Austin cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); 14096387f866SBrian Austin if (IS_ERR(cs35l35->regmap)) { 14106387f866SBrian Austin ret = PTR_ERR(cs35l35->regmap); 14111f758cd9SCharles Keepax dev_err(dev, "regmap_init() failed: %d\n", ret); 14126387f866SBrian Austin goto err; 14136387f866SBrian Austin } 14146387f866SBrian Austin 14156387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) 14166387f866SBrian Austin cs35l35->supplies[i].supply = cs35l35_supplies[i]; 141703ff570cSColin Ian King 14186387f866SBrian Austin cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); 14196387f866SBrian Austin 14201f758cd9SCharles Keepax ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies, 14216387f866SBrian Austin cs35l35->supplies); 14226387f866SBrian Austin if (ret != 0) { 14231f758cd9SCharles Keepax dev_err(dev, "Failed to request core supplies: %d\n", ret); 14246387f866SBrian Austin return ret; 14256387f866SBrian Austin } 14266387f866SBrian Austin 14276387f866SBrian Austin if (pdata) { 14286387f866SBrian Austin cs35l35->pdata = *pdata; 14296387f866SBrian Austin } else { 14301f758cd9SCharles Keepax pdata = devm_kzalloc(dev, sizeof(struct cs35l35_platform_data), 14316387f866SBrian Austin GFP_KERNEL); 14326387f866SBrian Austin if (!pdata) 14336387f866SBrian Austin return -ENOMEM; 14346387f866SBrian Austin if (i2c_client->dev.of_node) { 14356387f866SBrian Austin ret = cs35l35_handle_of_data(i2c_client, pdata); 14366387f866SBrian Austin if (ret != 0) 14376387f866SBrian Austin return ret; 14386387f866SBrian Austin 14396387f866SBrian Austin } 14406387f866SBrian Austin cs35l35->pdata = *pdata; 14416387f866SBrian Austin } 14426387f866SBrian Austin 14436387f866SBrian Austin ret = regulator_bulk_enable(cs35l35->num_supplies, 14446387f866SBrian Austin cs35l35->supplies); 14456387f866SBrian Austin if (ret != 0) { 14461f758cd9SCharles Keepax dev_err(dev, "Failed to enable core supplies: %d\n", ret); 14476387f866SBrian Austin return ret; 14486387f866SBrian Austin } 14496387f866SBrian Austin 14506387f866SBrian Austin /* returning NULL can be valid if in stereo mode */ 14511f758cd9SCharles Keepax cs35l35->reset_gpio = devm_gpiod_get_optional(dev, "reset", 14521f758cd9SCharles Keepax GPIOD_OUT_LOW); 14536387f866SBrian Austin if (IS_ERR(cs35l35->reset_gpio)) { 14546387f866SBrian Austin ret = PTR_ERR(cs35l35->reset_gpio); 14558e71321dSCharles Keepax cs35l35->reset_gpio = NULL; 14566387f866SBrian Austin if (ret == -EBUSY) { 14571f758cd9SCharles Keepax dev_info(dev, 14586387f866SBrian Austin "Reset line busy, assuming shared reset\n"); 14596387f866SBrian Austin } else { 14601f758cd9SCharles Keepax dev_err(dev, "Failed to get reset GPIO: %d\n", ret); 14616387f866SBrian Austin goto err; 14626387f866SBrian Austin } 14636387f866SBrian Austin } 14646387f866SBrian Austin 1465*dc43f46aSCharles Keepax cs35l35_reset(cs35l35); 14666387f866SBrian Austin 14676387f866SBrian Austin init_completion(&cs35l35->pdn_done); 14686387f866SBrian Austin 14691f758cd9SCharles Keepax ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq, 1470bf5043d6SCharles Keepax IRQF_ONESHOT | IRQF_TRIGGER_LOW | 1471bf5043d6SCharles Keepax IRQF_SHARED, "cs35l35", cs35l35); 14726387f866SBrian Austin if (ret != 0) { 14731f758cd9SCharles Keepax dev_err(dev, "Failed to request IRQ: %d\n", ret); 14746387f866SBrian Austin goto err; 14756387f866SBrian Austin } 14766387f866SBrian Austin /* initialize codec */ 14776387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_AB, ®); 14786387f866SBrian Austin 14796387f866SBrian Austin devid = (reg & 0xFF) << 12; 14806387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_CD, ®); 14816387f866SBrian Austin devid |= (reg & 0xFF) << 4; 14826387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_E, ®); 14836387f866SBrian Austin devid |= (reg & 0xF0) >> 4; 14846387f866SBrian Austin 14856387f866SBrian Austin if (devid != CS35L35_CHIP_ID) { 14861f758cd9SCharles Keepax dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n", 14876387f866SBrian Austin devid, CS35L35_CHIP_ID); 14886387f866SBrian Austin ret = -ENODEV; 14896387f866SBrian Austin goto err; 14906387f866SBrian Austin } 14916387f866SBrian Austin 14926387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, ®); 14936387f866SBrian Austin if (ret < 0) { 14941f758cd9SCharles Keepax dev_err(dev, "Get Revision ID failed: %d\n", ret); 14956387f866SBrian Austin goto err; 14966387f866SBrian Austin } 14976387f866SBrian Austin 14986387f866SBrian Austin ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch, 14996387f866SBrian Austin ARRAY_SIZE(cs35l35_errata_patch)); 15006387f866SBrian Austin if (ret < 0) { 15011f758cd9SCharles Keepax dev_err(dev, "Failed to apply errata patch: %d\n", ret); 15026387f866SBrian Austin goto err; 15036387f866SBrian Austin } 15046387f866SBrian Austin 15051f758cd9SCharles Keepax dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n", 150682875163SAxel Lin devid, reg & 0xFF); 15076387f866SBrian Austin 15086387f866SBrian Austin /* Set the INT Masks for critical errors */ 15096387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, 15106387f866SBrian Austin CS35L35_INT1_CRIT_MASK); 15116387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2, 15126387f866SBrian Austin CS35L35_INT2_CRIT_MASK); 15136387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3, 15146387f866SBrian Austin CS35L35_INT3_CRIT_MASK); 15156387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4, 15166387f866SBrian Austin CS35L35_INT4_CRIT_MASK); 15176387f866SBrian Austin 15186387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 15196387f866SBrian Austin CS35L35_PWR2_PDN_MASK, 15206387f866SBrian Austin CS35L35_PWR2_PDN_MASK); 15216387f866SBrian Austin 15226387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 15236387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 15246387f866SBrian Austin CS35L35_PDN_BST_MASK, 15256387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 15266387f866SBrian Austin else 15276387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 15286387f866SBrian Austin CS35L35_PDN_BST_MASK, 15296387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 15306387f866SBrian Austin 15316387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3, 15326387f866SBrian Austin CS35L35_PWR3_PDN_MASK, 15336387f866SBrian Austin CS35L35_PWR3_PDN_MASK); 15346387f866SBrian Austin 15356387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 15366387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT); 15376387f866SBrian Austin 15381f758cd9SCharles Keepax ret = snd_soc_register_codec(dev, &soc_codec_dev_cs35l35, cs35l35_dai, 15396387f866SBrian Austin ARRAY_SIZE(cs35l35_dai)); 15406387f866SBrian Austin if (ret < 0) { 15411f758cd9SCharles Keepax dev_err(dev, "Failed to register codec: %d\n", ret); 15426387f866SBrian Austin goto err; 15436387f866SBrian Austin } 15446387f866SBrian Austin 15451bb06adaSCharles Keepax return 0; 15461bb06adaSCharles Keepax 15476387f866SBrian Austin err: 15486387f866SBrian Austin regulator_bulk_disable(cs35l35->num_supplies, 15496387f866SBrian Austin cs35l35->supplies); 15506387f866SBrian Austin gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 15516387f866SBrian Austin 15526387f866SBrian Austin return ret; 15536387f866SBrian Austin } 15546387f866SBrian Austin 15556387f866SBrian Austin static int cs35l35_i2c_remove(struct i2c_client *client) 15566387f866SBrian Austin { 15576387f866SBrian Austin snd_soc_unregister_codec(&client->dev); 15586387f866SBrian Austin return 0; 15596387f866SBrian Austin } 15606387f866SBrian Austin 15616387f866SBrian Austin static const struct of_device_id cs35l35_of_match[] = { 15626387f866SBrian Austin {.compatible = "cirrus,cs35l35"}, 15636387f866SBrian Austin {}, 15646387f866SBrian Austin }; 15656387f866SBrian Austin MODULE_DEVICE_TABLE(of, cs35l35_of_match); 15666387f866SBrian Austin 15676387f866SBrian Austin static const struct i2c_device_id cs35l35_id[] = { 15686387f866SBrian Austin {"cs35l35", 0}, 15696387f866SBrian Austin {} 15706387f866SBrian Austin }; 15716387f866SBrian Austin 15726387f866SBrian Austin MODULE_DEVICE_TABLE(i2c, cs35l35_id); 15736387f866SBrian Austin 15746387f866SBrian Austin static struct i2c_driver cs35l35_i2c_driver = { 15756387f866SBrian Austin .driver = { 15766387f866SBrian Austin .name = "cs35l35", 15776387f866SBrian Austin .of_match_table = cs35l35_of_match, 15786387f866SBrian Austin }, 15796387f866SBrian Austin .id_table = cs35l35_id, 15806387f866SBrian Austin .probe = cs35l35_i2c_probe, 15816387f866SBrian Austin .remove = cs35l35_i2c_remove, 15826387f866SBrian Austin }; 15836387f866SBrian Austin 15846387f866SBrian Austin module_i2c_driver(cs35l35_i2c_driver); 15856387f866SBrian Austin 15866387f866SBrian Austin MODULE_DESCRIPTION("ASoC CS35L35 driver"); 15876387f866SBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); 15886387f866SBrian Austin MODULE_LICENSE("GPL"); 1589