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 = snd_soc_dapm_to_codec(w->dapm); 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 = snd_soc_dapm_to_codec(w->dapm); 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 = snd_soc_codec_get_dapm(codec); 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 /* Left HS PDM data routed to Right HSDAC */ 610 SOC_SINGLE("Headset Mono to Stereo Playback Switch", 611 TWL6040_REG_HSRCTL, 7, 1, 0), 612 613 /* Left HF PDM data routed to Right HFDAC */ 614 SOC_SINGLE("Handsfree Mono to Stereo Playback Switch", 615 TWL6040_REG_HFRCTL, 5, 1, 0), 616 617 SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum, 618 twl6040_pll_get_enum, twl6040_pll_put_enum), 619 }; 620 621 static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { 622 /* Inputs */ 623 SND_SOC_DAPM_INPUT("MAINMIC"), 624 SND_SOC_DAPM_INPUT("HSMIC"), 625 SND_SOC_DAPM_INPUT("SUBMIC"), 626 SND_SOC_DAPM_INPUT("AFML"), 627 SND_SOC_DAPM_INPUT("AFMR"), 628 629 /* Outputs */ 630 SND_SOC_DAPM_OUTPUT("HSOL"), 631 SND_SOC_DAPM_OUTPUT("HSOR"), 632 SND_SOC_DAPM_OUTPUT("HFL"), 633 SND_SOC_DAPM_OUTPUT("HFR"), 634 SND_SOC_DAPM_OUTPUT("EP"), 635 SND_SOC_DAPM_OUTPUT("AUXL"), 636 SND_SOC_DAPM_OUTPUT("AUXR"), 637 SND_SOC_DAPM_OUTPUT("VIBRAL"), 638 SND_SOC_DAPM_OUTPUT("VIBRAR"), 639 640 /* Analog input muxes for the capture amplifiers */ 641 SND_SOC_DAPM_MUX("Analog Left Capture Route", 642 SND_SOC_NOPM, 0, 0, &amicl_control), 643 SND_SOC_DAPM_MUX("Analog Right Capture Route", 644 SND_SOC_NOPM, 0, 0, &amicr_control), 645 646 /* Analog capture PGAs */ 647 SND_SOC_DAPM_PGA("MicAmpL", 648 TWL6040_REG_MICLCTL, 0, 0, NULL, 0), 649 SND_SOC_DAPM_PGA("MicAmpR", 650 TWL6040_REG_MICRCTL, 0, 0, NULL, 0), 651 652 /* Auxiliary FM PGAs */ 653 SND_SOC_DAPM_PGA("AFMAmpL", 654 TWL6040_REG_MICLCTL, 1, 0, NULL, 0), 655 SND_SOC_DAPM_PGA("AFMAmpR", 656 TWL6040_REG_MICRCTL, 1, 0, NULL, 0), 657 658 /* ADCs */ 659 SND_SOC_DAPM_ADC("ADC Left", NULL, TWL6040_REG_MICLCTL, 2, 0), 660 SND_SOC_DAPM_ADC("ADC Right", NULL, TWL6040_REG_MICRCTL, 2, 0), 661 662 /* Microphone bias */ 663 SND_SOC_DAPM_SUPPLY("Headset Mic Bias", 664 TWL6040_REG_AMICBCTL, 0, 0, NULL, 0), 665 SND_SOC_DAPM_SUPPLY("Main Mic Bias", 666 TWL6040_REG_AMICBCTL, 4, 0, NULL, 0), 667 SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias", 668 TWL6040_REG_DMICBCTL, 0, 0, NULL, 0), 669 SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias", 670 TWL6040_REG_DMICBCTL, 4, 0, NULL, 0), 671 672 /* DACs */ 673 SND_SOC_DAPM_DAC("HSDAC Left", NULL, SND_SOC_NOPM, 0, 0), 674 SND_SOC_DAPM_DAC("HSDAC Right", NULL, SND_SOC_NOPM, 0, 0), 675 SND_SOC_DAPM_DAC("HFDAC Left", NULL, TWL6040_REG_HFLCTL, 0, 0), 676 SND_SOC_DAPM_DAC("HFDAC Right", NULL, TWL6040_REG_HFRCTL, 0, 0), 677 /* Virtual DAC for vibra path (DL4 channel) */ 678 SND_SOC_DAPM_DAC("VIBRA DAC", NULL, SND_SOC_NOPM, 0, 0), 679 680 SND_SOC_DAPM_MUX("Handsfree Left Playback", 681 SND_SOC_NOPM, 0, 0, &hfl_mux_controls), 682 SND_SOC_DAPM_MUX("Handsfree Right Playback", 683 SND_SOC_NOPM, 0, 0, &hfr_mux_controls), 684 /* Analog playback Muxes */ 685 SND_SOC_DAPM_MUX("Headset Left Playback", 686 SND_SOC_NOPM, 0, 0, &hsl_mux_controls), 687 SND_SOC_DAPM_MUX("Headset Right Playback", 688 SND_SOC_NOPM, 0, 0, &hsr_mux_controls), 689 690 SND_SOC_DAPM_MUX("Vibra Left Playback", SND_SOC_NOPM, 0, 0, 691 &vibral_mux_controls), 692 SND_SOC_DAPM_MUX("Vibra Right Playback", SND_SOC_NOPM, 0, 0, 693 &vibrar_mux_controls), 694 695 SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0, 696 &ep_path_enable_control), 697 SND_SOC_DAPM_SWITCH("AUXL Playback", SND_SOC_NOPM, 0, 0, 698 &auxl_switch_control), 699 SND_SOC_DAPM_SWITCH("AUXR Playback", SND_SOC_NOPM, 0, 0, 700 &auxr_switch_control), 701 702 /* Analog playback drivers */ 703 SND_SOC_DAPM_OUT_DRV("HF Left Driver", 704 TWL6040_REG_HFLCTL, 4, 0, NULL, 0), 705 SND_SOC_DAPM_OUT_DRV("HF Right Driver", 706 TWL6040_REG_HFRCTL, 4, 0, NULL, 0), 707 SND_SOC_DAPM_OUT_DRV("HS Left Driver", 708 TWL6040_REG_HSLCTL, 2, 0, NULL, 0), 709 SND_SOC_DAPM_OUT_DRV("HS Right Driver", 710 TWL6040_REG_HSRCTL, 2, 0, NULL, 0), 711 SND_SOC_DAPM_OUT_DRV_E("Earphone Driver", 712 TWL6040_REG_EARCTL, 0, 0, NULL, 0, 713 twl6040_ep_drv_event, 714 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 715 SND_SOC_DAPM_OUT_DRV("Vibra Left Driver", 716 TWL6040_REG_VIBCTLL, 0, 0, NULL, 0), 717 SND_SOC_DAPM_OUT_DRV("Vibra Right Driver", 718 TWL6040_REG_VIBCTLR, 0, 0, NULL, 0), 719 720 SND_SOC_DAPM_SUPPLY("Vibra Left Control", TWL6040_REG_VIBCTLL, 2, 0, 721 NULL, 0), 722 SND_SOC_DAPM_SUPPLY("Vibra Right Control", TWL6040_REG_VIBCTLR, 2, 0, 723 NULL, 0), 724 SND_SOC_DAPM_SUPPLY_S("HSDAC Power", 1, SND_SOC_NOPM, 0, 0, 725 twl6040_hs_dac_event, 726 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 727 728 /* Analog playback PGAs */ 729 SND_SOC_DAPM_PGA("HF Left PGA", 730 TWL6040_REG_HFLCTL, 1, 0, NULL, 0), 731 SND_SOC_DAPM_PGA("HF Right PGA", 732 TWL6040_REG_HFRCTL, 1, 0, NULL, 0), 733 734 }; 735 736 static const struct snd_soc_dapm_route intercon[] = { 737 /* Stream -> DAC mapping */ 738 {"HSDAC Left", NULL, "Legacy Playback"}, 739 {"HSDAC Left", NULL, "Headset Playback"}, 740 {"HSDAC Right", NULL, "Legacy Playback"}, 741 {"HSDAC Right", NULL, "Headset Playback"}, 742 743 {"HFDAC Left", NULL, "Legacy Playback"}, 744 {"HFDAC Left", NULL, "Handsfree Playback"}, 745 {"HFDAC Right", NULL, "Legacy Playback"}, 746 {"HFDAC Right", NULL, "Handsfree Playback"}, 747 748 {"VIBRA DAC", NULL, "Legacy Playback"}, 749 {"VIBRA DAC", NULL, "Vibra Playback"}, 750 751 /* ADC -> Stream mapping */ 752 {"Legacy Capture" , NULL, "ADC Left"}, 753 {"Capture", NULL, "ADC Left"}, 754 {"Legacy Capture", NULL, "ADC Right"}, 755 {"Capture" , NULL, "ADC Right"}, 756 757 /* Capture path */ 758 {"Analog Left Capture Route", "Headset Mic", "HSMIC"}, 759 {"Analog Left Capture Route", "Main Mic", "MAINMIC"}, 760 {"Analog Left Capture Route", "Aux/FM Left", "AFML"}, 761 762 {"Analog Right Capture Route", "Headset Mic", "HSMIC"}, 763 {"Analog Right Capture Route", "Sub Mic", "SUBMIC"}, 764 {"Analog Right Capture Route", "Aux/FM Right", "AFMR"}, 765 766 {"MicAmpL", NULL, "Analog Left Capture Route"}, 767 {"MicAmpR", NULL, "Analog Right Capture Route"}, 768 769 {"ADC Left", NULL, "MicAmpL"}, 770 {"ADC Right", NULL, "MicAmpR"}, 771 772 /* AFM path */ 773 {"AFMAmpL", NULL, "AFML"}, 774 {"AFMAmpR", NULL, "AFMR"}, 775 776 {"HSDAC Left", NULL, "HSDAC Power"}, 777 {"HSDAC Right", NULL, "HSDAC Power"}, 778 779 {"Headset Left Playback", "HS DAC", "HSDAC Left"}, 780 {"Headset Left Playback", "Line-In amp", "AFMAmpL"}, 781 782 {"Headset Right Playback", "HS DAC", "HSDAC Right"}, 783 {"Headset Right Playback", "Line-In amp", "AFMAmpR"}, 784 785 {"HS Left Driver", NULL, "Headset Left Playback"}, 786 {"HS Right Driver", NULL, "Headset Right Playback"}, 787 788 {"HSOL", NULL, "HS Left Driver"}, 789 {"HSOR", NULL, "HS Right Driver"}, 790 791 /* Earphone playback path */ 792 {"Earphone Playback", "Switch", "HSDAC Left"}, 793 {"Earphone Driver", NULL, "Earphone Playback"}, 794 {"EP", NULL, "Earphone Driver"}, 795 796 {"Handsfree Left Playback", "HF DAC", "HFDAC Left"}, 797 {"Handsfree Left Playback", "Line-In amp", "AFMAmpL"}, 798 799 {"Handsfree Right Playback", "HF DAC", "HFDAC Right"}, 800 {"Handsfree Right Playback", "Line-In amp", "AFMAmpR"}, 801 802 {"HF Left PGA", NULL, "Handsfree Left Playback"}, 803 {"HF Right PGA", NULL, "Handsfree Right Playback"}, 804 805 {"HF Left Driver", NULL, "HF Left PGA"}, 806 {"HF Right Driver", NULL, "HF Right PGA"}, 807 808 {"HFL", NULL, "HF Left Driver"}, 809 {"HFR", NULL, "HF Right Driver"}, 810 811 {"AUXL Playback", "Switch", "HF Left PGA"}, 812 {"AUXR Playback", "Switch", "HF Right PGA"}, 813 814 {"AUXL", NULL, "AUXL Playback"}, 815 {"AUXR", NULL, "AUXR Playback"}, 816 817 /* Vibrator paths */ 818 {"Vibra Left Playback", "Audio PDM", "VIBRA DAC"}, 819 {"Vibra Right Playback", "Audio PDM", "VIBRA DAC"}, 820 821 {"Vibra Left Driver", NULL, "Vibra Left Playback"}, 822 {"Vibra Right Driver", NULL, "Vibra Right Playback"}, 823 {"Vibra Left Driver", NULL, "Vibra Left Control"}, 824 {"Vibra Right Driver", NULL, "Vibra Right Control"}, 825 826 {"VIBRAL", NULL, "Vibra Left Driver"}, 827 {"VIBRAR", NULL, "Vibra Right Driver"}, 828 }; 829 830 static int twl6040_set_bias_level(struct snd_soc_codec *codec, 831 enum snd_soc_bias_level level) 832 { 833 struct twl6040 *twl6040 = codec->control_data; 834 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 835 int ret = 0; 836 837 switch (level) { 838 case SND_SOC_BIAS_ON: 839 break; 840 case SND_SOC_BIAS_PREPARE: 841 break; 842 case SND_SOC_BIAS_STANDBY: 843 if (priv->codec_powered) { 844 /* Select low power PLL in standby */ 845 ret = twl6040_set_pll(twl6040, TWL6040_SYSCLK_SEL_LPPLL, 846 32768, 19200000); 847 break; 848 } 849 850 ret = twl6040_power(twl6040, 1); 851 if (ret) 852 break; 853 854 priv->codec_powered = 1; 855 856 /* Set external boost GPO */ 857 twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02); 858 break; 859 case SND_SOC_BIAS_OFF: 860 if (!priv->codec_powered) 861 break; 862 863 twl6040_power(twl6040, 0); 864 priv->codec_powered = 0; 865 break; 866 } 867 868 return ret; 869 } 870 871 static int twl6040_startup(struct snd_pcm_substream *substream, 872 struct snd_soc_dai *dai) 873 { 874 struct snd_soc_codec *codec = dai->codec; 875 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 876 877 snd_pcm_hw_constraint_list(substream->runtime, 0, 878 SNDRV_PCM_HW_PARAM_RATE, 879 &sysclk_constraints[priv->pll_power_mode]); 880 881 return 0; 882 } 883 884 static int twl6040_hw_params(struct snd_pcm_substream *substream, 885 struct snd_pcm_hw_params *params, 886 struct snd_soc_dai *dai) 887 { 888 struct snd_soc_codec *codec = dai->codec; 889 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 890 int rate; 891 892 rate = params_rate(params); 893 switch (rate) { 894 case 11250: 895 case 22500: 896 case 44100: 897 case 88200: 898 /* These rates are not supported when HPPLL is in use */ 899 if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) { 900 dev_err(codec->dev, "HPPLL does not support rate %d\n", 901 rate); 902 return -EINVAL; 903 } 904 priv->sysclk = 17640000; 905 break; 906 case 8000: 907 case 16000: 908 case 32000: 909 case 48000: 910 case 96000: 911 priv->sysclk = 19200000; 912 break; 913 default: 914 dev_err(codec->dev, "unsupported rate %d\n", rate); 915 return -EINVAL; 916 } 917 918 return 0; 919 } 920 921 static int twl6040_prepare(struct snd_pcm_substream *substream, 922 struct snd_soc_dai *dai) 923 { 924 struct snd_soc_codec *codec = dai->codec; 925 struct twl6040 *twl6040 = codec->control_data; 926 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 927 int ret; 928 929 if (!priv->sysclk) { 930 dev_err(codec->dev, 931 "no mclk configured, call set_sysclk() on init\n"); 932 return -EINVAL; 933 } 934 935 ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk); 936 if (ret) { 937 dev_err(codec->dev, "Can not set PLL (%d)\n", ret); 938 return -EPERM; 939 } 940 941 return 0; 942 } 943 944 static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, 945 int clk_id, unsigned int freq, int dir) 946 { 947 struct snd_soc_codec *codec = codec_dai->codec; 948 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 949 950 switch (clk_id) { 951 case TWL6040_SYSCLK_SEL_LPPLL: 952 case TWL6040_SYSCLK_SEL_HPPLL: 953 priv->pll = clk_id; 954 priv->clk_in = freq; 955 break; 956 default: 957 dev_err(codec->dev, "unknown clk_id %d\n", clk_id); 958 return -EINVAL; 959 } 960 961 return 0; 962 } 963 964 static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id, 965 int mute) 966 { 967 struct twl6040 *twl6040 = codec->control_data; 968 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 969 int hslctl, hsrctl, earctl; 970 int hflctl, hfrctl; 971 972 switch (id) { 973 case TWL6040_DAI_DL1: 974 hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL); 975 hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL); 976 earctl = twl6040_read(codec, TWL6040_REG_EARCTL); 977 978 if (mute) { 979 /* Power down drivers and DACs */ 980 earctl &= ~0x01; 981 hslctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA); 982 hsrctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA); 983 984 } 985 986 twl6040_reg_write(twl6040, TWL6040_REG_EARCTL, earctl); 987 twl6040_reg_write(twl6040, TWL6040_REG_HSLCTL, hslctl); 988 twl6040_reg_write(twl6040, TWL6040_REG_HSRCTL, hsrctl); 989 priv->dl1_unmuted = !mute; 990 break; 991 case TWL6040_DAI_DL2: 992 hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL); 993 hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL); 994 995 if (mute) { 996 /* Power down drivers and DACs */ 997 hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | 998 TWL6040_HFDRVENA | TWL6040_HFSWENA); 999 hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | 1000 TWL6040_HFDRVENA | TWL6040_HFSWENA); 1001 } 1002 1003 twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl); 1004 twl6040_reg_write(twl6040, TWL6040_REG_HFRCTL, hfrctl); 1005 priv->dl2_unmuted = !mute; 1006 break; 1007 default: 1008 break; 1009 } 1010 } 1011 1012 static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute) 1013 { 1014 switch (dai->id) { 1015 case TWL6040_DAI_LEGACY: 1016 twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute); 1017 twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute); 1018 break; 1019 case TWL6040_DAI_DL1: 1020 case TWL6040_DAI_DL2: 1021 twl6040_mute_path(dai->codec, dai->id, mute); 1022 break; 1023 default: 1024 break; 1025 } 1026 1027 return 0; 1028 } 1029 1030 static const struct snd_soc_dai_ops twl6040_dai_ops = { 1031 .startup = twl6040_startup, 1032 .hw_params = twl6040_hw_params, 1033 .prepare = twl6040_prepare, 1034 .set_sysclk = twl6040_set_dai_sysclk, 1035 .digital_mute = twl6040_digital_mute, 1036 }; 1037 1038 static struct snd_soc_dai_driver twl6040_dai[] = { 1039 { 1040 .name = "twl6040-legacy", 1041 .id = TWL6040_DAI_LEGACY, 1042 .playback = { 1043 .stream_name = "Legacy Playback", 1044 .channels_min = 1, 1045 .channels_max = 5, 1046 .rates = TWL6040_RATES, 1047 .formats = TWL6040_FORMATS, 1048 }, 1049 .capture = { 1050 .stream_name = "Legacy Capture", 1051 .channels_min = 1, 1052 .channels_max = 2, 1053 .rates = TWL6040_RATES, 1054 .formats = TWL6040_FORMATS, 1055 }, 1056 .ops = &twl6040_dai_ops, 1057 }, 1058 { 1059 .name = "twl6040-ul", 1060 .id = TWL6040_DAI_UL, 1061 .capture = { 1062 .stream_name = "Capture", 1063 .channels_min = 1, 1064 .channels_max = 2, 1065 .rates = TWL6040_RATES, 1066 .formats = TWL6040_FORMATS, 1067 }, 1068 .ops = &twl6040_dai_ops, 1069 }, 1070 { 1071 .name = "twl6040-dl1", 1072 .id = TWL6040_DAI_DL1, 1073 .playback = { 1074 .stream_name = "Headset Playback", 1075 .channels_min = 1, 1076 .channels_max = 2, 1077 .rates = TWL6040_RATES, 1078 .formats = TWL6040_FORMATS, 1079 }, 1080 .ops = &twl6040_dai_ops, 1081 }, 1082 { 1083 .name = "twl6040-dl2", 1084 .id = TWL6040_DAI_DL2, 1085 .playback = { 1086 .stream_name = "Handsfree Playback", 1087 .channels_min = 1, 1088 .channels_max = 2, 1089 .rates = TWL6040_RATES, 1090 .formats = TWL6040_FORMATS, 1091 }, 1092 .ops = &twl6040_dai_ops, 1093 }, 1094 { 1095 .name = "twl6040-vib", 1096 .id = TWL6040_DAI_VIB, 1097 .playback = { 1098 .stream_name = "Vibra Playback", 1099 .channels_min = 1, 1100 .channels_max = 1, 1101 .rates = SNDRV_PCM_RATE_CONTINUOUS, 1102 .formats = TWL6040_FORMATS, 1103 }, 1104 .ops = &twl6040_dai_ops, 1105 }, 1106 }; 1107 1108 static int twl6040_probe(struct snd_soc_codec *codec) 1109 { 1110 struct twl6040_data *priv; 1111 struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent); 1112 struct platform_device *pdev = to_platform_device(codec->dev); 1113 int ret = 0; 1114 1115 priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL); 1116 if (priv == NULL) 1117 return -ENOMEM; 1118 1119 snd_soc_codec_set_drvdata(codec, priv); 1120 1121 priv->codec = codec; 1122 codec->control_data = twl6040; 1123 1124 priv->plug_irq = platform_get_irq(pdev, 0); 1125 if (priv->plug_irq < 0) { 1126 dev_err(codec->dev, "invalid irq\n"); 1127 return -EINVAL; 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 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