1*decbc00eSZhengShunQian /* 2*decbc00eSZhengShunQian * Driver of Inno codec for rk3036 by Rockchip Inc. 3*decbc00eSZhengShunQian * 4*decbc00eSZhengShunQian * Author: Rockchip Inc. 5*decbc00eSZhengShunQian * Author: Zheng ShunQian<zhengsq@rock-chips.com> 6*decbc00eSZhengShunQian */ 7*decbc00eSZhengShunQian 8*decbc00eSZhengShunQian #include <sound/soc.h> 9*decbc00eSZhengShunQian #include <sound/tlv.h> 10*decbc00eSZhengShunQian #include <sound/soc-dapm.h> 11*decbc00eSZhengShunQian #include <sound/soc-dai.h> 12*decbc00eSZhengShunQian #include <sound/pcm.h> 13*decbc00eSZhengShunQian #include <sound/pcm_params.h> 14*decbc00eSZhengShunQian 15*decbc00eSZhengShunQian #include <linux/platform_device.h> 16*decbc00eSZhengShunQian #include <linux/of.h> 17*decbc00eSZhengShunQian #include <linux/clk.h> 18*decbc00eSZhengShunQian #include <linux/regmap.h> 19*decbc00eSZhengShunQian #include <linux/device.h> 20*decbc00eSZhengShunQian #include <linux/mfd/syscon.h> 21*decbc00eSZhengShunQian #include <linux/module.h> 22*decbc00eSZhengShunQian #include <linux/io.h> 23*decbc00eSZhengShunQian 24*decbc00eSZhengShunQian #include "inno_rk3036.h" 25*decbc00eSZhengShunQian 26*decbc00eSZhengShunQian struct rk3036_codec_priv { 27*decbc00eSZhengShunQian void __iomem *base; 28*decbc00eSZhengShunQian struct clk *pclk; 29*decbc00eSZhengShunQian struct regmap *regmap; 30*decbc00eSZhengShunQian struct device *dev; 31*decbc00eSZhengShunQian }; 32*decbc00eSZhengShunQian 33*decbc00eSZhengShunQian static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0); 34*decbc00eSZhengShunQian 35*decbc00eSZhengShunQian static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol, 36*decbc00eSZhengShunQian struct snd_ctl_elem_info *uinfo) 37*decbc00eSZhengShunQian { 38*decbc00eSZhengShunQian uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 39*decbc00eSZhengShunQian uinfo->count = 2; 40*decbc00eSZhengShunQian uinfo->value.integer.min = 0; 41*decbc00eSZhengShunQian uinfo->value.integer.max = 1; 42*decbc00eSZhengShunQian 43*decbc00eSZhengShunQian return 0; 44*decbc00eSZhengShunQian } 45*decbc00eSZhengShunQian 46*decbc00eSZhengShunQian static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol, 47*decbc00eSZhengShunQian struct snd_ctl_elem_value *ucontrol) 48*decbc00eSZhengShunQian { 49*decbc00eSZhengShunQian struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 50*decbc00eSZhengShunQian int val, ret, regval; 51*decbc00eSZhengShunQian 52*decbc00eSZhengShunQian ret = snd_soc_component_read(component, INNO_R09, ®val); 53*decbc00eSZhengShunQian if (ret) 54*decbc00eSZhengShunQian return ret; 55*decbc00eSZhengShunQian val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) & 56*decbc00eSZhengShunQian INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; 57*decbc00eSZhengShunQian ucontrol->value.integer.value[0] = val; 58*decbc00eSZhengShunQian 59*decbc00eSZhengShunQian val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) & 60*decbc00eSZhengShunQian INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; 61*decbc00eSZhengShunQian ucontrol->value.integer.value[1] = val; 62*decbc00eSZhengShunQian 63*decbc00eSZhengShunQian return 0; 64*decbc00eSZhengShunQian } 65*decbc00eSZhengShunQian 66*decbc00eSZhengShunQian static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol, 67*decbc00eSZhengShunQian struct snd_ctl_elem_value *ucontrol) 68*decbc00eSZhengShunQian { 69*decbc00eSZhengShunQian struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 70*decbc00eSZhengShunQian int val, ret, regmsk; 71*decbc00eSZhengShunQian 72*decbc00eSZhengShunQian val = (ucontrol->value.integer.value[0] ? 73*decbc00eSZhengShunQian INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << 74*decbc00eSZhengShunQian INNO_R09_HPL_ANITPOP_SHIFT; 75*decbc00eSZhengShunQian val |= (ucontrol->value.integer.value[1] ? 76*decbc00eSZhengShunQian INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << 77*decbc00eSZhengShunQian INNO_R09_HPR_ANITPOP_SHIFT; 78*decbc00eSZhengShunQian 79*decbc00eSZhengShunQian regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT | 80*decbc00eSZhengShunQian INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT; 81*decbc00eSZhengShunQian 82*decbc00eSZhengShunQian ret = snd_soc_component_update_bits(component, INNO_R09, 83*decbc00eSZhengShunQian regmsk, val); 84*decbc00eSZhengShunQian if (ret < 0) 85*decbc00eSZhengShunQian return ret; 86*decbc00eSZhengShunQian 87*decbc00eSZhengShunQian return 0; 88*decbc00eSZhengShunQian } 89*decbc00eSZhengShunQian 90*decbc00eSZhengShunQian #define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \ 91*decbc00eSZhengShunQian { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 92*decbc00eSZhengShunQian .info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \ 93*decbc00eSZhengShunQian .put = rk3036_codec_antipop_put, } 94*decbc00eSZhengShunQian 95*decbc00eSZhengShunQian static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = { 96*decbc00eSZhengShunQian SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08, 97*decbc00eSZhengShunQian INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB, 98*decbc00eSZhengShunQian INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv), 99*decbc00eSZhengShunQian SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT, 100*decbc00eSZhengShunQian INNO_R06_VOUTR_CZ_SHIFT, 1, 0), 101*decbc00eSZhengShunQian SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT, 102*decbc00eSZhengShunQian INNO_R09_HPR_MUTE_SHIFT, 1, 0), 103*decbc00eSZhengShunQian SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"), 104*decbc00eSZhengShunQian }; 105*decbc00eSZhengShunQian 106*decbc00eSZhengShunQian static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = { 107*decbc00eSZhengShunQian SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09, 108*decbc00eSZhengShunQian INNO_R09_DACL_SWITCH_SHIFT, 1, 0), 109*decbc00eSZhengShunQian }; 110*decbc00eSZhengShunQian 111*decbc00eSZhengShunQian static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = { 112*decbc00eSZhengShunQian SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09, 113*decbc00eSZhengShunQian INNO_R09_DACR_SWITCH_SHIFT, 1, 0), 114*decbc00eSZhengShunQian }; 115*decbc00eSZhengShunQian 116*decbc00eSZhengShunQian static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = { 117*decbc00eSZhengShunQian SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05, 118*decbc00eSZhengShunQian INNO_R05_HPL_WORK_SHIFT, 1, 0), 119*decbc00eSZhengShunQian }; 120*decbc00eSZhengShunQian 121*decbc00eSZhengShunQian static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = { 122*decbc00eSZhengShunQian SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05, 123*decbc00eSZhengShunQian INNO_R05_HPR_WORK_SHIFT, 1, 0), 124*decbc00eSZhengShunQian }; 125*decbc00eSZhengShunQian 126*decbc00eSZhengShunQian static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = { 127*decbc00eSZhengShunQian SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06, 128*decbc00eSZhengShunQian INNO_R06_DAC_EN_SHIFT, 0, NULL, 0), 129*decbc00eSZhengShunQian SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04, 130*decbc00eSZhengShunQian INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0), 131*decbc00eSZhengShunQian SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04, 132*decbc00eSZhengShunQian INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0), 133*decbc00eSZhengShunQian SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06, 134*decbc00eSZhengShunQian INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0), 135*decbc00eSZhengShunQian SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06, 136*decbc00eSZhengShunQian INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0), 137*decbc00eSZhengShunQian SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04, 138*decbc00eSZhengShunQian INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0), 139*decbc00eSZhengShunQian SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04, 140*decbc00eSZhengShunQian INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0), 141*decbc00eSZhengShunQian 142*decbc00eSZhengShunQian SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04, 143*decbc00eSZhengShunQian INNO_R04_DACL_SW_SHIFT, 0), 144*decbc00eSZhengShunQian SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04, 145*decbc00eSZhengShunQian INNO_R04_DACR_SW_SHIFT, 0), 146*decbc00eSZhengShunQian 147*decbc00eSZhengShunQian SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0, 148*decbc00eSZhengShunQian rk3036_codec_hpl_mixer_controls, 149*decbc00eSZhengShunQian ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)), 150*decbc00eSZhengShunQian SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0, 151*decbc00eSZhengShunQian rk3036_codec_hpr_mixer_controls, 152*decbc00eSZhengShunQian ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)), 153*decbc00eSZhengShunQian 154*decbc00eSZhengShunQian SND_SOC_DAPM_PGA("HP Left Out", INNO_R05, 155*decbc00eSZhengShunQian INNO_R05_HPL_EN_SHIFT, 0, NULL, 0), 156*decbc00eSZhengShunQian SND_SOC_DAPM_PGA("HP Right Out", INNO_R05, 157*decbc00eSZhengShunQian INNO_R05_HPR_EN_SHIFT, 0, NULL, 0), 158*decbc00eSZhengShunQian 159*decbc00eSZhengShunQian SND_SOC_DAPM_MIXER("HP Left Switch", SND_SOC_NOPM, 0, 0, 160*decbc00eSZhengShunQian rk3036_codec_hpl_switch_controls, 161*decbc00eSZhengShunQian ARRAY_SIZE(rk3036_codec_hpl_switch_controls)), 162*decbc00eSZhengShunQian SND_SOC_DAPM_MIXER("HP Right Switch", SND_SOC_NOPM, 0, 0, 163*decbc00eSZhengShunQian rk3036_codec_hpr_switch_controls, 164*decbc00eSZhengShunQian ARRAY_SIZE(rk3036_codec_hpr_switch_controls)), 165*decbc00eSZhengShunQian 166*decbc00eSZhengShunQian SND_SOC_DAPM_OUTPUT("HPL"), 167*decbc00eSZhengShunQian SND_SOC_DAPM_OUTPUT("HPR"), 168*decbc00eSZhengShunQian }; 169*decbc00eSZhengShunQian 170*decbc00eSZhengShunQian static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = { 171*decbc00eSZhengShunQian {"DACL VREF", NULL, "DAC PWR"}, 172*decbc00eSZhengShunQian {"DACR VREF", NULL, "DAC PWR"}, 173*decbc00eSZhengShunQian {"DACL HiLo VREF", NULL, "DAC PWR"}, 174*decbc00eSZhengShunQian {"DACR HiLo VREF", NULL, "DAC PWR"}, 175*decbc00eSZhengShunQian {"DACL CLK", NULL, "DAC PWR"}, 176*decbc00eSZhengShunQian {"DACR CLK", NULL, "DAC PWR"}, 177*decbc00eSZhengShunQian 178*decbc00eSZhengShunQian {"DACL", NULL, "DACL VREF"}, 179*decbc00eSZhengShunQian {"DACL", NULL, "DACL HiLo VREF"}, 180*decbc00eSZhengShunQian {"DACL", NULL, "DACL CLK"}, 181*decbc00eSZhengShunQian {"DACR", NULL, "DACR VREF"}, 182*decbc00eSZhengShunQian {"DACR", NULL, "DACR HiLo VREF"}, 183*decbc00eSZhengShunQian {"DACR", NULL, "DACR CLK"}, 184*decbc00eSZhengShunQian 185*decbc00eSZhengShunQian {"Left Headphone Mixer", "DAC Left Out Switch", "DACL"}, 186*decbc00eSZhengShunQian {"Right Headphone Mixer", "DAC Right Out Switch", "DACR"}, 187*decbc00eSZhengShunQian {"HP Left Out", NULL, "Left Headphone Mixer"}, 188*decbc00eSZhengShunQian {"HP Right Out", NULL, "Right Headphone Mixer"}, 189*decbc00eSZhengShunQian 190*decbc00eSZhengShunQian {"HP Left Switch", "HP Left Out Switch", "HP Left Out"}, 191*decbc00eSZhengShunQian {"HP Right Switch", "HP Right Out Switch", "HP Right Out"}, 192*decbc00eSZhengShunQian 193*decbc00eSZhengShunQian {"HPL", NULL, "HP Left Switch"}, 194*decbc00eSZhengShunQian {"HPR", NULL, "HP Right Switch"}, 195*decbc00eSZhengShunQian }; 196*decbc00eSZhengShunQian 197*decbc00eSZhengShunQian static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 198*decbc00eSZhengShunQian { 199*decbc00eSZhengShunQian struct snd_soc_codec *codec = dai->codec; 200*decbc00eSZhengShunQian unsigned int reg01_val = 0, reg02_val = 0, reg03_val = 0; 201*decbc00eSZhengShunQian 202*decbc00eSZhengShunQian dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt); 203*decbc00eSZhengShunQian 204*decbc00eSZhengShunQian switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 205*decbc00eSZhengShunQian case SND_SOC_DAIFMT_CBS_CFS: 206*decbc00eSZhengShunQian reg01_val |= INNO_R01_PINDIR_IN_SLAVE | 207*decbc00eSZhengShunQian INNO_R01_I2SMODE_SLAVE; 208*decbc00eSZhengShunQian break; 209*decbc00eSZhengShunQian case SND_SOC_DAIFMT_CBM_CFM: 210*decbc00eSZhengShunQian reg01_val |= INNO_R01_PINDIR_OUT_MASTER | 211*decbc00eSZhengShunQian INNO_R01_I2SMODE_MASTER; 212*decbc00eSZhengShunQian break; 213*decbc00eSZhengShunQian default: 214*decbc00eSZhengShunQian dev_err(codec->dev, "invalid fmt\n"); 215*decbc00eSZhengShunQian return -EINVAL; 216*decbc00eSZhengShunQian } 217*decbc00eSZhengShunQian 218*decbc00eSZhengShunQian switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 219*decbc00eSZhengShunQian case SND_SOC_DAIFMT_DSP_A: 220*decbc00eSZhengShunQian reg02_val |= INNO_R02_DACM_PCM; 221*decbc00eSZhengShunQian break; 222*decbc00eSZhengShunQian case SND_SOC_DAIFMT_I2S: 223*decbc00eSZhengShunQian reg02_val |= INNO_R02_DACM_I2S; 224*decbc00eSZhengShunQian break; 225*decbc00eSZhengShunQian case SND_SOC_DAIFMT_RIGHT_J: 226*decbc00eSZhengShunQian reg02_val |= INNO_R02_DACM_RJM; 227*decbc00eSZhengShunQian break; 228*decbc00eSZhengShunQian case SND_SOC_DAIFMT_LEFT_J: 229*decbc00eSZhengShunQian reg02_val |= INNO_R02_DACM_LJM; 230*decbc00eSZhengShunQian break; 231*decbc00eSZhengShunQian default: 232*decbc00eSZhengShunQian dev_err(codec->dev, "set dai format failed\n"); 233*decbc00eSZhengShunQian return -EINVAL; 234*decbc00eSZhengShunQian } 235*decbc00eSZhengShunQian 236*decbc00eSZhengShunQian switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 237*decbc00eSZhengShunQian case SND_SOC_DAIFMT_NB_NF: 238*decbc00eSZhengShunQian reg02_val |= INNO_R02_LRCP_NORMAL; 239*decbc00eSZhengShunQian reg03_val |= INNO_R03_BCP_NORMAL; 240*decbc00eSZhengShunQian break; 241*decbc00eSZhengShunQian case SND_SOC_DAIFMT_IB_IF: 242*decbc00eSZhengShunQian reg02_val |= INNO_R02_LRCP_REVERSAL; 243*decbc00eSZhengShunQian reg03_val |= INNO_R03_BCP_REVERSAL; 244*decbc00eSZhengShunQian break; 245*decbc00eSZhengShunQian case SND_SOC_DAIFMT_IB_NF: 246*decbc00eSZhengShunQian reg02_val |= INNO_R02_LRCP_REVERSAL; 247*decbc00eSZhengShunQian reg03_val |= INNO_R03_BCP_NORMAL; 248*decbc00eSZhengShunQian break; 249*decbc00eSZhengShunQian case SND_SOC_DAIFMT_NB_IF: 250*decbc00eSZhengShunQian reg02_val |= INNO_R02_LRCP_NORMAL; 251*decbc00eSZhengShunQian reg03_val |= INNO_R03_BCP_REVERSAL; 252*decbc00eSZhengShunQian break; 253*decbc00eSZhengShunQian default: 254*decbc00eSZhengShunQian dev_err(codec->dev, "set dai format failed\n"); 255*decbc00eSZhengShunQian return -EINVAL; 256*decbc00eSZhengShunQian } 257*decbc00eSZhengShunQian 258*decbc00eSZhengShunQian snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK | 259*decbc00eSZhengShunQian INNO_R01_PINDIR_MSK, reg01_val); 260*decbc00eSZhengShunQian snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | 261*decbc00eSZhengShunQian INNO_R02_DACM_MSK, reg02_val); 262*decbc00eSZhengShunQian snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val); 263*decbc00eSZhengShunQian 264*decbc00eSZhengShunQian return 0; 265*decbc00eSZhengShunQian } 266*decbc00eSZhengShunQian 267*decbc00eSZhengShunQian static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream, 268*decbc00eSZhengShunQian struct snd_pcm_hw_params *hw_params, 269*decbc00eSZhengShunQian struct snd_soc_dai *dai) 270*decbc00eSZhengShunQian { 271*decbc00eSZhengShunQian struct snd_soc_codec *codec = dai->codec; 272*decbc00eSZhengShunQian unsigned int reg02_val = 0, reg03_val = 0; 273*decbc00eSZhengShunQian 274*decbc00eSZhengShunQian switch (params_format(hw_params)) { 275*decbc00eSZhengShunQian case SNDRV_PCM_FORMAT_S16_LE: 276*decbc00eSZhengShunQian reg02_val |= INNO_R02_VWL_16BIT; 277*decbc00eSZhengShunQian break; 278*decbc00eSZhengShunQian case SNDRV_PCM_FORMAT_S20_3LE: 279*decbc00eSZhengShunQian reg02_val |= INNO_R02_VWL_20BIT; 280*decbc00eSZhengShunQian break; 281*decbc00eSZhengShunQian case SNDRV_PCM_FORMAT_S24_LE: 282*decbc00eSZhengShunQian reg02_val |= INNO_R02_VWL_24BIT; 283*decbc00eSZhengShunQian break; 284*decbc00eSZhengShunQian case SNDRV_PCM_FORMAT_S32_LE: 285*decbc00eSZhengShunQian reg02_val |= INNO_R02_VWL_32BIT; 286*decbc00eSZhengShunQian break; 287*decbc00eSZhengShunQian default: 288*decbc00eSZhengShunQian return -EINVAL; 289*decbc00eSZhengShunQian } 290*decbc00eSZhengShunQian 291*decbc00eSZhengShunQian reg02_val |= INNO_R02_LRCP_NORMAL; 292*decbc00eSZhengShunQian reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK; 293*decbc00eSZhengShunQian 294*decbc00eSZhengShunQian snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | 295*decbc00eSZhengShunQian INNO_R02_VWL_MSK, reg02_val); 296*decbc00eSZhengShunQian snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK | 297*decbc00eSZhengShunQian INNO_R03_FWL_MSK, reg03_val); 298*decbc00eSZhengShunQian return 0; 299*decbc00eSZhengShunQian } 300*decbc00eSZhengShunQian 301*decbc00eSZhengShunQian #define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000 | \ 302*decbc00eSZhengShunQian SNDRV_PCM_RATE_16000 | \ 303*decbc00eSZhengShunQian SNDRV_PCM_RATE_32000 | \ 304*decbc00eSZhengShunQian SNDRV_PCM_RATE_44100 | \ 305*decbc00eSZhengShunQian SNDRV_PCM_RATE_48000 | \ 306*decbc00eSZhengShunQian SNDRV_PCM_RATE_96000) 307*decbc00eSZhengShunQian 308*decbc00eSZhengShunQian #define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE | \ 309*decbc00eSZhengShunQian SNDRV_PCM_FMTBIT_S20_3LE | \ 310*decbc00eSZhengShunQian SNDRV_PCM_FMTBIT_S24_LE | \ 311*decbc00eSZhengShunQian SNDRV_PCM_FMTBIT_S32_LE) 312*decbc00eSZhengShunQian 313*decbc00eSZhengShunQian static struct snd_soc_dai_ops rk3036_codec_dai_ops = { 314*decbc00eSZhengShunQian .set_fmt = rk3036_codec_dai_set_fmt, 315*decbc00eSZhengShunQian .hw_params = rk3036_codec_dai_hw_params, 316*decbc00eSZhengShunQian }; 317*decbc00eSZhengShunQian 318*decbc00eSZhengShunQian static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = { 319*decbc00eSZhengShunQian { 320*decbc00eSZhengShunQian .name = "rk3036-codec-dai", 321*decbc00eSZhengShunQian .playback = { 322*decbc00eSZhengShunQian .stream_name = "Playback", 323*decbc00eSZhengShunQian .channels_min = 1, 324*decbc00eSZhengShunQian .channels_max = 2, 325*decbc00eSZhengShunQian .rates = RK3036_CODEC_RATES, 326*decbc00eSZhengShunQian .formats = RK3036_CODEC_FMTS, 327*decbc00eSZhengShunQian }, 328*decbc00eSZhengShunQian .ops = &rk3036_codec_dai_ops, 329*decbc00eSZhengShunQian .symmetric_rates = 1, 330*decbc00eSZhengShunQian }, 331*decbc00eSZhengShunQian }; 332*decbc00eSZhengShunQian 333*decbc00eSZhengShunQian static void rk3036_codec_reset(struct snd_soc_codec *codec) 334*decbc00eSZhengShunQian { 335*decbc00eSZhengShunQian snd_soc_write(codec, INNO_R00, 336*decbc00eSZhengShunQian INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET); 337*decbc00eSZhengShunQian snd_soc_write(codec, INNO_R00, 338*decbc00eSZhengShunQian INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK); 339*decbc00eSZhengShunQian } 340*decbc00eSZhengShunQian 341*decbc00eSZhengShunQian static int rk3036_codec_probe(struct snd_soc_codec *codec) 342*decbc00eSZhengShunQian { 343*decbc00eSZhengShunQian rk3036_codec_reset(codec); 344*decbc00eSZhengShunQian return 0; 345*decbc00eSZhengShunQian } 346*decbc00eSZhengShunQian 347*decbc00eSZhengShunQian static int rk3036_codec_remove(struct snd_soc_codec *codec) 348*decbc00eSZhengShunQian { 349*decbc00eSZhengShunQian rk3036_codec_reset(codec); 350*decbc00eSZhengShunQian return 0; 351*decbc00eSZhengShunQian } 352*decbc00eSZhengShunQian 353*decbc00eSZhengShunQian static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec, 354*decbc00eSZhengShunQian enum snd_soc_bias_level level) 355*decbc00eSZhengShunQian { 356*decbc00eSZhengShunQian switch (level) { 357*decbc00eSZhengShunQian case SND_SOC_BIAS_STANDBY: 358*decbc00eSZhengShunQian /* set a big current for capacitor charging. */ 359*decbc00eSZhengShunQian snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); 360*decbc00eSZhengShunQian /* start precharge */ 361*decbc00eSZhengShunQian snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE); 362*decbc00eSZhengShunQian 363*decbc00eSZhengShunQian break; 364*decbc00eSZhengShunQian 365*decbc00eSZhengShunQian case SND_SOC_BIAS_OFF: 366*decbc00eSZhengShunQian /* set a big current for capacitor discharging. */ 367*decbc00eSZhengShunQian snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); 368*decbc00eSZhengShunQian /* start discharge. */ 369*decbc00eSZhengShunQian snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE); 370*decbc00eSZhengShunQian 371*decbc00eSZhengShunQian break; 372*decbc00eSZhengShunQian default: 373*decbc00eSZhengShunQian break; 374*decbc00eSZhengShunQian } 375*decbc00eSZhengShunQian 376*decbc00eSZhengShunQian return 0; 377*decbc00eSZhengShunQian } 378*decbc00eSZhengShunQian 379*decbc00eSZhengShunQian static struct snd_soc_codec_driver rk3036_codec_driver = { 380*decbc00eSZhengShunQian .probe = rk3036_codec_probe, 381*decbc00eSZhengShunQian .remove = rk3036_codec_remove, 382*decbc00eSZhengShunQian .set_bias_level = rk3036_codec_set_bias_level, 383*decbc00eSZhengShunQian .controls = rk3036_codec_dapm_controls, 384*decbc00eSZhengShunQian .num_controls = ARRAY_SIZE(rk3036_codec_dapm_controls), 385*decbc00eSZhengShunQian .dapm_routes = rk3036_codec_dapm_routes, 386*decbc00eSZhengShunQian .num_dapm_routes = ARRAY_SIZE(rk3036_codec_dapm_routes), 387*decbc00eSZhengShunQian .dapm_widgets = rk3036_codec_dapm_widgets, 388*decbc00eSZhengShunQian .num_dapm_widgets = ARRAY_SIZE(rk3036_codec_dapm_widgets), 389*decbc00eSZhengShunQian }; 390*decbc00eSZhengShunQian 391*decbc00eSZhengShunQian static const struct regmap_config rk3036_codec_regmap_config = { 392*decbc00eSZhengShunQian .reg_bits = 32, 393*decbc00eSZhengShunQian .reg_stride = 4, 394*decbc00eSZhengShunQian .val_bits = 32, 395*decbc00eSZhengShunQian }; 396*decbc00eSZhengShunQian 397*decbc00eSZhengShunQian #define GRF_SOC_CON0 0x00140 398*decbc00eSZhengShunQian #define GRF_ACODEC_SEL (BIT(10) | BIT(16 + 10)) 399*decbc00eSZhengShunQian 400*decbc00eSZhengShunQian static int rk3036_codec_platform_probe(struct platform_device *pdev) 401*decbc00eSZhengShunQian { 402*decbc00eSZhengShunQian struct rk3036_codec_priv *priv; 403*decbc00eSZhengShunQian struct device_node *of_node = pdev->dev.of_node; 404*decbc00eSZhengShunQian struct resource *res; 405*decbc00eSZhengShunQian void __iomem *base; 406*decbc00eSZhengShunQian struct regmap *grf; 407*decbc00eSZhengShunQian int ret; 408*decbc00eSZhengShunQian 409*decbc00eSZhengShunQian priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 410*decbc00eSZhengShunQian if (!priv) 411*decbc00eSZhengShunQian return -ENOMEM; 412*decbc00eSZhengShunQian 413*decbc00eSZhengShunQian res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 414*decbc00eSZhengShunQian base = devm_ioremap_resource(&pdev->dev, res); 415*decbc00eSZhengShunQian if (IS_ERR(base)) 416*decbc00eSZhengShunQian return PTR_ERR(base); 417*decbc00eSZhengShunQian 418*decbc00eSZhengShunQian priv->base = base; 419*decbc00eSZhengShunQian priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base, 420*decbc00eSZhengShunQian &rk3036_codec_regmap_config); 421*decbc00eSZhengShunQian if (IS_ERR(priv->regmap)) { 422*decbc00eSZhengShunQian dev_err(&pdev->dev, "init regmap failed\n"); 423*decbc00eSZhengShunQian return PTR_ERR(priv->regmap); 424*decbc00eSZhengShunQian } 425*decbc00eSZhengShunQian 426*decbc00eSZhengShunQian grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf"); 427*decbc00eSZhengShunQian if (IS_ERR(grf)) { 428*decbc00eSZhengShunQian dev_err(&pdev->dev, "needs 'rockchip,grf' property\n"); 429*decbc00eSZhengShunQian return PTR_ERR(grf); 430*decbc00eSZhengShunQian } 431*decbc00eSZhengShunQian ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL); 432*decbc00eSZhengShunQian if (ret) { 433*decbc00eSZhengShunQian dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret); 434*decbc00eSZhengShunQian return ret; 435*decbc00eSZhengShunQian } 436*decbc00eSZhengShunQian 437*decbc00eSZhengShunQian priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk"); 438*decbc00eSZhengShunQian if (IS_ERR(priv->pclk)) 439*decbc00eSZhengShunQian return PTR_ERR(priv->pclk); 440*decbc00eSZhengShunQian 441*decbc00eSZhengShunQian ret = clk_prepare_enable(priv->pclk); 442*decbc00eSZhengShunQian if (ret < 0) { 443*decbc00eSZhengShunQian dev_err(&pdev->dev, "failed to enable clk\n"); 444*decbc00eSZhengShunQian return ret; 445*decbc00eSZhengShunQian } 446*decbc00eSZhengShunQian 447*decbc00eSZhengShunQian priv->dev = &pdev->dev; 448*decbc00eSZhengShunQian dev_set_drvdata(&pdev->dev, priv); 449*decbc00eSZhengShunQian 450*decbc00eSZhengShunQian ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver, 451*decbc00eSZhengShunQian rk3036_codec_dai_driver, 452*decbc00eSZhengShunQian ARRAY_SIZE(rk3036_codec_dai_driver)); 453*decbc00eSZhengShunQian if (ret) { 454*decbc00eSZhengShunQian clk_disable_unprepare(priv->pclk); 455*decbc00eSZhengShunQian dev_set_drvdata(&pdev->dev, NULL); 456*decbc00eSZhengShunQian } 457*decbc00eSZhengShunQian 458*decbc00eSZhengShunQian return ret; 459*decbc00eSZhengShunQian } 460*decbc00eSZhengShunQian 461*decbc00eSZhengShunQian static int rk3036_codec_platform_remove(struct platform_device *pdev) 462*decbc00eSZhengShunQian { 463*decbc00eSZhengShunQian struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev); 464*decbc00eSZhengShunQian 465*decbc00eSZhengShunQian snd_soc_unregister_codec(&pdev->dev); 466*decbc00eSZhengShunQian clk_disable_unprepare(priv->pclk); 467*decbc00eSZhengShunQian 468*decbc00eSZhengShunQian return 0; 469*decbc00eSZhengShunQian } 470*decbc00eSZhengShunQian 471*decbc00eSZhengShunQian static const struct of_device_id rk3036_codec_of_match[] = { 472*decbc00eSZhengShunQian { .compatible = "rockchip,rk3036-codec", }, 473*decbc00eSZhengShunQian {} 474*decbc00eSZhengShunQian }; 475*decbc00eSZhengShunQian MODULE_DEVICE_TABLE(of, rk3036_codec_of_match); 476*decbc00eSZhengShunQian 477*decbc00eSZhengShunQian static struct platform_driver rk3036_codec_platform_driver = { 478*decbc00eSZhengShunQian .driver = { 479*decbc00eSZhengShunQian .name = "rk3036-codec-platform", 480*decbc00eSZhengShunQian .owner = THIS_MODULE, 481*decbc00eSZhengShunQian .of_match_table = of_match_ptr(rk3036_codec_of_match), 482*decbc00eSZhengShunQian }, 483*decbc00eSZhengShunQian .probe = rk3036_codec_platform_probe, 484*decbc00eSZhengShunQian .remove = rk3036_codec_platform_remove, 485*decbc00eSZhengShunQian }; 486*decbc00eSZhengShunQian 487*decbc00eSZhengShunQian module_platform_driver(rk3036_codec_platform_driver); 488*decbc00eSZhengShunQian 489*decbc00eSZhengShunQian MODULE_AUTHOR("Rockchip Inc."); 490*decbc00eSZhengShunQian MODULE_DESCRIPTION("Rockchip rk3036 codec driver"); 491*decbc00eSZhengShunQian MODULE_LICENSE("GPL"); 492