162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Support for Digigram Lola PCI-e boards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/pci.h> 1662306a36Sopenharmony_ci#include <sound/core.h> 1762306a36Sopenharmony_ci#include <sound/control.h> 1862306a36Sopenharmony_ci#include <sound/pcm.h> 1962306a36Sopenharmony_ci#include <sound/initval.h> 2062306a36Sopenharmony_ci#include "lola.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Standard options */ 2362306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 2462306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 2562306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 2862306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for Digigram Lola driver."); 2962306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 3062306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for Digigram Lola driver."); 3162306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 3262306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable Digigram Lola driver."); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Lola-specific options */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* for instance use always max granularity which is compatible 3762306a36Sopenharmony_ci * with all sample rates 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_cistatic int granularity[SNDRV_CARDS] = { 4062306a36Sopenharmony_ci [0 ... (SNDRV_CARDS - 1)] = LOLA_GRANULARITY_MAX 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* below a sample_rate of 16kHz the analogue audio quality is NOT excellent */ 4462306a36Sopenharmony_cistatic int sample_rate_min[SNDRV_CARDS] = { 4562306a36Sopenharmony_ci [0 ... (SNDRV_CARDS - 1) ] = 16000 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cimodule_param_array(granularity, int, NULL, 0444); 4962306a36Sopenharmony_ciMODULE_PARM_DESC(granularity, "Granularity value"); 5062306a36Sopenharmony_cimodule_param_array(sample_rate_min, int, NULL, 0444); 5162306a36Sopenharmony_ciMODULE_PARM_DESC(sample_rate_min, "Minimal sample rate"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5762306a36Sopenharmony_ciMODULE_DESCRIPTION("Digigram Lola driver"); 5862306a36Sopenharmony_ciMODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#ifdef CONFIG_SND_DEBUG_VERBOSE 6162306a36Sopenharmony_cistatic int debug; 6262306a36Sopenharmony_cimodule_param(debug, int, 0644); 6362306a36Sopenharmony_ci#define verbose_debug(fmt, args...) \ 6462306a36Sopenharmony_ci do { if (debug > 1) pr_debug(SFX fmt, ##args); } while (0) 6562306a36Sopenharmony_ci#else 6662306a36Sopenharmony_ci#define verbose_debug(fmt, args...) 6762306a36Sopenharmony_ci#endif 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * pseudo-codec read/write via CORB/RIRB 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int corb_send_verb(struct lola *chip, unsigned int nid, 7462306a36Sopenharmony_ci unsigned int verb, unsigned int data, 7562306a36Sopenharmony_ci unsigned int extdata) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci unsigned long flags; 7862306a36Sopenharmony_ci int ret = -EIO; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci chip->last_cmd_nid = nid; 8162306a36Sopenharmony_ci chip->last_verb = verb; 8262306a36Sopenharmony_ci chip->last_data = data; 8362306a36Sopenharmony_ci chip->last_extdata = extdata; 8462306a36Sopenharmony_ci data |= (nid << 20) | (verb << 8); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 8762306a36Sopenharmony_ci if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) { 8862306a36Sopenharmony_ci unsigned int wp = chip->corb.wp + 1; 8962306a36Sopenharmony_ci wp %= LOLA_CORB_ENTRIES; 9062306a36Sopenharmony_ci chip->corb.wp = wp; 9162306a36Sopenharmony_ci chip->corb.buf[wp * 2] = cpu_to_le32(data); 9262306a36Sopenharmony_ci chip->corb.buf[wp * 2 + 1] = cpu_to_le32(extdata); 9362306a36Sopenharmony_ci lola_writew(chip, BAR0, CORBWP, wp); 9462306a36Sopenharmony_ci chip->rirb.cmds++; 9562306a36Sopenharmony_ci smp_wmb(); 9662306a36Sopenharmony_ci ret = 0; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 9962306a36Sopenharmony_ci return ret; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void lola_queue_unsol_event(struct lola *chip, unsigned int res, 10362306a36Sopenharmony_ci unsigned int res_ex) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci lola_update_ext_clock_freq(chip, res); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* retrieve RIRB entry - called from interrupt handler */ 10962306a36Sopenharmony_cistatic void lola_update_rirb(struct lola *chip) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci unsigned int rp, wp; 11262306a36Sopenharmony_ci u32 res, res_ex; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci wp = lola_readw(chip, BAR0, RIRBWP); 11562306a36Sopenharmony_ci if (wp == chip->rirb.wp) 11662306a36Sopenharmony_ci return; 11762306a36Sopenharmony_ci chip->rirb.wp = wp; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci while (chip->rirb.rp != wp) { 12062306a36Sopenharmony_ci chip->rirb.rp++; 12162306a36Sopenharmony_ci chip->rirb.rp %= LOLA_CORB_ENTRIES; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ 12462306a36Sopenharmony_ci res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); 12562306a36Sopenharmony_ci res = le32_to_cpu(chip->rirb.buf[rp]); 12662306a36Sopenharmony_ci if (res_ex & LOLA_RIRB_EX_UNSOL_EV) 12762306a36Sopenharmony_ci lola_queue_unsol_event(chip, res, res_ex); 12862306a36Sopenharmony_ci else if (chip->rirb.cmds) { 12962306a36Sopenharmony_ci chip->res = res; 13062306a36Sopenharmony_ci chip->res_ex = res_ex; 13162306a36Sopenharmony_ci smp_wmb(); 13262306a36Sopenharmony_ci chip->rirb.cmds--; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int rirb_get_response(struct lola *chip, unsigned int *val, 13862306a36Sopenharmony_ci unsigned int *extval) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci unsigned long timeout; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci again: 14362306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(1000); 14462306a36Sopenharmony_ci for (;;) { 14562306a36Sopenharmony_ci if (chip->polling_mode) { 14662306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 14762306a36Sopenharmony_ci lola_update_rirb(chip); 14862306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci if (!chip->rirb.cmds) { 15162306a36Sopenharmony_ci *val = chip->res; 15262306a36Sopenharmony_ci if (extval) 15362306a36Sopenharmony_ci *extval = chip->res_ex; 15462306a36Sopenharmony_ci verbose_debug("get_response: %x, %x\n", 15562306a36Sopenharmony_ci chip->res, chip->res_ex); 15662306a36Sopenharmony_ci if (chip->res_ex & LOLA_RIRB_EX_ERROR) { 15762306a36Sopenharmony_ci dev_warn(chip->card->dev, "RIRB ERROR: " 15862306a36Sopenharmony_ci "NID=%x, verb=%x, data=%x, ext=%x\n", 15962306a36Sopenharmony_ci chip->last_cmd_nid, 16062306a36Sopenharmony_ci chip->last_verb, chip->last_data, 16162306a36Sopenharmony_ci chip->last_extdata); 16262306a36Sopenharmony_ci return -EIO; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci udelay(20); 16962306a36Sopenharmony_ci cond_resched(); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci dev_warn(chip->card->dev, "RIRB response error\n"); 17262306a36Sopenharmony_ci if (!chip->polling_mode) { 17362306a36Sopenharmony_ci dev_warn(chip->card->dev, "switching to polling mode\n"); 17462306a36Sopenharmony_ci chip->polling_mode = 1; 17562306a36Sopenharmony_ci goto again; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci return -EIO; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* aynchronous write of a codec verb with data */ 18162306a36Sopenharmony_ciint lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb, 18262306a36Sopenharmony_ci unsigned int data, unsigned int extdata) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci verbose_debug("codec_write NID=%x, verb=%x, data=%x, ext=%x\n", 18562306a36Sopenharmony_ci nid, verb, data, extdata); 18662306a36Sopenharmony_ci return corb_send_verb(chip, nid, verb, data, extdata); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* write a codec verb with data and read the returned status */ 19062306a36Sopenharmony_ciint lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb, 19162306a36Sopenharmony_ci unsigned int data, unsigned int extdata, 19262306a36Sopenharmony_ci unsigned int *val, unsigned int *extval) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int err; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci verbose_debug("codec_read NID=%x, verb=%x, data=%x, ext=%x\n", 19762306a36Sopenharmony_ci nid, verb, data, extdata); 19862306a36Sopenharmony_ci err = corb_send_verb(chip, nid, verb, data, extdata); 19962306a36Sopenharmony_ci if (err < 0) 20062306a36Sopenharmony_ci return err; 20162306a36Sopenharmony_ci err = rirb_get_response(chip, val, extval); 20262306a36Sopenharmony_ci return err; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* flush all pending codec writes */ 20662306a36Sopenharmony_ciint lola_codec_flush(struct lola *chip) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned int tmp; 20962306a36Sopenharmony_ci return rirb_get_response(chip, &tmp, NULL); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * interrupt handler 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_cistatic irqreturn_t lola_interrupt(int irq, void *dev_id) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct lola *chip = dev_id; 21862306a36Sopenharmony_ci unsigned int notify_ins, notify_outs, error_ins, error_outs; 21962306a36Sopenharmony_ci int handled = 0; 22062306a36Sopenharmony_ci int i; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci notify_ins = notify_outs = error_ins = error_outs = 0; 22362306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 22462306a36Sopenharmony_ci for (;;) { 22562306a36Sopenharmony_ci unsigned int status, in_sts, out_sts; 22662306a36Sopenharmony_ci unsigned int reg; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci status = lola_readl(chip, BAR1, DINTSTS); 22962306a36Sopenharmony_ci if (!status || status == -1) 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci in_sts = lola_readl(chip, BAR1, DIINTSTS); 23362306a36Sopenharmony_ci out_sts = lola_readl(chip, BAR1, DOINTSTS); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* clear Input Interrupts */ 23662306a36Sopenharmony_ci for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) { 23762306a36Sopenharmony_ci if (!(in_sts & (1 << i))) 23862306a36Sopenharmony_ci continue; 23962306a36Sopenharmony_ci in_sts &= ~(1 << i); 24062306a36Sopenharmony_ci reg = lola_dsd_read(chip, i, STS); 24162306a36Sopenharmony_ci if (reg & LOLA_DSD_STS_DESE) /* error */ 24262306a36Sopenharmony_ci error_ins |= (1 << i); 24362306a36Sopenharmony_ci if (reg & LOLA_DSD_STS_BCIS) /* notify */ 24462306a36Sopenharmony_ci notify_ins |= (1 << i); 24562306a36Sopenharmony_ci /* clear */ 24662306a36Sopenharmony_ci lola_dsd_write(chip, i, STS, reg); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* clear Output Interrupts */ 25062306a36Sopenharmony_ci for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) { 25162306a36Sopenharmony_ci if (!(out_sts & (1 << i))) 25262306a36Sopenharmony_ci continue; 25362306a36Sopenharmony_ci out_sts &= ~(1 << i); 25462306a36Sopenharmony_ci reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS); 25562306a36Sopenharmony_ci if (reg & LOLA_DSD_STS_DESE) /* error */ 25662306a36Sopenharmony_ci error_outs |= (1 << i); 25762306a36Sopenharmony_ci if (reg & LOLA_DSD_STS_BCIS) /* notify */ 25862306a36Sopenharmony_ci notify_outs |= (1 << i); 25962306a36Sopenharmony_ci lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (status & LOLA_DINT_CTRL) { 26362306a36Sopenharmony_ci unsigned char rbsts; /* ring status is byte access */ 26462306a36Sopenharmony_ci rbsts = lola_readb(chip, BAR0, RIRBSTS); 26562306a36Sopenharmony_ci rbsts &= LOLA_RIRB_INT_MASK; 26662306a36Sopenharmony_ci if (rbsts) 26762306a36Sopenharmony_ci lola_writeb(chip, BAR0, RIRBSTS, rbsts); 26862306a36Sopenharmony_ci rbsts = lola_readb(chip, BAR0, CORBSTS); 26962306a36Sopenharmony_ci rbsts &= LOLA_CORB_INT_MASK; 27062306a36Sopenharmony_ci if (rbsts) 27162306a36Sopenharmony_ci lola_writeb(chip, BAR0, CORBSTS, rbsts); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci lola_update_rirb(chip); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) { 27762306a36Sopenharmony_ci /* clear global fifo error interrupt */ 27862306a36Sopenharmony_ci lola_writel(chip, BAR1, DINTSTS, 27962306a36Sopenharmony_ci (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR))); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci handled = 1; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins); 28662306a36Sopenharmony_ci lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return IRQ_RETVAL(handled); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* 29362306a36Sopenharmony_ci * controller 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_cistatic int reset_controller(struct lola *chip) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci unsigned int gctl = lola_readl(chip, BAR0, GCTL); 29862306a36Sopenharmony_ci unsigned long end_time; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (gctl) { 30162306a36Sopenharmony_ci /* to be sure */ 30262306a36Sopenharmony_ci lola_writel(chip, BAR1, BOARD_MODE, 0); 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci chip->cold_reset = 1; 30762306a36Sopenharmony_ci lola_writel(chip, BAR0, GCTL, LOLA_GCTL_RESET); 30862306a36Sopenharmony_ci end_time = jiffies + msecs_to_jiffies(200); 30962306a36Sopenharmony_ci do { 31062306a36Sopenharmony_ci msleep(1); 31162306a36Sopenharmony_ci gctl = lola_readl(chip, BAR0, GCTL); 31262306a36Sopenharmony_ci if (gctl) 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci } while (time_before(jiffies, end_time)); 31562306a36Sopenharmony_ci if (!gctl) { 31662306a36Sopenharmony_ci dev_err(chip->card->dev, "cannot reset controller\n"); 31762306a36Sopenharmony_ci return -EIO; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void lola_irq_enable(struct lola *chip) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci unsigned int val; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* enalbe all I/O streams */ 32762306a36Sopenharmony_ci val = (1 << chip->pcm[PLAY].num_streams) - 1; 32862306a36Sopenharmony_ci lola_writel(chip, BAR1, DOINTCTL, val); 32962306a36Sopenharmony_ci val = (1 << chip->pcm[CAPT].num_streams) - 1; 33062306a36Sopenharmony_ci lola_writel(chip, BAR1, DIINTCTL, val); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* enable global irqs */ 33362306a36Sopenharmony_ci val = LOLA_DINT_GLOBAL | LOLA_DINT_CTRL | LOLA_DINT_FIFOERR | 33462306a36Sopenharmony_ci LOLA_DINT_MUERR; 33562306a36Sopenharmony_ci lola_writel(chip, BAR1, DINTCTL, val); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic void lola_irq_disable(struct lola *chip) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci lola_writel(chip, BAR1, DINTCTL, 0); 34162306a36Sopenharmony_ci lola_writel(chip, BAR1, DIINTCTL, 0); 34262306a36Sopenharmony_ci lola_writel(chip, BAR1, DOINTCTL, 0); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic int setup_corb_rirb(struct lola *chip) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci unsigned char tmp; 34862306a36Sopenharmony_ci unsigned long end_time; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci chip->rb = snd_devm_alloc_pages(&chip->pci->dev, SNDRV_DMA_TYPE_DEV, 35162306a36Sopenharmony_ci PAGE_SIZE); 35262306a36Sopenharmony_ci if (!chip->rb) 35362306a36Sopenharmony_ci return -ENOMEM; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci chip->corb.addr = chip->rb->addr; 35662306a36Sopenharmony_ci chip->corb.buf = (__le32 *)chip->rb->area; 35762306a36Sopenharmony_ci chip->rirb.addr = chip->rb->addr + 2048; 35862306a36Sopenharmony_ci chip->rirb.buf = (__le32 *)(chip->rb->area + 2048); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* disable ringbuffer DMAs */ 36162306a36Sopenharmony_ci lola_writeb(chip, BAR0, RIRBCTL, 0); 36262306a36Sopenharmony_ci lola_writeb(chip, BAR0, CORBCTL, 0); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci end_time = jiffies + msecs_to_jiffies(200); 36562306a36Sopenharmony_ci do { 36662306a36Sopenharmony_ci if (!lola_readb(chip, BAR0, RIRBCTL) && 36762306a36Sopenharmony_ci !lola_readb(chip, BAR0, CORBCTL)) 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci msleep(1); 37062306a36Sopenharmony_ci } while (time_before(jiffies, end_time)); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* CORB set up */ 37362306a36Sopenharmony_ci lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr); 37462306a36Sopenharmony_ci lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr)); 37562306a36Sopenharmony_ci /* set the corb size to 256 entries */ 37662306a36Sopenharmony_ci lola_writeb(chip, BAR0, CORBSIZE, 0x02); 37762306a36Sopenharmony_ci /* set the corb write pointer to 0 */ 37862306a36Sopenharmony_ci lola_writew(chip, BAR0, CORBWP, 0); 37962306a36Sopenharmony_ci /* reset the corb hw read pointer */ 38062306a36Sopenharmony_ci lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR); 38162306a36Sopenharmony_ci /* enable corb dma */ 38262306a36Sopenharmony_ci lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN); 38362306a36Sopenharmony_ci /* clear flags if set */ 38462306a36Sopenharmony_ci tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK; 38562306a36Sopenharmony_ci if (tmp) 38662306a36Sopenharmony_ci lola_writeb(chip, BAR0, CORBSTS, tmp); 38762306a36Sopenharmony_ci chip->corb.wp = 0; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* RIRB set up */ 39062306a36Sopenharmony_ci lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr); 39162306a36Sopenharmony_ci lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr)); 39262306a36Sopenharmony_ci /* set the rirb size to 256 entries */ 39362306a36Sopenharmony_ci lola_writeb(chip, BAR0, RIRBSIZE, 0x02); 39462306a36Sopenharmony_ci /* reset the rirb hw write pointer */ 39562306a36Sopenharmony_ci lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR); 39662306a36Sopenharmony_ci /* set N=1, get RIRB response interrupt for new entry */ 39762306a36Sopenharmony_ci lola_writew(chip, BAR0, RINTCNT, 1); 39862306a36Sopenharmony_ci /* enable rirb dma and response irq */ 39962306a36Sopenharmony_ci lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN); 40062306a36Sopenharmony_ci /* clear flags if set */ 40162306a36Sopenharmony_ci tmp = lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK; 40262306a36Sopenharmony_ci if (tmp) 40362306a36Sopenharmony_ci lola_writeb(chip, BAR0, RIRBSTS, tmp); 40462306a36Sopenharmony_ci chip->rirb.rp = chip->rirb.cmds = 0; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void stop_corb_rirb(struct lola *chip) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci /* disable ringbuffer DMAs */ 41262306a36Sopenharmony_ci lola_writeb(chip, BAR0, RIRBCTL, 0); 41362306a36Sopenharmony_ci lola_writeb(chip, BAR0, CORBCTL, 0); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic void lola_reset_setups(struct lola *chip) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci /* update the granularity */ 41962306a36Sopenharmony_ci lola_set_granularity(chip, chip->granularity, true); 42062306a36Sopenharmony_ci /* update the sample clock */ 42162306a36Sopenharmony_ci lola_set_clock_index(chip, chip->clock.cur_index); 42262306a36Sopenharmony_ci /* enable unsolicited events of the clock widget */ 42362306a36Sopenharmony_ci lola_enable_clock_events(chip); 42462306a36Sopenharmony_ci /* update the analog gains */ 42562306a36Sopenharmony_ci lola_setup_all_analog_gains(chip, CAPT, false); /* input, update */ 42662306a36Sopenharmony_ci /* update SRC configuration if applicable */ 42762306a36Sopenharmony_ci lola_set_src_config(chip, chip->input_src_mask, false); 42862306a36Sopenharmony_ci /* update the analog outputs */ 42962306a36Sopenharmony_ci lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */ 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int lola_parse_tree(struct lola *chip) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci unsigned int val; 43562306a36Sopenharmony_ci int nid, err; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); 43862306a36Sopenharmony_ci if (err < 0) { 43962306a36Sopenharmony_ci dev_err(chip->card->dev, "Can't read VENDOR_ID\n"); 44062306a36Sopenharmony_ci return err; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci val >>= 16; 44362306a36Sopenharmony_ci if (val != 0x1369) { 44462306a36Sopenharmony_ci dev_err(chip->card->dev, "Unknown codec vendor 0x%x\n", val); 44562306a36Sopenharmony_ci return -EINVAL; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); 44962306a36Sopenharmony_ci if (err < 0) { 45062306a36Sopenharmony_ci dev_err(chip->card->dev, "Can't read FUNCTION_TYPE\n"); 45162306a36Sopenharmony_ci return err; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci if (val != 1) { 45462306a36Sopenharmony_ci dev_err(chip->card->dev, "Unknown function type %d\n", val); 45562306a36Sopenharmony_ci return -EINVAL; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); 45962306a36Sopenharmony_ci if (err < 0) { 46062306a36Sopenharmony_ci dev_err(chip->card->dev, "Can't read SPECCAPS\n"); 46162306a36Sopenharmony_ci return err; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci chip->lola_caps = val; 46462306a36Sopenharmony_ci chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps); 46562306a36Sopenharmony_ci chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps); 46662306a36Sopenharmony_ci dev_dbg(chip->card->dev, "speccaps=0x%x, pins in=%d, out=%d\n", 46762306a36Sopenharmony_ci chip->lola_caps, 46862306a36Sopenharmony_ci chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT || 47162306a36Sopenharmony_ci chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) { 47262306a36Sopenharmony_ci dev_err(chip->card->dev, "Invalid Lola-spec caps 0x%x\n", val); 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci nid = 0x02; 47762306a36Sopenharmony_ci err = lola_init_pcm(chip, CAPT, &nid); 47862306a36Sopenharmony_ci if (err < 0) 47962306a36Sopenharmony_ci return err; 48062306a36Sopenharmony_ci err = lola_init_pcm(chip, PLAY, &nid); 48162306a36Sopenharmony_ci if (err < 0) 48262306a36Sopenharmony_ci return err; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci err = lola_init_pins(chip, CAPT, &nid); 48562306a36Sopenharmony_ci if (err < 0) 48662306a36Sopenharmony_ci return err; 48762306a36Sopenharmony_ci err = lola_init_pins(chip, PLAY, &nid); 48862306a36Sopenharmony_ci if (err < 0) 48962306a36Sopenharmony_ci return err; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) { 49262306a36Sopenharmony_ci err = lola_init_clock_widget(chip, nid); 49362306a36Sopenharmony_ci if (err < 0) 49462306a36Sopenharmony_ci return err; 49562306a36Sopenharmony_ci nid++; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) { 49862306a36Sopenharmony_ci err = lola_init_mixer_widget(chip, nid); 49962306a36Sopenharmony_ci if (err < 0) 50062306a36Sopenharmony_ci return err; 50162306a36Sopenharmony_ci nid++; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* enable unsolicited events of the clock widget */ 50562306a36Sopenharmony_ci err = lola_enable_clock_events(chip); 50662306a36Sopenharmony_ci if (err < 0) 50762306a36Sopenharmony_ci return err; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* if last ResetController was not a ColdReset, we don't know 51062306a36Sopenharmony_ci * the state of the card; initialize here again 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci if (!chip->cold_reset) { 51362306a36Sopenharmony_ci lola_reset_setups(chip); 51462306a36Sopenharmony_ci chip->cold_reset = 1; 51562306a36Sopenharmony_ci } else { 51662306a36Sopenharmony_ci /* set the granularity if it is not the default */ 51762306a36Sopenharmony_ci if (chip->granularity != LOLA_GRANULARITY_MIN) 51862306a36Sopenharmony_ci lola_set_granularity(chip, chip->granularity, true); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic void lola_stop_hw(struct lola *chip) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci stop_corb_rirb(chip); 52762306a36Sopenharmony_ci lola_irq_disable(chip); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void lola_free(struct snd_card *card) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct lola *chip = card->private_data; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (chip->initialized) 53562306a36Sopenharmony_ci lola_stop_hw(chip); 53662306a36Sopenharmony_ci lola_free_mixer(chip); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int lola_create(struct snd_card *card, struct pci_dev *pci, int dev) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct lola *chip = card->private_data; 54262306a36Sopenharmony_ci int err; 54362306a36Sopenharmony_ci unsigned int dever; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci err = pcim_enable_device(pci); 54662306a36Sopenharmony_ci if (err < 0) 54762306a36Sopenharmony_ci return err; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci spin_lock_init(&chip->reg_lock); 55062306a36Sopenharmony_ci mutex_init(&chip->open_mutex); 55162306a36Sopenharmony_ci chip->card = card; 55262306a36Sopenharmony_ci chip->pci = pci; 55362306a36Sopenharmony_ci chip->irq = -1; 55462306a36Sopenharmony_ci card->private_free = lola_free; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci chip->granularity = granularity[dev]; 55762306a36Sopenharmony_ci switch (chip->granularity) { 55862306a36Sopenharmony_ci case 8: 55962306a36Sopenharmony_ci chip->sample_rate_max = 48000; 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci case 16: 56262306a36Sopenharmony_ci chip->sample_rate_max = 96000; 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci case 32: 56562306a36Sopenharmony_ci chip->sample_rate_max = 192000; 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci default: 56862306a36Sopenharmony_ci dev_warn(chip->card->dev, 56962306a36Sopenharmony_ci "Invalid granularity %d, reset to %d\n", 57062306a36Sopenharmony_ci chip->granularity, LOLA_GRANULARITY_MAX); 57162306a36Sopenharmony_ci chip->granularity = LOLA_GRANULARITY_MAX; 57262306a36Sopenharmony_ci chip->sample_rate_max = 192000; 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci chip->sample_rate_min = sample_rate_min[dev]; 57662306a36Sopenharmony_ci if (chip->sample_rate_min > chip->sample_rate_max) { 57762306a36Sopenharmony_ci dev_warn(chip->card->dev, 57862306a36Sopenharmony_ci "Invalid sample_rate_min %d, reset to 16000\n", 57962306a36Sopenharmony_ci chip->sample_rate_min); 58062306a36Sopenharmony_ci chip->sample_rate_min = 16000; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci err = pcim_iomap_regions(pci, (1 << 0) | (1 << 2), DRVNAME); 58462306a36Sopenharmony_ci if (err < 0) 58562306a36Sopenharmony_ci return err; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci chip->bar[0].addr = pci_resource_start(pci, 0); 58862306a36Sopenharmony_ci chip->bar[0].remap_addr = pcim_iomap_table(pci)[0]; 58962306a36Sopenharmony_ci chip->bar[1].addr = pci_resource_start(pci, 2); 59062306a36Sopenharmony_ci chip->bar[1].remap_addr = pcim_iomap_table(pci)[2]; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci pci_set_master(pci); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci err = reset_controller(chip); 59562306a36Sopenharmony_ci if (err < 0) 59662306a36Sopenharmony_ci return err; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (devm_request_irq(&pci->dev, pci->irq, lola_interrupt, IRQF_SHARED, 59962306a36Sopenharmony_ci KBUILD_MODNAME, chip)) { 60062306a36Sopenharmony_ci dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq); 60162306a36Sopenharmony_ci return -EBUSY; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci chip->irq = pci->irq; 60462306a36Sopenharmony_ci card->sync_irq = chip->irq; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci dever = lola_readl(chip, BAR1, DEVER); 60762306a36Sopenharmony_ci chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff; 60862306a36Sopenharmony_ci chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff; 60962306a36Sopenharmony_ci chip->version = (dever >> 24) & 0xff; 61062306a36Sopenharmony_ci dev_dbg(chip->card->dev, "streams in=%d, out=%d, version=0x%x\n", 61162306a36Sopenharmony_ci chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams, 61262306a36Sopenharmony_ci chip->version); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* Test LOLA_BAR1_DEVER */ 61562306a36Sopenharmony_ci if (chip->pcm[CAPT].num_streams > MAX_STREAM_IN_COUNT || 61662306a36Sopenharmony_ci chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT || 61762306a36Sopenharmony_ci (!chip->pcm[CAPT].num_streams && 61862306a36Sopenharmony_ci !chip->pcm[PLAY].num_streams)) { 61962306a36Sopenharmony_ci dev_err(chip->card->dev, "invalid DEVER = %x\n", dever); 62062306a36Sopenharmony_ci return -EINVAL; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci err = setup_corb_rirb(chip); 62462306a36Sopenharmony_ci if (err < 0) 62562306a36Sopenharmony_ci return err; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci strcpy(card->driver, "Lola"); 62862306a36Sopenharmony_ci strscpy(card->shortname, "Digigram Lola", sizeof(card->shortname)); 62962306a36Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), 63062306a36Sopenharmony_ci "%s at 0x%lx irq %i", 63162306a36Sopenharmony_ci card->shortname, chip->bar[0].addr, chip->irq); 63262306a36Sopenharmony_ci strcpy(card->mixername, card->shortname); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci lola_irq_enable(chip); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci chip->initialized = 1; 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int __lola_probe(struct pci_dev *pci, 64162306a36Sopenharmony_ci const struct pci_device_id *pci_id) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci static int dev; 64462306a36Sopenharmony_ci struct snd_card *card; 64562306a36Sopenharmony_ci struct lola *chip; 64662306a36Sopenharmony_ci int err; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (dev >= SNDRV_CARDS) 64962306a36Sopenharmony_ci return -ENODEV; 65062306a36Sopenharmony_ci if (!enable[dev]) { 65162306a36Sopenharmony_ci dev++; 65262306a36Sopenharmony_ci return -ENOENT; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 65662306a36Sopenharmony_ci sizeof(*chip), &card); 65762306a36Sopenharmony_ci if (err < 0) { 65862306a36Sopenharmony_ci dev_err(&pci->dev, "Error creating card!\n"); 65962306a36Sopenharmony_ci return err; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci chip = card->private_data; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci err = lola_create(card, pci, dev); 66462306a36Sopenharmony_ci if (err < 0) 66562306a36Sopenharmony_ci return err; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci err = lola_parse_tree(chip); 66862306a36Sopenharmony_ci if (err < 0) 66962306a36Sopenharmony_ci return err; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci err = lola_create_pcm(chip); 67262306a36Sopenharmony_ci if (err < 0) 67362306a36Sopenharmony_ci return err; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci err = lola_create_mixer(chip); 67662306a36Sopenharmony_ci if (err < 0) 67762306a36Sopenharmony_ci return err; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci lola_proc_debug_new(chip); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci err = snd_card_register(card); 68262306a36Sopenharmony_ci if (err < 0) 68362306a36Sopenharmony_ci return err; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci pci_set_drvdata(pci, card); 68662306a36Sopenharmony_ci dev++; 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic int lola_probe(struct pci_dev *pci, 69162306a36Sopenharmony_ci const struct pci_device_id *pci_id) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci return snd_card_free_on_error(&pci->dev, __lola_probe(pci, pci_id)); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci/* PCI IDs */ 69762306a36Sopenharmony_cistatic const struct pci_device_id lola_ids[] = { 69862306a36Sopenharmony_ci { PCI_VDEVICE(DIGIGRAM, 0x0001) }, 69962306a36Sopenharmony_ci { 0, } 70062306a36Sopenharmony_ci}; 70162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, lola_ids); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci/* pci_driver definition */ 70462306a36Sopenharmony_cistatic struct pci_driver lola_driver = { 70562306a36Sopenharmony_ci .name = KBUILD_MODNAME, 70662306a36Sopenharmony_ci .id_table = lola_ids, 70762306a36Sopenharmony_ci .probe = lola_probe, 70862306a36Sopenharmony_ci}; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cimodule_pci_driver(lola_driver); 711