Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3670536 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mark Brown
Browse files

ASoC: samsung: i2s: Add spinlock in place of local_irq_* calls



It seems this driver hasn't been updated for SMP, as local_irq_save/
local_irq_restore don't provide proper protection of read/modify/write
of the device's registers on such systems. Introduce a spinlock
serializing access to the register region, it will be helpful later
when I2SMOD, I2SPSR registers are made also accessible through the
clk API.

Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 872c26bd
Loading
Loading
Loading
Loading
+13 −5
Original line number Original line Diff line number Diff line
@@ -94,6 +94,10 @@ struct i2s_dai {
	u32	suspend_i2scon;
	u32	suspend_i2scon;
	u32	suspend_i2spsr;
	u32	suspend_i2spsr;
	const struct samsung_i2s_variant_regs *variant_regs;
	const struct samsung_i2s_variant_regs *variant_regs;

	/* Spinlock protecting access to the device's registers */
	spinlock_t spinlock;
	spinlock_t *lock;
};
};


/* Lock for cross i/f checks */
/* Lock for cross i/f checks */
@@ -867,10 +871,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		local_irq_save(flags);
		spin_lock_irqsave(i2s->lock, flags);


		if (config_setup(i2s)) {
		if (config_setup(i2s)) {
			local_irq_restore(flags);
			spin_unlock_irqrestore(i2s->lock, flags);
			return -EINVAL;
			return -EINVAL;
		}
		}


@@ -879,12 +883,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
		else
		else
			i2s_txctrl(i2s, 1);
			i2s_txctrl(i2s, 1);


		local_irq_restore(flags);
		spin_unlock_irqrestore(i2s->lock, flags);
		break;
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		local_irq_save(flags);
		spin_lock_irqsave(i2s->lock, flags);


		if (capture) {
		if (capture) {
			i2s_rxctrl(i2s, 0);
			i2s_rxctrl(i2s, 0);
@@ -894,7 +898,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
			i2s_fifo(i2s, FIC_TXFLUSH);
			i2s_fifo(i2s, FIC_TXFLUSH);
		}
		}


		local_irq_restore(flags);
		spin_unlock_irqrestore(i2s->lock, flags);
		break;
		break;
	}
	}


@@ -1157,6 +1161,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	spin_lock_init(&pri_dai->spinlock);
	pri_dai->lock = &pri_dai->spinlock;

	if (!np) {
	if (!np) {
		res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
		res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
		if (!res) {
		if (!res) {
@@ -1234,6 +1241,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
			return -ENOMEM;
			return -ENOMEM;
		}
		}


		sec_dai->lock = &pri_dai->spinlock;
		sec_dai->variant_regs = pri_dai->variant_regs;
		sec_dai->variant_regs = pri_dai->variant_regs;
		sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
		sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
		sec_dai->dma_playback.ch_name = "tx-sec";
		sec_dai->dma_playback.ch_name = "tx-sec";