1 /* 2 * wm8741.c -- WM8741 ALSA SoC Audio driver 3 * 4 * Copyright 2010-1 Wolfson Microelectronics plc 5 * 6 * Author: Ian Lartey <ian@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/spi/spi.h> 21 #include <linux/regmap.h> 22 #include <linux/regulator/consumer.h> 23 #include <linux/slab.h> 24 #include <linux/of_device.h> 25 #include <sound/core.h> 26 #include <sound/pcm.h> 27 #include <sound/pcm_params.h> 28 #include <sound/soc.h> 29 #include <sound/initval.h> 30 #include <sound/tlv.h> 31 32 #include "wm8741.h" 33 34 #define WM8741_NUM_SUPPLIES 2 35 static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { 36 "AVDD", 37 "DVDD", 38 }; 39 40 /* codec private data */ 41 struct wm8741_priv { 42 struct wm8741_platform_data pdata; 43 struct regmap *regmap; 44 struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; 45 unsigned int sysclk; 46 const struct snd_pcm_hw_constraint_list *sysclk_constraints; 47 }; 48 49 static const struct reg_default wm8741_reg_defaults[] = { 50 { 0, 0x0000 }, /* R0 - DACLLSB Attenuation */ 51 { 1, 0x0000 }, /* R1 - DACLMSB Attenuation */ 52 { 2, 0x0000 }, /* R2 - DACRLSB Attenuation */ 53 { 3, 0x0000 }, /* R3 - DACRMSB Attenuation */ 54 { 4, 0x0000 }, /* R4 - Volume Control */ 55 { 5, 0x000A }, /* R5 - Format Control */ 56 { 6, 0x0000 }, /* R6 - Filter Control */ 57 { 7, 0x0000 }, /* R7 - Mode Control 1 */ 58 { 8, 0x0002 }, /* R8 - Mode Control 2 */ 59 { 32, 0x0002 }, /* R32 - ADDITONAL_CONTROL_1 */ 60 }; 61 62 static int wm8741_reset(struct snd_soc_codec *codec) 63 { 64 return snd_soc_write(codec, WM8741_RESET, 0); 65 } 66 67 static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0); 68 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0); 69 70 static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = { 71 SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, 72 WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine), 73 SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, 74 WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv), 75 }; 76 77 static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = { 78 SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, 79 1, 255, 1, dac_tlv_fine), 80 SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, 81 0, 511, 1, dac_tlv), 82 }; 83 84 static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = { 85 SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION, 86 1, 255, 1, dac_tlv_fine), 87 SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION, 88 0, 511, 1, dac_tlv), 89 }; 90 91 static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = { 92 SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0), 93 SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0), 94 SND_SOC_DAPM_OUTPUT("VOUTLP"), 95 SND_SOC_DAPM_OUTPUT("VOUTLN"), 96 SND_SOC_DAPM_OUTPUT("VOUTRP"), 97 SND_SOC_DAPM_OUTPUT("VOUTRN"), 98 }; 99 100 static const struct snd_soc_dapm_route wm8741_dapm_routes[] = { 101 { "VOUTLP", NULL, "DACL" }, 102 { "VOUTLN", NULL, "DACL" }, 103 { "VOUTRP", NULL, "DACR" }, 104 { "VOUTRN", NULL, "DACR" }, 105 }; 106 107 static const unsigned int rates_11289[] = { 108 44100, 88200, 109 }; 110 111 static const struct snd_pcm_hw_constraint_list constraints_11289 = { 112 .count = ARRAY_SIZE(rates_11289), 113 .list = rates_11289, 114 }; 115 116 static const unsigned int rates_12288[] = { 117 32000, 48000, 96000, 118 }; 119 120 static const struct snd_pcm_hw_constraint_list constraints_12288 = { 121 .count = ARRAY_SIZE(rates_12288), 122 .list = rates_12288, 123 }; 124 125 static const unsigned int rates_16384[] = { 126 32000, 127 }; 128 129 static const struct snd_pcm_hw_constraint_list constraints_16384 = { 130 .count = ARRAY_SIZE(rates_16384), 131 .list = rates_16384, 132 }; 133 134 static const unsigned int rates_16934[] = { 135 44100, 88200, 136 }; 137 138 static const struct snd_pcm_hw_constraint_list constraints_16934 = { 139 .count = ARRAY_SIZE(rates_16934), 140 .list = rates_16934, 141 }; 142 143 static const unsigned int rates_18432[] = { 144 48000, 96000, 145 }; 146 147 static const struct snd_pcm_hw_constraint_list constraints_18432 = { 148 .count = ARRAY_SIZE(rates_18432), 149 .list = rates_18432, 150 }; 151 152 static const unsigned int rates_22579[] = { 153 44100, 88200, 176400 154 }; 155 156 static const struct snd_pcm_hw_constraint_list constraints_22579 = { 157 .count = ARRAY_SIZE(rates_22579), 158 .list = rates_22579, 159 }; 160 161 static const unsigned int rates_24576[] = { 162 32000, 48000, 96000, 192000 163 }; 164 165 static const struct snd_pcm_hw_constraint_list constraints_24576 = { 166 .count = ARRAY_SIZE(rates_24576), 167 .list = rates_24576, 168 }; 169 170 static const unsigned int rates_36864[] = { 171 48000, 96000, 192000 172 }; 173 174 static const struct snd_pcm_hw_constraint_list constraints_36864 = { 175 .count = ARRAY_SIZE(rates_36864), 176 .list = rates_36864, 177 }; 178 179 static int wm8741_startup(struct snd_pcm_substream *substream, 180 struct snd_soc_dai *dai) 181 { 182 struct snd_soc_codec *codec = dai->codec; 183 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 184 185 if (wm8741->sysclk) 186 snd_pcm_hw_constraint_list(substream->runtime, 0, 187 SNDRV_PCM_HW_PARAM_RATE, 188 wm8741->sysclk_constraints); 189 190 return 0; 191 } 192 193 static int wm8741_hw_params(struct snd_pcm_substream *substream, 194 struct snd_pcm_hw_params *params, 195 struct snd_soc_dai *dai) 196 { 197 struct snd_soc_codec *codec = dai->codec; 198 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 199 unsigned int iface; 200 int i; 201 202 /* The set of sample rates that can be supported depends on the 203 * MCLK supplied to the CODEC - enforce this. 204 */ 205 if (!wm8741->sysclk) { 206 dev_err(codec->dev, 207 "No MCLK configured, call set_sysclk() on init or in hw_params\n"); 208 return -EINVAL; 209 } 210 211 /* Find a supported LRCLK rate */ 212 for (i = 0; i < wm8741->sysclk_constraints->count; i++) { 213 if (wm8741->sysclk_constraints->list[i] == params_rate(params)) 214 break; 215 } 216 217 if (i == wm8741->sysclk_constraints->count) { 218 dev_err(codec->dev, "LRCLK %d unsupported with MCLK %d\n", 219 params_rate(params), wm8741->sysclk); 220 return -EINVAL; 221 } 222 223 /* bit size */ 224 switch (params_width(params)) { 225 case 16: 226 iface = 0x0; 227 break; 228 case 20: 229 iface = 0x1; 230 break; 231 case 24: 232 iface = 0x2; 233 break; 234 case 32: 235 iface = 0x3; 236 break; 237 default: 238 dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d", 239 params_width(params)); 240 return -EINVAL; 241 } 242 243 dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d, rate param = %d", 244 params_width(params), params_rate(params)); 245 246 snd_soc_update_bits(codec, WM8741_FORMAT_CONTROL, WM8741_IWL_MASK, 247 iface); 248 249 return 0; 250 } 251 252 static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai, 253 int clk_id, unsigned int freq, int dir) 254 { 255 struct snd_soc_codec *codec = codec_dai->codec; 256 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 257 258 dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq); 259 260 switch (freq) { 261 case 0: 262 wm8741->sysclk_constraints = NULL; 263 break; 264 case 11289600: 265 wm8741->sysclk_constraints = &constraints_11289; 266 break; 267 case 12288000: 268 wm8741->sysclk_constraints = &constraints_12288; 269 break; 270 case 16384000: 271 wm8741->sysclk_constraints = &constraints_16384; 272 break; 273 case 16934400: 274 wm8741->sysclk_constraints = &constraints_16934; 275 break; 276 case 18432000: 277 wm8741->sysclk_constraints = &constraints_18432; 278 break; 279 case 22579200: 280 case 33868800: 281 wm8741->sysclk_constraints = &constraints_22579; 282 break; 283 case 24576000: 284 wm8741->sysclk_constraints = &constraints_24576; 285 break; 286 case 36864000: 287 wm8741->sysclk_constraints = &constraints_36864; 288 break; 289 default: 290 return -EINVAL; 291 } 292 293 wm8741->sysclk = freq; 294 return 0; 295 } 296 297 static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, 298 unsigned int fmt) 299 { 300 struct snd_soc_codec *codec = codec_dai->codec; 301 unsigned int iface; 302 303 /* check master/slave audio interface */ 304 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 305 case SND_SOC_DAIFMT_CBS_CFS: 306 break; 307 default: 308 return -EINVAL; 309 } 310 311 /* interface format */ 312 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 313 case SND_SOC_DAIFMT_I2S: 314 iface = 0x08; 315 break; 316 case SND_SOC_DAIFMT_RIGHT_J: 317 iface = 0x00; 318 break; 319 case SND_SOC_DAIFMT_LEFT_J: 320 iface = 0x04; 321 break; 322 case SND_SOC_DAIFMT_DSP_A: 323 iface = 0x0C; 324 break; 325 case SND_SOC_DAIFMT_DSP_B: 326 iface = 0x1C; 327 break; 328 default: 329 return -EINVAL; 330 } 331 332 /* clock inversion */ 333 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 334 case SND_SOC_DAIFMT_NB_NF: 335 break; 336 case SND_SOC_DAIFMT_NB_IF: 337 iface |= 0x10; 338 break; 339 case SND_SOC_DAIFMT_IB_NF: 340 iface |= 0x20; 341 break; 342 case SND_SOC_DAIFMT_IB_IF: 343 iface |= 0x30; 344 break; 345 default: 346 return -EINVAL; 347 } 348 349 350 dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n", 351 fmt & SND_SOC_DAIFMT_FORMAT_MASK, 352 ((fmt & SND_SOC_DAIFMT_INV_MASK))); 353 354 snd_soc_update_bits(codec, WM8741_FORMAT_CONTROL, 355 WM8741_BCP_MASK | WM8741_LRP_MASK | WM8741_FMT_MASK, 356 iface); 357 358 return 0; 359 } 360 361 #define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 362 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ 363 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ 364 SNDRV_PCM_RATE_192000) 365 366 #define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 367 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 368 369 static const struct snd_soc_dai_ops wm8741_dai_ops = { 370 .startup = wm8741_startup, 371 .hw_params = wm8741_hw_params, 372 .set_sysclk = wm8741_set_dai_sysclk, 373 .set_fmt = wm8741_set_dai_fmt, 374 }; 375 376 static struct snd_soc_dai_driver wm8741_dai = { 377 .name = "wm8741", 378 .playback = { 379 .stream_name = "Playback", 380 .channels_min = 2, 381 .channels_max = 2, 382 .rates = WM8741_RATES, 383 .formats = WM8741_FORMATS, 384 }, 385 .ops = &wm8741_dai_ops, 386 }; 387 388 #ifdef CONFIG_PM 389 static int wm8741_resume(struct snd_soc_codec *codec) 390 { 391 snd_soc_cache_sync(codec); 392 return 0; 393 } 394 #else 395 #define wm8741_resume NULL 396 #endif 397 398 static int wm8741_configure(struct snd_soc_codec *codec) 399 { 400 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 401 402 /* Configure differential mode */ 403 switch (wm8741->pdata.diff_mode) { 404 case WM8741_DIFF_MODE_STEREO: 405 case WM8741_DIFF_MODE_STEREO_REVERSED: 406 case WM8741_DIFF_MODE_MONO_LEFT: 407 case WM8741_DIFF_MODE_MONO_RIGHT: 408 snd_soc_update_bits(codec, WM8741_MODE_CONTROL_2, 409 WM8741_DIFF_MASK, 410 wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT); 411 break; 412 default: 413 return -EINVAL; 414 } 415 416 /* Change some default settings - latch VU */ 417 snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION, 418 WM8741_UPDATELL, WM8741_UPDATELL); 419 snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION, 420 WM8741_UPDATELM, WM8741_UPDATELM); 421 snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION, 422 WM8741_UPDATERL, WM8741_UPDATERL); 423 snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION, 424 WM8741_UPDATERM, WM8741_UPDATERM); 425 426 return 0; 427 } 428 429 static int wm8741_add_controls(struct snd_soc_codec *codec) 430 { 431 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 432 433 switch (wm8741->pdata.diff_mode) { 434 case WM8741_DIFF_MODE_STEREO: 435 case WM8741_DIFF_MODE_STEREO_REVERSED: 436 snd_soc_add_codec_controls(codec, 437 wm8741_snd_controls_stereo, 438 ARRAY_SIZE(wm8741_snd_controls_stereo)); 439 break; 440 case WM8741_DIFF_MODE_MONO_LEFT: 441 snd_soc_add_codec_controls(codec, 442 wm8741_snd_controls_mono_left, 443 ARRAY_SIZE(wm8741_snd_controls_mono_left)); 444 break; 445 case WM8741_DIFF_MODE_MONO_RIGHT: 446 snd_soc_add_codec_controls(codec, 447 wm8741_snd_controls_mono_right, 448 ARRAY_SIZE(wm8741_snd_controls_mono_right)); 449 break; 450 default: 451 return -EINVAL; 452 } 453 454 return 0; 455 } 456 457 static int wm8741_probe(struct snd_soc_codec *codec) 458 { 459 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 460 int ret = 0; 461 462 ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), 463 wm8741->supplies); 464 if (ret != 0) { 465 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 466 goto err_get; 467 } 468 469 ret = wm8741_reset(codec); 470 if (ret < 0) { 471 dev_err(codec->dev, "Failed to issue reset\n"); 472 goto err_enable; 473 } 474 475 ret = wm8741_configure(codec); 476 if (ret < 0) { 477 dev_err(codec->dev, "Failed to change default settings\n"); 478 goto err_enable; 479 } 480 481 ret = wm8741_add_controls(codec); 482 if (ret < 0) { 483 dev_err(codec->dev, "Failed to add controls\n"); 484 goto err_enable; 485 } 486 487 dev_dbg(codec->dev, "Successful registration\n"); 488 return ret; 489 490 err_enable: 491 regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); 492 err_get: 493 return ret; 494 } 495 496 static int wm8741_remove(struct snd_soc_codec *codec) 497 { 498 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 499 500 regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); 501 502 return 0; 503 } 504 505 static const struct snd_soc_codec_driver soc_codec_dev_wm8741 = { 506 .probe = wm8741_probe, 507 .remove = wm8741_remove, 508 .resume = wm8741_resume, 509 510 .component_driver = { 511 .dapm_widgets = wm8741_dapm_widgets, 512 .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets), 513 .dapm_routes = wm8741_dapm_routes, 514 .num_dapm_routes = ARRAY_SIZE(wm8741_dapm_routes), 515 }, 516 }; 517 518 static const struct of_device_id wm8741_of_match[] = { 519 { .compatible = "wlf,wm8741", }, 520 { } 521 }; 522 MODULE_DEVICE_TABLE(of, wm8741_of_match); 523 524 static const struct regmap_config wm8741_regmap = { 525 .reg_bits = 7, 526 .val_bits = 9, 527 .max_register = WM8741_MAX_REGISTER, 528 529 .reg_defaults = wm8741_reg_defaults, 530 .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults), 531 .cache_type = REGCACHE_RBTREE, 532 }; 533 534 static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) 535 { 536 const struct wm8741_platform_data *pdata = dev_get_platdata(dev); 537 u32 diff_mode; 538 539 if (dev->of_node) { 540 if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode) 541 >= 0) 542 wm8741->pdata.diff_mode = diff_mode; 543 } else { 544 if (pdata != NULL) 545 memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata)); 546 } 547 548 return 0; 549 } 550 551 #if IS_ENABLED(CONFIG_I2C) 552 static int wm8741_i2c_probe(struct i2c_client *i2c, 553 const struct i2c_device_id *id) 554 { 555 struct wm8741_priv *wm8741; 556 int ret, i; 557 558 wm8741 = devm_kzalloc(&i2c->dev, sizeof(struct wm8741_priv), 559 GFP_KERNEL); 560 if (wm8741 == NULL) 561 return -ENOMEM; 562 563 for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) 564 wm8741->supplies[i].supply = wm8741_supply_names[i]; 565 566 ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies), 567 wm8741->supplies); 568 if (ret != 0) { 569 dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); 570 return ret; 571 } 572 573 wm8741->regmap = devm_regmap_init_i2c(i2c, &wm8741_regmap); 574 if (IS_ERR(wm8741->regmap)) { 575 ret = PTR_ERR(wm8741->regmap); 576 dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); 577 return ret; 578 } 579 580 ret = wm8741_set_pdata(&i2c->dev, wm8741); 581 if (ret != 0) { 582 dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret); 583 return ret; 584 } 585 586 i2c_set_clientdata(i2c, wm8741); 587 588 ret = snd_soc_register_codec(&i2c->dev, 589 &soc_codec_dev_wm8741, &wm8741_dai, 1); 590 591 return ret; 592 } 593 594 static int wm8741_i2c_remove(struct i2c_client *client) 595 { 596 snd_soc_unregister_codec(&client->dev); 597 return 0; 598 } 599 600 static const struct i2c_device_id wm8741_i2c_id[] = { 601 { "wm8741", 0 }, 602 { } 603 }; 604 MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); 605 606 static struct i2c_driver wm8741_i2c_driver = { 607 .driver = { 608 .name = "wm8741", 609 .of_match_table = wm8741_of_match, 610 }, 611 .probe = wm8741_i2c_probe, 612 .remove = wm8741_i2c_remove, 613 .id_table = wm8741_i2c_id, 614 }; 615 #endif 616 617 #if defined(CONFIG_SPI_MASTER) 618 static int wm8741_spi_probe(struct spi_device *spi) 619 { 620 struct wm8741_priv *wm8741; 621 int ret, i; 622 623 wm8741 = devm_kzalloc(&spi->dev, sizeof(struct wm8741_priv), 624 GFP_KERNEL); 625 if (wm8741 == NULL) 626 return -ENOMEM; 627 628 for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) 629 wm8741->supplies[i].supply = wm8741_supply_names[i]; 630 631 ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8741->supplies), 632 wm8741->supplies); 633 if (ret != 0) { 634 dev_err(&spi->dev, "Failed to request supplies: %d\n", ret); 635 return ret; 636 } 637 638 wm8741->regmap = devm_regmap_init_spi(spi, &wm8741_regmap); 639 if (IS_ERR(wm8741->regmap)) { 640 ret = PTR_ERR(wm8741->regmap); 641 dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); 642 return ret; 643 } 644 645 ret = wm8741_set_pdata(&spi->dev, wm8741); 646 if (ret != 0) { 647 dev_err(&spi->dev, "Failed to set pdata: %d\n", ret); 648 return ret; 649 } 650 651 spi_set_drvdata(spi, wm8741); 652 653 ret = snd_soc_register_codec(&spi->dev, 654 &soc_codec_dev_wm8741, &wm8741_dai, 1); 655 return ret; 656 } 657 658 static int wm8741_spi_remove(struct spi_device *spi) 659 { 660 snd_soc_unregister_codec(&spi->dev); 661 return 0; 662 } 663 664 static struct spi_driver wm8741_spi_driver = { 665 .driver = { 666 .name = "wm8741", 667 .of_match_table = wm8741_of_match, 668 }, 669 .probe = wm8741_spi_probe, 670 .remove = wm8741_spi_remove, 671 }; 672 #endif /* CONFIG_SPI_MASTER */ 673 674 static int __init wm8741_modinit(void) 675 { 676 int ret = 0; 677 678 #if IS_ENABLED(CONFIG_I2C) 679 ret = i2c_add_driver(&wm8741_i2c_driver); 680 if (ret != 0) 681 pr_err("Failed to register WM8741 I2C driver: %d\n", ret); 682 #endif 683 #if defined(CONFIG_SPI_MASTER) 684 ret = spi_register_driver(&wm8741_spi_driver); 685 if (ret != 0) { 686 printk(KERN_ERR "Failed to register wm8741 SPI driver: %d\n", 687 ret); 688 } 689 #endif 690 691 return ret; 692 } 693 module_init(wm8741_modinit); 694 695 static void __exit wm8741_exit(void) 696 { 697 #if defined(CONFIG_SPI_MASTER) 698 spi_unregister_driver(&wm8741_spi_driver); 699 #endif 700 #if IS_ENABLED(CONFIG_I2C) 701 i2c_del_driver(&wm8741_i2c_driver); 702 #endif 703 } 704 module_exit(wm8741_exit); 705 706 MODULE_DESCRIPTION("ASoC WM8741 driver"); 707 MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>"); 708 MODULE_LICENSE("GPL"); 709