Commit fed25395 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'asoc/topic/davinci', 'asoc/topic/doc',...

Merge remote-tracking branches 'asoc/topic/davinci', 'asoc/topic/doc', 'asoc/topic/dpcm', 'asoc/topic/dwc' and 'asoc/topic/fsi' into asoc-next
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ Optional properties:
- rx-num-evt : FIFO levels.
- sram-size-playback : size of sram to be allocated during playback
- sram-size-capture  : size of sram to be allocated during capture
- interrupts : Interrupt numbers for McASP, currently not used by the driver
- interrupts : Interrupt numbers for McASP
- interrupt-names : Known interrupt names are "tx" and "rx"
- pinctrl-0: Should specify pin control group used for this controller.
- pinctrl-names: Should contain only one value - "default", for more details
+236 −26
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ struct davinci_mcasp {
	void __iomem *base;
	u32 fifo_base;
	struct device *dev;
	struct snd_pcm_substream *substreams[2];

	/* McASP specific data */
	int	tdm_slots;
@@ -80,6 +81,7 @@ struct davinci_mcasp {
	u8	bclk_div;
	u16	bclk_lrclk_ratio;
	int	streams;
	u32	irq_request[2];

	int	sysclk_freq;
	bool	bclk_master;
@@ -90,6 +92,9 @@ struct davinci_mcasp {

	bool	dat_port;

	/* Used for comstraint setting on the second stream */
	u32	channels;

#ifdef CONFIG_PM_SLEEP
	struct davinci_mcasp_context context;
#endif
@@ -154,6 +159,13 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)

static void mcasp_start_rx(struct davinci_mcasp *mcasp)
{
	if (mcasp->rxnumevt) {	/* enable FIFO */
		u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;

		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
	}

	/* Start clocks */
	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
@@ -175,12 +187,23 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
	if (mcasp_is_synchronous(mcasp))
		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);

	/* enable receive IRQs */
	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
}

static void mcasp_start_tx(struct davinci_mcasp *mcasp)
{
	u32 cnt;

	if (mcasp->txnumevt) {	/* enable FIFO */
		u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;

		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
	}

	/* Start clocks */
	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
@@ -197,33 +220,28 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
	/* Release Frame Sync generator */
	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);

	/* enable transmit IRQs */
	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
}

static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
{
	u32 reg;

	mcasp->streams++;

	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
		if (mcasp->txnumevt) {	/* enable FIFO */
			reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
			mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
			mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
		}
	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
		mcasp_start_tx(mcasp);
	} else {
		if (mcasp->rxnumevt) {	/* enable FIFO */
			reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
			mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
			mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
		}
	else
		mcasp_start_rx(mcasp);
}
}

static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
{
	/* disable IRQ sources */
	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);

	/*
	 * In synchronous mode stop the TX clocks if no other stream is
	 * running
@@ -245,6 +263,10 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
{
	u32 val = 0;

	/* disable IRQ sources */
	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);

	/*
	 * In synchronous mode keep TX clocks running if the capture stream is
	 * still running.
@@ -272,6 +294,76 @@ static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
		mcasp_stop_rx(mcasp);
}

static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
{
	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
	struct snd_pcm_substream *substream;
	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
	u32 handled_mask = 0;
	u32 stat;

	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
	if (stat & XUNDRN & irq_mask) {
		dev_warn(mcasp->dev, "Transmit buffer underflow\n");
		handled_mask |= XUNDRN;

		substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
		if (substream) {
			snd_pcm_stream_lock_irq(substream);
			if (snd_pcm_running(substream))
				snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
			snd_pcm_stream_unlock_irq(substream);
		}
	}

	if (!handled_mask)
		dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
			 stat);

	if (stat & XRERR)
		handled_mask |= XRERR;

	/* Ack the handled event only */
	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);

	return IRQ_RETVAL(handled_mask);
}

static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
{
	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
	struct snd_pcm_substream *substream;
	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
	u32 handled_mask = 0;
	u32 stat;

	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
	if (stat & ROVRN & irq_mask) {
		dev_warn(mcasp->dev, "Receive buffer overflow\n");
		handled_mask |= ROVRN;

		substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
		if (substream) {
			snd_pcm_stream_lock_irq(substream);
			if (snd_pcm_running(substream))
				snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
			snd_pcm_stream_unlock_irq(substream);
		}
	}

	if (!handled_mask)
		dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
			 stat);

	if (stat & XRERR)
		handled_mask |= XRERR;

	/* Ack the handled event only */
	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);

	return IRQ_RETVAL(handled_mask);
}

