Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
0003  *
0004  * Copyright (C) 2014 Freescale Semiconductor, Inc.
0005  *
0006  * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
0007  *
0008  * This file is licensed under the terms of the GNU General Public License
0009  * version 2. This program is licensed "as is" without any warranty of any
0010  * kind, whether express or implied.
0011  */
0012 
0013 #include <linux/clk.h>
0014 #include <linux/delay.h>
0015 #include <linux/module.h>
0016 #include <linux/of_device.h>
0017 #include <linux/gpio/consumer.h>
0018 #include <linux/pm_runtime.h>
0019 #include <linux/regulator/consumer.h>
0020 #include <sound/pcm_params.h>
0021 #include <sound/soc.h>
0022 #include <sound/tlv.h>
0023 
0024 #include "cs42xx8.h"
0025 
0026 #define CS42XX8_NUM_SUPPLIES 4
0027 static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
0028     "VA",
0029     "VD",
0030     "VLS",
0031     "VLC",
0032 };
0033 
0034 #define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
0035              SNDRV_PCM_FMTBIT_S20_3LE | \
0036              SNDRV_PCM_FMTBIT_S24_LE | \
0037              SNDRV_PCM_FMTBIT_S32_LE)
0038 
0039 /* codec private data */
0040 struct cs42xx8_priv {
0041     struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
0042     const struct cs42xx8_driver_data *drvdata;
0043     struct regmap *regmap;
0044     struct clk *clk;
0045 
0046     bool slave_mode;
0047     unsigned long sysclk;
0048     u32 tx_channels;
0049     struct gpio_desc *gpiod_reset;
0050     u32 rate[2];
0051 };
0052 
0053 /* -127.5dB to 0dB with step of 0.5dB */
0054 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
0055 /* -64dB to 24dB with step of 0.5dB */
0056 static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
0057 
0058 static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
0059 static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
0060                     "Soft Ramp", "Soft Ramp on Zero Cross" };
0061 
0062 static const struct soc_enum adc1_single_enum =
0063     SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
0064 static const struct soc_enum adc2_single_enum =
0065     SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
0066 static const struct soc_enum adc3_single_enum =
0067     SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
0068 static const struct soc_enum dac_szc_enum =
0069     SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
0070 static const struct soc_enum adc_szc_enum =
0071     SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
0072 
0073 static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
0074     SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
0075              CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
0076     SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
0077              CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
0078     SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
0079              CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
0080     SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
0081              CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
0082     SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
0083                CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
0084     SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
0085                CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
0086     SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
0087     SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
0088     SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
0089     SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
0090     SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
0091     SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
0092     SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
0093     SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
0094     SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
0095     SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
0096     SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
0097     SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
0098     SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
0099     SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
0100     SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
0101     SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
0102 };
0103 
0104 static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
0105     SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
0106                CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
0107     SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
0108     SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
0109 };
0110 
0111 static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
0112     SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
0113     SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
0114     SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
0115     SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
0116 
0117     SND_SOC_DAPM_OUTPUT("AOUT1L"),
0118     SND_SOC_DAPM_OUTPUT("AOUT1R"),
0119     SND_SOC_DAPM_OUTPUT("AOUT2L"),
0120     SND_SOC_DAPM_OUTPUT("AOUT2R"),
0121     SND_SOC_DAPM_OUTPUT("AOUT3L"),
0122     SND_SOC_DAPM_OUTPUT("AOUT3R"),
0123     SND_SOC_DAPM_OUTPUT("AOUT4L"),
0124     SND_SOC_DAPM_OUTPUT("AOUT4R"),
0125 
0126     SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
0127     SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
0128 
0129     SND_SOC_DAPM_INPUT("AIN1L"),
0130     SND_SOC_DAPM_INPUT("AIN1R"),
0131     SND_SOC_DAPM_INPUT("AIN2L"),
0132     SND_SOC_DAPM_INPUT("AIN2R"),
0133 
0134     SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
0135 };
0136 
0137 static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
0138     SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
0139 
0140     SND_SOC_DAPM_INPUT("AIN3L"),
0141     SND_SOC_DAPM_INPUT("AIN3R"),
0142 };
0143 
0144 static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
0145     /* Playback */
0146     { "AOUT1L", NULL, "DAC1" },
0147     { "AOUT1R", NULL, "DAC1" },
0148     { "DAC1", NULL, "PWR" },
0149 
0150     { "AOUT2L", NULL, "DAC2" },
0151     { "AOUT2R", NULL, "DAC2" },
0152     { "DAC2", NULL, "PWR" },
0153 
0154     { "AOUT3L", NULL, "DAC3" },
0155     { "AOUT3R", NULL, "DAC3" },
0156     { "DAC3", NULL, "PWR" },
0157 
0158     { "AOUT4L", NULL, "DAC4" },
0159     { "AOUT4R", NULL, "DAC4" },
0160     { "DAC4", NULL, "PWR" },
0161 
0162     /* Capture */
0163     { "ADC1", NULL, "AIN1L" },
0164     { "ADC1", NULL, "AIN1R" },
0165     { "ADC1", NULL, "PWR" },
0166 
0167     { "ADC2", NULL, "AIN2L" },
0168     { "ADC2", NULL, "AIN2R" },
0169     { "ADC2", NULL, "PWR" },
0170 };
0171 
0172 static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
0173     /* Capture */
0174     { "ADC3", NULL, "AIN3L" },
0175     { "ADC3", NULL, "AIN3R" },
0176     { "ADC3", NULL, "PWR" },
0177 };
0178 
0179 struct cs42xx8_ratios {
0180     unsigned int mfreq;
0181     unsigned int min_mclk;
0182     unsigned int max_mclk;
0183     unsigned int ratio[3];
0184 };
0185 
0186 /*
0187  * According to reference mannual, define the cs42xx8_ratio struct
0188  * MFreq2 | MFreq1 | MFreq0 |     Description     | SSM | DSM | QSM |
0189  * 0      | 0      | 0      |1.029MHz to 12.8MHz  | 256 | 128 |  64 |
0190  * 0      | 0      | 1      |1.536MHz to 19.2MHz  | 384 | 192 |  96 |
0191  * 0      | 1      | 0      |2.048MHz to 25.6MHz  | 512 | 256 | 128 |
0192  * 0      | 1      | 1      |3.072MHz to 38.4MHz  | 768 | 384 | 192 |
0193  * 1      | x      | x      |4.096MHz to 51.2MHz  |1024 | 512 | 256 |
0194  */
0195 static const struct cs42xx8_ratios cs42xx8_ratios[] = {
0196     { 0, 1029000, 12800000, {256, 128, 64} },
0197     { 2, 1536000, 19200000, {384, 192, 96} },
0198     { 4, 2048000, 25600000, {512, 256, 128} },
0199     { 6, 3072000, 38400000, {768, 384, 192} },
0200     { 8, 4096000, 51200000, {1024, 512, 256} },
0201 };
0202 
0203 static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
0204                   int clk_id, unsigned int freq, int dir)
0205 {
0206     struct snd_soc_component *component = codec_dai->component;
0207     struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
0208 
0209     cs42xx8->sysclk = freq;
0210 
0211     return 0;
0212 }
0213 
0214 static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
0215                    unsigned int format)
0216 {
0217     struct snd_soc_component *component = codec_dai->component;
0218     struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
0219     u32 val;
0220 
0221     /* Set DAI format */
0222     switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
0223     case SND_SOC_DAIFMT_LEFT_J:
0224         val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
0225         break;
0226     case SND_SOC_DAIFMT_I2S:
0227         val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
0228         break;
0229     case SND_SOC_DAIFMT_RIGHT_J:
0230         val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
0231         break;
0232     case SND_SOC_DAIFMT_DSP_A:
0233         val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
0234         break;
0235     default:
0236         dev_err(component->dev, "unsupported dai format\n");
0237         return -EINVAL;
0238     }
0239 
0240     regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
0241                CS42XX8_INTF_DAC_DIF_MASK |
0242                CS42XX8_INTF_ADC_DIF_MASK, val);
0243 
0244     /* Set master/slave audio interface */
0245     switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
0246     case SND_SOC_DAIFMT_CBS_CFS:
0247         cs42xx8->slave_mode = true;
0248         break;
0249     case SND_SOC_DAIFMT_CBM_CFM:
0250         cs42xx8->slave_mode = false;
0251         break;
0252     default:
0253         dev_err(component->dev, "unsupported master/slave mode\n");
0254         return -EINVAL;
0255     }
0256 
0257     return 0;
0258 }
0259 
0260 static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
0261                  struct snd_pcm_hw_params *params,
0262                  struct snd_soc_dai *dai)
0263 {
0264     struct snd_soc_component *component = dai->component;
0265     struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
0266     bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
0267     u32 ratio[2];
0268     u32 rate[2];
0269     u32 fm[2];
0270     u32 i, val, mask;
0271     bool condition1, condition2;
0272 
0273     if (tx)
0274         cs42xx8->tx_channels = params_channels(params);
0275 
0276     rate[tx]  = params_rate(params);
0277     rate[!tx] = cs42xx8->rate[!tx];
0278 
0279     ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0;
0280     ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0;
0281 
0282     /* Get functional mode for tx and rx according to rate */
0283     for (i = 0; i < 2; i++) {
0284         if (cs42xx8->slave_mode) {
0285             fm[i] = CS42XX8_FM_AUTO;
0286         } else {
0287             if (rate[i] < 50000) {
0288                 fm[i] = CS42XX8_FM_SINGLE;
0289             } else if (rate[i] > 50000 && rate[i] < 100000) {
0290                 fm[i] = CS42XX8_FM_DOUBLE;
0291             } else if (rate[i] > 100000 && rate[i] < 200000) {
0292                 fm[i] = CS42XX8_FM_QUAD;
0293             } else {
0294                 dev_err(component->dev,
0295                     "unsupported sample rate\n");
0296                 return -EINVAL;
0297             }
0298         }
0299     }
0300 
0301     for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
0302         /* Is the ratio[tx] valid ? */
0303         condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ?
0304             (cs42xx8_ratios[i].ratio[0] == ratio[tx] ||
0305             cs42xx8_ratios[i].ratio[1] == ratio[tx] ||
0306             cs42xx8_ratios[i].ratio[2] == ratio[tx]) :
0307             (cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) &&
0308             cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk &&
0309             cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk;
0310 
0311         if (!ratio[tx])
0312             condition1 = true;
0313 
0314         /* Is the ratio[!tx] valid ? */
0315         condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ?
0316             (cs42xx8_ratios[i].ratio[0] == ratio[!tx] ||
0317             cs42xx8_ratios[i].ratio[1] == ratio[!tx] ||
0318             cs42xx8_ratios[i].ratio[2] == ratio[!tx]) :
0319             (cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx]));
0320 
0321         if (!ratio[!tx])
0322             condition2 = true;
0323 
0324         /*
0325          * Both ratio[tx] and ratio[!tx] is valid, then we get
0326          * a proper MFreq.
0327          */
0328         if (condition1 && condition2)
0329             break;
0330     }
0331 
0332     if (i == ARRAY_SIZE(cs42xx8_ratios)) {
0333         dev_err(component->dev, "unsupported sysclk ratio\n");
0334         return -EINVAL;
0335     }
0336 
0337     cs42xx8->rate[tx] = params_rate(params);
0338 
0339     mask = CS42XX8_FUNCMOD_MFREQ_MASK;
0340     val = cs42xx8_ratios[i].mfreq;
0341 
0342     regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
0343                CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
0344                CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val);
0345 
0346     return 0;
0347 }
0348 
0349 static int cs42xx8_hw_free(struct snd_pcm_substream *substream,
0350                struct snd_soc_dai *dai)
0351 {
0352     struct snd_soc_component *component = dai->component;
0353     struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
0354     bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
0355 
0356     /* Clear stored rate */
0357     cs42xx8->rate[tx] = 0;
0358 
0359     regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
0360                CS42XX8_FUNCMOD_xC_FM_MASK(tx),
0361                CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO));
0362     return 0;
0363 }
0364 
0365 static int cs42xx8_mute(struct snd_soc_dai *dai, int mute, int direction)
0366 {
0367     struct snd_soc_component *component = dai->component;
0368     struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
0369     u8 dac_unmute = cs42xx8->tx_channels ?
0370                 ~((0x1 << cs42xx8->tx_channels) - 1) : 0;
0371 
0372     regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
0373              mute ? CS42XX8_DACMUTE_ALL : dac_unmute);
0374 
0375     return 0;
0376 }
0377 
0378 static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
0379     .set_fmt    = cs42xx8_set_dai_fmt,
0380     .set_sysclk = cs42xx8_set_dai_sysclk,
0381     .hw_params  = cs42xx8_hw_params,
0382     .hw_free    = cs42xx8_hw_free,
0383     .mute_stream    = cs42xx8_mute,
0384     .no_capture_mute = 1,
0385 };
0386 
0387 static struct snd_soc_dai_driver cs42xx8_dai = {
0388     .playback = {
0389         .stream_name = "Playback",
0390         .channels_min = 1,
0391         .channels_max = 8,
0392         .rates = SNDRV_PCM_RATE_8000_192000,
0393         .formats = CS42XX8_FORMATS,
0394     },
0395     .capture = {
0396         .stream_name = "Capture",
0397         .channels_min = 1,
0398         .rates = SNDRV_PCM_RATE_8000_192000,
0399         .formats = CS42XX8_FORMATS,
0400     },
0401     .ops = &cs42xx8_dai_ops,
0402 };
0403 
0404 static const struct reg_default cs42xx8_reg[] = {
0405     { 0x02, 0x00 },   /* Power Control */
0406     { 0x03, 0xF0 },   /* Functional Mode */
0407     { 0x04, 0x46 },   /* Interface Formats */
0408     { 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */
0409     { 0x06, 0x10 },   /* Transition Control */
0410     { 0x07, 0x00 },   /* DAC Channel Mute */
0411     { 0x08, 0x00 },   /* Volume Control AOUT1 */
0412     { 0x09, 0x00 },   /* Volume Control AOUT2 */
0413     { 0x0a, 0x00 },   /* Volume Control AOUT3 */
0414     { 0x0b, 0x00 },   /* Volume Control AOUT4 */
0415     { 0x0c, 0x00 },   /* Volume Control AOUT5 */
0416     { 0x0d, 0x00 },   /* Volume Control AOUT6 */
0417     { 0x0e, 0x00 },   /* Volume Control AOUT7 */
0418     { 0x0f, 0x00 },   /* Volume Control AOUT8 */
0419     { 0x10, 0x00 },   /* DAC Channel Invert */
0420     { 0x11, 0x00 },   /* Volume Control AIN1 */
0421     { 0x12, 0x00 },   /* Volume Control AIN2 */
0422     { 0x13, 0x00 },   /* Volume Control AIN3 */
0423     { 0x14, 0x00 },   /* Volume Control AIN4 */
0424     { 0x15, 0x00 },   /* Volume Control AIN5 */
0425     { 0x16, 0x00 },   /* Volume Control AIN6 */
0426     { 0x17, 0x00 },   /* ADC Channel Invert */
0427     { 0x18, 0x00 },   /* Status Control */
0428     { 0x1a, 0x00 },   /* Status Mask */
0429     { 0x1b, 0x00 },   /* MUTEC Pin Control */
0430 };
0431 
0432 static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
0433 {
0434     switch (reg) {
0435     case CS42XX8_STATUS:
0436         return true;
0437     default:
0438         return false;
0439     }
0440 }
0441 
0442 static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
0443 {
0444     switch (reg) {
0445     case CS42XX8_CHIPID:
0446     case CS42XX8_STATUS:
0447         return false;
0448     default:
0449         return true;
0450     }
0451 }
0452 
0453 const struct regmap_config cs42xx8_regmap_config = {
0454     .reg_bits = 8,
0455     .val_bits = 8,
0456 
0457     .max_register = CS42XX8_LASTREG,
0458     .reg_defaults = cs42xx8_reg,
0459     .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
0460     .volatile_reg = cs42xx8_volatile_register,
0461     .writeable_reg = cs42xx8_writeable_register,
0462     .cache_type = REGCACHE_RBTREE,
0463 };
0464 EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
0465 
0466 static int cs42xx8_component_probe(struct snd_soc_component *component)
0467 {
0468     struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
0469     struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
0470 
0471     switch (cs42xx8->drvdata->num_adcs) {
0472     case 3:
0473         snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls,
0474                     ARRAY_SIZE(cs42xx8_adc3_snd_controls));
0475         snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
0476                     ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
0477         snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
0478                     ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
0479         break;
0480     default:
0481         break;
0482     }
0483 
0484     /* Mute all DAC channels */
0485     regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
0486 
0487     return 0;
0488 }
0489 
0490 static const struct snd_soc_component_driver cs42xx8_driver = {
0491     .probe          = cs42xx8_component_probe,
0492     .controls       = cs42xx8_snd_controls,
0493     .num_controls       = ARRAY_SIZE(cs42xx8_snd_controls),
0494     .dapm_widgets       = cs42xx8_dapm_widgets,
0495     .num_dapm_widgets   = ARRAY_SIZE(cs42xx8_dapm_widgets),
0496     .dapm_routes        = cs42xx8_dapm_routes,
0497     .num_dapm_routes    = ARRAY_SIZE(cs42xx8_dapm_routes),
0498     .use_pmdown_time    = 1,
0499     .endianness     = 1,
0500 };
0501 
0502 const struct cs42xx8_driver_data cs42448_data = {
0503     .name = "cs42448",
0504     .num_adcs = 3,
0505 };
0506 EXPORT_SYMBOL_GPL(cs42448_data);
0507 
0508 const struct cs42xx8_driver_data cs42888_data = {
0509     .name = "cs42888",
0510     .num_adcs = 2,
0511 };
0512 EXPORT_SYMBOL_GPL(cs42888_data);
0513 
0514 const struct of_device_id cs42xx8_of_match[] = {
0515     { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
0516     { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
0517     { /* sentinel */ }
0518 };
0519 MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
0520 EXPORT_SYMBOL_GPL(cs42xx8_of_match);
0521 
0522 int cs42xx8_probe(struct device *dev, struct regmap *regmap)
0523 {
0524     const struct of_device_id *of_id;
0525     struct cs42xx8_priv *cs42xx8;
0526     int ret, val, i;
0527 
0528     if (IS_ERR(regmap)) {
0529         ret = PTR_ERR(regmap);
0530         dev_err(dev, "failed to allocate regmap: %d\n", ret);
0531         return ret;
0532     }
0533 
0534     cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
0535     if (cs42xx8 == NULL)
0536         return -ENOMEM;
0537 
0538     cs42xx8->regmap = regmap;
0539     dev_set_drvdata(dev, cs42xx8);
0540 
0541     of_id = of_match_device(cs42xx8_of_match, dev);
0542     if (of_id)
0543         cs42xx8->drvdata = of_id->data;
0544 
0545     if (!cs42xx8->drvdata) {
0546         dev_err(dev, "failed to find driver data\n");
0547         return -EINVAL;
0548     }
0549 
0550     cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
0551                             GPIOD_OUT_HIGH);
0552     if (IS_ERR(cs42xx8->gpiod_reset))
0553         return PTR_ERR(cs42xx8->gpiod_reset);
0554 
0555     gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
0556 
0557     cs42xx8->clk = devm_clk_get(dev, "mclk");
0558     if (IS_ERR(cs42xx8->clk)) {
0559         dev_err(dev, "failed to get the clock: %ld\n",
0560                 PTR_ERR(cs42xx8->clk));
0561         return -EINVAL;
0562     }
0563 
0564     cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
0565 
0566     for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
0567         cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
0568 
0569     ret = devm_regulator_bulk_get(dev,
0570             ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
0571     if (ret) {
0572         dev_err(dev, "failed to request supplies: %d\n", ret);
0573         return ret;
0574     }
0575 
0576     ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
0577                     cs42xx8->supplies);
0578     if (ret) {
0579         dev_err(dev, "failed to enable supplies: %d\n", ret);
0580         return ret;
0581     }
0582 
0583     /* Make sure hardware reset done */
0584     msleep(5);
0585 
0586     /* Validate the chip ID */
0587     ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
0588     if (ret < 0) {
0589         dev_err(dev, "failed to get device ID, ret = %d", ret);
0590         goto err_enable;
0591     }
0592 
0593     /* The top four bits of the chip ID should be 0000 */
0594     if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
0595         dev_err(dev, "unmatched chip ID: %d\n",
0596             (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
0597         ret = -EINVAL;
0598         goto err_enable;
0599     }
0600 
0601     dev_info(dev, "found device, revision %X\n",
0602             val & CS42XX8_CHIPID_REV_ID_MASK);
0603 
0604     cs42xx8_dai.name = cs42xx8->drvdata->name;
0605 
0606     /* Each adc supports stereo input */
0607     cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
0608 
0609     ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
0610     if (ret) {
0611         dev_err(dev, "failed to register component:%d\n", ret);
0612         goto err_enable;
0613     }
0614 
0615     regcache_cache_only(cs42xx8->regmap, true);
0616 
0617 err_enable:
0618     regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
0619                    cs42xx8->supplies);
0620 
0621     return ret;
0622 }
0623 EXPORT_SYMBOL_GPL(cs42xx8_probe);
0624 
0625 #ifdef CONFIG_PM
0626 static int cs42xx8_runtime_resume(struct device *dev)
0627 {
0628     struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
0629     int ret;
0630 
0631     ret = clk_prepare_enable(cs42xx8->clk);
0632     if (ret) {
0633         dev_err(dev, "failed to enable mclk: %d\n", ret);
0634         return ret;
0635     }
0636 
0637     gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
0638 
0639     ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
0640                     cs42xx8->supplies);
0641     if (ret) {
0642         dev_err(dev, "failed to enable supplies: %d\n", ret);
0643         goto err_clk;
0644     }
0645 
0646     /* Make sure hardware reset done */
0647     msleep(5);
0648 
0649     regcache_cache_only(cs42xx8->regmap, false);
0650     regcache_mark_dirty(cs42xx8->regmap);
0651 
0652     ret = regcache_sync(cs42xx8->regmap);
0653     if (ret) {
0654         dev_err(dev, "failed to sync regmap: %d\n", ret);
0655         goto err_bulk;
0656     }
0657 
0658     return 0;
0659 
0660 err_bulk:
0661     regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
0662                    cs42xx8->supplies);
0663 err_clk:
0664     clk_disable_unprepare(cs42xx8->clk);
0665 
0666     return ret;
0667 }
0668 
0669 static int cs42xx8_runtime_suspend(struct device *dev)
0670 {
0671     struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
0672 
0673     regcache_cache_only(cs42xx8->regmap, true);
0674 
0675     regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
0676                    cs42xx8->supplies);
0677 
0678     gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1);
0679 
0680     clk_disable_unprepare(cs42xx8->clk);
0681 
0682     return 0;
0683 }
0684 #endif
0685 
0686 const struct dev_pm_ops cs42xx8_pm = {
0687     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0688                 pm_runtime_force_resume)
0689     SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
0690 };
0691 EXPORT_SYMBOL_GPL(cs42xx8_pm);
0692 
0693 MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
0694 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
0695 MODULE_LICENSE("GPL");