root/sound/soc/codecs/zx_aud96p22.c

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

DEFINITIONS

This source file includes following definitions.
  1. aud96p22_adc_event
  2. aud96p22_dac_event
  3. aud96p22_set_fmt
  4. aud96p22_i2c_probe
  5. aud96p22_i2c_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2017 Sanechips Technology Co., Ltd.
   4  * Copyright 2017 Linaro Ltd.
   5  *
   6  * Author: Baoyou Xie <baoyou.xie@linaro.org>
   7  */
   8 
   9 #include <linux/gpio/consumer.h>
  10 #include <linux/i2c.h>
  11 #include <linux/module.h>
  12 #include <linux/regmap.h>
  13 #include <sound/pcm.h>
  14 #include <sound/pcm_params.h>
  15 #include <sound/soc.h>
  16 #include <sound/soc-dai.h>
  17 #include <sound/tlv.h>
  18 
  19 #define AUD96P22_RESET                  0x00
  20 #define RST_DAC_DPZ                     BIT(0)
  21 #define RST_ADC_DPZ                     BIT(1)
  22 #define AUD96P22_I2S1_CONFIG_0          0x03
  23 #define I2S1_MS_MODE                    BIT(3)
  24 #define I2S1_MODE_MASK                  0x7
  25 #define I2S1_MODE_RIGHT_J               0x0
  26 #define I2S1_MODE_I2S                   0x1
  27 #define I2S1_MODE_LEFT_J                0x2
  28 #define AUD96P22_PD_0                   0x15
  29 #define AUD96P22_PD_1                   0x16
  30 #define AUD96P22_PD_3                   0x18
  31 #define AUD96P22_PD_4                   0x19
  32 #define AUD96P22_MUTE_0                 0x1d
  33 #define AUD96P22_MUTE_2                 0x1f
  34 #define AUD96P22_MUTE_4                 0x21
  35 #define AUD96P22_RECVOL_0               0x24
  36 #define AUD96P22_RECVOL_1               0x25
  37 #define AUD96P22_PGA1VOL_0              0x26
  38 #define AUD96P22_PGA1VOL_1              0x27
  39 #define AUD96P22_LMVOL_0                0x34
  40 #define AUD96P22_LMVOL_1                0x35
  41 #define AUD96P22_HS1VOL_0               0x38
  42 #define AUD96P22_HS1VOL_1               0x39
  43 #define AUD96P22_PGA1SEL_0              0x47
  44 #define AUD96P22_PGA1SEL_1              0x48
  45 #define AUD96P22_LDR1SEL_0              0x59
  46 #define AUD96P22_LDR1SEL_1              0x60
  47 #define AUD96P22_LDR2SEL_0              0x5d
  48 #define AUD96P22_REG_MAX                0xfb
  49 
  50 struct aud96p22_priv {
  51         struct regmap *regmap;
  52 };
  53 
  54 static int aud96p22_adc_event(struct snd_soc_dapm_widget *w,
  55                               struct snd_kcontrol *kcontrol, int event)
  56 {
  57         struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
  58         struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
  59         struct regmap *regmap = priv->regmap;
  60 
  61         if (event != SND_SOC_DAPM_POST_PMU)
  62                 return -EINVAL;
  63 
  64         /* Assert/de-assert the bit to reset ADC data path  */
  65         regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, 0);
  66         regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, RST_ADC_DPZ);
  67 
  68         return 0;
  69 }
  70 
  71 static int aud96p22_dac_event(struct snd_soc_dapm_widget *w,
  72                               struct snd_kcontrol *kcontrol, int event)
  73 {
  74         struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
  75         struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
  76         struct regmap *regmap = priv->regmap;
  77 
  78         if (event != SND_SOC_DAPM_POST_PMU)
  79                 return -EINVAL;
  80 
  81         /* Assert/de-assert the bit to reset DAC data path  */
  82         regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, 0);
  83         regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, RST_DAC_DPZ);
  84 
  85         return 0;
  86 }
  87 
  88 static const DECLARE_TLV_DB_SCALE(lm_tlv, -11550, 50, 0);
  89 static const DECLARE_TLV_DB_SCALE(hs_tlv, -3900, 300, 0);
  90 static const DECLARE_TLV_DB_SCALE(rec_tlv, -9550, 50, 0);
  91 static const DECLARE_TLV_DB_SCALE(pga_tlv, -1800, 100, 0);
  92 
  93 static const struct snd_kcontrol_new aud96p22_snd_controls[] = {
  94         /* Volume control */
  95         SOC_DOUBLE_R_TLV("Master Playback Volume", AUD96P22_LMVOL_0,
  96                          AUD96P22_LMVOL_1, 0, 0xff, 0, lm_tlv),
  97         SOC_DOUBLE_R_TLV("Headphone Volume", AUD96P22_HS1VOL_0,
  98                          AUD96P22_HS1VOL_1, 0, 0xf, 0, hs_tlv),
  99         SOC_DOUBLE_R_TLV("Master Capture Volume", AUD96P22_RECVOL_0,
 100                          AUD96P22_RECVOL_1, 0, 0xff, 0, rec_tlv),
 101         SOC_DOUBLE_R_TLV("Analogue Capture Volume", AUD96P22_PGA1VOL_0,
 102                          AUD96P22_PGA1VOL_1, 0, 0x37, 0, pga_tlv),
 103 
 104         /* Mute control */
 105         SOC_DOUBLE("Master Playback Switch", AUD96P22_MUTE_2, 0, 1, 1, 1),
 106         SOC_DOUBLE("Headphone Switch", AUD96P22_MUTE_2, 4, 5, 1, 1),
 107         SOC_DOUBLE("Line Out Switch", AUD96P22_MUTE_4, 0, 1, 1, 1),
 108         SOC_DOUBLE("Speaker Switch", AUD96P22_MUTE_4, 2, 3, 1, 1),
 109         SOC_DOUBLE("Master Capture Switch", AUD96P22_MUTE_0, 0, 1, 1, 1),
 110         SOC_DOUBLE("Analogue Capture Switch", AUD96P22_MUTE_0, 2, 3, 1, 1),
 111 };
 112 
 113 /* Input mux kcontrols */
 114 static const unsigned int ain_mux_values[] = {
 115         0, 1, 3, 4, 5,
 116 };
 117 
 118 static const char * const ainl_mux_texts[] = {
 119         "AINL1 differential",
 120         "AINL1 single-ended",
 121         "AINL3 single-ended",
 122         "AINL2 differential",
 123         "AINL2 single-ended",
 124 };
 125 
 126 static const char * const ainr_mux_texts[] = {
 127         "AINR1 differential",
 128         "AINR1 single-ended",
 129         "AINR3 single-ended",
 130         "AINR2 differential",
 131         "AINR2 single-ended",
 132 };
 133 
 134 static SOC_VALUE_ENUM_SINGLE_DECL(ainl_mux_enum, AUD96P22_PGA1SEL_0,
 135                                   0, 0x7, ainl_mux_texts, ain_mux_values);
 136 static SOC_VALUE_ENUM_SINGLE_DECL(ainr_mux_enum, AUD96P22_PGA1SEL_1,
 137                                   0, 0x7, ainr_mux_texts, ain_mux_values);
 138 
 139 static const struct snd_kcontrol_new ainl_mux_kcontrol =
 140                         SOC_DAPM_ENUM("AINL Mux", ainl_mux_enum);
 141 static const struct snd_kcontrol_new ainr_mux_kcontrol =
 142                         SOC_DAPM_ENUM("AINR Mux", ainr_mux_enum);
 143 
 144 /* Output mixer kcontrols */
 145 static const struct snd_kcontrol_new ld1_left_kcontrols[] = {
 146         SOC_DAPM_SINGLE("DACL LD1L Switch", AUD96P22_LDR1SEL_0, 0, 1, 0),
 147         SOC_DAPM_SINGLE("AINL LD1L Switch", AUD96P22_LDR1SEL_0, 1, 1, 0),
 148         SOC_DAPM_SINGLE("AINR LD1L Switch", AUD96P22_LDR1SEL_0, 2, 1, 0),
 149 };
 150 
 151 static const struct snd_kcontrol_new ld1_right_kcontrols[] = {
 152         SOC_DAPM_SINGLE("DACR LD1R Switch", AUD96P22_LDR1SEL_1, 8, 1, 0),
 153         SOC_DAPM_SINGLE("AINR LD1R Switch", AUD96P22_LDR1SEL_1, 9, 1, 0),
 154         SOC_DAPM_SINGLE("AINL LD1R Switch", AUD96P22_LDR1SEL_1, 10, 1, 0),
 155 };
 156 
 157 static const struct snd_kcontrol_new ld2_kcontrols[] = {
 158         SOC_DAPM_SINGLE("DACL LD2 Switch", AUD96P22_LDR2SEL_0, 0, 1, 0),
 159         SOC_DAPM_SINGLE("AINL LD2 Switch", AUD96P22_LDR2SEL_0, 1, 1, 0),
 160         SOC_DAPM_SINGLE("DACR LD2 Switch", AUD96P22_LDR2SEL_0, 2, 1, 0),
 161 };
 162 
 163 static const struct snd_soc_dapm_widget aud96p22_dapm_widgets[] = {
 164         /* Overall power bit */
 165         SND_SOC_DAPM_SUPPLY("POWER", AUD96P22_PD_0, 0, 0, NULL, 0),
 166 
 167         /* Input pins */
 168         SND_SOC_DAPM_INPUT("AINL1P"),
 169         SND_SOC_DAPM_INPUT("AINL2P"),
 170         SND_SOC_DAPM_INPUT("AINL3"),
 171         SND_SOC_DAPM_INPUT("AINL1N"),
 172         SND_SOC_DAPM_INPUT("AINL2N"),
 173         SND_SOC_DAPM_INPUT("AINR2N"),
 174         SND_SOC_DAPM_INPUT("AINR1N"),
 175         SND_SOC_DAPM_INPUT("AINR3"),
 176         SND_SOC_DAPM_INPUT("AINR2P"),
 177         SND_SOC_DAPM_INPUT("AINR1P"),
 178 
 179         /* Input muxes */
 180         SND_SOC_DAPM_MUX("AINLMUX", AUD96P22_PD_1, 2, 0, &ainl_mux_kcontrol),
 181         SND_SOC_DAPM_MUX("AINRMUX", AUD96P22_PD_1, 3, 0, &ainr_mux_kcontrol),
 182 
 183         /* ADCs */
 184         SND_SOC_DAPM_ADC_E("ADCL", "Capture Left", AUD96P22_PD_1, 0, 0,
 185                            aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
 186         SND_SOC_DAPM_ADC_E("ADCR", "Capture Right", AUD96P22_PD_1, 1, 0,
 187                            aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
 188 
 189         /* DACs */
 190         SND_SOC_DAPM_DAC_E("DACL", "Playback Left", AUD96P22_PD_3, 0, 0,
 191                            aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
 192         SND_SOC_DAPM_DAC_E("DACR", "Playback Right", AUD96P22_PD_3, 1, 0,
 193                            aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
 194 
 195         /* Output mixers */
 196         SND_SOC_DAPM_MIXER("LD1L", AUD96P22_PD_3, 6, 0, ld1_left_kcontrols,
 197                            ARRAY_SIZE(ld1_left_kcontrols)),
 198         SND_SOC_DAPM_MIXER("LD1R", AUD96P22_PD_3, 7, 0, ld1_right_kcontrols,
 199                            ARRAY_SIZE(ld1_right_kcontrols)),
 200         SND_SOC_DAPM_MIXER("LD2", AUD96P22_PD_4, 2, 0, ld2_kcontrols,
 201                            ARRAY_SIZE(ld2_kcontrols)),
 202 
 203         /* Headset power switch */
 204         SND_SOC_DAPM_SUPPLY("HS1L", AUD96P22_PD_3, 4, 0, NULL, 0),
 205         SND_SOC_DAPM_SUPPLY("HS1R", AUD96P22_PD_3, 5, 0, NULL, 0),
 206 
 207         /* Output pins */
 208         SND_SOC_DAPM_OUTPUT("HSOUTL"),
 209         SND_SOC_DAPM_OUTPUT("LINEOUTL"),
 210         SND_SOC_DAPM_OUTPUT("LINEOUTMP"),
 211         SND_SOC_DAPM_OUTPUT("LINEOUTMN"),
 212         SND_SOC_DAPM_OUTPUT("LINEOUTR"),
 213         SND_SOC_DAPM_OUTPUT("HSOUTR"),
 214 };
 215 
 216 static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
 217         { "AINLMUX", "AINL1 differential", "AINL1N" },
 218         { "AINLMUX", "AINL1 single-ended", "AINL1P" },
 219         { "AINLMUX", "AINL3 single-ended", "AINL3" },
 220         { "AINLMUX", "AINL2 differential", "AINL2N" },
 221         { "AINLMUX", "AINL2 single-ended", "AINL2P" },
 222 
 223         { "AINRMUX", "AINR1 differential", "AINR1N" },
 224         { "AINRMUX", "AINR1 single-ended", "AINR1P" },
 225         { "AINRMUX", "AINR3 single-ended", "AINR3" },
 226         { "AINRMUX", "AINR2 differential", "AINR2N" },
 227         { "AINRMUX", "AINR2 single-ended", "AINR2P" },
 228 
 229         { "ADCL", NULL, "AINLMUX" },
 230         { "ADCR", NULL, "AINRMUX" },
 231 
 232         { "ADCL", NULL, "POWER" },
 233         { "ADCR", NULL, "POWER" },
 234         { "DACL", NULL, "POWER" },
 235         { "DACR", NULL, "POWER" },
 236 
 237         { "LD1L", "DACL LD1L Switch", "DACL" },
 238         { "LD1L", "AINL LD1L Switch", "AINLMUX" },
 239         { "LD1L", "AINR LD1L Switch", "AINRMUX" },
 240 
 241         { "LD1R", "DACR LD1R Switch", "DACR" },
 242         { "LD1R", "AINR LD1R Switch", "AINRMUX" },
 243         { "LD1R", "AINL LD1R Switch", "AINLMUX" },
 244 
 245         { "LD2", "DACL LD2 Switch", "DACL" },
 246         { "LD2", "AINL LD2 Switch", "AINLMUX" },
 247         { "LD2", "DACR LD2 Switch", "DACR" },
 248 
 249         { "HSOUTL", NULL, "LD1L" },
 250         { "HSOUTR", NULL, "LD1R" },
 251         { "HSOUTL", NULL, "HS1L" },
 252         { "HSOUTR", NULL, "HS1R" },
 253 
 254         { "LINEOUTL", NULL, "LD1L" },
 255         { "LINEOUTR", NULL, "LD1R" },
 256 
 257         { "LINEOUTMP", NULL, "LD2" },
 258         { "LINEOUTMN", NULL, "LD2" },
 259 };
 260 
 261 static const struct snd_soc_component_driver aud96p22_driver = {
 262         .controls               = aud96p22_snd_controls,
 263         .num_controls           = ARRAY_SIZE(aud96p22_snd_controls),
 264         .dapm_widgets           = aud96p22_dapm_widgets,
 265         .num_dapm_widgets       = ARRAY_SIZE(aud96p22_dapm_widgets),
 266         .dapm_routes            = aud96p22_dapm_routes,
 267         .num_dapm_routes        = ARRAY_SIZE(aud96p22_dapm_routes),
 268         .idle_bias_on           = 1,
 269         .use_pmdown_time        = 1,
 270         .endianness             = 1,
 271         .non_legacy_dai_naming  = 1,
 272 };
 273 
 274 static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 275 {
 276         struct aud96p22_priv *priv = snd_soc_component_get_drvdata(dai->component);
 277         struct regmap *regmap = priv->regmap;
 278         unsigned int val;
 279 
 280         /* Master/slave mode */
 281         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 282         case SND_SOC_DAIFMT_CBS_CFS:
 283                 val = 0;
 284                 break;
 285         case SND_SOC_DAIFMT_CBM_CFM:
 286                 val = I2S1_MS_MODE;
 287                 break;
 288         default:
 289                 return -EINVAL;
 290         }
 291 
 292         regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MS_MODE, val);
 293 
 294         /* Audio format */
 295         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 296         case SND_SOC_DAIFMT_RIGHT_J:
 297                 val = I2S1_MODE_RIGHT_J;
 298                 break;
 299         case SND_SOC_DAIFMT_I2S:
 300                 val = I2S1_MODE_I2S;
 301                 break;
 302         case SND_SOC_DAIFMT_LEFT_J:
 303                 val = I2S1_MODE_LEFT_J;
 304                 break;
 305         default:
 306                 return -EINVAL;
 307         }
 308 
 309         regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MODE_MASK, val);
 310 
 311         return 0;
 312 }
 313 
 314 static const struct snd_soc_dai_ops aud96p22_dai_ops = {
 315         .set_fmt = aud96p22_set_fmt,
 316 };
 317 
 318 #define AUD96P22_RATES  SNDRV_PCM_RATE_8000_192000
 319 #define AUD96P22_FORMATS (\
 320                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
 321                 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
 322 
 323 static struct snd_soc_dai_driver aud96p22_dai = {
 324         .name = "aud96p22-dai",
 325         .playback = {
 326                 .stream_name = "Playback",
 327                 .channels_min = 1,
 328                 .channels_max = 2,
 329                 .rates = AUD96P22_RATES,
 330                 .formats = AUD96P22_FORMATS,
 331         },
 332         .capture = {
 333                 .stream_name = "Capture",
 334                 .channels_min = 1,
 335                 .channels_max = 2,
 336                 .rates = AUD96P22_RATES,
 337                 .formats = AUD96P22_FORMATS,
 338         },
 339         .ops = &aud96p22_dai_ops,
 340 };
 341 
 342 static const struct regmap_config aud96p22_regmap = {
 343         .reg_bits = 8,
 344         .val_bits = 8,
 345         .max_register = AUD96P22_REG_MAX,
 346         .cache_type = REGCACHE_RBTREE,
 347 };
 348 
 349 static int aud96p22_i2c_probe(struct i2c_client *i2c,
 350                               const struct i2c_device_id *id)
 351 {
 352         struct device *dev = &i2c->dev;
 353         struct aud96p22_priv *priv;
 354         int ret;
 355 
 356         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 357         if (priv == NULL)
 358                 return -ENOMEM;
 359 
 360         priv->regmap = devm_regmap_init_i2c(i2c, &aud96p22_regmap);
 361         if (IS_ERR(priv->regmap)) {
 362                 ret = PTR_ERR(priv->regmap);
 363                 dev_err(dev, "failed to init i2c regmap: %d\n", ret);
 364                 return ret;
 365         }
 366 
 367         i2c_set_clientdata(i2c, priv);
 368 
 369         ret = devm_snd_soc_register_component(dev, &aud96p22_driver, &aud96p22_dai, 1);
 370         if (ret) {
 371                 dev_err(dev, "failed to register component: %d\n", ret);
 372                 return ret;
 373         }
 374 
 375         return 0;
 376 }
 377 
 378 static int aud96p22_i2c_remove(struct i2c_client *i2c)
 379 {
 380         return 0;
 381 }
 382 
 383 static const struct of_device_id aud96p22_dt_ids[] = {
 384         { .compatible = "zte,zx-aud96p22", },
 385         { }
 386 };
 387 MODULE_DEVICE_TABLE(of, aud96p22_dt_ids);
 388 
 389 static struct i2c_driver aud96p22_i2c_driver = {
 390         .driver = {
 391                 .name = "zx_aud96p22",
 392                 .of_match_table = aud96p22_dt_ids,
 393         },
 394         .probe = aud96p22_i2c_probe,
 395         .remove = aud96p22_i2c_remove,
 396 };
 397 module_i2c_driver(aud96p22_i2c_driver);
 398 
 399 MODULE_DESCRIPTION("ZTE ASoC AUD96P22 CODEC driver");
 400 MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
 401 MODULE_LICENSE("GPL v2");

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