1 /* 2 * wm8523.c -- WM8523 ALSA SoC Audio driver 3 * 4 * Copyright 2009 Wolfson Microelectronics plc 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 #include <linux/module.h> 15 #include <linux/moduleparam.h> 16 #include <linux/init.h> 17 #include <linux/delay.h> 18 #include <linux/pm.h> 19 #include <linux/i2c.h> 20 #include <linux/platform_device.h> 21 #include <linux/regulator/consumer.h> 22 #include <sound/core.h> 23 #include <sound/pcm.h> 24 #include <sound/pcm_params.h> 25 #include <sound/soc.h> 26 #include <sound/soc-dapm.h> 27 #include <sound/initval.h> 28 #include <sound/tlv.h> 29 30 #include "wm8523.h" 31 32 static struct snd_soc_codec *wm8523_codec; 33 struct snd_soc_codec_device soc_codec_dev_wm8523; 34 35 #define WM8523_NUM_SUPPLIES 2 36 static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = { 37 "AVDD", 38 "LINEVDD", 39 }; 40 41 #define WM8523_NUM_RATES 7 42 43 /* codec private data */ 44 struct wm8523_priv { 45 struct snd_soc_codec codec; 46 u16 reg_cache[WM8523_REGISTER_COUNT]; 47 struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES]; 48 unsigned int sysclk; 49 unsigned int rate_constraint_list[WM8523_NUM_RATES]; 50 struct snd_pcm_hw_constraint_list rate_constraint; 51 }; 52 53 static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = { 54 0x8523, /* R0 - DEVICE_ID */ 55 0x0001, /* R1 - REVISION */ 56 0x0000, /* R2 - PSCTRL1 */ 57 0x1812, /* R3 - AIF_CTRL1 */ 58 0x0000, /* R4 - AIF_CTRL2 */ 59 0x0001, /* R5 - DAC_CTRL3 */ 60 0x0190, /* R6 - DAC_GAINL */ 61 0x0190, /* R7 - DAC_GAINR */ 62 0x0000, /* R8 - ZERO_DETECT */ 63 }; 64 65 static int wm8523_volatile_register(unsigned int reg) 66 { 67 switch (reg) { 68 case WM8523_DEVICE_ID: 69 case WM8523_REVISION: 70 return 1; 71 default: 72 return 0; 73 } 74 } 75 76 static int wm8523_reset(struct snd_soc_codec *codec) 77 { 78 return snd_soc_write(codec, WM8523_DEVICE_ID, 0); 79 } 80 81 static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0); 82 83 static const char *wm8523_zd_count_text[] = { 84 "1024", 85 "2048", 86 }; 87 88 static const struct soc_enum wm8523_zc_count = 89 SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text); 90 91 static const struct snd_kcontrol_new wm8523_snd_controls[] = { 92 SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR, 93 0, 448, 0, dac_tlv), 94 SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0), 95 SOC_SINGLE("Playback Deemphasis Switch", WM8523_AIF_CTRL1, 8, 1, 0), 96 SOC_DOUBLE("Playback Switch", WM8523_DAC_CTRL3, 2, 3, 1, 1), 97 SOC_SINGLE("Volume Ramp Up Switch", WM8523_DAC_CTRL3, 1, 1, 0), 98 SOC_SINGLE("Volume Ramp Down Switch", WM8523_DAC_CTRL3, 0, 1, 0), 99 SOC_ENUM("Zero Detect Count", wm8523_zc_count), 100 }; 101 102 static const struct snd_soc_dapm_widget wm8523_dapm_widgets[] = { 103 SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), 104 SND_SOC_DAPM_OUTPUT("LINEVOUTL"), 105 SND_SOC_DAPM_OUTPUT("LINEVOUTR"), 106 }; 107 108 static const struct snd_soc_dapm_route intercon[] = { 109 { "LINEVOUTL", NULL, "DAC" }, 110 { "LINEVOUTR", NULL, "DAC" }, 111 }; 112 113 static int wm8523_add_widgets(struct snd_soc_codec *codec) 114 { 115 snd_soc_dapm_new_controls(codec, wm8523_dapm_widgets, 116 ARRAY_SIZE(wm8523_dapm_widgets)); 117 118 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); 119 120 return 0; 121 } 122 123 static struct { 124 int value; 125 int ratio; 126 } lrclk_ratios[WM8523_NUM_RATES] = { 127 { 1, 128 }, 128 { 2, 192 }, 129 { 3, 256 }, 130 { 4, 384 }, 131 { 5, 512 }, 132 { 6, 768 }, 133 { 7, 1152 }, 134 }; 135 136 static int wm8523_startup(struct snd_pcm_substream *substream, 137 struct snd_soc_dai *dai) 138 { 139 struct snd_soc_codec *codec = dai->codec; 140 struct wm8523_priv *wm8523 = codec->private_data; 141 142 /* The set of sample rates that can be supported depends on the 143 * MCLK supplied to the CODEC - enforce this. 144 */ 145 if (!wm8523->sysclk) { 146 dev_err(codec->dev, 147 "No MCLK configured, call set_sysclk() on init\n"); 148 return -EINVAL; 149 } 150 151 return 0; 152 snd_pcm_hw_constraint_list(substream->runtime, 0, 153 SNDRV_PCM_HW_PARAM_RATE, 154 &wm8523->rate_constraint); 155 156 return 0; 157 } 158 159 static int wm8523_hw_params(struct snd_pcm_substream *substream, 160 struct snd_pcm_hw_params *params, 161 struct snd_soc_dai *dai) 162 { 163 struct snd_soc_pcm_runtime *rtd = substream->private_data; 164 struct snd_soc_device *socdev = rtd->socdev; 165 struct snd_soc_codec *codec = socdev->card->codec; 166 struct wm8523_priv *wm8523 = codec->private_data; 167 int i; 168 u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); 169 u16 aifctrl2 = snd_soc_read(codec, WM8523_AIF_CTRL2); 170 171 /* Find a supported LRCLK ratio */ 172 for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { 173 if (wm8523->sysclk / params_rate(params) == 174 lrclk_ratios[i].ratio) 175 break; 176 } 177 178 /* Should never happen, should be handled by constraints */ 179 if (i == ARRAY_SIZE(lrclk_ratios)) { 180 dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n", 181 wm8523->sysclk / params_rate(params)); 182 return -EINVAL; 183 } 184 185 aifctrl2 &= ~WM8523_SR_MASK; 186 aifctrl2 |= lrclk_ratios[i].value; 187 188 aifctrl1 &= ~WM8523_WL_MASK; 189 switch (params_format(params)) { 190 case SNDRV_PCM_FORMAT_S16_LE: 191 break; 192 case SNDRV_PCM_FORMAT_S20_3LE: 193 aifctrl1 |= 0x8; 194 break; 195 case SNDRV_PCM_FORMAT_S24_LE: 196 aifctrl1 |= 0x10; 197 break; 198 case SNDRV_PCM_FORMAT_S32_LE: 199 aifctrl1 |= 0x18; 200 break; 201 } 202 203 snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1); 204 snd_soc_write(codec, WM8523_AIF_CTRL2, aifctrl2); 205 206 return 0; 207 } 208 209 static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai, 210 int clk_id, unsigned int freq, int dir) 211 { 212 struct snd_soc_codec *codec = codec_dai->codec; 213 struct wm8523_priv *wm8523 = codec->private_data; 214 unsigned int val; 215 int i; 216 217 wm8523->sysclk = freq; 218 219 wm8523->rate_constraint.count = 0; 220 for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { 221 val = freq / lrclk_ratios[i].ratio; 222 /* Check that it's a standard rate since core can't 223 * cope with others and having the odd rates confuses 224 * constraint matching. 225 */ 226 switch (val) { 227 case 8000: 228 case 11025: 229 case 16000: 230 case 22050: 231 case 32000: 232 case 44100: 233 case 48000: 234 case 64000: 235 case 88200: 236 case 96000: 237 case 176400: 238 case 192000: 239 dev_dbg(codec->dev, "Supported sample rate: %dHz\n", 240 val); 241 wm8523->rate_constraint_list[i] = val; 242 wm8523->rate_constraint.count++; 243 break; 244 default: 245 dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", 246 val); 247 } 248 } 249 250 /* Need at least one supported rate... */ 251 if (wm8523->rate_constraint.count == 0) 252 return -EINVAL; 253 254 return 0; 255 } 256 257 258 static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, 259 unsigned int fmt) 260 { 261 struct snd_soc_codec *codec = codec_dai->codec; 262 u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); 263 264 aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK | 265 WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK); 266 267 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 268 case SND_SOC_DAIFMT_CBM_CFM: 269 aifctrl1 |= WM8523_AIF_MSTR; 270 break; 271 case SND_SOC_DAIFMT_CBS_CFS: 272 break; 273 default: 274 return -EINVAL; 275 } 276 277 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 278 case SND_SOC_DAIFMT_I2S: 279 aifctrl1 |= 0x0002; 280 break; 281 case SND_SOC_DAIFMT_RIGHT_J: 282 break; 283 case SND_SOC_DAIFMT_LEFT_J: 284 aifctrl1 |= 0x0001; 285 break; 286 case SND_SOC_DAIFMT_DSP_A: 287 aifctrl1 |= 0x0003; 288 break; 289 case SND_SOC_DAIFMT_DSP_B: 290 aifctrl1 |= 0x0023; 291 break; 292 default: 293 return -EINVAL; 294 } 295 296 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 297 case SND_SOC_DAIFMT_NB_NF: 298 break; 299 case SND_SOC_DAIFMT_IB_IF: 300 aifctrl1 |= WM8523_BCLK_INV | WM8523_LRCLK_INV; 301 break; 302 case SND_SOC_DAIFMT_IB_NF: 303 aifctrl1 |= WM8523_BCLK_INV; 304 break; 305 case SND_SOC_DAIFMT_NB_IF: 306 aifctrl1 |= WM8523_LRCLK_INV; 307 break; 308 default: 309 return -EINVAL; 310 } 311 312 snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1); 313 314 return 0; 315 } 316 317 static int wm8523_set_bias_level(struct snd_soc_codec *codec, 318 enum snd_soc_bias_level level) 319 { 320 struct wm8523_priv *wm8523 = codec->private_data; 321 int ret, i; 322 323 switch (level) { 324 case SND_SOC_BIAS_ON: 325 break; 326 327 case SND_SOC_BIAS_PREPARE: 328 /* Full power on */ 329 snd_soc_update_bits(codec, WM8523_PSCTRL1, 330 WM8523_SYS_ENA_MASK, 3); 331 break; 332 333 case SND_SOC_BIAS_STANDBY: 334 if (codec->bias_level == SND_SOC_BIAS_OFF) { 335 ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), 336 wm8523->supplies); 337 if (ret != 0) { 338 dev_err(codec->dev, 339 "Failed to enable supplies: %d\n", 340 ret); 341 return ret; 342 } 343 344 /* Initial power up */ 345 snd_soc_update_bits(codec, WM8523_PSCTRL1, 346 WM8523_SYS_ENA_MASK, 1); 347 348 /* Sync back default/cached values */ 349 for (i = WM8523_AIF_CTRL1; 350 i < WM8523_MAX_REGISTER; i++) 351 snd_soc_write(codec, i, wm8523->reg_cache[i]); 352 353 354 msleep(100); 355 } 356 357 /* Power up to mute */ 358 snd_soc_update_bits(codec, WM8523_PSCTRL1, 359 WM8523_SYS_ENA_MASK, 2); 360 361 break; 362 363 case SND_SOC_BIAS_OFF: 364 /* The chip runs through the power down sequence for us. */ 365 snd_soc_update_bits(codec, WM8523_PSCTRL1, 366 WM8523_SYS_ENA_MASK, 0); 367 msleep(100); 368 369 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), 370 wm8523->supplies); 371 break; 372 } 373 codec->bias_level = level; 374 return 0; 375 } 376 377 #define WM8523_RATES SNDRV_PCM_RATE_8000_192000 378 379 #define WM8523_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 380 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 381 382 static struct snd_soc_dai_ops wm8523_dai_ops = { 383 .startup = wm8523_startup, 384 .hw_params = wm8523_hw_params, 385 .set_sysclk = wm8523_set_dai_sysclk, 386 .set_fmt = wm8523_set_dai_fmt, 387 }; 388 389 struct snd_soc_dai wm8523_dai = { 390 .name = "WM8523", 391 .playback = { 392 .stream_name = "Playback", 393 .channels_min = 2, /* Mono modes not yet supported */ 394 .channels_max = 2, 395 .rates = WM8523_RATES, 396 .formats = WM8523_FORMATS, 397 }, 398 .ops = &wm8523_dai_ops, 399 }; 400 EXPORT_SYMBOL_GPL(wm8523_dai); 401 402 #ifdef CONFIG_PM 403 static int wm8523_suspend(struct platform_device *pdev, pm_message_t state) 404 { 405 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 406 struct snd_soc_codec *codec = socdev->card->codec; 407 408 wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); 409 return 0; 410 } 411 412 static int wm8523_resume(struct platform_device *pdev) 413 { 414 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 415 struct snd_soc_codec *codec = socdev->card->codec; 416 417 wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 418 419 return 0; 420 } 421 #else 422 #define wm8523_suspend NULL 423 #define wm8523_resume NULL 424 #endif 425 426 static int wm8523_probe(struct platform_device *pdev) 427 { 428 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 429 struct snd_soc_codec *codec; 430 int ret = 0; 431 432 if (wm8523_codec == NULL) { 433 dev_err(&pdev->dev, "Codec device not registered\n"); 434 return -ENODEV; 435 } 436 437 socdev->card->codec = wm8523_codec; 438 codec = wm8523_codec; 439 440 /* register pcms */ 441 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 442 if (ret < 0) { 443 dev_err(codec->dev, "failed to create pcms: %d\n", ret); 444 goto pcm_err; 445 } 446 447 snd_soc_add_controls(codec, wm8523_snd_controls, 448 ARRAY_SIZE(wm8523_snd_controls)); 449 wm8523_add_widgets(codec); 450 451 return ret; 452 453 pcm_err: 454 return ret; 455 } 456 457 static int wm8523_remove(struct platform_device *pdev) 458 { 459 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 460 461 snd_soc_free_pcms(socdev); 462 snd_soc_dapm_free(socdev); 463 464 return 0; 465 } 466 467 struct snd_soc_codec_device soc_codec_dev_wm8523 = { 468 .probe = wm8523_probe, 469 .remove = wm8523_remove, 470 .suspend = wm8523_suspend, 471 .resume = wm8523_resume, 472 }; 473 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523); 474 475 static int wm8523_register(struct wm8523_priv *wm8523, 476 enum snd_soc_control_type control) 477 { 478 int ret; 479 struct snd_soc_codec *codec = &wm8523->codec; 480 int i; 481 482 if (wm8523_codec) { 483 dev_err(codec->dev, "Another WM8523 is registered\n"); 484 return -EINVAL; 485 } 486 487 mutex_init(&codec->mutex); 488 INIT_LIST_HEAD(&codec->dapm_widgets); 489 INIT_LIST_HEAD(&codec->dapm_paths); 490 491 codec->private_data = wm8523; 492 codec->name = "WM8523"; 493 codec->owner = THIS_MODULE; 494 codec->bias_level = SND_SOC_BIAS_OFF; 495 codec->set_bias_level = wm8523_set_bias_level; 496 codec->dai = &wm8523_dai; 497 codec->num_dai = 1; 498 codec->reg_cache_size = WM8523_REGISTER_COUNT; 499 codec->reg_cache = &wm8523->reg_cache; 500 codec->volatile_register = wm8523_volatile_register; 501 502 wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; 503 wm8523->rate_constraint.count = 504 ARRAY_SIZE(wm8523->rate_constraint_list); 505 506 memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); 507 508 ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); 509 if (ret != 0) { 510 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 511 goto err; 512 } 513 514 for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) 515 wm8523->supplies[i].supply = wm8523_supply_names[i]; 516 517 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8523->supplies), 518 wm8523->supplies); 519 if (ret != 0) { 520 dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 521 goto err; 522 } 523 524 ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), 525 wm8523->supplies); 526 if (ret != 0) { 527 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 528 goto err_get; 529 } 530 531 ret = snd_soc_read(codec, WM8523_DEVICE_ID); 532 if (ret < 0) { 533 dev_err(codec->dev, "Failed to read ID register\n"); 534 goto err_enable; 535 } 536 if (ret != wm8523_reg[WM8523_DEVICE_ID]) { 537 dev_err(codec->dev, "Device is not a WM8523, ID is %x\n", ret); 538 ret = -EINVAL; 539 goto err_enable; 540 } 541 542 ret = snd_soc_read(codec, WM8523_REVISION); 543 if (ret < 0) { 544 dev_err(codec->dev, "Failed to read revision register\n"); 545 goto err_enable; 546 } 547 dev_info(codec->dev, "revision %c\n", 548 (ret & WM8523_CHIP_REV_MASK) + 'A'); 549 550 ret = wm8523_reset(codec); 551 if (ret < 0) { 552 dev_err(codec->dev, "Failed to issue reset\n"); 553 goto err_enable; 554 } 555 556 wm8523_dai.dev = codec->dev; 557 558 /* Change some default settings - latch VU and enable ZC */ 559 wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU; 560 wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC; 561 562 wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 563 564 /* Bias level configuration will have done an extra enable */ 565 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 566 567 wm8523_codec = codec; 568 569 ret = snd_soc_register_codec(codec); 570 if (ret != 0) { 571 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 572 return ret; 573 } 574 575 ret = snd_soc_register_dai(&wm8523_dai); 576 if (ret != 0) { 577 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 578 snd_soc_unregister_codec(codec); 579 return ret; 580 } 581 582 return 0; 583 584 err_enable: 585 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 586 err_get: 587 regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 588 err: 589 kfree(wm8523); 590 return ret; 591 } 592 593 static void wm8523_unregister(struct wm8523_priv *wm8523) 594 { 595 wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF); 596 regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 597 snd_soc_unregister_dai(&wm8523_dai); 598 snd_soc_unregister_codec(&wm8523->codec); 599 kfree(wm8523); 600 wm8523_codec = NULL; 601 } 602 603 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 604 static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, 605 const struct i2c_device_id *id) 606 { 607 struct wm8523_priv *wm8523; 608 struct snd_soc_codec *codec; 609 610 wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL); 611 if (wm8523 == NULL) 612 return -ENOMEM; 613 614 codec = &wm8523->codec; 615 codec->hw_write = (hw_write_t)i2c_master_send; 616 617 i2c_set_clientdata(i2c, wm8523); 618 codec->control_data = i2c; 619 620 codec->dev = &i2c->dev; 621 622 return wm8523_register(wm8523, SND_SOC_I2C); 623 } 624 625 static __devexit int wm8523_i2c_remove(struct i2c_client *client) 626 { 627 struct wm8523_priv *wm8523 = i2c_get_clientdata(client); 628 wm8523_unregister(wm8523); 629 return 0; 630 } 631 632 static const struct i2c_device_id wm8523_i2c_id[] = { 633 { "wm8523", 0 }, 634 { } 635 }; 636 MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id); 637 638 static struct i2c_driver wm8523_i2c_driver = { 639 .driver = { 640 .name = "WM8523", 641 .owner = THIS_MODULE, 642 }, 643 .probe = wm8523_i2c_probe, 644 .remove = __devexit_p(wm8523_i2c_remove), 645 .id_table = wm8523_i2c_id, 646 }; 647 #endif 648 649 static int __init wm8523_modinit(void) 650 { 651 int ret; 652 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 653 ret = i2c_add_driver(&wm8523_i2c_driver); 654 if (ret != 0) { 655 printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n", 656 ret); 657 } 658 #endif 659 return 0; 660 } 661 module_init(wm8523_modinit); 662 663 static void __exit wm8523_exit(void) 664 { 665 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 666 i2c_del_driver(&wm8523_i2c_driver); 667 #endif 668 } 669 module_exit(wm8523_exit); 670 671 MODULE_DESCRIPTION("ASoC WM8523 driver"); 672 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 673 MODULE_LICENSE("GPL"); 674