diff options
Diffstat (limited to 'sound/soc/codecs/wm8728.c')
-rw-r--r-- | sound/soc/codecs/wm8728.c | 289 |
1 files changed, 90 insertions, 199 deletions
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 34be2d2b69ef..075f35e4f4cb 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c | |||
@@ -29,8 +29,6 @@ | |||
29 | 29 | ||
30 | #include "wm8728.h" | 30 | #include "wm8728.h" |
31 | 31 | ||
32 | struct snd_soc_codec_device soc_codec_dev_wm8728; | ||
33 | |||
34 | /* | 32 | /* |
35 | * We can't read the WM8728 register space so we cache them instead. | 33 | * We can't read the WM8728 register space so we cache them instead. |
36 | * Note that the defaults here aren't the physical defaults, we latch | 34 | * Note that the defaults here aren't the physical defaults, we latch |
@@ -44,6 +42,11 @@ static const u16 wm8728_reg_defaults[] = { | |||
44 | 0x100, | 42 | 0x100, |
45 | }; | 43 | }; |
46 | 44 | ||
45 | /* codec private data */ | ||
46 | struct wm8728_priv { | ||
47 | enum snd_soc_control_type control_type; | ||
48 | }; | ||
49 | |||
47 | static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); | 50 | static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); |
48 | 51 | ||
49 | static const struct snd_kcontrol_new wm8728_snd_controls[] = { | 52 | static const struct snd_kcontrol_new wm8728_snd_controls[] = { |
@@ -96,8 +99,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream, | |||
96 | struct snd_soc_dai *dai) | 99 | struct snd_soc_dai *dai) |
97 | { | 100 | { |
98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 101 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
99 | struct snd_soc_device *socdev = rtd->socdev; | 102 | struct snd_soc_codec *codec = rtd->codec; |
100 | struct snd_soc_codec *codec = socdev->card->codec; | ||
101 | u16 dac = snd_soc_read(codec, WM8728_DACCTL); | 103 | u16 dac = snd_soc_read(codec, WM8728_DACCTL); |
102 | 104 | ||
103 | dac &= ~0x18; | 105 | dac &= ~0x18; |
@@ -210,8 +212,8 @@ static struct snd_soc_dai_ops wm8728_dai_ops = { | |||
210 | .set_fmt = wm8728_set_dai_fmt, | 212 | .set_fmt = wm8728_set_dai_fmt, |
211 | }; | 213 | }; |
212 | 214 | ||
213 | struct snd_soc_dai wm8728_dai = { | 215 | static struct snd_soc_dai_driver wm8728_dai = { |
214 | .name = "WM8728", | 216 | .name = "wm8728-hifi", |
215 | .playback = { | 217 | .playback = { |
216 | .stream_name = "Playback", | 218 | .stream_name = "Playback", |
217 | .channels_min = 2, | 219 | .channels_min = 2, |
@@ -221,63 +223,31 @@ struct snd_soc_dai wm8728_dai = { | |||
221 | }, | 223 | }, |
222 | .ops = &wm8728_dai_ops, | 224 | .ops = &wm8728_dai_ops, |
223 | }; | 225 | }; |
224 | EXPORT_SYMBOL_GPL(wm8728_dai); | ||
225 | 226 | ||
226 | static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) | 227 | static int wm8728_suspend(struct snd_soc_codec *codec, pm_message_t state) |
227 | { | 228 | { |
228 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
229 | struct snd_soc_codec *codec = socdev->card->codec; | ||
230 | |||
231 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | 229 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); |
232 | 230 | ||
233 | return 0; | 231 | return 0; |
234 | } | 232 | } |
235 | 233 | ||
236 | static int wm8728_resume(struct platform_device *pdev) | 234 | static int wm8728_resume(struct snd_soc_codec *codec) |
237 | { | 235 | { |
238 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
239 | struct snd_soc_codec *codec = socdev->card->codec; | ||
240 | |||
241 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 236 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
242 | 237 | ||
243 | return 0; | 238 | return 0; |
244 | } | 239 | } |
245 | 240 | ||
246 | /* | 241 | static int wm8728_probe(struct snd_soc_codec *codec) |
247 | * initialise the WM8728 driver | ||
248 | * register the mixer and dsp interfaces with the kernel | ||
249 | */ | ||
250 | static int wm8728_init(struct snd_soc_device *socdev, | ||
251 | enum snd_soc_control_type control) | ||
252 | { | 242 | { |
253 | struct snd_soc_codec *codec = socdev->card->codec; | 243 | struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec); |
254 | int ret = 0; | 244 | int ret; |
255 | |||
256 | codec->name = "WM8728"; | ||
257 | codec->owner = THIS_MODULE; | ||
258 | codec->set_bias_level = wm8728_set_bias_level; | ||
259 | codec->dai = &wm8728_dai; | ||
260 | codec->num_dai = 1; | ||
261 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
262 | codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults); | ||
263 | codec->reg_cache = kmemdup(wm8728_reg_defaults, | ||
264 | sizeof(wm8728_reg_defaults), | ||
265 | GFP_KERNEL); | ||
266 | if (codec->reg_cache == NULL) | ||
267 | return -ENOMEM; | ||
268 | 245 | ||
269 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | 246 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8728->control_type); |
270 | if (ret < 0) { | 247 | if (ret < 0) { |
271 | printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", | 248 | printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", |
272 | ret); | 249 | ret); |
273 | goto err; | 250 | return ret; |
274 | } | ||
275 | |||
276 | /* register pcms */ | ||
277 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
278 | if (ret < 0) { | ||
279 | printk(KERN_ERR "wm8728: failed to create pcms\n"); | ||
280 | goto err; | ||
281 | } | 251 | } |
282 | 252 | ||
283 | /* power on device */ | 253 | /* power on device */ |
@@ -288,215 +258,136 @@ static int wm8728_init(struct snd_soc_device *socdev, | |||
288 | wm8728_add_widgets(codec); | 258 | wm8728_add_widgets(codec); |
289 | 259 | ||
290 | return ret; | 260 | return ret; |
291 | |||
292 | err: | ||
293 | kfree(codec->reg_cache); | ||
294 | return ret; | ||
295 | } | 261 | } |
296 | 262 | ||
297 | static struct snd_soc_device *wm8728_socdev; | 263 | static int wm8728_remove(struct snd_soc_codec *codec) |
298 | 264 | { | |
299 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 265 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); |
266 | return 0; | ||
267 | } | ||
300 | 268 | ||
301 | /* | 269 | static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { |
302 | * WM8728 2 wire address is determined by GPIO5 | 270 | .probe = wm8728_probe, |
303 | * state during powerup. | 271 | .remove = wm8728_remove, |
304 | * low = 0x1a | 272 | .suspend = wm8728_suspend, |
305 | * high = 0x1b | 273 | .resume = wm8728_resume, |
306 | */ | 274 | .set_bias_level = wm8728_set_bias_level, |
275 | .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults), | ||
276 | .reg_word_size = sizeof(u16), | ||
277 | .reg_cache_default = wm8728_reg_defaults, | ||
278 | }; | ||
307 | 279 | ||
308 | static int wm8728_i2c_probe(struct i2c_client *i2c, | 280 | #if defined(CONFIG_SPI_MASTER) |
309 | const struct i2c_device_id *id) | 281 | static int __devinit wm8728_spi_probe(struct spi_device *spi) |
310 | { | 282 | { |
311 | struct snd_soc_device *socdev = wm8728_socdev; | 283 | struct wm8728_priv *wm8728; |
312 | struct snd_soc_codec *codec = socdev->card->codec; | ||
313 | int ret; | 284 | int ret; |
314 | 285 | ||
315 | i2c_set_clientdata(i2c, codec); | 286 | wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL); |
316 | codec->control_data = i2c; | 287 | if (wm8728 == NULL) |
288 | return -ENOMEM; | ||
289 | |||
290 | wm8728->control_type = SND_SOC_SPI; | ||
291 | spi_set_drvdata(spi, wm8728); | ||
317 | 292 | ||
318 | ret = wm8728_init(socdev, SND_SOC_I2C); | 293 | ret = snd_soc_register_codec(&spi->dev, |
294 | &soc_codec_dev_wm8728, &wm8728_dai, 1); | ||
319 | if (ret < 0) | 295 | if (ret < 0) |
320 | pr_err("failed to initialise WM8728\n"); | 296 | kfree(wm8728); |
321 | |||
322 | return ret; | 297 | return ret; |
323 | } | 298 | } |
324 | 299 | ||
325 | static int wm8728_i2c_remove(struct i2c_client *client) | 300 | static int __devexit wm8728_spi_remove(struct spi_device *spi) |
326 | { | 301 | { |
327 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 302 | snd_soc_unregister_codec(&spi->dev); |
328 | kfree(codec->reg_cache); | 303 | kfree(spi_get_drvdata(spi)); |
329 | return 0; | 304 | return 0; |
330 | } | 305 | } |
331 | 306 | ||
332 | static const struct i2c_device_id wm8728_i2c_id[] = { | 307 | static struct spi_driver wm8728_spi_driver = { |
333 | { "wm8728", 0 }, | ||
334 | { } | ||
335 | }; | ||
336 | MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); | ||
337 | |||
338 | static struct i2c_driver wm8728_i2c_driver = { | ||
339 | .driver = { | 308 | .driver = { |
340 | .name = "WM8728 I2C Codec", | 309 | .name = "wm8728-codec", |
341 | .owner = THIS_MODULE, | 310 | .owner = THIS_MODULE, |
342 | }, | 311 | }, |
343 | .probe = wm8728_i2c_probe, | 312 | .probe = wm8728_spi_probe, |
344 | .remove = wm8728_i2c_remove, | 313 | .remove = __devexit_p(wm8728_spi_remove), |
345 | .id_table = wm8728_i2c_id, | ||
346 | }; | 314 | }; |
315 | #endif /* CONFIG_SPI_MASTER */ | ||
347 | 316 | ||
348 | static int wm8728_add_i2c_device(struct platform_device *pdev, | 317 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
349 | const struct wm8728_setup_data *setup) | 318 | static __devinit int wm8728_i2c_probe(struct i2c_client *i2c, |
319 | const struct i2c_device_id *id) | ||
350 | { | 320 | { |
351 | struct i2c_board_info info; | 321 | struct wm8728_priv *wm8728; |
352 | struct i2c_adapter *adapter; | ||
353 | struct i2c_client *client; | ||
354 | int ret; | 322 | int ret; |
355 | 323 | ||
356 | ret = i2c_add_driver(&wm8728_i2c_driver); | 324 | wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL); |
357 | if (ret != 0) { | 325 | if (wm8728 == NULL) |
358 | dev_err(&pdev->dev, "can't add i2c driver\n"); | 326 | return -ENOMEM; |
359 | return ret; | ||
360 | } | ||
361 | |||
362 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
363 | info.addr = setup->i2c_address; | ||
364 | strlcpy(info.type, "wm8728", I2C_NAME_SIZE); | ||
365 | |||
366 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
367 | if (!adapter) { | ||
368 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
369 | setup->i2c_bus); | ||
370 | goto err_driver; | ||
371 | } | ||
372 | |||
373 | client = i2c_new_device(adapter, &info); | ||
374 | i2c_put_adapter(adapter); | ||
375 | if (!client) { | ||
376 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
377 | (unsigned int)info.addr); | ||
378 | goto err_driver; | ||
379 | } | ||
380 | |||
381 | return 0; | ||
382 | |||
383 | err_driver: | ||
384 | i2c_del_driver(&wm8728_i2c_driver); | ||
385 | return -ENODEV; | ||
386 | } | ||
387 | #endif | ||
388 | |||
389 | #if defined(CONFIG_SPI_MASTER) | ||
390 | static int __devinit wm8728_spi_probe(struct spi_device *spi) | ||
391 | { | ||
392 | struct snd_soc_device *socdev = wm8728_socdev; | ||
393 | struct snd_soc_codec *codec = socdev->card->codec; | ||
394 | int ret; | ||
395 | 327 | ||
396 | codec->control_data = spi; | 328 | i2c_set_clientdata(i2c, wm8728); |
329 | wm8728->control_type = SND_SOC_I2C; | ||
397 | 330 | ||
398 | ret = wm8728_init(socdev, SND_SOC_SPI); | 331 | ret = snd_soc_register_codec(&i2c->dev, |
332 | &soc_codec_dev_wm8728, &wm8728_dai, 1); | ||
399 | if (ret < 0) | 333 | if (ret < 0) |
400 | dev_err(&spi->dev, "failed to initialise WM8728\n"); | 334 | kfree(wm8728); |
401 | |||
402 | return ret; | 335 | return ret; |
403 | } | 336 | } |
404 | 337 | ||
405 | static int __devexit wm8728_spi_remove(struct spi_device *spi) | 338 | static __devexit int wm8728_i2c_remove(struct i2c_client *client) |
406 | { | 339 | { |
340 | snd_soc_unregister_codec(&client->dev); | ||
341 | kfree(i2c_get_clientdata(client)); | ||
407 | return 0; | 342 | return 0; |
408 | } | 343 | } |
409 | 344 | ||
410 | static struct spi_driver wm8728_spi_driver = { | 345 | static const struct i2c_device_id wm8728_i2c_id[] = { |
346 | { "wm8728", 0 }, | ||
347 | { } | ||
348 | }; | ||
349 | MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); | ||
350 | |||
351 | static struct i2c_driver wm8728_i2c_driver = { | ||
411 | .driver = { | 352 | .driver = { |
412 | .name = "wm8728", | 353 | .name = "wm8728-codec", |
413 | .bus = &spi_bus_type, | 354 | .owner = THIS_MODULE, |
414 | .owner = THIS_MODULE, | ||
415 | }, | 355 | }, |
416 | .probe = wm8728_spi_probe, | 356 | .probe = wm8728_i2c_probe, |
417 | .remove = __devexit_p(wm8728_spi_remove), | 357 | .remove = __devexit_p(wm8728_i2c_remove), |
358 | .id_table = wm8728_i2c_id, | ||
418 | }; | 359 | }; |
419 | #endif /* CONFIG_SPI_MASTER */ | 360 | #endif |
420 | 361 | ||
421 | static int wm8728_probe(struct platform_device *pdev) | 362 | static int __init wm8728_modinit(void) |
422 | { | 363 | { |
423 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
424 | struct wm8728_setup_data *setup; | ||
425 | struct snd_soc_codec *codec; | ||
426 | int ret = 0; | 364 | int ret = 0; |
427 | |||
428 | setup = socdev->codec_data; | ||
429 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
430 | if (codec == NULL) | ||
431 | return -ENOMEM; | ||
432 | |||
433 | socdev->card->codec = codec; | ||
434 | mutex_init(&codec->mutex); | ||
435 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
436 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
437 | |||
438 | wm8728_socdev = socdev; | ||
439 | ret = -ENODEV; | ||
440 | |||
441 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 365 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
442 | if (setup->i2c_address) { | 366 | ret = i2c_add_driver(&wm8728_i2c_driver); |
443 | ret = wm8728_add_i2c_device(pdev, setup); | 367 | if (ret != 0) { |
368 | printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n", | ||
369 | ret); | ||
444 | } | 370 | } |
445 | #endif | 371 | #endif |
446 | #if defined(CONFIG_SPI_MASTER) | 372 | #if defined(CONFIG_SPI_MASTER) |
447 | if (setup->spi) { | 373 | ret = spi_register_driver(&wm8728_spi_driver); |
448 | ret = spi_register_driver(&wm8728_spi_driver); | 374 | if (ret != 0) { |
449 | if (ret != 0) | 375 | printk(KERN_ERR "Failed to register wm8728 SPI driver: %d\n", |
450 | printk(KERN_ERR "can't add spi driver"); | 376 | ret); |
451 | } | 377 | } |
452 | #endif | 378 | #endif |
453 | |||
454 | if (ret != 0) | ||
455 | kfree(codec); | ||
456 | |||
457 | return ret; | 379 | return ret; |
458 | } | 380 | } |
381 | module_init(wm8728_modinit); | ||
459 | 382 | ||
460 | /* power down chip */ | 383 | static void __exit wm8728_exit(void) |
461 | static int wm8728_remove(struct platform_device *pdev) | ||
462 | { | 384 | { |
463 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
464 | struct snd_soc_codec *codec = socdev->card->codec; | ||
465 | |||
466 | if (codec->control_data) | ||
467 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
468 | |||
469 | snd_soc_free_pcms(socdev); | ||
470 | snd_soc_dapm_free(socdev); | ||
471 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 385 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
472 | i2c_unregister_device(codec->control_data); | ||
473 | i2c_del_driver(&wm8728_i2c_driver); | 386 | i2c_del_driver(&wm8728_i2c_driver); |
474 | #endif | 387 | #endif |
475 | #if defined(CONFIG_SPI_MASTER) | 388 | #if defined(CONFIG_SPI_MASTER) |
476 | spi_unregister_driver(&wm8728_spi_driver); | 389 | spi_unregister_driver(&wm8728_spi_driver); |
477 | #endif | 390 | #endif |
478 | kfree(codec); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | struct snd_soc_codec_device soc_codec_dev_wm8728 = { | ||
484 | .probe = wm8728_probe, | ||
485 | .remove = wm8728_remove, | ||
486 | .suspend = wm8728_suspend, | ||
487 | .resume = wm8728_resume, | ||
488 | }; | ||
489 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); | ||
490 | |||
491 | static int __init wm8728_modinit(void) | ||
492 | { | ||
493 | return snd_soc_register_dai(&wm8728_dai); | ||
494 | } | ||
495 | module_init(wm8728_modinit); | ||
496 | |||
497 | static void __exit wm8728_exit(void) | ||
498 | { | ||
499 | snd_soc_unregister_dai(&wm8728_dai); | ||
500 | } | 391 | } |
501 | module_exit(wm8728_exit); | 392 | module_exit(wm8728_exit); |
502 | 393 | ||