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 const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); 47 48 static const struct snd_kcontrol_new wm8728_snd_controls[] = { 49 50 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, 51 0, 255, 0, wm8728_tlv), 52 53 SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), 54 }; 55 56 /* 57 * DAPM controls. 58 */ 59 static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = { 60 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), 61 SND_SOC_DAPM_OUTPUT("VOUTL"), 62 SND_SOC_DAPM_OUTPUT("VOUTR"), 63 }; 64 65 static const struct snd_soc_dapm_route intercon[] = { 66 {"VOUTL", NULL, "DAC"}, 67 {"VOUTR", NULL, "DAC"}, 68 }; 69 70 static int wm8728_add_widgets(struct snd_soc_codec *codec) 71 { 72 snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets, 73 ARRAY_SIZE(wm8728_dapm_widgets)); 74 75 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); 76 77 snd_soc_dapm_new_widgets(codec); 78 79 return 0; 80 } 81 82 static int wm8728_mute(struct snd_soc_dai *dai, int mute) 83 { 84 struct snd_soc_codec *codec = dai->codec; 85 u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL); 86 87 if (mute) 88 snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1); 89 else 90 snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1); 91 92 return 0; 93 } 94 95 static int wm8728_hw_params(struct snd_pcm_substream *substream, 96 struct snd_pcm_hw_params *params, 97 struct snd_soc_dai *dai) 98 { 99 struct snd_soc_pcm_runtime *rtd = substream->private_data; 100 struct snd_soc_device *socdev = rtd->socdev; 101 struct snd_soc_codec *codec = socdev->card->codec; 102 u16 dac = snd_soc_read(codec, WM8728_DACCTL); 103 104 dac &= ~0x18; 105 106 switch (params_format(params)) { 107 case SNDRV_PCM_FORMAT_S16_LE: 108 break; 109 case SNDRV_PCM_FORMAT_S20_3LE: 110 dac |= 0x10; 111 break; 112 case SNDRV_PCM_FORMAT_S24_LE: 113 dac |= 0x08; 114 break; 115 default: 116 return -EINVAL; 117 } 118 119 snd_soc_write(codec, WM8728_DACCTL, dac); 120 121 return 0; 122 } 123 124 static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, 125 unsigned int fmt) 126 { 127 struct snd_soc_codec *codec = codec_dai->codec; 128 u16 iface = snd_soc_read(codec, WM8728_IFCTL); 129 130 /* Currently only I2S is supported by the driver, though the 131 * hardware is more flexible. 132 */ 133 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 134 case SND_SOC_DAIFMT_I2S: 135 iface |= 1; 136 break; 137 default: 138 return -EINVAL; 139 } 140 141 /* The hardware only support full slave mode */ 142 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 143 case SND_SOC_DAIFMT_CBS_CFS: 144 break; 145 default: 146 return -EINVAL; 147 } 148 149 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 150 case SND_SOC_DAIFMT_NB_NF: 151 iface &= ~0x22; 152 break; 153 case SND_SOC_DAIFMT_IB_NF: 154 iface |= 0x20; 155 iface &= ~0x02; 156 break; 157 case SND_SOC_DAIFMT_NB_IF: 158 iface |= 0x02; 159 iface &= ~0x20; 160 break; 161 case SND_SOC_DAIFMT_IB_IF: 162 iface |= 0x22; 163 break; 164 default: 165 return -EINVAL; 166 } 167 168 snd_soc_write(codec, WM8728_IFCTL, iface); 169 return 0; 170 } 171 172 static int wm8728_set_bias_level(struct snd_soc_codec *codec, 173 enum snd_soc_bias_level level) 174 { 175 u16 reg; 176 int i; 177 178 switch (level) { 179 case SND_SOC_BIAS_ON: 180 case SND_SOC_BIAS_PREPARE: 181 case SND_SOC_BIAS_STANDBY: 182 if (codec->bias_level == SND_SOC_BIAS_OFF) { 183 /* Power everything up... */ 184 reg = snd_soc_read(codec, WM8728_DACCTL); 185 snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4); 186 187 /* ..then sync in the register cache. */ 188 for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) 189 snd_soc_write(codec, i, 190 snd_soc_read(codec, i)); 191 } 192 break; 193 194 case SND_SOC_BIAS_OFF: 195 reg = snd_soc_read(codec, WM8728_DACCTL); 196 snd_soc_write(codec, WM8728_DACCTL, reg | 0x4); 197 break; 198 } 199 codec->bias_level = level; 200 return 0; 201 } 202 203 #define WM8728_RATES (SNDRV_PCM_RATE_8000_192000) 204 205 #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 206 SNDRV_PCM_FMTBIT_S24_LE) 207 208 static struct snd_soc_dai_ops wm8728_dai_ops = { 209 .hw_params = wm8728_hw_params, 210 .digital_mute = wm8728_mute, 211 .set_fmt = wm8728_set_dai_fmt, 212 }; 213 214 struct snd_soc_dai wm8728_dai = { 215 .name = "WM8728", 216 .playback = { 217 .stream_name = "Playback", 218 .channels_min = 2, 219 .channels_max = 2, 220 .rates = WM8728_RATES, 221 .formats = WM8728_FORMATS, 222 }, 223 .ops = &wm8728_dai_ops, 224 }; 225 EXPORT_SYMBOL_GPL(wm8728_dai); 226 227 static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) 228 { 229 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 230 struct snd_soc_codec *codec = socdev->card->codec; 231 232 wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); 233 234 return 0; 235 } 236 237 static int wm8728_resume(struct platform_device *pdev) 238 { 239 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 240 struct snd_soc_codec *codec = socdev->card->codec; 241 242 wm8728_set_bias_level(codec, codec->suspend_bias_level); 243 244 return 0; 245 } 246 247 /* 248 * initialise the WM8728 driver 249 * register the mixer and dsp interfaces with the kernel 250 */ 251 static int wm8728_init(struct snd_soc_device *socdev, 252 enum snd_soc_control_type control) 253 { 254 struct snd_soc_codec *codec = socdev->card->codec; 255 int ret = 0; 256 257 codec->name = "WM8728"; 258 codec->owner = THIS_MODULE; 259 codec->set_bias_level = wm8728_set_bias_level; 260 codec->dai = &wm8728_dai; 261 codec->num_dai = 1; 262 codec->bias_level = SND_SOC_BIAS_OFF; 263 codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults); 264 codec->reg_cache = kmemdup(wm8728_reg_defaults, 265 sizeof(wm8728_reg_defaults), 266 GFP_KERNEL); 267 if (codec->reg_cache == NULL) 268 return -ENOMEM; 269 270 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); 271 if (ret < 0) { 272 printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", 273 ret); 274 goto err; 275 } 276 277 /* register pcms */ 278 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 279 if (ret < 0) { 280 printk(KERN_ERR "wm8728: failed to create pcms\n"); 281 goto err; 282 } 283 284 /* power on device */ 285 wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 286 287 snd_soc_add_controls(codec, wm8728_snd_controls, 288 ARRAY_SIZE(wm8728_snd_controls)); 289 wm8728_add_widgets(codec); 290 ret = snd_soc_init_card(socdev); 291 if (ret < 0) { 292 printk(KERN_ERR "wm8728: failed to register card\n"); 293 goto card_err; 294 } 295 296 return ret; 297 298 card_err: 299 snd_soc_free_pcms(socdev); 300 snd_soc_dapm_free(socdev); 301 err: 302 kfree(codec->reg_cache); 303 return ret; 304 } 305 306 static struct snd_soc_device *wm8728_socdev; 307 308 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 309 310 /* 311 * WM8728 2 wire address is determined by GPIO5 312 * state during powerup. 313 * low = 0x1a 314 * high = 0x1b 315 */ 316 317 static int wm8728_i2c_probe(struct i2c_client *i2c, 318 const struct i2c_device_id *id) 319 { 320 struct snd_soc_device *socdev = wm8728_socdev; 321 struct snd_soc_codec *codec = socdev->card->codec; 322 int ret; 323 324 i2c_set_clientdata(i2c, codec); 325 codec->control_data = i2c; 326 327 ret = wm8728_init(socdev, SND_SOC_I2C); 328 if (ret < 0) 329 pr_err("failed to initialise WM8728\n"); 330 331 return ret; 332 } 333 334 static int wm8728_i2c_remove(struct i2c_client *client) 335 { 336 struct snd_soc_codec *codec = i2c_get_clientdata(client); 337 kfree(codec->reg_cache); 338 return 0; 339 } 340 341 static const struct i2c_device_id wm8728_i2c_id[] = { 342 { "wm8728", 0 }, 343 { } 344 }; 345 MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); 346 347 static struct i2c_driver wm8728_i2c_driver = { 348 .driver = { 349 .name = "WM8728 I2C Codec", 350 .owner = THIS_MODULE, 351 }, 352 .probe = wm8728_i2c_probe, 353 .remove = wm8728_i2c_remove, 354 .id_table = wm8728_i2c_id, 355 }; 356 357 static int wm8728_add_i2c_device(struct platform_device *pdev, 358 const struct wm8728_setup_data *setup) 359 { 360 struct i2c_board_info info; 361 struct i2c_adapter *adapter; 362 struct i2c_client *client; 363 int ret; 364 365 ret = i2c_add_driver(&wm8728_i2c_driver); 366 if (ret != 0) { 367 dev_err(&pdev->dev, "can't add i2c driver\n"); 368 return ret; 369 } 370 371 memset(&info, 0, sizeof(struct i2c_board_info)); 372 info.addr = setup->i2c_address; 373 strlcpy(info.type, "wm8728", I2C_NAME_SIZE); 374 375 adapter = i2c_get_adapter(setup->i2c_bus); 376 if (!adapter) { 377 dev_err(&pdev->dev, "can't get i2c adapter %d\n", 378 setup->i2c_bus); 379 goto err_driver; 380 } 381 382 client = i2c_new_device(adapter, &info); 383 i2c_put_adapter(adapter); 384 if (!client) { 385 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", 386 (unsigned int)info.addr); 387 goto err_driver; 388 } 389 390 return 0; 391 392 err_driver: 393 i2c_del_driver(&wm8728_i2c_driver); 394 return -ENODEV; 395 } 396 #endif 397 398 #if defined(CONFIG_SPI_MASTER) 399 static int __devinit wm8728_spi_probe(struct spi_device *spi) 400 { 401 struct snd_soc_device *socdev = wm8728_socdev; 402 struct snd_soc_codec *codec = socdev->card->codec; 403 int ret; 404 405 codec->control_data = spi; 406 407 ret = wm8728_init(socdev, SND_SOC_SPI); 408 if (ret < 0) 409 dev_err(&spi->dev, "failed to initialise WM8728\n"); 410 411 return ret; 412 } 413 414 static int __devexit wm8728_spi_remove(struct spi_device *spi) 415 { 416 return 0; 417 } 418 419 static struct spi_driver wm8728_spi_driver = { 420 .driver = { 421 .name = "wm8728", 422 .bus = &spi_bus_type, 423 .owner = THIS_MODULE, 424 }, 425 .probe = wm8728_spi_probe, 426 .remove = __devexit_p(wm8728_spi_remove), 427 }; 428 #endif /* CONFIG_SPI_MASTER */ 429 430 static int wm8728_probe(struct platform_device *pdev) 431 { 432 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 433 struct wm8728_setup_data *setup; 434 struct snd_soc_codec *codec; 435 int ret = 0; 436 437 setup = socdev->codec_data; 438 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 439 if (codec == NULL) 440 return -ENOMEM; 441 442 socdev->card->codec = codec; 443 mutex_init(&codec->mutex); 444 INIT_LIST_HEAD(&codec->dapm_widgets); 445 INIT_LIST_HEAD(&codec->dapm_paths); 446 447 wm8728_socdev = socdev; 448 ret = -ENODEV; 449 450 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 451 if (setup->i2c_address) { 452 ret = wm8728_add_i2c_device(pdev, setup); 453 } 454 #endif 455 #if defined(CONFIG_SPI_MASTER) 456 if (setup->spi) { 457 ret = spi_register_driver(&wm8728_spi_driver); 458 if (ret != 0) 459 printk(KERN_ERR "can't add spi driver"); 460 } 461 #endif 462 463 if (ret != 0) 464 kfree(codec); 465 466 return ret; 467 } 468 469 /* power down chip */ 470 static int wm8728_remove(struct platform_device *pdev) 471 { 472 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 473 struct snd_soc_codec *codec = socdev->card->codec; 474 475 if (codec->control_data) 476 wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); 477 478 snd_soc_free_pcms(socdev); 479 snd_soc_dapm_free(socdev); 480 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 481 i2c_unregister_device(codec->control_data); 482 i2c_del_driver(&wm8728_i2c_driver); 483 #endif 484 #if defined(CONFIG_SPI_MASTER) 485 spi_unregister_driver(&wm8728_spi_driver); 486 #endif 487 kfree(codec); 488 489 return 0; 490 } 491 492 struct snd_soc_codec_device soc_codec_dev_wm8728 = { 493 .probe = wm8728_probe, 494 .remove = wm8728_remove, 495 .suspend = wm8728_suspend, 496 .resume = wm8728_resume, 497 }; 498 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); 499 500 static int __init wm8728_modinit(void) 501 { 502 return snd_soc_register_dai(&wm8728_dai); 503 } 504 module_init(wm8728_modinit); 505 506 static void __exit wm8728_exit(void) 507 { 508 snd_soc_unregister_dai(&wm8728_dai); 509 } 510 module_exit(wm8728_exit); 511 512 MODULE_DESCRIPTION("ASoC WM8728 driver"); 513 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 514 MODULE_LICENSE("GPL"); 515