1 /* 2 * ALSA SoC TWL6040 codec driver 3 * 4 * Author: Misael Lopez Cruz <x0052729@ti.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * version 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * 02110-1301 USA 19 * 20 */ 21 22 #include <linux/module.h> 23 #include <linux/moduleparam.h> 24 #include <linux/init.h> 25 #include <linux/delay.h> 26 #include <linux/pm.h> 27 #include <linux/platform_device.h> 28 #include <linux/slab.h> 29 #include <linux/mfd/twl6040.h> 30 31 #include <sound/core.h> 32 #include <sound/pcm.h> 33 #include <sound/pcm_params.h> 34 #include <sound/soc.h> 35 #include <sound/soc-dapm.h> 36 #include <sound/initval.h> 37 #include <sound/tlv.h> 38 39 #include "twl6040.h" 40 41 enum twl6040_dai_id { 42 TWL6040_DAI_LEGACY = 0, 43 TWL6040_DAI_UL, 44 TWL6040_DAI_DL1, 45 TWL6040_DAI_DL2, 46 TWL6040_DAI_VIB, 47 }; 48 49 #define TWL6040_RATES SNDRV_PCM_RATE_8000_96000 50 #define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) 51 52 #define TWL6040_OUTHS_0dB 0x00 53 #define TWL6040_OUTHS_M30dB 0x0F 54 #define TWL6040_OUTHF_0dB 0x03 55 #define TWL6040_OUTHF_M52dB 0x1D 56 57 #define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1) 58 59 struct twl6040_jack_data { 60 struct snd_soc_jack *jack; 61 struct delayed_work work; 62 int report; 63 }; 64 65 /* codec private data */ 66 struct twl6040_data { 67 int plug_irq; 68 int codec_powered; 69 int pll; 70 int pll_power_mode; 71 int hs_power_mode; 72 int hs_power_mode_locked; 73 bool dl1_unmuted; 74 bool dl2_unmuted; 75 u8 dl12_cache[TWL6040_REG_HFRCTL - TWL6040_REG_HSLCTL + 1]; 76 unsigned int clk_in; 77 unsigned int sysclk; 78 struct twl6040_jack_data hs_jack; 79 struct snd_soc_codec *codec; 80 struct mutex mutex; 81 }; 82 83 /* set of rates for each pll: low-power and high-performance */ 84 static const unsigned int lp_rates[] = { 85 8000, 86 11250, 87 16000, 88 22500, 89 32000, 90 44100, 91 48000, 92 88200, 93 96000, 94 }; 95 96 static const unsigned int hp_rates[] = { 97 8000, 98 16000, 99 32000, 100 48000, 101 96000, 102 }; 103 104 static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = { 105 { .count = ARRAY_SIZE(lp_rates), .list = lp_rates, }, 106 { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, }, 107 }; 108 109 static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg) 110 { 111 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 112 struct twl6040 *twl6040 = codec->control_data; 113 u8 value; 114 115 if (reg >= TWL6040_CACHEREGNUM) 116 return -EIO; 117 118 switch (reg) { 119 case TWL6040_REG_HSLCTL: 120 case TWL6040_REG_HSRCTL: 121 case TWL6040_REG_EARCTL: 122 case TWL6040_REG_HFLCTL: 123 case TWL6040_REG_HFRCTL: 124 value = priv->dl12_cache[reg - TWL6040_REG_HSLCTL]; 125 break; 126 default: 127 value = twl6040_reg_read(twl6040, reg); 128 break; 129 } 130 131 return value; 132 } 133 134 static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec, 135 unsigned int reg) 136 { 137 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 138 139 switch (reg) { 140 case TWL6040_REG_HSLCTL: 141 case TWL6040_REG_HSRCTL: 142 case TWL6040_REG_EARCTL: 143 /* DL1 path */ 144 return priv->dl1_unmuted; 145 case TWL6040_REG_HFLCTL: 146 case TWL6040_REG_HFRCTL: 147 return priv->dl2_unmuted; 148 default: 149 return 1; 150 } 151 } 152 153 static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec, 154 u8 reg, u8 value) 155 { 156 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 157 158 switch (reg) { 159 case TWL6040_REG_HSLCTL: 160 case TWL6040_REG_HSRCTL: 161 case TWL6040_REG_EARCTL: 162 case TWL6040_REG_HFLCTL: 163 case TWL6040_REG_HFRCTL: 164 priv->dl12_cache[reg - TWL6040_REG_HSLCTL] = value; 165 break; 166 default: 167 break; 168 } 169 } 170 171 static int twl6040_write(struct snd_soc_codec *codec, 172 unsigned int reg, unsigned int value) 173 { 174 struct twl6040 *twl6040 = codec->control_data; 175 176 if (reg >= TWL6040_CACHEREGNUM) 177 return -EIO; 178 179 twl6040_update_dl12_cache(codec, reg, value); 180 if (twl6040_can_write_to_chip(codec, reg)) 181 return twl6040_reg_write(twl6040, reg, value); 182 else 183 return 0; 184 } 185 186 static void twl6040_init_chip(struct snd_soc_codec *codec) 187 { 188 twl6040_read(codec, TWL6040_REG_TRIM1); 189 twl6040_read(codec, TWL6040_REG_TRIM2); 190 twl6040_read(codec, TWL6040_REG_TRIM3); 191 twl6040_read(codec, TWL6040_REG_HSOTRIM); 192 twl6040_read(codec, TWL6040_REG_HFOTRIM); 193 194 /* Change chip defaults */ 195 /* No imput selected for microphone amplifiers */ 196 twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18); 197 twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18); 198 199 /* 200 * We need to lower the default gain values, so the ramp code 201 * can work correctly for the first playback. 202 * This reduces the pop noise heard at the first playback. 203 */ 204 twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff); 205 twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e); 206 twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d); 207 twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d); 208 twl6040_write(codec, TWL6040_REG_LINEGAIN, 0); 209 } 210 211 /* set headset dac and driver power mode */ 212 static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) 213 { 214 int hslctl, hsrctl; 215 int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE; 216 217 hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL); 218 hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL); 219 220 if (high_perf) { 221 hslctl &= ~mask; 222 hsrctl &= ~mask; 223 } else { 224 hslctl |= mask; 225 hsrctl |= mask; 226 } 227 228 twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl); 229 twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl); 230 231 return 0; 232 } 233 234 static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w, 235 struct snd_kcontrol *kcontrol, int event) 236 { 237 struct snd_soc_codec *codec = w->codec; 238 u8 hslctl, hsrctl; 239 240 /* 241 * Workaround for Headset DC offset caused pop noise: 242 * Both HS DAC need to be turned on (before the HS driver) and off at 243 * the same time. 244 */ 245 hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL); 246 hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL); 247 if (SND_SOC_DAPM_EVENT_ON(event)) { 248 hslctl |= TWL6040_HSDACENA; 249 hsrctl |= TWL6040_HSDACENA; 250 } else { 251 hslctl &= ~TWL6040_HSDACENA; 252 hsrctl &= ~TWL6040_HSDACENA; 253 } 254 twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl); 255 twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl); 256 257 msleep(1); 258 return 0; 259 } 260 261 static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w, 262 struct snd_kcontrol *kcontrol, int event) 263 { 264 struct snd_soc_codec *codec = w->codec; 265 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 266 int ret = 0; 267 268 if (SND_SOC_DAPM_EVENT_ON(event)) { 269 /* Earphone doesn't support low power mode */ 270 priv->hs_power_mode_locked = 1; 271 ret = headset_power_mode(codec, 1); 272 } else { 273 priv->hs_power_mode_locked = 0; 274 ret = headset_power_mode(codec, priv->hs_power_mode); 275 } 276 277 msleep(1); 278 279 return ret; 280 } 281 282 static void twl6040_hs_jack_report(struct snd_soc_codec *codec, 283 struct snd_soc_jack *jack, int report) 284 { 285 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 286 int status; 287 288 mutex_lock(&priv->mutex); 289 290 /* Sync status */ 291 status = twl6040_read(codec, TWL6040_REG_STATUS); 292 if (status & TWL6040_PLUGCOMP) 293 snd_soc_jack_report(jack, report, report); 294 else 295 snd_soc_jack_report(jack, 0, report); 296 297 mutex_unlock(&priv->mutex); 298 } 299 300 void twl6040_hs_jack_detect(struct snd_soc_codec *codec, 301 struct snd_soc_jack *jack, int report) 302 { 303 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 304 struct twl6040_jack_data *hs_jack = &priv->hs_jack; 305 306 hs_jack->jack = jack; 307 hs_jack->report = report; 308 309 twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report); 310 } 311 EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect); 312 313 static void twl6040_accessory_work(struct work_struct *work) 314 { 315 struct twl6040_data *priv = container_of(work, 316 struct twl6040_data, hs_jack.work.work); 317 struct snd_soc_codec *codec = priv->codec; 318 struct twl6040_jack_data *hs_jack = &priv->hs_jack; 319 320 twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report); 321 } 322 323 /* audio interrupt handler */ 324 static irqreturn_t twl6040_audio_handler(int irq, void *data) 325 { 326 struct snd_soc_codec *codec = data; 327 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 328 329 queue_delayed_work(system_power_efficient_wq, 330 &priv->hs_jack.work, msecs_to_jiffies(200)); 331 332 return IRQ_HANDLED; 333 } 334 335 static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol, 336 struct snd_ctl_elem_value *ucontrol) 337 { 338 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); 339 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 340 unsigned int val; 341 342 /* Do not allow changes while Input/FF efect is running */ 343 val = twl6040_read(codec, e->reg); 344 if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL)) 345 return -EBUSY; 346 347 return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); 348 } 349 350 /* 351 * MICATT volume control: 352 * from -6 to 0 dB in 6 dB steps 353 */ 354 static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0); 355 356 /* 357 * MICGAIN volume control: 358 * from 6 to 30 dB in 6 dB steps 359 */ 360 static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0); 361 362 /* 363 * AFMGAIN volume control: 364 * from -18 to 24 dB in 6 dB steps 365 */ 366 static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0); 367 368 /* 369 * HSGAIN volume control: 370 * from -30 to 0 dB in 2 dB steps 371 */ 372 static DECLARE_TLV_DB_SCALE(hs_tlv, -3000, 200, 0); 373 374 /* 375 * HFGAIN volume control: 376 * from -52 to 6 dB in 2 dB steps 377 */ 378 static DECLARE_TLV_DB_SCALE(hf_tlv, -5200, 200, 0); 379 380 /* 381 * EPGAIN volume control: 382 * from -24 to 6 dB in 2 dB steps 383 */ 384 static DECLARE_TLV_DB_SCALE(ep_tlv, -2400, 200, 0); 385 386 /* Left analog microphone selection */ 387 static const char *twl6040_amicl_texts[] = 388 {"Headset Mic", "Main Mic", "Aux/FM Left", "Off"}; 389 390 /* Right analog microphone selection */ 391 static const char *twl6040_amicr_texts[] = 392 {"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"}; 393 394 static const struct soc_enum twl6040_enum[] = { 395 SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, 396 ARRAY_SIZE(twl6040_amicl_texts), twl6040_amicl_texts), 397 SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, 398 ARRAY_SIZE(twl6040_amicr_texts), twl6040_amicr_texts), 399 }; 400 401 static const char *twl6040_hs_texts[] = { 402 "Off", "HS DAC", "Line-In amp" 403 }; 404 405 static const struct soc_enum twl6040_hs_enum[] = { 406 SOC_ENUM_SINGLE(TWL6040_REG_HSLCTL, 5, ARRAY_SIZE(twl6040_hs_texts), 407 twl6040_hs_texts), 408 SOC_ENUM_SINGLE(TWL6040_REG_HSRCTL, 5, ARRAY_SIZE(twl6040_hs_texts), 409 twl6040_hs_texts), 410 }; 411 412 static const char *twl6040_hf_texts[] = { 413 "Off", "HF DAC", "Line-In amp" 414 }; 415 416 static const struct soc_enum twl6040_hf_enum[] = { 417 SOC_ENUM_SINGLE(TWL6040_REG_HFLCTL, 2, ARRAY_SIZE(twl6040_hf_texts), 418 twl6040_hf_texts), 419 SOC_ENUM_SINGLE(TWL6040_REG_HFRCTL, 2, ARRAY_SIZE(twl6040_hf_texts), 420 twl6040_hf_texts), 421 }; 422 423 static const char *twl6040_vibrapath_texts[] = { 424 "Input FF", "Audio PDM" 425 }; 426 427 static const struct soc_enum twl6040_vibra_enum[] = { 428 SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLL, 1, 429 ARRAY_SIZE(twl6040_vibrapath_texts), 430 twl6040_vibrapath_texts), 431 SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLR, 1, 432 ARRAY_SIZE(twl6040_vibrapath_texts), 433 twl6040_vibrapath_texts), 434 }; 435 436 static const struct snd_kcontrol_new amicl_control = 437 SOC_DAPM_ENUM("Route", twl6040_enum[0]); 438 439 static const struct snd_kcontrol_new amicr_control = 440 SOC_DAPM_ENUM("Route", twl6040_enum[1]); 441 442 /* Headset DAC playback switches */ 443 static const struct snd_kcontrol_new hsl_mux_controls = 444 SOC_DAPM_ENUM("Route", twl6040_hs_enum[0]); 445 446 static const struct snd_kcontrol_new hsr_mux_controls = 447 SOC_DAPM_ENUM("Route", twl6040_hs_enum[1]); 448 449 /* Handsfree DAC playback switches */ 450 static const struct snd_kcontrol_new hfl_mux_controls = 451 SOC_DAPM_ENUM("Route", twl6040_hf_enum[0]); 452 453 static const struct snd_kcontrol_new hfr_mux_controls = 454 SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]); 455 456 static const struct snd_kcontrol_new ep_path_enable_control = 457 SOC_DAPM_SINGLE_VIRT("Switch", 1); 458 459 static const struct snd_kcontrol_new auxl_switch_control = 460 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0); 461 462 static const struct snd_kcontrol_new auxr_switch_control = 463 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 6, 1, 0); 464 465 /* Vibra playback switches */ 466 static const struct snd_kcontrol_new vibral_mux_controls = 467 SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[0], 468 snd_soc_dapm_get_enum_double, 469 twl6040_soc_dapm_put_vibra_enum); 470 471 static const struct snd_kcontrol_new vibrar_mux_controls = 472 SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[1], 473 snd_soc_dapm_get_enum_double, 474 twl6040_soc_dapm_put_vibra_enum); 475 476 /* Headset power mode */ 477 static const char *twl6040_power_mode_texts[] = { 478 "Low-Power", "High-Performance", 479 }; 480 481 static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum, 482 twl6040_power_mode_texts); 483 484 static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, 485 struct snd_ctl_elem_value *ucontrol) 486 { 487 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 488 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 489 490 ucontrol->value.enumerated.item[0] = priv->hs_power_mode; 491 492 return 0; 493 } 494 495 static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol, 496 struct snd_ctl_elem_value *ucontrol) 497 { 498 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 499 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 500 int high_perf = ucontrol->value.enumerated.item[0]; 501 int ret = 0; 502 503 if (!priv->hs_power_mode_locked) 504 ret = headset_power_mode(codec, high_perf); 505 506 if (!ret) 507 priv->hs_power_mode = high_perf; 508 509 return ret; 510 } 511 512 static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol, 513 struct snd_ctl_elem_value *ucontrol) 514 { 515 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 516 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 517 518 ucontrol->value.enumerated.item[0] = priv->pll_power_mode; 519 520 return 0; 521 } 522 523 static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol, 524 struct snd_ctl_elem_value *ucontrol) 525 { 526 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 527 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 528 529 priv->pll_power_mode = ucontrol->value.enumerated.item[0]; 530 531 return 0; 532 } 533 534 int twl6040_get_dl1_gain(struct snd_soc_codec *codec) 535 { 536 struct snd_soc_dapm_context *dapm = &codec->dapm; 537 538 if (snd_soc_dapm_get_pin_status(dapm, "EP")) 539 return -1; /* -1dB */ 540 541 if (snd_soc_dapm_get_pin_status(dapm, "HSOR") || 542 snd_soc_dapm_get_pin_status(dapm, "HSOL")) { 543 544 u8 val = snd_soc_read(codec, TWL6040_REG_HSLCTL); 545 if (val & TWL6040_HSDACMODE) 546 /* HSDACL in LP mode */ 547 return -8; /* -8dB */ 548 else 549 /* HSDACL in HP mode */ 550 return -1; /* -1dB */ 551 } 552 return 0; /* 0dB */ 553 } 554 EXPORT_SYMBOL_GPL(twl6040_get_dl1_gain); 555 556 int twl6040_get_clk_id(struct snd_soc_codec *codec) 557 { 558 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 559 560 return priv->pll_power_mode; 561 } 562 EXPORT_SYMBOL_GPL(twl6040_get_clk_id); 563 564 int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim) 565 { 566 if (unlikely(trim >= TWL6040_TRIM_INVAL)) 567 return -EINVAL; 568 569 return twl6040_read(codec, TWL6040_REG_TRIM1 + trim); 570 } 571 EXPORT_SYMBOL_GPL(twl6040_get_trim_value); 572 573 int twl6040_get_hs_step_size(struct snd_soc_codec *codec) 574 { 575 struct twl6040 *twl6040 = codec->control_data; 576 577 if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3) 578 /* For ES under ES_1.3 HS step is 2 mV */ 579 return 2; 580 else 581 /* For ES_1.3 HS step is 1 mV */ 582 return 1; 583 } 584 EXPORT_SYMBOL_GPL(twl6040_get_hs_step_size); 585 586 static const struct snd_kcontrol_new twl6040_snd_controls[] = { 587 /* Capture gains */ 588 SOC_DOUBLE_TLV("Capture Preamplifier Volume", 589 TWL6040_REG_MICGAIN, 6, 7, 1, 1, mic_preamp_tlv), 590 SOC_DOUBLE_TLV("Capture Volume", 591 TWL6040_REG_MICGAIN, 0, 3, 4, 0, mic_amp_tlv), 592 593 /* AFM gains */ 594 SOC_DOUBLE_TLV("Aux FM Volume", 595 TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv), 596 597 /* Playback gains */ 598 SOC_DOUBLE_TLV("Headset Playback Volume", 599 TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv), 600 SOC_DOUBLE_R_TLV("Handsfree Playback Volume", 601 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv), 602 SOC_SINGLE_TLV("Earphone Playback Volume", 603 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv), 604 605 SOC_ENUM_EXT("Headset Power Mode", twl6040_power_mode_enum, 606 twl6040_headset_power_get_enum, 607 twl6040_headset_power_put_enum), 608 609 SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum, 610 twl6040_pll_get_enum, twl6040_pll_put_enum), 611 }; 612 613 static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { 614 /* Inputs */ 615 SND_SOC_DAPM_INPUT("MAINMIC"), 616 SND_SOC_DAPM_INPUT("HSMIC"), 617 SND_SOC_DAPM_INPUT("SUBMIC"), 618 SND_SOC_DAPM_INPUT("AFML"), 619 SND_SOC_DAPM_INPUT("AFMR"), 620 621 /* Outputs */ 622 SND_SOC_DAPM_OUTPUT("HSOL"), 623 SND_SOC_DAPM_OUTPUT("HSOR"), 624 SND_SOC_DAPM_OUTPUT("HFL"), 625 SND_SOC_DAPM_OUTPUT("HFR"), 626 SND_SOC_DAPM_OUTPUT("EP"), 627 SND_SOC_DAPM_OUTPUT("AUXL"), 628 SND_SOC_DAPM_OUTPUT("AUXR"), 629 SND_SOC_DAPM_OUTPUT("VIBRAL"), 630 SND_SOC_DAPM_OUTPUT("VIBRAR"), 631 632 /* Analog input muxes for the capture amplifiers */ 633 SND_SOC_DAPM_MUX("Analog Left Capture Route", 634 SND_SOC_NOPM, 0, 0, &amicl_control), 635 SND_SOC_DAPM_MUX("Analog Right Capture Route", 636 SND_SOC_NOPM, 0, 0, &amicr_control), 637 638 /* Analog capture PGAs */ 639 SND_SOC_DAPM_PGA("MicAmpL", 640 TWL6040_REG_MICLCTL, 0, 0, NULL, 0), 641 SND_SOC_DAPM_PGA("MicAmpR", 642 TWL6040_REG_MICRCTL, 0, 0, NULL, 0), 643 644 /* Auxiliary FM PGAs */ 645 SND_SOC_DAPM_PGA("AFMAmpL", 646 TWL6040_REG_MICLCTL, 1, 0, NULL, 0), 647 SND_SOC_DAPM_PGA("AFMAmpR", 648 TWL6040_REG_MICRCTL, 1, 0, NULL, 0), 649 650 /* ADCs */ 651 SND_SOC_DAPM_ADC("ADC Left", NULL, TWL6040_REG_MICLCTL, 2, 0), 652 SND_SOC_DAPM_ADC("ADC Right", NULL, TWL6040_REG_MICRCTL, 2, 0), 653 654 /* Microphone bias */ 655 SND_SOC_DAPM_SUPPLY("Headset Mic Bias", 656 TWL6040_REG_AMICBCTL, 0, 0, NULL, 0), 657 SND_SOC_DAPM_SUPPLY("Main Mic Bias", 658 TWL6040_REG_AMICBCTL, 4, 0, NULL, 0), 659 SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias", 660 TWL6040_REG_DMICBCTL, 0, 0, NULL, 0), 661 SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias", 662 TWL6040_REG_DMICBCTL, 4, 0, NULL, 0), 663 664 /* DACs */ 665 SND_SOC_DAPM_DAC("HSDAC Left", NULL, SND_SOC_NOPM, 0, 0), 666 SND_SOC_DAPM_DAC("HSDAC Right", NULL, SND_SOC_NOPM, 0, 0), 667 SND_SOC_DAPM_DAC("HFDAC Left", NULL, TWL6040_REG_HFLCTL, 0, 0), 668 SND_SOC_DAPM_DAC("HFDAC Right", NULL, TWL6040_REG_HFRCTL, 0, 0), 669 /* Virtual DAC for vibra path (DL4 channel) */ 670 SND_SOC_DAPM_DAC("VIBRA DAC", NULL, SND_SOC_NOPM, 0, 0), 671 672 SND_SOC_DAPM_MUX("Handsfree Left Playback", 673 SND_SOC_NOPM, 0, 0, &hfl_mux_controls), 674 SND_SOC_DAPM_MUX("Handsfree Right Playback", 675 SND_SOC_NOPM, 0, 0, &hfr_mux_controls), 676 /* Analog playback Muxes */ 677 SND_SOC_DAPM_MUX("Headset Left Playback", 678 SND_SOC_NOPM, 0, 0, &hsl_mux_controls), 679 SND_SOC_DAPM_MUX("Headset Right Playback", 680 SND_SOC_NOPM, 0, 0, &hsr_mux_controls), 681 682 SND_SOC_DAPM_MUX("Vibra Left Playback", SND_SOC_NOPM, 0, 0, 683 &vibral_mux_controls), 684 SND_SOC_DAPM_MUX("Vibra Right Playback", SND_SOC_NOPM, 0, 0, 685 &vibrar_mux_controls), 686 687 SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0, 688 &ep_path_enable_control), 689 SND_SOC_DAPM_SWITCH("AUXL Playback", SND_SOC_NOPM, 0, 0, 690 &auxl_switch_control), 691 SND_SOC_DAPM_SWITCH("AUXR Playback", SND_SOC_NOPM, 0, 0, 692 &auxr_switch_control), 693 694 /* Analog playback drivers */ 695 SND_SOC_DAPM_OUT_DRV("HF Left Driver", 696 TWL6040_REG_HFLCTL, 4, 0, NULL, 0), 697 SND_SOC_DAPM_OUT_DRV("HF Right Driver", 698 TWL6040_REG_HFRCTL, 4, 0, NULL, 0), 699 SND_SOC_DAPM_OUT_DRV("HS Left Driver", 700 TWL6040_REG_HSLCTL, 2, 0, NULL, 0), 701 SND_SOC_DAPM_OUT_DRV("HS Right Driver", 702 TWL6040_REG_HSRCTL, 2, 0, NULL, 0), 703 SND_SOC_DAPM_OUT_DRV_E("Earphone Driver", 704 TWL6040_REG_EARCTL, 0, 0, NULL, 0, 705 twl6040_ep_drv_event, 706 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 707 SND_SOC_DAPM_OUT_DRV("Vibra Left Driver", 708 TWL6040_REG_VIBCTLL, 0, 0, NULL, 0), 709 SND_SOC_DAPM_OUT_DRV("Vibra Right Driver", 710 TWL6040_REG_VIBCTLR, 0, 0, NULL, 0), 711 712 SND_SOC_DAPM_SUPPLY("Vibra Left Control", TWL6040_REG_VIBCTLL, 2, 0, 713 NULL, 0), 714 SND_SOC_DAPM_SUPPLY("Vibra Right Control", TWL6040_REG_VIBCTLR, 2, 0, 715 NULL, 0), 716 SND_SOC_DAPM_SUPPLY_S("HSDAC Power", 1, SND_SOC_NOPM, 0, 0, 717 twl6040_hs_dac_event, 718 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 719 720 /* Analog playback PGAs */ 721 SND_SOC_DAPM_PGA("HF Left PGA", 722 TWL6040_REG_HFLCTL, 1, 0, NULL, 0), 723 SND_SOC_DAPM_PGA("HF Right PGA", 724 TWL6040_REG_HFRCTL, 1, 0, NULL, 0), 725 726 }; 727 728 static const struct snd_soc_dapm_route intercon[] = { 729 /* Stream -> DAC mapping */ 730 {"HSDAC Left", NULL, "Legacy Playback"}, 731 {"HSDAC Left", NULL, "Headset Playback"}, 732 {"HSDAC Right", NULL, "Legacy Playback"}, 733 {"HSDAC Right", NULL, "Headset Playback"}, 734 735 {"HFDAC Left", NULL, "Legacy Playback"}, 736 {"HFDAC Left", NULL, "Handsfree Playback"}, 737 {"HFDAC Right", NULL, "Legacy Playback"}, 738 {"HFDAC Right", NULL, "Handsfree Playback"}, 739 740 {"VIBRA DAC", NULL, "Legacy Playback"}, 741 {"VIBRA DAC", NULL, "Vibra Playback"}, 742 743 /* ADC -> Stream mapping */ 744 {"Legacy Capture" , NULL, "ADC Left"}, 745 {"Capture", NULL, "ADC Left"}, 746 {"Legacy Capture", NULL, "ADC Right"}, 747 {"Capture" , NULL, "ADC Right"}, 748 749 /* Capture path */ 750 {"Analog Left Capture Route", "Headset Mic", "HSMIC"}, 751 {"Analog Left Capture Route", "Main Mic", "MAINMIC"}, 752 {"Analog Left Capture Route", "Aux/FM Left", "AFML"}, 753 754 {"Analog Right Capture Route", "Headset Mic", "HSMIC"}, 755 {"Analog Right Capture Route", "Sub Mic", "SUBMIC"}, 756 {"Analog Right Capture Route", "Aux/FM Right", "AFMR"}, 757 758 {"MicAmpL", NULL, "Analog Left Capture Route"}, 759 {"MicAmpR", NULL, "Analog Right Capture Route"}, 760 761 {"ADC Left", NULL, "MicAmpL"}, 762 {"ADC Right", NULL, "MicAmpR"}, 763 764 /* AFM path */ 765 {"AFMAmpL", NULL, "AFML"}, 766 {"AFMAmpR", NULL, "AFMR"}, 767 768 {"HSDAC Left", NULL, "HSDAC Power"}, 769 {"HSDAC Right", NULL, "HSDAC Power"}, 770 771 {"Headset Left Playback", "HS DAC", "HSDAC Left"}, 772 {"Headset Left Playback", "Line-In amp", "AFMAmpL"}, 773 774 {"Headset Right Playback", "HS DAC", "HSDAC Right"}, 775 {"Headset Right Playback", "Line-In amp", "AFMAmpR"}, 776 777 {"HS Left Driver", NULL, "Headset Left Playback"}, 778 {"HS Right Driver", NULL, "Headset Right Playback"}, 779 780 {"HSOL", NULL, "HS Left Driver"}, 781 {"HSOR", NULL, "HS Right Driver"}, 782 783 /* Earphone playback path */ 784 {"Earphone Playback", "Switch", "HSDAC Left"}, 785 {"Earphone Driver", NULL, "Earphone Playback"}, 786 {"EP", NULL, "Earphone Driver"}, 787 788 {"Handsfree Left Playback", "HF DAC", "HFDAC Left"}, 789 {"Handsfree Left Playback", "Line-In amp", "AFMAmpL"}, 790 791 {"Handsfree Right Playback", "HF DAC", "HFDAC Right"}, 792 {"Handsfree Right Playback", "Line-In amp", "AFMAmpR"}, 793 794 {"HF Left PGA", NULL, "Handsfree Left Playback"}, 795 {"HF Right PGA", NULL, "Handsfree Right Playback"}, 796 797 {"HF Left Driver", NULL, "HF Left PGA"}, 798 {"HF Right Driver", NULL, "HF Right PGA"}, 799 800 {"HFL", NULL, "HF Left Driver"}, 801 {"HFR", NULL, "HF Right Driver"}, 802 803 {"AUXL Playback", "Switch", "HF Left PGA"}, 804 {"AUXR Playback", "Switch", "HF Right PGA"}, 805 806 {"AUXL", NULL, "AUXL Playback"}, 807 {"AUXR", NULL, "AUXR Playback"}, 808 809 /* Vibrator paths */ 810 {"Vibra Left Playback", "Audio PDM", "VIBRA DAC"}, 811 {"Vibra Right Playback", "Audio PDM", "VIBRA DAC"}, 812 813 {"Vibra Left Driver", NULL, "Vibra Left Playback"}, 814 {"Vibra Right Driver", NULL, "Vibra Right Playback"}, 815 {"Vibra Left Driver", NULL, "Vibra Left Control"}, 816 {"Vibra Right Driver", NULL, "Vibra Right Control"}, 817 818 {"VIBRAL", NULL, "Vibra Left Driver"}, 819 {"VIBRAR", NULL, "Vibra Right Driver"}, 820 }; 821 822 static int twl6040_set_bias_level(struct snd_soc_codec *codec, 823 enum snd_soc_bias_level level) 824 { 825 struct twl6040 *twl6040 = codec->control_data; 826 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 827 int ret; 828 829 switch (level) { 830 case SND_SOC_BIAS_ON: 831 break; 832 case SND_SOC_BIAS_PREPARE: 833 break; 834 case SND_SOC_BIAS_STANDBY: 835 if (priv->codec_powered) 836 break; 837 838 ret = twl6040_power(twl6040, 1); 839 if (ret) 840 return ret; 841 842 priv->codec_powered = 1; 843 844 /* Set external boost GPO */ 845 twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02); 846 break; 847 case SND_SOC_BIAS_OFF: 848 if (!priv->codec_powered) 849 break; 850 851 twl6040_power(twl6040, 0); 852 priv->codec_powered = 0; 853 break; 854 } 855 856 codec->dapm.bias_level = level; 857 858 return 0; 859 } 860 861 static int twl6040_startup(struct snd_pcm_substream *substream, 862 struct snd_soc_dai *dai) 863 { 864 struct snd_soc_codec *codec = dai->codec; 865 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 866 867 snd_pcm_hw_constraint_list(substream->runtime, 0, 868 SNDRV_PCM_HW_PARAM_RATE, 869 &sysclk_constraints[priv->pll_power_mode]); 870 871 return 0; 872 } 873 874 static int twl6040_hw_params(struct snd_pcm_substream *substream, 875 struct snd_pcm_hw_params *params, 876 struct snd_soc_dai *dai) 877 { 878 struct snd_soc_codec *codec = dai->codec; 879 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 880 int rate; 881 882 rate = params_rate(params); 883 switch (rate) { 884 case 11250: 885 case 22500: 886 case 44100: 887 case 88200: 888 /* These rates are not supported when HPPLL is in use */ 889 if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) { 890 dev_err(codec->dev, "HPPLL does not support rate %d\n", 891 rate); 892 return -EINVAL; 893 } 894 priv->sysclk = 17640000; 895 break; 896 case 8000: 897 case 16000: 898 case 32000: 899 case 48000: 900 case 96000: 901 priv->sysclk = 19200000; 902 break; 903 default: 904 dev_err(codec->dev, "unsupported rate %d\n", rate); 905 return -EINVAL; 906 } 907 908 return 0; 909 } 910 911 static int twl6040_prepare(struct snd_pcm_substream *substream, 912 struct snd_soc_dai *dai) 913 { 914 struct snd_soc_codec *codec = dai->codec; 915 struct twl6040 *twl6040 = codec->control_data; 916 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 917 int ret; 918 919 if (!priv->sysclk) { 920 dev_err(codec->dev, 921 "no mclk configured, call set_sysclk() on init\n"); 922 return -EINVAL; 923 } 924 925 ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk); 926 if (ret) { 927 dev_err(codec->dev, "Can not set PLL (%d)\n", ret); 928 return -EPERM; 929 } 930 931 return 0; 932 } 933 934 static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, 935 int clk_id, unsigned int freq, int dir) 936 { 937 struct snd_soc_codec *codec = codec_dai->codec; 938 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 939 940 switch (clk_id) { 941 case TWL6040_SYSCLK_SEL_LPPLL: 942 case TWL6040_SYSCLK_SEL_HPPLL: 943 priv->pll = clk_id; 944 priv->clk_in = freq; 945 break; 946 default: 947 dev_err(codec->dev, "unknown clk_id %d\n", clk_id); 948 return -EINVAL; 949 } 950 951 return 0; 952 } 953 954 static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id, 955 int mute) 956 { 957 struct twl6040 *twl6040 = codec->control_data; 958 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 959 int hslctl, hsrctl, earctl; 960 int hflctl, hfrctl; 961 962 switch (id) { 963 case TWL6040_DAI_DL1: 964 hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL); 965 hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL); 966 earctl = twl6040_read(codec, TWL6040_REG_EARCTL); 967 968 if (mute) { 969 /* Power down drivers and DACs */ 970 earctl &= ~0x01; 971 hslctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA); 972 hsrctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA); 973 974 } 975 976 twl6040_reg_write(twl6040, TWL6040_REG_EARCTL, earctl); 977 twl6040_reg_write(twl6040, TWL6040_REG_HSLCTL, hslctl); 978 twl6040_reg_write(twl6040, TWL6040_REG_HSRCTL, hsrctl); 979 priv->dl1_unmuted = !mute; 980 break; 981 case TWL6040_DAI_DL2: 982 hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL); 983 hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL); 984 985 if (mute) { 986 /* Power down drivers and DACs */ 987 hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | 988 TWL6040_HFDRVENA); 989 hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | 990 TWL6040_HFDRVENA); 991 } 992 993 twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl); 994 twl6040_reg_write(twl6040, TWL6040_REG_HFRCTL, hfrctl); 995 priv->dl2_unmuted = !mute; 996 break; 997 default: 998 break; 999 } 1000 } 1001 1002 static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute) 1003 { 1004 switch (dai->id) { 1005 case TWL6040_DAI_LEGACY: 1006 twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute); 1007 twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute); 1008 break; 1009 case TWL6040_DAI_DL1: 1010 case TWL6040_DAI_DL2: 1011 twl6040_mute_path(dai->codec, dai->id, mute); 1012 break; 1013 default: 1014 break; 1015 } 1016 1017 return 0; 1018 } 1019 1020 static const struct snd_soc_dai_ops twl6040_dai_ops = { 1021 .startup = twl6040_startup, 1022 .hw_params = twl6040_hw_params, 1023 .prepare = twl6040_prepare, 1024 .set_sysclk = twl6040_set_dai_sysclk, 1025 .digital_mute = twl6040_digital_mute, 1026 }; 1027 1028 static struct snd_soc_dai_driver twl6040_dai[] = { 1029 { 1030 .name = "twl6040-legacy", 1031 .id = TWL6040_DAI_LEGACY, 1032 .playback = { 1033 .stream_name = "Legacy Playback", 1034 .channels_min = 1, 1035 .channels_max = 5, 1036 .rates = TWL6040_RATES, 1037 .formats = TWL6040_FORMATS, 1038 }, 1039 .capture = { 1040 .stream_name = "Legacy Capture", 1041 .channels_min = 1, 1042 .channels_max = 2, 1043 .rates = TWL6040_RATES, 1044 .formats = TWL6040_FORMATS, 1045 }, 1046 .ops = &twl6040_dai_ops, 1047 }, 1048 { 1049 .name = "twl6040-ul", 1050 .id = TWL6040_DAI_UL, 1051 .capture = { 1052 .stream_name = "Capture", 1053 .channels_min = 1, 1054 .channels_max = 2, 1055 .rates = TWL6040_RATES, 1056 .formats = TWL6040_FORMATS, 1057 }, 1058 .ops = &twl6040_dai_ops, 1059 }, 1060 { 1061 .name = "twl6040-dl1", 1062 .id = TWL6040_DAI_DL1, 1063 .playback = { 1064 .stream_name = "Headset Playback", 1065 .channels_min = 1, 1066 .channels_max = 2, 1067 .rates = TWL6040_RATES, 1068 .formats = TWL6040_FORMATS, 1069 }, 1070 .ops = &twl6040_dai_ops, 1071 }, 1072 { 1073 .name = "twl6040-dl2", 1074 .id = TWL6040_DAI_DL2, 1075 .playback = { 1076 .stream_name = "Handsfree Playback", 1077 .channels_min = 1, 1078 .channels_max = 2, 1079 .rates = TWL6040_RATES, 1080 .formats = TWL6040_FORMATS, 1081 }, 1082 .ops = &twl6040_dai_ops, 1083 }, 1084 { 1085 .name = "twl6040-vib", 1086 .id = TWL6040_DAI_VIB, 1087 .playback = { 1088 .stream_name = "Vibra Playback", 1089 .channels_min = 1, 1090 .channels_max = 1, 1091 .rates = SNDRV_PCM_RATE_CONTINUOUS, 1092 .formats = TWL6040_FORMATS, 1093 }, 1094 .ops = &twl6040_dai_ops, 1095 }, 1096 }; 1097 1098 #ifdef CONFIG_PM 1099 static int twl6040_suspend(struct snd_soc_codec *codec) 1100 { 1101 twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); 1102 1103 return 0; 1104 } 1105 1106 static int twl6040_resume(struct snd_soc_codec *codec) 1107 { 1108 twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1109 1110 return 0; 1111 } 1112 #else 1113 #define twl6040_suspend NULL 1114 #define twl6040_resume NULL 1115 #endif 1116 1117 static int twl6040_probe(struct snd_soc_codec *codec) 1118 { 1119 struct twl6040_data *priv; 1120 struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent); 1121 struct platform_device *pdev = container_of(codec->dev, 1122 struct platform_device, dev); 1123 int ret = 0; 1124 1125 priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL); 1126 if (priv == NULL) 1127 return -ENOMEM; 1128 1129 snd_soc_codec_set_drvdata(codec, priv); 1130 1131 priv->codec = codec; 1132 codec->control_data = twl6040; 1133 1134 priv->plug_irq = platform_get_irq(pdev, 0); 1135 if (priv->plug_irq < 0) { 1136 dev_err(codec->dev, "invalid irq\n"); 1137 return -EINVAL; 1138 } 1139 1140 INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work); 1141 1142 mutex_init(&priv->mutex); 1143 1144 ret = request_threaded_irq(priv->plug_irq, NULL, 1145 twl6040_audio_handler, IRQF_NO_SUSPEND, 1146 "twl6040_irq_plug", codec); 1147 if (ret) { 1148 dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret); 1149 return ret; 1150 } 1151 1152 twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1153 twl6040_init_chip(codec); 1154 1155 return 0; 1156 } 1157 1158 static int twl6040_remove(struct snd_soc_codec *codec) 1159 { 1160 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1161 1162 free_irq(priv->plug_irq, codec); 1163 twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); 1164 1165 return 0; 1166 } 1167 1168 static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { 1169 .probe = twl6040_probe, 1170 .remove = twl6040_remove, 1171 .suspend = twl6040_suspend, 1172 .resume = twl6040_resume, 1173 .read = twl6040_read, 1174 .write = twl6040_write, 1175 .set_bias_level = twl6040_set_bias_level, 1176 .ignore_pmdown_time = true, 1177 1178 .controls = twl6040_snd_controls, 1179 .num_controls = ARRAY_SIZE(twl6040_snd_controls), 1180 .dapm_widgets = twl6040_dapm_widgets, 1181 .num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets), 1182 .dapm_routes = intercon, 1183 .num_dapm_routes = ARRAY_SIZE(intercon), 1184 }; 1185 1186 static int twl6040_codec_probe(struct platform_device *pdev) 1187 { 1188 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl6040, 1189 twl6040_dai, ARRAY_SIZE(twl6040_dai)); 1190 } 1191 1192 static int twl6040_codec_remove(struct platform_device *pdev) 1193 { 1194 snd_soc_unregister_codec(&pdev->dev); 1195 return 0; 1196 } 1197 1198 static struct platform_driver twl6040_codec_driver = { 1199 .driver = { 1200 .name = "twl6040-codec", 1201 .owner = THIS_MODULE, 1202 }, 1203 .probe = twl6040_codec_probe, 1204 .remove = twl6040_codec_remove, 1205 }; 1206 1207 module_platform_driver(twl6040_codec_driver); 1208 1209 MODULE_DESCRIPTION("ASoC TWL6040 codec driver"); 1210 MODULE_AUTHOR("Misael Lopez Cruz"); 1211 MODULE_LICENSE("GPL"); 1212