Skip to content

Commit

Permalink
ASoC: wm8741: Add differential mono mode support
Browse files Browse the repository at this point in the history
The WM8741 DAC supports several differential output modes (stereo,
stereo reversed, mono left, mono right). Add platform data and DT
bindings to configure it.

Signed-off-by: Sergej Sawazki <ce3a@gmx.de>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Sergej Sawazki authored and Mark Brown committed May 13, 2015
1 parent b787f68 commit c354b54
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 13 deletions.
11 changes: 11 additions & 0 deletions Documentation/devicetree/bindings/sound/wm8741.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@ Required properties:
- reg : the I2C address of the device for I2C, the chip select
number for SPI.

Optional properties:

- diff-mode: Differential output mode configuration. Default value for field
DIFF in register R8 (MODE_CONTROL_2). If absent, the default is 0, shall be:
0 = stereo
1 = mono left
2 = stereo reversed
3 = mono right

Example:

codec: wm8741@1a {
compatible = "wlf,wm8741";
reg = <0x1a>;

diff-mode = <3>;
};
129 changes: 116 additions & 13 deletions sound/soc/codecs/wm8741.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {

/* codec private data */
struct wm8741_priv {
struct wm8741_platform_data pdata;
struct regmap *regmap;
struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
unsigned int sysclk;
Expand Down Expand Up @@ -87,13 +88,27 @@ static int wm8741_reset(struct snd_soc_codec *codec)
static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);

static const struct snd_kcontrol_new wm8741_snd_controls[] = {
static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = {
SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
};

static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = {
SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
1, 255, 1, dac_tlv_fine),
SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
0, 511, 1, dac_tlv),
};

static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = {
SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
1, 255, 1, dac_tlv_fine),
SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION,
0, 511, 1, dac_tlv),
};

static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
Expand Down Expand Up @@ -398,7 +413,7 @@ static struct snd_soc_dai_driver wm8741_dai = {
.name = "wm8741",
.playback = {
.stream_name = "Playback",
.channels_min = 2, /* Mono modes not yet supported */
.channels_min = 2,
.channels_max = 2,
.rates = WM8741_RATES,
.formats = WM8741_FORMATS,
Expand All @@ -416,6 +431,65 @@ static int wm8741_resume(struct snd_soc_codec *codec)
#define wm8741_resume NULL
#endif

static int wm8741_configure(struct snd_soc_codec *codec)
{
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);

/* Configure differential mode */
switch (wm8741->pdata.diff_mode) {
case WM8741_DIFF_MODE_STEREO:
case WM8741_DIFF_MODE_STEREO_REVERSED:
case WM8741_DIFF_MODE_MONO_LEFT:
case WM8741_DIFF_MODE_MONO_RIGHT:
snd_soc_update_bits(codec, WM8741_MODE_CONTROL_2,
WM8741_DIFF_MASK,
wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT);
break;
default:
return -EINVAL;
}

/* Change some default settings - latch VU */
snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
WM8741_UPDATELL, WM8741_UPDATELL);
snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
WM8741_UPDATELM, WM8741_UPDATELM);
snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
WM8741_UPDATERL, WM8741_UPDATERL);
snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
WM8741_UPDATERM, WM8741_UPDATERM);

return 0;
}

static int wm8741_add_controls(struct snd_soc_codec *codec)
{
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);

switch (wm8741->pdata.diff_mode) {
case WM8741_DIFF_MODE_STEREO:
case WM8741_DIFF_MODE_STEREO_REVERSED:
snd_soc_add_codec_controls(codec,
wm8741_snd_controls_stereo,
ARRAY_SIZE(wm8741_snd_controls_stereo));
break;
case WM8741_DIFF_MODE_MONO_LEFT:
snd_soc_add_codec_controls(codec,
wm8741_snd_controls_mono_left,
ARRAY_SIZE(wm8741_snd_controls_mono_left));
break;
case WM8741_DIFF_MODE_MONO_RIGHT:
snd_soc_add_codec_controls(codec,
wm8741_snd_controls_mono_right,
ARRAY_SIZE(wm8741_snd_controls_mono_right));
break;
default:
return -EINVAL;
}

return 0;
}

static int wm8741_probe(struct snd_soc_codec *codec)
{
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
Expand All @@ -434,15 +508,17 @@ static int wm8741_probe(struct snd_soc_codec *codec)
goto err_enable;
}

/* Change some default settings - latch VU */
snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
WM8741_UPDATELL, WM8741_UPDATELL);
snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
WM8741_UPDATELM, WM8741_UPDATELM);
snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
WM8741_UPDATERL, WM8741_UPDATERL);
snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
WM8741_UPDATERM, WM8741_UPDATERM);
ret = wm8741_configure(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to change default settings\n");
goto err_enable;
}

ret = wm8741_add_controls(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to add controls\n");
goto err_enable;
}

dev_dbg(codec->dev, "Successful registration\n");
return ret;
Expand All @@ -467,8 +543,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
.remove = wm8741_remove,
.resume = wm8741_resume,

.controls = wm8741_snd_controls,
.num_controls = ARRAY_SIZE(wm8741_snd_controls),
.dapm_widgets = wm8741_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets),
.dapm_routes = wm8741_dapm_routes,
Expand All @@ -493,6 +567,23 @@ static const struct regmap_config wm8741_regmap = {
.readable_reg = wm8741_readable,
};

static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
{
const struct wm8741_platform_data *pdata = dev_get_platdata(dev);
u32 diff_mode;

if (dev->of_node) {
if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode)
>= 0)
wm8741->pdata.diff_mode = diff_mode;
} else {
if (pdata != NULL)
memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata));
}

return 0;
}

#if IS_ENABLED(CONFIG_I2C)
static int wm8741_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
Expand Down Expand Up @@ -522,6 +613,12 @@ static int wm8741_i2c_probe(struct i2c_client *i2c,
return ret;
}

wm8741_set_pdata(&i2c->dev, wm8741);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret);
return ret;
}

i2c_set_clientdata(i2c, wm8741);

ret = snd_soc_register_codec(&i2c->dev,
Expand Down Expand Up @@ -582,6 +679,12 @@ static int wm8741_spi_probe(struct spi_device *spi)
return ret;
}

wm8741_set_pdata(&spi->dev, wm8741);
if (ret != 0) {
dev_err(&spi->dev, "Failed to set pdata: %d\n", ret);
return ret;
}

spi_set_drvdata(spi, wm8741);

ret = snd_soc_register_codec(&spi->dev,
Expand Down
10 changes: 10 additions & 0 deletions sound/soc/codecs/wm8741.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@
#define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */
#define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */

/* DIFF field values */
#define WM8741_DIFF_MODE_STEREO 0 /* stereo normal */
#define WM8741_DIFF_MODE_STEREO_REVERSED 2 /* stereo reversed */
#define WM8741_DIFF_MODE_MONO_LEFT 1 /* mono left */
#define WM8741_DIFF_MODE_MONO_RIGHT 3 /* mono right */

/*
* R32 (0x20) - ADDITONAL_CONTROL_1
*/
Expand All @@ -208,4 +214,8 @@

#define WM8741_SYSCLK 0

struct wm8741_platform_data {
u32 diff_mode; /* Differential Output Mode */
};

#endif

0 comments on commit c354b54

Please sign in to comment.