root/sound/soc/codecs/pcm1681.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcm1681_accessible_reg
  2. pcm1681_writeable_reg
  3. pcm1681_set_deemph
  4. pcm1681_get_deemph
  5. pcm1681_put_deemph
  6. pcm1681_set_dai_fmt
  7. pcm1681_digital_mute
  8. pcm1681_hw_params
  9. pcm1681_i2c_probe

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

/* [<][>][^][v][top][bottom][index][help] */