Beispiel #1
0
static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
{
	struct lpass_data *drvdata = dev_get_drvdata(dev);
	struct lpass_variant *v = drvdata->variant;
	int i;

	for (i = 0; i < v->i2s_ports; ++i)
		if (reg == LPAIF_I2SCTL_REG(v, i))
			return true;

	for (i = 0; i < v->irq_ports; ++i) {
		if (reg == LPAIF_IRQEN_REG(v, i))
			return true;
		if (reg == LPAIF_IRQSTAT_REG(v, i))
			return true;
	}

	for (i = 0; i < v->rdma_channels; ++i) {
		if (reg == LPAIF_RDMACTL_REG(v, i))
			return true;
		if (reg == LPAIF_RDMABASE_REG(v, i))
			return true;
		if (reg == LPAIF_RDMABUFF_REG(v, i))
			return true;
		if (reg == LPAIF_RDMACURR_REG(v, i))
			return true;
		if (reg == LPAIF_RDMAPER_REG(v, i))
			return true;
	}

	return false;
}
Beispiel #2
0
static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
{
	int i;

	for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
		if (reg == LPAIF_I2SCTL_REG(i))
			return true;

	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
		if (reg == LPAIF_IRQEN_REG(i))
			return true;
		if (reg == LPAIF_IRQSTAT_REG(i))
			return true;
	}

	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
		if (reg == LPAIF_RDMACTL_REG(i))
			return true;
		if (reg == LPAIF_RDMABASE_REG(i))
			return true;
		if (reg == LPAIF_RDMABUFF_REG(i))
			return true;
		if (reg == LPAIF_RDMACURR_REG(i))
			return true;
		if (reg == LPAIF_RDMAPER_REG(i))
			return true;
	}

	return false;
}
Beispiel #3
0
static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
	struct lpass_data *drvdata =
		snd_soc_platform_get_drvdata(soc_runtime->platform);
	int ret;

	ret = regmap_write(drvdata->lpaif_map,
			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
	if (ret)
		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
				__func__, ret);

	return ret;
}
Beispiel #4
0
static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
{
	struct snd_pcm *pcm = soc_runtime->pcm;
	struct snd_pcm_substream *substream =
		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
	struct lpass_data *drvdata =
		snd_soc_platform_get_drvdata(soc_runtime->platform);
	int ret;

	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
	soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;

	ret = lpass_platform_alloc_buffer(substream, soc_runtime);
	if (ret)
		return ret;

	ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
			"lpass-irq-lpaif", substream);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
				__func__, ret);
		goto err_buf;
	}

	/* ensure audio hardware is disabled */
	ret = regmap_write(drvdata->lpaif_map,
			LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
				__func__, ret);
		return ret;
	}
	ret = regmap_write(drvdata->lpaif_map,
			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
				__func__, ret);
		return ret;
	}

	return 0;

err_buf:
	lpass_platform_free_buffer(substream, soc_runtime);
	return ret;
}
Beispiel #5
0
static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
	struct lpass_data *drvdata =
		snd_soc_platform_get_drvdata(soc_runtime->platform);
	int ret;

	ret = regmap_write(drvdata->lpaif_map,
			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S),
			runtime->dma_addr);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
				__func__, ret);
		return ret;
	}

	ret = regmap_write(drvdata->lpaif_map,
			LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S),
			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
				__func__, ret);
		return ret;
	}

	ret = regmap_write(drvdata->lpaif_map,
			LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S),
			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
				__func__, ret);
		return ret;
	}

	ret = regmap_update_bits(drvdata->lpaif_map,
			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
				__func__, ret);
		return ret;
	}

	return 0;
}
Beispiel #6
0
static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
		struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
	struct lpass_data *drvdata =
		snd_soc_platform_get_drvdata(soc_runtime->platform);
	snd_pcm_format_t format = params_format(params);
	unsigned int channels = params_channels(params);
	unsigned int regval;
	int bitwidth;
	int ret;

	bitwidth = snd_pcm_format_width(format);
	if (bitwidth < 0) {
		dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n",
				__func__, bitwidth);
		return bitwidth;
	}

	regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
			LPAIF_RDMACTL_AUDINTF_MI2S |
			LPAIF_RDMACTL_FIFOWM_8;

	switch (bitwidth) {
	case 16:
		switch (channels) {
		case 1:
		case 2:
			regval |= LPAIF_RDMACTL_WPSCNT_ONE;
			break;
		case 4:
			regval |= LPAIF_RDMACTL_WPSCNT_TWO;
			break;
		case 6:
			regval |= LPAIF_RDMACTL_WPSCNT_THREE;
			break;
		case 8:
			regval |= LPAIF_RDMACTL_WPSCNT_FOUR;
			break;
		default:
			dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
					__func__, bitwidth, channels);
			return -EINVAL;
		}
		break;
	case 24:
	case 32:
		switch (channels) {
		case 1:
			regval |= LPAIF_RDMACTL_WPSCNT_ONE;
			break;
		case 2:
			regval |= LPAIF_RDMACTL_WPSCNT_TWO;
			break;
		case 4:
			regval |= LPAIF_RDMACTL_WPSCNT_FOUR;
			break;
		case 6:
			regval |= LPAIF_RDMACTL_WPSCNT_SIX;
			break;
		case 8:
			regval |= LPAIF_RDMACTL_WPSCNT_EIGHT;
			break;
		default:
			dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
					__func__, bitwidth, channels);
			return -EINVAL;
		}
		break;
	default:
		dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
				__func__, bitwidth, channels);
		return -EINVAL;
	}

	ret = regmap_write(drvdata->lpaif_map,
			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval);
	if (ret) {
		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
				__func__, ret);
		return ret;
	}

	return 0;
}
Beispiel #7
0
static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
		int cmd)
{
	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
	struct lpass_data *drvdata =
		snd_soc_platform_get_drvdata(soc_runtime->platform);
	int ret;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		/* clear status before enabling interrupts */
		ret = regmap_write(drvdata->lpaif_map,
				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
		if (ret) {
			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
					__func__, ret);
			return ret;
		}

		ret = regmap_update_bits(drvdata->lpaif_map,
				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
		if (ret) {
			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
					__func__, ret);
			return ret;
		}

		ret = regmap_update_bits(drvdata->lpaif_map,
				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
				LPAIF_RDMACTL_ENABLE_MASK,
				LPAIF_RDMACTL_ENABLE_ON);
		if (ret) {
			dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
					__func__, ret);
			return ret;
		}
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		ret = regmap_update_bits(drvdata->lpaif_map,
				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
				LPAIF_RDMACTL_ENABLE_MASK,
				LPAIF_RDMACTL_ENABLE_OFF);
		if (ret) {
			dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
					__func__, ret);
			return ret;
		}

		ret = regmap_update_bits(drvdata->lpaif_map,
				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
		if (ret) {
			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
					__func__, ret);
			return ret;
		}
		break;
	}

	return 0;
}