680 lines · c
1/*2 * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver3 *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 License9 * version 2. This program is licensed "as is" without any warranty of any10 * 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/gpio/consumer.h>17#include <linux/pm_runtime.h>18#include <linux/regulator/consumer.h>19#include <sound/pcm_params.h>20#include <sound/soc.h>21#include <sound/tlv.h>22 23#include "cs42xx8.h"24 25#define CS42XX8_NUM_SUPPLIES 426static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {27 "VA",28 "VD",29 "VLS",30 "VLC",31};32 33#define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \34 SNDRV_PCM_FMTBIT_S20_3LE | \35 SNDRV_PCM_FMTBIT_S24_LE | \36 SNDRV_PCM_FMTBIT_S32_LE)37 38/* codec private data */39struct cs42xx8_priv {40 struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];41 const struct cs42xx8_driver_data *drvdata;42 struct regmap *regmap;43 struct clk *clk;44 45 bool slave_mode;46 unsigned long sysclk;47 u32 tx_channels;48 struct gpio_desc *gpiod_reset;49 u32 rate[2];50};51 52/* -127.5dB to 0dB with step of 0.5dB */53static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);54/* -64dB to 24dB with step of 0.5dB */55static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);56 57static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };58static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",59 "Soft Ramp", "Soft Ramp on Zero Cross" };60 61static const struct soc_enum adc1_single_enum =62 SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);63static const struct soc_enum adc2_single_enum =64 SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);65static const struct soc_enum adc3_single_enum =66 SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);67static const struct soc_enum dac_szc_enum =68 SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);69static const struct soc_enum adc_szc_enum =70 SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);71 72static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {73 SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,74 CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),75 SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,76 CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),77 SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,78 CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),79 SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,80 CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),81 SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,82 CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),83 SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,84 CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),85 SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),86 SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),87 SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),88 SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),89 SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),90 SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),91 SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),92 SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),93 SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),94 SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),95 SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),96 SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),97 SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),98 SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),99 SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),100 SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),101};102 103static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {104 SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,105 CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),106 SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),107 SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),108};109 110static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {111 SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),112 SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),113 SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),114 SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),115 116 SND_SOC_DAPM_OUTPUT("AOUT1L"),117 SND_SOC_DAPM_OUTPUT("AOUT1R"),118 SND_SOC_DAPM_OUTPUT("AOUT2L"),119 SND_SOC_DAPM_OUTPUT("AOUT2R"),120 SND_SOC_DAPM_OUTPUT("AOUT3L"),121 SND_SOC_DAPM_OUTPUT("AOUT3R"),122 SND_SOC_DAPM_OUTPUT("AOUT4L"),123 SND_SOC_DAPM_OUTPUT("AOUT4R"),124 125 SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),126 SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),127 128 SND_SOC_DAPM_INPUT("AIN1L"),129 SND_SOC_DAPM_INPUT("AIN1R"),130 SND_SOC_DAPM_INPUT("AIN2L"),131 SND_SOC_DAPM_INPUT("AIN2R"),132 133 SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),134};135 136static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {137 SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),138 139 SND_SOC_DAPM_INPUT("AIN3L"),140 SND_SOC_DAPM_INPUT("AIN3R"),141};142 143static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {144 /* Playback */145 { "AOUT1L", NULL, "DAC1" },146 { "AOUT1R", NULL, "DAC1" },147 { "DAC1", NULL, "PWR" },148 149 { "AOUT2L", NULL, "DAC2" },150 { "AOUT2R", NULL, "DAC2" },151 { "DAC2", NULL, "PWR" },152 153 { "AOUT3L", NULL, "DAC3" },154 { "AOUT3R", NULL, "DAC3" },155 { "DAC3", NULL, "PWR" },156 157 { "AOUT4L", NULL, "DAC4" },158 { "AOUT4R", NULL, "DAC4" },159 { "DAC4", NULL, "PWR" },160 161 /* Capture */162 { "ADC1", NULL, "AIN1L" },163 { "ADC1", NULL, "AIN1R" },164 { "ADC1", NULL, "PWR" },165 166 { "ADC2", NULL, "AIN2L" },167 { "ADC2", NULL, "AIN2R" },168 { "ADC2", NULL, "PWR" },169};170 171static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {172 /* Capture */173 { "ADC3", NULL, "AIN3L" },174 { "ADC3", NULL, "AIN3R" },175 { "ADC3", NULL, "PWR" },176};177 178struct cs42xx8_ratios {179 unsigned int mfreq;180 unsigned int min_mclk;181 unsigned int max_mclk;182 unsigned int ratio[3];183};184 185/*186 * According to reference mannual, define the cs42xx8_ratio struct187 * MFreq2 | MFreq1 | MFreq0 | Description | SSM | DSM | QSM |188 * 0 | 0 | 0 |1.029MHz to 12.8MHz | 256 | 128 | 64 |189 * 0 | 0 | 1 |1.536MHz to 19.2MHz | 384 | 192 | 96 |190 * 0 | 1 | 0 |2.048MHz to 25.6MHz | 512 | 256 | 128 |191 * 0 | 1 | 1 |3.072MHz to 38.4MHz | 768 | 384 | 192 |192 * 1 | x | x |4.096MHz to 51.2MHz |1024 | 512 | 256 |193 */194static const struct cs42xx8_ratios cs42xx8_ratios[] = {195 { 0, 1029000, 12800000, {256, 128, 64} },196 { 2, 1536000, 19200000, {384, 192, 96} },197 { 4, 2048000, 25600000, {512, 256, 128} },198 { 6, 3072000, 38400000, {768, 384, 192} },199 { 8, 4096000, 51200000, {1024, 512, 256} },200};201 202static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,203 int clk_id, unsigned int freq, int dir)204{205 struct snd_soc_component *component = codec_dai->component;206 struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);207 208 cs42xx8->sysclk = freq;209 210 return 0;211}212 213static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,214 unsigned int format)215{216 struct snd_soc_component *component = codec_dai->component;217 struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);218 u32 val;219 220 /* Set DAI format */221 switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {222 case SND_SOC_DAIFMT_LEFT_J:223 val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;224 break;225 case SND_SOC_DAIFMT_I2S:226 val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;227 break;228 case SND_SOC_DAIFMT_RIGHT_J:229 val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;230 break;231 case SND_SOC_DAIFMT_DSP_A:232 val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;233 break;234 default:235 dev_err(component->dev, "unsupported dai format\n");236 return -EINVAL;237 }238 239 regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,240 CS42XX8_INTF_DAC_DIF_MASK |241 CS42XX8_INTF_ADC_DIF_MASK, val);242 243 /* Set master/slave audio interface */244 switch (format & SND_SOC_DAIFMT_MASTER_MASK) {245 case SND_SOC_DAIFMT_CBS_CFS:246 cs42xx8->slave_mode = true;247 break;248 case SND_SOC_DAIFMT_CBM_CFM:249 cs42xx8->slave_mode = false;250 break;251 default:252 dev_err(component->dev, "unsupported master/slave mode\n");253 return -EINVAL;254 }255 256 return 0;257}258 259static int cs42xx8_hw_params(struct snd_pcm_substream *substream,260 struct snd_pcm_hw_params *params,261 struct snd_soc_dai *dai)262{263 struct snd_soc_component *component = dai->component;264 struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);265 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;266 u32 ratio[2];267 u32 rate[2];268 u32 fm[2];269 u32 i, val, mask;270 bool condition1, condition2;271 272 if (tx)273 cs42xx8->tx_channels = params_channels(params);274 275 rate[tx] = params_rate(params);276 rate[!tx] = cs42xx8->rate[!tx];277 278 ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0;279 ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0;280 281 /* Get functional mode for tx and rx according to rate */282 for (i = 0; i < 2; i++) {283 if (cs42xx8->slave_mode) {284 fm[i] = CS42XX8_FM_AUTO;285 } else {286 if (rate[i] < 50000) {287 fm[i] = CS42XX8_FM_SINGLE;288 } else if (rate[i] > 50000 && rate[i] < 100000) {289 fm[i] = CS42XX8_FM_DOUBLE;290 } else if (rate[i] > 100000 && rate[i] < 200000) {291 fm[i] = CS42XX8_FM_QUAD;292 } else {293 dev_err(component->dev,294 "unsupported sample rate\n");295 return -EINVAL;296 }297 }298 }299 300 for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {301 /* Is the ratio[tx] valid ? */302 condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ?303 (cs42xx8_ratios[i].ratio[0] == ratio[tx] ||304 cs42xx8_ratios[i].ratio[1] == ratio[tx] ||305 cs42xx8_ratios[i].ratio[2] == ratio[tx]) :306 (cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) &&307 cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk &&308 cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk;309 310 if (!ratio[tx])311 condition1 = true;312 313 /* Is the ratio[!tx] valid ? */314 condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ?315 (cs42xx8_ratios[i].ratio[0] == ratio[!tx] ||316 cs42xx8_ratios[i].ratio[1] == ratio[!tx] ||317 cs42xx8_ratios[i].ratio[2] == ratio[!tx]) :318 (cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx]));319 320 if (!ratio[!tx])321 condition2 = true;322 323 /*324 * Both ratio[tx] and ratio[!tx] is valid, then we get325 * a proper MFreq.326 */327 if (condition1 && condition2)328 break;329 }330 331 if (i == ARRAY_SIZE(cs42xx8_ratios)) {332 dev_err(component->dev, "unsupported sysclk ratio\n");333 return -EINVAL;334 }335 336 cs42xx8->rate[tx] = params_rate(params);337 338 mask = CS42XX8_FUNCMOD_MFREQ_MASK;339 val = cs42xx8_ratios[i].mfreq;340 341 regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,342 CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,343 CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val);344 345 return 0;346}347 348static int cs42xx8_hw_free(struct snd_pcm_substream *substream,349 struct snd_soc_dai *dai)350{351 struct snd_soc_component *component = dai->component;352 struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);353 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;354 355 /* Clear stored rate */356 cs42xx8->rate[tx] = 0;357 358 regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,359 CS42XX8_FUNCMOD_xC_FM_MASK(tx),360 CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO));361 return 0;362}363 364static int cs42xx8_mute(struct snd_soc_dai *dai, int mute, int direction)365{366 struct snd_soc_component *component = dai->component;367 struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);368 u8 dac_unmute = cs42xx8->tx_channels ?369 ~((0x1 << cs42xx8->tx_channels) - 1) : 0;370 371 regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,372 mute ? CS42XX8_DACMUTE_ALL : dac_unmute);373 374 return 0;375}376 377static const struct snd_soc_dai_ops cs42xx8_dai_ops = {378 .set_fmt = cs42xx8_set_dai_fmt,379 .set_sysclk = cs42xx8_set_dai_sysclk,380 .hw_params = cs42xx8_hw_params,381 .hw_free = cs42xx8_hw_free,382 .mute_stream = cs42xx8_mute,383 .no_capture_mute = 1,384};385 386static 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 403static 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 431static 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 441static 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 452const 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_MAPLE,462};463EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);464 465static 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 489static 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};500 501const struct cs42xx8_driver_data cs42448_data = {502 .name = "cs42448",503 .num_adcs = 3,504};505EXPORT_SYMBOL_GPL(cs42448_data);506 507const struct cs42xx8_driver_data cs42888_data = {508 .name = "cs42888",509 .num_adcs = 2,510};511EXPORT_SYMBOL_GPL(cs42888_data);512 513int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata)514{515 struct cs42xx8_priv *cs42xx8;516 int ret, val, i;517 518 if (IS_ERR(regmap)) {519 ret = PTR_ERR(regmap);520 dev_err(dev, "failed to allocate regmap: %d\n", ret);521 return ret;522 }523 524 cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);525 if (cs42xx8 == NULL)526 return -ENOMEM;527 528 dev_set_drvdata(dev, cs42xx8);529 530 cs42xx8->regmap = regmap;531 532 cs42xx8->drvdata = drvdata;533 534 cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",535 GPIOD_OUT_HIGH);536 if (IS_ERR(cs42xx8->gpiod_reset))537 return PTR_ERR(cs42xx8->gpiod_reset);538 539 gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);540 541 cs42xx8->clk = devm_clk_get(dev, "mclk");542 if (IS_ERR(cs42xx8->clk)) {543 dev_err(dev, "failed to get the clock: %ld\n",544 PTR_ERR(cs42xx8->clk));545 return -EINVAL;546 }547 548 cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);549 550 for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)551 cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];552 553 ret = devm_regulator_bulk_get(dev,554 ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);555 if (ret) {556 dev_err(dev, "failed to request supplies: %d\n", ret);557 return ret;558 }559 560 ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),561 cs42xx8->supplies);562 if (ret) {563 dev_err(dev, "failed to enable supplies: %d\n", ret);564 return ret;565 }566 567 /* Make sure hardware reset done */568 msleep(5);569 570 /* Validate the chip ID */571 ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);572 if (ret < 0) {573 dev_err(dev, "failed to get device ID, ret = %d", ret);574 goto err_enable;575 }576 577 /* The top four bits of the chip ID should be 0000 */578 if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {579 dev_err(dev, "unmatched chip ID: %d\n",580 (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);581 ret = -EINVAL;582 goto err_enable;583 }584 585 dev_info(dev, "found device, revision %X\n",586 val & CS42XX8_CHIPID_REV_ID_MASK);587 588 cs42xx8_dai.name = cs42xx8->drvdata->name;589 590 /* Each adc supports stereo input */591 cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;592 593 ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);594 if (ret) {595 dev_err(dev, "failed to register component:%d\n", ret);596 goto err_enable;597 }598 599 regcache_cache_only(cs42xx8->regmap, true);600 601err_enable:602 regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),603 cs42xx8->supplies);604 605 return ret;606}607EXPORT_SYMBOL_GPL(cs42xx8_probe);608 609#ifdef CONFIG_PM610static int cs42xx8_runtime_resume(struct device *dev)611{612 struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);613 int ret;614 615 ret = clk_prepare_enable(cs42xx8->clk);616 if (ret) {617 dev_err(dev, "failed to enable mclk: %d\n", ret);618 return ret;619 }620 621 gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);622 623 ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),624 cs42xx8->supplies);625 if (ret) {626 dev_err(dev, "failed to enable supplies: %d\n", ret);627 goto err_clk;628 }629 630 /* Make sure hardware reset done */631 msleep(5);632 633 regcache_cache_only(cs42xx8->regmap, false);634 regcache_mark_dirty(cs42xx8->regmap);635 636 ret = regcache_sync(cs42xx8->regmap);637 if (ret) {638 dev_err(dev, "failed to sync regmap: %d\n", ret);639 goto err_bulk;640 }641 642 return 0;643 644err_bulk:645 regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),646 cs42xx8->supplies);647err_clk:648 clk_disable_unprepare(cs42xx8->clk);649 650 return ret;651}652 653static int cs42xx8_runtime_suspend(struct device *dev)654{655 struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);656 657 regcache_cache_only(cs42xx8->regmap, true);658 659 regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),660 cs42xx8->supplies);661 662 gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1);663 664 clk_disable_unprepare(cs42xx8->clk);665 666 return 0;667}668#endif669 670const struct dev_pm_ops cs42xx8_pm = {671 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,672 pm_runtime_force_resume)673 SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)674};675EXPORT_SYMBOL_GPL(cs42xx8_pm);676 677MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");678MODULE_AUTHOR("Freescale Semiconductor, Inc.");679MODULE_LICENSE("GPL");680