1*95169d08SMarek Belisko /* 2*95169d08SMarek Belisko * PCM1681 ASoC codec driver 3*95169d08SMarek Belisko * 4*95169d08SMarek Belisko * Copyright (c) StreamUnlimited GmbH 2013 5*95169d08SMarek Belisko * Marek Belisko <marek.belisko@streamunlimited.com> 6*95169d08SMarek Belisko * 7*95169d08SMarek Belisko * This program is free software; you can redistribute it and/or 8*95169d08SMarek Belisko * modify it under the terms of the GNU General Public License 9*95169d08SMarek Belisko * as published by the Free Software Foundation; either version 2 10*95169d08SMarek Belisko * of the License, or (at your option) any later version. 11*95169d08SMarek Belisko * 12*95169d08SMarek Belisko * This program is distributed in the hope that it will be useful, 13*95169d08SMarek Belisko * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*95169d08SMarek Belisko * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*95169d08SMarek Belisko * GNU General Public License for more details. 16*95169d08SMarek Belisko */ 17*95169d08SMarek Belisko 18*95169d08SMarek Belisko #include <linux/module.h> 19*95169d08SMarek Belisko #include <linux/slab.h> 20*95169d08SMarek Belisko #include <linux/delay.h> 21*95169d08SMarek Belisko #include <linux/gpio.h> 22*95169d08SMarek Belisko #include <linux/i2c.h> 23*95169d08SMarek Belisko #include <linux/regmap.h> 24*95169d08SMarek Belisko #include <linux/of_device.h> 25*95169d08SMarek Belisko #include <linux/of_gpio.h> 26*95169d08SMarek Belisko #include <sound/pcm.h> 27*95169d08SMarek Belisko #include <sound/pcm_params.h> 28*95169d08SMarek Belisko #include <sound/soc.h> 29*95169d08SMarek Belisko #include <sound/tlv.h> 30*95169d08SMarek Belisko 31*95169d08SMarek Belisko #define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 32*95169d08SMarek Belisko SNDRV_PCM_FMTBIT_S24_LE) 33*95169d08SMarek Belisko 34*95169d08SMarek Belisko #define PCM1681_PCM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ 35*95169d08SMarek Belisko SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 36*95169d08SMarek Belisko SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ 37*95169d08SMarek Belisko SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) 38*95169d08SMarek Belisko 39*95169d08SMarek Belisko #define PCM1681_SOFT_MUTE_ALL 0xff 40*95169d08SMarek Belisko #define PCM1681_DEEMPH_RATE_MASK 0x18 41*95169d08SMarek Belisko #define PCM1681_DEEMPH_MASK 0x01 42*95169d08SMarek Belisko 43*95169d08SMarek Belisko #define PCM1681_ATT_CONTROL(X) (X <= 6 ? X : X + 9) /* Attenuation level */ 44*95169d08SMarek Belisko #define PCM1681_SOFT_MUTE 0x07 /* Soft mute control register */ 45*95169d08SMarek Belisko #define PCM1681_DAC_CONTROL 0x08 /* DAC operation control */ 46*95169d08SMarek Belisko #define PCM1681_FMT_CONTROL 0x09 /* Audio interface data format */ 47*95169d08SMarek Belisko #define PCM1681_DEEMPH_CONTROL 0x0a /* De-emphasis control */ 48*95169d08SMarek Belisko #define PCM1681_ZERO_DETECT_STATUS 0x0e /* Zero detect status reg */ 49*95169d08SMarek Belisko 50*95169d08SMarek Belisko static const struct reg_default pcm1681_reg_defaults[] = { 51*95169d08SMarek Belisko { 0x01, 0xff }, 52*95169d08SMarek Belisko { 0x02, 0xff }, 53*95169d08SMarek Belisko { 0x03, 0xff }, 54*95169d08SMarek Belisko { 0x04, 0xff }, 55*95169d08SMarek Belisko { 0x05, 0xff }, 56*95169d08SMarek Belisko { 0x06, 0xff }, 57*95169d08SMarek Belisko { 0x07, 0x00 }, 58*95169d08SMarek Belisko { 0x08, 0x00 }, 59*95169d08SMarek Belisko { 0x09, 0x06 }, 60*95169d08SMarek Belisko { 0x0A, 0x00 }, 61*95169d08SMarek Belisko { 0x0B, 0xff }, 62*95169d08SMarek Belisko { 0x0C, 0x0f }, 63*95169d08SMarek Belisko { 0x0D, 0x00 }, 64*95169d08SMarek Belisko { 0x10, 0xff }, 65*95169d08SMarek Belisko { 0x11, 0xff }, 66*95169d08SMarek Belisko { 0x12, 0x00 }, 67*95169d08SMarek Belisko { 0x13, 0x00 }, 68*95169d08SMarek Belisko }; 69*95169d08SMarek Belisko 70*95169d08SMarek Belisko static bool pcm1681_accessible_reg(struct device *dev, unsigned int reg) 71*95169d08SMarek Belisko { 72*95169d08SMarek Belisko return !((reg == 0x00) || (reg == 0x0f)); 73*95169d08SMarek Belisko } 74*95169d08SMarek Belisko 75*95169d08SMarek Belisko static bool pcm1681_writeable_reg(struct device *dev, unsigned register reg) 76*95169d08SMarek Belisko { 77*95169d08SMarek Belisko return pcm1681_accessible_reg(dev, reg) && 78*95169d08SMarek Belisko (reg != PCM1681_ZERO_DETECT_STATUS); 79*95169d08SMarek Belisko } 80*95169d08SMarek Belisko 81*95169d08SMarek Belisko struct pcm1681_private { 82*95169d08SMarek Belisko struct regmap *regmap; 83*95169d08SMarek Belisko unsigned int format; 84*95169d08SMarek Belisko /* Current deemphasis status */ 85*95169d08SMarek Belisko unsigned int deemph; 86*95169d08SMarek Belisko /* Current rate for deemphasis control */ 87*95169d08SMarek Belisko unsigned int rate; 88*95169d08SMarek Belisko }; 89*95169d08SMarek Belisko 90*95169d08SMarek Belisko static const int pcm1681_deemph[] = { 44100, 48000, 32000 }; 91*95169d08SMarek Belisko 92*95169d08SMarek Belisko static int pcm1681_set_deemph(struct snd_soc_codec *codec) 93*95169d08SMarek Belisko { 94*95169d08SMarek Belisko struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); 95*95169d08SMarek Belisko int i = 0, val = -1, enable = 0; 96*95169d08SMarek Belisko 97*95169d08SMarek Belisko if (priv->deemph) 98*95169d08SMarek Belisko for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) 99*95169d08SMarek Belisko if (pcm1681_deemph[i] == priv->rate) 100*95169d08SMarek Belisko val = i; 101*95169d08SMarek Belisko 102*95169d08SMarek Belisko if (val != -1) { 103*95169d08SMarek Belisko regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, 104*95169d08SMarek Belisko PCM1681_DEEMPH_RATE_MASK, val); 105*95169d08SMarek Belisko enable = 1; 106*95169d08SMarek Belisko } else 107*95169d08SMarek Belisko enable = 0; 108*95169d08SMarek Belisko 109*95169d08SMarek Belisko /* enable/disable deemphasis functionality */ 110*95169d08SMarek Belisko return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, 111*95169d08SMarek Belisko PCM1681_DEEMPH_MASK, enable); 112*95169d08SMarek Belisko } 113*95169d08SMarek Belisko 114*95169d08SMarek Belisko static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, 115*95169d08SMarek Belisko struct snd_ctl_elem_value *ucontrol) 116*95169d08SMarek Belisko { 117*95169d08SMarek Belisko struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 118*95169d08SMarek Belisko struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); 119*95169d08SMarek Belisko 120*95169d08SMarek Belisko ucontrol->value.enumerated.item[0] = priv->deemph; 121*95169d08SMarek Belisko 122*95169d08SMarek Belisko return 0; 123*95169d08SMarek Belisko } 124*95169d08SMarek Belisko 125*95169d08SMarek Belisko static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol, 126*95169d08SMarek Belisko struct snd_ctl_elem_value *ucontrol) 127*95169d08SMarek Belisko { 128*95169d08SMarek Belisko struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 129*95169d08SMarek Belisko struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); 130*95169d08SMarek Belisko 131*95169d08SMarek Belisko priv->deemph = ucontrol->value.enumerated.item[0]; 132*95169d08SMarek Belisko 133*95169d08SMarek Belisko return pcm1681_set_deemph(codec); 134*95169d08SMarek Belisko } 135*95169d08SMarek Belisko 136*95169d08SMarek Belisko static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai, 137*95169d08SMarek Belisko unsigned int format) 138*95169d08SMarek Belisko { 139*95169d08SMarek Belisko struct snd_soc_codec *codec = codec_dai->codec; 140*95169d08SMarek Belisko struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); 141*95169d08SMarek Belisko 142*95169d08SMarek Belisko /* The PCM1681 can only be slave to all clocks */ 143*95169d08SMarek Belisko if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { 144*95169d08SMarek Belisko dev_err(codec->dev, "Invalid clocking mode\n"); 145*95169d08SMarek Belisko return -EINVAL; 146*95169d08SMarek Belisko } 147*95169d08SMarek Belisko 148*95169d08SMarek Belisko priv->format = format; 149*95169d08SMarek Belisko 150*95169d08SMarek Belisko return 0; 151*95169d08SMarek Belisko } 152*95169d08SMarek Belisko 153*95169d08SMarek Belisko static int pcm1681_digital_mute(struct snd_soc_dai *dai, int mute) 154*95169d08SMarek Belisko { 155*95169d08SMarek Belisko struct snd_soc_codec *codec = dai->codec; 156*95169d08SMarek Belisko struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); 157*95169d08SMarek Belisko int val; 158*95169d08SMarek Belisko 159*95169d08SMarek Belisko if (mute) 160*95169d08SMarek Belisko val = PCM1681_SOFT_MUTE_ALL; 161*95169d08SMarek Belisko else 162*95169d08SMarek Belisko val = 0; 163*95169d08SMarek Belisko 164*95169d08SMarek Belisko return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val); 165*95169d08SMarek Belisko } 166*95169d08SMarek Belisko 167*95169d08SMarek Belisko static int pcm1681_hw_params(struct snd_pcm_substream *substream, 168*95169d08SMarek Belisko struct snd_pcm_hw_params *params, 169*95169d08SMarek Belisko struct snd_soc_dai *dai) 170*95169d08SMarek Belisko { 171*95169d08SMarek Belisko struct snd_soc_codec *codec = dai->codec; 172*95169d08SMarek Belisko struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); 173*95169d08SMarek Belisko int val = 0, ret; 174*95169d08SMarek Belisko int pcm_format = params_format(params); 175*95169d08SMarek Belisko 176*95169d08SMarek Belisko priv->rate = params_rate(params); 177*95169d08SMarek Belisko 178*95169d08SMarek Belisko switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { 179*95169d08SMarek Belisko case SND_SOC_DAIFMT_RIGHT_J: 180*95169d08SMarek Belisko if (pcm_format == SNDRV_PCM_FORMAT_S24_LE) 181*95169d08SMarek Belisko val = 0x00; 182*95169d08SMarek Belisko else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) 183*95169d08SMarek Belisko val = 0x03; 184*95169d08SMarek Belisko break; 185*95169d08SMarek Belisko case SND_SOC_DAIFMT_I2S: 186*95169d08SMarek Belisko val = 0x04; 187*95169d08SMarek Belisko break; 188*95169d08SMarek Belisko case SND_SOC_DAIFMT_LEFT_J: 189*95169d08SMarek Belisko val = 0x05; 190*95169d08SMarek Belisko break; 191*95169d08SMarek Belisko default: 192*95169d08SMarek Belisko dev_err(codec->dev, "Invalid DAI format\n"); 193*95169d08SMarek Belisko return -EINVAL; 194*95169d08SMarek Belisko } 195*95169d08SMarek Belisko 196*95169d08SMarek Belisko ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val); 197*95169d08SMarek Belisko if (ret < 0) 198*95169d08SMarek Belisko return ret; 199*95169d08SMarek Belisko 200*95169d08SMarek Belisko return pcm1681_set_deemph(codec); 201*95169d08SMarek Belisko } 202*95169d08SMarek Belisko 203*95169d08SMarek Belisko static const struct snd_soc_dai_ops pcm1681_dai_ops = { 204*95169d08SMarek Belisko .set_fmt = pcm1681_set_dai_fmt, 205*95169d08SMarek Belisko .hw_params = pcm1681_hw_params, 206*95169d08SMarek Belisko .digital_mute = pcm1681_digital_mute, 207*95169d08SMarek Belisko }; 208*95169d08SMarek Belisko 209*95169d08SMarek Belisko static const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1); 210*95169d08SMarek Belisko 211*95169d08SMarek Belisko static const struct snd_kcontrol_new pcm1681_controls[] = { 212*95169d08SMarek Belisko SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume", 213*95169d08SMarek Belisko PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0, 214*95169d08SMarek Belisko 0x7f, 0, pcm1681_dac_tlv), 215*95169d08SMarek Belisko SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume", 216*95169d08SMarek Belisko PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0, 217*95169d08SMarek Belisko 0x7f, 0, pcm1681_dac_tlv), 218*95169d08SMarek Belisko SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume", 219*95169d08SMarek Belisko PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0, 220*95169d08SMarek Belisko 0x7f, 0, pcm1681_dac_tlv), 221*95169d08SMarek Belisko SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume", 222*95169d08SMarek Belisko PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0, 223*95169d08SMarek Belisko 0x7f, 0, pcm1681_dac_tlv), 224*95169d08SMarek Belisko SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, 225*95169d08SMarek Belisko pcm1681_get_deemph, pcm1681_put_deemph), 226*95169d08SMarek Belisko }; 227*95169d08SMarek Belisko 228*95169d08SMarek Belisko struct snd_soc_dai_driver pcm1681_dai = { 229*95169d08SMarek Belisko .name = "pcm1681-hifi", 230*95169d08SMarek Belisko .playback = { 231*95169d08SMarek Belisko .stream_name = "Playback", 232*95169d08SMarek Belisko .channels_min = 2, 233*95169d08SMarek Belisko .channels_max = 8, 234*95169d08SMarek Belisko .rates = PCM1681_PCM_RATES, 235*95169d08SMarek Belisko .formats = PCM1681_PCM_FORMATS, 236*95169d08SMarek Belisko }, 237*95169d08SMarek Belisko .ops = &pcm1681_dai_ops, 238*95169d08SMarek Belisko }; 239*95169d08SMarek Belisko 240*95169d08SMarek Belisko #ifdef CONFIG_OF 241*95169d08SMarek Belisko static const struct of_device_id pcm1681_dt_ids[] = { 242*95169d08SMarek Belisko { .compatible = "ti,pcm1681", }, 243*95169d08SMarek Belisko { } 244*95169d08SMarek Belisko }; 245*95169d08SMarek Belisko MODULE_DEVICE_TABLE(of, pcm1681_dt_ids); 246*95169d08SMarek Belisko #endif 247*95169d08SMarek Belisko 248*95169d08SMarek Belisko static const struct regmap_config pcm1681_regmap = { 249*95169d08SMarek Belisko .reg_bits = 8, 250*95169d08SMarek Belisko .val_bits = 8, 251*95169d08SMarek Belisko .max_register = ARRAY_SIZE(pcm1681_reg_defaults) + 1, 252*95169d08SMarek Belisko .reg_defaults = pcm1681_reg_defaults, 253*95169d08SMarek Belisko .num_reg_defaults = ARRAY_SIZE(pcm1681_reg_defaults), 254*95169d08SMarek Belisko .writeable_reg = pcm1681_writeable_reg, 255*95169d08SMarek Belisko .readable_reg = pcm1681_accessible_reg, 256*95169d08SMarek Belisko }; 257*95169d08SMarek Belisko 258*95169d08SMarek Belisko static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = { 259*95169d08SMarek Belisko .controls = pcm1681_controls, 260*95169d08SMarek Belisko .num_controls = ARRAY_SIZE(pcm1681_controls), 261*95169d08SMarek Belisko }; 262*95169d08SMarek Belisko 263*95169d08SMarek Belisko static const struct i2c_device_id pcm1681_i2c_id[] = { 264*95169d08SMarek Belisko {"pcm1681", 0}, 265*95169d08SMarek Belisko {} 266*95169d08SMarek Belisko }; 267*95169d08SMarek Belisko MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id); 268*95169d08SMarek Belisko 269*95169d08SMarek Belisko static int pcm1681_i2c_probe(struct i2c_client *client, 270*95169d08SMarek Belisko const struct i2c_device_id *id) 271*95169d08SMarek Belisko { 272*95169d08SMarek Belisko int ret; 273*95169d08SMarek Belisko struct pcm1681_private *priv; 274*95169d08SMarek Belisko 275*95169d08SMarek Belisko priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 276*95169d08SMarek Belisko if (!priv) 277*95169d08SMarek Belisko return -ENOMEM; 278*95169d08SMarek Belisko 279*95169d08SMarek Belisko priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap); 280*95169d08SMarek Belisko if (IS_ERR(priv->regmap)) { 281*95169d08SMarek Belisko ret = PTR_ERR(priv->regmap); 282*95169d08SMarek Belisko dev_err(&client->dev, "Failed to create regmap: %d\n", ret); 283*95169d08SMarek Belisko return ret; 284*95169d08SMarek Belisko } 285*95169d08SMarek Belisko 286*95169d08SMarek Belisko i2c_set_clientdata(client, priv); 287*95169d08SMarek Belisko 288*95169d08SMarek Belisko return snd_soc_register_codec(&client->dev, &soc_codec_dev_pcm1681, 289*95169d08SMarek Belisko &pcm1681_dai, 1); 290*95169d08SMarek Belisko } 291*95169d08SMarek Belisko 292*95169d08SMarek Belisko static int pcm1681_i2c_remove(struct i2c_client *client) 293*95169d08SMarek Belisko { 294*95169d08SMarek Belisko snd_soc_unregister_codec(&client->dev); 295*95169d08SMarek Belisko return 0; 296*95169d08SMarek Belisko } 297*95169d08SMarek Belisko 298*95169d08SMarek Belisko static struct i2c_driver pcm1681_i2c_driver = { 299*95169d08SMarek Belisko .driver = { 300*95169d08SMarek Belisko .name = "pcm1681", 301*95169d08SMarek Belisko .owner = THIS_MODULE, 302*95169d08SMarek Belisko .of_match_table = of_match_ptr(pcm1681_dt_ids), 303*95169d08SMarek Belisko }, 304*95169d08SMarek Belisko .id_table = pcm1681_i2c_id, 305*95169d08SMarek Belisko .probe = pcm1681_i2c_probe, 306*95169d08SMarek Belisko .remove = pcm1681_i2c_remove, 307*95169d08SMarek Belisko }; 308*95169d08SMarek Belisko 309*95169d08SMarek Belisko module_i2c_driver(pcm1681_i2c_driver); 310*95169d08SMarek Belisko 311*95169d08SMarek Belisko MODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver"); 312*95169d08SMarek Belisko MODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>"); 313*95169d08SMarek Belisko MODULE_LICENSE("GPL"); 314