1/* 2 * wm8741.c -- WM8741 ALSA SoC Audio driver 3 * 4 * Copyright 2010 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/platform_device.h> 21#include <linux/regulator/consumer.h> 22#include <linux/slab.h> 23#include <sound/core.h> 24#include <sound/pcm.h> 25#include <sound/pcm_params.h> 26#include <sound/soc.h> 27#include <sound/soc-dapm.h> 28#include <sound/initval.h> 29#include <sound/tlv.h> 30 31#include "wm8741.h" 32 33static struct snd_soc_codec *wm8741_codec; 34struct snd_soc_codec_device soc_codec_dev_wm8741; 35 36#define WM8741_NUM_SUPPLIES 2 37static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { 38 "AVDD", 39 "DVDD", 40}; 41 42#define WM8741_NUM_RATES 4 43 44/* codec private data */ 45struct wm8741_priv { 46 struct snd_soc_codec codec; 47 u16 reg_cache[WM8741_REGISTER_COUNT]; 48 struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; 49 unsigned int sysclk; 50 unsigned int rate_constraint_list[WM8741_NUM_RATES]; 51 struct snd_pcm_hw_constraint_list rate_constraint; 52}; 53 54static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = { 55 0x0000, /* R0 - DACLLSB Attenuation */ 56 0x0000, /* R1 - DACLMSB Attenuation */ 57 0x0000, /* R2 - DACRLSB Attenuation */ 58 0x0000, /* R3 - DACRMSB Attenuation */ 59 0x0000, /* R4 - Volume Control */ 60 0x000A, /* R5 - Format Control */ 61 0x0000, /* R6 - Filter Control */ 62 0x0000, /* R7 - Mode Control 1 */ 63 0x0002, /* R8 - Mode Control 2 */ 64 0x0000, /* R9 - Reset */ 65 0x0002, /* R32 - ADDITONAL_CONTROL_1 */ 66}; 67 68 69static int wm8741_reset(struct snd_soc_codec *codec) 70{ 71 return snd_soc_write(codec, WM8741_RESET, 0); 72} 73 74static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0); 75static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0); 76 77static const struct snd_kcontrol_new wm8741_snd_controls[] = { 78SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, 79 WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine), 80SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, 81 WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv), 82}; 83 84static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = { 85SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0), 86SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0), 87SND_SOC_DAPM_OUTPUT("VOUTLP"), 88SND_SOC_DAPM_OUTPUT("VOUTLN"), 89SND_SOC_DAPM_OUTPUT("VOUTRP"), 90SND_SOC_DAPM_OUTPUT("VOUTRN"), 91}; 92 93static const struct snd_soc_dapm_route intercon[] = { 94 { "VOUTLP", NULL, "DACL" }, 95 { "VOUTLN", NULL, "DACL" }, 96 { "VOUTRP", NULL, "DACR" }, 97 { "VOUTRN", NULL, "DACR" }, 98}; 99 100static int wm8741_add_widgets(struct snd_soc_codec *codec) 101{ 102 snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets, 103 ARRAY_SIZE(wm8741_dapm_widgets)); 104 105 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); 106 107 return 0; 108} 109 110static struct { 111 int value; 112 int ratio; 113} lrclk_ratios[WM8741_NUM_RATES] = { 114 { 1, 256 }, 115 { 2, 384 }, 116 { 3, 512 }, 117 { 4, 768 }, 118}; 119 120 121static int wm8741_startup(struct snd_pcm_substream *substream, 122 struct snd_soc_dai *dai) 123{ 124 struct snd_soc_codec *codec = dai->codec; 125 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 126 127 /* The set of sample rates that can be supported depends on the 128 * MCLK supplied to the CODEC - enforce this. 129 */ 130 if (!wm8741->sysclk) { 131 dev_err(codec->dev, 132 "No MCLK configured, call set_sysclk() on init\n"); 133 return -EINVAL; 134 } 135 136 snd_pcm_hw_constraint_list(substream->runtime, 0, 137 SNDRV_PCM_HW_PARAM_RATE, 138 &wm8741->rate_constraint); 139 140 return 0; 141} 142 143static int wm8741_hw_params(struct snd_pcm_substream *substream, 144 struct snd_pcm_hw_params *params, 145 struct snd_soc_dai *dai) 146{ 147 struct snd_soc_pcm_runtime *rtd = substream->private_data; 148 struct snd_soc_device *socdev = rtd->socdev; 149 struct snd_soc_codec *codec = socdev->card->codec; 150 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 151 u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC; 152 int i; 153 154 /* Find a supported LRCLK ratio */ 155 for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { 156 if (wm8741->sysclk / params_rate(params) == 157 lrclk_ratios[i].ratio) 158 break; 159 } 160 161 /* Should never happen, should be handled by constraints */ 162 if (i == ARRAY_SIZE(lrclk_ratios)) { 163 dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n", 164 wm8741->sysclk / params_rate(params)); 165 return -EINVAL; 166 } 167 168 /* bit size */ 169 switch (params_format(params)) { 170 case SNDRV_PCM_FORMAT_S16_LE: 171 break; 172 case SNDRV_PCM_FORMAT_S20_3LE: 173 iface |= 0x0001; 174 break; 175 case SNDRV_PCM_FORMAT_S24_LE: 176 iface |= 0x0002; 177 break; 178 case SNDRV_PCM_FORMAT_S32_LE: 179 iface |= 0x0003; 180 break; 181 default: 182 dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d", 183 params_format(params)); 184 return -EINVAL; 185 } 186 187 dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d", 188 params_format(params)); 189 190 snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); 191 return 0; 192} 193 194static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai, 195 int clk_id, unsigned int freq, int dir) 196{ 197 struct snd_soc_codec *codec = codec_dai->codec; 198 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 199 unsigned int val; 200 int i; 201 202 dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq); 203 204 wm8741->sysclk = freq; 205 206 wm8741->rate_constraint.count = 0; 207 208 for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { 209 dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d", 210 i, lrclk_ratios[i].ratio, freq); 211 212 val = freq / lrclk_ratios[i].ratio; 213 /* Check that it's a standard rate since core can't 214 * cope with others and having the odd rates confuses 215 * constraint matching. 216 */ 217 switch (val) { 218 case 32000: 219 case 44100: 220 case 48000: 221 case 64000: 222 case 88200: 223 case 96000: 224 dev_dbg(codec->dev, "Supported sample rate: %dHz\n", 225 val); 226 wm8741->rate_constraint_list[i] = val; 227 wm8741->rate_constraint.count++; 228 break; 229 default: 230 dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", 231 val); 232 } 233 } 234 235 /* Need at least one supported rate... */ 236 if (wm8741->rate_constraint.count == 0) 237 return -EINVAL; 238 239 return 0; 240} 241 242static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, 243 unsigned int fmt) 244{ 245 struct snd_soc_codec *codec = codec_dai->codec; 246 u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3; 247 248 /* check master/slave audio interface */ 249 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 250 case SND_SOC_DAIFMT_CBS_CFS: 251 break; 252 default: 253 return -EINVAL; 254 } 255 256 /* interface format */ 257 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 258 case SND_SOC_DAIFMT_I2S: 259 iface |= 0x0008; 260 break; 261 case SND_SOC_DAIFMT_RIGHT_J: 262 break; 263 case SND_SOC_DAIFMT_LEFT_J: 264 iface |= 0x0004; 265 break; 266 case SND_SOC_DAIFMT_DSP_A: 267 iface |= 0x0003; 268 break; 269 case SND_SOC_DAIFMT_DSP_B: 270 iface |= 0x0013; 271 break; 272 default: 273 return -EINVAL; 274 } 275 276 /* clock inversion */ 277 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 278 case SND_SOC_DAIFMT_NB_NF: 279 break; 280 case SND_SOC_DAIFMT_IB_IF: 281 iface |= 0x0010; 282 break; 283 case SND_SOC_DAIFMT_IB_NF: 284 iface |= 0x0020; 285 break; 286 case SND_SOC_DAIFMT_NB_IF: 287 iface |= 0x0030; 288 break; 289 default: 290 return -EINVAL; 291 } 292 293 294 dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n", 295 fmt & SND_SOC_DAIFMT_FORMAT_MASK, 296 ((fmt & SND_SOC_DAIFMT_INV_MASK))); 297 298 snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); 299 return 0; 300} 301 302#define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 303 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ 304 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ 305 SNDRV_PCM_RATE_192000) 306 307#define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 308 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 309 310static struct snd_soc_dai_ops wm8741_dai_ops = { 311 .startup = wm8741_startup, 312 .hw_params = wm8741_hw_params, 313 .set_sysclk = wm8741_set_dai_sysclk, 314 .set_fmt = wm8741_set_dai_fmt, 315}; 316 317struct snd_soc_dai wm8741_dai = { 318 .name = "WM8741", 319 .playback = { 320 .stream_name = "Playback", 321 .channels_min = 2, /* Mono modes not yet supported */ 322 .channels_max = 2, 323 .rates = WM8741_RATES, 324 .formats = WM8741_FORMATS, 325 }, 326 .ops = &wm8741_dai_ops, 327}; 328EXPORT_SYMBOL_GPL(wm8741_dai); 329 330#ifdef CONFIG_PM 331static int wm8741_resume(struct platform_device *pdev) 332{ 333 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 334 struct snd_soc_codec *codec = socdev->card->codec; 335 u16 *cache = codec->reg_cache; 336 int i; 337 338 /* RESTORE REG Cache */ 339 for (i = 0; i < WM8741_REGISTER_COUNT; i++) { 340 if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i) 341 continue; 342 snd_soc_write(codec, i, cache[i]); 343 } 344 return 0; 345} 346#else 347#define wm8741_suspend NULL 348#define wm8741_resume NULL 349#endif 350 351static int wm8741_probe(struct platform_device *pdev) 352{ 353 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 354 struct snd_soc_codec *codec; 355 int ret = 0; 356 357 if (wm8741_codec == NULL) { 358 dev_err(&pdev->dev, "Codec device not registered\n"); 359 return -ENODEV; 360 } 361 362 socdev->card->codec = wm8741_codec; 363 codec = wm8741_codec; 364 365 /* register pcms */ 366 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 367 if (ret < 0) { 368 dev_err(codec->dev, "failed to create pcms: %d\n", ret); 369 goto pcm_err; 370 } 371 372 snd_soc_add_controls(codec, wm8741_snd_controls, 373 ARRAY_SIZE(wm8741_snd_controls)); 374 wm8741_add_widgets(codec); 375 376 return ret; 377 378pcm_err: 379 return ret; 380} 381 382static int wm8741_remove(struct platform_device *pdev) 383{ 384 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 385 386 snd_soc_free_pcms(socdev); 387 snd_soc_dapm_free(socdev); 388 389 return 0; 390} 391 392struct snd_soc_codec_device soc_codec_dev_wm8741 = { 393 .probe = wm8741_probe, 394 .remove = wm8741_remove, 395 .resume = wm8741_resume, 396}; 397EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741); 398 399static int wm8741_register(struct wm8741_priv *wm8741, 400 enum snd_soc_control_type control) 401{ 402 int ret; 403 struct snd_soc_codec *codec = &wm8741->codec; 404 int i; 405 406 if (wm8741_codec) { 407 dev_err(codec->dev, "Another WM8741 is registered\n"); 408 return -EINVAL; 409 } 410 411 mutex_init(&codec->mutex); 412 INIT_LIST_HEAD(&codec->dapm_widgets); 413 INIT_LIST_HEAD(&codec->dapm_paths); 414 415 snd_soc_codec_set_drvdata(codec, wm8741); 416 codec->name = "WM8741"; 417 codec->owner = THIS_MODULE; 418 codec->bias_level = SND_SOC_BIAS_OFF; 419 codec->set_bias_level = NULL; 420 codec->dai = &wm8741_dai; 421 codec->num_dai = 1; 422 codec->reg_cache_size = WM8741_REGISTER_COUNT; 423 codec->reg_cache = &wm8741->reg_cache; 424 425 wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0]; 426 wm8741->rate_constraint.count = 427 ARRAY_SIZE(wm8741->rate_constraint_list); 428 429 memcpy(codec->reg_cache, wm8741_reg_defaults, 430 sizeof(wm8741->reg_cache)); 431 432 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); 433 if (ret != 0) { 434 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 435 goto err; 436 } 437 438 for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) 439 wm8741->supplies[i].supply = wm8741_supply_names[i]; 440 441 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies), 442 wm8741->supplies); 443 if (ret != 0) { 444 dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 445 goto err; 446 } 447 448 ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), 449 wm8741->supplies); 450 if (ret != 0) { 451 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 452 goto err_get; 453 } 454 455 ret = wm8741_reset(codec); 456 if (ret < 0) { 457 dev_err(codec->dev, "Failed to issue reset\n"); 458 goto err_enable; 459 } 460 461 wm8741_dai.dev = codec->dev; 462 463 /* Change some default settings - latch VU */ 464 wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL; 465 wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM; 466 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL; 467 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM; 468 469 wm8741_codec = codec; 470 471 ret = snd_soc_register_codec(codec); 472 if (ret != 0) { 473 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 474 return ret; 475 } 476 477 ret = snd_soc_register_dai(&wm8741_dai); 478 if (ret != 0) { 479 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 480 snd_soc_unregister_codec(codec); 481 return ret; 482 } 483 484 dev_dbg(codec->dev, "Successful registration\n"); 485 return 0; 486 487err_enable: 488 regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); 489 490err_get: 491 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); 492 493err: 494 kfree(wm8741); 495 return ret; 496} 497 498static void wm8741_unregister(struct wm8741_priv *wm8741) 499{ 500 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); 501 502 snd_soc_unregister_dai(&wm8741_dai); 503 snd_soc_unregister_codec(&wm8741->codec); 504 kfree(wm8741); 505 wm8741_codec = NULL; 506} 507 508#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 509static __devinit int wm8741_i2c_probe(struct i2c_client *i2c, 510 const struct i2c_device_id *id) 511{ 512 struct wm8741_priv *wm8741; 513 struct snd_soc_codec *codec; 514 515 wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL); 516 if (wm8741 == NULL) 517 return -ENOMEM; 518 519 codec = &wm8741->codec; 520 codec->hw_write = (hw_write_t)i2c_master_send; 521 522 i2c_set_clientdata(i2c, wm8741); 523 codec->control_data = i2c; 524 525 codec->dev = &i2c->dev; 526 527 return wm8741_register(wm8741, SND_SOC_I2C); 528} 529 530static __devexit int wm8741_i2c_remove(struct i2c_client *client) 531{ 532 struct wm8741_priv *wm8741 = i2c_get_clientdata(client); 533 wm8741_unregister(wm8741); 534 return 0; 535} 536 537static const struct i2c_device_id wm8741_i2c_id[] = { 538 { "wm8741", 0 }, 539 { } 540}; 541MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); 542 543 544static struct i2c_driver wm8741_i2c_driver = { 545 .driver = { 546 .name = "WM8741", 547 .owner = THIS_MODULE, 548 }, 549 .probe = wm8741_i2c_probe, 550 .remove = __devexit_p(wm8741_i2c_remove), 551 .id_table = wm8741_i2c_id, 552}; 553#endif 554 555static int __init wm8741_modinit(void) 556{ 557 int ret; 558#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 559 ret = i2c_add_driver(&wm8741_i2c_driver); 560 if (ret != 0) { 561 printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n", 562 ret); 563 } 564#endif 565 return 0; 566} 567module_init(wm8741_modinit); 568 569static void __exit wm8741_exit(void) 570{ 571#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 572 i2c_del_driver(&wm8741_i2c_driver); 573#endif 574} 575module_exit(wm8741_exit); 576 577MODULE_DESCRIPTION("ASoC WM8741 driver"); 578MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>"); 579MODULE_LICENSE("GPL"); 580