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