Commit 02dc14d6 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/wm8741', 'asoc/topic/wm8753',...

Merge remote-tracking branches 'asoc/topic/wm8741', 'asoc/topic/wm8753', 'asoc/topic/wm8904', 'asoc/topic/wm8960' and 'asoc/topic/wm8983' into asoc-next
...@@ -61,25 +61,6 @@ static const struct reg_default wm8741_reg_defaults[] = { ...@@ -61,25 +61,6 @@ static const struct reg_default wm8741_reg_defaults[] = {
{ 32, 0x0002 }, /* R32 - ADDITONAL_CONTROL_1 */ { 32, 0x0002 }, /* R32 - ADDITONAL_CONTROL_1 */
}; };
static bool wm8741_readable(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8741_DACLLSB_ATTENUATION:
case WM8741_DACLMSB_ATTENUATION:
case WM8741_DACRLSB_ATTENUATION:
case WM8741_DACRMSB_ATTENUATION:
case WM8741_VOLUME_CONTROL:
case WM8741_FORMAT_CONTROL:
case WM8741_FILTER_CONTROL:
case WM8741_MODE_CONTROL_1:
case WM8741_MODE_CONTROL_2:
case WM8741_ADDITIONAL_CONTROL_1:
return true;
default:
return false;
}
}
static int wm8741_reset(struct snd_soc_codec *codec) static int wm8741_reset(struct snd_soc_codec *codec)
{ {
return snd_soc_write(codec, WM8741_RESET, 0); return snd_soc_write(codec, WM8741_RESET, 0);
...@@ -278,51 +259,38 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -278,51 +259,38 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
switch (freq) { switch (freq) {
case 0: case 0:
wm8741->sysclk_constraints = NULL; wm8741->sysclk_constraints = NULL;
wm8741->sysclk = freq; break;
return 0;
case 11289600: case 11289600:
wm8741->sysclk_constraints = &constraints_11289; wm8741->sysclk_constraints = &constraints_11289;
wm8741->sysclk = freq; break;
return 0;
case 12288000: case 12288000:
wm8741->sysclk_constraints = &constraints_12288; wm8741->sysclk_constraints = &constraints_12288;
wm8741->sysclk = freq; break;
return 0;
case 16384000: case 16384000:
wm8741->sysclk_constraints = &constraints_16384; wm8741->sysclk_constraints = &constraints_16384;
wm8741->sysclk = freq; break;
return 0;
case 16934400: case 16934400:
wm8741->sysclk_constraints = &constraints_16934; wm8741->sysclk_constraints = &constraints_16934;
wm8741->sysclk = freq; break;
return 0;
case 18432000: case 18432000:
wm8741->sysclk_constraints = &constraints_18432; wm8741->sysclk_constraints = &constraints_18432;
wm8741->sysclk = freq; break;
return 0;
case 22579200: case 22579200:
case 33868800: case 33868800:
wm8741->sysclk_constraints = &constraints_22579; wm8741->sysclk_constraints = &constraints_22579;
wm8741->sysclk = freq; break;
return 0;
case 24576000: case 24576000:
wm8741->sysclk_constraints = &constraints_24576; wm8741->sysclk_constraints = &constraints_24576;
wm8741->sysclk = freq; break;
return 0;
case 36864000: case 36864000:
wm8741->sysclk_constraints = &constraints_36864; wm8741->sysclk_constraints = &constraints_36864;
break;
default:
return -EINVAL;
}
wm8741->sysclk = freq; wm8741->sysclk = freq;
return 0; return 0;
}
return -EINVAL;
} }
static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
...@@ -554,8 +522,6 @@ static const struct regmap_config wm8741_regmap = { ...@@ -554,8 +522,6 @@ static const struct regmap_config wm8741_regmap = {
.reg_defaults = wm8741_reg_defaults, .reg_defaults = wm8741_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults), .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
.readable_reg = wm8741_readable,
}; };
static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
......
...@@ -138,11 +138,6 @@ static bool wm8753_volatile(struct device *dev, unsigned int reg) ...@@ -138,11 +138,6 @@ static bool wm8753_volatile(struct device *dev, unsigned int reg)
return reg == WM8753_RESET; return reg == WM8753_RESET;
} }
static bool wm8753_writeable(struct device *dev, unsigned int reg)
{
return reg <= WM8753_ADCTL2;
}
/* codec private data */ /* codec private data */
struct wm8753_priv { struct wm8753_priv {
struct regmap *regmap; struct regmap *regmap;
...@@ -1509,7 +1504,6 @@ static const struct regmap_config wm8753_regmap = { ...@@ -1509,7 +1504,6 @@ static const struct regmap_config wm8753_regmap = {
.val_bits = 9, .val_bits = 9,
.max_register = WM8753_ADCTL2, .max_register = WM8753_ADCTL2,
.writeable_reg = wm8753_writeable,
.volatile_reg = wm8753_volatile, .volatile_reg = wm8753_volatile,
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
......
...@@ -1837,7 +1837,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, ...@@ -1837,7 +1837,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
clk_prepare_enable(wm8904->mclk); ret = clk_prepare_enable(wm8904->mclk);
if (ret)
return ret;
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
......
...@@ -48,6 +48,9 @@ ...@@ -48,6 +48,9 @@
#define WM8960_DISOP 0x40 #define WM8960_DISOP 0x40
#define WM8960_DRES_MASK 0x30 #define WM8960_DRES_MASK 0x30
static bool is_pll_freq_available(unsigned int source, unsigned int target);
static int wm8960_set_pll(struct snd_soc_codec *codec,
unsigned int freq_in, unsigned int freq_out);
/* /*
* wm8960 register cache * wm8960 register cache
* We can't read the WM8960 register space when we are * We can't read the WM8960 register space when we are
...@@ -126,9 +129,12 @@ struct wm8960_priv { ...@@ -126,9 +129,12 @@ struct wm8960_priv {
struct snd_soc_dapm_widget *rout1; struct snd_soc_dapm_widget *rout1;
struct snd_soc_dapm_widget *out3; struct snd_soc_dapm_widget *out3;
bool deemph; bool deemph;
int playback_fs; int lrclk;
int bclk; int bclk;
int sysclk; int sysclk;
int clk_id;
int freq_in;
bool is_stream_in_use[2];
struct wm8960_data pdata; struct wm8960_data pdata;
}; };
...@@ -164,8 +170,8 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec) ...@@ -164,8 +170,8 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)
if (wm8960->deemph) { if (wm8960->deemph) {
best = 1; best = 1;
for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
if (abs(deemph_settings[i] - wm8960->playback_fs) < if (abs(deemph_settings[i] - wm8960->lrclk) <
abs(deemph_settings[best] - wm8960->playback_fs)) abs(deemph_settings[best] - wm8960->lrclk))
best = i; best = i;
} }
...@@ -565,6 +571,9 @@ static struct { ...@@ -565,6 +571,9 @@ static struct {
{ 8000, 5 }, { 8000, 5 },
}; };
/* -1 for reserved value */
static const int sysclk_divs[] = { 1, -1, 2, -1 };
/* Multiply 256 for internal 256 div */ /* Multiply 256 for internal 256 div */
static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 };
...@@ -574,61 +583,110 @@ static const int bclk_divs[] = { ...@@ -574,61 +583,110 @@ static const int bclk_divs[] = {
120, 160, 220, 240, 320, 320, 320 120, 160, 220, 240, 320, 320, 320
}; };
static void wm8960_configure_clocking(struct snd_soc_codec *codec, static int wm8960_configure_clocking(struct snd_soc_codec *codec)
bool tx, int lrclk)
{ {
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
int sysclk, bclk, lrclk, freq_out, freq_in;
u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); int i, j, k;
u32 sysclk;
int i, j;
if (!(iface1 & (1<<6))) { if (!(iface1 & (1<<6))) {
dev_dbg(codec->dev, dev_dbg(codec->dev,
"Codec is slave mode, no need to configure clock\n"); "Codec is slave mode, no need to configure clock\n");
return; return 0;
} }
if (!wm8960->sysclk) { if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) {
dev_dbg(codec->dev, "No SYSCLK configured\n"); dev_err(codec->dev, "No MCLK configured\n");
return; return -EINVAL;
} }
if (!wm8960->bclk || !lrclk) { freq_in = wm8960->freq_in;
dev_dbg(codec->dev, "No audio clocks configured\n"); bclk = wm8960->bclk;
return; lrclk = wm8960->lrclk;
/*
* If it's sysclk auto mode, check if the MCLK can provide sysclk or
* not. If MCLK can provide sysclk, using MCLK to provide sysclk
* directly. Otherwise, auto select a available pll out frequency
* and set PLL.
*/
if (wm8960->clk_id == WM8960_SYSCLK_AUTO) {
/* disable the PLL and using MCLK to provide sysclk */
wm8960_set_pll(codec, 0, 0);
freq_out = freq_in;
} else if (wm8960->sysclk) {
freq_out = wm8960->sysclk;
} else {
dev_err(codec->dev, "No SYSCLK configured\n");
return -EINVAL;
} }
for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { /* check if the sysclk frequency is available. */
if (wm8960->sysclk == lrclk * dac_divs[i]) { for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { if (sysclk_divs[i] == -1)
sysclk = wm8960->bclk * bclk_divs[j] / 10; continue;
if (wm8960->sysclk == sysclk) sysclk = freq_out / sysclk_divs[i];
for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
if (sysclk == dac_divs[j] * lrclk) {
for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
if (sysclk == bclk * bclk_divs[k] / 10)
break;
if (k != ARRAY_SIZE(bclk_divs))
break; break;
} }
if(j != ARRAY_SIZE(bclk_divs)) }
if (j != ARRAY_SIZE(dac_divs))
break;
}
if (i != ARRAY_SIZE(sysclk_divs)) {
goto configure_clock;
} else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
dev_err(codec->dev, "failed to configure clock\n");
return -EINVAL;
}
/* get a available pll out frequency and set pll */
for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
if (sysclk_divs[i] == -1)
continue;
for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
sysclk = lrclk * dac_divs[j];
freq_out = sysclk * sysclk_divs[i];
for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
if (sysclk == bclk * bclk_divs[k] / 10 &&
is_pll_freq_available(freq_in, freq_out)) {
wm8960_set_pll(codec,
freq_in, freq_out);
break;
} else {
continue;
}
}
if (k != ARRAY_SIZE(bclk_divs))
break; break;
} }
if (j != ARRAY_SIZE(dac_divs))
break;
} }
if (i == ARRAY_SIZE(dac_divs)) { if (i == ARRAY_SIZE(sysclk_divs)) {
dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); dev_err(codec->dev, "failed to configure clock\n");
return; return -EINVAL;
} }
/* configure_clock:
* configure frame clock. If ADCLRC configure as GPIO pin, DACLRC /* configure sysclk clock */
* pin is used as a frame clock for ADCs and DACs. snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1);
*/
if (iface2 & (1<<6)) /* configure frame clock */
snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3);
else if (tx) snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6);
snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
else if (!tx)
snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6);
/* configure bit clock */ /* configure bit clock */
snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k);
return 0;
} }
static int wm8960_hw_params(struct snd_pcm_substream *substream, static int wm8960_hw_params(struct snd_pcm_substream *substream,
...@@ -667,9 +725,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, ...@@ -667,9 +725,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
wm8960->lrclk = params_rate(params);
/* Update filters for the new rate */ /* Update filters for the new rate */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (tx) {
wm8960->playback_fs = params_rate(params);
wm8960_set_deemph(codec); wm8960_set_deemph(codec);
} else { } else {
for (i = 0; i < ARRAY_SIZE(alc_rates); i++) for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
...@@ -682,7 +740,23 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, ...@@ -682,7 +740,23 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
/* set iface */ /* set iface */
snd_soc_write(codec, WM8960_IFACE1, iface); snd_soc_write(codec, WM8960_IFACE1, iface);
wm8960_configure_clocking(codec, tx, params_rate(params)); wm8960->is_stream_in_use[tx] = true;
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON &&
!wm8960->is_stream_in_use[!tx])
return wm8960_configure_clocking(codec);
return 0;
}
static int wm8960_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
wm8960->is_stream_in_use[tx] = false;
return 0; return 0;
} }
...@@ -702,6 +776,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, ...@@ -702,6 +776,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
int ret; int ret;
switch (level) { switch (level) {
...@@ -721,11 +796,22 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, ...@@ -721,11 +796,22 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
} }
} }
ret = wm8960_configure_clocking(codec);
if (ret)
return ret;
/* Set VMID to 2x50k */ /* Set VMID to 2x50k */
snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
break; break;
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/*
* If it's sysclk auto mode, and the pll is enabled,
* disable the pll
*/
if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
wm8960_set_pll(codec, 0, 0);
if (!IS_ERR(wm8960->mclk)) if (!IS_ERR(wm8960->mclk))
clk_disable_unprepare(wm8960->mclk); clk_disable_unprepare(wm8960->mclk);
break; break;
...@@ -780,6 +866,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, ...@@ -780,6 +866,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
int reg, ret; int reg, ret;
switch (level) { switch (level) {
...@@ -831,9 +918,21 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, ...@@ -831,9 +918,21 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
return ret; return ret;
} }
} }
ret = wm8960_configure_clocking(codec);
if (ret)
return ret;
break; break;
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/*
* If it's sysclk auto mode, and the pll is enabled,
* disable the pll
*/
if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
wm8960_set_pll(codec, 0, 0);
if (!IS_ERR(wm8960->mclk)) if (!IS_ERR(wm8960->mclk))
clk_disable_unprepare(wm8960->mclk); clk_disable_unprepare(wm8960->mclk);
...@@ -892,6 +991,28 @@ struct _pll_div { ...@@ -892,6 +991,28 @@ struct _pll_div {
u32 k:24; u32 k:24;
}; };
static bool is_pll_freq_available(unsigned int source, unsigned int target)
{
unsigned int Ndiv;
if (source == 0 || target == 0)
return false;
/* Scale up target to PLL operating frequency */
target *= 4;
Ndiv = target / source;
if (Ndiv < 6) {
source >>= 1;
Ndiv = target / source;
}
if ((Ndiv < 6) || (Ndiv > 12))
return false;
return true;
}
/* The size in bits of the pll divide multiplied by 10 /* The size in bits of the pll divide multiplied by 10
* to allow rounding later */ * to allow rounding later */
#define FIXED_PLL_SIZE ((1 << 24) * 10) #define FIXED_PLL_SIZE ((1 << 24) * 10)
...@@ -943,10 +1064,9 @@ static int pll_factors(unsigned int source, unsigned int target, ...@@ -943,10 +1064,9 @@ static int pll_factors(unsigned int source, unsigned int target,
return 0; return 0;
} }
static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, static int wm8960_set_pll(struct snd_soc_codec *codec,
int source, unsigned int freq_in, unsigned int freq_out) unsigned int freq_in, unsigned int freq_out)
{ {
struct snd_soc_codec *codec = codec_dai->codec;
u16 reg; u16 reg;
static struct _pll_div pll_div; static struct _pll_div pll_div;
int ret; int ret;
...@@ -986,6 +1106,20 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, ...@@ -986,6 +1106,20 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
return 0; return 0;
} }
static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
wm8960->freq_in = freq_in;
if (pll_id == WM8960_SYSCLK_AUTO)
return 0;
return wm8960_set_pll(codec, freq_in, freq_out);
}
static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
int div_id, int div) int div_id, int div)
{ {
...@@ -1043,11 +1177,14 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, ...@@ -1043,11 +1177,14 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
snd_soc_update_bits(codec, WM8960_CLOCK1, snd_soc_update_bits(codec, WM8960_CLOCK1,
0x1, WM8960_SYSCLK_PLL); 0x1, WM8960_SYSCLK_PLL);
break; break;
case WM8960_SYSCLK_AUTO:
break;
default: default:
return -EINVAL; return -EINVAL;
} }
wm8960->sysclk = freq; wm8960->sysclk = freq;
wm8960->clk_id = clk_id;
return 0; return 0;
} }
...@@ -1060,6 +1197,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, ...@@ -1060,6 +1197,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
static const struct snd_soc_dai_ops wm8960_dai_ops = { static const struct snd_soc_dai_ops wm8960_dai_ops = {
.hw_params = wm8960_hw_params, .hw_params = wm8960_hw_params,
.hw_free = wm8960_hw_free,
.digital_mute = wm8960_mute, .digital_mute = wm8960_mute,
.set_fmt = wm8960_set_dai_fmt, .set_fmt = wm8960_set_dai_fmt,
.set_clkdiv = wm8960_set_dai_clkdiv, .set_clkdiv = wm8960_set_dai_clkdiv,
......
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
#define WM8960_SYSCLK_MCLK (0 << 0) #define WM8960_SYSCLK_MCLK (0 << 0)
#define WM8960_SYSCLK_PLL (1 << 0) #define WM8960_SYSCLK_PLL (1 << 0)
#define WM8960_SYSCLK_AUTO (2 << 0)
#define WM8960_DAC_DIV_1 (0 << 3) #define WM8960_DAC_DIV_1 (0 << 3)
#define WM8960_DAC_DIV_1_5 (1 << 3) #define WM8960_DAC_DIV_1_5 (1 << 3)
......
...@@ -84,66 +84,6 @@ static const struct reg_default wm8983_defaults[] = { ...@@ -84,66 +84,6 @@ static const struct reg_default wm8983_defaults[] = {
{ 0x3D, 0x0000 }, /* R61 - BIAS CTRL */ { 0x3D, 0x0000 }, /* R61 - BIAS CTRL */
}; };
static const struct wm8983_reg_access {
u16 read; /* Mask of readable bits */
u16 write; /* Mask of writable bits */
} wm8983_access_masks[WM8983_MAX_REGISTER + 1] = {
[0x00] = { 0x0000, 0x01FF }, /* R0 - Software Reset */
[0x01] = { 0x0000, 0x01FF }, /* R1 - Power management 1 */
[0x02] = { 0x0000, 0x01FF }, /* R2 - Power management 2 */
[0x03] = { 0x0000, 0x01EF }, /* R3 - Power management 3 */
[0x04] = { 0x0000, 0x01FF }, /* R4 - Audio Interface */
[0x05] = { 0x0000, 0x003F }, /* R5 - Companding control */
[0x06] = { 0x0000, 0x01FD }, /* R6 - Clock Gen control */
[0x07] = { 0x0000, 0x000F }, /* R7 - Additional control */
[0x08] = { 0x0000, 0x003F }, /* R8 - GPIO Control */
[0x09] = { 0x0000, 0x0070 }, /* R9 - Jack Detect Control 1 */
[0x0A] = { 0x0000, 0x004F }, /* R10 - DAC Control */
[0x0B] = { 0x0000, 0x01FF }, /* R11 - Left DAC digital Vol */
[0x0C] = { 0x0000, 0x01FF }, /* R12 - Right DAC digital vol */
[0x0D] = { 0x0000, 0x00FF }, /* R13 - Jack Detect Control 2 */
[0x0E] = { 0x0000, 0x01FB }, /* R14 - ADC Control */
[0x0F] = { 0x0000, 0x01FF }, /* R15 - Left ADC Digital Vol */
[0x10] = { 0x0000, 0x01FF }, /* R16 - Right ADC Digital Vol */
[0x12] = { 0x0000, 0x017F }, /* R18 - EQ1 - low shelf */
[0x13] = { 0x0000, 0x017F }, /* R19 - EQ2 - peak 1 */
[0x14] = { 0x0000, 0x017F }, /* R20 - EQ3 - peak 2 */
[0x15] = { 0x0000, 0x017F }, /* R21 - EQ4 - peak 3 */
[0x16] = { 0x0000, 0x007F }, /* R22 - EQ5 - high shelf */
[0x18] = { 0x0000, 0x01FF }, /* R24 - DAC Limiter 1 */
[0x19] = { 0x0000, 0x007F }, /* R25 - DAC Limiter 2 */
[0x1B] = { 0x0000, 0x01FF }, /* R27 - Notch Filter 1 */
[0x1C] = { 0x0000, 0x017F }, /* R28 - Notch Filter 2 */
[0x1D] = { 0x0000, 0x017F }, /* R29 - Notch Filter 3 */
[0x1E] = { 0x0000, 0x017F }, /* R30 - Notch Filter 4 */
[0x20] = { 0x0000, 0x01BF }, /* R32 - ALC control 1 */
[0x21] = { 0x0000, 0x00FF }, /* R33 - ALC control 2 */
[0x22] = { 0x0000, 0x01FF }, /* R34 - ALC control 3 */
[0x23] = { 0x0000, 0x000F }, /* R35 - Noise Gate */
[0x24] = { 0x0000, 0x001F }, /* R36 - PLL N */
[0x25] = { 0x0000, 0x003F }, /* R37 - PLL K 1 */
[0x26] = { 0x0000, 0x01FF }, /* R38 - PLL K 2 */
[0x27] = { 0x0000, 0x01FF }, /* R39 - PLL K 3 */
[0x29] = { 0x0000, 0x000F }, /* R41 - 3D control */
[0x2A] = { 0x0000, 0x01E7 }, /* R42 - OUT4 to ADC */
[0x2B] = { 0x0000, 0x01BF }, /* R43 - Beep control */
[0x2C] = { 0x0000, 0x0177 }, /* R44 - Input ctrl */
[0x2D] = { 0x0000, 0x01FF }, /* R45 - Left INP PGA gain ctrl */
[0x2E] = { 0x0000, 0x01FF }, /* R46 - Right INP PGA gain ctrl */
[0x2F] = { 0x0000, 0x0177 }, /* R47 - Left ADC BOOST ctrl */
[0x30] = { 0x0000, 0x0177 }, /* R48 - Right ADC BOOST ctrl */
[0x31] = { 0x0000, 0x007F }, /* R49 - Output ctrl */
[0x32] = { 0x0000, 0x01FF }, /* R50 - Left mixer ctrl */
[0x33] = { 0x0000, 0x01FF }, /* R51 - Right mixer ctrl */
[0x34] = { 0x0000, 0x01FF }, /* R52 - LOUT1 (HP) volume ctrl */
[0x35] = { 0x0000, 0x01FF }, /* R53 - ROUT1 (HP) volume ctrl */
[0x36] = { 0x0000, 0x01FF }, /* R54 - LOUT2 (SPK) volume ctrl */
[0x37] = { 0x0000, 0x01FF }, /* R55 - ROUT2 (SPK) volume ctrl */
[0x38] = { 0x0000, 0x004F }, /* R56 - OUT3 mixer ctrl */
[0x39] = { 0x0000, 0x00FF }, /* R57 - OUT4 (MONO) mix ctrl */
[0x3D] = { 0x0000, 0x0100 } /* R61 - BIAS CTRL */
};
/* vol/gain update regs */ /* vol/gain update regs */
static const int vol_update_regs[] = { static const int vol_update_regs[] = {
WM8983_LEFT_DAC_DIGITAL_VOL, WM8983_LEFT_DAC_DIGITAL_VOL,
...@@ -605,12 +545,19 @@ static int eqmode_put(struct snd_kcontrol *kcontrol, ...@@ -605,12 +545,19 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
static bool wm8983_readable(struct device *dev, unsigned int reg) static bool wm8983_writeable(struct device *dev, unsigned int reg)
{ {
if (reg > WM8983_MAX_REGISTER) switch (reg) {
return 0; case WM8983_SOFTWARE_RESET ... WM8983_RIGHT_ADC_DIGITAL_VOL:
case WM8983_EQ1_LOW_SHELF ... WM8983_DAC_LIMITER_2:
return wm8983_access_masks[reg].read != 0; case WM8983_NOTCH_FILTER_1 ... WM8983_NOTCH_FILTER_4:
case WM8983_ALC_CONTROL_1 ... WM8983_PLL_K_3:
case WM8983_3D_CONTROL ... WM8983_OUT4_MONO_MIX_CTRL:
case WM8983_BIAS_CTRL:
return true;
default:
return false;
}
} }
static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute) static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute)
...@@ -1048,8 +995,9 @@ static const struct regmap_config wm8983_regmap = { ...@@ -1048,8 +995,9 @@ static const struct regmap_config wm8983_regmap = {
.reg_defaults = wm8983_defaults, .reg_defaults = wm8983_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8983_defaults), .num_reg_defaults = ARRAY_SIZE(wm8983_defaults),
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
.max_register = WM8983_MAX_REGISTER,
.readable_reg = wm8983_readable, .writeable_reg = wm8983_writeable,
}; };
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment