root/sound/soc/codecs/cs42xx8.c

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

DEFINITIONS

This source file includes following definitions.
  1. cs42xx8_set_dai_sysclk
  2. cs42xx8_set_dai_fmt
  3. cs42xx8_hw_params
  4. cs42xx8_hw_free
  5. cs42xx8_digital_mute
  6. cs42xx8_volatile_register
  7. cs42xx8_writeable_register
  8. cs42xx8_component_probe
  9. cs42xx8_probe
  10. cs42xx8_runtime_resume
  11. cs42xx8_runtime_suspend

   1 /*
   2  * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
   3  *
   4  * Copyright (C) 2014 Freescale Semiconductor, Inc.
   5  *
   6  * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
   7  *
   8  * This file is licensed under the terms of the GNU General Public License
   9  * version 2. This program is licensed "as is" without any warranty of any
  10  * kind, whether express or implied.
  11  */
  12 
  13 #include <linux/clk.h>
  14 #include <linux/delay.h>
  15 #include <linux/module.h>
  16 #include <linux/of_device.h>
  17 #include <linux/gpio/consumer.h>
  18 #include <linux/pm_runtime.h>
  19 #include <linux/regulator/consumer.h>
  20 #include <sound/pcm_params.h>
  21 #include <sound/soc.h>
  22 #include <sound/tlv.h>
  23 
  24 #include "cs42xx8.h"
  25 
  26 #define CS42XX8_NUM_SUPPLIES 4
  27 static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
  28         "VA",
  29         "VD",
  30         "VLS",
  31         "VLC",
  32 };
  33 
  34 #define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
  35                          SNDRV_PCM_FMTBIT_S20_3LE | \
  36                          SNDRV_PCM_FMTBIT_S24_LE | \
  37                          SNDRV_PCM_FMTBIT_S32_LE)
  38 
  39 /* codec private data */
  40 struct cs42xx8_priv {
  41         struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
  42         const struct cs42xx8_driver_data *drvdata;
  43         struct regmap *regmap;
  44         struct clk *clk;
  45 
  46         bool slave_mode;
  47         unsigned long sysclk;
  48         u32 tx_channels;
  49         struct gpio_desc *gpiod_reset;
  50         u32 rate[2];
  51 };
  52 
  53 /* -127.5dB to 0dB with step of 0.5dB */
  54 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
  55 /* -64dB to 24dB with step of 0.5dB */
  56 static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
  57 
  58 static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
  59 static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
  60                                         "Soft Ramp", "Soft Ramp on Zero Cross" };
  61 
  62 static const struct soc_enum adc1_single_enum =
  63         SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
  64 static const struct soc_enum adc2_single_enum =
  65         SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
  66 static const struct soc_enum adc3_single_enum =
  67         SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
  68 static const struct soc_enum dac_szc_enum =
  69         SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
  70 static const struct soc_enum adc_szc_enum =
  71         SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
  72 
  73 static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
  74         SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
  75                          CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
  76         SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
  77                          CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
  78         SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
  79                          CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
  80         SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
  81                          CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
  82         SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
  83                            CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
  84         SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
  85                            CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
  86         SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
  87         SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
  88         SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
  89         SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
  90         SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
  91         SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
  92         SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
  93         SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
  94         SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
  95         SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
  96         SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
  97         SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
  98         SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
  99         SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
 100         SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
 101         SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
 102 };
 103 
 104 static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
 105         SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
 106                            CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
 107         SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
 108         SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
 109 };
 110 
 111 static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
 112         SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
 113         SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
 114         SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
 115         SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
 116 
 117         SND_SOC_DAPM_OUTPUT("AOUT1L"),
 118         SND_SOC_DAPM_OUTPUT("AOUT1R"),
 119         SND_SOC_DAPM_OUTPUT("AOUT2L"),
 120         SND_SOC_DAPM_OUTPUT("AOUT2R"),
 121         SND_SOC_DAPM_OUTPUT("AOUT3L"),
 122         SND_SOC_DAPM_OUTPUT("AOUT3R"),
 123         SND_SOC_DAPM_OUTPUT("AOUT4L"),
 124         SND_SOC_DAPM_OUTPUT("AOUT4R"),
 125 
 126         SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
 127         SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
 128 
 129         SND_SOC_DAPM_INPUT("AIN1L"),
 130         SND_SOC_DAPM_INPUT("AIN1R"),
 131         SND_SOC_DAPM_INPUT("AIN2L"),
 132         SND_SOC_DAPM_INPUT("AIN2R"),
 133 
 134         SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
 135 };
 136 
 137 static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
 138         SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
 139 
 140         SND_SOC_DAPM_INPUT("AIN3L"),
 141         SND_SOC_DAPM_INPUT("AIN3R"),
 142 };
 143 
 144 static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
 145         /* Playback */
 146         { "AOUT1L", NULL, "DAC1" },
 147         { "AOUT1R", NULL, "DAC1" },
 148         { "DAC1", NULL, "PWR" },
 149 
 150         { "AOUT2L", NULL, "DAC2" },
 151         { "AOUT2R", NULL, "DAC2" },
 152         { "DAC2", NULL, "PWR" },
 153 
 154         { "AOUT3L", NULL, "DAC3" },
 155         { "AOUT3R", NULL, "DAC3" },
 156         { "DAC3", NULL, "PWR" },
 157 
 158         { "AOUT4L", NULL, "DAC4" },
 159         { "AOUT4R", NULL, "DAC4" },
 160         { "DAC4", NULL, "PWR" },
 161 
 162         /* Capture */
 163         { "ADC1", NULL, "AIN1L" },
 164         { "ADC1", NULL, "AIN1R" },
 165         { "ADC1", NULL, "PWR" },
 166 
 167         { "ADC2", NULL, "AIN2L" },
 168         { "ADC2", NULL, "AIN2R" },
 169         { "ADC2", NULL, "PWR" },
 170 };
 171 
 172 static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
 173         /* Capture */
 174         { "ADC3", NULL, "AIN3L" },
 175         { "ADC3", NULL, "AIN3R" },
 176         { "ADC3", NULL, "PWR" },
 177 };
 178 
 179 struct cs42xx8_ratios {
 180         unsigned int mfreq;
 181         unsigned int min_mclk;
 182         unsigned int max_mclk;
 183         unsigned int ratio[3];
 184 };
 185 
 186 /*
 187  * According to reference mannual, define the cs42xx8_ratio struct
 188  * MFreq2 | MFreq1 | MFreq0 |     Description     | SSM | DSM | QSM |
 189  * 0      | 0      | 0      |1.029MHz to 12.8MHz  | 256 | 128 |  64 |
 190  * 0      | 0      | 1      |1.536MHz to 19.2MHz  | 384 | 192 |  96 |
 191  * 0      | 1      | 0      |2.048MHz to 25.6MHz  | 512 | 256 | 128 |
 192  * 0      | 1      | 1      |3.072MHz to 38.4MHz  | 768 | 384 | 192 |
 193  * 1      | x      | x      |4.096MHz to 51.2MHz  |1024 | 512 | 256 |
 194  */
 195 static const struct cs42xx8_ratios cs42xx8_ratios[] = {
 196         { 0, 1029000, 12800000, {256, 128, 64} },
 197         { 2, 1536000, 19200000, {384, 192, 96} },
 198         { 4, 2048000, 25600000, {512, 256, 128} },
 199         { 6, 3072000, 38400000, {768, 384, 192} },
 200         { 8, 4096000, 51200000, {1024, 512, 256} },
 201 };
 202 
 203 static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 204                                   int clk_id, unsigned int freq, int dir)
 205 {
 206         struct snd_soc_component *component = codec_dai->component;
 207         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 208 
 209         cs42xx8->sysclk = freq;
 210 
 211         return 0;
 212 }
 213 
 214 static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
 215                                unsigned int format)
 216 {
 217         struct snd_soc_component *component = codec_dai->component;
 218         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 219         u32 val;
 220 
 221         /* Set DAI format */
 222         switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
 223         case SND_SOC_DAIFMT_LEFT_J:
 224                 val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
 225                 break;
 226         case SND_SOC_DAIFMT_I2S:
 227                 val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
 228                 break;
 229         case SND_SOC_DAIFMT_RIGHT_J:
 230                 val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
 231                 break;
 232         case SND_SOC_DAIFMT_DSP_A:
 233                 val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
 234                 break;
 235         default:
 236                 dev_err(component->dev, "unsupported dai format\n");
 237                 return -EINVAL;
 238         }
 239 
 240         regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
 241                            CS42XX8_INTF_DAC_DIF_MASK |
 242                            CS42XX8_INTF_ADC_DIF_MASK, val);
 243 
 244         /* Set master/slave audio interface */
 245         switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
 246         case SND_SOC_DAIFMT_CBS_CFS:
 247                 cs42xx8->slave_mode = true;
 248                 break;
 249         case SND_SOC_DAIFMT_CBM_CFM:
 250                 cs42xx8->slave_mode = false;
 251                 break;
 252         default:
 253                 dev_err(component->dev, "unsupported master/slave mode\n");
 254                 return -EINVAL;
 255         }
 256 
 257         return 0;
 258 }
 259 
 260 static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
 261                              struct snd_pcm_hw_params *params,
 262                              struct snd_soc_dai *dai)
 263 {
 264         struct snd_soc_component *component = dai->component;
 265         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 266         bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 267         u32 ratio[2];
 268         u32 rate[2];
 269         u32 fm[2];
 270         u32 i, val, mask;
 271         bool condition1, condition2;
 272 
 273         if (tx)
 274                 cs42xx8->tx_channels = params_channels(params);
 275 
 276         rate[tx]  = params_rate(params);
 277         rate[!tx] = cs42xx8->rate[!tx];
 278 
 279         ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0;
 280         ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0;
 281 
 282         /* Get functional mode for tx and rx according to rate */
 283         for (i = 0; i < 2; i++) {
 284                 if (cs42xx8->slave_mode) {
 285                         fm[i] = CS42XX8_FM_AUTO;
 286                 } else {
 287                         if (rate[i] < 50000) {
 288                                 fm[i] = CS42XX8_FM_SINGLE;
 289                         } else if (rate[i] > 50000 && rate[i] < 100000) {
 290                                 fm[i] = CS42XX8_FM_DOUBLE;
 291                         } else if (rate[i] > 100000 && rate[i] < 200000) {
 292                                 fm[i] = CS42XX8_FM_QUAD;
 293                         } else {
 294                                 dev_err(component->dev,
 295                                         "unsupported sample rate\n");
 296                                 return -EINVAL;
 297                         }
 298                 }
 299         }
 300 
 301         for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
 302                 /* Is the ratio[tx] valid ? */
 303                 condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ?
 304                         (cs42xx8_ratios[i].ratio[0] == ratio[tx] ||
 305                         cs42xx8_ratios[i].ratio[1] == ratio[tx] ||
 306                         cs42xx8_ratios[i].ratio[2] == ratio[tx]) :
 307                         (cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) &&
 308                         cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk &&
 309                         cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk;
 310 
 311                 if (!ratio[tx])
 312                         condition1 = true;
 313 
 314                 /* Is the ratio[!tx] valid ? */
 315                 condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ?
 316                         (cs42xx8_ratios[i].ratio[0] == ratio[!tx] ||
 317                         cs42xx8_ratios[i].ratio[1] == ratio[!tx] ||
 318                         cs42xx8_ratios[i].ratio[2] == ratio[!tx]) :
 319                         (cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx]));
 320 
 321                 if (!ratio[!tx])
 322                         condition2 = true;
 323 
 324                 /*
 325                  * Both ratio[tx] and ratio[!tx] is valid, then we get
 326                  * a proper MFreq.
 327                  */
 328                 if (condition1 && condition2)
 329                         break;
 330         }
 331 
 332         if (i == ARRAY_SIZE(cs42xx8_ratios)) {
 333                 dev_err(component->dev, "unsupported sysclk ratio\n");
 334                 return -EINVAL;
 335         }
 336 
 337         cs42xx8->rate[tx] = params_rate(params);
 338 
 339         mask = CS42XX8_FUNCMOD_MFREQ_MASK;
 340         val = cs42xx8_ratios[i].mfreq;
 341 
 342         regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
 343                            CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
 344                            CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val);
 345 
 346         return 0;
 347 }
 348 
 349 static int cs42xx8_hw_free(struct snd_pcm_substream *substream,
 350                            struct snd_soc_dai *dai)
 351 {
 352         struct snd_soc_component *component = dai->component;
 353         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 354         bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 355 
 356         /* Clear stored rate */
 357         cs42xx8->rate[tx] = 0;
 358 
 359         regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
 360                            CS42XX8_FUNCMOD_xC_FM_MASK(tx),
 361                            CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO));
 362         return 0;
 363 }
 364 
 365 static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
 366 {
 367         struct snd_soc_component *component = dai->component;
 368         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 369         u8 dac_unmute = cs42xx8->tx_channels ?
 370                         ~((0x1 << cs42xx8->tx_channels) - 1) : 0;
 371 
 372         regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
 373                      mute ? CS42XX8_DACMUTE_ALL : dac_unmute);
 374 
 375         return 0;
 376 }
 377 
 378 static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
 379         .set_fmt        = cs42xx8_set_dai_fmt,
 380         .set_sysclk     = cs42xx8_set_dai_sysclk,
 381         .hw_params      = cs42xx8_hw_params,
 382         .hw_free        = cs42xx8_hw_free,
 383         .digital_mute   = cs42xx8_digital_mute,
 384 };
 385 
 386 static struct snd_soc_dai_driver cs42xx8_dai = {
 387         .playback = {
 388                 .stream_name = "Playback",
 389                 .channels_min = 1,
 390                 .channels_max = 8,
 391                 .rates = SNDRV_PCM_RATE_8000_192000,
 392                 .formats = CS42XX8_FORMATS,
 393         },
 394         .capture = {
 395                 .stream_name = "Capture",
 396                 .channels_min = 1,
 397                 .rates = SNDRV_PCM_RATE_8000_192000,
 398                 .formats = CS42XX8_FORMATS,
 399         },
 400         .ops = &cs42xx8_dai_ops,
 401 };
 402 
 403 static const struct reg_default cs42xx8_reg[] = {
 404         { 0x02, 0x00 },   /* Power Control */
 405         { 0x03, 0xF0 },   /* Functional Mode */
 406         { 0x04, 0x46 },   /* Interface Formats */
 407         { 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */
 408         { 0x06, 0x10 },   /* Transition Control */
 409         { 0x07, 0x00 },   /* DAC Channel Mute */
 410         { 0x08, 0x00 },   /* Volume Control AOUT1 */
 411         { 0x09, 0x00 },   /* Volume Control AOUT2 */
 412         { 0x0a, 0x00 },   /* Volume Control AOUT3 */
 413         { 0x0b, 0x00 },   /* Volume Control AOUT4 */
 414         { 0x0c, 0x00 },   /* Volume Control AOUT5 */
 415         { 0x0d, 0x00 },   /* Volume Control AOUT6 */
 416         { 0x0e, 0x00 },   /* Volume Control AOUT7 */
 417         { 0x0f, 0x00 },   /* Volume Control AOUT8 */
 418         { 0x10, 0x00 },   /* DAC Channel Invert */
 419         { 0x11, 0x00 },   /* Volume Control AIN1 */
 420         { 0x12, 0x00 },   /* Volume Control AIN2 */
 421         { 0x13, 0x00 },   /* Volume Control AIN3 */
 422         { 0x14, 0x00 },   /* Volume Control AIN4 */
 423         { 0x15, 0x00 },   /* Volume Control AIN5 */
 424         { 0x16, 0x00 },   /* Volume Control AIN6 */
 425         { 0x17, 0x00 },   /* ADC Channel Invert */
 426         { 0x18, 0x00 },   /* Status Control */
 427         { 0x1a, 0x00 },   /* Status Mask */
 428         { 0x1b, 0x00 },   /* MUTEC Pin Control */
 429 };
 430 
 431 static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
 432 {
 433         switch (reg) {
 434         case CS42XX8_STATUS:
 435                 return true;
 436         default:
 437                 return false;
 438         }
 439 }
 440 
 441 static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
 442 {
 443         switch (reg) {
 444         case CS42XX8_CHIPID:
 445         case CS42XX8_STATUS:
 446                 return false;
 447         default:
 448                 return true;
 449         }
 450 }
 451 
 452 const struct regmap_config cs42xx8_regmap_config = {
 453         .reg_bits = 8,
 454         .val_bits = 8,
 455 
 456         .max_register = CS42XX8_LASTREG,
 457         .reg_defaults = cs42xx8_reg,
 458         .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
 459         .volatile_reg = cs42xx8_volatile_register,
 460         .writeable_reg = cs42xx8_writeable_register,
 461         .cache_type = REGCACHE_RBTREE,
 462 };
 463 EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
 464 
 465 static int cs42xx8_component_probe(struct snd_soc_component *component)
 466 {
 467         struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 468         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 469 
 470         switch (cs42xx8->drvdata->num_adcs) {
 471         case 3:
 472                 snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls,
 473                                         ARRAY_SIZE(cs42xx8_adc3_snd_controls));
 474                 snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
 475                                         ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
 476                 snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
 477                                         ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
 478                 break;
 479         default:
 480                 break;
 481         }
 482 
 483         /* Mute all DAC channels */
 484         regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
 485 
 486         return 0;
 487 }
 488 
 489 static const struct snd_soc_component_driver cs42xx8_driver = {
 490         .probe                  = cs42xx8_component_probe,
 491         .controls               = cs42xx8_snd_controls,
 492         .num_controls           = ARRAY_SIZE(cs42xx8_snd_controls),
 493         .dapm_widgets           = cs42xx8_dapm_widgets,
 494         .num_dapm_widgets       = ARRAY_SIZE(cs42xx8_dapm_widgets),
 495         .dapm_routes            = cs42xx8_dapm_routes,
 496         .num_dapm_routes        = ARRAY_SIZE(cs42xx8_dapm_routes),
 497         .use_pmdown_time        = 1,
 498         .endianness             = 1,
 499         .non_legacy_dai_naming  = 1,
 500 };
 501 
 502 const struct cs42xx8_driver_data cs42448_data = {
 503         .name = "cs42448",
 504         .num_adcs = 3,
 505 };
 506 EXPORT_SYMBOL_GPL(cs42448_data);
 507 
 508 const struct cs42xx8_driver_data cs42888_data = {
 509         .name = "cs42888",
 510         .num_adcs = 2,
 511 };
 512 EXPORT_SYMBOL_GPL(cs42888_data);
 513 
 514 const struct of_device_id cs42xx8_of_match[] = {
 515         { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
 516         { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
 517         { /* sentinel */ }
 518 };
 519 MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
 520 EXPORT_SYMBOL_GPL(cs42xx8_of_match);
 521 
 522 int cs42xx8_probe(struct device *dev, struct regmap *regmap)
 523 {
 524         const struct of_device_id *of_id;
 525         struct cs42xx8_priv *cs42xx8;
 526         int ret, val, i;
 527 
 528         if (IS_ERR(regmap)) {
 529                 ret = PTR_ERR(regmap);
 530                 dev_err(dev, "failed to allocate regmap: %d\n", ret);
 531                 return ret;
 532         }
 533 
 534         cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
 535         if (cs42xx8 == NULL)
 536                 return -ENOMEM;
 537 
 538         cs42xx8->regmap = regmap;
 539         dev_set_drvdata(dev, cs42xx8);
 540 
 541         of_id = of_match_device(cs42xx8_of_match, dev);
 542         if (of_id)
 543                 cs42xx8->drvdata = of_id->data;
 544 
 545         if (!cs42xx8->drvdata) {
 546                 dev_err(dev, "failed to find driver data\n");
 547                 return -EINVAL;
 548         }
 549 
 550         cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
 551                                                         GPIOD_OUT_HIGH);
 552         if (IS_ERR(cs42xx8->gpiod_reset))
 553                 return PTR_ERR(cs42xx8->gpiod_reset);
 554 
 555         gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
 556 
 557         cs42xx8->clk = devm_clk_get(dev, "mclk");
 558         if (IS_ERR(cs42xx8->clk)) {
 559                 dev_err(dev, "failed to get the clock: %ld\n",
 560                                 PTR_ERR(cs42xx8->clk));
 561                 return -EINVAL;
 562         }
 563 
 564         cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
 565 
 566         for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
 567                 cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
 568 
 569         ret = devm_regulator_bulk_get(dev,
 570                         ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
 571         if (ret) {
 572                 dev_err(dev, "failed to request supplies: %d\n", ret);
 573                 return ret;
 574         }
 575 
 576         ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
 577                                     cs42xx8->supplies);
 578         if (ret) {
 579                 dev_err(dev, "failed to enable supplies: %d\n", ret);
 580                 return ret;
 581         }
 582 
 583         /* Make sure hardware reset done */
 584         msleep(5);
 585 
 586         /* Validate the chip ID */
 587         ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
 588         if (ret < 0) {
 589                 dev_err(dev, "failed to get device ID, ret = %d", ret);
 590                 goto err_enable;
 591         }
 592 
 593         /* The top four bits of the chip ID should be 0000 */
 594         if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
 595                 dev_err(dev, "unmatched chip ID: %d\n",
 596                         (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
 597                 ret = -EINVAL;
 598                 goto err_enable;
 599         }
 600 
 601         dev_info(dev, "found device, revision %X\n",
 602                         val & CS42XX8_CHIPID_REV_ID_MASK);
 603 
 604         cs42xx8_dai.name = cs42xx8->drvdata->name;
 605 
 606         /* Each adc supports stereo input */
 607         cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
 608 
 609         ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
 610         if (ret) {
 611                 dev_err(dev, "failed to register component:%d\n", ret);
 612                 goto err_enable;
 613         }
 614 
 615         regcache_cache_only(cs42xx8->regmap, true);
 616 
 617 err_enable:
 618         regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
 619                                cs42xx8->supplies);
 620 
 621         return ret;
 622 }
 623 EXPORT_SYMBOL_GPL(cs42xx8_probe);
 624 
 625 #ifdef CONFIG_PM
 626 static int cs42xx8_runtime_resume(struct device *dev)
 627 {
 628         struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
 629         int ret;
 630 
 631         ret = clk_prepare_enable(cs42xx8->clk);
 632         if (ret) {
 633                 dev_err(dev, "failed to enable mclk: %d\n", ret);
 634                 return ret;
 635         }
 636 
 637         gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
 638 
 639         ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
 640                                     cs42xx8->supplies);
 641         if (ret) {
 642                 dev_err(dev, "failed to enable supplies: %d\n", ret);
 643                 goto err_clk;
 644         }
 645 
 646         /* Make sure hardware reset done */
 647         msleep(5);
 648 
 649         regcache_cache_only(cs42xx8->regmap, false);
 650         regcache_mark_dirty(cs42xx8->regmap);
 651 
 652         ret = regcache_sync(cs42xx8->regmap);
 653         if (ret) {
 654                 dev_err(dev, "failed to sync regmap: %d\n", ret);
 655                 goto err_bulk;
 656         }
 657 
 658         return 0;
 659 
 660 err_bulk:
 661         regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
 662                                cs42xx8->supplies);
 663 err_clk:
 664         clk_disable_unprepare(cs42xx8->clk);
 665 
 666         return ret;
 667 }
 668 
 669 static int cs42xx8_runtime_suspend(struct device *dev)
 670 {
 671         struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
 672 
 673         regcache_cache_only(cs42xx8->regmap, true);
 674 
 675         regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
 676                                cs42xx8->supplies);
 677 
 678         gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1);
 679 
 680         clk_disable_unprepare(cs42xx8->clk);
 681 
 682         return 0;
 683 }
 684 #endif
 685 
 686 const struct dev_pm_ops cs42xx8_pm = {
 687         SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 688                                 pm_runtime_force_resume)
 689         SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
 690 };
 691 EXPORT_SYMBOL_GPL(cs42xx8_pm);
 692 
 693 MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
 694 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 695 MODULE_LICENSE("GPL");

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