[alsa-devel] [PATCH v2 0/9] ASoC: fsl-ssi: offline/online configuration and cleanups
Hi,
This patch series fixes some fsl-ssi code that does not act exactly as it is described in the reference manuals.
The reference manuals before imx50 do mention that some register bits, including TDMAE/RDMAE, should not be changed while the SSI unit is enabled (SSIEN). At the same time the SDMA unit has a undefined request handling if there are DMA requests before the SDMA engine and its channel is configured. The reference manual states that SSI DMA requests are sent as soon as the FIFO and the DMAE bits are enabled. It does not mention a dependency to SCR's TE/RE bit.
To avoid sending DMA requests before a channel is configured, we have to seperate the fsl-ssi behavior into offline and online configuration. SoCs before imx50 have to use offline configuration while later SoC versions can use online reconfiguration.
This series adds support for online configuration and cleans up the configuration register code especially in fsl_ssi_trigger. At the end we have a seperation between enable/disable logic and the actual configuration register values used to enable/disable TX/RX.
I tested this series on mx53.
The series is based on Mark Brown's topic/fsl branch.
Regards,
Markus
Changes in v2: - Enable fsl-ssi interrupts independent of CONFIG_DEBUG_FS. - Move irq mapping fix into seperate patch (was in "Move sysfs stats to debugfs") - Rebased on v3.13-rc1 topic/fsl branch.
Changes in v1: - Not removing imx21-ssi from the compatible array in the DTS patch. - Dropped "ASoC: fsl-ssi: Drop AC97 debug register usage" for the moment as I don't have time to setup AC97 hardware for some tests
Markus Pargmann (9): ASoC: fsl-ssi: Move sysfs stats to debugfs ASoC: fsl-ssi: Fix interrupt mapping and release ASoC: fsl-ssi: Add imx50-ssi and of_device_id matching ASoC: fsl-ssi: Add offline_config flag ASoC: fsl-ssi: Add configuration helper functions ASoC: fsl-ssi: Move RX/TX configuration to seperate functions ASoC: fsl-ssi: Drop ac97 specific trigger function ARM: DTS: imx5* imx6*, use imx50-ssi ASoC: fsl-ssi: Drop AC97 debug register usage
arch/arm/boot/dts/imx51.dtsi | 10 +- arch/arm/boot/dts/imx53.dtsi | 10 +- arch/arm/boot/dts/imx6qdl.dtsi | 12 +- arch/arm/boot/dts/imx6sl.dtsi | 12 +- sound/soc/fsl/fsl_ssi.c | 521 +++++++++++++++++++++++++++-------------- 5 files changed, 371 insertions(+), 194 deletions(-)
Interrupt statistics of fsl_ssi are mainly for debugging purpose. Most of those interrupts show error states, e.g. under/overflow. The stats should be exposed via debugfs instead of sysfs.
This patch moves the statistics file to debugfs.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 190 ++++++++++++++++++++++++++++++------------------ 1 file changed, 121 insertions(+), 69 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index fb8f52a..66ffc58 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -35,6 +35,7 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/clk.h> +#include <linux/debugfs.h> #include <linux/device.h> #include <linux/delay.h> #include <linux/slab.h> @@ -113,6 +114,14 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set) CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \ CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN)
+#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \ + CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \ + CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN) +#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \ + CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \ + CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN) +#define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS) + /** * fsl_ssi_private: per-SSI private data * @@ -136,7 +145,6 @@ struct fsl_ssi_private { struct snd_pcm_substream *second_stream; unsigned int fifo_depth; struct snd_soc_dai_driver cpu_dai_drv; - struct device_attribute dev_attr; struct platform_device *pdev;
bool new_binding; @@ -173,6 +181,8 @@ struct fsl_ssi_private { unsigned int tfe1; unsigned int tfe0; } stats; + struct dentry *dbg_dir; + struct dentry *dbg_stats;
char name[1]; }; @@ -201,7 +211,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) were interrupted for. We mask it with the Interrupt Enable register so that we only check for events that we're interested in. */ - sisr = read_ssi(&ssi->sisr) & SIER_FLAGS; + sisr = read_ssi(&ssi->sisr) & FSLSSI_SISR_MASK;
if (sisr & CCSR_SSI_SISR_RFRC) { ssi_private->stats.rfrc++; @@ -321,6 +331,102 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) return ret; }
+#if IS_ENABLED(CONFIG_DEBUG_FS) +/* Show the statistics of a flag only if its interrupt is enabled. The + * compiler will optimze this code to a no-op if the interrupt is not + * enabled. + */ +#define SIER_SHOW(flag, name) \ + do { \ + if (FSLSSI_SISR_MASK & CCSR_SSI_SIER_##flag) \ + seq_printf(s, #name "=%u\n", ssi_private->stats.name); \ + } while (0) + + +/** + * fsl_sysfs_ssi_show: display SSI statistics + * + * Display the statistics for the current SSI device. To avoid confusion, + * we only show those counts that are enabled. + */ +static ssize_t fsl_ssi_stats_show(struct seq_file *s, void *unused) +{ + struct fsl_ssi_private *ssi_private = s->private; + + SIER_SHOW(RFRC_EN, rfrc); + SIER_SHOW(TFRC_EN, tfrc); + SIER_SHOW(CMDAU_EN, cmdau); + SIER_SHOW(CMDDU_EN, cmddu); + SIER_SHOW(RXT_EN, rxt); + SIER_SHOW(RDR1_EN, rdr1); + SIER_SHOW(RDR0_EN, rdr0); + SIER_SHOW(TDE1_EN, tde1); + SIER_SHOW(TDE0_EN, tde0); + SIER_SHOW(ROE1_EN, roe1); + SIER_SHOW(ROE0_EN, roe0); + SIER_SHOW(TUE1_EN, tue1); + SIER_SHOW(TUE0_EN, tue0); + SIER_SHOW(TFS_EN, tfs); + SIER_SHOW(RFS_EN, rfs); + SIER_SHOW(TLS_EN, tls); + SIER_SHOW(RLS_EN, rls); + SIER_SHOW(RFF1_EN, rff1); + SIER_SHOW(RFF0_EN, rff0); + SIER_SHOW(TFE1_EN, tfe1); + SIER_SHOW(TFE0_EN, tfe0); + + return 0; +} + +static int fsl_ssi_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, fsl_ssi_stats_show, inode->i_private); +} + +static const struct file_operations fsl_ssi_stats_ops = { + .open = fsl_ssi_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private, + struct device *dev) +{ + ssi_private->dbg_dir = debugfs_create_dir(dev_name(dev), NULL); + if (!ssi_private->dbg_dir) + return -ENOMEM; + + ssi_private->dbg_stats = debugfs_create_file("stats", S_IRUGO, + ssi_private->dbg_dir, ssi_private, &fsl_ssi_stats_ops); + if (!ssi_private->dbg_stats) { + debugfs_remove(ssi_private->dbg_dir); + return -ENOMEM; + } + + return 0; +} + +static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private) +{ + debugfs_remove(ssi_private->dbg_stats); + debugfs_remove(ssi_private->dbg_dir); +} + +#else + +static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private, + struct device *dev) +{ + return 0; +} + +static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private) +{ +} + +#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ + static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) { struct ccsr_ssi __iomem *ssi = ssi_private->ssi; @@ -795,56 +901,6 @@ static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = { .write = fsl_ssi_ac97_write, };
-/* Show the statistics of a flag only if its interrupt is enabled. The - * compiler will optimze this code to a no-op if the interrupt is not - * enabled. - */ -#define SIER_SHOW(flag, name) \ - do { \ - if (SIER_FLAGS & CCSR_SSI_SIER_##flag) \ - length += sprintf(buf + length, #name "=%u\n", \ - ssi_private->stats.name); \ - } while (0) - - -/** - * fsl_sysfs_ssi_show: display SSI statistics - * - * Display the statistics for the current SSI device. To avoid confusion, - * we only show those counts that are enabled. - */ -static ssize_t fsl_sysfs_ssi_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fsl_ssi_private *ssi_private = - container_of(attr, struct fsl_ssi_private, dev_attr); - ssize_t length = 0; - - SIER_SHOW(RFRC_EN, rfrc); - SIER_SHOW(TFRC_EN, tfrc); - SIER_SHOW(CMDAU_EN, cmdau); - SIER_SHOW(CMDDU_EN, cmddu); - SIER_SHOW(RXT_EN, rxt); - SIER_SHOW(RDR1_EN, rdr1); - SIER_SHOW(RDR0_EN, rdr0); - SIER_SHOW(TDE1_EN, tde1); - SIER_SHOW(TDE0_EN, tde0); - SIER_SHOW(ROE1_EN, roe1); - SIER_SHOW(ROE0_EN, roe0); - SIER_SHOW(TUE1_EN, tue1); - SIER_SHOW(TUE0_EN, tue0); - SIER_SHOW(TFS_EN, tfs); - SIER_SHOW(RFS_EN, rfs); - SIER_SHOW(TLS_EN, tls); - SIER_SHOW(RLS_EN, rls); - SIER_SHOW(RFF1_EN, rff1); - SIER_SHOW(RFF0_EN, rff0); - SIER_SHOW(TFE1_EN, tfe1); - SIER_SHOW(TFE0_EN, tfe0); - - return length; -} - /** * Make every character in a string lower-case */ @@ -1020,20 +1076,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) } }
- /* Initialize the the device_attribute structure */ - dev_attr = &ssi_private->dev_attr; - sysfs_attr_init(&dev_attr->attr); - dev_attr->attr.name = "statistics"; - dev_attr->attr.mode = S_IRUGO; - dev_attr->show = fsl_sysfs_ssi_show; - - ret = device_create_file(&pdev->dev, dev_attr); - if (ret) { - dev_err(&pdev->dev, "could not create sysfs %s file\n", - ssi_private->dev_attr.attr.name); - goto error_clk; - } - /* Register with ASoC */ dev_set_drvdata(&pdev->dev, ssi_private);
@@ -1044,6 +1086,10 @@ static int fsl_ssi_probe(struct platform_device *pdev) goto error_dev; }
+ ret = fsl_ssi_debugfs_create(ssi_private, &pdev->dev); + if (ret) + goto error_dbgfs; + if (ssi_private->ssi_on_imx) { if (!ssi_private->use_dma) {
@@ -1063,11 +1109,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params); if (ret) - goto error_dev; + goto error_pcm; } else { ret = imx_pcm_dma_init(pdev); if (ret) - goto error_dev; + goto error_pcm; } }
@@ -1111,6 +1157,11 @@ done: error_dai: if (ssi_private->ssi_on_imx) imx_pcm_dma_exit(pdev); + +error_pcm: + fsl_ssi_debugfs_remove(ssi_private); + +error_dbgfs: snd_soc_unregister_component(&pdev->dev);
error_dev: @@ -1130,12 +1181,13 @@ static int fsl_ssi_remove(struct platform_device *pdev) { struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
+ fsl_ssi_debugfs_remove(ssi_private); + if (!ssi_private->new_binding) platform_device_unregister(ssi_private->pdev); if (ssi_private->ssi_on_imx) imx_pcm_dma_exit(pdev); snd_soc_unregister_component(&pdev->dev); - device_remove_file(&pdev->dev, &ssi_private->dev_attr); if (ssi_private->ssi_on_imx) clk_disable_unprepare(ssi_private->clk); irq_dispose_mapping(ssi_private->irq);
irqs should only be requested and released with DMA.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 66ffc58..57e331f 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1064,7 +1064,9 @@ static int fsl_ssi_probe(struct platform_device *pdev) dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI); imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx, dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI); - } else if (ssi_private->use_dma) { + } + + if (ssi_private->use_dma) { /* The 'name' should not have any slashes in it. */ ret = devm_request_irq(&pdev->dev, ssi_private->irq, fsl_ssi_isr, 0, ssi_private->name, @@ -1172,7 +1174,8 @@ error_clk: clk_disable_unprepare(ssi_private->clk);
error_irqmap: - irq_dispose_mapping(ssi_private->irq); + if (ssi_private->use_dma) + irq_dispose_mapping(ssi_private->irq);
return ret; } @@ -1190,7 +1193,8 @@ static int fsl_ssi_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); if (ssi_private->ssi_on_imx) clk_disable_unprepare(ssi_private->clk); - irq_dispose_mapping(ssi_private->irq); + if (ssi_private->use_dma) + irq_dispose_mapping(ssi_private->irq);
return 0; }
There is a small but significant difference between imx21-ssi and imx50-ssi and above. imx21-ssi does not allow online reconfiguration of some registers. They have to be configured at the beginning.
imx50-ssi has to reconfigure the SSI unit while it is running. Otherwise it would not be possible to have two streams in parallel. The new SDMA unit in imx50 and above has to be configured before the first DMA request arrives. Therefor we need to setup TDMAE/RDMAE just before starting the stream.
This patch introduces distinct imx50-ssi as compatible and adds of_device_id matching in the probe function.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 57e331f..5e95244 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -187,6 +187,20 @@ struct fsl_ssi_private { char name[1]; };
+enum fsl_ssi_type { + FSL_SSI_MCP8610, + FSL_SSI_MX21, + FSL_SSI_MX50, +}; + +static const struct of_device_id fsl_ssi_ids[] = { + { .compatible = "fsl,mpc8610-ssi", .data = (void *) FSL_SSI_MCP8610}, + { .compatible = "fsl,imx50-ssi", .data = (void *) FSL_SSI_MX50}, + { .compatible = "fsl,imx21-ssi", .data = (void *) FSL_SSI_MX21}, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_ssi_ids); + /** * fsl_ssi_isr: SSI interrupt handler * @@ -922,6 +936,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) int ret = 0; struct device_attribute *dev_attr = NULL; struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; + enum fsl_ssi_type hw_type; const char *p, *sprop; const uint32_t *iprop; struct resource res; @@ -936,6 +952,11 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (!of_device_is_available(np)) return -ENODEV;
+ of_id = of_match_device(fsl_ssi_ids, &pdev->dev); + if (!of_id) + return -EINVAL; + hw_type = (enum fsl_ssi_type) of_id->data; + /* We only support the SSI in "I2S Slave" mode */ sprop = of_get_property(np, "fsl,mode", NULL); if (!sprop) { @@ -1009,7 +1030,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Older 8610 DTs didn't have the fifo-depth property */ ssi_private->fifo_depth = 8;
- if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) { + if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX50) { u32 dma_events[2]; ssi_private->ssi_on_imx = true;
@@ -1199,13 +1220,6 @@ static int fsl_ssi_remove(struct platform_device *pdev) return 0; }
-static const struct of_device_id fsl_ssi_ids[] = { - { .compatible = "fsl,mpc8610-ssi", }, - { .compatible = "fsl,imx21-ssi", }, - {} -}; -MODULE_DEVICE_TABLE(of, fsl_ssi_ids); - static struct platform_driver fsl_ssi_driver = { .driver = { .name = "fsl-ssi-dai",
On Mon, Nov 25, 2013 at 12:13:39PM +0100, Markus Pargmann wrote:
There is a small but significant difference between imx21-ssi and imx50-ssi and above.
Haven't we already agreed that imx51-ssi should be used in naming and compatible, since imx51 comes to the world earlier than imx50?
Shawn
imx21-ssi does not allow online reconfiguration of some registers. They have to be configured at the beginning.
imx50-ssi has to reconfigure the SSI unit while it is running. Otherwise it would not be possible to have two streams in parallel. The new SDMA unit in imx50 and above has to be configured before the first DMA request arrives. Therefor we need to setup TDMAE/RDMAE just before starting the stream.
This patch introduces distinct imx50-ssi as compatible and adds of_device_id matching in the probe function.
Signed-off-by: Markus Pargmann mpa@pengutronix.de
sound/soc/fsl/fsl_ssi.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 57e331f..5e95244 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -187,6 +187,20 @@ struct fsl_ssi_private { char name[1]; };
+enum fsl_ssi_type {
- FSL_SSI_MCP8610,
- FSL_SSI_MX21,
- FSL_SSI_MX50,
+};
+static const struct of_device_id fsl_ssi_ids[] = {
- { .compatible = "fsl,mpc8610-ssi", .data = (void *) FSL_SSI_MCP8610},
- { .compatible = "fsl,imx50-ssi", .data = (void *) FSL_SSI_MX50},
- { .compatible = "fsl,imx21-ssi", .data = (void *) FSL_SSI_MX21},
- {}
+}; +MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
/**
- fsl_ssi_isr: SSI interrupt handler
@@ -922,6 +936,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) int ret = 0; struct device_attribute *dev_attr = NULL; struct device_node *np = pdev->dev.of_node;
- const struct of_device_id *of_id;
- enum fsl_ssi_type hw_type; const char *p, *sprop; const uint32_t *iprop; struct resource res;
@@ -936,6 +952,11 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (!of_device_is_available(np)) return -ENODEV;
- of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
- if (!of_id)
return -EINVAL;
- hw_type = (enum fsl_ssi_type) of_id->data;
- /* We only support the SSI in "I2S Slave" mode */ sprop = of_get_property(np, "fsl,mode", NULL); if (!sprop) {
@@ -1009,7 +1030,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Older 8610 DTs didn't have the fifo-depth property */ ssi_private->fifo_depth = 8;
- if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
- if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX50) { u32 dma_events[2]; ssi_private->ssi_on_imx = true;
@@ -1199,13 +1220,6 @@ static int fsl_ssi_remove(struct platform_device *pdev) return 0; }
-static const struct of_device_id fsl_ssi_ids[] = {
- { .compatible = "fsl,mpc8610-ssi", },
- { .compatible = "fsl,imx21-ssi", },
- {}
-}; -MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
static struct platform_driver fsl_ssi_driver = { .driver = { .name = "fsl-ssi-dai", -- 1.8.4.2
Hi,
On Tue, Nov 26, 2013 at 12:33:57PM +0800, Shawn Guo wrote:
On Mon, Nov 25, 2013 at 12:13:39PM +0100, Markus Pargmann wrote:
There is a small but significant difference between imx21-ssi and imx50-ssi and above.
Haven't we already agreed that imx51-ssi should be used in naming and compatible, since imx51 comes to the world earlier than imx50?
Yes of course, sorry. Seems I have lost those fixups somewhere. I will resend this series.
Thanks,
Markus
imx50-ssi and later versions of this IP support online reconfiguration of all registers. The reference manual does not list any registers that can only be configured while the SSI unit is disabled. This patch introduces the flag for later use.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 5e95244..abe6172 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -151,6 +151,7 @@ struct fsl_ssi_private { bool ssi_on_imx; bool imx_ac97; bool use_dma; + bool offline_config; struct clk *clk; struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; @@ -1030,6 +1031,24 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Older 8610 DTs didn't have the fifo-depth property */ ssi_private->fifo_depth = 8;
+ /* + * imx50 and later SoCs have a slightly different IP that allows the + * SSI configuration while the SSI unit is running. + * + * More important, it is necessary on those SoCs to configure the + * sperate TX/RX DMA bits just before starting the stream + * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi + * sends any DMA requests to the SDMA unit, otherwise it is not defined + * how the SDMA unit handles the DMA request. + * + * SDMA units are present on devices starting at imx35 but the imx35 + * reference manual states that the DMA bits should not be changed + * while the SSI unit is running (SSIEN). So we support the necessary + * online configuration of fsl-ssi starting at imx50. + */ + if (hw_type != FSL_SSI_MX50) + ssi_private->offline_config = true; + if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX50) { u32 dma_events[2]; ssi_private->ssi_on_imx = true;
This patch adds a struct 'fsl_ssi_rxtx_reg_val' which holds register values necessary to enable rx/tx. Based on those preset register values, the added configuration functions will cleanly enable/disable different parts of the SSI IP while supporting online/offline configuration. Different operating modes can be setup directly as different register values in fsl_ssi_reg_val.
These functions and structs will help to cleanup and simplify the trigger function to support many different IP versions (online/offline configuration) and different operating modes.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index abe6172..e0594e9 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -122,6 +122,18 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set) CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN) #define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS)
+struct fsl_ssi_reg_val { + u32 sier; + u32 srcr; + u32 stcr; + u32 scr; +}; + +struct fsl_ssi_rxtx_reg_val { + struct fsl_ssi_reg_val rx; + struct fsl_ssi_reg_val tx; +}; + /** * fsl_ssi_private: per-SSI private data * @@ -158,6 +170,8 @@ struct fsl_ssi_private { struct imx_dma_data filter_data_tx; struct imx_dma_data filter_data_rx; struct imx_pcm_fiq_params fiq_params; + /* Register values for rx/tx configuration */ + struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
struct { unsigned int rfrc; @@ -442,6 +456,114 @@ static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
+/* + * Enable/Disable all rx/tx config flags at once. + */ +static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, + bool enable) +{ + struct ccsr_ssi __iomem *ssi = ssi_private->ssi; + struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val; + + if (enable) { + write_ssi_mask(&ssi->sier, 0, vals->rx.sier | vals->tx.sier); + write_ssi_mask(&ssi->srcr, 0, vals->rx.srcr | vals->tx.srcr); + write_ssi_mask(&ssi->stcr, 0, vals->rx.stcr | vals->tx.stcr); + } else { + write_ssi_mask(&ssi->srcr, vals->rx.srcr | vals->tx.srcr, 0); + write_ssi_mask(&ssi->stcr, vals->rx.stcr | vals->tx.stcr, 0); + write_ssi_mask(&ssi->sier, vals->rx.sier | vals->tx.sier, 0); + } +} + +/* + * Enable/Disable a ssi configuration. You have to pass either + * ssi_private->rxtx_reg_val.rx or tx as vals parameter. + */ +static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, + struct fsl_ssi_reg_val *vals) +{ + struct ccsr_ssi __iomem *ssi = ssi_private->ssi; + struct fsl_ssi_reg_val *avals; + u32 scr_val = read_ssi(&ssi->scr); + int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) + + !!(scr_val & CCSR_SSI_SCR_RE); + + /* Find the other direction values rx or tx which we do not want to + * modify */ + if (&ssi_private->rxtx_reg_val.rx == vals) + avals = &ssi_private->rxtx_reg_val.tx; + else + avals = &ssi_private->rxtx_reg_val.rx; + + /* If vals should be disabled, start with disabling the unit */ + if (!enable) { + u32 scr = vals->scr & (vals->scr ^ avals->scr); + write_ssi_mask(&ssi->scr, scr, 0); + } + + /* + * We are running on a SoC which does not support online SSI + * reconfiguration, so we have to enable all necessary flags at once + * even if we do not use them later (capture and playback configuration) + */ + if (ssi_private->offline_config) { + if ((enable && !nr_active_streams) || + (!enable && nr_active_streams == 1)) + fsl_ssi_rxtx_config(ssi_private, enable); + + goto config_done; + } + + /* + * Configure single direction units while the SSI unit is running + * (online configuration) + */ + if (enable) { + write_ssi_mask(&ssi->sier, 0, vals->sier); + write_ssi_mask(&ssi->srcr, 0, vals->srcr); + write_ssi_mask(&ssi->stcr, 0, vals->stcr); + } else { + u32 sier; + u32 srcr; + u32 stcr; + + /* + * Disabling the necessary flags for one of rx/tx while the + * other stream is active is a little bit more difficult. We + * have to disable only those flags that differ between both + * streams (rx XOR tx) and that are set in the stream that is + * disabled now. Otherwise we could alter flags of the other + * stream + */ + + /* These assignments are simply vals without bits set in avals*/ + sier = vals->sier & (vals->sier ^ avals->sier); + srcr = vals->srcr & (vals->srcr ^ avals->srcr); + stcr = vals->stcr & (vals->stcr ^ avals->stcr); + + write_ssi_mask(&ssi->srcr, srcr, 0); + write_ssi_mask(&ssi->stcr, stcr, 0); + write_ssi_mask(&ssi->sier, sier, 0); + } + +config_done: + /* Enabling of subunits is done after configuration */ + if (enable) + write_ssi_mask(&ssi->scr, 0, vals->scr); +} + + +static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable) +{ + fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx); +} + +static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable) +{ + fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx); +} + static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) { struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
This patch defines the appropriate register values for different oparation modes and IP versions. We have to handle DMA/FIQ, AC97, DEBUG-IRQs and offline/online configuration support.
With this patch we cleanup some driver code that was not reference manual conform and try to cleanup the whole trigger function to seperate the actual register values from the enable/disable logic, which is now hidden in fsl_ssi_config helpers.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 94 +++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 46 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e0594e9..21b300c 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -107,13 +107,6 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set) SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) #endif
-/* SIER bitflag of interrupts to enable */ -#define SIER_FLAGS (CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE | \ - CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN | \ - CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN | \ - CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \ - CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN) - #define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \ CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \ CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN) @@ -564,6 +557,43 @@ static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable) fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx); }
+/* + * Setup rx/tx register values used to enable/disable the streams. These will + * be used later in fsl_ssi_config to setup the streams without the need to + * check for all different SSI modes. + */ +static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private) +{ + struct fsl_ssi_rxtx_reg_val *reg = &ssi_private->rxtx_reg_val; + + reg->rx.sier = CCSR_SSI_SIER_RFF0_EN; + reg->rx.srcr = CCSR_SSI_SRCR_RFEN0; + reg->rx.scr = 0; + reg->tx.sier = CCSR_SSI_SIER_TFE0_EN; + reg->tx.stcr = CCSR_SSI_STCR_TFEN0; + reg->tx.scr = 0; + + if (!ssi_private->imx_ac97) { + reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE; + reg->rx.sier |= CCSR_SSI_SIER_RFF0_EN; + reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE; + reg->tx.sier |= CCSR_SSI_SIER_TFE0_EN; + } + + if (ssi_private->use_dma) { + reg->rx.sier |= CCSR_SSI_SIER_RDMAE; + reg->tx.sier |= CCSR_SSI_SIER_TDMAE; + } else { + reg->rx.sier |= CCSR_SSI_SIER_RIE; + reg->tx.sier |= CCSR_SSI_SIER_TIE; + } + +#if IS_ENABLED(CONFIG_DEBUG_FS) + reg->rx.sier |= FSLSSI_SIER_DBG_RX_FLAGS; + reg->tx.sier |= FSLSSI_SIER_DBG_TX_FLAGS; +#endif +} + static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) { struct ccsr_ssi __iomem *ssi = ssi_private->ssi; @@ -601,6 +631,8 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) u8 wm; int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+ fsl_ssi_setup_reg_vals(ssi_private); + if (ssi_private->imx_ac97) i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET; else @@ -624,13 +656,12 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) i2s_mode | (synchronous ? CCSR_SSI_SCR_SYN : 0));
- write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | - CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS | - CCSR_SSI_STCR_TSCKP, &ssi->stcr); + write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFSI | + CCSR_SSI_STCR_TEFS | CCSR_SSI_STCR_TSCKP, &ssi->stcr); + + write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFSI | + CCSR_SSI_SRCR_REFS | CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
- write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 | - CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS | - CCSR_SSI_SRCR_RSCKP, &ssi->srcr); /* * The DC and PM bits are only used if the SSI is the clock master. */ @@ -797,57 +828,28 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); - struct ccsr_ssi __iomem *ssi = ssi_private->ssi; - unsigned int sier_bits; - - /* - * Enable only the interrupts and DMA requests - * that are needed for the channel. As the fiq - * is polling for this bits, we have to ensure - * that this are aligned with the preallocated - * buffers - */ - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (ssi_private->use_dma) - sier_bits = SIER_FLAGS; - else - sier_bits = CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TFE0_EN; - } else { - if (ssi_private->use_dma) - sier_bits = SIER_FLAGS; - else - sier_bits = CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_RFF0_EN; - }
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - write_ssi_mask(&ssi->scr, 0, - CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); + fsl_ssi_tx_config(ssi_private, true); else - write_ssi_mask(&ssi->scr, 0, - CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); + fsl_ssi_rx_config(ssi_private, true); break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0); + fsl_ssi_tx_config(ssi_private, false); else - write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0); - - if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) & - (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) - write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); + fsl_ssi_rx_config(ssi_private, false); break;
default: return -EINVAL; }
- write_ssi(sier_bits, &ssi->sier);
return 0; }
The normal trigger function can now be used for AC97. Drop AC97 trigger function.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 61 ++++++------------------------------------------- 1 file changed, 7 insertions(+), 54 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 21b300c..cf55da0 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -850,6 +850,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, return -EINVAL; }
+ if (ssi_private->imx_ac97) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor); + else + write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor); + }
return 0; } @@ -913,59 +919,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = { .name = "fsl-ssi", };
-/** - * fsl_ssi_ac97_trigger: start and stop the AC97 receive/transmit. - * - * This function is called by ALSA to start, stop, pause, and resume the - * transfer of data. - */ -static int fsl_ssi_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata( - rtd->cpu_dai); - struct ccsr_ssi __iomem *ssi = ssi_private->ssi; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_TIE | - CCSR_SSI_SIER_TFE0_EN); - else - write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_RIE | - CCSR_SSI_SIER_RFF0_EN); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_TIE | - CCSR_SSI_SIER_TFE0_EN, 0); - else - write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RIE | - CCSR_SSI_SIER_RFF0_EN, 0); - break; - - default: - return -EINVAL; - } - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor); - else - write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor); - - return 0; -} - -static const struct snd_soc_dai_ops fsl_ssi_ac97_dai_ops = { - .startup = fsl_ssi_startup, - .shutdown = fsl_ssi_shutdown, - .trigger = fsl_ssi_ac97_trigger, -}; - static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .ac97_control = 1, .playback = { @@ -982,7 +935,7 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &fsl_ssi_ac97_dai_ops, + .ops = &fsl_ssi_dai_ops, };
imx50-ssi and imx21-ssi are different IPs. imx50-ssi supports online reconfiguration and needs this for correct interaction with SDMA. This patch adds imx50-ssi before each imx21-ssi for all imx5/imx6 SoCs.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- arch/arm/boot/dts/imx51.dtsi | 10 +++++++--- arch/arm/boot/dts/imx53.dtsi | 10 +++++++--- arch/arm/boot/dts/imx6qdl.dtsi | 12 +++++++++--- arch/arm/boot/dts/imx6sl.dtsi | 12 +++++++++--- 4 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 4bcdd3a..5fa0a16 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -155,7 +155,9 @@ };
ssi2: ssi@70014000 { - compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx51-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x70014000 0x4000>; interrupts = <30>; clocks = <&clks 49>; @@ -440,7 +442,8 @@ };
ssi1: ssi@83fcc000 { - compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx51-ssi", "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x83fcc000 0x4000>; interrupts = <29>; clocks = <&clks 48>; @@ -492,7 +495,8 @@ };
ssi3: ssi@83fe8000 { - compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx51-ssi", "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x83fe8000 0x4000>; interrupts = <96>; clocks = <&clks 50>; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 4307e80..1f5c622 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -149,7 +149,9 @@ };
ssi2: ssi@50014000 { - compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx53-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x50014000 0x4000>; interrupts = <30>; clocks = <&clks 49>; @@ -1049,7 +1051,8 @@ };
ssi1: ssi@63fcc000 { - compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx53-ssi", "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x63fcc000 0x4000>; interrupts = <29>; clocks = <&clks 48>; @@ -1076,7 +1079,8 @@ };
ssi3: ssi@63fe8000 { - compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + compatible = "fsl,imx53-ssi", "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x63fe8000 0x4000>; interrupts = <96>; clocks = <&clks 50>; diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 59154dc..2e102f5 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -232,7 +232,9 @@ };
ssi1: ssi@02028000 { - compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6q-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <0 46 0x04>; clocks = <&clks 178>; @@ -245,7 +247,9 @@ };
ssi2: ssi@0202c000 { - compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6q-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; interrupts = <0 47 0x04>; clocks = <&clks 179>; @@ -258,7 +262,9 @@ };
ssi3: ssi@02030000 { - compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6q-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x02030000 0x4000>; interrupts = <0 48 0x04>; clocks = <&clks 180>; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index 28558f1..d21fa17 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -195,7 +195,9 @@ };
ssi1: ssi@02028000 { - compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6sl-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <0 46 0x04>; clocks = <&clks IMX6SL_CLK_SSI1>; @@ -207,7 +209,9 @@ };
ssi2: ssi@0202c000 { - compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6sl-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; interrupts = <0 47 0x04>; clocks = <&clks IMX6SL_CLK_SSI2>; @@ -219,7 +223,9 @@ };
ssi3: ssi@02030000 { - compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; + compatible = "fsl,imx6sl-ssi", + "fsl,imx50-ssi", + "fsl,imx21-ssi"; reg = <0x02030000 0x4000>; interrupts = <0 48 0x04>; clocks = <&clks IMX6SL_CLK_SSI3>;
In i.MX27 reference manual the SOR register is listed for debugging purpose only. In mx50 and later, this register is not even listed anymore. We shouldn't use a debug register for normal operation.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 9 --------- 1 file changed, 9 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index cf55da0..befe1ed 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -620,8 +620,6 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) */ write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE); - - write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor); }
static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) @@ -850,13 +848,6 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, return -EINVAL; }
- if (ssi_private->imx_ac97) { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor); - else - write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor); - } - return 0; }
participants (2)
-
Markus Pargmann
-
Shawn Guo