Skip to content

Commit

Permalink
Merge remote-tracking branches 'asoc/topic/wm8580', 'asoc/topic/wm875…
Browse files Browse the repository at this point in the history
…3', 'asoc/topic/wm8978', 'asoc/topic/wm9081' and 'asoc/topic/wm9705' into asoc-next
  • Loading branch information
Mark Brown committed Dec 12, 2016
6 parents dc42c6c + 60bc617 + 68b24a2 + fbd972d + e2d5759 + d41a5b4 commit fb4587d
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 130 deletions.
4 changes: 2 additions & 2 deletions Documentation/devicetree/bindings/sound/wm8580.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
WM8580 audio CODEC
WM8580 and WM8581 audio CODEC

This device supports I2C only.

Required properties:

- compatible : "wlf,wm8580"
- compatible : "wlf,wm8580", "wlf,wm8581"

- reg : the I2C address of the device.

Expand Down
4 changes: 3 additions & 1 deletion sound/soc/codecs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ config SND_SOC_WM8523
depends on I2C

config SND_SOC_WM8580
tristate "Wolfson Microelectronics WM8523 CODEC"
tristate "Wolfson Microelectronics WM8580 and WM8581 CODECs"
depends on I2C

config SND_SOC_WM8711
Expand Down Expand Up @@ -1072,12 +1072,14 @@ config SND_SOC_WM8998

config SND_SOC_WM9081
tristate
depends on I2C

config SND_SOC_WM9090
tristate

config SND_SOC_WM9705
tristate
select REGMAP_AC97

config SND_SOC_WM9712
tristate
Expand Down
123 changes: 90 additions & 33 deletions sound/soc/codecs/wm8580.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* wm8580.c -- WM8580 ALSA Soc Audio driver
* wm8580.c -- WM8580 and WM8581 ALSA Soc Audio driver
*
* Copyright 2008-12 Wolfson Microelectronics PLC.
*
Expand All @@ -12,6 +12,9 @@
* The WM8580 is a multichannel codec with S/PDIF support, featuring six
* DAC channels and two ADC channels.
*
* The WM8581 is a multichannel codec with S/PDIF support, featuring eight
* DAC channels and two ADC channels.
*
* Currently only the primary audio interface is supported - S/PDIF and
* the secondary audio interfaces are not.
*/
Expand Down Expand Up @@ -65,6 +68,8 @@
#define WM8580_DIGITAL_ATTENUATION_DACR2 0x17
#define WM8580_DIGITAL_ATTENUATION_DACL3 0x18
#define WM8580_DIGITAL_ATTENUATION_DACR3 0x19
#define WM8581_DIGITAL_ATTENUATION_DACL4 0x1A
#define WM8581_DIGITAL_ATTENUATION_DACR4 0x1B
#define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C
#define WM8580_ADC_CONTROL1 0x1D
#define WM8580_SPDTXCHAN0 0x1E
Expand Down Expand Up @@ -236,12 +241,17 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
"PVDD",
};

struct wm8580_driver_data {
int num_dacs;
};

/* codec private data */
struct wm8580_priv {
struct regmap *regmap;
struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
struct pll_state a;
struct pll_state b;
const struct wm8580_driver_data *drvdata;
int sysclk[2];
};

Expand Down Expand Up @@ -306,6 +316,19 @@ SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
};

static const struct snd_kcontrol_new wm8581_snd_controls[] = {
SOC_DOUBLE_R_EXT_TLV("DAC4 Playback Volume",
WM8581_DIGITAL_ATTENUATION_DACL4,
WM8581_DIGITAL_ATTENUATION_DACR4,
0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),

SOC_SINGLE("DAC4 Deemphasis Switch", WM8580_DAC_CONTROL3, 3, 1, 0),

SOC_DOUBLE("DAC4 Invert Switch", WM8580_DAC_CONTROL4, 8, 7, 1, 0),

SOC_SINGLE("DAC4 Switch", WM8580_DAC_CONTROL5, 3, 1, 1),
};

static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),
SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1),
Expand All @@ -324,6 +347,13 @@ SND_SOC_DAPM_INPUT("AINL"),
SND_SOC_DAPM_INPUT("AINR"),
};

static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC4", "Playback", WM8580_PWRDN1, 5, 1),

SND_SOC_DAPM_OUTPUT("VOUT4L"),
SND_SOC_DAPM_OUTPUT("VOUT4R"),
};

static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {
{ "VOUT1L", NULL, "DAC1" },
{ "VOUT1R", NULL, "DAC1" },
Expand All @@ -338,6 +368,11 @@ static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {
{ "ADC", NULL, "AINR" },
};

static const struct snd_soc_dapm_route wm8581_dapm_routes[] = {
{ "VOUT4L", NULL, "DAC4" },
{ "VOUT4R", NULL, "DAC4" },
};

/* PLL divisors */
struct _pll_div {
u32 prescale:1;
Expand Down Expand Up @@ -815,10 +850,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
return 0;
}

static int wm8580_playback_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);

return snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 1, wm8580->drvdata->num_dacs * 2);
}

#define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)

