diff options
Diffstat (limited to 'sound/soc/codecs/ssm2602.c')
-rw-r--r-- | sound/soc/codecs/ssm2602.c | 196 |
1 files changed, 96 insertions, 100 deletions
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 2727befd158e..7e2194975360 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/pm.h> | 33 | #include <linux/pm.h> |
34 | #include <linux/i2c.h> | 34 | #include <linux/i2c.h> |
35 | #include <linux/spi/spi.h> | ||
35 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
36 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
37 | #include <sound/core.h> | 38 | #include <sound/core.h> |
@@ -48,7 +49,6 @@ | |||
48 | struct ssm2602_priv { | 49 | struct ssm2602_priv { |
49 | unsigned int sysclk; | 50 | unsigned int sysclk; |
50 | enum snd_soc_control_type control_type; | 51 | enum snd_soc_control_type control_type; |
51 | void *control_data; | ||
52 | struct snd_pcm_substream *master_substream; | 52 | struct snd_pcm_substream *master_substream; |
53 | struct snd_pcm_substream *slave_substream; | 53 | struct snd_pcm_substream *slave_substream; |
54 | }; | 54 | }; |
@@ -65,55 +65,7 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { | |||
65 | 0x0000, 0x0000 | 65 | 0x0000, 0x0000 |
66 | }; | 66 | }; |
67 | 67 | ||
68 | /* | 68 | #define ssm2602_reset(c) snd_soc_write(c, SSM2602_RESET, 0) |
69 | * read ssm2602 register cache | ||
70 | */ | ||
71 | static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec, | ||
72 | unsigned int reg) | ||
73 | { | ||
74 | u16 *cache = codec->reg_cache; | ||
75 | if (reg == SSM2602_RESET) | ||
76 | return 0; | ||
77 | if (reg >= SSM2602_CACHEREGNUM) | ||
78 | return -1; | ||
79 | return cache[reg]; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * write ssm2602 register cache | ||
84 | */ | ||
85 | static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec, | ||
86 | u16 reg, unsigned int value) | ||
87 | { | ||
88 | u16 *cache = codec->reg_cache; | ||
89 | if (reg >= SSM2602_CACHEREGNUM) | ||
90 | return; | ||
91 | cache[reg] = value; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * write to the ssm2602 register space | ||
96 | */ | ||
97 | static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg, | ||
98 | unsigned int value) | ||
99 | { | ||
100 | u8 data[2]; | ||
101 | |||
102 | /* data is | ||
103 | * D15..D9 ssm2602 register offset | ||
104 | * D8...D0 register data | ||
105 | */ | ||
106 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
107 | data[1] = value & 0x00ff; | ||
108 | |||
109 | ssm2602_write_reg_cache(codec, reg, value); | ||
110 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
111 | return 0; | ||
112 | else | ||
113 | return -EIO; | ||
114 | } | ||
115 | |||
116 | #define ssm2602_reset(c) ssm2602_write(c, SSM2602_RESET, 0) | ||
117 | 69 | ||
118 | /*Appending several "None"s just for OSS mixer use*/ | 70 | /*Appending several "None"s just for OSS mixer use*/ |
119 | static const char *ssm2602_input_select[] = { | 71 | static const char *ssm2602_input_select[] = { |
@@ -278,12 +230,11 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, | |||
278 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 230 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
279 | struct snd_soc_codec *codec = rtd->codec; | 231 | struct snd_soc_codec *codec = rtd->codec; |
280 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 232 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
281 | struct i2c_client *i2c = codec->control_data; | 233 | u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3; |
282 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; | ||
283 | int i = get_coeff(ssm2602->sysclk, params_rate(params)); | 234 | int i = get_coeff(ssm2602->sysclk, params_rate(params)); |
284 | 235 | ||
285 | if (substream == ssm2602->slave_substream) { | 236 | if (substream == ssm2602->slave_substream) { |
286 | dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); | 237 | dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n"); |
287 | return 0; | 238 | return 0; |
288 | } | 239 | } |
289 | 240 | ||
@@ -294,8 +245,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, | |||
294 | srate = (coeff_div[i].sr << 2) | | 245 | srate = (coeff_div[i].sr << 2) | |
295 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | 246 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; |
296 | 247 | ||
297 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | 248 | snd_soc_write(codec, SSM2602_ACTIVE, 0); |
298 | ssm2602_write(codec, SSM2602_SRATE, srate); | 249 | snd_soc_write(codec, SSM2602_SRATE, srate); |
299 | 250 | ||
300 | /* bit size */ | 251 | /* bit size */ |
301 | switch (params_format(params)) { | 252 | switch (params_format(params)) { |
@@ -311,8 +262,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, | |||
311 | iface |= 0x000c; | 262 | iface |= 0x000c; |
312 | break; | 263 | break; |
313 | } | 264 | } |
314 | ssm2602_write(codec, SSM2602_IFACE, iface); | 265 | snd_soc_write(codec, SSM2602_IFACE, iface); |
315 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | 266 | snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); |
316 | return 0; | 267 | return 0; |
317 | } | 268 | } |
318 | 269 | ||
@@ -360,7 +311,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, | |||
360 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 311 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
361 | struct snd_soc_codec *codec = rtd->codec; | 312 | struct snd_soc_codec *codec = rtd->codec; |
362 | /* set active */ | 313 | /* set active */ |
363 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | 314 | snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); |
364 | 315 | ||
365 | return 0; | 316 | return 0; |
366 | } | 317 | } |
@@ -374,7 +325,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, | |||
374 | 325 | ||
375 | /* deactivate */ | 326 | /* deactivate */ |
376 | if (!codec->active) | 327 | if (!codec->active) |
377 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | 328 | snd_soc_write(codec, SSM2602_ACTIVE, 0); |
378 | 329 | ||
379 | if (ssm2602->master_substream == substream) | 330 | if (ssm2602->master_substream == substream) |
380 | ssm2602->master_substream = ssm2602->slave_substream; | 331 | ssm2602->master_substream = ssm2602->slave_substream; |
@@ -385,12 +336,12 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, | |||
385 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) | 336 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) |
386 | { | 337 | { |
387 | struct snd_soc_codec *codec = dai->codec; | 338 | struct snd_soc_codec *codec = dai->codec; |
388 | u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; | 339 | u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; |
389 | if (mute) | 340 | if (mute) |
390 | ssm2602_write(codec, SSM2602_APDIGI, | 341 | snd_soc_write(codec, SSM2602_APDIGI, |
391 | mute_reg | APDIGI_ENABLE_DAC_MUTE); | 342 | mute_reg | APDIGI_ENABLE_DAC_MUTE); |
392 | else | 343 | else |
393 | ssm2602_write(codec, SSM2602_APDIGI, mute_reg); | 344 | snd_soc_write(codec, SSM2602_APDIGI, mute_reg); |
394 | return 0; | 345 | return 0; |
395 | } | 346 | } |
396 | 347 | ||
@@ -466,30 +417,30 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
466 | } | 417 | } |
467 | 418 | ||
468 | /* set iface */ | 419 | /* set iface */ |
469 | ssm2602_write(codec, SSM2602_IFACE, iface); | 420 | snd_soc_write(codec, SSM2602_IFACE, iface); |
470 | return 0; | 421 | return 0; |
471 | } | 422 | } |
472 | 423 | ||
473 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | 424 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, |
474 | enum snd_soc_bias_level level) | 425 | enum snd_soc_bias_level level) |
475 | { | 426 | { |
476 | u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f; | 427 | u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f; |
477 | 428 | ||
478 | switch (level) { | 429 | switch (level) { |
479 | case SND_SOC_BIAS_ON: | 430 | case SND_SOC_BIAS_ON: |
480 | /* vref/mid, osc on, dac unmute */ | 431 | /* vref/mid, osc on, dac unmute */ |
481 | ssm2602_write(codec, SSM2602_PWR, reg); | 432 | snd_soc_write(codec, SSM2602_PWR, reg); |
482 | break; | 433 | break; |
483 | case SND_SOC_BIAS_PREPARE: | 434 | case SND_SOC_BIAS_PREPARE: |
484 | break; | 435 | break; |
485 | case SND_SOC_BIAS_STANDBY: | 436 | case SND_SOC_BIAS_STANDBY: |
486 | /* everything off except vref/vmid, */ | 437 | /* everything off except vref/vmid, */ |
487 | ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); | 438 | snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); |
488 | break; | 439 | break; |
489 | case SND_SOC_BIAS_OFF: | 440 | case SND_SOC_BIAS_OFF: |
490 | /* everything off, dac mute, inactive */ | 441 | /* everything off, dac mute, inactive */ |
491 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | 442 | snd_soc_write(codec, SSM2602_ACTIVE, 0); |
492 | ssm2602_write(codec, SSM2602_PWR, 0xffff); | 443 | snd_soc_write(codec, SSM2602_PWR, 0xffff); |
493 | break; | 444 | break; |
494 | 445 | ||
495 | } | 446 | } |
@@ -539,17 +490,10 @@ static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state) | |||
539 | 490 | ||
540 | static int ssm2602_resume(struct snd_soc_codec *codec) | 491 | static int ssm2602_resume(struct snd_soc_codec *codec) |
541 | { | 492 | { |
542 | int i; | 493 | snd_soc_cache_sync(codec); |
543 | u8 data[2]; | 494 | |
544 | u16 *cache = codec->reg_cache; | ||
545 | |||
546 | /* Sync reg_cache with the hardware */ | ||
547 | for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) { | ||
548 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
549 | data[1] = cache[i] & 0x00ff; | ||
550 | codec->hw_write(codec->control_data, data, 2); | ||
551 | } | ||
552 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 495 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
496 | |||
553 | return 0; | 497 | return 0; |
554 | } | 498 | } |
555 | 499 | ||
@@ -560,31 +504,39 @@ static int ssm2602_probe(struct snd_soc_codec *codec) | |||
560 | 504 | ||
561 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); | 505 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); |
562 | 506 | ||
563 | codec->control_data = ssm2602->control_data; | 507 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type); |
508 | if (ret < 0) { | ||
509 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
510 | return ret; | ||
511 | } | ||
564 | 512 | ||
565 | ssm2602_reset(codec); | 513 | ret = ssm2602_reset(codec); |
514 | if (ret < 0) { | ||
515 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | ||
516 | return ret; | ||
517 | } | ||
566 | 518 | ||
567 | /*power on device*/ | 519 | /*power on device*/ |
568 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | 520 | snd_soc_write(codec, SSM2602_ACTIVE, 0); |
569 | /* set the update bits */ | 521 | /* set the update bits */ |
570 | reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL); | 522 | reg = snd_soc_read(codec, SSM2602_LINVOL); |
571 | ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); | 523 | snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); |
572 | reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL); | 524 | reg = snd_soc_read(codec, SSM2602_RINVOL); |
573 | ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); | 525 | snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); |
574 | reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V); | 526 | reg = snd_soc_read(codec, SSM2602_LOUT1V); |
575 | ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); | 527 | snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); |
576 | reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V); | 528 | reg = snd_soc_read(codec, SSM2602_ROUT1V); |
577 | ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); | 529 | snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); |
578 | /*select Line in as default input*/ | 530 | /*select Line in as default input*/ |
579 | ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC | | 531 | snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | |
580 | APANA_ENABLE_MIC_BOOST); | 532 | APANA_ENABLE_MIC_BOOST); |
581 | ssm2602_write(codec, SSM2602_PWR, 0); | 533 | snd_soc_write(codec, SSM2602_PWR, 0); |
582 | 534 | ||
583 | snd_soc_add_controls(codec, ssm2602_snd_controls, | 535 | snd_soc_add_controls(codec, ssm2602_snd_controls, |
584 | ARRAY_SIZE(ssm2602_snd_controls)); | 536 | ARRAY_SIZE(ssm2602_snd_controls)); |
585 | ssm2602_add_widgets(codec); | 537 | ssm2602_add_widgets(codec); |
586 | 538 | ||
587 | return ret; | 539 | return 0; |
588 | } | 540 | } |
589 | 541 | ||
590 | /* remove everything here */ | 542 | /* remove everything here */ |
@@ -599,14 +551,49 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { | |||
599 | .remove = ssm2602_remove, | 551 | .remove = ssm2602_remove, |
600 | .suspend = ssm2602_suspend, | 552 | .suspend = ssm2602_suspend, |
601 | .resume = ssm2602_resume, | 553 | .resume = ssm2602_resume, |
602 | .read = ssm2602_read_reg_cache, | ||
603 | .write = ssm2602_write, | ||
604 | .set_bias_level = ssm2602_set_bias_level, | 554 | .set_bias_level = ssm2602_set_bias_level, |
605 | .reg_cache_size = sizeof(ssm2602_reg), | 555 | .reg_cache_size = sizeof(ssm2602_reg), |
606 | .reg_word_size = sizeof(u16), | 556 | .reg_word_size = sizeof(u16), |
607 | .reg_cache_default = ssm2602_reg, | 557 | .reg_cache_default = ssm2602_reg, |
608 | }; | 558 | }; |
609 | 559 | ||
560 | #if defined(CONFIG_SPI_MASTER) | ||
561 | static int __devinit ssm2602_spi_probe(struct spi_device *spi) | ||
562 | { | ||
563 | struct ssm2602_priv *ssm2602; | ||
564 | int ret; | ||
565 | |||
566 | ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL); | ||
567 | if (ssm2602 == NULL) | ||
568 | return -ENOMEM; | ||
569 | |||
570 | spi_set_drvdata(spi, ssm2602); | ||
571 | ssm2602->control_type = SND_SOC_SPI; | ||
572 | |||
573 | ret = snd_soc_register_codec(&spi->dev, | ||
574 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); | ||
575 | if (ret < 0) | ||
576 | kfree(ssm2602); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | static int __devexit ssm2602_spi_remove(struct spi_device *spi) | ||
581 | { | ||
582 | snd_soc_unregister_codec(&spi->dev); | ||
583 | kfree(spi_get_drvdata(spi)); | ||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | static struct spi_driver ssm2602_spi_driver = { | ||
588 | .driver = { | ||
589 | .name = "ssm2602", | ||
590 | .owner = THIS_MODULE, | ||
591 | }, | ||
592 | .probe = ssm2602_spi_probe, | ||
593 | .remove = __devexit_p(ssm2602_spi_remove), | ||
594 | }; | ||
595 | #endif | ||
596 | |||
610 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 597 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
611 | /* | 598 | /* |
612 | * ssm2602 2 wire address is determined by GPIO5 | 599 | * ssm2602 2 wire address is determined by GPIO5 |
@@ -625,7 +612,6 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c, | |||
625 | return -ENOMEM; | 612 | return -ENOMEM; |
626 | 613 | ||
627 | i2c_set_clientdata(i2c, ssm2602); | 614 | i2c_set_clientdata(i2c, ssm2602); |
628 | ssm2602->control_data = i2c; | ||
629 | ssm2602->control_type = SND_SOC_I2C; | 615 | ssm2602->control_type = SND_SOC_I2C; |
630 | 616 | ||
631 | ret = snd_soc_register_codec(&i2c->dev, | 617 | ret = snd_soc_register_codec(&i2c->dev, |
@@ -651,7 +637,7 @@ MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | |||
651 | /* corgi i2c codec control layer */ | 637 | /* corgi i2c codec control layer */ |
652 | static struct i2c_driver ssm2602_i2c_driver = { | 638 | static struct i2c_driver ssm2602_i2c_driver = { |
653 | .driver = { | 639 | .driver = { |
654 | .name = "ssm2602-codec", | 640 | .name = "ssm2602", |
655 | .owner = THIS_MODULE, | 641 | .owner = THIS_MODULE, |
656 | }, | 642 | }, |
657 | .probe = ssm2602_i2c_probe, | 643 | .probe = ssm2602_i2c_probe, |
@@ -664,19 +650,29 @@ static struct i2c_driver ssm2602_i2c_driver = { | |||
664 | static int __init ssm2602_modinit(void) | 650 | static int __init ssm2602_modinit(void) |
665 | { | 651 | { |
666 | int ret = 0; | 652 | int ret = 0; |
653 | |||
654 | #if defined(CONFIG_SPI_MASTER) | ||
655 | ret = spi_register_driver(&ssm2602_spi_driver); | ||
656 | if (ret) | ||
657 | return ret; | ||
658 | #endif | ||
659 | |||
667 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 660 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
668 | ret = i2c_add_driver(&ssm2602_i2c_driver); | 661 | ret = i2c_add_driver(&ssm2602_i2c_driver); |
669 | if (ret != 0) { | 662 | if (ret) |
670 | printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n", | 663 | return ret; |
671 | ret); | ||
672 | } | ||
673 | #endif | 664 | #endif |
665 | |||
674 | return ret; | 666 | return ret; |
675 | } | 667 | } |
676 | module_init(ssm2602_modinit); | 668 | module_init(ssm2602_modinit); |
677 | 669 | ||
678 | static void __exit ssm2602_exit(void) | 670 | static void __exit ssm2602_exit(void) |
679 | { | 671 | { |
672 | #if defined(CONFIG_SPI_MASTER) | ||
673 | spi_unregister_driver(&ssm2602_spi_driver); | ||
674 | #endif | ||
675 | |||
680 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 676 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
681 | i2c_del_driver(&ssm2602_i2c_driver); | 677 | i2c_del_driver(&ssm2602_i2c_driver); |
682 | #endif | 678 | #endif |