From aa0bcc5c44437457307c8c22e57a67bb57424041 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:59:01 +0300 Subject: ASoC: rt5677: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969ac1192..9048ba7efee1 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5209,7 +5209,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val); if (val != RT5677_DEVICE_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5677\n", val); + "Device with ID register %#x is not rt5677\n", val); return -ENODEV; } -- cgit From e22579713ae1384a3dff545369cebe42b01370fa Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Fri, 5 Jun 2015 10:19:06 +0200 Subject: ASoC: simple card: set cpu-dai sysclk with mclk-fs Allows to request a specific mclk frequency per cpu_dai. To support some codecs with mclk provided by the cpu_dai, the mclk rate must be set depending on frame rate. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d5554939146e..3ff76d419436 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -76,6 +76,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = &priv->dai_props[rtd - rtd->card->rtd]; @@ -91,8 +92,16 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, mclk = params_rate(params) * mclk_fs; ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) + goto err; + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret && ret != -ENOTSUPP) + goto err; } +err: return ret; } -- cgit From efd901ee4bc8312e3bbf5561fdab8e3765e26334 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 22 Jun 2015 11:12:59 -0700 Subject: ASoC: rt5677: Switch to use descriptor-based gpiod API This patch makes the driver use the new descriptor-based gpiod API so that gpio assignment info can be provided by Device Tree, ACPI or board files. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 85 +++++++++++++++++------------------------------ sound/soc/codecs/rt5677.h | 5 +-- 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9048ba7efee1..232243009e1e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -15,13 +15,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -4764,10 +4762,10 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 0); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 0); + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } @@ -4781,10 +4779,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 0); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 0); + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; @@ -4795,12 +4793,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 1); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 1); - if (gpio_is_valid(rt5677->pow_ldo2) || - gpio_is_valid(rt5677->reset_pin)) + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 1); + if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); regcache_cache_only(rt5677->regmap, false); @@ -5037,24 +5034,6 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) rt5677->pdata.lout3_diff = of_property_read_bool(np, "realtek,lout3-differential"); - rt5677->pow_ldo2 = of_get_named_gpio(np, - "realtek,pow-ldo2-gpio", 0); - rt5677->reset_pin = of_get_named_gpio(np, - "realtek,reset-gpio", 0); - - /* - * POW_LDO2 is optional (it may be statically tied on the board). - * -ENOENT means that the property doesn't exist, i.e. there is no - * GPIO, so is not an error. Any other error code means the property - * exists, but could not be parsed. - */ - if (!gpio_is_valid(rt5677->pow_ldo2) && - (rt5677->pow_ldo2 != -ENOENT)) - return rt5677->pow_ldo2; - if (!gpio_is_valid(rt5677->reset_pin) && - (rt5677->reset_pin != -ENOENT)) - return rt5677->reset_pin; - of_property_read_u8_array(np, "realtek,gpio-config", rt5677->pdata.gpio_config, RT5677_GPIO_NUM); @@ -5158,30 +5137,26 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, rt5677->reset_pin = -EINVAL; } - if (gpio_is_valid(rt5677->pow_ldo2)) { - ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2, - GPIOF_OUT_INIT_HIGH, - "RT5677 POW_LDO2"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n", - rt5677->pow_ldo2, ret); - return ret; - } + /* pow-ldo2 and reset are optional. The codec pins may be statically + * connected on the board without gpios. If the gpio device property + * isn't specified, devm_gpiod_get_optional returns NULL. + */ + rt5677->pow_ldo2 = devm_gpiod_get_optional(&i2c->dev, + "realtek,pow-ldo2", GPIOD_OUT_HIGH); + if (IS_ERR(rt5677->pow_ldo2)) { + ret = PTR_ERR(rt5677->pow_ldo2); + dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret); + rt5677->pow_ldo2 = 0; } - - if (gpio_is_valid(rt5677->reset_pin)) { - ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin, - GPIOF_OUT_INIT_HIGH, - "RT5677 RESET"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request RESET %d: %d\n", - rt5677->reset_pin, ret); - return ret; - } + rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, + "realtek,reset", GPIOD_OUT_HIGH); + if (IS_ERR(rt5677->reset_pin)) { + ret = PTR_ERR(rt5677->reset_pin); + dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); + rt5677->reset_pin = 0; } - if (gpio_is_valid(rt5677->pow_ldo2) || - gpio_is_valid(rt5677->reset_pin)) { + if (rt5677->pow_ldo2 || rt5677->reset_pin) { /* Wait a while until I2C bus becomes available. The datasheet * does not specify the exact we should wait but startup * sequence mentiones at least a few milliseconds. diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 7eca38a23255..d46855a42c40 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -14,6 +14,7 @@ #include #include +#include /* Info */ #define RT5677_RESET 0x00 @@ -1775,8 +1776,8 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; - int pow_ldo2; /* POW_LDO2 pin */ - int reset_pin; /* RESET pin */ + struct gpio_desc *pow_ldo2; /* POW_LDO2 pin */ + struct gpio_desc *reset_pin; /* RESET pin */ enum rt5677_type type; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; -- cgit From 9bfde72157036f4eaa44f3e8982217ce1b3e14b6 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 22 Jun 2015 11:13:00 -0700 Subject: ASoC: rt5677: Switch to use unified device property API This patch makes the driver use the unified device property API so that platform data can be provided by Device Tree, ACPI or board files. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 57 +++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 232243009e1e..13b871f11023 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -5021,27 +5022,29 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); -static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) +static void rt5677_read_device_properties(struct rt5677_priv *rt5677, + struct device *dev) { - rt5677->pdata.in1_diff = of_property_read_bool(np, - "realtek,in1-differential"); - rt5677->pdata.in2_diff = of_property_read_bool(np, - "realtek,in2-differential"); - rt5677->pdata.lout1_diff = of_property_read_bool(np, - "realtek,lout1-differential"); - rt5677->pdata.lout2_diff = of_property_read_bool(np, - "realtek,lout2-differential"); - rt5677->pdata.lout3_diff = of_property_read_bool(np, - "realtek,lout3-differential"); - - of_property_read_u8_array(np, "realtek,gpio-config", - rt5677->pdata.gpio_config, RT5677_GPIO_NUM); - - of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); - of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); - of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); - - return 0; + rt5677->pdata.in1_diff = device_property_read_bool(dev, + "realtek,in1-differential"); + rt5677->pdata.in2_diff = device_property_read_bool(dev, + "realtek,in2-differential"); + rt5677->pdata.lout1_diff = device_property_read_bool(dev, + "realtek,lout1-differential"); + rt5677->pdata.lout2_diff = device_property_read_bool(dev, + "realtek,lout2-differential"); + rt5677->pdata.lout3_diff = device_property_read_bool(dev, + "realtek,lout3-differential"); + + device_property_read_u8_array(dev, "realtek,gpio-config", + rt5677->pdata.gpio_config, RT5677_GPIO_NUM); + + device_property_read_u32(dev, "realtek,jd1-gpio", + &rt5677->pdata.jd1_gpio); + device_property_read_u32(dev, "realtek,jd2-gpio", + &rt5677->pdata.jd2_gpio); + device_property_read_u32(dev, "realtek,jd3-gpio", + &rt5677->pdata.jd3_gpio); } static struct regmap_irq rt5677_irqs[] = { @@ -5124,18 +5127,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; - - if (i2c->dev.of_node) { - ret = rt5677_parse_dt(rt5677, i2c->dev.of_node); - if (ret) { - dev_err(&i2c->dev, "Failed to parse device tree: %d\n", - ret); - return ret; - } - } else { - rt5677->pow_ldo2 = -EINVAL; - rt5677->reset_pin = -EINVAL; - } + else + rt5677_read_device_properties(rt5677, &i2c->dev); /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property -- cgit From 8e2175d42e435b7957bfaa921fc27cb40e923372 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 13:50:49 +0800 Subject: ASoC: sirf-audio-codec: Staticise local symbols Also make sirf_audio_codec_dai_ops const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/sirf-audio-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 29cb44256044..6bfd25c289d1 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -370,11 +370,11 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, return 0; } -struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { +static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { .trigger = sirf_audio_codec_trigger, }; -struct snd_soc_dai_driver sirf_audio_codec_dai = { +static struct snd_soc_dai_driver sirf_audio_codec_dai = { .name = "sirf-audio-codec", .playback = { .stream_name = "Playback", -- cgit From f285f1610341af4181791938777e0affb5531278 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 23:32:04 +0800 Subject: ASoC: rt5677: Remove NULL test for desc before gpiod_set_value_cansleep call It's safe to call gpiod_set_value_cansleep() with NULL desc. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 13b871f11023..62230e05eac1 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4763,10 +4763,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } @@ -4780,10 +4778,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; @@ -4794,10 +4790,8 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 1); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); + gpiod_set_value_cansleep(rt5677->reset_pin, 1); if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); -- cgit From f8163c8673efaabb361281a2759b3167d181ecf6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 25 Jul 2015 10:23:40 +0800 Subject: ASoC: rt5677: Return error if devm_gpiod_get_optional return ERR_PTR If devm_gpiod_get_optional() return ERR_PTR, it means something wrong so request gpio fails. We had better return error in such case. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 62230e05eac1..3f890a6708cd 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5133,14 +5133,14 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (IS_ERR(rt5677->pow_ldo2)) { ret = PTR_ERR(rt5677->pow_ldo2); dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret); - rt5677->pow_ldo2 = 0; + return ret; } rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, "realtek,reset", GPIOD_OUT_HIGH); if (IS_ERR(rt5677->reset_pin)) { ret = PTR_ERR(rt5677->reset_pin); dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); - rt5677->reset_pin = 0; + return ret; } if (rt5677->pow_ldo2 || rt5677->reset_pin) { -- cgit From 552ef80389ec2567566be1ccc0dd79f08ba32cce Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Aug 2015 16:52:30 +0800 Subject: ASoC: SPEAr: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/spear/spdif_in.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index a4028601da01..977a078eb92f 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -203,35 +203,25 @@ static int spdif_in_probe(struct platform_device *pdev) struct spdif_in_dev *host; struct spear_spdif_platform_data *pdata; struct resource *res, *res_fifo; + void __iomem *io_base; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; + io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res_fifo) return -EINVAL; - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) { - dev_warn(&pdev->dev, "Failed to get memory resourse\n"); - return -ENOENT; - } - host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) { dev_warn(&pdev->dev, "kzalloc fail\n"); return -ENOMEM; } - host->io_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!host->io_base) { - dev_warn(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - + host->io_base = io_base; host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) return -EINVAL; -- cgit From 7d4d443eb4386d6dbd420fa96303dd8fbc1eefc8 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Fri, 21 Aug 2015 21:17:00 -0700 Subject: ASoC: rt5677: Allow arbitrary block read/write via SPI Added rt5677_spi_read() and refactored rt5677_spi_write() so that an arbitrary block in the DSP address space can be read/written via SPI. For example, this allows us to load an ELF DSP firmware with sparse sections, and stream audio samples from DSP ring buffer. Signed-off-by: Ben Zhang Acked-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 233 +++++++++++++++++++++++++++++++----------- sound/soc/codecs/rt5677-spi.h | 8 +- sound/soc/codecs/rt5677.c | 4 +- 3 files changed, 178 insertions(+), 67 deletions(-) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index ef6348cb9157..3505aafbade4 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -31,84 +31,197 @@ #include "rt5677-spi.h" +#define RT5677_SPI_BURST_LEN 240 +#define RT5677_SPI_HEADER 5 +#define RT5677_SPI_FREQ 6000000 + +/* The AddressPhase and DataPhase of SPI commands are MSB first on the wire. + * DataPhase word size of 16-bit commands is 2 bytes. + * DataPhase word size of 32-bit commands is 4 bytes. + * DataPhase word size of burst commands is 8 bytes. + * The DSP CPU is little-endian. + */ +#define RT5677_SPI_WRITE_BURST 0x5 +#define RT5677_SPI_READ_BURST 0x4 +#define RT5677_SPI_WRITE_32 0x3 +#define RT5677_SPI_READ_32 0x2 +#define RT5677_SPI_WRITE_16 0x1 +#define RT5677_SPI_READ_16 0x0 + static struct spi_device *g_spi; +static DEFINE_MUTEX(spi_mutex); -/** - * rt5677_spi_write - Write data to SPI. - * @txbuf: Data Buffer for writing. - * @len: Data length. +/* Select a suitable transfer command for the next transfer to ensure + * the transfer address is always naturally aligned while minimizing + * the total number of transfers required. + * + * 3 transfer commands are available: + * RT5677_SPI_READ/WRITE_16: Transfer 2 bytes + * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes + * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes + * + * For example, reading 260 bytes at 0x60030002 uses the following commands: + * 0x60030002 RT5677_SPI_READ_16 2 bytes + * 0x60030004 RT5677_SPI_READ_32 4 bytes + * 0x60030008 RT5677_SPI_READ_BURST 240 bytes + * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes + * 0x60030100 RT5677_SPI_READ_32 4 bytes + * 0x60030104 RT5677_SPI_READ_16 2 bytes * + * Input: + * @read: true for read commands; false for write commands + * @align: alignment of the next transfer address + * @remain: number of bytes remaining to transfer * - * Returns true for success. + * Output: + * @len: number of bytes to transfer with the selected command + * Returns the selected command */ -int rt5677_spi_write(u8 *txbuf, size_t len) +static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len) { - int status; - - status = spi_write(g_spi, txbuf, len); - - if (status) - dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); - - return status; + u8 cmd; + + if (align == 2 || align == 6 || remain == 2) { + cmd = RT5677_SPI_READ_16; + *len = 2; + } else if (align == 4 || remain <= 6) { + cmd = RT5677_SPI_READ_32; + *len = 4; + } else { + cmd = RT5677_SPI_READ_BURST; + *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN); + } + return read ? cmd : cmd + 1; } -EXPORT_SYMBOL_GPL(rt5677_spi_write); -/** - * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. - * @addr: Start address. - * @txbuf: Data Buffer for writng. - * @len: Data length, it must be a multiple of 8. - * - * - * Returns true for success. +/* Copy dstlen bytes from src to dst, while reversing byte order for each word. + * If srclen < dstlen, zeros are padded. */ -int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) +static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen) { - u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; - u8 *write_buf; - unsigned int i, end, offset = 0; - - write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); - - if (write_buf == NULL) - return -ENOMEM; - - while (offset < fw->size) { - if (offset + RT5677_SPI_BUF_LEN <= fw->size) - end = RT5677_SPI_BUF_LEN; - else - end = fw->size % RT5677_SPI_BUF_LEN; - - write_buf[0] = spi_cmd; - write_buf[1] = ((addr + offset) & 0xff000000) >> 24; - write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; - write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; - write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; - - for (i = 0; i < end; i += 8) { - write_buf[i + 12] = fw->data[offset + i + 0]; - write_buf[i + 11] = fw->data[offset + i + 1]; - write_buf[i + 10] = fw->data[offset + i + 2]; - write_buf[i + 9] = fw->data[offset + i + 3]; - write_buf[i + 8] = fw->data[offset + i + 4]; - write_buf[i + 7] = fw->data[offset + i + 5]; - write_buf[i + 6] = fw->data[offset + i + 6]; - write_buf[i + 5] = fw->data[offset + i + 7]; + u32 w, i, si; + u32 word_size = min_t(u32, dstlen, 8); + + for (w = 0; w < dstlen; w += word_size) { + for (i = 0; i < word_size; i++) { + si = w + word_size - i - 1; + dst[w + i] = si < srclen ? src[si] : 0; } + } +} - write_buf[end + 5] = spi_cmd; +/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */ +int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) +{ + u32 offset; + int status = 0; + struct spi_transfer t[2]; + struct spi_message m; + /* +4 bytes is for the DummyPhase following the AddressPhase */ + u8 header[RT5677_SPI_HEADER + 4]; + u8 body[RT5677_SPI_BURST_LEN]; + u8 spi_cmd; + u8 *cb = rxbuf; + + if (!g_spi) + return -ENODEV; + + if ((addr & 1) || (len & 1)) { + dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); + return -EACCES; + } - rt5677_spi_write(write_buf, end + 6); + memset(t, 0, sizeof(t)); + t[0].tx_buf = header; + t[0].len = sizeof(header); + t[0].speed_hz = RT5677_SPI_FREQ; + t[1].rx_buf = body; + t[1].speed_hz = RT5677_SPI_FREQ; + spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t)); + + for (offset = 0; offset < len; offset += t[1].len) { + spi_cmd = rt5677_spi_select_cmd(true, (addr + offset) & 7, + len - offset, &t[1].len); + + /* Construct SPI message header */ + header[0] = spi_cmd; + header[1] = ((addr + offset) & 0xff000000) >> 24; + header[2] = ((addr + offset) & 0x00ff0000) >> 16; + header[3] = ((addr + offset) & 0x0000ff00) >> 8; + header[4] = ((addr + offset) & 0x000000ff) >> 0; + + mutex_lock(&spi_mutex); + status |= spi_sync(g_spi, &m); + mutex_unlock(&spi_mutex); + + /* Copy data back to caller buffer */ + rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len); + } + return status; +} +EXPORT_SYMBOL_GPL(rt5677_spi_read); - offset += RT5677_SPI_BUF_LEN; +/* Write DSP address space using SPI. addr has to be 2-byte aligned. + * If len is not 2-byte aligned, an extra byte of zero is written at the end + * as padding. + */ +int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) +{ + u32 offset, len_with_pad = len; + int status = 0; + struct spi_transfer t; + struct spi_message m; + /* +1 byte is for the DummyPhase following the DataPhase */ + u8 buf[RT5677_SPI_HEADER + RT5677_SPI_BURST_LEN + 1]; + u8 *body = buf + RT5677_SPI_HEADER; + u8 spi_cmd; + const u8 *cb = txbuf; + + if (!g_spi) + return -ENODEV; + + if (addr & 1) { + dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); + return -EACCES; } - kfree(write_buf); + if (len & 1) + len_with_pad = len + 1; + + memset(&t, 0, sizeof(t)); + t.tx_buf = buf; + t.speed_hz = RT5677_SPI_FREQ; + spi_message_init_with_transfers(&m, &t, 1); + + for (offset = 0; offset < len_with_pad;) { + spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7, + len_with_pad - offset, &t.len); + + /* Construct SPI message header */ + buf[0] = spi_cmd; + buf[1] = ((addr + offset) & 0xff000000) >> 24; + buf[2] = ((addr + offset) & 0x00ff0000) >> 16; + buf[3] = ((addr + offset) & 0x0000ff00) >> 8; + buf[4] = ((addr + offset) & 0x000000ff) >> 0; + + /* Fetch data from caller buffer */ + rt5677_spi_reverse(body, t.len, cb + offset, len - offset); + offset += t.len; + t.len += RT5677_SPI_HEADER + 1; + + mutex_lock(&spi_mutex); + status |= spi_sync(g_spi, &m); + mutex_unlock(&spi_mutex); + } + return status; +} +EXPORT_SYMBOL_GPL(rt5677_spi_write); - return 0; +int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw) +{ + return rt5677_spi_write(addr, fw->data, fw->size); } -EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); +EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware); static int rt5677_spi_probe(struct spi_device *spi) { diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h index ec41b2b3b2ca..662db16cfb6a 100644 --- a/sound/soc/codecs/rt5677-spi.h +++ b/sound/soc/codecs/rt5677-spi.h @@ -12,10 +12,8 @@ #ifndef __RT5677_SPI_H__ #define __RT5677_SPI_H__ -#define RT5677_SPI_BUF_LEN 240 -#define RT5677_SPI_CMD_BURST_WRITE 0x05 - -int rt5677_spi_write(u8 *txbuf, size_t len); -int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); +int rt5677_spi_read(u32 addr, void *rxbuf, size_t len); +int rt5677_spi_write(u32 addr, const void *txbuf, size_t len); +int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw); #endif /* __RT5677_SPI_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 3f890a6708cd..d916d0c72690 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -745,14 +745,14 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, codec->dev); if (ret == 0) { - rt5677_spi_burst_write(0x50000000, rt5677->fw1); + rt5677_spi_write_firmware(0x50000000, rt5677->fw1); release_firmware(rt5677->fw1); } ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, codec->dev); if (ret == 0) { - rt5677_spi_burst_write(0x60000000, rt5677->fw2); + rt5677_spi_write_firmware(0x60000000, rt5677->fw2); release_firmware(rt5677->fw2); } -- cgit From 92eca20bbeaa4ec1908bad8aeefcaa2d98e302ff Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:50:53 +0800 Subject: ASoC: sh: ssi: Convert to devm_snd_soc_register_component Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/sh/ssi.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index ab13146e4f82..89ed1b107ac5 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -385,14 +385,9 @@ static const struct snd_soc_component_driver sh4_ssi_component = { static int sh4_soc_dai_probe(struct platform_device *pdev) { - return snd_soc_register_component(&pdev->dev, &sh4_ssi_component, - sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); -} - -static int sh4_soc_dai_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component, + sh4_ssi_dai, + ARRAY_SIZE(sh4_ssi_dai)); } static struct platform_driver sh4_ssi_driver = { @@ -401,7 +396,6 @@ static struct platform_driver sh4_ssi_driver = { }, .probe = sh4_soc_dai_probe, - .remove = sh4_soc_dai_remove, }; module_platform_driver(sh4_ssi_driver); -- cgit From 2c3f4b97eea5ce405baf2591715445da6ed05851 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 08:08:15 +0800 Subject: ASoC: spear_pcm: Use devm_snd_dmaengine_pcm_register to fix resource leak All the callers assume devm_spear_pcm_platform_register is a devm_ API, so use devm_snd_dmaengine_pcm_register in devm_spear_pcm_platform_register. Fixes: e1771bcf99b0 ("ASoC: SPEAr: remove custom DMA alloc compat function") Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/spear/spear_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index a7dc3c56f44d..e8476da157cd 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -44,7 +44,7 @@ int devm_spear_pcm_platform_register(struct device *dev, *config = spear_dmaengine_pcm_config; config->compat_filter_fn = filter; - return snd_dmaengine_pcm_register(dev, config, + return devm_snd_dmaengine_pcm_register(dev, config, SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_COMPAT); } -- cgit From e8de871e19668257972b167aabd56bb5faae784c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 11:07:33 +0800 Subject: ASoC: sh: dma-sh7760: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Acked-by: Manuel Lauss Signed-off-by: Mark Brown --- sound/soc/sh/dma-sh7760.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index fd11404a3bc7..8fad4441c87d 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -327,13 +327,7 @@ static struct snd_soc_platform_driver sh7760_soc_platform = { static int sh7760_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); -} - -static int sh7760_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); } static struct platform_driver sh7760_pcm_driver = { @@ -342,7 +336,6 @@ static struct platform_driver sh7760_pcm_driver = { }, .probe = sh7760_soc_platform_probe, - .remove = sh7760_soc_platform_remove, }; module_platform_driver(sh7760_pcm_driver); -- cgit