diff options
Diffstat (limited to 'sound/soc/codecs/ssm2602.c')
-rw-r--r-- | sound/soc/codecs/ssm2602.c | 107 |
1 files changed, 74 insertions, 33 deletions
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 9801cd7cfcb5..3cb3271c5fe2 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -59,6 +59,7 @@ struct ssm2602_priv { | |||
59 | struct snd_pcm_substream *slave_substream; | 59 | struct snd_pcm_substream *slave_substream; |
60 | 60 | ||
61 | enum ssm2602_type type; | 61 | enum ssm2602_type type; |
62 | unsigned int clk_out_pwr; | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | /* | 65 | /* |
@@ -294,7 +295,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, | |||
294 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 295 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
295 | struct snd_soc_codec *codec = rtd->codec; | 296 | struct snd_soc_codec *codec = rtd->codec; |
296 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 297 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
297 | struct i2c_client *i2c = codec->control_data; | ||
298 | struct snd_pcm_runtime *master_runtime; | 298 | struct snd_pcm_runtime *master_runtime; |
299 | 299 | ||
300 | /* The DAI has shared clocks so if we already have a playback or | 300 | /* The DAI has shared clocks so if we already have a playback or |
@@ -303,7 +303,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, | |||
303 | */ | 303 | */ |
304 | if (ssm2602->master_substream) { | 304 | if (ssm2602->master_substream) { |
305 | master_runtime = ssm2602->master_substream->runtime; | 305 | master_runtime = ssm2602->master_substream->runtime; |
306 | dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", | 306 | dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n", |
307 | master_runtime->sample_bits, | 307 | master_runtime->sample_bits, |
308 | master_runtime->rate); | 308 | master_runtime->rate); |
309 | 309 | ||
@@ -343,12 +343,14 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, | |||
343 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) | 343 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) |
344 | { | 344 | { |
345 | struct snd_soc_codec *codec = dai->codec; | 345 | struct snd_soc_codec *codec = dai->codec; |
346 | u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; | 346 | |
347 | if (mute) | 347 | if (mute) |
348 | snd_soc_write(codec, SSM2602_APDIGI, | 348 | snd_soc_update_bits(codec, SSM2602_APDIGI, |
349 | mute_reg | APDIGI_ENABLE_DAC_MUTE); | 349 | APDIGI_ENABLE_DAC_MUTE, |
350 | APDIGI_ENABLE_DAC_MUTE); | ||
350 | else | 351 | else |
351 | snd_soc_write(codec, SSM2602_APDIGI, mute_reg); | 352 | snd_soc_update_bits(codec, SSM2602_APDIGI, |
353 | APDIGI_ENABLE_DAC_MUTE, 0); | ||
352 | return 0; | 354 | return 0; |
353 | } | 355 | } |
354 | 356 | ||
@@ -357,16 +359,46 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
357 | { | 359 | { |
358 | struct snd_soc_codec *codec = codec_dai->codec; | 360 | struct snd_soc_codec *codec = codec_dai->codec; |
359 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 361 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
360 | switch (freq) { | 362 | |
361 | case 11289600: | 363 | if (dir == SND_SOC_CLOCK_IN) { |
362 | case 12000000: | 364 | if (clk_id != SSM2602_SYSCLK) |
363 | case 12288000: | 365 | return -EINVAL; |
364 | case 16934400: | 366 | |
365 | case 18432000: | 367 | switch (freq) { |
366 | ssm2602->sysclk = freq; | 368 | case 11289600: |
367 | return 0; | 369 | case 12000000: |
370 | case 12288000: | ||
371 | case 16934400: | ||
372 | case 18432000: | ||
373 | ssm2602->sysclk = freq; | ||
374 | break; | ||
375 | default: | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | } else { | ||
379 | unsigned int mask; | ||
380 | |||
381 | switch (clk_id) { | ||
382 | case SSM2602_CLK_CLKOUT: | ||
383 | mask = PWR_CLK_OUT_PDN; | ||
384 | break; | ||
385 | case SSM2602_CLK_XTO: | ||
386 | mask = PWR_OSC_PDN; | ||
387 | break; | ||
388 | default: | ||
389 | return -EINVAL; | ||
390 | } | ||
391 | |||
392 | if (freq == 0) | ||
393 | ssm2602->clk_out_pwr |= mask; | ||
394 | else | ||
395 | ssm2602->clk_out_pwr &= ~mask; | ||
396 | |||
397 | snd_soc_update_bits(codec, SSM2602_PWR, | ||
398 | PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr); | ||
368 | } | 399 | } |
369 | return -EINVAL; | 400 | |
401 | return 0; | ||
370 | } | 402 | } |
371 | 403 | ||
372 | static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, | 404 | static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, |
@@ -431,23 +463,27 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
431 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | 463 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, |
432 | enum snd_soc_bias_level level) | 464 | enum snd_soc_bias_level level) |
433 | { | 465 | { |
434 | u16 reg = snd_soc_read(codec, SSM2602_PWR); | 466 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
435 | reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN); | ||
436 | 467 | ||
437 | switch (level) { | 468 | switch (level) { |
438 | case SND_SOC_BIAS_ON: | 469 | case SND_SOC_BIAS_ON: |
439 | /* vref/mid, osc on, dac unmute */ | 470 | /* vref/mid on, osc and clkout on if enabled */ |
440 | snd_soc_write(codec, SSM2602_PWR, reg); | 471 | snd_soc_update_bits(codec, SSM2602_PWR, |
472 | PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN, | ||
473 | ssm2602->clk_out_pwr); | ||
441 | break; | 474 | break; |
442 | case SND_SOC_BIAS_PREPARE: | 475 | case SND_SOC_BIAS_PREPARE: |
443 | break; | 476 | break; |
444 | case SND_SOC_BIAS_STANDBY: | 477 | case SND_SOC_BIAS_STANDBY: |
445 | /* everything off except vref/vmid, */ | 478 | /* everything off except vref/vmid, */ |
446 | snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); | 479 | snd_soc_update_bits(codec, SSM2602_PWR, |
480 | PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN, | ||
481 | PWR_CLK_OUT_PDN | PWR_OSC_PDN); | ||
447 | break; | 482 | break; |
448 | case SND_SOC_BIAS_OFF: | 483 | case SND_SOC_BIAS_OFF: |
449 | /* everything off, dac mute, inactive */ | 484 | /* everything off */ |
450 | snd_soc_write(codec, SSM2602_PWR, 0xffff); | 485 | snd_soc_update_bits(codec, SSM2602_PWR, |
486 | PWR_POWER_OFF, PWR_POWER_OFF); | ||
451 | break; | 487 | break; |
452 | 488 | ||
453 | } | 489 | } |
@@ -506,12 +542,12 @@ static int ssm2602_resume(struct snd_soc_codec *codec) | |||
506 | static int ssm2602_probe(struct snd_soc_codec *codec) | 542 | static int ssm2602_probe(struct snd_soc_codec *codec) |
507 | { | 543 | { |
508 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 544 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
509 | int ret, reg; | 545 | int ret; |
510 | 546 | ||
511 | reg = snd_soc_read(codec, SSM2602_LOUT1V); | 547 | snd_soc_update_bits(codec, SSM2602_LOUT1V, |
512 | snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); | 548 | LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH); |
513 | reg = snd_soc_read(codec, SSM2602_ROUT1V); | 549 | snd_soc_update_bits(codec, SSM2602_ROUT1V, |
514 | snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); | 550 | ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH); |
515 | 551 | ||
516 | ret = snd_soc_add_controls(codec, ssm2602_snd_controls, | 552 | ret = snd_soc_add_controls(codec, ssm2602_snd_controls, |
517 | ARRAY_SIZE(ssm2602_snd_controls)); | 553 | ARRAY_SIZE(ssm2602_snd_controls)); |
@@ -544,7 +580,7 @@ static int ssm2604_probe(struct snd_soc_codec *codec) | |||
544 | static int ssm260x_probe(struct snd_soc_codec *codec) | 580 | static int ssm260x_probe(struct snd_soc_codec *codec) |
545 | { | 581 | { |
546 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 582 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
547 | int ret, reg; | 583 | int ret; |
548 | 584 | ||
549 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); | 585 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); |
550 | 586 | ||
@@ -561,10 +597,10 @@ static int ssm260x_probe(struct snd_soc_codec *codec) | |||
561 | } | 597 | } |
562 | 598 | ||
563 | /* set the update bits */ | 599 | /* set the update bits */ |
564 | reg = snd_soc_read(codec, SSM2602_LINVOL); | 600 | snd_soc_update_bits(codec, SSM2602_LINVOL, |
565 | snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); | 601 | LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH); |
566 | reg = snd_soc_read(codec, SSM2602_RINVOL); | 602 | snd_soc_update_bits(codec, SSM2602_RINVOL, |
567 | snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); | 603 | RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH); |
568 | /*select Line in as default input*/ | 604 | /*select Line in as default input*/ |
569 | snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | | 605 | snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | |
570 | APANA_ENABLE_MIC_BOOST); | 606 | APANA_ENABLE_MIC_BOOST); |
@@ -578,7 +614,12 @@ static int ssm260x_probe(struct snd_soc_codec *codec) | |||
578 | break; | 614 | break; |
579 | } | 615 | } |
580 | 616 | ||
581 | return ret; | 617 | if (ret) |
618 | return ret; | ||
619 | |||
620 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
621 | |||
622 | return 0; | ||
582 | } | 623 | } |
583 | 624 | ||
584 | /* remove everything here */ | 625 | /* remove everything here */ |