1 /* 2 * wm8728.c -- WM8728 ALSA SoC Audio driver 3 * 4 * Copyright 2008 Wolfson Microelectronics plc 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/moduleparam.h> 15 #include <linux/init.h> 16 #include <linux/delay.h> 17 #include <linux/pm.h> 18 #include <linux/i2c.h> 19 #include <linux/platform_device.h> 20 #include <linux/spi/spi.h> 21 #include <sound/core.h> 22 #include <sound/pcm.h> 23 #include <sound/pcm_params.h> 24 #include <sound/soc.h> 25 #include <sound/soc-dapm.h> 26 #include <sound/initval.h> 27 #include <sound/tlv.h> 28 29 #include "wm8728.h" 30 31 struct snd_soc_codec_device soc_codec_dev_wm8728; 32 33 /* 34 * We can't read the WM8728 register space so we cache them instead. 35 * Note that the defaults here aren't the physical defaults, we latch 36 * the volume update bits, mute the output and enable infinite zero 37 * detect. 38 */ 39 static const u16 wm8728_reg_defaults[] = { 40 0x1ff, 41 0x1ff, 42 0x001, 43 0x100, 44 }; 45 46 static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, 47 unsigned int reg) 48 { 49 u16 *cache = codec->reg_cache; 50 BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); 51 return cache[reg]; 52 } 53 54 static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, 55 u16 reg, unsigned int value) 56 { 57 u16 *cache = codec->reg_cache; 58 BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); 59 cache[reg] = value; 60 } 61 62 /* 63 * write to the WM8728 register space 64 */ 65 static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg, 66 unsigned int value) 67 { 68 u8 data[2]; 69 70 /* data is 71 * D15..D9 WM8728 register offset 72 * D8...D0 register data 73 */ 74 data[0] = (reg << 1) | ((value >> 8) & 0x0001); 75 data[1] = value & 0x00ff; 76 77 wm8728_write_reg_cache(codec, reg, value); 78 79 if (codec->hw_write(codec->control_data, data, 2) == 2) 80 return 0; 81 else 82 return -EIO; 83 } 84 85 static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); 86 87 static const struct snd_kcontrol_new wm8728_snd_controls[] = { 88 89 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, 90 0, 255, 0, wm8728_tlv), 91 92 SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), 93 }; 94 95 /* 96 * DAPM controls. 97 */ 98 static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = { 99 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), 100 SND_SOC_DAPM_OUTPUT("VOUTL"), 101 SND_SOC_DAPM_OUTPUT("VOUTR"), 102 }; 103 104 static const struct snd_soc_dapm_route intercon[] = { 105 {"VOUTL", NULL, "DAC"}, 106 {"VOUTR", NULL, "DAC"}, 107 }; 108 109 static int wm8728_add_widgets(struct snd_soc_codec *codec) 110 { 111 snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets, 112 ARRAY_SIZE(wm8728_dapm_widgets)); 113 114 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); 115 116 snd_soc_dapm_new_widgets(codec); 117 118 return 0; 119 } 120 121 static int wm8728_mute(struct snd_soc_dai *dai, int mute) 122 { 123 struct snd_soc_codec *codec = dai->codec; 124 u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); 125 126 if (mute) 127 wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); 128 else 129 wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); 130 131 return 0; 132 } 133 134 static int wm8728_hw_params(struct snd_pcm_substream *substream, 135 struct snd_pcm_hw_params *params, 136 struct snd_soc_dai *dai) 137 { 138 struct snd_soc_pcm_runtime *rtd = substream->private_data; 139 struct snd_soc_device *socdev = rtd->socdev; 140 struct snd_soc_codec *codec = socdev->card->codec; 141 u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); 142 143 dac &= ~0x18; 144 145 switch (params_format(params)) { 146 case SNDRV_PCM_FORMAT_S16_LE: 147 break; 148 case SNDRV_PCM_FORMAT_S20_3LE: 149 dac |= 0x10; 150 break; 151 case SNDRV_PCM_FORMAT_S24_LE: 152 dac |= 0x08; 153 break; 154 default: 155 return -EINVAL; 156 } 157 158 wm8728_write(codec, WM8728_DACCTL, dac); 159 160 return 0; 161 } 162 163 static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, 164 unsigned int fmt) 165 { 166 struct snd_soc_codec *codec = codec_dai->codec; 167 u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); 168 169 /* Currently only I2S is supported by the driver, though the 170 * hardware is more flexible. 171 */ 172 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 173 case SND_SOC_DAIFMT_I2S: 174 iface |= 1; 175 break; 176 default: 177 return -EINVAL; 178 } 179 180 /* The hardware only support full slave mode */ 181 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 182 case SND_SOC_DAIFMT_CBS_CFS: 183 break; 184 default: 185 return -EINVAL; 186 } 187 188 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 189 case SND_SOC_DAIFMT_NB_NF: 190 iface &= ~0x22; 191 break; 192 case SND_SOC_DAIFMT_IB_NF: 193 iface |= 0x20; 194 iface &= ~0x02; 195 break; 196 case SND_SOC_DAIFMT_NB_IF: 197 iface |= 0x02; 198 iface &= ~0x20; 199 break; 200 case SND_SOC_DAIFMT_IB_IF: 201 iface |= 0x22; 202 break; 203 default: 204 return -EINVAL; 205 } 206 207 wm8728_write(codec, WM8728_IFCTL, iface); 208 return 0; 209 } 210 211 static int wm8728_set_bias_level(struct snd_soc_codec *codec, 212 enum snd_soc_bias_level level) 213 { 214 u16 reg; 215 int i; 216 217 switch (level) { 218 case SND_SOC_BIAS_ON: 219 case SND_SOC_BIAS_PREPARE: 220 case SND_SOC_BIAS_STANDBY: 221 if (codec->bias_level == SND_SOC_BIAS_OFF) { 222 /* Power everything up... */ 223 reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); 224 wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); 225 226 /* ..then sync in the register cache. */ 227 for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) 228 wm8728_write(codec, i, 229 wm8728_read_reg_cache(codec, i)); 230 } 231 break; 232 233 case SND_SOC_BIAS_OFF: 234 reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); 235 wm8728_write(codec, WM8728_DACCTL, reg | 0x4); 236 break; 237 } 238 codec->bias_level = level; 239 return 0; 240 } 241 242 #define WM8728_RATES (SNDRV_PCM_RATE_8000_192000) 243 244 #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 245 SNDRV_PCM_FMTBIT_S24_LE) 246 247 static struct snd_soc_dai_ops wm8728_dai_ops = { 248 .hw_params = wm8728_hw_params, 249 .digital_mute = wm8728_mute, 250 .set_fmt = wm8728_set_dai_fmt, 251 }; 252 253 struct snd_soc_dai wm8728_dai = { 254 .name = "WM8728", 255 .playback = { 256 .stream_name = "Playback", 257 .channels_min = 2, 258 .channels_max = 2, 259 .rates = WM8728_RATES, 260 .formats = WM8728_FORMATS, 261 }, 262 .ops = &wm8728_dai_ops, 263 }; 264 EXPORT_SYMBOL_GPL(wm8728_dai); 265 266 static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) 267 { 268 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 269 struct snd_soc_codec *codec = socdev->card->codec; 270 271 wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); 272 273 return 0; 274 } 275 276 static int wm8728_resume(struct platform_device *pdev) 277 { 278 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 279 struct snd_soc_codec *codec = socdev->card->codec; 280 281 wm8728_set_bias_level(codec, codec->suspend_bias_level); 282 283 return 0; 284 } 285 286 /* 287 * initialise the WM8728 driver 288 * register the mixer and dsp interfaces with the kernel 289 */ 290 static int wm8728_init(struct snd_soc_device *socdev) 291 { 292 struct snd_soc_codec *codec = socdev->card->codec; 293 int ret = 0; 294 295 codec->name = "WM8728"; 296 codec->owner = THIS_MODULE; 297 codec->read = wm8728_read_reg_cache; 298 codec->write = wm8728_write; 299 codec->set_bias_level = wm8728_set_bias_level; 300 codec->dai = &wm8728_dai; 301 codec->num_dai = 1; 302 codec->bias_level = SND_SOC_BIAS_OFF; 303 codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults); 304 codec->reg_cache = kmemdup(wm8728_reg_defaults, 305 sizeof(wm8728_reg_defaults), 306 GFP_KERNEL); 307 if (codec->reg_cache == NULL) 308 return -ENOMEM; 309 310 /* register pcms */ 311 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 312 if (ret < 0) { 313 printk(KERN_ERR "wm8728: failed to create pcms\n"); 314 goto pcm_err; 315 } 316 317 /* power on device */ 318 wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 319 320 snd_soc_add_controls(codec, wm8728_snd_controls, 321 ARRAY_SIZE(wm8728_snd_controls)); 322 wm8728_add_widgets(codec); 323 ret = snd_soc_init_card(socdev); 324 if (ret < 0) { 325 printk(KERN_ERR "wm8728: failed to register card\n"); 326 goto card_err; 327 } 328 329 return ret; 330 331 card_err: 332 snd_soc_free_pcms(socdev); 333 snd_soc_dapm_free(socdev); 334 pcm_err: 335 kfree(codec->reg_cache); 336 return ret; 337 } 338 339 static struct snd_soc_device *wm8728_socdev; 340 341 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 342 343 /* 344 * WM8728 2 wire address is determined by GPIO5 345 * state during powerup. 346 * low = 0x1a 347 * high = 0x1b 348 */ 349 350 static int wm8728_i2c_probe(struct i2c_client *i2c, 351 const struct i2c_device_id *id) 352 { 353 struct snd_soc_device *socdev = wm8728_socdev; 354 struct snd_soc_codec *codec = socdev->card->codec; 355 int ret; 356 357 i2c_set_clientdata(i2c, codec); 358 codec->control_data = i2c; 359 360 ret = wm8728_init(socdev); 361 if (ret < 0) 362 pr_err("failed to initialise WM8728\n"); 363 364 return ret; 365 } 366 367 static int wm8728_i2c_remove(struct i2c_client *client) 368 { 369 struct snd_soc_codec *codec = i2c_get_clientdata(client); 370 kfree(codec->reg_cache); 371 return 0; 372 } 373 374 static const struct i2c_device_id wm8728_i2c_id[] = { 375 { "wm8728", 0 }, 376 { } 377 }; 378 MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); 379 380 static struct i2c_driver wm8728_i2c_driver = { 381 .driver = { 382 .name = "WM8728 I2C Codec", 383 .owner = THIS_MODULE, 384 }, 385 .probe = wm8728_i2c_probe, 386 .remove = wm8728_i2c_remove, 387 .id_table = wm8728_i2c_id, 388 }; 389 390 static int wm8728_add_i2c_device(struct platform_device *pdev, 391 const struct wm8728_setup_data *setup) 392 { 393 struct i2c_board_info info; 394 struct i2c_adapter *adapter; 395 struct i2c_client *client; 396 int ret; 397 398 ret = i2c_add_driver(&wm8728_i2c_driver); 399 if (ret != 0) { 400 dev_err(&pdev->dev, "can't add i2c driver\n"); 401 return ret; 402 } 403 404 memset(&info, 0, sizeof(struct i2c_board_info)); 405 info.addr = setup->i2c_address; 406 strlcpy(info.type, "wm8728", I2C_NAME_SIZE); 407 408 adapter = i2c_get_adapter(setup->i2c_bus); 409 if (!adapter) { 410 dev_err(&pdev->dev, "can't get i2c adapter %d\n", 411 setup->i2c_bus); 412 goto err_driver; 413 } 414 415 client = i2c_new_device(adapter, &info); 416 i2c_put_adapter(adapter); 417 if (!client) { 418 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", 419 (unsigned int)info.addr); 420 goto err_driver; 421 } 422 423 return 0; 424 425 err_driver: 426 i2c_del_driver(&wm8728_i2c_driver); 427 return -ENODEV; 428 } 429 #endif 430 431 #if defined(CONFIG_SPI_MASTER) 432 static int __devinit wm8728_spi_probe(struct spi_device *spi) 433 { 434 struct snd_soc_device *socdev = wm8728_socdev; 435 struct snd_soc_codec *codec = socdev->card->codec; 436 int ret; 437 438 codec->control_data = spi; 439 440 ret = wm8728_init(socdev); 441 if (ret < 0) 442 dev_err(&spi->dev, "failed to initialise WM8728\n"); 443 444 return ret; 445 } 446 447 static int __devexit wm8728_spi_remove(struct spi_device *spi) 448 { 449 return 0; 450 } 451 452 static struct spi_driver wm8728_spi_driver = { 453 .driver = { 454 .name = "wm8728", 455 .bus = &spi_bus_type, 456 .owner = THIS_MODULE, 457 }, 458 .probe = wm8728_spi_probe, 459 .remove = __devexit_p(wm8728_spi_remove), 460 }; 461 462 static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) 463 { 464 struct spi_transfer t; 465 struct spi_message m; 466 u8 msg[2]; 467 468 if (len <= 0) 469 return 0; 470 471 msg[0] = data[0]; 472 msg[1] = data[1]; 473 474 spi_message_init(&m); 475 memset(&t, 0, (sizeof t)); 476 477 t.tx_buf = &msg[0]; 478 t.len = len; 479 480 spi_message_add_tail(&t, &m); 481 spi_sync(spi, &m); 482 483 return len; 484 } 485 #endif /* CONFIG_SPI_MASTER */ 486 487 static int wm8728_probe(struct platform_device *pdev) 488 { 489 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 490 struct wm8728_setup_data *setup; 491 struct snd_soc_codec *codec; 492 int ret = 0; 493 494 setup = socdev->codec_data; 495 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 496 if (codec == NULL) 497 return -ENOMEM; 498 499 socdev->card->codec = codec; 500 mutex_init(&codec->mutex); 501 INIT_LIST_HEAD(&codec->dapm_widgets); 502 INIT_LIST_HEAD(&codec->dapm_paths); 503 504 wm8728_socdev = socdev; 505 ret = -ENODEV; 506 507 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 508 if (setup->i2c_address) { 509 codec->hw_write = (hw_write_t)i2c_master_send; 510 ret = wm8728_add_i2c_device(pdev, setup); 511 } 512 #endif 513 #if defined(CONFIG_SPI_MASTER) 514 if (setup->spi) { 515 codec->hw_write = (hw_write_t)wm8728_spi_write; 516 ret = spi_register_driver(&wm8728_spi_driver); 517 if (ret != 0) 518 printk(KERN_ERR "can't add spi driver"); 519 } 520 #endif 521 522 if (ret != 0) 523 kfree(codec); 524 525 return ret; 526 } 527 528 /* power down chip */ 529 static int wm8728_remove(struct platform_device *pdev) 530 { 531 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 532 struct snd_soc_codec *codec = socdev->card->codec; 533 534 if (codec->control_data) 535 wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); 536 537 snd_soc_free_pcms(socdev); 538 snd_soc_dapm_free(socdev); 539 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 540 i2c_unregister_device(codec->control_data); 541 i2c_del_driver(&wm8728_i2c_driver); 542 #endif 543 #if defined(CONFIG_SPI_MASTER) 544 spi_unregister_driver(&wm8728_spi_driver); 545 #endif 546 kfree(codec); 547 548 return 0; 549 } 550 551 struct snd_soc_codec_device soc_codec_dev_wm8728 = { 552 .probe = wm8728_probe, 553 .remove = wm8728_remove, 554 .suspend = wm8728_suspend, 555 .resume = wm8728_resume, 556 }; 557 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); 558 559 static int __init wm8728_modinit(void) 560 { 561 return snd_soc_register_dai(&wm8728_dai); 562 } 563 module_init(wm8728_modinit); 564 565 static void __exit wm8728_exit(void) 566 { 567 snd_soc_unregister_dai(&wm8728_dai); 568 } 569 module_exit(wm8728_exit); 570 571 MODULE_DESCRIPTION("ASoC WM8728 driver"); 572 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 573 MODULE_LICENSE("GPL"); 574