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