1 /* 2 * cs42l51.c 3 * 4 * ASoC Driver for Cirrus Logic CS42L51 codecs 5 * 6 * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com> 7 * 8 * Based on cs4270.c - Copyright (c) Freescale Semiconductor 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * For now: 20 * - Only I2C is support. Not SPI 21 * - master mode *NOT* supported 22 */ 23 24 #include <linux/module.h> 25 #include <linux/slab.h> 26 #include <sound/core.h> 27 #include <sound/soc.h> 28 #include <sound/tlv.h> 29 #include <sound/initval.h> 30 #include <sound/pcm_params.h> 31 #include <sound/pcm.h> 32 #include <linux/regmap.h> 33 34 #include "cs42l51.h" 35 36 enum master_slave_mode { 37 MODE_SLAVE, 38 MODE_SLAVE_AUTO, 39 MODE_MASTER, 40 }; 41 42 struct cs42l51_private { 43 unsigned int mclk; 44 unsigned int audio_mode; /* The mode (I2S or left-justified) */ 45 enum master_slave_mode func; 46 }; 47 48 #define CS42L51_FORMATS ( \ 49 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ 50 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ 51 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ 52 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) 53 54 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, 55 struct snd_ctl_elem_value *ucontrol) 56 { 57 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 58 unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3; 59 60 switch (value) { 61 default: 62 case 0: 63 ucontrol->value.integer.value[0] = 0; 64 break; 65 /* same value : (L+R)/2 and (R+L)/2 */ 66 case 1: 67 case 2: 68 ucontrol->value.integer.value[0] = 1; 69 break; 70 case 3: 71 ucontrol->value.integer.value[0] = 2; 72 break; 73 } 74 75 return 0; 76 } 77 78 #define CHAN_MIX_NORMAL 0x00 79 #define CHAN_MIX_BOTH 0x55 80 #define CHAN_MIX_SWAP 0xFF 81 82 static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol, 83 struct snd_ctl_elem_value *ucontrol) 84 { 85 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 86 unsigned char val; 87 88 switch (ucontrol->value.integer.value[0]) { 89 default: 90 case 0: 91 val = CHAN_MIX_NORMAL; 92 break; 93 case 1: 94 val = CHAN_MIX_BOTH; 95 break; 96 case 2: 97 val = CHAN_MIX_SWAP; 98 break; 99 } 100 101 snd_soc_write(codec, CS42L51_PCM_MIXER, val); 102 103 return 1; 104 } 105 106 static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0); 107 static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); 108 109 static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0); 110 111 static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0); 112 static const char *chan_mix[] = { 113 "L R", 114 "L+R", 115 "R L", 116 }; 117 118 static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix); 119 120 static const struct snd_kcontrol_new cs42l51_snd_controls[] = { 121 SOC_DOUBLE_R_SX_TLV("PCM Playback Volume", 122 CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 123 0, 0x19, 0x7F, adc_pcm_tlv), 124 SOC_DOUBLE_R("PCM Playback Switch", 125 CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1), 126 SOC_DOUBLE_R_SX_TLV("Analog Playback Volume", 127 CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL, 128 0, 0x34, 0xE4, aout_tlv), 129 SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", 130 CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 131 0, 0x19, 0x7F, adc_pcm_tlv), 132 SOC_DOUBLE_R("ADC Mixer Switch", 133 CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1), 134 SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0), 135 SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0), 136 SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0), 137 SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0), 138 SOC_DOUBLE_TLV("Mic Boost Volume", 139 CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv), 140 SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv), 141 SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv), 142 SOC_ENUM_EXT("PCM channel mixer", 143 cs42l51_chan_mix, 144 cs42l51_get_chan_mix, cs42l51_set_chan_mix), 145 }; 146 147 /* 148 * to power down, one must: 149 * 1.) Enable the PDN bit 150 * 2.) enable power-down for the select channels 151 * 3.) disable the PDN bit. 152 */ 153 static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, 154 struct snd_kcontrol *kcontrol, int event) 155 { 156 switch (event) { 157 case SND_SOC_DAPM_PRE_PMD: 158 snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, 159 CS42L51_POWER_CTL1_PDN, 160 CS42L51_POWER_CTL1_PDN); 161 break; 162 default: 163 case SND_SOC_DAPM_POST_PMD: 164 snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, 165 CS42L51_POWER_CTL1_PDN, 0); 166 break; 167 } 168 169 return 0; 170 } 171 172 static const char *cs42l51_dac_names[] = {"Direct PCM", 173 "DSP PCM", "ADC"}; 174 static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum, 175 CS42L51_DAC_CTL, 6, cs42l51_dac_names); 176 static const struct snd_kcontrol_new cs42l51_dac_mux_controls = 177 SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum); 178 179 static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left", 180 "MIC Left", "MIC+preamp Left"}; 181 static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum, 182 CS42L51_ADC_INPUT, 4, cs42l51_adcl_names); 183 static const struct snd_kcontrol_new cs42l51_adcl_mux_controls = 184 SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum); 185 186 static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right", 187 "MIC Right", "MIC+preamp Right"}; 188 static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum, 189 CS42L51_ADC_INPUT, 6, cs42l51_adcr_names); 190 static const struct snd_kcontrol_new cs42l51_adcr_mux_controls = 191 SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); 192 193 static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { 194 SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1), 195 SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0, 196 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), 197 SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0, 198 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), 199 SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture", 200 CS42L51_POWER_CTL1, 1, 1, 201 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), 202 SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture", 203 CS42L51_POWER_CTL1, 2, 1, 204 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), 205 SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback", 206 CS42L51_POWER_CTL1, 5, 1, 207 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), 208 SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback", 209 CS42L51_POWER_CTL1, 6, 1, 210 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), 211 212 /* analog/mic */ 213 SND_SOC_DAPM_INPUT("AIN1L"), 214 SND_SOC_DAPM_INPUT("AIN1R"), 215 SND_SOC_DAPM_INPUT("AIN2L"), 216 SND_SOC_DAPM_INPUT("AIN2R"), 217 SND_SOC_DAPM_INPUT("MICL"), 218 SND_SOC_DAPM_INPUT("MICR"), 219 220 SND_SOC_DAPM_MIXER("Mic Preamp Left", 221 CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0), 222 SND_SOC_DAPM_MIXER("Mic Preamp Right", 223 CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0), 224 225 /* HP */ 226 SND_SOC_DAPM_OUTPUT("HPL"), 227 SND_SOC_DAPM_OUTPUT("HPR"), 228 229 /* mux */ 230 SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, 231 &cs42l51_dac_mux_controls), 232 SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0, 233 &cs42l51_adcl_mux_controls), 234 SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0, 235 &cs42l51_adcr_mux_controls), 236 }; 237 238 static const struct snd_soc_dapm_route cs42l51_routes[] = { 239 {"HPL", NULL, "Left DAC"}, 240 {"HPR", NULL, "Right DAC"}, 241 242 {"Left ADC", NULL, "Left PGA"}, 243 {"Right ADC", NULL, "Right PGA"}, 244 245 {"Mic Preamp Left", NULL, "MICL"}, 246 {"Mic Preamp Right", NULL, "MICR"}, 247 248 {"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" }, 249 {"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" }, 250 {"PGA-ADC Mux Left", "MIC Left", "MICL" }, 251 {"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" }, 252 {"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" }, 253 {"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" }, 254 {"PGA-ADC Mux Right", "MIC Right", "MICR" }, 255 {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" }, 256 257 {"Left PGA", NULL, "PGA-ADC Mux Left"}, 258 {"Right PGA", NULL, "PGA-ADC Mux Right"}, 259 }; 260 261 static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai, 262 unsigned int format) 263 { 264 struct snd_soc_codec *codec = codec_dai->codec; 265 struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); 266 267 switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { 268 case SND_SOC_DAIFMT_I2S: 269 case SND_SOC_DAIFMT_LEFT_J: 270 case SND_SOC_DAIFMT_RIGHT_J: 271 cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK; 272 break; 273 default: 274 dev_err(codec->dev, "invalid DAI format\n"); 275 return -EINVAL; 276 } 277 278 switch (format & SND_SOC_DAIFMT_MASTER_MASK) { 279 case SND_SOC_DAIFMT_CBM_CFM: 280 cs42l51->func = MODE_MASTER; 281 break; 282 case SND_SOC_DAIFMT_CBS_CFS: 283 cs42l51->func = MODE_SLAVE_AUTO; 284 break; 285 default: 286 dev_err(codec->dev, "Unknown master/slave configuration\n"); 287 return -EINVAL; 288 } 289 290 return 0; 291 } 292 293 struct cs42l51_ratios { 294 unsigned int ratio; 295 unsigned char speed_mode; 296 unsigned char mclk; 297 }; 298 299 static struct cs42l51_ratios slave_ratios[] = { 300 { 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 }, 301 { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 }, 302 { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 }, 303 { 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 }, 304 { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 }, 305 { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 }, 306 { 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 }, 307 { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 }, 308 { 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 }, 309 { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 }, 310 { 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 }, 311 }; 312 313 static struct cs42l51_ratios slave_auto_ratios[] = { 314 { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 }, 315 { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 }, 316 { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 }, 317 { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 }, 318 { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 }, 319 { 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 }, 320 { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 }, 321 { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 }, 322 }; 323 324 static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai, 325 int clk_id, unsigned int freq, int dir) 326 { 327 struct snd_soc_codec *codec = codec_dai->codec; 328 struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); 329 330 cs42l51->mclk = freq; 331 return 0; 332 } 333 334 static int cs42l51_hw_params(struct snd_pcm_substream *substream, 335 struct snd_pcm_hw_params *params, 336 struct snd_soc_dai *dai) 337 { 338 struct snd_soc_codec *codec = dai->codec; 339 struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); 340 int ret; 341 unsigned int i; 342 unsigned int rate; 343 unsigned int ratio; 344 struct cs42l51_ratios *ratios = NULL; 345 int nr_ratios = 0; 346 int intf_ctl, power_ctl, fmt; 347 348 switch (cs42l51->func) { 349 case MODE_MASTER: 350 return -EINVAL; 351 case MODE_SLAVE: 352 ratios = slave_ratios; 353 nr_ratios = ARRAY_SIZE(slave_ratios); 354 break; 355 case MODE_SLAVE_AUTO: 356 ratios = slave_auto_ratios; 357 nr_ratios = ARRAY_SIZE(slave_auto_ratios); 358 break; 359 } 360 361 /* Figure out which MCLK/LRCK ratio to use */ 362 rate = params_rate(params); /* Sampling rate, in Hz */ 363 ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */ 364 for (i = 0; i < nr_ratios; i++) { 365 if (ratios[i].ratio == ratio) 366 break; 367 } 368 369 if (i == nr_ratios) { 370 /* We did not find a matching ratio */ 371 dev_err(codec->dev, "could not find matching ratio\n"); 372 return -EINVAL; 373 } 374 375 intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL); 376 power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL); 377 378 intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S 379 | CS42L51_INTF_CTL_DAC_FORMAT(7)); 380 power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3) 381 | CS42L51_MIC_POWER_CTL_MCLK_DIV2); 382 383 switch (cs42l51->func) { 384 case MODE_MASTER: 385 intf_ctl |= CS42L51_INTF_CTL_MASTER; 386 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); 387 break; 388 case MODE_SLAVE: 389 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); 390 break; 391 case MODE_SLAVE_AUTO: 392 power_ctl |= CS42L51_MIC_POWER_CTL_AUTO; 393 break; 394 } 395 396 switch (cs42l51->audio_mode) { 397 case SND_SOC_DAIFMT_I2S: 398 intf_ctl |= CS42L51_INTF_CTL_ADC_I2S; 399 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S); 400 break; 401 case SND_SOC_DAIFMT_LEFT_J: 402 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24); 403 break; 404 case SND_SOC_DAIFMT_RIGHT_J: 405 switch (params_width(params)) { 406 case 16: 407 fmt = CS42L51_DAC_DIF_RJ16; 408 break; 409 case 18: 410 fmt = CS42L51_DAC_DIF_RJ18; 411 break; 412 case 20: 413 fmt = CS42L51_DAC_DIF_RJ20; 414 break; 415 case 24: 416 fmt = CS42L51_DAC_DIF_RJ24; 417 break; 418 default: 419 dev_err(codec->dev, "unknown format\n"); 420 return -EINVAL; 421 } 422 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt); 423 break; 424 default: 425 dev_err(codec->dev, "unknown format\n"); 426 return -EINVAL; 427 } 428 429 if (ratios[i].mclk) 430 power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2; 431 432 ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl); 433 if (ret < 0) 434 return ret; 435 436 ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl); 437 if (ret < 0) 438 return ret; 439 440 return 0; 441 } 442 443 static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute) 444 { 445 struct snd_soc_codec *codec = dai->codec; 446 int reg; 447 int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE; 448 449 reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL); 450 451 if (mute) 452 reg |= mask; 453 else 454 reg &= ~mask; 455 456 return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg); 457 } 458 459 static const struct snd_soc_dai_ops cs42l51_dai_ops = { 460 .hw_params = cs42l51_hw_params, 461 .set_sysclk = cs42l51_set_dai_sysclk, 462 .set_fmt = cs42l51_set_dai_fmt, 463 .digital_mute = cs42l51_dai_mute, 464 }; 465 466 static struct snd_soc_dai_driver cs42l51_dai = { 467 .name = "cs42l51-hifi", 468 .playback = { 469 .stream_name = "Playback", 470 .channels_min = 1, 471 .channels_max = 2, 472 .rates = SNDRV_PCM_RATE_8000_96000, 473 .formats = CS42L51_FORMATS, 474 }, 475 .capture = { 476 .stream_name = "Capture", 477 .channels_min = 1, 478 .channels_max = 2, 479 .rates = SNDRV_PCM_RATE_8000_96000, 480 .formats = CS42L51_FORMATS, 481 }, 482 .ops = &cs42l51_dai_ops, 483 }; 484 485 static int cs42l51_codec_probe(struct snd_soc_codec *codec) 486 { 487 int ret, reg; 488 489 /* 490 * DAC configuration 491 * - Use signal processor 492 * - auto mute 493 * - vol changes immediate 494 * - no de-emphasize 495 */ 496 reg = CS42L51_DAC_CTL_DATA_SEL(1) 497 | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0); 498 ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg); 499 if (ret < 0) 500 return ret; 501 502 return 0; 503 } 504 505 static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { 506 .probe = cs42l51_codec_probe, 507 508 .controls = cs42l51_snd_controls, 509 .num_controls = ARRAY_SIZE(cs42l51_snd_controls), 510 .dapm_widgets = cs42l51_dapm_widgets, 511 .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets), 512 .dapm_routes = cs42l51_routes, 513 .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), 514 }; 515 516 const struct regmap_config cs42l51_regmap = { 517 .max_register = CS42L51_CHARGE_FREQ, 518 .cache_type = REGCACHE_RBTREE, 519 }; 520 EXPORT_SYMBOL_GPL(cs42l51_regmap); 521 522 int cs42l51_probe(struct device *dev, struct regmap *regmap) 523 { 524 struct cs42l51_private *cs42l51; 525 unsigned int val; 526 int ret; 527 528 if (IS_ERR(regmap)) 529 return PTR_ERR(regmap); 530 531 cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private), 532 GFP_KERNEL); 533 if (!cs42l51) 534 return -ENOMEM; 535 536 dev_set_drvdata(dev, cs42l51); 537 538 /* Verify that we have a CS42L51 */ 539 ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); 540 if (ret < 0) { 541 dev_err(dev, "failed to read I2C\n"); 542 goto error; 543 } 544 545 if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && 546 (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { 547 dev_err(dev, "Invalid chip id: %x\n", val); 548 ret = -ENODEV; 549 goto error; 550 } 551 dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n", 552 val & CS42L51_CHIP_REV_MASK); 553 554 ret = snd_soc_register_codec(dev, 555 &soc_codec_device_cs42l51, &cs42l51_dai, 1); 556 error: 557 return ret; 558 } 559 EXPORT_SYMBOL_GPL(cs42l51_probe); 560 561 static const struct of_device_id cs42l51_of_match[] = { 562 { .compatible = "cirrus,cs42l51", }, 563 { } 564 }; 565 MODULE_DEVICE_TABLE(of, cs42l51_of_match); 566 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); 567 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); 568 MODULE_LICENSE("GPL"); 569