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