Загрузка данных


static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
			    struct snd_soc_dai *dai)
{
	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	unsigned long lock_flags;
	int ret = 0;

	spin_lock_irqsave(&xcvr->lock, lock_flags);

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		/* set DPATH RESET */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx));
		if (ret < 0) {
			dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret);
			goto release_lock;
		}

		if (tx) {
			switch (xcvr->mode) {
			case FSL_XCVR_MODE_EARC:
				/* set isr_cmdc_tx_en, w1c */
				ret = regmap_write(xcvr->regmap,
						   FSL_XCVR_ISR_SET,
						   FSL_XCVR_ISR_CMDC_TX_EN);
				if (ret < 0) {
					dev_err(dai->dev, "err updating isr %d\n", ret);
					goto release_lock;
				}
				fallthrough;
			case FSL_XCVR_MODE_SPDIF:
				ret = regmap_set_bits(xcvr->regmap,
						      FSL_XCVR_TX_DPTH_CTRL,
						      FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
				if (ret < 0) {
					dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
					goto release_lock;
				}
				break;
			}
		}

		/* enable DMA RD/WR */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
		if (ret < 0) {
			dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
			goto release_lock;
		}

		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
					 FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
		if (ret < 0) {
			dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
			goto release_lock;
		}

		/* clear DPATH RESET */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
					 0);
		if (ret < 0) {
			dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret);
			goto release_lock;
		}

		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		/* disable DMA RD/WR */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
		if (ret < 0) {
			dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
			goto release_lock;
		}

		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
					 FSL_XCVR_IRQ_EARC_ALL, 0);
		if (ret < 0) {
			dev_err(dai->dev, "Failed to clear IER0: %d\n", ret);
			goto release_lock;
		}

		if (tx) {
			switch (xcvr->mode) {
			case FSL_XCVR_MODE_SPDIF:
				ret = regmap_clear_bits(xcvr->regmap,
							FSL_XCVR_TX_DPTH_CTRL,
							FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
				if (ret < 0) {
					dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
					goto release_lock;
				}
				if (xcvr->soc_data->spdif_only)
					break;
				else
					fallthrough;
			case FSL_XCVR_MODE_EARC:
				/* clear ISR_CMDC_TX_EN, W1C */
				ret = regmap_write(xcvr->regmap,
						   FSL_XCVR_ISR_CLR,
						   FSL_XCVR_ISR_CMDC_TX_EN);
				if (ret < 0) {
					dev_err(dai->dev,
						"Err updating ISR %d\n", ret);
					goto release_lock;
				}
				break;
			}
		}
		break;
	default:
		ret = -EINVAL;
		break;
	}

release_lock:
	spin_unlock_irqrestore(&xcvr->lock, lock_flags);
	return ret;
}

static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
{
	struct device *dev = &xcvr->pdev->dev;
	const struct firmware *fw;
	int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET;
	u32 mask, val;

	ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev);
	if (ret) {
		dev_err(dev, "failed to request firmware.\n");
		return ret;
	}

	rem = fw->size;

	/* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */
	if (rem > 16384) {
		dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
		release_firmware(fw);
		return -ENOMEM;
	}

	for (page = 0; page < 10; page++) {
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_PAGE_MASK,
					 FSL_XCVR_EXT_CTRL_PAGE(page));
		if (ret < 0) {
			dev_err(dev, "FW: failed to set page %d, err=%d\n",
				page, ret);
			goto err_firmware;
		}

		off = page * size;
		out = min(rem, size);
		/* IPG clock is assumed to be running, otherwise it will hang */
		if (out > 0) {
			/* write firmware into code memory */
			memcpy_toio(xcvr->ram_addr, fw->data + off, out);
			rem -= out;
			if (rem == 0) {
				/* last part of firmware written */
				/* clean remaining part of code memory page */
				memset_io(xcvr->ram_addr + out, 0, size - out);
			}
		} else {
			/* clean current page, including data memory */
			memset_io(xcvr->ram_addr, 0, size);
		}
	}

err_firmware:
	release_firmware(fw);
	if (ret < 0)
		return ret;

	/* configure watermarks */
	mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
	val  = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
	val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX);
	/* disable DMA RD/WR */
	mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
	val  |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
	/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
	mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK;
	val  |= FSL_XCVR_EXT_CTRL_PAGE(8);

	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
	if (ret < 0) {
		dev_err(dev, "Failed to set watermarks: %d\n", ret);
		return ret;
	}

	/* Store Capabilities Data Structure into Data RAM */
	memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds,
		    FSL_XCVR_CAPDS_SIZE);
	return 0;
}

static int fsl_xcvr_type_iec958_info(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
	uinfo->count = 1;

	return 0;
}

static int fsl_xcvr_type_iec958_bytes_info(struct snd_kcontrol *kcontrol,
					   struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
	uinfo->count = sizeof_field(struct snd_aes_iec958, status);

	return 0;
}

static int fsl_xcvr_rx_cs_get(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);

	memcpy(ucontrol->value.iec958.status, xcvr->rx_iec958.status, 24);

	return 0;
}

static int fsl_xcvr_tx_cs_get(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);

	memcpy(ucontrol->value.iec958.status, xcvr->tx_iec958.status, 24);

	return 0;
}

static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);

	memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status, 24);

	return 0;
}

static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = {
	/* Channel status controller */
	{
		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
		.access = SNDRV_CTL_ELEM_ACCESS_READ,
		.info = fsl_xcvr_type_iec958_info,
		.get = fsl_xcvr_rx_cs_get,
	},
	/* Capture channel status, bytes */
	{
		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
		.name = "Capture Channel Status",
		.access = SNDRV_CTL_ELEM_ACCESS_READ,
		.info = fsl_xcvr_type_iec958_bytes_info,
		.get = fsl_xcvr_rx_cs_get,
	},
};

static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
	/* Channel status controller */
	{
		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
		.info = fsl_xcvr_type_iec958_info,
		.get = fsl_xcvr_tx_cs_get,
		.put = fsl_xcvr_tx_cs_put,
	},
	/* Playback channel status, bytes */
	{
		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
		.name = "Playback Channel Status",
		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
		.info = fsl_xcvr_type_iec958_bytes_info,
		.get = fsl_xcvr_tx_cs_get,
		.put = fsl_xcvr_tx_cs_put,
	},
};