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