From e75a52c6723a61a0d768ee53794e86b7edbe54f0 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Thu, 6 Jun 2013 19:38:45 +0800 Subject: ASoC: WM8962: Create default platform data structure Embed a copy of struct wm8962_pdata in stuct wm8962_priv so that there's no need to check validity of pdata any more. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 68 +++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index e9710280e5e1..d56dd867057d 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -51,6 +51,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = { /* codec private data */ struct wm8962_priv { + struct wm8962_pdata pdata; struct regmap *regmap; struct snd_soc_codec *codec; @@ -2345,12 +2346,13 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = { static int wm8962_add_widgets(struct snd_soc_codec *codec) { - struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); + struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_pdata *pdata = &wm8962->pdata; struct snd_soc_dapm_context *dapm = &codec->dapm; snd_soc_add_codec_controls(codec, wm8962_snd_controls, ARRAY_SIZE(wm8962_snd_controls)); - if (pdata && pdata->spk_mono) + if (pdata->spk_mono) snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls, ARRAY_SIZE(wm8962_spk_mono_controls)); else @@ -2360,7 +2362,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_new_controls(dapm, wm8962_dapm_widgets, ARRAY_SIZE(wm8962_dapm_widgets)); - if (pdata && pdata->spk_mono) + if (pdata->spk_mono) snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_mono_widgets, ARRAY_SIZE(wm8962_dapm_spk_mono_widgets)); else @@ -2369,7 +2371,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(dapm, wm8962_intercon, ARRAY_SIZE(wm8962_intercon)); - if (pdata && pdata->spk_mono) + if (pdata->spk_mono) snd_soc_dapm_add_routes(dapm, wm8962_spk_mono_intercon, ARRAY_SIZE(wm8962_spk_mono_intercon)); else @@ -3333,14 +3335,14 @@ static struct gpio_chip wm8962_template_chip = { static void wm8962_init_gpio(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); + struct wm8962_pdata *pdata = &wm8962->pdata; int ret; wm8962->gpio_chip = wm8962_template_chip; wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO; wm8962->gpio_chip.dev = codec->dev; - if (pdata && pdata->gpio_base) + if (pdata->gpio_base) wm8962->gpio_chip.base = pdata->gpio_base; else wm8962->gpio_chip.base = -1; @@ -3373,7 +3375,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) { int ret; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); + struct wm8962_pdata *pdata = &wm8962->pdata; u16 *reg_cache = codec->reg_cache; int i, trigger, irq_pol; bool dmicclk, dmicdat; @@ -3421,30 +3423,28 @@ static int wm8962_probe(struct snd_soc_codec *codec) WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, 0); - if (pdata) { - /* Apply static configuration for GPIOs */ - for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) - if (pdata->gpio_init[i]) { - wm8962_set_gpio_mode(codec, i + 1); - snd_soc_write(codec, 0x200 + i, - pdata->gpio_init[i] & 0xffff); - } + /* Apply static configuration for GPIOs */ + for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) + if (pdata->gpio_init[i]) { + wm8962_set_gpio_mode(codec, i + 1); + snd_soc_write(codec, 0x200 + i, + pdata->gpio_init[i] & 0xffff); + } - /* Put the speakers into mono mode? */ - if (pdata->spk_mono) - reg_cache[WM8962_CLASS_D_CONTROL_2] - |= WM8962_SPK_MONO; - - /* Micbias setup, detection enable and detection - * threasholds. */ - if (pdata->mic_cfg) - snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4, - WM8962_MICDET_ENA | - WM8962_MICDET_THR_MASK | - WM8962_MICSHORT_THR_MASK | - WM8962_MICBIAS_LVL, - pdata->mic_cfg); - } + /* Put the speakers into mono mode? */ + if (pdata->spk_mono) + reg_cache[WM8962_CLASS_D_CONTROL_2] + |= WM8962_SPK_MONO; + + /* Micbias setup, detection enable and detection + * threasholds. */ + if (pdata->mic_cfg) + snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4, + WM8962_MICDET_ENA | + WM8962_MICDET_THR_MASK | + WM8962_MICSHORT_THR_MASK | + WM8962_MICBIAS_LVL, + pdata->mic_cfg); /* Latch volume update bits */ snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME, @@ -3506,7 +3506,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) wm8962_init_gpio(codec); if (wm8962->irq) { - if (pdata && pdata->irq_active_low) { + if (pdata->irq_active_low) { trigger = IRQF_TRIGGER_LOW; irq_pol = WM8962_IRQ_POL; } else { @@ -3603,6 +3603,10 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, init_completion(&wm8962->fll_lock); wm8962->irq = i2c->irq; + /* If platform data was supplied, update the default data in priv */ + if (pdata) + memcpy(&wm8962->pdata, pdata, sizeof(struct wm8962_pdata)); + for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) wm8962->supplies[i].supply = wm8962_supply_names[i]; @@ -3666,7 +3670,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, goto err_enable; } - if (pdata && pdata->in4_dc_measure) { + if (wm8962->pdata.in4_dc_measure) { ret = regmap_register_patch(wm8962->regmap, wm8962_dc_measure, ARRAY_SIZE(wm8962_dc_measure)); -- cgit v1.2.3-59-g8ed1b From d74e9e7090aeb9b61e683e5abf7ca70fa18f846b Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 7 Jun 2013 11:23:27 +0800 Subject: ASoC: wm8962: Add device tree binding Document the device tree binding for the WM8962 codec, and modify the driver to extract platform data from the device tree, if present. Based on work of WM8903 by Stephen Warren Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8962.txt | 23 ++++++++++++++ sound/soc/codecs/wm8962.c | 35 +++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/wm8962.txt b/Documentation/devicetree/bindings/sound/wm8962.txt index dceb3b1c2bb7..7f82b59ec8f9 100644 --- a/Documentation/devicetree/bindings/sound/wm8962.txt +++ b/Documentation/devicetree/bindings/sound/wm8962.txt @@ -8,9 +8,32 @@ Required properties: - reg : the I2C address of the device. +Optional properties: + - spk-mono: This is a boolean property. If present, the SPK_MONO bit + of R51 (Class D Control 2) gets set, indicating that the speaker is + in mono mode. + + - mic-cfg : Default register value for R48 (Additional Control 4). + If absent, the default should be the register default. + + - gpio-cfg : A list of GPIO configuration register values. The list must + be 6 entries long. If absent, no configuration of these registers is + performed. And note that only the value within [0x0, 0xffff] is valid. + Any other value is regarded as setting the GPIO register by its reset + value 0x0. + Example: codec: wm8962@1a { compatible = "wlf,wm8962"; reg = <0x1a>; + + gpio-cfg = < + 0x0000 /* 0:Default */ + 0x0000 /* 1:Default */ + 0x0013 /* 2:FN_DMICCLK */ + 0x0000 /* 3:Default */ + 0x8014 /* 4:FN_DMICCDAT */ + 0x0000 /* 5:Default */ + >; }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index d56dd867057d..26219ea2bbb5 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3584,6 +3584,34 @@ static const struct regmap_config wm8962_regmap = { .cache_type = REGCACHE_RBTREE, }; +static int wm8962_set_pdata_from_of(struct i2c_client *i2c, + struct wm8962_pdata *pdata) +{ + const struct device_node *np = i2c->dev.of_node; + u32 val32; + int i; + + if (of_property_read_bool(np, "spk-mono")) + pdata->spk_mono = true; + + if (of_property_read_u32(np, "mic-cfg", &val32) >= 0) + pdata->mic_cfg = val32; + + if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_init, + ARRAY_SIZE(pdata->gpio_init)) >= 0) + for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) { + /* + * The range of GPIO register value is [0x0, 0xffff] + * While the default value of each register is 0x0 + * Any other value will be regarded as default value + */ + if (pdata->gpio_init[i] > 0xffff) + pdata->gpio_init[i] = 0x0; + } + + return 0; +} + static int wm8962_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -3604,8 +3632,13 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, wm8962->irq = i2c->irq; /* If platform data was supplied, update the default data in priv */ - if (pdata) + if (pdata) { memcpy(&wm8962->pdata, pdata, sizeof(struct wm8962_pdata)); + } else if (i2c->dev.of_node) { + ret = wm8962_set_pdata_from_of(i2c, &wm8962->pdata); + if (ret != 0) + return ret; + } for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) wm8962->supplies[i].supply = wm8962_supply_names[i]; -- cgit v1.2.3-59-g8ed1b From 9c24b1672283644adf871244771ebf387dd73f90 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 7 Jun 2013 16:19:58 +0100 Subject: ASoC: wm8962: Restore device state after reset in runtime resume After the device has been reset we need to repeat the same initialisation we do on probe to make sure that the device is in a known state. Tested-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 26219ea2bbb5..7a7a0567e547 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3756,6 +3756,21 @@ static int wm8962_runtime_resume(struct device *dev) wm8962_reset(wm8962); + /* SYSCLK defaults to on; make sure it is off so we can safely + * write to registers if the device is declocked. + */ + regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, + WM8962_SYSCLK_ENA, 0); + + /* Ensure we have soft control over all registers */ + regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, + WM8962_CLKREG_OVD, WM8962_CLKREG_OVD); + + /* Ensure that the oscillator and PLLs are disabled */ + regmap_update_bits(wm8962->regmap, WM8962_PLL2, + WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, + 0); + regcache_sync(wm8962->regmap); return 0; -- cgit v1.2.3-59-g8ed1b