static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
					 unsigned int fmt)
{
@@ -634,19 +726,29 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
	return 0;
}

static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
			      int channels)
{
	int i, active_slots;
	int total_slots;
	int active_serializers;
	u32 mask = 0;
	u32 busel = 0;

	if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) {
		dev_err(mcasp->dev, "tdm slot %d not supported\n",
			mcasp->tdm_slots);
		return -EINVAL;
	}
	total_slots = mcasp->tdm_slots;

	/*
	 * If more than one serializer is needed, then use them with
	 * their specified tdm_slots count. Otherwise, one serializer
	 * can cope with the transaction using as many slots as channels
	 * in the stream, requires channels symmetry
	 */
	active_serializers = (channels + total_slots - 1) / total_slots;
	if (active_serializers == 1)
		active_slots = channels;
	else
		active_slots = total_slots;

	active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
	for (i = 0; i < active_slots; i++)
		mask |= (1 << i);

@@ -658,12 +760,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
	mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
		       FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
		       FSXMOD(total_slots), FSXMOD(0x1FF));

	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
	mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
	mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
		       FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
		       FSRMOD(total_slots), FSRMOD(0x1FF));

	return 0;
}
@@ -777,7 +879,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
		ret = mcasp_dit_hw_param(mcasp, params_rate(params));
	else
		ret = mcasp_i2s_hw_param(mcasp, substream->stream);
		ret = mcasp_i2s_hw_param(mcasp, substream->stream,
					 channels);

	if (ret)
		return ret;
@@ -825,6 +928,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,

	davinci_config_channel_size(mcasp, word_length);

	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
		mcasp->channels = channels;

	return 0;
}

@@ -853,7 +959,65 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
	return ret;
}

static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
				 struct snd_soc_dai *cpu_dai)
{
	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
	u32 max_channels = 0;
	int i, dir;

	mcasp->substreams[substream->stream] = substream;

	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
		return 0;

	/*
	 * Limit the maximum allowed channels for the first stream:
	 * number of serializers for the direction * tdm slots per serializer
	 */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		dir = TX_MODE;
	else
		dir = RX_MODE;

	for (i = 0; i < mcasp->num_serializer; i++) {
		if (mcasp->serial_dir[i] == dir)
			max_channels++;
	}
	max_channels *= mcasp->tdm_slots;
	/*
	 * If the already active stream has less channels than the calculated
	 * limnit based on the seirializers * tdm_slots, we need to use that as
	 * a constraint for the second stream.
	 * Otherwise (first stream or less allowed channels) we use the
	 * calculated constraint.
	 */
	if (mcasp->channels && mcasp->channels < max_channels)
		max_channels = mcasp->channels;

	snd_pcm_hw_constraint_minmax(substream->runtime,
				     SNDRV_PCM_HW_PARAM_CHANNELS,
				     2, max_channels);
	return 0;
}

static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
				   struct snd_soc_dai *cpu_dai)
{
	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);

	mcasp->substreams[substream->stream] = NULL;

	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
		return;

	if (!cpu_dai->active)
		mcasp->channels = 0;
}

static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
	.startup	= davinci_mcasp_startup,
	.shutdown	= davinci_mcasp_shutdown,
	.trigger	= davinci_mcasp_trigger,
	.hw_params	= davinci_mcasp_hw_params,
	.set_fmt	= davinci_mcasp_set_dai_fmt,
@@ -1194,6 +1358,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
	struct resource *mem, *ioarea, *res, *dat;
	struct davinci_mcasp_pdata *pdata;
	struct davinci_mcasp *mcasp;
	char *irq_name;
	int irq;
	int ret;

	if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -1247,7 +1413,21 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
	}

	mcasp->op_mode = pdata->op_mode;
	/* sanity check for tdm slots parameter */
	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
		if (pdata->tdm_slots < 2) {
			dev_err(&pdev->dev, "invalid tdm slots: %d\n",
				pdata->tdm_slots);
			mcasp->tdm_slots = 2;
		} else if (pdata->tdm_slots > 32) {
			dev_err(&pdev->dev, "invalid tdm slots: %d\n",
				pdata->tdm_slots);
			mcasp->tdm_slots = 32;
		} else {
			mcasp->tdm_slots = pdata->tdm_slots;
		}
	}

	mcasp->num_serializer = pdata->num_serializer;
