Re: [PATCH 2/3] ASoC: xlnx: Add i2s driver
On 17. 12. 18 13:24, Mark Brown wrote: > On Fri, Dec 14, 2018 at 07:50:43AM +0100, Michal Simek wrote: >> On 13. 12. 18 16:31, Mark Brown wrote: >>> On Sat, Dec 08, 2018 at 12:02:37AM +0530, Maruthi Srinivas Bayyavarapu >>> wrote: > @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx ASoC I2S audio support + * > >>> This looks otherwise good so I've applied it but please send a followup >>> patch converting the entire comment block to C++ style so this looks >>> more consistent. > >> Is it the rule for your subsystems? Or did it come from any generic >> agreement how this should be handled in .c files? > > It's mainly me, it's certainly not a consistent policy. > ok. Maruthi: Please send that patch which Mark is asking about. Thanks, Michal
Re: [PATCH 2/3] ASoC: xlnx: Add i2s driver
On Fri, Dec 14, 2018 at 07:50:43AM +0100, Michal Simek wrote: > On 13. 12. 18 16:31, Mark Brown wrote: > > On Sat, Dec 08, 2018 at 12:02:37AM +0530, Maruthi Srinivas Bayyavarapu > > wrote: > >> @@ -0,0 +1,185 @@ > >> +// SPDX-License-Identifier: GPL-2.0 > >> +/* > >> + * Xilinx ASoC I2S audio support > >> + * > > This looks otherwise good so I've applied it but please send a followup > > patch converting the entire comment block to C++ style so this looks > > more consistent. > Is it the rule for your subsystems? Or did it come from any generic > agreement how this should be handled in .c files? It's mainly me, it's certainly not a consistent policy. signature.asc Description: PGP signature
Re: [PATCH 2/3] ASoC: xlnx: Add i2s driver
Hi Mark, On 13. 12. 18 16:31, Mark Brown wrote: > On Sat, Dec 08, 2018 at 12:02:37AM +0530, Maruthi Srinivas Bayyavarapu wrote: > >> @@ -0,0 +1,185 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Xilinx ASoC I2S audio support >> + * > > This looks otherwise good so I've applied it but please send a followup > patch converting the entire comment block to C++ style so this looks > more consistent. Is it the rule for your subsystems? Or did it come from any generic agreement how this should be handled in .c files? Thanks, Michal
Re: [PATCH 2/3] ASoC: xlnx: Add i2s driver
On Sat, Dec 08, 2018 at 12:02:37AM +0530, Maruthi Srinivas Bayyavarapu wrote: > @@ -0,0 +1,185 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Xilinx ASoC I2S audio support > + * This looks otherwise good so I've applied it but please send a followup patch converting the entire comment block to C++ style so this looks more consistent. signature.asc Description: PGP signature
[PATCH 2/3] ASoC: xlnx: Add i2s driver
I2S IP instance can work in transmitter/playback or receiver/capture mode exclusively. The patch registers corresponding instance as ASoC component with audio framework. Signed-off-by: Maruthi Srinivas Bayyavarapu --- sound/soc/xilinx/xlnx_i2s.c | 185 1 file changed, 185 insertions(+) create mode 100644 sound/soc/xilinx/xlnx_i2s.c diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c new file mode 100644 index 000..d4ae9ef --- /dev/null +++ b/sound/soc/xilinx/xlnx_i2s.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx ASoC I2S audio support + * + * Copyright (C) 2018 Xilinx, Inc. + * + * Author: Praveen Vuppala + * Author: Maruthi Srinivas Bayyavarapu + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "xlnx_i2s" + +#define I2S_CORE_CTRL_OFFSET 0x08 +#define I2S_I2STIM_OFFSET 0x20 +#define I2S_CH0_OFFSET 0x30 +#define I2S_I2STIM_VALID_MASK GENMASK(7, 0) + +static int xlnx_i2s_set_sclkout_div(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + void __iomem *base = snd_soc_dai_get_drvdata(cpu_dai); + + if (!div || (div & ~I2S_I2STIM_VALID_MASK)) + return -EINVAL; + + writel(div, base + I2S_I2STIM_OFFSET); + + return 0; +} + +static int xlnx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *i2s_dai) +{ + u32 reg_off, chan_id; + void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai); + + chan_id = params_channels(params) / 2; + + while (chan_id > 0) { + reg_off = I2S_CH0_OFFSET + ((chan_id - 1) * 4); + writel(chan_id, base + reg_off); + chan_id--; + } + + return 0; +} + +static int xlnx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *i2s_dai) +{ + void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + writel(1, base + I2S_CORE_CTRL_OFFSET); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + writel(0, base + I2S_CORE_CTRL_OFFSET); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops xlnx_i2s_dai_ops = { + .trigger = xlnx_i2s_trigger, + .set_clkdiv = xlnx_i2s_set_sclkout_div, + .hw_params = xlnx_i2s_hw_params +}; + +static const struct snd_soc_component_driver xlnx_i2s_component = { + .name = DRV_NAME, +}; + +static const struct of_device_id xlnx_i2s_of_match[] = { + { .compatible = "xlnx,i2s-transmitter-1.0", }, + { .compatible = "xlnx,i2s-receiver-1.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match); + +static int xlnx_i2s_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + struct snd_soc_dai_driver *dai_drv; + int ret; + u32 ch, format, data_width; + struct device *dev = >dev; + struct device_node *node = dev->of_node; + + dai_drv = devm_kzalloc(>dev, sizeof(*dai_drv), GFP_KERNEL); + if (!dai_drv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(>dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + ret = of_property_read_u32(node, "xlnx,num-channels", ); + if (ret < 0) { + dev_err(dev, "cannot get supported channels\n"); + return ret; + } + ch = ch * 2; + + ret = of_property_read_u32(node, "xlnx,dwidth", _width); + if (ret < 0) { + dev_err(dev, "cannot get data width\n"); + return ret; + } + switch (data_width) { + case 16: + format = SNDRV_PCM_FMTBIT_S16_LE; + break; + case 24: + format = SNDRV_PCM_FMTBIT_S24_LE; + break; + default: + return -EINVAL; + } + + if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) { + dai_drv->name = "xlnx_i2s_playback"; + dai_drv->playback.stream_name = "Playback"; + dai_drv->playback.formats = format; + dai_drv->playback.channels_min = ch; + dai_drv->playback.channels_max = ch; + dai_drv->playback.rates = SNDRV_PCM_RATE_8000_192000; + dai_drv->ops = _i2s_dai_ops; + } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) { +
[PATCH 2/3] ASoC: xlnx: Add i2s driver
I2S IP instance can work in transmitter/playback or receiver/capture mode exclusively. The patch registers corresponding instance as ASoC component with audio framework. Signed-off-by: Maruthi Srinivas Bayyavarapu --- sound/soc/xilinx/xlnx_i2s.c | 185 1 file changed, 185 insertions(+) create mode 100644 sound/soc/xilinx/xlnx_i2s.c diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c new file mode 100644 index 000..d4ae9ef --- /dev/null +++ b/sound/soc/xilinx/xlnx_i2s.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx ASoC I2S audio support + * + * Copyright (C) 2018 Xilinx, Inc. + * + * Author: Praveen Vuppala + * Author: Maruthi Srinivas Bayyavarapu + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "xlnx_i2s" + +#define I2S_CORE_CTRL_OFFSET 0x08 +#define I2S_I2STIM_OFFSET 0x20 +#define I2S_CH0_OFFSET 0x30 +#define I2S_I2STIM_VALID_MASK GENMASK(7, 0) + +static int xlnx_i2s_set_sclkout_div(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + void __iomem *base = snd_soc_dai_get_drvdata(cpu_dai); + + if (!div || (div & ~I2S_I2STIM_VALID_MASK)) + return -EINVAL; + + writel(div, base + I2S_I2STIM_OFFSET); + + return 0; +} + +static int xlnx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *i2s_dai) +{ + u32 reg_off, chan_id; + void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai); + + chan_id = params_channels(params) / 2; + + while (chan_id > 0) { + reg_off = I2S_CH0_OFFSET + ((chan_id - 1) * 4); + writel(chan_id, base + reg_off); + chan_id--; + } + + return 0; +} + +static int xlnx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *i2s_dai) +{ + void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + writel(1, base + I2S_CORE_CTRL_OFFSET); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + writel(0, base + I2S_CORE_CTRL_OFFSET); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops xlnx_i2s_dai_ops = { + .trigger = xlnx_i2s_trigger, + .set_clkdiv = xlnx_i2s_set_sclkout_div, + .hw_params = xlnx_i2s_hw_params +}; + +static const struct snd_soc_component_driver xlnx_i2s_component = { + .name = DRV_NAME, +}; + +static const struct of_device_id xlnx_i2s_of_match[] = { + { .compatible = "xlnx,i2s-transmitter-1.0", }, + { .compatible = "xlnx,i2s-receiver-1.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match); + +static int xlnx_i2s_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + struct snd_soc_dai_driver *dai_drv; + int ret; + u32 ch, format, data_width; + struct device *dev = >dev; + struct device_node *node = dev->of_node; + + dai_drv = devm_kzalloc(>dev, sizeof(*dai_drv), GFP_KERNEL); + if (!dai_drv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(>dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + ret = of_property_read_u32(node, "xlnx,num-channels", ); + if (ret < 0) { + dev_err(dev, "cannot get supported channels\n"); + return ret; + } + ch = ch * 2; + + ret = of_property_read_u32(node, "xlnx,dwidth", _width); + if (ret < 0) { + dev_err(dev, "cannot get data width\n"); + return ret; + } + switch (data_width) { + case 16: + format = SNDRV_PCM_FMTBIT_S16_LE; + break; + case 24: + format = SNDRV_PCM_FMTBIT_S24_LE; + break; + default: + return -EINVAL; + } + + if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) { + dai_drv->name = "xlnx_i2s_playback"; + dai_drv->playback.stream_name = "Playback"; + dai_drv->playback.formats = format; + dai_drv->playback.channels_min = ch; + dai_drv->playback.channels_max = ch; + dai_drv->playback.rates = SNDRV_PCM_RATE_8000_192000; + dai_drv->ops = _i2s_dai_ops; + } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) { +