#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
-#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
struct snd_pcm_substream *slave_substream;
enum ssm2602_type type;
+ unsigned int clk_out_pwr;
};
/*
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
/* The DAI has shared clocks so if we already have a playback or
*/
if (ssm2602->master_substream) {
master_runtime = ssm2602->master_substream->runtime;
- dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
+ dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n",
master_runtime->sample_bits,
master_runtime->rate);
static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+
if (mute)
- snd_soc_write(codec, SSM2602_APDIGI,
- mute_reg | APDIGI_ENABLE_DAC_MUTE);
+ snd_soc_update_bits(codec, SSM2602_APDIGI,
+ APDIGI_ENABLE_DAC_MUTE,
+ APDIGI_ENABLE_DAC_MUTE);
else
- snd_soc_write(codec, SSM2602_APDIGI, mute_reg);
+ snd_soc_update_bits(codec, SSM2602_APDIGI,
+ APDIGI_ENABLE_DAC_MUTE, 0);
return 0;
}
{
struct snd_soc_codec *codec = codec_dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- switch (freq) {
- case 11289600:
- case 12000000:
- case 12288000:
- case 16934400:
- case 18432000:
- ssm2602->sysclk = freq;
- return 0;
+
+ if (dir == SND_SOC_CLOCK_IN) {
+ if (clk_id != SSM2602_SYSCLK)
+ return -EINVAL;
+
+ switch (freq) {
+ case 11289600:
+ case 12000000:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ ssm2602->sysclk = freq;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ unsigned int mask;
+
+ switch (clk_id) {
+ case SSM2602_CLK_CLKOUT:
+ mask = PWR_CLK_OUT_PDN;
+ break;
+ case SSM2602_CLK_XTO:
+ mask = PWR_OSC_PDN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (freq == 0)
+ ssm2602->clk_out_pwr |= mask;
+ else
+ ssm2602->clk_out_pwr &= ~mask;
+
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
}
- return -EINVAL;
+
+ return 0;
}
static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg = snd_soc_read(codec, SSM2602_PWR);
- reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN);
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_ON:
- /* vref/mid, osc on, dac unmute */
- snd_soc_write(codec, SSM2602_PWR, reg);
+ /* vref/mid on, osc and clkout on if enabled */
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
+ ssm2602->clk_out_pwr);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/* everything off except vref/vmid, */
- snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
+ PWR_CLK_OUT_PDN | PWR_OSC_PDN);
break;
case SND_SOC_BIAS_OFF:
- /* everything off, dac mute, inactive */
- snd_soc_write(codec, SSM2602_PWR, 0xffff);
+ /* everything off */
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_POWER_OFF, PWR_POWER_OFF);
break;
}
#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops ssm2602_dai_ops = {
+static const struct snd_soc_dai_ops ssm2602_dai_ops = {
.startup = ssm2602_startup,
.hw_params = ssm2602_hw_params,
.shutdown = ssm2602_shutdown,
.ops = &ssm2602_dai_ops,
};
-static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int ssm2602_suspend(struct snd_soc_codec *codec)
{
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
static int ssm2602_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret, reg;
+ int ret;
- reg = snd_soc_read(codec, SSM2602_LOUT1V);
- snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
- reg = snd_soc_read(codec, SSM2602_ROUT1V);
- snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+ snd_soc_update_bits(codec, SSM2602_LOUT1V,
+ LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
+ snd_soc_update_bits(codec, SSM2602_ROUT1V,
+ ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
ARRAY_SIZE(ssm2602_snd_controls));
static int ssm260x_probe(struct snd_soc_codec *codec)
{
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- int ret, reg;
+ int ret;
pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
}
/* set the update bits */
- reg = snd_soc_read(codec, SSM2602_LINVOL);
- snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
- reg = snd_soc_read(codec, SSM2602_RINVOL);
- snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
+ snd_soc_update_bits(codec, SSM2602_LINVOL,
+ LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
+ snd_soc_update_bits(codec, SSM2602_RINVOL,
+ RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
/*select Line in as default input*/
snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
APANA_ENABLE_MIC_BOOST);
break;
}
- return ret;
+ if (ret)
+ return ret;
+
+ ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
}
/* remove everything here */