static const struct snd_soc_dai_ops wm8580_dai_ops_playback = {
.startup = wm8580_playback_startup,
.set_sysclk = wm8580_set_sysclk,
.hw_params = wm8580_paif_hw_params,
.set_fmt = wm8580_set_paif_dai_fmt,
Expand All @@ -842,7 +888,6 @@ static struct snd_soc_dai_driver wm8580_dai[] = {
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 6,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = WM8580_FORMATS,
},
Expand All @@ -865,8 +910,22 @@ static struct snd_soc_dai_driver wm8580_dai[] = {
static int wm8580_probe(struct snd_soc_codec *codec)
{
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int ret = 0;

switch (wm8580->drvdata->num_dacs) {
case 4:
snd_soc_add_codec_controls(codec, wm8581_snd_controls,
ARRAY_SIZE(wm8581_snd_controls));
snd_soc_dapm_new_controls(dapm, wm8581_dapm_widgets,
ARRAY_SIZE(wm8581_dapm_widgets));
snd_soc_dapm_add_routes(dapm, wm8581_dapm_routes,
ARRAY_SIZE(wm8581_dapm_routes));
break;
default:
break;
}

ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
wm8580->supplies);
if (ret != 0) {
Expand Down Expand Up @@ -914,12 +973,6 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
},
};

static const struct of_device_id wm8580_of_match[] = {
{ .compatible = "wlf,wm8580" },
{ },
};
MODULE_DEVICE_TABLE(of, wm8580_of_match);

static const struct regmap_config wm8580_regmap = {
.reg_bits = 7,
.val_bits = 9,
Expand All @@ -932,10 +985,25 @@ static const struct regmap_config wm8580_regmap = {
.volatile_reg = wm8580_volatile,
};

#if IS_ENABLED(CONFIG_I2C)
static const struct wm8580_driver_data wm8580_data = {
.num_dacs = 3,
};

static const struct wm8580_driver_data wm8581_data = {
.num_dacs = 4,
};

static const struct of_device_id wm8580_of_match[] = {
{ .compatible = "wlf,wm8580", .data = &wm8580_data },
{ .compatible = "wlf,wm8581", .data = &wm8581_data },
{ },
};
MODULE_DEVICE_TABLE(of, wm8580_of_match);

static int wm8580_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
const struct of_device_id *of_id;
struct wm8580_priv *wm8580;
int ret, i;

Expand All @@ -960,6 +1028,15 @@ static int wm8580_i2c_probe(struct i2c_client *i2c,

i2c_set_clientdata(i2c, wm8580);

of_id = of_match_device(wm8580_of_match, &i2c->dev);
if (of_id)
wm8580->drvdata = of_id->data;

if (!wm8580->drvdata) {
dev_err(&i2c->dev, "failed to find driver data\n");
return -EINVAL;
}

ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));

Expand All @@ -973,7 +1050,8 @@ static int wm8580_i2c_remove(struct i2c_client *client)
}

static const struct i2c_device_id wm8580_i2c_id[] = {
{ "wm8580", 0 },
{ "wm8580", (kernel_ulong_t)&wm8580_data },
{ "wm8581", (kernel_ulong_t)&wm8581_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
Expand All @@ -987,31 +1065,10 @@ static struct i2c_driver wm8580_i2c_driver = {
.remove = wm8580_i2c_remove,
.id_table = wm8580_i2c_id,
};
#endif

static int __init wm8580_modinit(void)
{
int ret = 0;

#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8580_i2c_driver);
if (ret != 0) {
pr_err("Failed to register WM8580 I2C driver: %d\n", ret);
}
#endif

return ret;
}
module_init(wm8580_modinit);

static void __exit wm8580_exit(void)
{
#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8580_i2c_driver);
#endif
}
module_exit(wm8580_exit);
module_i2c_driver(wm8580_i2c_driver);

MODULE_DESCRIPTION("ASoC WM8580 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
MODULE_LICENSE("GPL");
3 changes: 0 additions & 3 deletions sound/soc/codecs/wm8753.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,4 @@
#define WM8753_VXCLK_DIV_8 (3 << 6)
#define WM8753_VXCLK_DIV_16 (4 << 6)

#define WM8753_DAI_HIFI 0
#define WM8753_DAI_VOICE 1

#endif
2 changes: 1 addition & 1 deletion sound/soc/codecs/wm8978.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ enum wm8978_clk_id {
};

enum wm8978_sysclk_src {
WM8978_MCLK = 0,
WM8978_PLL,
WM8978_MCLK
};

#endif /* __WM8978_H__ */
2 changes: 0 additions & 2 deletions sound/soc/codecs/wm9081.c
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,6 @@ static const struct regmap_config wm9081_regmap = {
.cache_type = REGCACHE_RBTREE,
};

#if IS_ENABLED(CONFIG_I2C)
static int wm9081_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
Expand Down Expand Up @@ -1384,7 +1383,6 @@ static struct i2c_driver wm9081_i2c_driver = {
.remove = wm9081_i2c_remove,
.id_table = wm9081_i2c_id,
};
#endif

module_i2c_driver(wm9081_i2c_driver);

Expand Down
Loading

0 comments on commit fb4587d

Please sign in to comment.