1 /* 2 * Copyright (C) STMicroelectronics SA 2015 3 * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> 4 * for STMicroelectronics. 5 * License terms: GNU General Public License (GPL), version 2 6 */ 7 8 #include <linux/io.h> 9 #include <linux/module.h> 10 #include <linux/regmap.h> 11 #include <linux/reset.h> 12 #include <linux/mfd/syscon.h> 13 14 #include <sound/soc.h> 15 #include <sound/soc-dapm.h> 16 17 /* chipID supported */ 18 #define CHIPID_STIH416 0 19 #define CHIPID_STIH407 1 20 21 /* DAC definitions */ 22 23 /* stih416 DAC registers */ 24 /* sysconf 2517: Audio-DAC-Control */ 25 #define STIH416_AUDIO_DAC_CTRL 0x00000814 26 /* sysconf 2519: Audio-Gue-Control */ 27 #define STIH416_AUDIO_GLUE_CTRL 0x0000081C 28 29 #define STIH416_DAC_NOT_STANDBY 0x3 30 #define STIH416_DAC_SOFTMUTE 0x4 31 #define STIH416_DAC_ANA_NOT_PWR 0x5 32 #define STIH416_DAC_NOT_PNDBG 0x6 33 34 #define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY) 35 #define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE) 36 #define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR) 37 #define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG) 38 39 /* stih407 DAC registers */ 40 /* sysconf 5041: Audio-Gue-Control */ 41 #define STIH407_AUDIO_GLUE_CTRL 0x000000A4 42 /* sysconf 5042: Audio-DAC-Control */ 43 #define STIH407_AUDIO_DAC_CTRL 0x000000A8 44 45 /* DAC definitions */ 46 #define STIH407_DAC_SOFTMUTE 0x0 47 #define STIH407_DAC_STANDBY_ANA 0x1 48 #define STIH407_DAC_STANDBY 0x2 49 50 #define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE) 51 #define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA) 52 #define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY) 53 54 /* SPDIF definitions */ 55 #define SPDIF_BIPHASE_ENABLE 0x6 56 #define SPDIF_BIPHASE_IDLE 0x7 57 58 #define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE) 59 #define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE) 60 61 enum { 62 STI_SAS_DAI_SPDIF_OUT, 63 STI_SAS_DAI_ANALOG_OUT, 64 }; 65 66 static const struct reg_default stih416_sas_reg_defaults[] = { 67 { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, 68 { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, 69 }; 70 71 static const struct reg_default stih407_sas_reg_defaults[] = { 72 { STIH416_AUDIO_DAC_CTRL, 0x000000000 }, 73 { STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, 74 }; 75 76 struct sti_dac_audio { 77 struct regmap *regmap; 78 struct regmap *virt_regmap; 79 struct regmap_field **field; 80 struct reset_control *rst; 81 int mclk; 82 }; 83 84 struct sti_spdif_audio { 85 struct regmap *regmap; 86 struct regmap_field **field; 87 int mclk; 88 }; 89 90 /* device data structure */ 91 struct sti_sas_dev_data { 92 const int chipid; /* IC version */ 93 const struct regmap_config *regmap; 94 const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ 95 const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ 96 const int num_dapm_widgets; /* dapms declaration */ 97 const struct snd_soc_dapm_route *dapm_routes; /* route declaration */ 98 const int num_dapm_routes; /* route declaration */ 99 }; 100 101 /* driver data structure */ 102 struct sti_sas_data { 103 struct device *dev; 104 const struct sti_sas_dev_data *dev_data; 105 struct sti_dac_audio dac; 106 struct sti_spdif_audio spdif; 107 }; 108 109 /* Read a register from the sysconf reg bank */ 110 static int sti_sas_read_reg(void *context, unsigned int reg, 111 unsigned int *value) 112 { 113 struct sti_sas_data *drvdata = context; 114 int status; 115 u32 val; 116 117 status = regmap_read(drvdata->dac.regmap, reg, &val); 118 *value = (unsigned int)val; 119 120 return status; 121 } 122 123 /* Read a register from the sysconf reg bank */ 124 static int sti_sas_write_reg(void *context, unsigned int reg, 125 unsigned int value) 126 { 127 struct sti_sas_data *drvdata = context; 128 int status; 129 130 status = regmap_write(drvdata->dac.regmap, reg, value); 131 132 return status; 133 } 134 135 static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, 136 struct sti_sas_data *data) 137 { 138 int ret; 139 /* 140 * DAC and SPDIF are activated by default 141 * put them in IDLE to save power 142 */ 143 144 /* Initialise bi-phase formatter to disabled */ 145 ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, 146 SPDIF_BIPHASE_ENABLE_MASK, 0); 147 148 if (!ret) 149 /* Initialise bi-phase formatter idle value to 0 */ 150 ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, 151 SPDIF_BIPHASE_IDLE_MASK, 0); 152 if (ret < 0) { 153 dev_err(codec->dev, "Failed to update SPDIF registers"); 154 return ret; 155 } 156 157 /* Init DAC configuration */ 158 switch (data->dev_data->chipid) { 159 case CHIPID_STIH407: 160 /* init configuration */ 161 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 162 STIH407_DAC_STANDBY_MASK, 163 STIH407_DAC_STANDBY_MASK); 164 165 if (!ret) 166 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 167 STIH407_DAC_STANDBY_ANA_MASK, 168 STIH407_DAC_STANDBY_ANA_MASK); 169 if (!ret) 170 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 171 STIH407_DAC_SOFTMUTE_MASK, 172 STIH407_DAC_SOFTMUTE_MASK); 173 break; 174 case CHIPID_STIH416: 175 ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, 176 STIH416_DAC_NOT_STANDBY_MASK, 0); 177 if (!ret) 178 ret = snd_soc_update_bits(codec, 179 STIH416_AUDIO_DAC_CTRL, 180 STIH416_DAC_ANA_NOT_PWR, 0); 181 if (!ret) 182 ret = snd_soc_update_bits(codec, 183 STIH416_AUDIO_DAC_CTRL, 184 STIH416_DAC_NOT_PNDBG_MASK, 185 0); 186 if (!ret) 187 ret = snd_soc_update_bits(codec, 188 STIH416_AUDIO_DAC_CTRL, 189 STIH416_DAC_SOFTMUTE_MASK, 190 STIH416_DAC_SOFTMUTE_MASK); 191 break; 192 default: 193 return -EINVAL; 194 } 195 196 if (ret < 0) { 197 dev_err(codec->dev, "Failed to update DAC registers"); 198 return ret; 199 } 200 201 return ret; 202 } 203 204 /* 205 * DAC 206 */ 207 static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 208 { 209 /* Sanity check only */ 210 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { 211 dev_err(dai->codec->dev, 212 "%s: ERROR: Unsupporter master mask 0x%x\n", 213 __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); 214 return -EINVAL; 215 } 216 217 return 0; 218 } 219 220 static int stih416_dac_probe(struct snd_soc_dai *dai) 221 { 222 struct snd_soc_codec *codec = dai->codec; 223 struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); 224 struct sti_dac_audio *dac = &drvdata->dac; 225 226 /* Get reset control */ 227 dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); 228 if (IS_ERR(dac->rst)) { 229 dev_err(dai->codec->dev, 230 "%s: ERROR: DAC reset control not defined !\n", 231 __func__); 232 dac->rst = NULL; 233 return -EFAULT; 234 } 235 /* Put the DAC into reset */ 236 reset_control_assert(dac->rst); 237 238 return 0; 239 } 240 241 static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { 242 SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, 243 STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), 244 SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, 245 STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0), 246 SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL, 247 STIH416_DAC_NOT_STANDBY, 0), 248 SND_SOC_DAPM_OUTPUT("DAC Output"), 249 }; 250 251 static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { 252 SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, 253 STIH407_DAC_STANDBY_ANA, 1, NULL, 0), 254 SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL, 255 STIH407_DAC_STANDBY, 1), 256 SND_SOC_DAPM_OUTPUT("DAC Output"), 257 }; 258 259 static const struct snd_soc_dapm_route stih416_sas_route[] = { 260 {"DAC Output", NULL, "DAC bandgap"}, 261 {"DAC Output", NULL, "DAC standby ana"}, 262 {"DAC standby ana", NULL, "DAC standby"}, 263 }; 264 265 static const struct snd_soc_dapm_route stih407_sas_route[] = { 266 {"DAC Output", NULL, "DAC standby ana"}, 267 {"DAC standby ana", NULL, "DAC standby"}, 268 }; 269 270 static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) 271 { 272 struct snd_soc_codec *codec = dai->codec; 273 274 if (mute) { 275 return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, 276 STIH416_DAC_SOFTMUTE_MASK, 277 STIH416_DAC_SOFTMUTE_MASK); 278 } else { 279 return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, 280 STIH416_DAC_SOFTMUTE_MASK, 0); 281 } 282 } 283 284 static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) 285 { 286 struct snd_soc_codec *codec = dai->codec; 287 288 if (mute) { 289 return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 290 STIH407_DAC_SOFTMUTE_MASK, 291 STIH407_DAC_SOFTMUTE_MASK); 292 } else { 293 return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 294 STIH407_DAC_SOFTMUTE_MASK, 295 0); 296 } 297 } 298 299 /* 300 * SPDIF 301 */ 302 static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai, 303 unsigned int fmt) 304 { 305 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { 306 dev_err(dai->codec->dev, 307 "%s: ERROR: Unsupporter master mask 0x%x\n", 308 __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); 309 return -EINVAL; 310 } 311 312 return 0; 313 } 314 315 /* 316 * sti_sas_spdif_trigger: 317 * Trigger function is used to ensure that BiPhase Formater is disabled 318 * before CPU dai is stopped. 319 * This is mandatory to avoid that BPF is stalled 320 */ 321 static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd, 322 struct snd_soc_dai *dai) 323 { 324 struct snd_soc_codec *codec = dai->codec; 325 326 switch (cmd) { 327 case SNDRV_PCM_TRIGGER_START: 328 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 329 return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, 330 SPDIF_BIPHASE_ENABLE_MASK, 331 SPDIF_BIPHASE_ENABLE_MASK); 332 case SNDRV_PCM_TRIGGER_RESUME: 333 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 334 case SNDRV_PCM_TRIGGER_STOP: 335 case SNDRV_PCM_TRIGGER_SUSPEND: 336 return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, 337 SPDIF_BIPHASE_ENABLE_MASK, 338 0); 339 default: 340 return -EINVAL; 341 } 342 } 343 344 static bool sti_sas_volatile_register(struct device *dev, unsigned int reg) 345 { 346 if (reg == STIH407_AUDIO_GLUE_CTRL) 347 return true; 348 349 return false; 350 } 351 352 /* 353 * CODEC DAIS 354 */ 355 356 /* 357 * sti_sas_set_sysclk: 358 * get MCLK input frequency to check that MCLK-FS ratio is coherent 359 */ 360 static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id, 361 unsigned int freq, int dir) 362 { 363 struct snd_soc_codec *codec = dai->codec; 364 struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); 365 366 if (dir == SND_SOC_CLOCK_OUT) 367 return 0; 368 369 if (clk_id != 0) 370 return -EINVAL; 371 372 switch (dai->id) { 373 case STI_SAS_DAI_SPDIF_OUT: 374 drvdata->spdif.mclk = freq; 375 break; 376 377 case STI_SAS_DAI_ANALOG_OUT: 378 drvdata->dac.mclk = freq; 379 break; 380 } 381 382 return 0; 383 } 384 385 static int sti_sas_prepare(struct snd_pcm_substream *substream, 386 struct snd_soc_dai *dai) 387 { 388 struct snd_soc_codec *codec = dai->codec; 389 struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); 390 struct snd_pcm_runtime *runtime = substream->runtime; 391 392 switch (dai->id) { 393 case STI_SAS_DAI_SPDIF_OUT: 394 if ((drvdata->spdif.mclk / runtime->rate) != 128) { 395 dev_err(codec->dev, "unexpected mclk-fs ratio"); 396 return -EINVAL; 397 } 398 break; 399 case STI_SAS_DAI_ANALOG_OUT: 400 if ((drvdata->dac.mclk / runtime->rate) != 256) { 401 dev_err(codec->dev, "unexpected mclk-fs ratio"); 402 return -EINVAL; 403 } 404 break; 405 } 406 407 return 0; 408 } 409 410 static const struct snd_soc_dai_ops stih416_dac_ops = { 411 .set_fmt = sti_sas_dac_set_fmt, 412 .mute_stream = stih416_sas_dac_mute, 413 .prepare = sti_sas_prepare, 414 .set_sysclk = sti_sas_set_sysclk, 415 }; 416 417 static const struct snd_soc_dai_ops stih407_dac_ops = { 418 .set_fmt = sti_sas_dac_set_fmt, 419 .mute_stream = stih407_sas_dac_mute, 420 .prepare = sti_sas_prepare, 421 .set_sysclk = sti_sas_set_sysclk, 422 }; 423 424 static const struct regmap_config stih407_sas_regmap = { 425 .reg_bits = 32, 426 .val_bits = 32, 427 428 .max_register = STIH407_AUDIO_DAC_CTRL, 429 .reg_defaults = stih407_sas_reg_defaults, 430 .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), 431 .volatile_reg = sti_sas_volatile_register, 432 .cache_type = REGCACHE_RBTREE, 433 .reg_read = sti_sas_read_reg, 434 .reg_write = sti_sas_write_reg, 435 }; 436 437 static const struct regmap_config stih416_sas_regmap = { 438 .reg_bits = 32, 439 .val_bits = 32, 440 441 .max_register = STIH416_AUDIO_DAC_CTRL, 442 .reg_defaults = stih416_sas_reg_defaults, 443 .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults), 444 .volatile_reg = sti_sas_volatile_register, 445 .cache_type = REGCACHE_RBTREE, 446 .reg_read = sti_sas_read_reg, 447 .reg_write = sti_sas_write_reg, 448 }; 449 450 static const struct sti_sas_dev_data stih416_data = { 451 .chipid = CHIPID_STIH416, 452 .regmap = &stih416_sas_regmap, 453 .dac_ops = &stih416_dac_ops, 454 .dapm_widgets = stih416_sas_dapm_widgets, 455 .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets), 456 .dapm_routes = stih416_sas_route, 457 .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), 458 }; 459 460 static const struct sti_sas_dev_data stih407_data = { 461 .chipid = CHIPID_STIH407, 462 .regmap = &stih407_sas_regmap, 463 .dac_ops = &stih407_dac_ops, 464 .dapm_widgets = stih407_sas_dapm_widgets, 465 .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets), 466 .dapm_routes = stih407_sas_route, 467 .num_dapm_routes = ARRAY_SIZE(stih407_sas_route), 468 }; 469 470 static struct snd_soc_dai_driver sti_sas_dai[] = { 471 { 472 .name = "sas-dai-spdif-out", 473 .id = STI_SAS_DAI_SPDIF_OUT, 474 .playback = { 475 .stream_name = "spdif_p", 476 .channels_min = 2, 477 .channels_max = 2, 478 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 479 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | 480 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 481 SNDRV_PCM_RATE_192000, 482 .formats = SNDRV_PCM_FMTBIT_S16_LE | 483 SNDRV_PCM_FMTBIT_S32_LE, 484 }, 485 .ops = (struct snd_soc_dai_ops[]) { 486 { 487 .set_fmt = sti_sas_spdif_set_fmt, 488 .trigger = sti_sas_spdif_trigger, 489 .set_sysclk = sti_sas_set_sysclk, 490 .prepare = sti_sas_prepare, 491 } 492 }, 493 }, 494 { 495 .name = "sas-dai-dac", 496 .id = STI_SAS_DAI_ANALOG_OUT, 497 .playback = { 498 .stream_name = "dac_p", 499 .channels_min = 2, 500 .channels_max = 2, 501 .rates = SNDRV_PCM_RATE_8000_48000, 502 .formats = SNDRV_PCM_FMTBIT_S16_LE | 503 SNDRV_PCM_FMTBIT_S32_LE, 504 }, 505 }, 506 }; 507 508 #ifdef CONFIG_PM_SLEEP 509 static int sti_sas_resume(struct snd_soc_codec *codec) 510 { 511 struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); 512 513 return sti_sas_init_sas_registers(codec, drvdata); 514 } 515 #else 516 #define sti_sas_resume NULL 517 #endif 518 519 static int sti_sas_codec_probe(struct snd_soc_codec *codec) 520 { 521 struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); 522 int ret; 523 524 ret = sti_sas_init_sas_registers(codec, drvdata); 525 526 return ret; 527 } 528 529 static struct snd_soc_codec_driver sti_sas_driver = { 530 .probe = sti_sas_codec_probe, 531 .resume = sti_sas_resume, 532 }; 533 534 static const struct of_device_id sti_sas_dev_match[] = { 535 { 536 .compatible = "st,stih416-sas-codec", 537 .data = &stih416_data, 538 }, 539 { 540 .compatible = "st,stih407-sas-codec", 541 .data = &stih407_data, 542 }, 543 {}, 544 }; 545 546 static int sti_sas_driver_probe(struct platform_device *pdev) 547 { 548 struct device_node *pnode = pdev->dev.of_node; 549 struct sti_sas_data *drvdata; 550 const struct of_device_id *of_id; 551 552 /* Allocate device structure */ 553 drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data), 554 GFP_KERNEL); 555 if (!drvdata) 556 return -ENOMEM; 557 558 /* Populate data structure depending on compatibility */ 559 of_id = of_match_node(sti_sas_dev_match, pnode); 560 if (!of_id->data) { 561 dev_err(&pdev->dev, "data associated to device is missing"); 562 return -EINVAL; 563 } 564 565 drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data; 566 567 /* Initialise device structure */ 568 drvdata->dev = &pdev->dev; 569 570 /* Request the DAC & SPDIF registers memory region */ 571 drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata, 572 drvdata->dev_data->regmap); 573 if (IS_ERR(drvdata->dac.virt_regmap)) { 574 dev_err(&pdev->dev, "audio registers not enabled\n"); 575 return PTR_ERR(drvdata->dac.virt_regmap); 576 } 577 578 /* Request the syscon region */ 579 drvdata->dac.regmap = 580 syscon_regmap_lookup_by_phandle(pnode, "st,syscfg"); 581 if (IS_ERR(drvdata->dac.regmap)) { 582 dev_err(&pdev->dev, "syscon registers not available\n"); 583 return PTR_ERR(drvdata->dac.regmap); 584 } 585 drvdata->spdif.regmap = drvdata->dac.regmap; 586 587 /* Set DAC dai probe */ 588 if (drvdata->dev_data->chipid == CHIPID_STIH416) 589 sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe; 590 591 sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; 592 593 /* Set dapms*/ 594 sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; 595 sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; 596 597 sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; 598 sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; 599 600 /* Store context */ 601 dev_set_drvdata(&pdev->dev, drvdata); 602 603 return snd_soc_register_codec(&pdev->dev, &sti_sas_driver, 604 sti_sas_dai, 605 ARRAY_SIZE(sti_sas_dai)); 606 } 607 608 static int sti_sas_driver_remove(struct platform_device *pdev) 609 { 610 snd_soc_unregister_codec(&pdev->dev); 611 612 return 0; 613 } 614 615 static struct platform_driver sti_sas_platform_driver = { 616 .driver = { 617 .name = "sti-sas-codec", 618 .of_match_table = sti_sas_dev_match, 619 }, 620 .probe = sti_sas_driver_probe, 621 .remove = sti_sas_driver_remove, 622 }; 623 624 module_platform_driver(sti_sas_platform_driver); 625 626 MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms"); 627 MODULE_AUTHOR("Arnaud.pouliquen@st.com"); 628 MODULE_LICENSE("GPL v2"); 629