* [PATCH 2/3 v4 RESEND] ASoC: wm_adsp: Move DVFS control into codec driver
2014-08-08 13:32 [PATCH 1/3 v4 RESEND] mfd: arizona: Export function to control subsystem DVFS Richard Fitzgerald
@ 2014-08-08 13:34 ` Richard Fitzgerald
2014-08-08 13:35 ` [PATCH 3/3 v4 RESEND] ASoC: arizona: Add DVFS handling for sample rate control Richard Fitzgerald
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Richard Fitzgerald @ 2014-08-08 13:34 UTC (permalink / raw)
To: broonie, lee.jones, sameo, lgirdwood, perex, tiwai
Cc: alsa-devel, patches, linux-kernel
From: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
In theory the ADSP driver should not need to know
anything about the codec it is part of. But some codecs
need DVFS control based on ADSP clocking speed. This was
being handled by bundling part of the knowledge of this
into the ADSP driver.
This change removes this handling out of the ADSP driver.
A new macro WM_ADSP2_E() takes a callback function to be
called by the preloader widget in place of the default
handler, and this can be used to do codec-specific power
control.
The WM5102 driver has been updated to implement the DVFS.
Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
drivers/regulator/arizona-ldo1.c | 5 ---
sound/soc/codecs/wm5102.c | 47 +++++++++++++++++++++++-
sound/soc/codecs/wm5110.c | 2 +-
sound/soc/codecs/wm_adsp.c | 73 +-------------------------------------
sound/soc/codecs/wm_adsp.h | 13 ++++---
5 files changed, 54 insertions(+), 86 deletions(-)
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index 04f262a..47b48c8 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -78,11 +78,6 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
if (ret != 0)
return ret;
- ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
- ARIZONA_SUBSYS_MAX_FREQ, val);
- if (ret != 0)
- return ret;
-
if (val)
return 0;
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index fa24d55..0ecc89b 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -612,6 +612,49 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
return 0;
}
+static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+ unsigned int v;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to read SYSCLK state: %d\n", ret);
+ return -EIO;
+ }
+
+ v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+ if (v >= 3) {
+ ret = arizona_dvfs_up(arizona, ARIZONA_DVFS_ADSP1_RQ);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to raise DVFS: %d\n", ret);
+ return ret;
+ }
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ ret = arizona_dvfs_down(arizona, ARIZONA_DVFS_ADSP1_RQ);
+ if (ret != 0)
+ dev_warn(codec->dev,
+ "Failed to lower DVFS: %d\n", ret);
+ break;
+
+ default:
+ break;
+ }
+
+ return wm_adsp2_early_event(w, kcontrol, event);
+}
+
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1362,7 +1405,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
-WM_ADSP2("DSP1", 0),
+WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
@@ -1909,7 +1952,7 @@ static int wm5102_probe(struct platform_device *pdev)
wm5102->core.adsp[0].mem = wm5102_dsp1_regions;
wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions);
- ret = wm_adsp2_init(&wm5102->core.adsp[0], true);
+ ret = wm_adsp2_init(&wm5102->core.adsp[0]);
if (ret != 0)
return ret;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 62ef544..a2a3951 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -1688,7 +1688,7 @@ static int wm5110_probe(struct platform_device *pdev)
wm5110->core.adsp[i].num_mems
= ARRAY_SIZE(wm5110_dsp1_regions);
- ret = wm_adsp2_init(&wm5110->core.adsp[i], false);
+ ret = wm_adsp2_init(&wm5110->core.adsp[i]);
if (ret != 0)
return ret;
}
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 0600271..cdf98bf 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1539,35 +1539,6 @@ static void wm_adsp2_boot_work(struct work_struct *work)
return;
}
- if (dsp->dvfs) {
- ret = regmap_read(dsp->regmap,
- dsp->base + ADSP2_CLOCKING, &val);
- if (ret != 0) {
- adsp_err(dsp, "Failed to read clocking: %d\n", ret);
- return;
- }
-
- if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
- ret = regulator_enable(dsp->dvfs);
- if (ret != 0) {
- adsp_err(dsp,
- "Failed to enable supply: %d\n",
- ret);
- return;
- }
-
- ret = regulator_set_voltage(dsp->dvfs,
- 1800000,
- 1800000);
- if (ret != 0) {
- adsp_err(dsp,
- "Failed to raise supply: %d\n",
- ret);
- return;
- }
- }
- }
-
ret = wm_adsp2_ena(dsp);
if (ret != 0)
return;
@@ -1668,21 +1639,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
- if (dsp->dvfs) {
- ret = regulator_set_voltage(dsp->dvfs, 1200000,
- 1800000);
- if (ret != 0)
- adsp_warn(dsp,
- "Failed to lower supply: %d\n",
- ret);
-
- ret = regulator_disable(dsp->dvfs);
- if (ret != 0)
- adsp_err(dsp,
- "Failed to enable supply: %d\n",
- ret);
- }
-
list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0;
@@ -1709,7 +1665,7 @@ err:
}
EXPORT_SYMBOL_GPL(wm_adsp2_event);
-int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
+int wm_adsp2_init(struct wm_adsp *adsp)
{
int ret;
@@ -1728,33 +1684,6 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
INIT_LIST_HEAD(&adsp->ctl_list);
INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work);
- if (dvfs) {
- adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
- if (IS_ERR(adsp->dvfs)) {
- ret = PTR_ERR(adsp->dvfs);
- adsp_err(adsp, "Failed to get DCVDD: %d\n", ret);
- return ret;
- }
-
- ret = regulator_enable(adsp->dvfs);
- if (ret != 0) {
- adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret);
- return ret;
- }
-
- ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
- if (ret != 0) {
- adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret);
- return ret;
- }
-
- ret = regulator_disable(adsp->dvfs);
- if (ret != 0) {
- adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret);
- return ret;
- }
- }
-
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index a4f6b64..a86e531 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -56,8 +56,6 @@ struct wm_adsp {
int fw;
bool running;
- struct regulator *dvfs;
-
struct list_head ctl_list;
struct work_struct boot_work;
@@ -67,19 +65,22 @@ struct wm_adsp {
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
-#define WM_ADSP2(wname, num) \
+#define WM_ADSP2_E(wname, num, event_fn) \
{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
- .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \
- .event_flags = SND_SOC_DAPM_PRE_PMU }, \
+ .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
+ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \
{ .id = snd_soc_dapm_out_drv, .name = wname, \
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+#define WM_ADSP2(wname, num) \
+ WM_ADSP2_E(wname, num, wm_adsp2_early_event)
+
extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
int wm_adsp1_init(struct wm_adsp *adsp);
-int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
+int wm_adsp2_init(struct wm_adsp *adsp);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
--
1.7.2.5
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 1/3 v4 RESEND] mfd: arizona: Export function to control subsystem DVFS
2014-08-08 13:32 [PATCH 1/3 v4 RESEND] mfd: arizona: Export function to control subsystem DVFS Richard Fitzgerald
2014-08-08 13:34 ` [PATCH 2/3 v4 RESEND] ASoC: wm_adsp: Move DVFS control into codec driver Richard Fitzgerald
2014-08-08 13:35 ` [PATCH 3/3 v4 RESEND] ASoC: arizona: Add DVFS handling for sample rate control Richard Fitzgerald
@ 2014-08-21 10:40 ` Lee Jones
2014-08-25 10:15 ` Richard Fitzgerald
2014-09-01 14:47 ` Richard Fitzgerald
3 siblings, 1 reply; 8+ messages in thread
From: Lee Jones @ 2014-08-21 10:40 UTC (permalink / raw)
To: Richard Fitzgerald
Cc: alsa-devel, sameo, broonie, tiwai, linux-kernel, patches,
lgirdwood
On Fri, 08 Aug 2014, Richard Fitzgerald wrote:
> From: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
>
> Moving this control from being a side-effect of the LDO1
> regulator driver to a specific exported function.
>
> Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
> drivers/mfd/arizona-core.c | 89 ++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/arizona/core.h | 12 +++++
> 2 files changed, 101 insertions(+), 0 deletions(-)
If this is the same patch I reviewed before:
Acked-by: Lee Jones <lee.jones@linaro.org>
I guess we're just waiting for maintainer Acks before I can apply the
set.
> diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
> index cfc191a..04cde4b 100644
> --- a/drivers/mfd/arizona-core.c
> +++ b/drivers/mfd/arizona-core.c
> @@ -94,6 +94,94 @@ int arizona_clk32k_disable(struct arizona *arizona)
> }
> EXPORT_SYMBOL_GPL(arizona_clk32k_disable);
>
> +int arizona_dvfs_up(struct arizona *arizona, unsigned int flags)
> +{
> + unsigned int new_flags;
> + int ret = 0;
> +
> + mutex_lock(&arizona->subsys_max_lock);
> +
> + new_flags = arizona->subsys_max_rq | flags;
> +
> + if (arizona->subsys_max_rq != new_flags) {
> + switch (arizona->type) {
> + case WM5102:
> + case WM8997:
> + ret = regulator_set_voltage(arizona->dcvdd,
> + 1800000, 1800000);
> + if (ret != 0) {
> + dev_err(arizona->dev,
> + "Failed to set DCVDD (DVFS up): %d\n",
> + ret);
> + goto err;
> + }
> +
> + ret = regmap_update_bits(arizona->regmap,
> + ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
> + ARIZONA_SUBSYS_MAX_FREQ, 1);
> + if (ret != 0) {
> + dev_err(arizona->dev,
> + "Failed to enable subsys max: %d\n",
> + ret);
> + regulator_set_voltage(arizona->dcvdd,
> + 1200000, 1800000);
> + goto err;
> + }
> + break;
> +
> + default:
> + break;
> + }
> +
> + arizona->subsys_max_rq = new_flags;
> + }
> +err:
> + mutex_unlock(&arizona->subsys_max_lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(arizona_dvfs_up);
> +
> +int arizona_dvfs_down(struct arizona *arizona, unsigned int flags)
> +{
> + int ret = 0;
> +
> + mutex_lock(&arizona->subsys_max_lock);
> +
> + if ((arizona->subsys_max_rq & flags) != flags)
> + dev_warn(arizona->dev, "Unbalanced DVFS down: %x\n", flags);
> +
> + arizona->subsys_max_rq &= ~flags;
> +
> + if (arizona->subsys_max_rq == 0) {
> + switch (arizona->type) {
> + case WM5102:
> + case WM8997:
> + ret = regmap_update_bits(arizona->regmap,
> + ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
> + ARIZONA_SUBSYS_MAX_FREQ, 0);
> + if (ret != 0)
> + dev_err(arizona->dev,
> + "Failed to disable subsys max: %d\n",
> + ret);
> +
> + ret = regulator_set_voltage(arizona->dcvdd,
> + 1200000, 1800000);
> + if (ret != 0)
> + dev_err(arizona->dev,
> + "Failed to set DCVDD (DVFS down): %d\n",
> + ret);
> + break;
> +
> + default:
> + break;
> + }
> + }
> +
> + mutex_unlock(&arizona->subsys_max_lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(arizona_dvfs_down);
> +
> static irqreturn_t arizona_clkgen_err(int irq, void *data)
> {
> struct arizona *arizona = data;
> @@ -641,6 +729,7 @@ int arizona_dev_init(struct arizona *arizona)
>
> dev_set_drvdata(arizona->dev, arizona);
> mutex_init(&arizona->clk_lock);
> + mutex_init(&arizona->subsys_max_lock);
>
> if (dev_get_platdata(arizona->dev))
> memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
> diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
> index a614b33..4aec6a3 100644
> --- a/include/linux/mfd/arizona/core.h
> +++ b/include/linux/mfd/arizona/core.h
> @@ -109,6 +109,9 @@ struct arizona {
> struct mutex clk_lock;
> int clk32k_ref;
>
> + struct mutex subsys_max_lock;
> + unsigned int subsys_max_rq;
> +
> struct snd_soc_dapm_context *dapm;
>
> int tdm_width[ARIZONA_MAX_AIF];
> @@ -118,8 +121,17 @@ struct arizona {
> uint8_t dac_comp_enabled;
> };
>
> +#define ARIZONA_DVFS_SR1_RQ 0x00000001
> +#define ARIZONA_DVFS_SR2_RQ 0x00000002
> +#define ARIZONA_DVFS_SR3_RQ 0x00000004
> +#define ARIZONA_DVFS_ASR1_RQ 0x00000010
> +#define ARIZONA_DVFS_ASR2_RQ 0x00000020
> +#define ARIZONA_DVFS_ADSP1_RQ 0x00010000
> +
> int arizona_clk32k_enable(struct arizona *arizona);
> int arizona_clk32k_disable(struct arizona *arizona);
> +int arizona_dvfs_up(struct arizona *arizona, unsigned int mask);
> +int arizona_dvfs_down(struct arizona *arizona, unsigned int mask);
>
> int arizona_request_irq(struct arizona *arizona, int irq, char *name,
> irq_handler_t handler, void *data);
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply [flat|nested] 8+ messages in thread