[alsa-devel] [PATCH 0/8] 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 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 (8): ASoC: fsl-ssi: Move ac97 specific setup to seperate function ASoC: fsl-ssi: Move sysfs stats to debugfs 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
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 | 588 +++++++++++++++++++++++++++-------------- 5 files changed, 417 insertions(+), 215 deletions(-)
This is a pure cleanup patch to increase code readability.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 57 +++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 25 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 35e2773..fb8f52a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -321,6 +321,36 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) return ret; }
+static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) +{ + struct ccsr_ssi __iomem *ssi = ssi_private->ssi; + + /* + * Setup the clock control register + */ + write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13), + &ssi->stccr); + write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13), + &ssi->srccr); + + /* + * Enable AC97 mode and startup the SSI + */ + write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV, + &ssi->sacnt); + write_ssi(0xff, &ssi->saccdis); + write_ssi(0x300, &ssi->saccen); + + /* + * Enable SSI, Transmit and Receive. AC97 has to communicate with the + * codec before a stream is started. + */ + 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) { struct ccsr_ssi __iomem *ssi = ssi_private->ssi; @@ -387,31 +417,8 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) * because it is also running without an active substream. Normally SSI * is only enabled when there is a substream. */ - if (ssi_private->imx_ac97) { - /* - * Setup the clock control register - */ - write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13), - &ssi->stccr); - write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13), - &ssi->srccr); - - /* - * Enable AC97 mode and startup the SSI - */ - write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV, - &ssi->sacnt); - write_ssi(0xff, &ssi->saccdis); - write_ssi(0x300, &ssi->saccen); - - /* - * Enable SSI, Transmit and Receive - */ - 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); - } + if (ssi_private->imx_ac97) + fsl_ssi_setup_ac97(ssi_private);
return 0; }
In the worst case, the stats exposed via sysfs generate some irq load on the system. In the best case, they show some statistics that are interesting for developers. However, the interrupts and statistics are not useful in general.
This patch moves the statistics to debugfs and disables interrupts completely if the kernel is build without DEBUG_FS enabled.
While adding some error handling in the probe function, it fixes some error jump labels.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/fsl/fsl_ssi.c | 206 +++++++++++++++++++++++++++++++----------------- 1 file changed, 135 insertions(+), 71 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index fb8f52a..c2fc031 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> @@ -112,6 +113,17 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set) 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) +#if IS_ENABLED(CONFIG_DEBUG_FS) +#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_RDR0_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_TDE0_EN | \ + CCSR_SSI_SIER_TFRC_EN) +#define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS) +#endif
/** * fsl_ssi_private: per-SSI private data @@ -136,7 +148,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,10 +184,13 @@ struct fsl_ssi_private { unsigned int tfe1; unsigned int tfe0; } stats; + struct dentry *dbg_dir; + struct dentry *dbg_stats;
char name[1]; };
+#if IS_ENABLED(CONFIG_DEBUG_FS) /** * fsl_ssi_isr: SSI interrupt handler * @@ -201,7 +215,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 +335,101 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) return ret; }
+/* 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 +904,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 */ @@ -1008,7 +1067,10 @@ 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 IS_ENABLED(CONFIG_DEBUG_FS) + 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, @@ -1019,20 +1081,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) goto error_irqmap; } } - - /* 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; - } +#endif
/* Register with ASoC */ dev_set_drvdata(&pdev->dev, ssi_private); @@ -1044,6 +1093,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 +1116,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 +1164,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: @@ -1121,7 +1179,10 @@ error_clk: clk_disable_unprepare(ssi_private->clk);
error_irqmap: - irq_dispose_mapping(ssi_private->irq); +#if IS_ENABLED(CONFIG_DEBUG_FS) + if (ssi_private->use_dma) + irq_dispose_mapping(ssi_private->irq); +#endif
return ret; } @@ -1130,15 +1191,18 @@ 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); +#if IS_ENABLED(CONFIG_DEBUG_FS) irq_dispose_mapping(ssi_private->irq); +#endif
return 0; }
On Wed, Nov 20, 2013 at 10:04:16AM +0100, Markus Pargmann wrote:
This patch moves the statistics to debugfs and disables interrupts completely if the kernel is build without DEBUG_FS enabled.
We can still see the error counts through /proc/interrupts even without the debugfs file.
Hi,
On Thu, Nov 21, 2013 at 02:22:08PM +0000, Mark Brown wrote:
On Wed, Nov 20, 2013 at 10:04:16AM +0100, Markus Pargmann wrote:
This patch moves the statistics to debugfs and disables interrupts completely if the kernel is build without DEBUG_FS enabled.
We can still see the error counts through /proc/interrupts even without the debugfs file.
The interrupts are visible without the debugfs file when enabled through SIER register. But it does not show the specific reason for the interrupts.
I am not sure what you suggest. To remove the stats file completely and always disable interrupts?
Regards,
Markus
On Fri, Nov 22, 2013 at 05:42:04PM +0100, Markus Pargmann wrote:
On Thu, Nov 21, 2013 at 02:22:08PM +0000, Mark Brown wrote:
On Wed, Nov 20, 2013 at 10:04:16AM +0100, Markus Pargmann wrote:
This patch moves the statistics to debugfs and disables interrupts completely if the kernel is build without DEBUG_FS enabled.
We can still see the error counts through /proc/interrupts even without the debugfs file.
The interrupts are visible without the debugfs file when enabled through SIER register. But it does not show the specific reason for the interrupts.
I am not sure what you suggest. To remove the stats file completely and always disable interrupts?
No, I'm suggesting not disabling interrupts completely when debugfs is disabled. Since we can still see the interrupts happening even if debugfs is not enabled we're still getting diagnostics.
Hi,
On Fri, Nov 22, 2013 at 06:33:56PM +0000, Mark Brown wrote:
On Fri, Nov 22, 2013 at 05:42:04PM +0100, Markus Pargmann wrote:
On Thu, Nov 21, 2013 at 02:22:08PM +0000, Mark Brown wrote:
On Wed, Nov 20, 2013 at 10:04:16AM +0100, Markus Pargmann wrote:
This patch moves the statistics to debugfs and disables interrupts completely if the kernel is build without DEBUG_FS enabled.
We can still see the error counts through /proc/interrupts even without the debugfs file.
The interrupts are visible without the debugfs file when enabled through SIER register. But it does not show the specific reason for the interrupts.
I am not sure what you suggest. To remove the stats file completely and always disable interrupts?
No, I'm suggesting not disabling interrupts completely when debugfs is disabled. Since we can still see the interrupts happening even if debugfs is not enabled we're still getting diagnostics.
Okay, I will change it.
Thanks,
Markus
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 c2fc031..d493d2d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -190,6 +190,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); + #if IS_ENABLED(CONFIG_DEBUG_FS) /** * fsl_ssi_isr: SSI interrupt handler @@ -925,6 +939,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; @@ -939,6 +955,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) { @@ -1012,7 +1033,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;
@@ -1207,13 +1228,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 Wed, Nov 20, 2013 at 10:04:17AM +0100, Markus Pargmann wrote:
There is a small but significant difference between imx21-ssi and imx50-ssi and above.
Markus,
Sorry, I did not point it out in the last review. But SoC imx51 came out earlier than imx50, so I think imx51-ssi should be used instead as compatible.
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 c2fc031..d493d2d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -190,6 +190,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);
#if IS_ENABLED(CONFIG_DEBUG_FS) /**
- fsl_ssi_isr: SSI interrupt handler
@@ -925,6 +939,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;
@@ -939,6 +955,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) {
@@ -1012,7 +1033,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;
@@ -1207,13 +1228,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 Shawn,
On Wed, Nov 20, 2013 at 08:45:01PM +0800, Shawn Guo wrote:
On Wed, Nov 20, 2013 at 10:04:17AM +0100, Markus Pargmann wrote:
There is a small but significant difference between imx21-ssi and imx50-ssi and above.
Markus,
Sorry, I did not point it out in the last review. But SoC imx51 came out earlier than imx50, so I think imx51-ssi should be used instead as compatible.
Ah, I didn't know imx51 was released earlier. I will replace imx50-ssi with imx51-ssi.
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 d493d2d..d268785 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -154,6 +154,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; @@ -1033,6 +1034,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 d268785..45279e6 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -125,6 +125,18 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set) #define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS) #endif
+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 * @@ -161,6 +173,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; @@ -445,6 +459,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 | 93 +++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 45 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 45279e6..c2bd7cd 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -107,12 +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) #if IS_ENABLED(CONFIG_DEBUG_FS) #define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \ CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \ @@ -567,6 +561,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; @@ -604,6 +635,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 @@ -627,13 +660,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. */ @@ -800,57 +832,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 c2bd7cd..4d155af 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -854,6 +854,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; } @@ -917,59 +923,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 = { @@ -986,7 +939,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 54cee65..706bdf3 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -150,7 +150,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>; @@ -427,7 +429,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>; @@ -479,7 +482,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 ccd55c2..26dc080 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -201,7 +201,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>; @@ -214,7 +216,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>; @@ -227,7 +231,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 c46651e..22cec8b 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -191,7 +191,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>; @@ -203,7 +205,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>; @@ -215,7 +219,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>;
participants (3)
-
Mark Brown
-
Markus Pargmann
-
Shawn Guo