1*6387f866SBrian Austin /* 2*6387f866SBrian Austin * cs35l35.c -- CS35L35 ALSA SoC audio driver 3*6387f866SBrian Austin * 4*6387f866SBrian Austin * Copyright 2017 Cirrus Logic, Inc. 5*6387f866SBrian Austin * 6*6387f866SBrian Austin * Author: Brian Austin <brian.austin@cirrus.com> 7*6387f866SBrian Austin * 8*6387f866SBrian Austin * This program is free software; you can redistribute it and/or modify 9*6387f866SBrian Austin * it under the terms of the GNU General Public License version 2 as 10*6387f866SBrian Austin * published by the Free Software Foundation. 11*6387f866SBrian Austin * 12*6387f866SBrian Austin */ 13*6387f866SBrian Austin 14*6387f866SBrian Austin #include <linux/module.h> 15*6387f866SBrian Austin #include <linux/moduleparam.h> 16*6387f866SBrian Austin #include <linux/version.h> 17*6387f866SBrian Austin #include <linux/kernel.h> 18*6387f866SBrian Austin #include <linux/init.h> 19*6387f866SBrian Austin #include <linux/delay.h> 20*6387f866SBrian Austin #include <linux/i2c.h> 21*6387f866SBrian Austin #include <linux/slab.h> 22*6387f866SBrian Austin #include <linux/platform_device.h> 23*6387f866SBrian Austin #include <linux/regulator/consumer.h> 24*6387f866SBrian Austin #include <linux/gpio/consumer.h> 25*6387f866SBrian Austin #include <linux/of_device.h> 26*6387f866SBrian Austin #include <linux/of_gpio.h> 27*6387f866SBrian Austin #include <linux/regmap.h> 28*6387f866SBrian Austin #include <sound/core.h> 29*6387f866SBrian Austin #include <sound/pcm.h> 30*6387f866SBrian Austin #include <sound/pcm_params.h> 31*6387f866SBrian Austin #include <sound/soc.h> 32*6387f866SBrian Austin #include <sound/soc-dapm.h> 33*6387f866SBrian Austin #include <linux/gpio.h> 34*6387f866SBrian Austin #include <sound/initval.h> 35*6387f866SBrian Austin #include <sound/tlv.h> 36*6387f866SBrian Austin #include <sound/cs35l35.h> 37*6387f866SBrian Austin #include <linux/of_irq.h> 38*6387f866SBrian Austin #include <linux/completion.h> 39*6387f866SBrian Austin 40*6387f866SBrian Austin #include "cs35l35.h" 41*6387f866SBrian Austin 42*6387f866SBrian Austin /* 43*6387f866SBrian Austin * Some fields take zero as a valid value so use a high bit flag that won't 44*6387f866SBrian Austin * get written to the device to mark those. 45*6387f866SBrian Austin */ 46*6387f866SBrian Austin #define CS35L35_VALID_PDATA 0x80000000 47*6387f866SBrian Austin 48*6387f866SBrian Austin static const struct reg_default cs35l35_reg[] = { 49*6387f866SBrian Austin {CS35L35_PWRCTL1, 0x01}, 50*6387f866SBrian Austin {CS35L35_PWRCTL2, 0x11}, 51*6387f866SBrian Austin {CS35L35_PWRCTL3, 0x00}, 52*6387f866SBrian Austin {CS35L35_CLK_CTL1, 0x04}, 53*6387f866SBrian Austin {CS35L35_CLK_CTL2, 0x10}, 54*6387f866SBrian Austin {CS35L35_CLK_CTL3, 0xCF}, 55*6387f866SBrian Austin {CS35L35_SP_FMT_CTL1, 0x20}, 56*6387f866SBrian Austin {CS35L35_SP_FMT_CTL2, 0x00}, 57*6387f866SBrian Austin {CS35L35_SP_FMT_CTL3, 0x02}, 58*6387f866SBrian Austin {CS35L35_MAG_COMP_CTL, 0x00}, 59*6387f866SBrian Austin {CS35L35_AMP_INP_DRV_CTL, 0x01}, 60*6387f866SBrian Austin {CS35L35_AMP_DIG_VOL_CTL, 0x12}, 61*6387f866SBrian Austin {CS35L35_AMP_DIG_VOL, 0x00}, 62*6387f866SBrian Austin {CS35L35_ADV_DIG_VOL, 0x00}, 63*6387f866SBrian Austin {CS35L35_PROTECT_CTL, 0x06}, 64*6387f866SBrian Austin {CS35L35_AMP_GAIN_AUD_CTL, 0x13}, 65*6387f866SBrian Austin {CS35L35_AMP_GAIN_PDM_CTL, 0x00}, 66*6387f866SBrian Austin {CS35L35_AMP_GAIN_ADV_CTL, 0x00}, 67*6387f866SBrian Austin {CS35L35_GPI_CTL, 0x00}, 68*6387f866SBrian Austin {CS35L35_BST_CVTR_V_CTL, 0x00}, 69*6387f866SBrian Austin {CS35L35_BST_PEAK_I, 0x07}, 70*6387f866SBrian Austin {CS35L35_BST_RAMP_CTL, 0x85}, 71*6387f866SBrian Austin {CS35L35_BST_CONV_COEF_1, 0x24}, 72*6387f866SBrian Austin {CS35L35_BST_CONV_COEF_2, 0x24}, 73*6387f866SBrian Austin {CS35L35_BST_CONV_SLOPE_COMP, 0x47}, 74*6387f866SBrian Austin {CS35L35_BST_CONV_SW_FREQ, 0x04}, 75*6387f866SBrian Austin {CS35L35_CLASS_H_CTL, 0x0B}, 76*6387f866SBrian Austin {CS35L35_CLASS_H_HEADRM_CTL, 0x0B}, 77*6387f866SBrian Austin {CS35L35_CLASS_H_RELEASE_RATE, 0x08}, 78*6387f866SBrian Austin {CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41}, 79*6387f866SBrian Austin {CS35L35_CLASS_H_VP_CTL, 0xC5}, 80*6387f866SBrian Austin {CS35L35_VPBR_CTL, 0x0A}, 81*6387f866SBrian Austin {CS35L35_VPBR_VOL_CTL, 0x09}, 82*6387f866SBrian Austin {CS35L35_VPBR_TIMING_CTL, 0x6A}, 83*6387f866SBrian Austin {CS35L35_VPBR_MODE_VOL_CTL, 0x40}, 84*6387f866SBrian Austin {CS35L35_SPKR_MON_CTL, 0xC0}, 85*6387f866SBrian Austin {CS35L35_IMON_SCALE_CTL, 0x30}, 86*6387f866SBrian Austin {CS35L35_AUDIN_RXLOC_CTL, 0x00}, 87*6387f866SBrian Austin {CS35L35_ADVIN_RXLOC_CTL, 0x80}, 88*6387f866SBrian Austin {CS35L35_VMON_TXLOC_CTL, 0x00}, 89*6387f866SBrian Austin {CS35L35_IMON_TXLOC_CTL, 0x80}, 90*6387f866SBrian Austin {CS35L35_VPMON_TXLOC_CTL, 0x04}, 91*6387f866SBrian Austin {CS35L35_VBSTMON_TXLOC_CTL, 0x84}, 92*6387f866SBrian Austin {CS35L35_VPBR_STATUS_TXLOC_CTL, 0x04}, 93*6387f866SBrian Austin {CS35L35_ZERO_FILL_LOC_CTL, 0x00}, 94*6387f866SBrian Austin {CS35L35_AUDIN_DEPTH_CTL, 0x0F}, 95*6387f866SBrian Austin {CS35L35_SPKMON_DEPTH_CTL, 0x0F}, 96*6387f866SBrian Austin {CS35L35_SUPMON_DEPTH_CTL, 0x0F}, 97*6387f866SBrian Austin {CS35L35_ZEROFILL_DEPTH_CTL, 0x00}, 98*6387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH1, 0x02}, 99*6387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH2, 0x80}, 100*6387f866SBrian Austin {CS35L35_PROT_RELEASE_CTL, 0x00}, 101*6387f866SBrian Austin {CS35L35_DIAG_MODE_REG_LOCK, 0x00}, 102*6387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_1, 0x40}, 103*6387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_2, 0x00}, 104*6387f866SBrian Austin {CS35L35_INT_MASK_1, 0xFF}, 105*6387f866SBrian Austin {CS35L35_INT_MASK_2, 0xFF}, 106*6387f866SBrian Austin {CS35L35_INT_MASK_3, 0xFF}, 107*6387f866SBrian Austin {CS35L35_INT_MASK_4, 0xFF}, 108*6387f866SBrian Austin 109*6387f866SBrian Austin }; 110*6387f866SBrian Austin 111*6387f866SBrian Austin static bool cs35l35_volatile_register(struct device *dev, unsigned int reg) 112*6387f866SBrian Austin { 113*6387f866SBrian Austin switch (reg) { 114*6387f866SBrian Austin case CS35L35_INT_STATUS_1: 115*6387f866SBrian Austin case CS35L35_INT_STATUS_2: 116*6387f866SBrian Austin case CS35L35_INT_STATUS_3: 117*6387f866SBrian Austin case CS35L35_INT_STATUS_4: 118*6387f866SBrian Austin case CS35L35_PLL_STATUS: 119*6387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 120*6387f866SBrian Austin return true; 121*6387f866SBrian Austin default: 122*6387f866SBrian Austin return false; 123*6387f866SBrian Austin } 124*6387f866SBrian Austin } 125*6387f866SBrian Austin 126*6387f866SBrian Austin static bool cs35l35_readable_register(struct device *dev, unsigned int reg) 127*6387f866SBrian Austin { 128*6387f866SBrian Austin switch (reg) { 129*6387f866SBrian Austin case CS35L35_DEVID_AB ... CS35L35_PWRCTL3: 130*6387f866SBrian Austin case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3: 131*6387f866SBrian Austin case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL: 132*6387f866SBrian Austin case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I: 133*6387f866SBrian Austin case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ: 134*6387f866SBrian Austin case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL: 135*6387f866SBrian Austin case CS35L35_CLASS_H_STATUS: 136*6387f866SBrian Austin case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL: 137*6387f866SBrian Austin case CS35L35_VPBR_ATTEN_STATUS: 138*6387f866SBrian Austin case CS35L35_SPKR_MON_CTL: 139*6387f866SBrian Austin case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL: 140*6387f866SBrian Austin case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL: 141*6387f866SBrian Austin case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2: 142*6387f866SBrian Austin case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS: 143*6387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 144*6387f866SBrian Austin return true; 145*6387f866SBrian Austin default: 146*6387f866SBrian Austin return false; 147*6387f866SBrian Austin } 148*6387f866SBrian Austin } 149*6387f866SBrian Austin 150*6387f866SBrian Austin static bool cs35l35_precious_register(struct device *dev, unsigned int reg) 151*6387f866SBrian Austin { 152*6387f866SBrian Austin switch (reg) { 153*6387f866SBrian Austin case CS35L35_INT_STATUS_1: 154*6387f866SBrian Austin case CS35L35_INT_STATUS_2: 155*6387f866SBrian Austin case CS35L35_INT_STATUS_3: 156*6387f866SBrian Austin case CS35L35_INT_STATUS_4: 157*6387f866SBrian Austin case CS35L35_PLL_STATUS: 158*6387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 159*6387f866SBrian Austin return true; 160*6387f866SBrian Austin default: 161*6387f866SBrian Austin return false; 162*6387f866SBrian Austin } 163*6387f866SBrian Austin } 164*6387f866SBrian Austin 165*6387f866SBrian Austin static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, 166*6387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 167*6387f866SBrian Austin { 168*6387f866SBrian Austin struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 169*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 170*6387f866SBrian Austin int ret = 0; 171*6387f866SBrian Austin 172*6387f866SBrian Austin switch (event) { 173*6387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 174*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 175*6387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 176*6387f866SBrian Austin 0 << CS35L35_MCLK_DIS_SHIFT); 177*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 178*6387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 179*6387f866SBrian Austin 0 << CS35L35_DISCHG_FILT_SHIFT); 180*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 181*6387f866SBrian Austin CS35L35_PDN_ALL_MASK, 0); 182*6387f866SBrian Austin break; 183*6387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 184*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 185*6387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 186*6387f866SBrian Austin 1 << CS35L35_DISCHG_FILT_SHIFT); 187*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 188*6387f866SBrian Austin CS35L35_PDN_ALL_MASK, 1); 189*6387f866SBrian Austin 190*6387f866SBrian Austin reinit_completion(&cs35l35->pdn_done); 191*6387f866SBrian Austin 192*6387f866SBrian Austin ret = wait_for_completion_timeout(&cs35l35->pdn_done, 193*6387f866SBrian Austin msecs_to_jiffies(100)); 194*6387f866SBrian Austin if (ret == 0) { 195*6387f866SBrian Austin dev_err(codec->dev, "TIMEOUT PDN_DONE did not complete in 100ms\n"); 196*6387f866SBrian Austin ret = -ETIMEDOUT; 197*6387f866SBrian Austin } 198*6387f866SBrian Austin 199*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 200*6387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 201*6387f866SBrian Austin 1 << CS35L35_MCLK_DIS_SHIFT); 202*6387f866SBrian Austin break; 203*6387f866SBrian Austin default: 204*6387f866SBrian Austin dev_err(codec->dev, "Invalid event = 0x%x\n", event); 205*6387f866SBrian Austin ret = -EINVAL; 206*6387f866SBrian Austin } 207*6387f866SBrian Austin return ret; 208*6387f866SBrian Austin } 209*6387f866SBrian Austin 210*6387f866SBrian Austin static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w, 211*6387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 212*6387f866SBrian Austin { 213*6387f866SBrian Austin struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 214*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 215*6387f866SBrian Austin unsigned int reg[4]; 216*6387f866SBrian Austin int i; 217*6387f866SBrian Austin 218*6387f866SBrian Austin switch (event) { 219*6387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 220*6387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 221*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 222*6387f866SBrian Austin CS35L35_PDN_BST_MASK, 223*6387f866SBrian Austin 0 << CS35L35_PDN_BST_FETON_SHIFT); 224*6387f866SBrian Austin else 225*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 226*6387f866SBrian Austin CS35L35_PDN_BST_MASK, 227*6387f866SBrian Austin 0 << CS35L35_PDN_BST_FETOFF_SHIFT); 228*6387f866SBrian Austin break; 229*6387f866SBrian Austin case SND_SOC_DAPM_POST_PMU: 230*6387f866SBrian Austin usleep_range(5000, 5100); 231*6387f866SBrian Austin /* If in PDM mode we must use VP for Voltage control */ 232*6387f866SBrian Austin if (cs35l35->pdm_mode) 233*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 234*6387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 235*6387f866SBrian Austin CS35L35_BST_CTL_MASK, 236*6387f866SBrian Austin 0 << CS35L35_BST_CTL_SHIFT); 237*6387f866SBrian Austin 238*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 239*6387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 0); 240*6387f866SBrian Austin 241*6387f866SBrian Austin for (i = 0; i < 2; i++) 242*6387f866SBrian Austin regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1, 243*6387f866SBrian Austin ®, ARRAY_SIZE(reg)); 244*6387f866SBrian Austin 245*6387f866SBrian Austin break; 246*6387f866SBrian Austin case SND_SOC_DAPM_PRE_PMD: 247*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 248*6387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 249*6387f866SBrian Austin 1 << CS35L35_AMP_MUTE_SHIFT); 250*6387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 251*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 252*6387f866SBrian Austin CS35L35_PDN_BST_MASK, 253*6387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 254*6387f866SBrian Austin else 255*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 256*6387f866SBrian Austin CS35L35_PDN_BST_MASK, 257*6387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 258*6387f866SBrian Austin break; 259*6387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 260*6387f866SBrian Austin usleep_range(5000, 5100); 261*6387f866SBrian Austin /* 262*6387f866SBrian Austin * If PDM mode we should switch back to pdata value 263*6387f866SBrian Austin * for Voltage control when we go down 264*6387f866SBrian Austin */ 265*6387f866SBrian Austin if (cs35l35->pdm_mode) 266*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 267*6387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 268*6387f866SBrian Austin CS35L35_BST_CTL_MASK, 269*6387f866SBrian Austin cs35l35->pdata.bst_vctl 270*6387f866SBrian Austin << CS35L35_BST_CTL_SHIFT); 271*6387f866SBrian Austin 272*6387f866SBrian Austin break; 273*6387f866SBrian Austin default: 274*6387f866SBrian Austin dev_err(codec->dev, "Invalid event = 0x%x\n", event); 275*6387f866SBrian Austin } 276*6387f866SBrian Austin return 0; 277*6387f866SBrian Austin } 278*6387f866SBrian Austin 279*6387f866SBrian Austin static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); 280*6387f866SBrian Austin static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); 281*6387f866SBrian Austin 282*6387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_aud_controls[] = { 283*6387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL, 284*6387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 285*6387f866SBrian Austin SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0, 286*6387f866SBrian Austin amp_gain_tlv), 287*6387f866SBrian Austin SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0, 288*6387f866SBrian Austin amp_gain_tlv), 289*6387f866SBrian Austin }; 290*6387f866SBrian Austin 291*6387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_adv_controls[] = { 292*6387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL, 293*6387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 294*6387f866SBrian Austin SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0, 295*6387f866SBrian Austin amp_gain_tlv), 296*6387f866SBrian Austin }; 297*6387f866SBrian Austin 298*6387f866SBrian Austin static const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = { 299*6387f866SBrian Austin SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1, 300*6387f866SBrian Austin cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU | 301*6387f866SBrian Austin SND_SOC_DAPM_POST_PMD), 302*6387f866SBrian Austin SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1), 303*6387f866SBrian Austin 304*6387f866SBrian Austin SND_SOC_DAPM_OUTPUT("SPK"), 305*6387f866SBrian Austin 306*6387f866SBrian Austin SND_SOC_DAPM_INPUT("VP"), 307*6387f866SBrian Austin SND_SOC_DAPM_INPUT("VBST"), 308*6387f866SBrian Austin SND_SOC_DAPM_INPUT("ISENSE"), 309*6387f866SBrian Austin SND_SOC_DAPM_INPUT("VSENSE"), 310*6387f866SBrian Austin 311*6387f866SBrian Austin SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1), 312*6387f866SBrian Austin SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1), 313*6387f866SBrian Austin SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1), 314*6387f866SBrian Austin SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1), 315*6387f866SBrian Austin SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1), 316*6387f866SBrian Austin 317*6387f866SBrian Austin SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0, 318*6387f866SBrian Austin cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU | 319*6387f866SBrian Austin SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU | 320*6387f866SBrian Austin SND_SOC_DAPM_PRE_PMD), 321*6387f866SBrian Austin }; 322*6387f866SBrian Austin 323*6387f866SBrian Austin static const struct snd_soc_dapm_route cs35l35_audio_map[] = { 324*6387f866SBrian Austin {"VPMON ADC", NULL, "VP"}, 325*6387f866SBrian Austin {"VBSTMON ADC", NULL, "VBST"}, 326*6387f866SBrian Austin {"IMON ADC", NULL, "ISENSE"}, 327*6387f866SBrian Austin {"VMON ADC", NULL, "VSENSE"}, 328*6387f866SBrian Austin {"SDOUT", NULL, "IMON ADC"}, 329*6387f866SBrian Austin {"SDOUT", NULL, "VMON ADC"}, 330*6387f866SBrian Austin {"SDOUT", NULL, "VBSTMON ADC"}, 331*6387f866SBrian Austin {"SDOUT", NULL, "VPMON ADC"}, 332*6387f866SBrian Austin {"AMP Capture", NULL, "SDOUT"}, 333*6387f866SBrian Austin 334*6387f866SBrian Austin {"SDIN", NULL, "AMP Playback"}, 335*6387f866SBrian Austin {"CLASS H", NULL, "SDIN"}, 336*6387f866SBrian Austin {"Main AMP", NULL, "CLASS H"}, 337*6387f866SBrian Austin {"SPK", NULL, "Main AMP"}, 338*6387f866SBrian Austin }; 339*6387f866SBrian Austin 340*6387f866SBrian Austin static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 341*6387f866SBrian Austin { 342*6387f866SBrian Austin struct snd_soc_codec *codec = codec_dai->codec; 343*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 344*6387f866SBrian Austin 345*6387f866SBrian Austin switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 346*6387f866SBrian Austin case SND_SOC_DAIFMT_CBM_CFM: 347*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 348*6387f866SBrian Austin CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT); 349*6387f866SBrian Austin cs35l35->slave_mode = false; 350*6387f866SBrian Austin break; 351*6387f866SBrian Austin case SND_SOC_DAIFMT_CBS_CFS: 352*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 353*6387f866SBrian Austin CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT); 354*6387f866SBrian Austin cs35l35->slave_mode = true; 355*6387f866SBrian Austin break; 356*6387f866SBrian Austin default: 357*6387f866SBrian Austin return -EINVAL; 358*6387f866SBrian Austin } 359*6387f866SBrian Austin 360*6387f866SBrian Austin switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 361*6387f866SBrian Austin case SND_SOC_DAIFMT_I2S: 362*6387f866SBrian Austin cs35l35->i2s_mode = true; 363*6387f866SBrian Austin cs35l35->pdm_mode = false; 364*6387f866SBrian Austin break; 365*6387f866SBrian Austin case SND_SOC_DAIFMT_PDM: 366*6387f866SBrian Austin cs35l35->pdm_mode = true; 367*6387f866SBrian Austin cs35l35->i2s_mode = false; 368*6387f866SBrian Austin break; 369*6387f866SBrian Austin default: 370*6387f866SBrian Austin return -EINVAL; 371*6387f866SBrian Austin } 372*6387f866SBrian Austin 373*6387f866SBrian Austin return 0; 374*6387f866SBrian Austin } 375*6387f866SBrian Austin 376*6387f866SBrian Austin struct cs35l35_sysclk_config { 377*6387f866SBrian Austin int sysclk; 378*6387f866SBrian Austin int srate; 379*6387f866SBrian Austin u8 clk_cfg; 380*6387f866SBrian Austin }; 381*6387f866SBrian Austin 382*6387f866SBrian Austin static struct cs35l35_sysclk_config cs35l35_clk_ctl[] = { 383*6387f866SBrian Austin 384*6387f866SBrian Austin /* SYSCLK, Sample Rate, Serial Port Cfg */ 385*6387f866SBrian Austin {5644800, 44100, 0x00}, 386*6387f866SBrian Austin {5644800, 88200, 0x40}, 387*6387f866SBrian Austin {6144000, 48000, 0x10}, 388*6387f866SBrian Austin {6144000, 96000, 0x50}, 389*6387f866SBrian Austin {11289600, 44100, 0x01}, 390*6387f866SBrian Austin {11289600, 88200, 0x41}, 391*6387f866SBrian Austin {11289600, 176400, 0x81}, 392*6387f866SBrian Austin {12000000, 44100, 0x03}, 393*6387f866SBrian Austin {12000000, 48000, 0x13}, 394*6387f866SBrian Austin {12000000, 88200, 0x43}, 395*6387f866SBrian Austin {12000000, 96000, 0x53}, 396*6387f866SBrian Austin {12000000, 176400, 0x83}, 397*6387f866SBrian Austin {12000000, 192000, 0x93}, 398*6387f866SBrian Austin {12288000, 48000, 0x11}, 399*6387f866SBrian Austin {12288000, 96000, 0x51}, 400*6387f866SBrian Austin {12288000, 192000, 0x91}, 401*6387f866SBrian Austin {13000000, 44100, 0x07}, 402*6387f866SBrian Austin {13000000, 48000, 0x17}, 403*6387f866SBrian Austin {13000000, 88200, 0x47}, 404*6387f866SBrian Austin {13000000, 96000, 0x57}, 405*6387f866SBrian Austin {13000000, 176400, 0x87}, 406*6387f866SBrian Austin {13000000, 192000, 0x97}, 407*6387f866SBrian Austin {22579200, 44100, 0x02}, 408*6387f866SBrian Austin {22579200, 88200, 0x42}, 409*6387f866SBrian Austin {22579200, 176400, 0x82}, 410*6387f866SBrian Austin {24000000, 44100, 0x0B}, 411*6387f866SBrian Austin {24000000, 48000, 0x1B}, 412*6387f866SBrian Austin {24000000, 88200, 0x4B}, 413*6387f866SBrian Austin {24000000, 96000, 0x5B}, 414*6387f866SBrian Austin {24000000, 176400, 0x8B}, 415*6387f866SBrian Austin {24000000, 192000, 0x9B}, 416*6387f866SBrian Austin {24576000, 48000, 0x12}, 417*6387f866SBrian Austin {24576000, 96000, 0x52}, 418*6387f866SBrian Austin {24576000, 192000, 0x92}, 419*6387f866SBrian Austin {26000000, 44100, 0x0F}, 420*6387f866SBrian Austin {26000000, 48000, 0x1F}, 421*6387f866SBrian Austin {26000000, 88200, 0x4F}, 422*6387f866SBrian Austin {26000000, 96000, 0x5F}, 423*6387f866SBrian Austin {26000000, 176400, 0x8F}, 424*6387f866SBrian Austin {26000000, 192000, 0x9F}, 425*6387f866SBrian Austin }; 426*6387f866SBrian Austin 427*6387f866SBrian Austin static int cs35l35_get_clk_config(int sysclk, int srate) 428*6387f866SBrian Austin { 429*6387f866SBrian Austin int i; 430*6387f866SBrian Austin 431*6387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) { 432*6387f866SBrian Austin if (cs35l35_clk_ctl[i].sysclk == sysclk && 433*6387f866SBrian Austin cs35l35_clk_ctl[i].srate == srate) 434*6387f866SBrian Austin return cs35l35_clk_ctl[i].clk_cfg; 435*6387f866SBrian Austin } 436*6387f866SBrian Austin return -EINVAL; 437*6387f866SBrian Austin } 438*6387f866SBrian Austin 439*6387f866SBrian Austin static int cs35l35_hw_params(struct snd_pcm_substream *substream, 440*6387f866SBrian Austin struct snd_pcm_hw_params *params, 441*6387f866SBrian Austin struct snd_soc_dai *dai) 442*6387f866SBrian Austin { 443*6387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 444*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 445*6387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 446*6387f866SBrian Austin int srate = params_rate(params); 447*6387f866SBrian Austin int ret = 0; 448*6387f866SBrian Austin u8 sp_sclks; 449*6387f866SBrian Austin int audin_format; 450*6387f866SBrian Austin int errata_chk; 451*6387f866SBrian Austin 452*6387f866SBrian Austin int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate); 453*6387f866SBrian Austin 454*6387f866SBrian Austin if (clk_ctl < 0) { 455*6387f866SBrian Austin dev_err(codec->dev, "Invalid CLK:Rate %d:%d\n", 456*6387f866SBrian Austin cs35l35->sysclk, srate); 457*6387f866SBrian Austin return -EINVAL; 458*6387f866SBrian Austin } 459*6387f866SBrian Austin 460*6387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2, 461*6387f866SBrian Austin CS35L35_CLK_CTL2_MASK, clk_ctl); 462*6387f866SBrian Austin if (ret != 0) { 463*6387f866SBrian Austin dev_err(codec->dev, "Failed to set port config %d\n", ret); 464*6387f866SBrian Austin return ret; 465*6387f866SBrian Austin } 466*6387f866SBrian Austin 467*6387f866SBrian Austin /* 468*6387f866SBrian Austin * Rev A0 Errata 469*6387f866SBrian Austin * When configured for the weak-drive detection path (CH_WKFET_DIS = 0) 470*6387f866SBrian Austin * the Class H algorithm does not enable weak-drive operation for 471*6387f866SBrian Austin * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10 472*6387f866SBrian Austin */ 473*6387f866SBrian Austin errata_chk = clk_ctl & CS35L35_SP_RATE_MASK; 474*6387f866SBrian Austin 475*6387f866SBrian Austin if (classh->classh_wk_fet_disable == 0x00 && 476*6387f866SBrian Austin (errata_chk == 0x01 || errata_chk == 0x03)) { 477*6387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 478*6387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 479*6387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 480*6387f866SBrian Austin 0 << CS35L35_CH_WKFET_DEL_SHIFT); 481*6387f866SBrian Austin if (ret != 0) { 482*6387f866SBrian Austin dev_err(codec->dev, "Failed to set fet config %d\n", 483*6387f866SBrian Austin ret); 484*6387f866SBrian Austin return ret; 485*6387f866SBrian Austin } 486*6387f866SBrian Austin } 487*6387f866SBrian Austin 488*6387f866SBrian Austin /* 489*6387f866SBrian Austin * You can pull more Monitor data from the SDOUT pin than going to SDIN 490*6387f866SBrian Austin * Just make sure your SCLK is fast enough to fill the frame 491*6387f866SBrian Austin */ 492*6387f866SBrian Austin if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 493*6387f866SBrian Austin switch (params_width(params)) { 494*6387f866SBrian Austin case 8: 495*6387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_8; 496*6387f866SBrian Austin break; 497*6387f866SBrian Austin case 16: 498*6387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_16; 499*6387f866SBrian Austin break; 500*6387f866SBrian Austin case 24: 501*6387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_24; 502*6387f866SBrian Austin break; 503*6387f866SBrian Austin default: 504*6387f866SBrian Austin dev_err(codec->dev, "Unsupported Width %d\n", 505*6387f866SBrian Austin params_width(params)); 506*6387f866SBrian Austin return -EINVAL; 507*6387f866SBrian Austin } 508*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 509*6387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 510*6387f866SBrian Austin CS35L35_AUDIN_DEPTH_MASK, 511*6387f866SBrian Austin audin_format << 512*6387f866SBrian Austin CS35L35_AUDIN_DEPTH_SHIFT); 513*6387f866SBrian Austin if (cs35l35->pdata.stereo) { 514*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 515*6387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 516*6387f866SBrian Austin CS35L35_ADVIN_DEPTH_MASK, 517*6387f866SBrian Austin audin_format << 518*6387f866SBrian Austin CS35L35_ADVIN_DEPTH_SHIFT); 519*6387f866SBrian Austin } 520*6387f866SBrian Austin } 521*6387f866SBrian Austin 522*6387f866SBrian Austin if (cs35l35->i2s_mode) { 523*6387f866SBrian Austin /* We have to take the SCLK to derive num sclks 524*6387f866SBrian Austin * to configure the CLOCK_CTL3 register correctly 525*6387f866SBrian Austin */ 526*6387f866SBrian Austin if ((cs35l35->sclk / srate) % 4) { 527*6387f866SBrian Austin dev_err(codec->dev, "Unsupported sclk/fs ratio %d:%d\n", 528*6387f866SBrian Austin cs35l35->sclk, srate); 529*6387f866SBrian Austin return -EINVAL; 530*6387f866SBrian Austin } 531*6387f866SBrian Austin sp_sclks = ((cs35l35->sclk / srate) / 4) - 1; 532*6387f866SBrian Austin 533*6387f866SBrian Austin /* Only certain ratios are supported in I2S Slave Mode */ 534*6387f866SBrian Austin if (cs35l35->slave_mode) { 535*6387f866SBrian Austin switch (sp_sclks) { 536*6387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 537*6387f866SBrian Austin case CS35L35_SP_SCLKS_48FS: 538*6387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 539*6387f866SBrian Austin break; 540*6387f866SBrian Austin default: 541*6387f866SBrian Austin dev_err(codec->dev, "ratio not supported\n"); 542*6387f866SBrian Austin return -EINVAL; 543*6387f866SBrian Austin }; 544*6387f866SBrian Austin } else { 545*6387f866SBrian Austin /* Only certain ratios supported in I2S MASTER Mode */ 546*6387f866SBrian Austin switch (sp_sclks) { 547*6387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 548*6387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 549*6387f866SBrian Austin break; 550*6387f866SBrian Austin default: 551*6387f866SBrian Austin dev_err(codec->dev, "ratio not supported\n"); 552*6387f866SBrian Austin return -EINVAL; 553*6387f866SBrian Austin }; 554*6387f866SBrian Austin } 555*6387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 556*6387f866SBrian Austin CS35L35_CLK_CTL3, 557*6387f866SBrian Austin CS35L35_SP_SCLKS_MASK, sp_sclks << 558*6387f866SBrian Austin CS35L35_SP_SCLKS_SHIFT); 559*6387f866SBrian Austin if (ret != 0) { 560*6387f866SBrian Austin dev_err(codec->dev, "Failed to set fsclk %d\n", ret); 561*6387f866SBrian Austin return ret; 562*6387f866SBrian Austin } 563*6387f866SBrian Austin } 564*6387f866SBrian Austin 565*6387f866SBrian Austin return ret; 566*6387f866SBrian Austin } 567*6387f866SBrian Austin 568*6387f866SBrian Austin static const unsigned int cs35l35_src_rates[] = { 569*6387f866SBrian Austin 44100, 48000, 88200, 96000, 176400, 192000 570*6387f866SBrian Austin }; 571*6387f866SBrian Austin 572*6387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_constraints = { 573*6387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_src_rates), 574*6387f866SBrian Austin .list = cs35l35_src_rates, 575*6387f866SBrian Austin }; 576*6387f866SBrian Austin 577*6387f866SBrian Austin static int cs35l35_pcm_startup(struct snd_pcm_substream *substream, 578*6387f866SBrian Austin struct snd_soc_dai *dai) 579*6387f866SBrian Austin { 580*6387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 581*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 582*6387f866SBrian Austin 583*6387f866SBrian Austin if (!substream->runtime) 584*6387f866SBrian Austin return 0; 585*6387f866SBrian Austin 586*6387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 587*6387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints); 588*6387f866SBrian Austin 589*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 590*6387f866SBrian Austin CS35L35_PDM_MODE_MASK, 591*6387f866SBrian Austin 0 << CS35L35_PDM_MODE_SHIFT); 592*6387f866SBrian Austin 593*6387f866SBrian Austin return 0; 594*6387f866SBrian Austin } 595*6387f866SBrian Austin 596*6387f866SBrian Austin static const unsigned int cs35l35_pdm_rates[] = { 597*6387f866SBrian Austin 44100, 48000, 88200, 96000 598*6387f866SBrian Austin }; 599*6387f866SBrian Austin 600*6387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = { 601*6387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_pdm_rates), 602*6387f866SBrian Austin .list = cs35l35_pdm_rates, 603*6387f866SBrian Austin }; 604*6387f866SBrian Austin 605*6387f866SBrian Austin static int cs35l35_pdm_startup(struct snd_pcm_substream *substream, 606*6387f866SBrian Austin struct snd_soc_dai *dai) 607*6387f866SBrian Austin { 608*6387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 609*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 610*6387f866SBrian Austin 611*6387f866SBrian Austin if (!substream->runtime) 612*6387f866SBrian Austin return 0; 613*6387f866SBrian Austin 614*6387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 615*6387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, 616*6387f866SBrian Austin &cs35l35_pdm_constraints); 617*6387f866SBrian Austin 618*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 619*6387f866SBrian Austin CS35L35_PDM_MODE_MASK, 620*6387f866SBrian Austin 1 << CS35L35_PDM_MODE_SHIFT); 621*6387f866SBrian Austin 622*6387f866SBrian Austin return 0; 623*6387f866SBrian Austin } 624*6387f866SBrian Austin 625*6387f866SBrian Austin static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai, 626*6387f866SBrian Austin int clk_id, unsigned int freq, int dir) 627*6387f866SBrian Austin { 628*6387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 629*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 630*6387f866SBrian Austin 631*6387f866SBrian Austin /* Need the SCLK Frequency regardless of sysclk source for I2S */ 632*6387f866SBrian Austin cs35l35->sclk = freq; 633*6387f866SBrian Austin 634*6387f866SBrian Austin return 0; 635*6387f866SBrian Austin } 636*6387f866SBrian Austin 637*6387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_ops = { 638*6387f866SBrian Austin .startup = cs35l35_pcm_startup, 639*6387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 640*6387f866SBrian Austin .hw_params = cs35l35_hw_params, 641*6387f866SBrian Austin .set_sysclk = cs35l35_dai_set_sysclk, 642*6387f866SBrian Austin }; 643*6387f866SBrian Austin 644*6387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_pdm_ops = { 645*6387f866SBrian Austin .startup = cs35l35_pdm_startup, 646*6387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 647*6387f866SBrian Austin .hw_params = cs35l35_hw_params, 648*6387f866SBrian Austin }; 649*6387f866SBrian Austin 650*6387f866SBrian Austin static struct snd_soc_dai_driver cs35l35_dai[] = { 651*6387f866SBrian Austin { 652*6387f866SBrian Austin .name = "cs35l35-pcm", 653*6387f866SBrian Austin .id = 0, 654*6387f866SBrian Austin .playback = { 655*6387f866SBrian Austin .stream_name = "AMP Playback", 656*6387f866SBrian Austin .channels_min = 1, 657*6387f866SBrian Austin .channels_max = 8, 658*6387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 659*6387f866SBrian Austin .formats = CS35L35_FORMATS, 660*6387f866SBrian Austin }, 661*6387f866SBrian Austin .capture = { 662*6387f866SBrian Austin .stream_name = "AMP Capture", 663*6387f866SBrian Austin .channels_min = 1, 664*6387f866SBrian Austin .channels_max = 8, 665*6387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 666*6387f866SBrian Austin .formats = CS35L35_FORMATS, 667*6387f866SBrian Austin }, 668*6387f866SBrian Austin .ops = &cs35l35_ops, 669*6387f866SBrian Austin .symmetric_rates = 1, 670*6387f866SBrian Austin }, 671*6387f866SBrian Austin { 672*6387f866SBrian Austin .name = "cs35l35-pdm", 673*6387f866SBrian Austin .id = 1, 674*6387f866SBrian Austin .playback = { 675*6387f866SBrian Austin .stream_name = "PDM Playback", 676*6387f866SBrian Austin .channels_min = 1, 677*6387f866SBrian Austin .channels_max = 2, 678*6387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 679*6387f866SBrian Austin .formats = CS35L35_FORMATS, 680*6387f866SBrian Austin }, 681*6387f866SBrian Austin .ops = &cs35l35_pdm_ops, 682*6387f866SBrian Austin }, 683*6387f866SBrian Austin }; 684*6387f866SBrian Austin 685*6387f866SBrian Austin static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec, 686*6387f866SBrian Austin int clk_id, int source, unsigned int freq, 687*6387f866SBrian Austin int dir) 688*6387f866SBrian Austin { 689*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 690*6387f866SBrian Austin int clksrc; 691*6387f866SBrian Austin int ret = 0; 692*6387f866SBrian Austin 693*6387f866SBrian Austin switch (clk_id) { 694*6387f866SBrian Austin case 0: 695*6387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_MCLK; 696*6387f866SBrian Austin break; 697*6387f866SBrian Austin case 1: 698*6387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_SCLK; 699*6387f866SBrian Austin break; 700*6387f866SBrian Austin case 2: 701*6387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_PDM; 702*6387f866SBrian Austin break; 703*6387f866SBrian Austin default: 704*6387f866SBrian Austin dev_err(codec->dev, "Invalid CLK Source\n"); 705*6387f866SBrian Austin return -EINVAL; 706*6387f866SBrian Austin }; 707*6387f866SBrian Austin 708*6387f866SBrian Austin switch (freq) { 709*6387f866SBrian Austin case 5644800: 710*6387f866SBrian Austin case 6144000: 711*6387f866SBrian Austin case 11289600: 712*6387f866SBrian Austin case 12000000: 713*6387f866SBrian Austin case 12288000: 714*6387f866SBrian Austin case 13000000: 715*6387f866SBrian Austin case 22579200: 716*6387f866SBrian Austin case 24000000: 717*6387f866SBrian Austin case 24576000: 718*6387f866SBrian Austin case 26000000: 719*6387f866SBrian Austin cs35l35->sysclk = freq; 720*6387f866SBrian Austin break; 721*6387f866SBrian Austin default: 722*6387f866SBrian Austin dev_err(codec->dev, "Invalid CLK Frequency Input : %d\n", freq); 723*6387f866SBrian Austin return -EINVAL; 724*6387f866SBrian Austin } 725*6387f866SBrian Austin 726*6387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 727*6387f866SBrian Austin CS35L35_CLK_SOURCE_MASK, 728*6387f866SBrian Austin clksrc << CS35L35_CLK_SOURCE_SHIFT); 729*6387f866SBrian Austin if (ret != 0) { 730*6387f866SBrian Austin dev_err(codec->dev, "Failed to set sysclk %d\n", ret); 731*6387f866SBrian Austin return ret; 732*6387f866SBrian Austin } 733*6387f866SBrian Austin 734*6387f866SBrian Austin return ret; 735*6387f866SBrian Austin } 736*6387f866SBrian Austin 737*6387f866SBrian Austin static int cs35l35_codec_probe(struct snd_soc_codec *codec) 738*6387f866SBrian Austin { 739*6387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 740*6387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 741*6387f866SBrian Austin struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; 742*6387f866SBrian Austin int ret; 743*6387f866SBrian Austin 744*6387f866SBrian Austin cs35l35->codec = codec; 745*6387f866SBrian Austin 746*6387f866SBrian Austin /* Set Platform Data */ 747*6387f866SBrian Austin if (cs35l35->pdata.bst_vctl) 748*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, 749*6387f866SBrian Austin CS35L35_BST_CTL_MASK, 750*6387f866SBrian Austin cs35l35->pdata.bst_vctl); 751*6387f866SBrian Austin 752*6387f866SBrian Austin if (cs35l35->pdata.bst_ipk) 753*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I, 754*6387f866SBrian Austin CS35L35_BST_IPK_MASK, 755*6387f866SBrian Austin cs35l35->pdata.bst_ipk << 756*6387f866SBrian Austin CS35L35_BST_IPK_SHIFT); 757*6387f866SBrian Austin 758*6387f866SBrian Austin if (cs35l35->pdata.gain_zc) 759*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 760*6387f866SBrian Austin CS35L35_AMP_GAIN_ZC_MASK, 761*6387f866SBrian Austin cs35l35->pdata.gain_zc << 762*6387f866SBrian Austin CS35L35_AMP_GAIN_ZC_SHIFT); 763*6387f866SBrian Austin 764*6387f866SBrian Austin if (cs35l35->pdata.aud_channel) 765*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 766*6387f866SBrian Austin CS35L35_AUDIN_RXLOC_CTL, 767*6387f866SBrian Austin CS35L35_AUD_IN_LR_MASK, 768*6387f866SBrian Austin cs35l35->pdata.aud_channel << 769*6387f866SBrian Austin CS35L35_AUD_IN_LR_SHIFT); 770*6387f866SBrian Austin 771*6387f866SBrian Austin if (cs35l35->pdata.stereo) { 772*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 773*6387f866SBrian Austin CS35L35_ADVIN_RXLOC_CTL, 774*6387f866SBrian Austin CS35L35_ADV_IN_LR_MASK, 775*6387f866SBrian Austin cs35l35->pdata.adv_channel << 776*6387f866SBrian Austin CS35L35_ADV_IN_LR_SHIFT); 777*6387f866SBrian Austin if (cs35l35->pdata.shared_bst) 778*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL, 779*6387f866SBrian Austin CS35L35_CH_STEREO_MASK, 780*6387f866SBrian Austin 1 << CS35L35_CH_STEREO_SHIFT); 781*6387f866SBrian Austin ret = snd_soc_add_codec_controls(codec, cs35l35_adv_controls, 782*6387f866SBrian Austin ARRAY_SIZE(cs35l35_adv_controls)); 783*6387f866SBrian Austin if (ret) 784*6387f866SBrian Austin return ret; 785*6387f866SBrian Austin } 786*6387f866SBrian Austin 787*6387f866SBrian Austin if (cs35l35->pdata.sp_drv_str) 788*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 789*6387f866SBrian Austin CS35L35_SP_DRV_MASK, 790*6387f866SBrian Austin cs35l35->pdata.sp_drv_str << 791*6387f866SBrian Austin CS35L35_SP_DRV_SHIFT); 792*6387f866SBrian Austin 793*6387f866SBrian Austin if (classh->classh_algo_enable) { 794*6387f866SBrian Austin if (classh->classh_bst_override) 795*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 796*6387f866SBrian Austin CS35L35_CLASS_H_CTL, 797*6387f866SBrian Austin CS35L35_CH_BST_OVR_MASK, 798*6387f866SBrian Austin classh->classh_bst_override << 799*6387f866SBrian Austin CS35L35_CH_BST_OVR_SHIFT); 800*6387f866SBrian Austin if (classh->classh_bst_max_limit) 801*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 802*6387f866SBrian Austin CS35L35_CLASS_H_CTL, 803*6387f866SBrian Austin CS35L35_CH_BST_LIM_MASK, 804*6387f866SBrian Austin classh->classh_bst_max_limit << 805*6387f866SBrian Austin CS35L35_CH_BST_LIM_SHIFT); 806*6387f866SBrian Austin if (classh->classh_mem_depth) 807*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 808*6387f866SBrian Austin CS35L35_CLASS_H_CTL, 809*6387f866SBrian Austin CS35L35_CH_MEM_DEPTH_MASK, 810*6387f866SBrian Austin classh->classh_mem_depth << 811*6387f866SBrian Austin CS35L35_CH_MEM_DEPTH_SHIFT); 812*6387f866SBrian Austin if (classh->classh_headroom) 813*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 814*6387f866SBrian Austin CS35L35_CLASS_H_HEADRM_CTL, 815*6387f866SBrian Austin CS35L35_CH_HDRM_CTL_MASK, 816*6387f866SBrian Austin classh->classh_headroom << 817*6387f866SBrian Austin CS35L35_CH_HDRM_CTL_SHIFT); 818*6387f866SBrian Austin if (classh->classh_release_rate) 819*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 820*6387f866SBrian Austin CS35L35_CLASS_H_RELEASE_RATE, 821*6387f866SBrian Austin CS35L35_CH_REL_RATE_MASK, 822*6387f866SBrian Austin classh->classh_release_rate << 823*6387f866SBrian Austin CS35L35_CH_REL_RATE_SHIFT); 824*6387f866SBrian Austin if (classh->classh_wk_fet_disable) 825*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 826*6387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 827*6387f866SBrian Austin CS35L35_CH_WKFET_DIS_MASK, 828*6387f866SBrian Austin classh->classh_wk_fet_disable << 829*6387f866SBrian Austin CS35L35_CH_WKFET_DIS_SHIFT); 830*6387f866SBrian Austin if (classh->classh_wk_fet_delay) 831*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 832*6387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 833*6387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 834*6387f866SBrian Austin classh->classh_wk_fet_delay << 835*6387f866SBrian Austin CS35L35_CH_WKFET_DEL_SHIFT); 836*6387f866SBrian Austin if (classh->classh_wk_fet_thld) 837*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 838*6387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 839*6387f866SBrian Austin CS35L35_CH_WKFET_THLD_MASK, 840*6387f866SBrian Austin classh->classh_wk_fet_thld << 841*6387f866SBrian Austin CS35L35_CH_WKFET_THLD_SHIFT); 842*6387f866SBrian Austin if (classh->classh_vpch_auto) 843*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 844*6387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 845*6387f866SBrian Austin CS35L35_CH_VP_AUTO_MASK, 846*6387f866SBrian Austin classh->classh_vpch_auto << 847*6387f866SBrian Austin CS35L35_CH_VP_AUTO_SHIFT); 848*6387f866SBrian Austin if (classh->classh_vpch_rate) 849*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 850*6387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 851*6387f866SBrian Austin CS35L35_CH_VP_RATE_MASK, 852*6387f866SBrian Austin classh->classh_vpch_rate << 853*6387f866SBrian Austin CS35L35_CH_VP_RATE_SHIFT); 854*6387f866SBrian Austin if (classh->classh_vpch_man) 855*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 856*6387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 857*6387f866SBrian Austin CS35L35_CH_VP_MAN_MASK, 858*6387f866SBrian Austin classh->classh_vpch_man << 859*6387f866SBrian Austin CS35L35_CH_VP_MAN_SHIFT); 860*6387f866SBrian Austin } 861*6387f866SBrian Austin 862*6387f866SBrian Austin if (monitor_config->is_present) { 863*6387f866SBrian Austin if (monitor_config->vmon_specs) { 864*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 865*6387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 866*6387f866SBrian Austin CS35L35_VMON_DEPTH_MASK, 867*6387f866SBrian Austin monitor_config->vmon_dpth << 868*6387f866SBrian Austin CS35L35_VMON_DEPTH_SHIFT); 869*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 870*6387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 871*6387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 872*6387f866SBrian Austin monitor_config->vmon_loc << 873*6387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 874*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 875*6387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 876*6387f866SBrian Austin CS35L35_MON_FRM_MASK, 877*6387f866SBrian Austin monitor_config->vmon_frm << 878*6387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 879*6387f866SBrian Austin } 880*6387f866SBrian Austin if (monitor_config->imon_specs) { 881*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 882*6387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 883*6387f866SBrian Austin CS35L35_IMON_DEPTH_MASK, 884*6387f866SBrian Austin monitor_config->imon_dpth << 885*6387f866SBrian Austin CS35L35_IMON_DEPTH_SHIFT); 886*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 887*6387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 888*6387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 889*6387f866SBrian Austin monitor_config->imon_loc << 890*6387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 891*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 892*6387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 893*6387f866SBrian Austin CS35L35_MON_FRM_MASK, 894*6387f866SBrian Austin monitor_config->imon_frm << 895*6387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 896*6387f866SBrian Austin } 897*6387f866SBrian Austin if (monitor_config->vpmon_specs) { 898*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 899*6387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 900*6387f866SBrian Austin CS35L35_VPMON_DEPTH_MASK, 901*6387f866SBrian Austin monitor_config->vpmon_dpth << 902*6387f866SBrian Austin CS35L35_VPMON_DEPTH_SHIFT); 903*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 904*6387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 905*6387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 906*6387f866SBrian Austin monitor_config->vpmon_loc << 907*6387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 908*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 909*6387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 910*6387f866SBrian Austin CS35L35_MON_FRM_MASK, 911*6387f866SBrian Austin monitor_config->vpmon_frm << 912*6387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 913*6387f866SBrian Austin } 914*6387f866SBrian Austin if (monitor_config->vbstmon_specs) { 915*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 916*6387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 917*6387f866SBrian Austin CS35L35_VBSTMON_DEPTH_MASK, 918*6387f866SBrian Austin monitor_config->vpmon_dpth << 919*6387f866SBrian Austin CS35L35_VBSTMON_DEPTH_SHIFT); 920*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 921*6387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 922*6387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 923*6387f866SBrian Austin monitor_config->vbstmon_loc << 924*6387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 925*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 926*6387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 927*6387f866SBrian Austin CS35L35_MON_FRM_MASK, 928*6387f866SBrian Austin monitor_config->vbstmon_frm << 929*6387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 930*6387f866SBrian Austin } 931*6387f866SBrian Austin if (monitor_config->vpbrstat_specs) { 932*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 933*6387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 934*6387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_MASK, 935*6387f866SBrian Austin monitor_config->vpbrstat_dpth << 936*6387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_SHIFT); 937*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 938*6387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 939*6387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 940*6387f866SBrian Austin monitor_config->vpbrstat_loc << 941*6387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 942*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 943*6387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 944*6387f866SBrian Austin CS35L35_MON_FRM_MASK, 945*6387f866SBrian Austin monitor_config->vpbrstat_frm << 946*6387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 947*6387f866SBrian Austin } 948*6387f866SBrian Austin if (monitor_config->zerofill_specs) { 949*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 950*6387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 951*6387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_MASK, 952*6387f866SBrian Austin monitor_config->zerofill_dpth << 953*6387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_SHIFT); 954*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 955*6387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 956*6387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 957*6387f866SBrian Austin monitor_config->zerofill_loc << 958*6387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 959*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 960*6387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 961*6387f866SBrian Austin CS35L35_MON_FRM_MASK, 962*6387f866SBrian Austin monitor_config->zerofill_frm << 963*6387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 964*6387f866SBrian Austin } 965*6387f866SBrian Austin } 966*6387f866SBrian Austin 967*6387f866SBrian Austin return ret; 968*6387f866SBrian Austin } 969*6387f866SBrian Austin 970*6387f866SBrian Austin static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = { 971*6387f866SBrian Austin .probe = cs35l35_codec_probe, 972*6387f866SBrian Austin .set_sysclk = cs35l35_codec_set_sysclk, 973*6387f866SBrian Austin .component_driver = { 974*6387f866SBrian Austin .dapm_widgets = cs35l35_dapm_widgets, 975*6387f866SBrian Austin .num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets), 976*6387f866SBrian Austin 977*6387f866SBrian Austin .dapm_routes = cs35l35_audio_map, 978*6387f866SBrian Austin .num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map), 979*6387f866SBrian Austin 980*6387f866SBrian Austin .controls = cs35l35_aud_controls, 981*6387f866SBrian Austin .num_controls = ARRAY_SIZE(cs35l35_aud_controls), 982*6387f866SBrian Austin }, 983*6387f866SBrian Austin 984*6387f866SBrian Austin }; 985*6387f866SBrian Austin 986*6387f866SBrian Austin static struct regmap_config cs35l35_regmap = { 987*6387f866SBrian Austin .reg_bits = 8, 988*6387f866SBrian Austin .val_bits = 8, 989*6387f866SBrian Austin 990*6387f866SBrian Austin .max_register = CS35L35_MAX_REGISTER, 991*6387f866SBrian Austin .reg_defaults = cs35l35_reg, 992*6387f866SBrian Austin .num_reg_defaults = ARRAY_SIZE(cs35l35_reg), 993*6387f866SBrian Austin .volatile_reg = cs35l35_volatile_register, 994*6387f866SBrian Austin .readable_reg = cs35l35_readable_register, 995*6387f866SBrian Austin .precious_reg = cs35l35_precious_register, 996*6387f866SBrian Austin .cache_type = REGCACHE_RBTREE, 997*6387f866SBrian Austin }; 998*6387f866SBrian Austin 999*6387f866SBrian Austin static irqreturn_t cs35l35_irq(int irq, void *data) 1000*6387f866SBrian Austin { 1001*6387f866SBrian Austin struct cs35l35_private *cs35l35 = data; 1002*6387f866SBrian Austin struct snd_soc_codec *codec = cs35l35->codec; 1003*6387f866SBrian Austin unsigned int sticky1, sticky2, sticky3, sticky4; 1004*6387f866SBrian Austin unsigned int mask1, mask2, mask3, mask4, current1; 1005*6387f866SBrian Austin 1006*6387f866SBrian Austin /* ack the irq by reading all status registers */ 1007*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4); 1008*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3); 1009*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2); 1010*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1); 1011*6387f866SBrian Austin 1012*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4); 1013*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3); 1014*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2); 1015*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1); 1016*6387f866SBrian Austin 1017*6387f866SBrian Austin /* Check to see if unmasked bits are active */ 1018*6387f866SBrian Austin if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) 1019*6387f866SBrian Austin && !(sticky4 & ~mask4)) 1020*6387f866SBrian Austin return IRQ_NONE; 1021*6387f866SBrian Austin 1022*6387f866SBrian Austin if (sticky2 & CS35L35_PDN_DONE) 1023*6387f866SBrian Austin complete(&cs35l35->pdn_done); 1024*6387f866SBrian Austin 1025*6387f866SBrian Austin /* read the current values */ 1026*6387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, ¤t1); 1027*6387f866SBrian Austin 1028*6387f866SBrian Austin /* handle the interrupts */ 1029*6387f866SBrian Austin if (sticky1 & CS35L35_CAL_ERR) { 1030*6387f866SBrian Austin dev_crit(codec->dev, "Calibration Error\n"); 1031*6387f866SBrian Austin 1032*6387f866SBrian Austin /* error is no longer asserted; safe to reset */ 1033*6387f866SBrian Austin if (!(current1 & CS35L35_CAL_ERR)) { 1034*6387f866SBrian Austin pr_debug("%s : Cal error release\n", __func__); 1035*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1036*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1037*6387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 1038*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1039*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1040*6387f866SBrian Austin CS35L35_CAL_ERR_RLS, 1041*6387f866SBrian Austin CS35L35_CAL_ERR_RLS); 1042*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1043*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1044*6387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 1045*6387f866SBrian Austin } 1046*6387f866SBrian Austin } 1047*6387f866SBrian Austin 1048*6387f866SBrian Austin if (sticky1 & CS35L35_AMP_SHORT) { 1049*6387f866SBrian Austin dev_crit(codec->dev, "AMP Short Error\n"); 1050*6387f866SBrian Austin /* error is no longer asserted; safe to reset */ 1051*6387f866SBrian Austin if (!(current1 & CS35L35_AMP_SHORT)) { 1052*6387f866SBrian Austin dev_dbg(codec->dev, "Amp short error release\n"); 1053*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1054*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1055*6387f866SBrian Austin CS35L35_SHORT_RLS, 0); 1056*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1057*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1058*6387f866SBrian Austin CS35L35_SHORT_RLS, 1059*6387f866SBrian Austin CS35L35_SHORT_RLS); 1060*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1061*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1062*6387f866SBrian Austin CS35L35_SHORT_RLS, 0); 1063*6387f866SBrian Austin } 1064*6387f866SBrian Austin } 1065*6387f866SBrian Austin 1066*6387f866SBrian Austin if (sticky1 & CS35L35_OTW) { 1067*6387f866SBrian Austin dev_warn(codec->dev, "Over temperature warning\n"); 1068*6387f866SBrian Austin 1069*6387f866SBrian Austin /* error is no longer asserted; safe to reset */ 1070*6387f866SBrian Austin if (!(current1 & CS35L35_OTW)) { 1071*6387f866SBrian Austin dev_dbg(codec->dev, "Over temperature warn release\n"); 1072*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1073*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1074*6387f866SBrian Austin CS35L35_OTW_RLS, 0); 1075*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1076*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1077*6387f866SBrian Austin CS35L35_OTW_RLS, 1078*6387f866SBrian Austin CS35L35_OTW_RLS); 1079*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1080*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1081*6387f866SBrian Austin CS35L35_OTW_RLS, 0); 1082*6387f866SBrian Austin } 1083*6387f866SBrian Austin } 1084*6387f866SBrian Austin 1085*6387f866SBrian Austin if (sticky1 & CS35L35_OTE) { 1086*6387f866SBrian Austin dev_crit(codec->dev, "Over temperature error\n"); 1087*6387f866SBrian Austin /* error is no longer asserted; safe to reset */ 1088*6387f866SBrian Austin if (!(current1 & CS35L35_OTE)) { 1089*6387f866SBrian Austin dev_dbg(codec->dev, "Over temperature error release\n"); 1090*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1091*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1092*6387f866SBrian Austin CS35L35_OTE_RLS, 0); 1093*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1094*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1095*6387f866SBrian Austin CS35L35_OTE_RLS, 1096*6387f866SBrian Austin CS35L35_OTE_RLS); 1097*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 1098*6387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 1099*6387f866SBrian Austin CS35L35_OTE_RLS, 0); 1100*6387f866SBrian Austin } 1101*6387f866SBrian Austin } 1102*6387f866SBrian Austin 1103*6387f866SBrian Austin if (sticky3 & CS35L35_BST_HIGH) { 1104*6387f866SBrian Austin dev_crit(codec->dev, "VBST error: powering off!\n"); 1105*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 1106*6387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 1107*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 1108*6387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 1109*6387f866SBrian Austin } 1110*6387f866SBrian Austin 1111*6387f866SBrian Austin if (sticky3 & CS35L35_LBST_SHORT) { 1112*6387f866SBrian Austin dev_crit(codec->dev, "LBST error: powering off!\n"); 1113*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 1114*6387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 1115*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 1116*6387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 1117*6387f866SBrian Austin } 1118*6387f866SBrian Austin 1119*6387f866SBrian Austin if (sticky2 & CS35L35_VPBR_ERR) 1120*6387f866SBrian Austin dev_dbg(codec->dev, "Error: Reactive Brownout\n"); 1121*6387f866SBrian Austin 1122*6387f866SBrian Austin if (sticky4 & CS35L35_VMON_OVFL) 1123*6387f866SBrian Austin dev_dbg(codec->dev, "Error: VMON overflow\n"); 1124*6387f866SBrian Austin 1125*6387f866SBrian Austin if (sticky4 & CS35L35_IMON_OVFL) 1126*6387f866SBrian Austin dev_dbg(codec->dev, "Error: IMON overflow\n"); 1127*6387f866SBrian Austin 1128*6387f866SBrian Austin return IRQ_HANDLED; 1129*6387f866SBrian Austin } 1130*6387f866SBrian Austin 1131*6387f866SBrian Austin 1132*6387f866SBrian Austin static int cs35l35_handle_of_data(struct i2c_client *i2c_client, 1133*6387f866SBrian Austin struct cs35l35_platform_data *pdata) 1134*6387f866SBrian Austin { 1135*6387f866SBrian Austin struct device_node *np = i2c_client->dev.of_node; 1136*6387f866SBrian Austin struct device_node *classh, *signal_format; 1137*6387f866SBrian Austin struct classh_cfg *classh_config = &pdata->classh_algo; 1138*6387f866SBrian Austin struct monitor_cfg *monitor_config = &pdata->mon_cfg; 1139*6387f866SBrian Austin unsigned int val32 = 0; 1140*6387f866SBrian Austin u8 monitor_array[3]; 1141*6387f866SBrian Austin int ret = 0; 1142*6387f866SBrian Austin 1143*6387f866SBrian Austin if (!np) 1144*6387f866SBrian Austin return 0; 1145*6387f866SBrian Austin 1146*6387f866SBrian Austin pdata->bst_pdn_fet_on = of_property_read_bool(np, 1147*6387f866SBrian Austin "cirrus,boost-pdn-fet-on"); 1148*6387f866SBrian Austin 1149*6387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32); 1150*6387f866SBrian Austin if (ret >= 0) { 1151*6387f866SBrian Austin if (val32 < 2600 || val32 > 9000) { 1152*6387f866SBrian Austin dev_err(&i2c_client->dev, 1153*6387f866SBrian Austin "Invalid Boost Voltage %d mV\n", val32); 1154*6387f866SBrian Austin return -EINVAL; 1155*6387f866SBrian Austin } 1156*6387f866SBrian Austin pdata->bst_vctl = ((val32 - 2600) / 100) + 1; 1157*6387f866SBrian Austin } 1158*6387f866SBrian Austin 1159*6387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32); 1160*6387f866SBrian Austin if (ret >= 0) { 1161*6387f866SBrian Austin if (val32 < 1680 || val32 > 4480) { 1162*6387f866SBrian Austin dev_err(&i2c_client->dev, 1163*6387f866SBrian Austin "Invalid Boost Peak Current %u mA\n", val32); 1164*6387f866SBrian Austin return -EINVAL; 1165*6387f866SBrian Austin } 1166*6387f866SBrian Austin 1167*6387f866SBrian Austin pdata->bst_ipk = (val32 - 1680) / 110; 1168*6387f866SBrian Austin } 1169*6387f866SBrian Austin 1170*6387f866SBrian Austin if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) 1171*6387f866SBrian Austin pdata->sp_drv_str = val32; 1172*6387f866SBrian Austin 1173*6387f866SBrian Austin pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); 1174*6387f866SBrian Austin 1175*6387f866SBrian Austin if (pdata->stereo) { 1176*6387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,audio-channel", &val32); 1177*6387f866SBrian Austin if (ret >= 0) 1178*6387f866SBrian Austin pdata->aud_channel = val32; 1179*6387f866SBrian Austin 1180*6387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,advisory-channel", 1181*6387f866SBrian Austin &val32); 1182*6387f866SBrian Austin if (ret >= 0) 1183*6387f866SBrian Austin pdata->adv_channel = val32; 1184*6387f866SBrian Austin 1185*6387f866SBrian Austin pdata->shared_bst = of_property_read_bool(np, 1186*6387f866SBrian Austin "cirrus,shared-boost"); 1187*6387f866SBrian Austin } 1188*6387f866SBrian Austin 1189*6387f866SBrian Austin pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); 1190*6387f866SBrian Austin 1191*6387f866SBrian Austin classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); 1192*6387f866SBrian Austin classh_config->classh_algo_enable = classh ? true : false; 1193*6387f866SBrian Austin 1194*6387f866SBrian Austin if (classh_config->classh_algo_enable) { 1195*6387f866SBrian Austin classh_config->classh_bst_override = 1196*6387f866SBrian Austin of_property_read_bool(np, "cirrus,classh-bst-overide"); 1197*6387f866SBrian Austin 1198*6387f866SBrian Austin ret = of_property_read_u32(classh, 1199*6387f866SBrian Austin "cirrus,classh-bst-max-limit", 1200*6387f866SBrian Austin &val32); 1201*6387f866SBrian Austin if (ret >= 0) { 1202*6387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 1203*6387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 1204*6387f866SBrian Austin } 1205*6387f866SBrian Austin 1206*6387f866SBrian Austin ret = of_property_read_u32(classh, 1207*6387f866SBrian Austin "cirrus,classh-bst-max-limit", 1208*6387f866SBrian Austin &val32); 1209*6387f866SBrian Austin if (ret >= 0) { 1210*6387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 1211*6387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 1212*6387f866SBrian Austin } 1213*6387f866SBrian Austin 1214*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-mem-depth", 1215*6387f866SBrian Austin &val32); 1216*6387f866SBrian Austin if (ret >= 0) { 1217*6387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 1218*6387f866SBrian Austin classh_config->classh_mem_depth = val32; 1219*6387f866SBrian Austin } 1220*6387f866SBrian Austin 1221*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-release-rate", 1222*6387f866SBrian Austin &val32); 1223*6387f866SBrian Austin if (ret >= 0) 1224*6387f866SBrian Austin classh_config->classh_release_rate = val32; 1225*6387f866SBrian Austin 1226*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-headroom", 1227*6387f866SBrian Austin &val32); 1228*6387f866SBrian Austin if (ret >= 0) { 1229*6387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 1230*6387f866SBrian Austin classh_config->classh_headroom = val32; 1231*6387f866SBrian Austin } 1232*6387f866SBrian Austin 1233*6387f866SBrian Austin ret = of_property_read_u32(classh, 1234*6387f866SBrian Austin "cirrus,classh-wk-fet-disable", 1235*6387f866SBrian Austin &val32); 1236*6387f866SBrian Austin if (ret >= 0) 1237*6387f866SBrian Austin classh_config->classh_wk_fet_disable = val32; 1238*6387f866SBrian Austin 1239*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay", 1240*6387f866SBrian Austin &val32); 1241*6387f866SBrian Austin if (ret >= 0) { 1242*6387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 1243*6387f866SBrian Austin classh_config->classh_wk_fet_delay = val32; 1244*6387f866SBrian Austin } 1245*6387f866SBrian Austin 1246*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld", 1247*6387f866SBrian Austin &val32); 1248*6387f866SBrian Austin if (ret >= 0) 1249*6387f866SBrian Austin classh_config->classh_wk_fet_thld = val32; 1250*6387f866SBrian Austin 1251*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto", 1252*6387f866SBrian Austin &val32); 1253*6387f866SBrian Austin if (ret >= 0) { 1254*6387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 1255*6387f866SBrian Austin classh_config->classh_vpch_auto = val32; 1256*6387f866SBrian Austin } 1257*6387f866SBrian Austin 1258*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate", 1259*6387f866SBrian Austin &val32); 1260*6387f866SBrian Austin if (ret >= 0) { 1261*6387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 1262*6387f866SBrian Austin classh_config->classh_vpch_rate = val32; 1263*6387f866SBrian Austin } 1264*6387f866SBrian Austin 1265*6387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-man", 1266*6387f866SBrian Austin &val32); 1267*6387f866SBrian Austin if (ret >= 0) 1268*6387f866SBrian Austin classh_config->classh_vpch_man = val32; 1269*6387f866SBrian Austin } 1270*6387f866SBrian Austin of_node_put(classh); 1271*6387f866SBrian Austin 1272*6387f866SBrian Austin /* frame depth location */ 1273*6387f866SBrian Austin signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format"); 1274*6387f866SBrian Austin monitor_config->is_present = signal_format ? true : false; 1275*6387f866SBrian Austin if (monitor_config->is_present) { 1276*6387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,imon", 1277*6387f866SBrian Austin monitor_array, ARRAY_SIZE(monitor_array)); 1278*6387f866SBrian Austin if (!ret) { 1279*6387f866SBrian Austin monitor_config->imon_specs = true; 1280*6387f866SBrian Austin monitor_config->imon_dpth = monitor_array[0]; 1281*6387f866SBrian Austin monitor_config->imon_loc = monitor_array[1]; 1282*6387f866SBrian Austin monitor_config->imon_frm = monitor_array[2]; 1283*6387f866SBrian Austin } 1284*6387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vmon", 1285*6387f866SBrian Austin monitor_array, ARRAY_SIZE(monitor_array)); 1286*6387f866SBrian Austin if (!ret) { 1287*6387f866SBrian Austin monitor_config->vmon_specs = true; 1288*6387f866SBrian Austin monitor_config->vmon_dpth = monitor_array[0]; 1289*6387f866SBrian Austin monitor_config->vmon_loc = monitor_array[1]; 1290*6387f866SBrian Austin monitor_config->vmon_frm = monitor_array[2]; 1291*6387f866SBrian Austin } 1292*6387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpmon", 1293*6387f866SBrian Austin monitor_array, ARRAY_SIZE(monitor_array)); 1294*6387f866SBrian Austin if (!ret) { 1295*6387f866SBrian Austin monitor_config->vpmon_specs = true; 1296*6387f866SBrian Austin monitor_config->vpmon_dpth = monitor_array[0]; 1297*6387f866SBrian Austin monitor_config->vpmon_loc = monitor_array[1]; 1298*6387f866SBrian Austin monitor_config->vpmon_frm = monitor_array[2]; 1299*6387f866SBrian Austin } 1300*6387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon", 1301*6387f866SBrian Austin monitor_array, ARRAY_SIZE(monitor_array)); 1302*6387f866SBrian Austin if (!ret) { 1303*6387f866SBrian Austin monitor_config->vbstmon_specs = true; 1304*6387f866SBrian Austin monitor_config->vbstmon_dpth = monitor_array[0]; 1305*6387f866SBrian Austin monitor_config->vbstmon_loc = monitor_array[1]; 1306*6387f866SBrian Austin monitor_config->vbstmon_frm = monitor_array[2]; 1307*6387f866SBrian Austin } 1308*6387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat", 1309*6387f866SBrian Austin monitor_array, ARRAY_SIZE(monitor_array)); 1310*6387f866SBrian Austin if (!ret) { 1311*6387f866SBrian Austin monitor_config->vpbrstat_specs = true; 1312*6387f866SBrian Austin monitor_config->vpbrstat_dpth = monitor_array[0]; 1313*6387f866SBrian Austin monitor_config->vpbrstat_loc = monitor_array[1]; 1314*6387f866SBrian Austin monitor_config->vpbrstat_frm = monitor_array[2]; 1315*6387f866SBrian Austin } 1316*6387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,zerofill", 1317*6387f866SBrian Austin monitor_array, ARRAY_SIZE(monitor_array)); 1318*6387f866SBrian Austin if (!ret) { 1319*6387f866SBrian Austin monitor_config->zerofill_specs = true; 1320*6387f866SBrian Austin monitor_config->zerofill_dpth = monitor_array[0]; 1321*6387f866SBrian Austin monitor_config->zerofill_loc = monitor_array[1]; 1322*6387f866SBrian Austin monitor_config->zerofill_frm = monitor_array[2]; 1323*6387f866SBrian Austin } 1324*6387f866SBrian Austin } 1325*6387f866SBrian Austin of_node_put(signal_format); 1326*6387f866SBrian Austin 1327*6387f866SBrian Austin return 0; 1328*6387f866SBrian Austin } 1329*6387f866SBrian Austin 1330*6387f866SBrian Austin /* Errata Rev A0 */ 1331*6387f866SBrian Austin static const struct reg_sequence cs35l35_errata_patch[] = { 1332*6387f866SBrian Austin 1333*6387f866SBrian Austin { 0x7F, 0x99 }, 1334*6387f866SBrian Austin { 0x00, 0x99 }, 1335*6387f866SBrian Austin { 0x52, 0x22 }, 1336*6387f866SBrian Austin { 0x04, 0x14 }, 1337*6387f866SBrian Austin { 0x6D, 0x44 }, 1338*6387f866SBrian Austin { 0x24, 0x10 }, 1339*6387f866SBrian Austin { 0x58, 0xC4 }, 1340*6387f866SBrian Austin { 0x00, 0x98 }, 1341*6387f866SBrian Austin { 0x18, 0x08 }, 1342*6387f866SBrian Austin { 0x00, 0x00 }, 1343*6387f866SBrian Austin { 0x7F, 0x00 }, 1344*6387f866SBrian Austin }; 1345*6387f866SBrian Austin 1346*6387f866SBrian Austin static int cs35l35_i2c_probe(struct i2c_client *i2c_client, 1347*6387f866SBrian Austin const struct i2c_device_id *id) 1348*6387f866SBrian Austin { 1349*6387f866SBrian Austin struct cs35l35_private *cs35l35; 1350*6387f866SBrian Austin struct cs35l35_platform_data *pdata = 1351*6387f866SBrian Austin dev_get_platdata(&i2c_client->dev); 1352*6387f866SBrian Austin int i; 1353*6387f866SBrian Austin int ret; 1354*6387f866SBrian Austin unsigned int devid = 0; 1355*6387f866SBrian Austin unsigned int reg; 1356*6387f866SBrian Austin 1357*6387f866SBrian Austin cs35l35 = devm_kzalloc(&i2c_client->dev, 1358*6387f866SBrian Austin sizeof(struct cs35l35_private), 1359*6387f866SBrian Austin GFP_KERNEL); 1360*6387f866SBrian Austin if (!cs35l35) 1361*6387f866SBrian Austin return -ENOMEM; 1362*6387f866SBrian Austin 1363*6387f866SBrian Austin i2c_set_clientdata(i2c_client, cs35l35); 1364*6387f866SBrian Austin cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); 1365*6387f866SBrian Austin if (IS_ERR(cs35l35->regmap)) { 1366*6387f866SBrian Austin ret = PTR_ERR(cs35l35->regmap); 1367*6387f866SBrian Austin dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); 1368*6387f866SBrian Austin goto err; 1369*6387f866SBrian Austin } 1370*6387f866SBrian Austin 1371*6387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) 1372*6387f866SBrian Austin cs35l35->supplies[i].supply = cs35l35_supplies[i]; 1373*6387f866SBrian Austin cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); 1374*6387f866SBrian Austin 1375*6387f866SBrian Austin ret = devm_regulator_bulk_get(&i2c_client->dev, 1376*6387f866SBrian Austin cs35l35->num_supplies, 1377*6387f866SBrian Austin cs35l35->supplies); 1378*6387f866SBrian Austin if (ret != 0) { 1379*6387f866SBrian Austin dev_err(&i2c_client->dev, 1380*6387f866SBrian Austin "Failed to request core supplies: %d\n", 1381*6387f866SBrian Austin ret); 1382*6387f866SBrian Austin return ret; 1383*6387f866SBrian Austin } 1384*6387f866SBrian Austin 1385*6387f866SBrian Austin if (pdata) { 1386*6387f866SBrian Austin cs35l35->pdata = *pdata; 1387*6387f866SBrian Austin } else { 1388*6387f866SBrian Austin pdata = devm_kzalloc(&i2c_client->dev, 1389*6387f866SBrian Austin sizeof(struct cs35l35_platform_data), 1390*6387f866SBrian Austin GFP_KERNEL); 1391*6387f866SBrian Austin if (!pdata) 1392*6387f866SBrian Austin return -ENOMEM; 1393*6387f866SBrian Austin if (i2c_client->dev.of_node) { 1394*6387f866SBrian Austin ret = cs35l35_handle_of_data(i2c_client, pdata); 1395*6387f866SBrian Austin if (ret != 0) 1396*6387f866SBrian Austin return ret; 1397*6387f866SBrian Austin 1398*6387f866SBrian Austin } 1399*6387f866SBrian Austin cs35l35->pdata = *pdata; 1400*6387f866SBrian Austin } 1401*6387f866SBrian Austin 1402*6387f866SBrian Austin ret = regulator_bulk_enable(cs35l35->num_supplies, 1403*6387f866SBrian Austin cs35l35->supplies); 1404*6387f866SBrian Austin if (ret != 0) { 1405*6387f866SBrian Austin dev_err(&i2c_client->dev, 1406*6387f866SBrian Austin "Failed to enable core supplies: %d\n", 1407*6387f866SBrian Austin ret); 1408*6387f866SBrian Austin return ret; 1409*6387f866SBrian Austin } 1410*6387f866SBrian Austin 1411*6387f866SBrian Austin /* returning NULL can be valid if in stereo mode */ 1412*6387f866SBrian Austin cs35l35->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, 1413*6387f866SBrian Austin "reset", GPIOD_OUT_LOW); 1414*6387f866SBrian Austin if (IS_ERR(cs35l35->reset_gpio)) { 1415*6387f866SBrian Austin ret = PTR_ERR(cs35l35->reset_gpio); 1416*6387f866SBrian Austin if (ret == -EBUSY) { 1417*6387f866SBrian Austin dev_info(&i2c_client->dev, 1418*6387f866SBrian Austin "Reset line busy, assuming shared reset\n"); 1419*6387f866SBrian Austin cs35l35->reset_gpio = NULL; 1420*6387f866SBrian Austin } else { 1421*6387f866SBrian Austin dev_err(&i2c_client->dev, 1422*6387f866SBrian Austin "Failed to get reset GPIO: %d\n", ret); 1423*6387f866SBrian Austin goto err; 1424*6387f866SBrian Austin } 1425*6387f866SBrian Austin } 1426*6387f866SBrian Austin 1427*6387f866SBrian Austin gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); 1428*6387f866SBrian Austin 1429*6387f866SBrian Austin init_completion(&cs35l35->pdn_done); 1430*6387f866SBrian Austin 1431*6387f866SBrian Austin ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, 1432*6387f866SBrian Austin cs35l35_irq, IRQF_ONESHOT | IRQF_TRIGGER_LOW, 1433*6387f866SBrian Austin "cs35l35", cs35l35); 1434*6387f866SBrian Austin if (ret != 0) { 1435*6387f866SBrian Austin dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); 1436*6387f866SBrian Austin goto err; 1437*6387f866SBrian Austin } 1438*6387f866SBrian Austin /* initialize codec */ 1439*6387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_AB, ®); 1440*6387f866SBrian Austin 1441*6387f866SBrian Austin devid = (reg & 0xFF) << 12; 1442*6387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_CD, ®); 1443*6387f866SBrian Austin devid |= (reg & 0xFF) << 4; 1444*6387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_E, ®); 1445*6387f866SBrian Austin devid |= (reg & 0xF0) >> 4; 1446*6387f866SBrian Austin 1447*6387f866SBrian Austin if (devid != CS35L35_CHIP_ID) { 1448*6387f866SBrian Austin dev_err(&i2c_client->dev, 1449*6387f866SBrian Austin "CS35L35 Device ID (%X). Expected ID %X\n", 1450*6387f866SBrian Austin devid, CS35L35_CHIP_ID); 1451*6387f866SBrian Austin ret = -ENODEV; 1452*6387f866SBrian Austin goto err; 1453*6387f866SBrian Austin } 1454*6387f866SBrian Austin 1455*6387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, ®); 1456*6387f866SBrian Austin if (ret < 0) { 1457*6387f866SBrian Austin dev_err(&i2c_client->dev, "Get Revision ID failed: %d\n", ret); 1458*6387f866SBrian Austin goto err; 1459*6387f866SBrian Austin } 1460*6387f866SBrian Austin 1461*6387f866SBrian Austin ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch, 1462*6387f866SBrian Austin ARRAY_SIZE(cs35l35_errata_patch)); 1463*6387f866SBrian Austin if (ret < 0) { 1464*6387f866SBrian Austin dev_err(&i2c_client->dev, "Failed to apply errata patch: %d\n", 1465*6387f866SBrian Austin ret); 1466*6387f866SBrian Austin goto err; 1467*6387f866SBrian Austin } 1468*6387f866SBrian Austin 1469*6387f866SBrian Austin dev_info(&i2c_client->dev, 1470*6387f866SBrian Austin "Cirrus Logic CS35L35 (%x), Revision: %02X\n", devid, 1471*6387f866SBrian Austin ret & 0xFF); 1472*6387f866SBrian Austin 1473*6387f866SBrian Austin /* Set the INT Masks for critical errors */ 1474*6387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, 1475*6387f866SBrian Austin CS35L35_INT1_CRIT_MASK); 1476*6387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2, 1477*6387f866SBrian Austin CS35L35_INT2_CRIT_MASK); 1478*6387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3, 1479*6387f866SBrian Austin CS35L35_INT3_CRIT_MASK); 1480*6387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4, 1481*6387f866SBrian Austin CS35L35_INT4_CRIT_MASK); 1482*6387f866SBrian Austin 1483*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 1484*6387f866SBrian Austin CS35L35_PWR2_PDN_MASK, 1485*6387f866SBrian Austin CS35L35_PWR2_PDN_MASK); 1486*6387f866SBrian Austin 1487*6387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 1488*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 1489*6387f866SBrian Austin CS35L35_PDN_BST_MASK, 1490*6387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 1491*6387f866SBrian Austin else 1492*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 1493*6387f866SBrian Austin CS35L35_PDN_BST_MASK, 1494*6387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 1495*6387f866SBrian Austin 1496*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3, 1497*6387f866SBrian Austin CS35L35_PWR3_PDN_MASK, 1498*6387f866SBrian Austin CS35L35_PWR3_PDN_MASK); 1499*6387f866SBrian Austin 1500*6387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 1501*6387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT); 1502*6387f866SBrian Austin 1503*6387f866SBrian Austin ret = snd_soc_register_codec(&i2c_client->dev, 1504*6387f866SBrian Austin &soc_codec_dev_cs35l35, cs35l35_dai, 1505*6387f866SBrian Austin ARRAY_SIZE(cs35l35_dai)); 1506*6387f866SBrian Austin if (ret < 0) { 1507*6387f866SBrian Austin dev_err(&i2c_client->dev, 1508*6387f866SBrian Austin "Failed to register codec: %d\n", ret); 1509*6387f866SBrian Austin goto err; 1510*6387f866SBrian Austin } 1511*6387f866SBrian Austin 1512*6387f866SBrian Austin err: 1513*6387f866SBrian Austin regulator_bulk_disable(cs35l35->num_supplies, 1514*6387f866SBrian Austin cs35l35->supplies); 1515*6387f866SBrian Austin gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 1516*6387f866SBrian Austin 1517*6387f866SBrian Austin return ret; 1518*6387f866SBrian Austin } 1519*6387f866SBrian Austin 1520*6387f866SBrian Austin static int cs35l35_i2c_remove(struct i2c_client *client) 1521*6387f866SBrian Austin { 1522*6387f866SBrian Austin snd_soc_unregister_codec(&client->dev); 1523*6387f866SBrian Austin return 0; 1524*6387f866SBrian Austin } 1525*6387f866SBrian Austin 1526*6387f866SBrian Austin static const struct of_device_id cs35l35_of_match[] = { 1527*6387f866SBrian Austin {.compatible = "cirrus,cs35l35"}, 1528*6387f866SBrian Austin {}, 1529*6387f866SBrian Austin }; 1530*6387f866SBrian Austin MODULE_DEVICE_TABLE(of, cs35l35_of_match); 1531*6387f866SBrian Austin 1532*6387f866SBrian Austin static const struct i2c_device_id cs35l35_id[] = { 1533*6387f866SBrian Austin {"cs35l35", 0}, 1534*6387f866SBrian Austin {} 1535*6387f866SBrian Austin }; 1536*6387f866SBrian Austin 1537*6387f866SBrian Austin MODULE_DEVICE_TABLE(i2c, cs35l35_id); 1538*6387f866SBrian Austin 1539*6387f866SBrian Austin static struct i2c_driver cs35l35_i2c_driver = { 1540*6387f866SBrian Austin .driver = { 1541*6387f866SBrian Austin .name = "cs35l35", 1542*6387f866SBrian Austin .of_match_table = cs35l35_of_match, 1543*6387f866SBrian Austin }, 1544*6387f866SBrian Austin .id_table = cs35l35_id, 1545*6387f866SBrian Austin .probe = cs35l35_i2c_probe, 1546*6387f866SBrian Austin .remove = cs35l35_i2c_remove, 1547*6387f866SBrian Austin }; 1548*6387f866SBrian Austin 1549*6387f866SBrian Austin module_i2c_driver(cs35l35_i2c_driver); 1550*6387f866SBrian Austin 1551*6387f866SBrian Austin MODULE_DESCRIPTION("ASoC CS35L35 driver"); 1552*6387f866SBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); 1553*6387f866SBrian Austin MODULE_LICENSE("GPL"); 1554