18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Support for Digigram Lola PCI-e boards
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
118c2ecf20Sopenharmony_ci#include <linux/pci.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <sound/core.h>
148c2ecf20Sopenharmony_ci#include <sound/pcm.h>
158c2ecf20Sopenharmony_ci#include "lola.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define LOLA_MAX_BDL_ENTRIES	8
188c2ecf20Sopenharmony_ci#define LOLA_MAX_BUF_SIZE	(1024*1024*1024)
198c2ecf20Sopenharmony_ci#define LOLA_BDL_ENTRY_SIZE	(16 * 16)
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	struct lola *chip = snd_pcm_substream_chip(substream);
248c2ecf20Sopenharmony_ci	return &chip->pcm[substream->stream];
258c2ecf20Sopenharmony_ci}
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic struct lola_stream *lola_get_stream(struct snd_pcm_substream *substream)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	struct lola_pcm *pcm = lola_get_pcm(substream);
308c2ecf20Sopenharmony_ci	unsigned int idx = substream->number;
318c2ecf20Sopenharmony_ci	return &pcm->streams[idx];
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic unsigned int lola_get_lrc(struct lola *chip)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return lola_readl(chip, BAR1, LRC);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic unsigned int lola_get_tstamp(struct lola *chip, bool quick_no_sync)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	unsigned int tstamp = lola_get_lrc(chip) >> 8;
428c2ecf20Sopenharmony_ci	if (chip->granularity) {
438c2ecf20Sopenharmony_ci		unsigned int wait_banks = quick_no_sync ? 0 : 8;
448c2ecf20Sopenharmony_ci		tstamp += (wait_banks + 1) * chip->granularity - 1;
458c2ecf20Sopenharmony_ci		tstamp -= tstamp % chip->granularity;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	return tstamp << 8;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* clear any pending interrupt status */
518c2ecf20Sopenharmony_cistatic void lola_stream_clear_pending_irq(struct lola *chip,
528c2ecf20Sopenharmony_ci					  struct lola_stream *str)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	unsigned int val = lola_dsd_read(chip, str->dsd, STS);
558c2ecf20Sopenharmony_ci	val &= LOLA_DSD_STS_DESE | LOLA_DSD_STS_BCIS;
568c2ecf20Sopenharmony_ci	if (val)
578c2ecf20Sopenharmony_ci		lola_dsd_write(chip, str->dsd, STS, val);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void lola_stream_start(struct lola *chip, struct lola_stream *str,
618c2ecf20Sopenharmony_ci			      unsigned int tstamp)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	lola_stream_clear_pending_irq(chip, str);
648c2ecf20Sopenharmony_ci	lola_dsd_write(chip, str->dsd, CTL,
658c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_SRUN |
668c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_IOCE |
678c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_DEIE |
688c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_VLRCV |
698c2ecf20Sopenharmony_ci		       tstamp);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic void lola_stream_stop(struct lola *chip, struct lola_stream *str,
738c2ecf20Sopenharmony_ci			     unsigned int tstamp)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	lola_dsd_write(chip, str->dsd, CTL,
768c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_IOCE |
778c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_DEIE |
788c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_VLRCV |
798c2ecf20Sopenharmony_ci		       tstamp);
808c2ecf20Sopenharmony_ci	lola_stream_clear_pending_irq(chip, str);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	unsigned long end_time = jiffies + msecs_to_jiffies(200);
868c2ecf20Sopenharmony_ci	while (time_before(jiffies, end_time)) {
878c2ecf20Sopenharmony_ci		unsigned int val;
888c2ecf20Sopenharmony_ci		val = lola_dsd_read(chip, str->dsd, CTL);
898c2ecf20Sopenharmony_ci		if (!(val & LOLA_DSD_CTL_SRST))
908c2ecf20Sopenharmony_ci			return;
918c2ecf20Sopenharmony_ci		msleep(1);
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci	dev_warn(chip->card->dev, "SRST not clear (stream %d)\n", str->dsd);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int lola_stream_wait_for_fifo(struct lola *chip,
978c2ecf20Sopenharmony_ci				     struct lola_stream *str,
988c2ecf20Sopenharmony_ci				     bool ready)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
1018c2ecf20Sopenharmony_ci	unsigned long end_time = jiffies + msecs_to_jiffies(200);
1028c2ecf20Sopenharmony_ci	while (time_before(jiffies, end_time)) {
1038c2ecf20Sopenharmony_ci		unsigned int reg = lola_dsd_read(chip, str->dsd, STS);
1048c2ecf20Sopenharmony_ci		if ((reg & LOLA_DSD_STS_FIFORDY) == val)
1058c2ecf20Sopenharmony_ci			return 0;
1068c2ecf20Sopenharmony_ci		msleep(1);
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci	dev_warn(chip->card->dev, "FIFO not ready (stream %d)\n", str->dsd);
1098c2ecf20Sopenharmony_ci	return -EIO;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* sync for FIFO ready/empty for all linked streams;
1138c2ecf20Sopenharmony_ci * clear paused flag when FIFO gets ready again
1148c2ecf20Sopenharmony_ci */
1158c2ecf20Sopenharmony_cistatic int lola_sync_wait_for_fifo(struct lola *chip,
1168c2ecf20Sopenharmony_ci				   struct snd_pcm_substream *substream,
1178c2ecf20Sopenharmony_ci				   bool ready)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
1208c2ecf20Sopenharmony_ci	unsigned long end_time = jiffies + msecs_to_jiffies(200);
1218c2ecf20Sopenharmony_ci	struct snd_pcm_substream *s;
1228c2ecf20Sopenharmony_ci	int pending = 0;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	while (time_before(jiffies, end_time)) {
1258c2ecf20Sopenharmony_ci		pending = 0;
1268c2ecf20Sopenharmony_ci		snd_pcm_group_for_each_entry(s, substream) {
1278c2ecf20Sopenharmony_ci			struct lola_stream *str;
1288c2ecf20Sopenharmony_ci			if (s->pcm->card != substream->pcm->card)
1298c2ecf20Sopenharmony_ci				continue;
1308c2ecf20Sopenharmony_ci			str = lola_get_stream(s);
1318c2ecf20Sopenharmony_ci			if (str->prepared && str->paused) {
1328c2ecf20Sopenharmony_ci				unsigned int reg;
1338c2ecf20Sopenharmony_ci				reg = lola_dsd_read(chip, str->dsd, STS);
1348c2ecf20Sopenharmony_ci				if ((reg & LOLA_DSD_STS_FIFORDY) != val) {
1358c2ecf20Sopenharmony_ci					pending = str->dsd + 1;
1368c2ecf20Sopenharmony_ci					break;
1378c2ecf20Sopenharmony_ci				}
1388c2ecf20Sopenharmony_ci				if (ready)
1398c2ecf20Sopenharmony_ci					str->paused = 0;
1408c2ecf20Sopenharmony_ci			}
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci		if (!pending)
1438c2ecf20Sopenharmony_ci			return 0;
1448c2ecf20Sopenharmony_ci		msleep(1);
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci	dev_warn(chip->card->dev, "FIFO not ready (pending %d)\n", pending - 1);
1478c2ecf20Sopenharmony_ci	return -EIO;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* finish pause - prepare for a new resume */
1518c2ecf20Sopenharmony_cistatic void lola_sync_pause(struct lola *chip,
1528c2ecf20Sopenharmony_ci			    struct snd_pcm_substream *substream)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct snd_pcm_substream *s;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	lola_sync_wait_for_fifo(chip, substream, false);
1578c2ecf20Sopenharmony_ci	snd_pcm_group_for_each_entry(s, substream) {
1588c2ecf20Sopenharmony_ci		struct lola_stream *str;
1598c2ecf20Sopenharmony_ci		if (s->pcm->card != substream->pcm->card)
1608c2ecf20Sopenharmony_ci			continue;
1618c2ecf20Sopenharmony_ci		str = lola_get_stream(s);
1628c2ecf20Sopenharmony_ci		if (str->paused && str->prepared)
1638c2ecf20Sopenharmony_ci			lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN |
1648c2ecf20Sopenharmony_ci				       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci	lola_sync_wait_for_fifo(chip, substream, true);
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic void lola_stream_reset(struct lola *chip, struct lola_stream *str)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	if (str->prepared) {
1728c2ecf20Sopenharmony_ci		if (str->paused)
1738c2ecf20Sopenharmony_ci			lola_sync_pause(chip, str->substream);
1748c2ecf20Sopenharmony_ci		str->prepared = 0;
1758c2ecf20Sopenharmony_ci		lola_dsd_write(chip, str->dsd, CTL,
1768c2ecf20Sopenharmony_ci			       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
1778c2ecf20Sopenharmony_ci		lola_stream_wait_for_fifo(chip, str, false);
1788c2ecf20Sopenharmony_ci		lola_stream_clear_pending_irq(chip, str);
1798c2ecf20Sopenharmony_ci		lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST);
1808c2ecf20Sopenharmony_ci		lola_dsd_write(chip, str->dsd, LVI, 0);
1818c2ecf20Sopenharmony_ci		lola_dsd_write(chip, str->dsd, BDPU, 0);
1828c2ecf20Sopenharmony_ci		lola_dsd_write(chip, str->dsd, BDPL, 0);
1838c2ecf20Sopenharmony_ci		wait_for_srst_clear(chip, str);
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware lola_pcm_hw = {
1888c2ecf20Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
1898c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_INTERLEAVED |
1908c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
1918c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
1928c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_PAUSE),
1938c2ecf20Sopenharmony_ci	.formats =		(SNDRV_PCM_FMTBIT_S16_LE |
1948c2ecf20Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S24_LE |
1958c2ecf20Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S32_LE |
1968c2ecf20Sopenharmony_ci				 SNDRV_PCM_FMTBIT_FLOAT_LE),
1978c2ecf20Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_8000_192000,
1988c2ecf20Sopenharmony_ci	.rate_min =		8000,
1998c2ecf20Sopenharmony_ci	.rate_max =		192000,
2008c2ecf20Sopenharmony_ci	.channels_min =		1,
2018c2ecf20Sopenharmony_ci	.channels_max =		2,
2028c2ecf20Sopenharmony_ci	.buffer_bytes_max =	LOLA_MAX_BUF_SIZE,
2038c2ecf20Sopenharmony_ci	.period_bytes_min =	128,
2048c2ecf20Sopenharmony_ci	.period_bytes_max =	LOLA_MAX_BUF_SIZE / 2,
2058c2ecf20Sopenharmony_ci	.periods_min =		2,
2068c2ecf20Sopenharmony_ci	.periods_max =		LOLA_MAX_BDL_ENTRIES,
2078c2ecf20Sopenharmony_ci	.fifo_size =		0,
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic int lola_pcm_open(struct snd_pcm_substream *substream)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct lola *chip = snd_pcm_substream_chip(substream);
2138c2ecf20Sopenharmony_ci	struct lola_pcm *pcm = lola_get_pcm(substream);
2148c2ecf20Sopenharmony_ci	struct lola_stream *str = lola_get_stream(substream);
2158c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	mutex_lock(&chip->open_mutex);
2188c2ecf20Sopenharmony_ci	if (str->opened) {
2198c2ecf20Sopenharmony_ci		mutex_unlock(&chip->open_mutex);
2208c2ecf20Sopenharmony_ci		return -EBUSY;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	str->substream = substream;
2238c2ecf20Sopenharmony_ci	str->master = NULL;
2248c2ecf20Sopenharmony_ci	str->opened = 1;
2258c2ecf20Sopenharmony_ci	runtime->hw = lola_pcm_hw;
2268c2ecf20Sopenharmony_ci	runtime->hw.channels_max = pcm->num_streams - str->index;
2278c2ecf20Sopenharmony_ci	if (chip->sample_rate) {
2288c2ecf20Sopenharmony_ci		/* sample rate is locked */
2298c2ecf20Sopenharmony_ci		runtime->hw.rate_min = chip->sample_rate;
2308c2ecf20Sopenharmony_ci		runtime->hw.rate_max = chip->sample_rate;
2318c2ecf20Sopenharmony_ci	} else {
2328c2ecf20Sopenharmony_ci		runtime->hw.rate_min = chip->sample_rate_min;
2338c2ecf20Sopenharmony_ci		runtime->hw.rate_max = chip->sample_rate_max;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	chip->ref_count_rate++;
2368c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
2378c2ecf20Sopenharmony_ci	/* period size = multiple of chip->granularity (8, 16 or 32 frames)*/
2388c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
2398c2ecf20Sopenharmony_ci				   chip->granularity);
2408c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
2418c2ecf20Sopenharmony_ci				   chip->granularity);
2428c2ecf20Sopenharmony_ci	mutex_unlock(&chip->open_mutex);
2438c2ecf20Sopenharmony_ci	return 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic void lola_cleanup_slave_streams(struct lola_pcm *pcm,
2478c2ecf20Sopenharmony_ci				       struct lola_stream *str)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	int i;
2508c2ecf20Sopenharmony_ci	for (i = str->index + 1; i < pcm->num_streams; i++) {
2518c2ecf20Sopenharmony_ci		struct lola_stream *s = &pcm->streams[i];
2528c2ecf20Sopenharmony_ci		if (s->master != str)
2538c2ecf20Sopenharmony_ci			break;
2548c2ecf20Sopenharmony_ci		s->master = NULL;
2558c2ecf20Sopenharmony_ci		s->opened = 0;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int lola_pcm_close(struct snd_pcm_substream *substream)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct lola *chip = snd_pcm_substream_chip(substream);
2628c2ecf20Sopenharmony_ci	struct lola_stream *str = lola_get_stream(substream);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	mutex_lock(&chip->open_mutex);
2658c2ecf20Sopenharmony_ci	if (str->substream == substream) {
2668c2ecf20Sopenharmony_ci		str->substream = NULL;
2678c2ecf20Sopenharmony_ci		str->opened = 0;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci	if (--chip->ref_count_rate == 0) {
2708c2ecf20Sopenharmony_ci		/* release sample rate */
2718c2ecf20Sopenharmony_ci		chip->sample_rate = 0;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci	mutex_unlock(&chip->open_mutex);
2748c2ecf20Sopenharmony_ci	return 0;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic int lola_pcm_hw_params(struct snd_pcm_substream *substream,
2788c2ecf20Sopenharmony_ci			      struct snd_pcm_hw_params *hw_params)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct lola_stream *str = lola_get_stream(substream);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	str->bufsize = 0;
2838c2ecf20Sopenharmony_ci	str->period_bytes = 0;
2848c2ecf20Sopenharmony_ci	str->format_verb = 0;
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic int lola_pcm_hw_free(struct snd_pcm_substream *substream)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct lola *chip = snd_pcm_substream_chip(substream);
2918c2ecf20Sopenharmony_ci	struct lola_pcm *pcm = lola_get_pcm(substream);
2928c2ecf20Sopenharmony_ci	struct lola_stream *str = lola_get_stream(substream);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	mutex_lock(&chip->open_mutex);
2958c2ecf20Sopenharmony_ci	lola_stream_reset(chip, str);
2968c2ecf20Sopenharmony_ci	lola_cleanup_slave_streams(pcm, str);
2978c2ecf20Sopenharmony_ci	mutex_unlock(&chip->open_mutex);
2988c2ecf20Sopenharmony_ci	return 0;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/*
3028c2ecf20Sopenharmony_ci * set up a BDL entry
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_cistatic int setup_bdle(struct snd_pcm_substream *substream,
3058c2ecf20Sopenharmony_ci		      struct lola_stream *str, __le32 **bdlp,
3068c2ecf20Sopenharmony_ci		      int ofs, int size)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	__le32 *bdl = *bdlp;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	while (size > 0) {
3118c2ecf20Sopenharmony_ci		dma_addr_t addr;
3128c2ecf20Sopenharmony_ci		int chunk;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci		if (str->frags >= LOLA_MAX_BDL_ENTRIES)
3158c2ecf20Sopenharmony_ci			return -EINVAL;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		addr = snd_pcm_sgbuf_get_addr(substream, ofs);
3188c2ecf20Sopenharmony_ci		/* program the address field of the BDL entry */
3198c2ecf20Sopenharmony_ci		bdl[0] = cpu_to_le32((u32)addr);
3208c2ecf20Sopenharmony_ci		bdl[1] = cpu_to_le32(upper_32_bits(addr));
3218c2ecf20Sopenharmony_ci		/* program the size field of the BDL entry */
3228c2ecf20Sopenharmony_ci		chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
3238c2ecf20Sopenharmony_ci		bdl[2] = cpu_to_le32(chunk);
3248c2ecf20Sopenharmony_ci		/* program the IOC to enable interrupt
3258c2ecf20Sopenharmony_ci		 * only when the whole fragment is processed
3268c2ecf20Sopenharmony_ci		 */
3278c2ecf20Sopenharmony_ci		size -= chunk;
3288c2ecf20Sopenharmony_ci		bdl[3] = size ? 0 : cpu_to_le32(0x01);
3298c2ecf20Sopenharmony_ci		bdl += 4;
3308c2ecf20Sopenharmony_ci		str->frags++;
3318c2ecf20Sopenharmony_ci		ofs += chunk;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci	*bdlp = bdl;
3348c2ecf20Sopenharmony_ci	return ofs;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/*
3388c2ecf20Sopenharmony_ci * set up BDL entries
3398c2ecf20Sopenharmony_ci */
3408c2ecf20Sopenharmony_cistatic int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
3418c2ecf20Sopenharmony_ci			      struct snd_pcm_substream *substream,
3428c2ecf20Sopenharmony_ci			      struct lola_stream *str)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	__le32 *bdl;
3458c2ecf20Sopenharmony_ci	int i, ofs, periods, period_bytes;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	period_bytes = str->period_bytes;
3488c2ecf20Sopenharmony_ci	periods = str->bufsize / period_bytes;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* program the initial BDL entries */
3518c2ecf20Sopenharmony_ci	bdl = (__le32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index);
3528c2ecf20Sopenharmony_ci	ofs = 0;
3538c2ecf20Sopenharmony_ci	str->frags = 0;
3548c2ecf20Sopenharmony_ci	for (i = 0; i < periods; i++) {
3558c2ecf20Sopenharmony_ci		ofs = setup_bdle(substream, str, &bdl, ofs, period_bytes);
3568c2ecf20Sopenharmony_ci		if (ofs < 0)
3578c2ecf20Sopenharmony_ci			goto error;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci	return 0;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci error:
3628c2ecf20Sopenharmony_ci	dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n",
3638c2ecf20Sopenharmony_ci		   str->bufsize, period_bytes);
3648c2ecf20Sopenharmony_ci	return -EINVAL;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic unsigned int lola_get_format_verb(struct snd_pcm_substream *substream)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	unsigned int verb;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	switch (substream->runtime->format) {
3728c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
3738c2ecf20Sopenharmony_ci		verb = 0x00000000;
3748c2ecf20Sopenharmony_ci		break;
3758c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
3768c2ecf20Sopenharmony_ci		verb = 0x00000200;
3778c2ecf20Sopenharmony_ci		break;
3788c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32_LE:
3798c2ecf20Sopenharmony_ci		verb = 0x00000300;
3808c2ecf20Sopenharmony_ci		break;
3818c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_FLOAT_LE:
3828c2ecf20Sopenharmony_ci		verb = 0x00001300;
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci	default:
3858c2ecf20Sopenharmony_ci		return 0;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci	verb |= substream->runtime->channels;
3888c2ecf20Sopenharmony_ci	return verb;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic int lola_set_stream_config(struct lola *chip,
3928c2ecf20Sopenharmony_ci				  struct lola_stream *str,
3938c2ecf20Sopenharmony_ci				  int channels)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	int i, err;
3968c2ecf20Sopenharmony_ci	unsigned int verb, val;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/* set format info for all channels
3998c2ecf20Sopenharmony_ci	 * (with only one command for the first channel)
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT,
4028c2ecf20Sopenharmony_ci			      str->format_verb, 0, &val, NULL);
4038c2ecf20Sopenharmony_ci	if (err < 0) {
4048c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "Cannot set stream format 0x%x\n",
4058c2ecf20Sopenharmony_ci		       str->format_verb);
4068c2ecf20Sopenharmony_ci		return err;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* update stream - channel config */
4108c2ecf20Sopenharmony_ci	for (i = 0; i < channels; i++) {
4118c2ecf20Sopenharmony_ci		verb = (str->index << 6) | i;
4128c2ecf20Sopenharmony_ci		err = lola_codec_read(chip, str[i].nid,
4138c2ecf20Sopenharmony_ci				      LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb,
4148c2ecf20Sopenharmony_ci				      &val, NULL);
4158c2ecf20Sopenharmony_ci		if (err < 0) {
4168c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
4178c2ecf20Sopenharmony_ci				"Cannot set stream channel %d\n", i);
4188c2ecf20Sopenharmony_ci			return err;
4198c2ecf20Sopenharmony_ci		}
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci	return 0;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci/*
4258c2ecf20Sopenharmony_ci * set up the SD for streaming
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_cistatic int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm,
4288c2ecf20Sopenharmony_ci				 struct lola_stream *str)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	dma_addr_t bdl;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if (str->prepared)
4338c2ecf20Sopenharmony_ci		return -EINVAL;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	/* set up BDL */
4368c2ecf20Sopenharmony_ci	bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index;
4378c2ecf20Sopenharmony_ci	lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl);
4388c2ecf20Sopenharmony_ci	lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl));
4398c2ecf20Sopenharmony_ci	/* program the stream LVI (last valid index) of the BDL */
4408c2ecf20Sopenharmony_ci	lola_dsd_write(chip, str->dsd, LVI, str->frags - 1);
4418c2ecf20Sopenharmony_ci	lola_stream_clear_pending_irq(chip, str);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci 	lola_dsd_write(chip, str->dsd, CTL,
4448c2ecf20Sopenharmony_ci		       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	str->prepared = 1;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	return lola_stream_wait_for_fifo(chip, str, true);
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic int lola_pcm_prepare(struct snd_pcm_substream *substream)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct lola *chip = snd_pcm_substream_chip(substream);
4548c2ecf20Sopenharmony_ci	struct lola_pcm *pcm = lola_get_pcm(substream);
4558c2ecf20Sopenharmony_ci	struct lola_stream *str = lola_get_stream(substream);
4568c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
4578c2ecf20Sopenharmony_ci	unsigned int bufsize, period_bytes, format_verb;
4588c2ecf20Sopenharmony_ci	int i, err;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	mutex_lock(&chip->open_mutex);
4618c2ecf20Sopenharmony_ci	lola_stream_reset(chip, str);
4628c2ecf20Sopenharmony_ci	lola_cleanup_slave_streams(pcm, str);
4638c2ecf20Sopenharmony_ci	if (str->index + runtime->channels > pcm->num_streams) {
4648c2ecf20Sopenharmony_ci		mutex_unlock(&chip->open_mutex);
4658c2ecf20Sopenharmony_ci		return -EINVAL;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci	for (i = 1; i < runtime->channels; i++) {
4688c2ecf20Sopenharmony_ci		str[i].master = str;
4698c2ecf20Sopenharmony_ci		str[i].opened = 1;
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci	mutex_unlock(&chip->open_mutex);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	bufsize = snd_pcm_lib_buffer_bytes(substream);
4748c2ecf20Sopenharmony_ci	period_bytes = snd_pcm_lib_period_bytes(substream);
4758c2ecf20Sopenharmony_ci	format_verb = lola_get_format_verb(substream);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	str->bufsize = bufsize;
4788c2ecf20Sopenharmony_ci	str->period_bytes = period_bytes;
4798c2ecf20Sopenharmony_ci	str->format_verb = format_verb;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	err = lola_setup_periods(chip, pcm, substream, str);
4828c2ecf20Sopenharmony_ci	if (err < 0)
4838c2ecf20Sopenharmony_ci		return err;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	err = lola_set_sample_rate(chip, runtime->rate);
4868c2ecf20Sopenharmony_ci	if (err < 0)
4878c2ecf20Sopenharmony_ci		return err;
4888c2ecf20Sopenharmony_ci	chip->sample_rate = runtime->rate;	/* sample rate gets locked */
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	err = lola_set_stream_config(chip, str, runtime->channels);
4918c2ecf20Sopenharmony_ci	if (err < 0)
4928c2ecf20Sopenharmony_ci		return err;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	err = lola_setup_controller(chip, pcm, str);
4958c2ecf20Sopenharmony_ci	if (err < 0) {
4968c2ecf20Sopenharmony_ci		lola_stream_reset(chip, str);
4978c2ecf20Sopenharmony_ci		return err;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	return 0;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct lola *chip = snd_pcm_substream_chip(substream);
5068c2ecf20Sopenharmony_ci	struct lola_stream *str;
5078c2ecf20Sopenharmony_ci	struct snd_pcm_substream *s;
5088c2ecf20Sopenharmony_ci	unsigned int start;
5098c2ecf20Sopenharmony_ci	unsigned int tstamp;
5108c2ecf20Sopenharmony_ci	bool sync_streams;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	switch (cmd) {
5138c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
5148c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
5158c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
5168c2ecf20Sopenharmony_ci		start = 1;
5178c2ecf20Sopenharmony_ci		break;
5188c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
5198c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
5208c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
5218c2ecf20Sopenharmony_ci		start = 0;
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci	default:
5248c2ecf20Sopenharmony_ci		return -EINVAL;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	/*
5288c2ecf20Sopenharmony_ci	 * sample correct synchronization is only needed starting several
5298c2ecf20Sopenharmony_ci	 * streams. On stop or if only one stream do as quick as possible
5308c2ecf20Sopenharmony_ci	 */
5318c2ecf20Sopenharmony_ci	sync_streams = (start && snd_pcm_stream_linked(substream));
5328c2ecf20Sopenharmony_ci	tstamp = lola_get_tstamp(chip, !sync_streams);
5338c2ecf20Sopenharmony_ci	spin_lock(&chip->reg_lock);
5348c2ecf20Sopenharmony_ci	snd_pcm_group_for_each_entry(s, substream) {
5358c2ecf20Sopenharmony_ci		if (s->pcm->card != substream->pcm->card)
5368c2ecf20Sopenharmony_ci			continue;
5378c2ecf20Sopenharmony_ci		str = lola_get_stream(s);
5388c2ecf20Sopenharmony_ci		if (start)
5398c2ecf20Sopenharmony_ci			lola_stream_start(chip, str, tstamp);
5408c2ecf20Sopenharmony_ci		else
5418c2ecf20Sopenharmony_ci			lola_stream_stop(chip, str, tstamp);
5428c2ecf20Sopenharmony_ci		str->running = start;
5438c2ecf20Sopenharmony_ci		str->paused = !start;
5448c2ecf20Sopenharmony_ci		snd_pcm_trigger_done(s, substream);
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci	spin_unlock(&chip->reg_lock);
5478c2ecf20Sopenharmony_ci	return 0;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct lola *chip = snd_pcm_substream_chip(substream);
5538c2ecf20Sopenharmony_ci	struct lola_stream *str = lola_get_stream(substream);
5548c2ecf20Sopenharmony_ci	unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	if (pos >= str->bufsize)
5578c2ecf20Sopenharmony_ci		pos = 0;
5588c2ecf20Sopenharmony_ci	return bytes_to_frames(substream->runtime, pos);
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_civoid lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	int i;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	for (i = 0; bits && i < pcm->num_streams; i++) {
5668c2ecf20Sopenharmony_ci		if (bits & (1 << i)) {
5678c2ecf20Sopenharmony_ci			struct lola_stream *str = &pcm->streams[i];
5688c2ecf20Sopenharmony_ci			if (str->substream && str->running)
5698c2ecf20Sopenharmony_ci				snd_pcm_period_elapsed(str->substream);
5708c2ecf20Sopenharmony_ci			bits &= ~(1 << i);
5718c2ecf20Sopenharmony_ci		}
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops lola_pcm_ops = {
5768c2ecf20Sopenharmony_ci	.open = lola_pcm_open,
5778c2ecf20Sopenharmony_ci	.close = lola_pcm_close,
5788c2ecf20Sopenharmony_ci	.hw_params = lola_pcm_hw_params,
5798c2ecf20Sopenharmony_ci	.hw_free = lola_pcm_hw_free,
5808c2ecf20Sopenharmony_ci	.prepare = lola_pcm_prepare,
5818c2ecf20Sopenharmony_ci	.trigger = lola_pcm_trigger,
5828c2ecf20Sopenharmony_ci	.pointer = lola_pcm_pointer,
5838c2ecf20Sopenharmony_ci};
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ciint lola_create_pcm(struct lola *chip)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
5888c2ecf20Sopenharmony_ci	int i, err;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
5918c2ecf20Sopenharmony_ci		err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
5928c2ecf20Sopenharmony_ci					  &chip->pci->dev,
5938c2ecf20Sopenharmony_ci					  PAGE_SIZE, &chip->pcm[i].bdl);
5948c2ecf20Sopenharmony_ci		if (err < 0)
5958c2ecf20Sopenharmony_ci			return err;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	err = snd_pcm_new(chip->card, "Digigram Lola", 0,
5998c2ecf20Sopenharmony_ci			  chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams,
6008c2ecf20Sopenharmony_ci			  chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams,
6018c2ecf20Sopenharmony_ci			  &pcm);
6028c2ecf20Sopenharmony_ci	if (err < 0)
6038c2ecf20Sopenharmony_ci		return err;
6048c2ecf20Sopenharmony_ci	strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name));
6058c2ecf20Sopenharmony_ci	pcm->private_data = chip;
6068c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
6078c2ecf20Sopenharmony_ci		if (chip->pcm[i].num_streams)
6088c2ecf20Sopenharmony_ci			snd_pcm_set_ops(pcm, i, &lola_pcm_ops);
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci	/* buffer pre-allocation */
6118c2ecf20Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
6128c2ecf20Sopenharmony_ci				       &chip->pci->dev,
6138c2ecf20Sopenharmony_ci				       1024 * 64, 32 * 1024 * 1024);
6148c2ecf20Sopenharmony_ci	return 0;
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_civoid lola_free_pcm(struct lola *chip)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	snd_dma_free_pages(&chip->pcm[0].bdl);
6208c2ecf20Sopenharmony_ci	snd_dma_free_pages(&chip->pcm[1].bdl);
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci/*
6248c2ecf20Sopenharmony_ci */
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic int lola_init_stream(struct lola *chip, struct lola_stream *str,
6278c2ecf20Sopenharmony_ci			    int idx, int nid, int dir)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	unsigned int val;
6308c2ecf20Sopenharmony_ci	int err;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	str->nid = nid;
6338c2ecf20Sopenharmony_ci	str->index = idx;
6348c2ecf20Sopenharmony_ci	str->dsd = idx;
6358c2ecf20Sopenharmony_ci	if (dir == PLAY)
6368c2ecf20Sopenharmony_ci		str->dsd += MAX_STREAM_IN_COUNT;
6378c2ecf20Sopenharmony_ci	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
6388c2ecf20Sopenharmony_ci	if (err < 0) {
6398c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
6408c2ecf20Sopenharmony_ci		return err;
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci	if (dir == PLAY) {
6438c2ecf20Sopenharmony_ci		/* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */
6448c2ecf20Sopenharmony_ci		if ((val & 0x00f00dff) != 0x00000010) {
6458c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
6468c2ecf20Sopenharmony_ci				"Invalid wcaps 0x%x for 0x%x\n",
6478c2ecf20Sopenharmony_ci			       val, nid);
6488c2ecf20Sopenharmony_ci			return -EINVAL;
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci	} else {
6518c2ecf20Sopenharmony_ci		/* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1)
6528c2ecf20Sopenharmony_ci		 * (bug : ignore bit8: Conn list = 0/1)
6538c2ecf20Sopenharmony_ci		 */
6548c2ecf20Sopenharmony_ci		if ((val & 0x00f00cff) != 0x00100010) {
6558c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
6568c2ecf20Sopenharmony_ci				"Invalid wcaps 0x%x for 0x%x\n",
6578c2ecf20Sopenharmony_ci			       val, nid);
6588c2ecf20Sopenharmony_ci			return -EINVAL;
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci		/* test bit9:DIGITAL and bit12:SRC_PRESENT*/
6618c2ecf20Sopenharmony_ci		if ((val & 0x00001200) == 0x00001200)
6628c2ecf20Sopenharmony_ci			chip->input_src_caps_mask |= (1 << idx);
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
6668c2ecf20Sopenharmony_ci	if (err < 0) {
6678c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "Can't read FORMATS 0x%x\n", nid);
6688c2ecf20Sopenharmony_ci		return err;
6698c2ecf20Sopenharmony_ci	}
6708c2ecf20Sopenharmony_ci	val &= 3;
6718c2ecf20Sopenharmony_ci	if (val == 3)
6728c2ecf20Sopenharmony_ci		str->can_float = true;
6738c2ecf20Sopenharmony_ci	if (!(val & 1)) {
6748c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
6758c2ecf20Sopenharmony_ci			"Invalid formats 0x%x for 0x%x", val, nid);
6768c2ecf20Sopenharmony_ci		return -EINVAL;
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci	return 0;
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ciint lola_init_pcm(struct lola *chip, int dir, int *nidp)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	struct lola_pcm *pcm = &chip->pcm[dir];
6848c2ecf20Sopenharmony_ci	int i, nid, err;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	nid = *nidp;
6878c2ecf20Sopenharmony_ci	for (i = 0; i < pcm->num_streams; i++, nid++) {
6888c2ecf20Sopenharmony_ci		err = lola_init_stream(chip, &pcm->streams[i], i, nid, dir);
6898c2ecf20Sopenharmony_ci		if (err < 0)
6908c2ecf20Sopenharmony_ci			return err;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci	*nidp = nid;
6938c2ecf20Sopenharmony_ci	return 0;
6948c2ecf20Sopenharmony_ci}
695