diff options
Diffstat (limited to 'sound/soc/codecs/ad193x.c')
-rw-r--r-- | sound/soc/codecs/ad193x.c | 217 |
1 files changed, 77 insertions, 140 deletions
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 1def75e4862f..fa2834c91b9f 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
@@ -24,9 +24,10 @@ | |||
24 | 24 | ||
25 | /* codec private data */ | 25 | /* codec private data */ |
26 | struct ad193x_priv { | 26 | struct ad193x_priv { |
27 | unsigned int sysclk; | ||
28 | struct snd_soc_codec codec; | ||
29 | u8 reg_cache[AD193X_NUM_REGS]; | 27 | u8 reg_cache[AD193X_NUM_REGS]; |
28 | enum snd_soc_control_type bus_type; | ||
29 | void *control_data; | ||
30 | int sysclk; | ||
30 | }; | 31 | }; |
31 | 32 | ||
32 | /* ad193x register cache & default register settings */ | 33 | /* ad193x register cache & default register settings */ |
@@ -34,9 +35,6 @@ static const u8 ad193x_reg[AD193X_NUM_REGS] = { | |||
34 | 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, | 35 | 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, |
35 | }; | 36 | }; |
36 | 37 | ||
37 | static struct snd_soc_codec *ad193x_codec; | ||
38 | struct snd_soc_codec_device soc_codec_dev_ad193x; | ||
39 | |||
40 | /* | 38 | /* |
41 | * AD193X volume/mute/de-emphasis etc. controls | 39 | * AD193X volume/mute/de-emphasis etc. controls |
42 | */ | 40 | */ |
@@ -275,8 +273,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream, | |||
275 | int word_len = 0, reg = 0, master_rate = 0; | 273 | int word_len = 0, reg = 0, master_rate = 0; |
276 | 274 | ||
277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 275 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
278 | struct snd_soc_device *socdev = rtd->socdev; | 276 | struct snd_soc_codec *codec = rtd->codec; |
279 | struct snd_soc_codec *codec = socdev->card->codec; | ||
280 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); | 277 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); |
281 | 278 | ||
282 | /* bit size */ | 279 | /* bit size */ |
@@ -323,100 +320,6 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream, | |||
323 | return 0; | 320 | return 0; |
324 | } | 321 | } |
325 | 322 | ||
326 | static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type) | ||
327 | { | ||
328 | struct snd_soc_codec *codec; | ||
329 | struct ad193x_priv *ad193x; | ||
330 | int ret; | ||
331 | |||
332 | if (ad193x_codec) { | ||
333 | dev_err(dev, "Another ad193x is registered\n"); | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | |||
337 | ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL); | ||
338 | if (ad193x == NULL) | ||
339 | return -ENOMEM; | ||
340 | |||
341 | dev_set_drvdata(dev, ad193x); | ||
342 | |||
343 | codec = &ad193x->codec; | ||
344 | mutex_init(&codec->mutex); | ||
345 | codec->control_data = ctrl_data; | ||
346 | codec->dev = dev; | ||
347 | snd_soc_codec_set_drvdata(codec, ad193x); | ||
348 | codec->reg_cache = ad193x->reg_cache; | ||
349 | codec->reg_cache_size = AD193X_NUM_REGS; | ||
350 | codec->name = "AD193X"; | ||
351 | codec->owner = THIS_MODULE; | ||
352 | codec->dai = &ad193x_dai; | ||
353 | codec->num_dai = 1; | ||
354 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
355 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
356 | |||
357 | ad193x_dai.dev = codec->dev; | ||
358 | ad193x_codec = codec; | ||
359 | |||
360 | memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS); | ||
361 | |||
362 | if (bus_type == SND_SOC_I2C) | ||
363 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type); | ||
364 | else | ||
365 | ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type); | ||
366 | if (ret < 0) { | ||
367 | dev_err(codec->dev, "failed to set cache I/O: %d\n", | ||
368 | ret); | ||
369 | kfree(ad193x); | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | /* default setting for ad193x */ | ||
374 | |||
375 | /* unmute dac channels */ | ||
376 | snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0); | ||
377 | /* de-emphasis: 48kHz, powedown dac */ | ||
378 | snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A); | ||
379 | /* powerdown dac, dac in tdm mode */ | ||
380 | snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41); | ||
381 | /* high-pass filter enable */ | ||
382 | snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3); | ||
383 | /* sata delay=1, adc aux mode */ | ||
384 | snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43); | ||
385 | /* pll input: mclki/xi */ | ||
386 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ | ||
387 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); | ||
388 | ad193x->sysclk = 12288000; | ||
389 | |||
390 | ret = snd_soc_register_codec(codec); | ||
391 | if (ret != 0) { | ||
392 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
393 | kfree(ad193x); | ||
394 | return ret; | ||
395 | } | ||
396 | |||
397 | ret = snd_soc_register_dai(&ad193x_dai); | ||
398 | if (ret != 0) { | ||
399 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
400 | snd_soc_unregister_codec(codec); | ||
401 | kfree(ad193x); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int ad193x_bus_remove(struct device *dev) | ||
409 | { | ||
410 | struct ad193x_priv *ad193x = dev_get_drvdata(dev); | ||
411 | |||
412 | snd_soc_unregister_dai(&ad193x_dai); | ||
413 | snd_soc_unregister_codec(&ad193x->codec); | ||
414 | kfree(ad193x); | ||
415 | ad193x_codec = NULL; | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static struct snd_soc_dai_ops ad193x_dai_ops = { | 323 | static struct snd_soc_dai_ops ad193x_dai_ops = { |
421 | .hw_params = ad193x_hw_params, | 324 | .hw_params = ad193x_hw_params, |
422 | .digital_mute = ad193x_mute, | 325 | .digital_mute = ad193x_mute, |
@@ -426,8 +329,8 @@ static struct snd_soc_dai_ops ad193x_dai_ops = { | |||
426 | }; | 329 | }; |
427 | 330 | ||
428 | /* codec DAI instance */ | 331 | /* codec DAI instance */ |
429 | struct snd_soc_dai ad193x_dai = { | 332 | static struct snd_soc_dai_driver ad193x_dai = { |
430 | .name = "AD193X", | 333 | .name = "ad193x-hifi", |
431 | .playback = { | 334 | .playback = { |
432 | .stream_name = "Playback", | 335 | .stream_name = "Playback", |
433 | .channels_min = 2, | 336 | .channels_min = 2, |
@@ -446,28 +349,39 @@ struct snd_soc_dai ad193x_dai = { | |||
446 | }, | 349 | }, |
447 | .ops = &ad193x_dai_ops, | 350 | .ops = &ad193x_dai_ops, |
448 | }; | 351 | }; |
449 | EXPORT_SYMBOL_GPL(ad193x_dai); | ||
450 | 352 | ||
451 | static int ad193x_probe(struct platform_device *pdev) | 353 | static int ad193x_probe(struct snd_soc_codec *codec) |
452 | { | 354 | { |
453 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 355 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); |
454 | struct snd_soc_codec *codec; | 356 | int ret; |
455 | int ret = 0; | ||
456 | 357 | ||
457 | if (ad193x_codec == NULL) { | 358 | codec->control_data = ad193x->control_data; |
458 | dev_err(&pdev->dev, "Codec device not registered\n"); | 359 | if (ad193x->bus_type == SND_SOC_I2C) |
459 | return -ENODEV; | 360 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type); |
361 | else | ||
362 | ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type); | ||
363 | if (ret < 0) { | ||
364 | dev_err(codec->dev, "failed to set cache I/O: %d\n", | ||
365 | ret); | ||
366 | kfree(ad193x); | ||
367 | return ret; | ||
460 | } | 368 | } |
461 | 369 | ||
462 | socdev->card->codec = ad193x_codec; | 370 | /* default setting for ad193x */ |
463 | codec = ad193x_codec; | ||
464 | 371 | ||
465 | /* register pcms */ | 372 | /* unmute dac channels */ |
466 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 373 | snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0); |
467 | if (ret < 0) { | 374 | /* de-emphasis: 48kHz, powedown dac */ |
468 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | 375 | snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A); |
469 | goto pcm_err; | 376 | /* powerdown dac, dac in tdm mode */ |
470 | } | 377 | snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41); |
378 | /* high-pass filter enable */ | ||
379 | snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3); | ||
380 | /* sata delay=1, adc aux mode */ | ||
381 | snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43); | ||
382 | /* pll input: mclki/xi */ | ||
383 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ | ||
384 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); | ||
471 | 385 | ||
472 | snd_soc_add_controls(codec, ad193x_snd_controls, | 386 | snd_soc_add_controls(codec, ad193x_snd_controls, |
473 | ARRAY_SIZE(ad193x_snd_controls)); | 387 | ARRAY_SIZE(ad193x_snd_controls)); |
@@ -475,41 +389,47 @@ static int ad193x_probe(struct platform_device *pdev) | |||
475 | ARRAY_SIZE(ad193x_dapm_widgets)); | 389 | ARRAY_SIZE(ad193x_dapm_widgets)); |
476 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); | 390 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); |
477 | 391 | ||
478 | pcm_err: | ||
479 | return ret; | 392 | return ret; |
480 | } | 393 | } |
481 | 394 | ||
482 | /* power down chip */ | 395 | static struct snd_soc_codec_driver soc_codec_dev_ad193x = { |
483 | static int ad193x_remove(struct platform_device *pdev) | ||
484 | { | ||
485 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
486 | |||
487 | snd_soc_free_pcms(socdev); | ||
488 | snd_soc_dapm_free(socdev); | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | struct snd_soc_codec_device soc_codec_dev_ad193x = { | ||
494 | .probe = ad193x_probe, | 396 | .probe = ad193x_probe, |
495 | .remove = ad193x_remove, | 397 | .reg_cache_default = ad193x_reg, |
398 | .reg_cache_size = AD193X_NUM_REGS, | ||
399 | .reg_word_size = sizeof(u16), | ||
496 | }; | 400 | }; |
497 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x); | ||
498 | 401 | ||
499 | #if defined(CONFIG_SPI_MASTER) | 402 | #if defined(CONFIG_SPI_MASTER) |
500 | static int __devinit ad193x_spi_probe(struct spi_device *spi) | 403 | static int __devinit ad193x_spi_probe(struct spi_device *spi) |
501 | { | 404 | { |
502 | return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI); | 405 | struct ad193x_priv *ad193x; |
406 | int ret; | ||
407 | |||
408 | ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL); | ||
409 | if (ad193x == NULL) | ||
410 | return -ENOMEM; | ||
411 | |||
412 | spi_set_drvdata(spi, ad193x); | ||
413 | ad193x->control_data = spi; | ||
414 | ad193x->bus_type = SND_SOC_SPI; | ||
415 | |||
416 | ret = snd_soc_register_codec(&spi->dev, | ||
417 | &soc_codec_dev_ad193x, &ad193x_dai, 1); | ||
418 | if (ret < 0) | ||
419 | kfree(ad193x); | ||
420 | return ret; | ||
503 | } | 421 | } |
504 | 422 | ||
505 | static int __devexit ad193x_spi_remove(struct spi_device *spi) | 423 | static int __devexit ad193x_spi_remove(struct spi_device *spi) |
506 | { | 424 | { |
507 | return ad193x_bus_remove(&spi->dev); | 425 | snd_soc_unregister_codec(&spi->dev); |
426 | kfree(spi_get_drvdata(spi)); | ||
427 | return 0; | ||
508 | } | 428 | } |
509 | 429 | ||
510 | static struct spi_driver ad193x_spi_driver = { | 430 | static struct spi_driver ad193x_spi_driver = { |
511 | .driver = { | 431 | .driver = { |
512 | .name = "ad193x", | 432 | .name = "ad193x-codec", |
513 | .owner = THIS_MODULE, | 433 | .owner = THIS_MODULE, |
514 | }, | 434 | }, |
515 | .probe = ad193x_spi_probe, | 435 | .probe = ad193x_spi_probe, |
@@ -528,17 +448,34 @@ MODULE_DEVICE_TABLE(i2c, ad193x_id); | |||
528 | static int __devinit ad193x_i2c_probe(struct i2c_client *client, | 448 | static int __devinit ad193x_i2c_probe(struct i2c_client *client, |
529 | const struct i2c_device_id *id) | 449 | const struct i2c_device_id *id) |
530 | { | 450 | { |
531 | return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C); | 451 | struct ad193x_priv *ad193x; |
452 | int ret; | ||
453 | |||
454 | ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL); | ||
455 | if (ad193x == NULL) | ||
456 | return -ENOMEM; | ||
457 | |||
458 | i2c_set_clientdata(client, ad193x); | ||
459 | ad193x->control_data = client; | ||
460 | ad193x->bus_type = SND_SOC_I2C; | ||
461 | |||
462 | ret = snd_soc_register_codec(&client->dev, | ||
463 | &soc_codec_dev_ad193x, &ad193x_dai, 1); | ||
464 | if (ret < 0) | ||
465 | kfree(ad193x); | ||
466 | return ret; | ||
532 | } | 467 | } |
533 | 468 | ||
534 | static int __devexit ad193x_i2c_remove(struct i2c_client *client) | 469 | static int __devexit ad193x_i2c_remove(struct i2c_client *client) |
535 | { | 470 | { |
536 | return ad193x_bus_remove(&client->dev); | 471 | snd_soc_unregister_codec(&client->dev); |
472 | kfree(i2c_get_clientdata(client)); | ||
473 | return 0; | ||
537 | } | 474 | } |
538 | 475 | ||
539 | static struct i2c_driver ad193x_i2c_driver = { | 476 | static struct i2c_driver ad193x_i2c_driver = { |
540 | .driver = { | 477 | .driver = { |
541 | .name = "ad193x", | 478 | .name = "ad193x-codec", |
542 | }, | 479 | }, |
543 | .probe = ad193x_i2c_probe, | 480 | .probe = ad193x_i2c_probe, |
544 | .remove = __devexit_p(ad193x_i2c_remove), | 481 | .remove = __devexit_p(ad193x_i2c_remove), |