#ifdef CONFIG_PM_SLEEP
	mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
@@ -1261,6 +1441,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev)

	mcasp->dev = &pdev->dev;

	irq = platform_get_irq_byname(pdev, "rx");
	if (irq >= 0) {
		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n",
					  dev_name(&pdev->dev));
		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
						davinci_mcasp_rx_irq_handler,
						IRQF_ONESHOT, irq_name, mcasp);
		if (ret) {
			dev_err(&pdev->dev, "RX IRQ request failed\n");
			goto err;
		}

		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
	}

	irq = platform_get_irq_byname(pdev, "tx");
	if (irq >= 0) {
		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n",
					  dev_name(&pdev->dev));
		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
						davinci_mcasp_tx_irq_handler,
						IRQF_ONESHOT, irq_name, mcasp);
		if (ret) {
			dev_err(&pdev->dev, "TX IRQ request failed\n");
			goto err;
		}

		mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
	}

	dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
	if (dat)
		mcasp->dat_port = true;
+11 −0
Original line number Diff line number Diff line
@@ -256,6 +256,7 @@
 * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits
 * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits
 */
#define XRERR		BIT(8) /* Transmit/Receive error */
#define XRDATA		BIT(5) /* Transmit/Receive data ready */

/*
@@ -284,6 +285,16 @@
 */
#define TXDATADMADIS	BIT(0)

/*
 * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits
 */
#define ROVRN		BIT(0)

/*
 * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits
 */
#define XUNDRN		BIT(0)

/*
 * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
 */
+19 −27
Original line number Diff line number Diff line
@@ -338,31 +338,34 @@ static int dw_i2s_probe(struct platform_device *pdev)
		return -EINVAL;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "no i2s resource defined\n");
		return -ENODEV;
	}

	if (!devm_request_mem_region(&pdev->dev, res->start,
				resource_size(res), pdev->name)) {
		dev_err(&pdev->dev, "i2s region already claimed\n");
		return -EBUSY;
	}

	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
	if (!dev) {
		dev_warn(&pdev->dev, "kzalloc fail\n");
		return -ENOMEM;
	}

	dev->i2s_base = devm_ioremap(&pdev->dev, res->start,
			resource_size(res));
	if (!dev->i2s_base) {
		dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
	dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
	if (!dw_i2s_dai) {
		dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
		return -ENOMEM;
	}

	dw_i2s_dai->ops = &dw_i2s_dai_ops;
	dw_i2s_dai->suspend = dw_i2s_suspend;
	dw_i2s_dai->resume = dw_i2s_resume;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "no i2s resource defined\n");
		return -ENODEV;
	}

	dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(dev->i2s_base)) {
		dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
		return PTR_ERR(dev->i2s_base);
	}

	cap = pdata->cap;
	dev->capability = cap;
	dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
@@ -388,13 +391,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
	if (ret < 0)
		goto err_clk_put;

	dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
	if (!dw_i2s_dai) {
		dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
		ret = -ENOMEM;
		goto err_clk_disable;
	}

	if (cap & DWC_I2S_PLAY) {
		dev_dbg(&pdev->dev, " designware: play supported\n");
		dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
@@ -411,10 +407,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
		dw_i2s_dai->capture.rates = pdata->snd_rates;
	}

	dw_i2s_dai->ops = &dw_i2s_dai_ops;
	dw_i2s_dai->suspend = dw_i2s_suspend;
	dw_i2s_dai->resume = dw_i2s_resume;

	dev->dev = &pdev->dev;
	dev_set_drvdata(&pdev->dev, dev);
	ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
+3 −6
Original line number Diff line number Diff line
@@ -842,11 +842,8 @@ static int fsi_clk_disable(struct device *dev,
		return -EINVAL;

	if (1 == clock->count--) {
		if (clock->xck)
		clk_disable(clock->xck);
		if (clock->ick)
		clk_disable(clock->ick);
		if (clock->div)
		clk_disable(clock->div);
	}

Loading