From 71f6e0645be42f93c0f90dfcc93b9d2d277c2ee6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Dec 2009 15:11:08 +0900 Subject: ASoC: sh_fsi: avoid using global variable Current FSI driver use global variable to access device data. But this style will be broken if SuperH come with multiple FSI blocks in future. To solve this problem, this patch use cpu_dai->private_data. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 115 +++++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 53 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 9c49c11c43ce..7506ef6d287a 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -92,6 +92,7 @@ struct fsi_priv { void __iomem *base; struct snd_pcm_substream *substream; + struct fsi_master *master; int fifo_max; int chan; @@ -110,8 +111,6 @@ struct fsi_master { struct sh_fsi_platform_info *info; }; -static struct fsi_master *master; - /************************************************************************ @@ -166,7 +165,7 @@ static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); } -static int fsi_master_write(u32 reg, u32 data) +static int fsi_master_write(struct fsi_master *master, u32 reg, u32 data) { if ((reg < MREG_START) || (reg > MREG_END)) @@ -175,7 +174,7 @@ static int fsi_master_write(u32 reg, u32 data) return __fsi_reg_write((u32)(master->base + reg), data); } -static u32 fsi_master_read(u32 reg) +static u32 fsi_master_read(struct fsi_master *master, u32 reg) { if ((reg < MREG_START) || (reg > MREG_END)) @@ -184,7 +183,8 @@ static u32 fsi_master_read(u32 reg) return __fsi_reg_read((u32)(master->base + reg)); } -static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) +static int fsi_master_mask_set(struct fsi_master *master, + u32 reg, u32 mask, u32 data) { if ((reg < MREG_START) || (reg > MREG_END)) @@ -200,43 +200,29 @@ static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) ************************************************************************/ -static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream) +static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) { - struct snd_soc_pcm_runtime *rtd; - struct fsi_priv *fsi = NULL; - - if (!substream || !master) - return NULL; - - rtd = substream->private_data; - switch (rtd->dai->cpu_dai->id) { - case 0: - fsi = &master->fsia; - break; - case 1: - fsi = &master->fsib; - break; - } - - return fsi; + return fsi->master; } static int fsi_is_port_a(struct fsi_priv *fsi) { - /* return - * 1 : port a - * 0 : port b - */ + return fsi->master->base == fsi->base; +} - if (fsi == &master->fsia) - return 1; +static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *dai = machine->cpu_dai; - return 0; + return dai->private_data; } static u32 fsi_get_info_flags(struct fsi_priv *fsi) { int is_porta = fsi_is_port_a(fsi); + struct fsi_master *master = fsi_get_master(fsi); return is_porta ? master->info->porta_flags : master->info->portb_flags; @@ -314,27 +300,30 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) { u32 data = fsi_port_ab_io_bit(fsi, is_play); + struct fsi_master *master = fsi_get_master(fsi); - fsi_master_mask_set(IMSK, data, data); - fsi_master_mask_set(IEMSK, data, data); + fsi_master_mask_set(master, IMSK, data, data); + fsi_master_mask_set(master, IEMSK, data, data); } static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) { u32 data = fsi_port_ab_io_bit(fsi, is_play); + struct fsi_master *master = fsi_get_master(fsi); - fsi_master_mask_set(IMSK, data, 0); - fsi_master_mask_set(IEMSK, data, 0); + fsi_master_mask_set(master, IMSK, data, 0); + fsi_master_mask_set(master, IEMSK, data, 0); } static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) { u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); + struct fsi_master *master = fsi_get_master(fsi); if (enable) - fsi_master_mask_set(CLK_RST, val, val); + fsi_master_mask_set(master, CLK_RST, val, val); else - fsi_master_mask_set(CLK_RST, val, 0); + fsi_master_mask_set(master, CLK_RST, val, 0); } static void fsi_irq_init(struct fsi_priv *fsi, int is_play) @@ -355,23 +344,23 @@ static void fsi_irq_init(struct fsi_priv *fsi, int is_play) fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); /* clear interrupt factor */ - fsi_master_mask_set(INT_ST, data, 0); + fsi_master_mask_set(fsi_get_master(fsi), INT_ST, data, 0); } -static void fsi_soft_all_reset(void) +static void fsi_soft_all_reset(struct fsi_master *master) { - u32 status = fsi_master_read(SOFT_RST); + u32 status = fsi_master_read(master, SOFT_RST); /* port AB reset */ status &= 0x000000ff; - fsi_master_write(SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status); mdelay(10); /* soft reset */ status &= 0x000000f0; - fsi_master_write(SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status); status |= 0x00000001; - fsi_master_write(SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status); mdelay(10); } @@ -517,12 +506,13 @@ static int fsi_data_pop(struct fsi_priv *fsi) static irqreturn_t fsi_interrupt(int irq, void *data) { - u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; - u32 int_st = fsi_master_read(INT_ST); + struct fsi_master *master = data; + u32 status = fsi_master_read(master, SOFT_RST) & ~0x00000010; + u32 int_st = fsi_master_read(master, INT_ST); /* clear irq status */ - fsi_master_write(SOFT_RST, status); - fsi_master_write(SOFT_RST, status | 0x00000010); + fsi_master_write(master, SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status | 0x00000010); if (int_st & INT_A_OUT) fsi_data_push(&master->fsia); @@ -533,7 +523,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data) if (int_st & INT_B_IN) fsi_data_pop(&master->fsib); - fsi_master_write(INT_ST, 0x0000000); + fsi_master_write(master, INT_ST, 0x0000000); return IRQ_HANDLED; } @@ -548,7 +538,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data) static int fsi_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); const char *msg; u32 flags = fsi_get_info_flags(fsi); u32 fmt; @@ -667,7 +657,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, static void fsi_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; fsi_irq_disable(fsi, is_play); @@ -679,7 +669,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); struct snd_pcm_runtime *runtime = substream->runtime; int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; @@ -760,7 +750,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); long location; location = (fsi->byte_offset - 1); @@ -870,10 +860,16 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform); ************************************************************************/ static int fsi_probe(struct platform_device *pdev) { + struct fsi_master *master; struct resource *res; unsigned int irq; int ret; + if (0 != pdev->id) { + dev_err(&pdev->dev, "current fsi support id 0 only now\n"); + return -ENODEV; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!res || !irq) { @@ -899,15 +895,19 @@ static int fsi_probe(struct platform_device *pdev) master->irq = irq; master->info = pdev->dev.platform_data; master->fsia.base = master->base; + master->fsia.master = master; master->fsib.base = master->base + 0x40; + master->fsib.master = master; pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); fsi_soc_dai[0].dev = &pdev->dev; + fsi_soc_dai[0].private_data = &master->fsia; fsi_soc_dai[1].dev = &pdev->dev; + fsi_soc_dai[1].private_data = &master->fsib; - fsi_soft_all_reset(); + fsi_soft_all_reset(master); ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); if (ret) { @@ -937,6 +937,10 @@ exit: static int fsi_remove(struct platform_device *pdev) { + struct fsi_master *master; + + master = fsi_get_master(fsi_soc_dai[0].private_data); + snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); snd_soc_unregister_platform(&fsi_soc_platform); @@ -946,7 +950,12 @@ static int fsi_remove(struct platform_device *pdev) iounmap(master->base); kfree(master); - master = NULL; + + fsi_soc_dai[0].dev = NULL; + fsi_soc_dai[0].private_data = NULL; + fsi_soc_dai[1].dev = NULL; + fsi_soc_dai[1].private_data = NULL; + return 0; } -- cgit v1.2.3 From 1c418d1f623438147a485db987de296ab372e0f3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Dec 2009 14:09:05 +0900 Subject: ASoC: fsi: Add over_period flag to prevent the misunderstanding Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 7506ef6d287a..b311a9eaf021 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -373,14 +373,16 @@ static int fsi_data_push(struct fsi_priv *fsi) int fifo_free; int width; u8 *start; - int i; + int i, over_period; if (!fsi || !fsi->substream || !fsi->substream->runtime) return -EINVAL; - runtime = fsi->substream->runtime; + over_period = 0; + substream = fsi->substream; + runtime = substream->runtime; /* FSI FIFO has limit. * So, this driver can not send periods data at a time @@ -388,7 +390,7 @@ static int fsi_data_push(struct fsi_priv *fsi) if (fsi->byte_offset >= fsi->period_len * (fsi->periods + 1)) { - substream = fsi->substream; + over_period = 1; fsi->periods = (fsi->periods + 1) % runtime->periods; if (0 == fsi->periods) @@ -429,7 +431,7 @@ static int fsi_data_push(struct fsi_priv *fsi) fsi_irq_enable(fsi, 1); - if (substream) + if (over_period) snd_pcm_period_elapsed(substream); return 0; @@ -443,14 +445,16 @@ static int fsi_data_pop(struct fsi_priv *fsi) int fifo_fill; int width; u8 *start; - int i; + int i, over_period; if (!fsi || !fsi->substream || !fsi->substream->runtime) return -EINVAL; - runtime = fsi->substream->runtime; + over_period = 0; + substream = fsi->substream; + runtime = substream->runtime; /* FSI FIFO has limit. * So, this driver can not send periods data at a time @@ -458,7 +462,7 @@ static int fsi_data_pop(struct fsi_priv *fsi) if (fsi->byte_offset >= fsi->period_len * (fsi->periods + 1)) { - substream = fsi->substream; + over_period = 1; fsi->periods = (fsi->periods + 1) % runtime->periods; if (0 == fsi->periods) @@ -498,7 +502,7 @@ static int fsi_data_pop(struct fsi_priv *fsi) fsi_irq_enable(fsi, 0); - if (substream) + if (over_period) snd_pcm_period_elapsed(substream); return 0; -- cgit v1.2.3 From 142e8174b3c493f40469d3ecee0e404645e9c483 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Dec 2009 14:09:11 +0900 Subject: ASoC: fsi: Add fsi_get_dai to get snd_soc_dai Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index b311a9eaf021..d078151e1de6 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -210,11 +210,17 @@ static int fsi_is_port_a(struct fsi_priv *fsi) return fsi->master->base == fsi->base; } -static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) +static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_dai *dai = machine->cpu_dai; + + return machine->cpu_dai; +} + +static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) +{ + struct snd_soc_dai *dai = fsi_get_dai(substream); return dai->private_data; } -- cgit v1.2.3 From 59c3b003ddd3c815de1aa015920710a9e4bf195b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Dec 2009 14:09:16 +0900 Subject: ASoC: fsi: Add over/under run error settlement Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index d078151e1de6..123cd6f45e0c 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -67,6 +67,7 @@ /* DOFF_ST */ #define ERR_OVER 0x00000010 #define ERR_UNDER 0x00000001 +#define ST_ERR (ERR_OVER | ERR_UNDER) /* CLK_RST */ #define B_CLK 0x00000010 @@ -375,11 +376,12 @@ static int fsi_data_push(struct fsi_priv *fsi) { struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream = NULL; + u32 status; int send; int fifo_free; int width; u8 *start; - int i, over_period; + int i, ret, over_period; if (!fsi || !fsi->substream || @@ -435,23 +437,33 @@ static int fsi_data_push(struct fsi_priv *fsi) fsi->byte_offset += send * width; + ret = 0; + status = fsi_reg_read(fsi, DOFF_ST); + if (status & ERR_OVER) { + struct snd_soc_dai *dai = fsi_get_dai(substream); + dev_err(dai->dev, "over run error\n"); + fsi_reg_write(fsi, DOFF_ST, status & ~ST_ERR); + ret = -EIO; + } + fsi_irq_enable(fsi, 1); if (over_period) snd_pcm_period_elapsed(substream); - return 0; + return ret; } static int fsi_data_pop(struct fsi_priv *fsi) { struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream = NULL; + u32 status; int free; int fifo_fill; int width; u8 *start; - int i, over_period; + int i, ret, over_period; if (!fsi || !fsi->substream || @@ -506,12 +518,21 @@ static int fsi_data_pop(struct fsi_priv *fsi) fsi->byte_offset += fifo_fill * width; + ret = 0; + status = fsi_reg_read(fsi, DIFF_ST); + if (status & ERR_UNDER) { + struct snd_soc_dai *dai = fsi_get_dai(substream); + dev_err(dai->dev, "under run error\n"); + fsi_reg_write(fsi, DIFF_ST, status & ~ST_ERR); + ret = -EIO; + } + fsi_irq_enable(fsi, 0); if (over_period) snd_pcm_period_elapsed(substream); - return 0; + return ret; } static irqreturn_t fsi_interrupt(int irq, void *data) -- cgit v1.2.3 From 8fc176d5abb2d92c52df859faac7974b4a1585c1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 28 Jan 2010 13:46:16 +0900 Subject: ASoC: fsi: Add spin lock operation for accessing shared area fsi_master_xxx function should be protected by spin lock, because it are used from both FSI-A and FSI-B. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 5f9f2693f4eb..ebf358808db1 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -110,6 +110,7 @@ struct fsi_master { struct fsi_priv fsia; struct fsi_priv fsib; struct sh_fsi_platform_info *info; + spinlock_t lock; }; /************************************************************************ @@ -168,30 +169,51 @@ static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) static int fsi_master_write(struct fsi_master *master, u32 reg, u32 data) { + int ret; + unsigned long flags; + if ((reg < MREG_START) || (reg > MREG_END)) return -1; - return __fsi_reg_write((u32)(master->base + reg), data); + spin_lock_irqsave(&master->lock, flags); + ret = __fsi_reg_write((u32)(master->base + reg), data); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; } static u32 fsi_master_read(struct fsi_master *master, u32 reg) { + u32 ret; + unsigned long flags; + if ((reg < MREG_START) || (reg > MREG_END)) return 0; - return __fsi_reg_read((u32)(master->base + reg)); + spin_lock_irqsave(&master->lock, flags); + ret = __fsi_reg_read((u32)(master->base + reg)); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; } static int fsi_master_mask_set(struct fsi_master *master, u32 reg, u32 mask, u32 data) { + int ret; + unsigned long flags; + if ((reg < MREG_START) || (reg > MREG_END)) return -1; - return __fsi_reg_mask_set((u32)(master->base + reg), mask, data); + spin_lock_irqsave(&master->lock, flags); + ret = __fsi_reg_mask_set((u32)(master->base + reg), mask, data); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; } /************************************************************************ @@ -929,6 +951,7 @@ static int fsi_probe(struct platform_device *pdev) master->fsia.master = master; master->fsib.base = master->base + 0x40; master->fsib.master = master; + spin_lock_init(&master->lock); pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); -- cgit v1.2.3 From 0f69d9782c6e6a7b0e60113a850845bc642c3f4e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 3 Feb 2010 17:37:23 +0100 Subject: ASoC: fix compilation breakage in sound/soc/sh/fsi.c ctrl_outl() has become void at some point, which breaks compilation of fsi.c. Make writing functions void, as their output is anyway not evaluated, and use __raw_writel and __raw_readl instead of deprecated ctrl_outl and ctrl_inl respectively. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ebf358808db1..3c36d24a6c20 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -120,35 +120,35 @@ struct fsi_master { ************************************************************************/ -static int __fsi_reg_write(u32 reg, u32 data) +static void __fsi_reg_write(u32 reg, u32 data) { /* valid data area is 24bit */ data &= 0x00ffffff; - return ctrl_outl(data, reg); + __raw_writel(data, reg); } static u32 __fsi_reg_read(u32 reg) { - return ctrl_inl(reg); + return __raw_readl(reg); } -static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) +static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) { u32 val = __fsi_reg_read(reg); val &= ~mask; val |= data & mask; - return __fsi_reg_write(reg, val); + __fsi_reg_write(reg, val); } -static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) +static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) { if (reg > REG_END) - return -1; + return; - return __fsi_reg_write((u32)(fsi->base + reg), data); + __fsi_reg_write((u32)(fsi->base + reg), data); } static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) @@ -159,28 +159,25 @@ static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) return __fsi_reg_read((u32)(fsi->base + reg)); } -static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) +static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) { if (reg > REG_END) - return -1; + return; - return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); + __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); } -static int fsi_master_write(struct fsi_master *master, u32 reg, u32 data) +static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data) { - int ret; unsigned long flags; if ((reg < MREG_START) || (reg > MREG_END)) - return -1; + return; spin_lock_irqsave(&master->lock, flags); - ret = __fsi_reg_write((u32)(master->base + reg), data); + __fsi_reg_write((u32)(master->base + reg), data); spin_unlock_irqrestore(&master->lock, flags); - - return ret; } static u32 fsi_master_read(struct fsi_master *master, u32 reg) @@ -199,21 +196,18 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg) return ret; } -static int fsi_master_mask_set(struct fsi_master *master, +static void fsi_master_mask_set(struct fsi_master *master, u32 reg, u32 mask, u32 data) { - int ret; unsigned long flags; if ((reg < MREG_START) || (reg > MREG_END)) - return -1; + return; spin_lock_irqsave(&master->lock, flags); - ret = __fsi_reg_mask_set((u32)(master->base + reg), mask, data); + __fsi_reg_mask_set((u32)(master->base + reg), mask, data); spin_unlock_irqrestore(&master->lock, flags); - - return ret; } /************************************************************************ -- cgit v1.2.3 From 47fc9a0a808f23b7b305f6c018e4882118b88d92 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Feb 2010 16:41:57 +0900 Subject: ASoC: fsi: Modify over/under run error settlement In current FSI driver, playback function cares only overrun, and capture function cares only underrun. But playback function should had cared about underrun, and capture function should had cared about overrun too. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 3c36d24a6c20..993abb730dfa 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -388,7 +388,7 @@ static void fsi_soft_all_reset(struct fsi_master *master) } /* playback interrupt */ -static int fsi_data_push(struct fsi_priv *fsi) +static int fsi_data_push(struct fsi_priv *fsi, int startup) { struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream = NULL; @@ -397,7 +397,7 @@ static int fsi_data_push(struct fsi_priv *fsi) int fifo_free; int width; u8 *start; - int i, ret, over_period; + int i, over_period; if (!fsi || !fsi->substream || @@ -453,24 +453,26 @@ static int fsi_data_push(struct fsi_priv *fsi) fsi->byte_offset += send * width; - ret = 0; status = fsi_reg_read(fsi, DOFF_ST); - if (status & ERR_OVER) { + if (!startup) { struct snd_soc_dai *dai = fsi_get_dai(substream); - dev_err(dai->dev, "over run error\n"); - fsi_reg_write(fsi, DOFF_ST, status & ~ST_ERR); - ret = -EIO; + + if (status & ERR_OVER) + dev_err(dai->dev, "over run\n"); + if (status & ERR_UNDER) + dev_err(dai->dev, "under run\n"); } + fsi_reg_write(fsi, DOFF_ST, 0); fsi_irq_enable(fsi, 1); if (over_period) snd_pcm_period_elapsed(substream); - return ret; + return 0; } -static int fsi_data_pop(struct fsi_priv *fsi) +static int fsi_data_pop(struct fsi_priv *fsi, int startup) { struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream = NULL; @@ -479,7 +481,7 @@ static int fsi_data_pop(struct fsi_priv *fsi) int fifo_fill; int width; u8 *start; - int i, ret, over_period; + int i, over_period; if (!fsi || !fsi->substream || @@ -534,21 +536,23 @@ static int fsi_data_pop(struct fsi_priv *fsi) fsi->byte_offset += fifo_fill * width; - ret = 0; status = fsi_reg_read(fsi, DIFF_ST); - if (status & ERR_UNDER) { + if (!startup) { struct snd_soc_dai *dai = fsi_get_dai(substream); - dev_err(dai->dev, "under run error\n"); - fsi_reg_write(fsi, DIFF_ST, status & ~ST_ERR); - ret = -EIO; + + if (status & ERR_OVER) + dev_err(dai->dev, "over run\n"); + if (status & ERR_UNDER) + dev_err(dai->dev, "under run\n"); } + fsi_reg_write(fsi, DIFF_ST, 0); fsi_irq_enable(fsi, 0); if (over_period) snd_pcm_period_elapsed(substream); - return ret; + return 0; } static irqreturn_t fsi_interrupt(int irq, void *data) @@ -562,13 +566,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data) fsi_master_write(master, SOFT_RST, status | 0x00000010); if (int_st & INT_A_OUT) - fsi_data_push(&master->fsia); + fsi_data_push(&master->fsia, 0); if (int_st & INT_B_OUT) - fsi_data_push(&master->fsib); + fsi_data_push(&master->fsib, 0); if (int_st & INT_A_IN) - fsi_data_pop(&master->fsia); + fsi_data_pop(&master->fsia, 0); if (int_st & INT_B_IN) - fsi_data_pop(&master->fsib); + fsi_data_pop(&master->fsib, 0); fsi_master_write(master, INT_ST, 0x0000000); @@ -726,7 +730,7 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, fsi_stream_push(fsi, substream, frames_to_bytes(runtime, runtime->buffer_size), frames_to_bytes(runtime, runtime->period_size)); - ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); + ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1); break; case SNDRV_PCM_TRIGGER_STOP: fsi_irq_disable(fsi, is_play); -- cgit v1.2.3