From a5c6951c49fbf7509419d877620625ca3cdae9b1 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 13 Sep 2017 21:37:17 +0200 Subject: mfd: wm97xx-core: core support for wm97xx Codec The WM9705, WM9712 and WM9713 are highly integrated codecs, with an audio codec, DAC and ADC, GPIO unit and a touchscreen interface. Historically the support was spread across drivers/input/touchscreen and sound/soc/codecs. The sharing was done through ac97 bus sharing. This model will not withstand the new AC97 bus model, where codecs are discovered on runtime. Signed-off-by: Robert Jarzmik Acked-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- include/linux/mfd/wm97xx.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 include/linux/mfd/wm97xx.h (limited to 'include/linux') diff --git a/include/linux/mfd/wm97xx.h b/include/linux/mfd/wm97xx.h new file mode 100644 index 000000000000..45fb54f19d09 --- /dev/null +++ b/include/linux/mfd/wm97xx.h @@ -0,0 +1,25 @@ +/* + * wm97xx client interface + * + * Copyright (C) 2017 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_MFD_WM97XX_H +#define __LINUX_MFD_WM97XX_H + +struct regmap; +struct wm97xx_batt_pdata; +struct snd_ac97; + +struct wm97xx_platform_data { + struct snd_ac97 *ac97; + struct regmap *regmap; + struct wm97xx_batt_pdata *batt_pdata; +}; + +#endif -- cgit v1.2.3 From 85e7dd3f871b988702973c80d9ef128e10dd3dad Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 4 Sep 2017 16:41:53 +0100 Subject: ASoC: arizona: Add support for setting the output volume limits The output volume limits allow signals to be limited to specific levels appropriate for the hardware attached. As this is a property of the hardware itself these will be configured through device tree. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- include/linux/mfd/arizona/pdata.h | 3 +++ sound/soc/codecs/arizona.c | 25 +++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 1 + sound/soc/codecs/cs47l24.c | 3 +++ sound/soc/codecs/wm5102.c | 3 +++ sound/soc/codecs/wm5110.c | 3 +++ sound/soc/codecs/wm8997.c | 3 +++ 7 files changed, 41 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index bfeecf179895..f72dc53848d7 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h @@ -174,6 +174,9 @@ struct arizona_pdata { /** Mode for outputs */ int out_mono[ARIZONA_MAX_OUTPUT]; + /** Limit output volumes */ + unsigned int out_vol_limit[2 * ARIZONA_MAX_OUTPUT]; + /** PDM speaker mute setting */ unsigned int spk_mute[ARIZONA_MAX_PDM_SPK]; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e6967385dccb..b3375e19598a 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -372,6 +372,22 @@ int arizona_init_common(struct arizona *arizona) } EXPORT_SYMBOL_GPL(arizona_init_common); +int arizona_init_vol_limit(struct arizona *arizona) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(arizona->pdata.out_vol_limit); ++i) { + if (arizona->pdata.out_vol_limit[i]) + regmap_update_bits(arizona->regmap, + ARIZONA_DAC_VOLUME_LIMIT_1L + i * 4, + ARIZONA_OUT1L_VOL_LIM_MASK, + arizona->pdata.out_vol_limit[i]); + } + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_vol_limit); + const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", @@ -2810,6 +2826,15 @@ int arizona_of_get_audio_pdata(struct arizona *arizona) count++; } + count = 0; + of_property_for_each_u32(np, "wlf,out-volume-limit", prop, cur, val) { + if (count == ARRAY_SIZE(pdata->out_vol_limit)) + break; + + pdata->out_vol_limit[count] = val; + count++; + } + ret = of_property_read_u32_array(np, "wlf,spk-fmt", pdm_val, ARRAY_SIZE(pdm_val)); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 2d198fb2ce97..dfdf6d8c9687 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -315,6 +315,7 @@ int arizona_init_gpio(struct snd_soc_codec *codec); int arizona_init_mono(struct snd_soc_codec *codec); int arizona_init_common(struct arizona *arizona); +int arizona_init_vol_limit(struct arizona *arizona); int arizona_init_spk_irqs(struct arizona *arizona); int arizona_free_spk_irqs(struct arizona *arizona); diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 0fe7d7a87ff3..94c0209977d0 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1297,6 +1297,9 @@ static int cs47l24_probe(struct platform_device *pdev) arizona_init_common(arizona); + ret = arizona_init_vol_limit(arizona); + if (ret < 0) + goto err_dsp_irq; ret = arizona_init_spk_irqs(arizona); if (ret < 0) goto err_dsp_irq; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 5a917dd73f32..4f0481d3c7a7 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -2107,6 +2107,9 @@ static int wm5102_probe(struct platform_device *pdev) arizona_init_common(arizona); + ret = arizona_init_vol_limit(arizona); + if (ret < 0) + goto err_dsp_irq; ret = arizona_init_spk_irqs(arizona); if (ret < 0) goto err_dsp_irq; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index ba1e90ca8be4..6ed1e1f9ce51 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2463,6 +2463,9 @@ static int wm5110_probe(struct platform_device *pdev) arizona_init_common(arizona); + ret = arizona_init_vol_limit(arizona); + if (ret < 0) + goto err_dsp_irq; ret = arizona_init_spk_irqs(arizona); if (ret < 0) goto err_dsp_irq; diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index c5aef9ecdecc..77f512767273 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1176,6 +1176,9 @@ static int wm8997_probe(struct platform_device *pdev) arizona_init_common(arizona); + ret = arizona_init_vol_limit(arizona); + if (ret < 0) + return ret; ret = arizona_init_spk_irqs(arizona); if (ret < 0) return ret; -- cgit v1.2.3 From e901b9873876ca30a09253731bd3a6b00c44b5b0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 4 Oct 2017 16:15:59 +0200 Subject: usb: core: Add a helper function to check the validity of EP type in URB This patch adds a new helper function to perform a sanity check of the given URB to see whether it contains a valid endpoint. It's a light- weight version of what usb_submit_urb() does, but without the kernel warning followed by the stack trace, just returns an error code. Especially for a driver that doesn't parse the descriptor but fills the URB with the fixed endpoint (e.g. some quirks for non-compliant devices), this kind of check is preferable at the probe phase before actually submitting the urb. Tested-by: Andrey Konovalov Acked-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai --- drivers/usb/core/urb.c | 30 ++++++++++++++++++++++++++---- include/linux/usb.h | 2 ++ 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 47903d510955..8b800e34407b 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -187,6 +187,31 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); /*-------------------------------------------------------------------*/ +static const int pipetypes[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + +/** + * usb_urb_ep_type_check - sanity check of endpoint in the given urb + * @urb: urb to be checked + * + * This performs a light-weight sanity check for the endpoint in the + * given urb. It returns 0 if the urb contains a valid endpoint, otherwise + * a negative error code. + */ +int usb_urb_ep_type_check(const struct urb *urb) +{ + const struct usb_host_endpoint *ep; + + ep = usb_pipe_endpoint(urb->dev, urb->pipe); + if (!ep) + return -EINVAL; + if (usb_pipetype(urb->pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(usb_urb_ep_type_check); + /** * usb_submit_urb - issue an asynchronous transfer request for an endpoint * @urb: pointer to the urb describing the request @@ -326,9 +351,6 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - static int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; int xfertype, max; struct usb_device *dev; struct usb_host_endpoint *ep; @@ -444,7 +466,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) */ /* Check that the pipe's type matches the endpoint's type */ - if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) + if (usb_urb_ep_type_check(urb)) dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); diff --git a/include/linux/usb.h b/include/linux/usb.h index cb9fbd54386e..2b861804fffa 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1728,6 +1728,8 @@ static inline int usb_urb_dir_out(struct urb *urb) return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; } +int usb_urb_ep_type_check(const struct urb *urb); + void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); void usb_free_coherent(struct usb_device *dev, size_t size, -- cgit v1.2.3