xref: /openbmc/linux/sound/sparc/dbri.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21bd9debfSTakashi Iwai /*
31bd9debfSTakashi Iwai  * Driver for DBRI sound chip found on Sparcs.
44338829eSMartin Habets  * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net)
51bd9debfSTakashi Iwai  *
61be54c82SKrzysztof Helt  * Converted to ring buffered version by Krzysztof Helt (krzysztof.h1@wp.pl)
71be54c82SKrzysztof Helt  *
81bd9debfSTakashi Iwai  * Based entirely upon drivers/sbus/audio/dbri.c which is:
91bd9debfSTakashi Iwai  * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
101bd9debfSTakashi Iwai  * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org)
111bd9debfSTakashi Iwai  *
121bd9debfSTakashi Iwai  * This is the low level driver for the DBRI & MMCODEC duo used for ISDN & AUDIO
13098ccbc5SKrzysztof Helt  * on Sun SPARCStation 10, 20, LX and Voyager models.
141bd9debfSTakashi Iwai  *
151bd9debfSTakashi Iwai  * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel
161bd9debfSTakashi Iwai  *   data time multiplexer with ISDN support (aka T7259)
171bd9debfSTakashi Iwai  *   Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel.
181bd9debfSTakashi Iwai  *   CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?).
191bd9debfSTakashi Iwai  *   Documentation:
20098ccbc5SKrzysztof Helt  *   - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Transceiver" from
211bd9debfSTakashi Iwai  *     Sparc Technology Business (courtesy of Sun Support)
221bd9debfSTakashi Iwai  *   - Data sheet of the T7903, a newer but very similar ISA bus equivalent
23098ccbc5SKrzysztof Helt  *     available from the Lucent (formerly AT&T microelectronics) home
241bd9debfSTakashi Iwai  *     page.
257ed33ea6SAlexander A. Klimov  *   - https://www.freesoft.org/Linux/DBRI/
261bd9debfSTakashi Iwai  * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec
271bd9debfSTakashi Iwai  *   Interfaces: CHI, Audio In & Out, 2 bits parallel
281bd9debfSTakashi Iwai  *   Documentation: from the Crystal Semiconductor home page.
291bd9debfSTakashi Iwai  *
301bd9debfSTakashi Iwai  * The DBRI is a 32 pipe machine, each pipe can transfer some bits between
31098ccbc5SKrzysztof Helt  * memory and a serial device (long pipes, no. 0-15) or between two serial
32098ccbc5SKrzysztof Helt  * devices (short pipes, no. 16-31), or simply send a fixed data to a serial
331bd9debfSTakashi Iwai  * device (short pipes).
34098ccbc5SKrzysztof Helt  * A timeslot defines the bit-offset and no. of bits read from a serial device.
351bd9debfSTakashi Iwai  * The timeslots are linked to 6 circular lists, one for each direction for
361bd9debfSTakashi Iwai  * each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes
371bd9debfSTakashi Iwai  * (the second one is a monitor/tee pipe, valid only for serial input).
381bd9debfSTakashi Iwai  *
391bd9debfSTakashi Iwai  * The mmcodec is connected via the CHI bus and needs the data & some
405fc3a2b2SKrzysztof Helt  * parameters (volume, output selection) time multiplexed in 8 byte
411bd9debfSTakashi Iwai  * chunks. It also has a control mode, which serves for audio format setting.
421bd9debfSTakashi Iwai  *
431bd9debfSTakashi Iwai  * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on
44098ccbc5SKrzysztof Helt  * the same CHI bus, so I thought perhaps it is possible to use the on-board
45098ccbc5SKrzysztof Helt  * & the speakerbox codec simultaneously, giving 2 (not very independent :-)
461bd9debfSTakashi Iwai  * audio devices. But the SUN HW group decided against it, at least on my
471bd9debfSTakashi Iwai  * LX the speakerbox connector has at least 1 pin missing and 1 wrongly
481bd9debfSTakashi Iwai  * connected.
494338829eSMartin Habets  *
504338829eSMartin Habets  * I've tried to stick to the following function naming conventions:
514338829eSMartin Habets  * snd_*	ALSA stuff
52d254c8f7SAdrian Bunk  * cs4215_*	CS4215 codec specific stuff
534338829eSMartin Habets  * dbri_*	DBRI high-level stuff
544338829eSMartin Habets  * other	DBRI low-level stuff
551bd9debfSTakashi Iwai  */
561bd9debfSTakashi Iwai 
571bd9debfSTakashi Iwai #include <linux/interrupt.h>
581bd9debfSTakashi Iwai #include <linux/delay.h>
59098ccbc5SKrzysztof Helt #include <linux/irq.h>
60098ccbc5SKrzysztof Helt #include <linux/io.h>
61738f2b7bSDavid S. Miller #include <linux/dma-mapping.h>
625a0e3ad6STejun Heo #include <linux/gfp.h>
631bd9debfSTakashi Iwai 
641bd9debfSTakashi Iwai #include <sound/core.h>
651bd9debfSTakashi Iwai #include <sound/pcm.h>
661bd9debfSTakashi Iwai #include <sound/pcm_params.h>
671bd9debfSTakashi Iwai #include <sound/info.h>
681bd9debfSTakashi Iwai #include <sound/control.h>
691bd9debfSTakashi Iwai #include <sound/initval.h>
701bd9debfSTakashi Iwai 
71ef285fe6SKrzysztof Helt #include <linux/of.h>
72*7e9f2839SRob Herring #include <linux/platform_device.h>
7360063497SArun Sharma #include <linux/atomic.h>
74da155d5bSPaul Gortmaker #include <linux/module.h>
751bd9debfSTakashi Iwai 
761bd9debfSTakashi Iwai MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
771bd9debfSTakashi Iwai MODULE_DESCRIPTION("Sun DBRI");
781bd9debfSTakashi Iwai MODULE_LICENSE("GPL");
791bd9debfSTakashi Iwai 
801bd9debfSTakashi Iwai static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
811bd9debfSTakashi Iwai static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
82098ccbc5SKrzysztof Helt /* Enable this card */
83a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
841bd9debfSTakashi Iwai 
851bd9debfSTakashi Iwai module_param_array(index, int, NULL, 0444);
861bd9debfSTakashi Iwai MODULE_PARM_DESC(index, "Index value for Sun DBRI soundcard.");
871bd9debfSTakashi Iwai module_param_array(id, charp, NULL, 0444);
881bd9debfSTakashi Iwai MODULE_PARM_DESC(id, "ID string for Sun DBRI soundcard.");
891bd9debfSTakashi Iwai module_param_array(enable, bool, NULL, 0444);
901bd9debfSTakashi Iwai MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
911bd9debfSTakashi Iwai 
92ab93c7aeSKrzysztof Helt #undef DBRI_DEBUG
931bd9debfSTakashi Iwai 
941bd9debfSTakashi Iwai #define D_INT	(1<<0)
951bd9debfSTakashi Iwai #define D_GEN	(1<<1)
961bd9debfSTakashi Iwai #define D_CMD	(1<<2)
971bd9debfSTakashi Iwai #define D_MM	(1<<3)
981bd9debfSTakashi Iwai #define D_USR	(1<<4)
991bd9debfSTakashi Iwai #define D_DESC	(1<<5)
1001bd9debfSTakashi Iwai 
1016581f4e7STakashi Iwai static int dbri_debug;
1024338829eSMartin Habets module_param(dbri_debug, int, 0644);
1031bd9debfSTakashi Iwai MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");
1041bd9debfSTakashi Iwai 
1051bd9debfSTakashi Iwai #ifdef DBRI_DEBUG
106121f46beSTakashi Iwai static const char * const cmds[] = {
1071bd9debfSTakashi Iwai 	"WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
1081bd9debfSTakashi Iwai 	"SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
1091bd9debfSTakashi Iwai };
1101bd9debfSTakashi Iwai 
1111bd9debfSTakashi Iwai #define dprintk(a, x...) if (dbri_debug & a) printk(KERN_DEBUG x)
1121bd9debfSTakashi Iwai 
1131bd9debfSTakashi Iwai #else
114aaad3653SKrzysztof Helt #define dprintk(a, x...) do { } while (0)
1151bd9debfSTakashi Iwai 
11642fe7647SKrzysztof Helt #endif				/* DBRI_DEBUG */
11742fe7647SKrzysztof Helt 
1181bd9debfSTakashi Iwai #define DBRI_CMD(cmd, intr, value) ((cmd << 28) |	\
1191bd9debfSTakashi Iwai 				    (intr << 27) |	\
1201bd9debfSTakashi Iwai 				    value)
1211bd9debfSTakashi Iwai 
1221bd9debfSTakashi Iwai /***************************************************************************
1231bd9debfSTakashi Iwai 	CS4215 specific definitions and structures
1241bd9debfSTakashi Iwai ****************************************************************************/
1251bd9debfSTakashi Iwai 
1261bd9debfSTakashi Iwai struct cs4215 {
1271bd9debfSTakashi Iwai 	__u8 data[4];		/* Data mode: Time slots 5-8 */
1281bd9debfSTakashi Iwai 	__u8 ctrl[4];		/* Ctrl mode: Time slots 1-4 */
1291bd9debfSTakashi Iwai 	__u8 onboard;
1301bd9debfSTakashi Iwai 	__u8 offset;		/* Bit offset from frame sync to time slot 1 */
1311bd9debfSTakashi Iwai 	volatile __u32 status;
1321bd9debfSTakashi Iwai 	volatile __u32 version;
1331bd9debfSTakashi Iwai 	__u8 precision;		/* In bits, either 8 or 16 */
1341bd9debfSTakashi Iwai 	__u8 channels;		/* 1 or 2 */
1351bd9debfSTakashi Iwai };
1361bd9debfSTakashi Iwai 
1371bd9debfSTakashi Iwai /*
1381bd9debfSTakashi Iwai  * Control mode first
1391bd9debfSTakashi Iwai  */
1401bd9debfSTakashi Iwai 
1411bd9debfSTakashi Iwai /* Time Slot 1, Status register */
1421bd9debfSTakashi Iwai #define CS4215_CLB	(1<<2)	/* Control Latch Bit */
1431bd9debfSTakashi Iwai #define CS4215_OLB	(1<<3)	/* 1: line: 2.0V, speaker 4V */
1441bd9debfSTakashi Iwai 				/* 0: line: 2.8V, speaker 8V */
1451bd9debfSTakashi Iwai #define CS4215_MLB	(1<<4)	/* 1: Microphone: 20dB gain disabled */
1461bd9debfSTakashi Iwai #define CS4215_RSRVD_1  (1<<5)
1471bd9debfSTakashi Iwai 
1481bd9debfSTakashi Iwai /* Time Slot 2, Data Format Register */
1491bd9debfSTakashi Iwai #define CS4215_DFR_LINEAR16	0
1501bd9debfSTakashi Iwai #define CS4215_DFR_ULAW		1
1511bd9debfSTakashi Iwai #define CS4215_DFR_ALAW		2
1521bd9debfSTakashi Iwai #define CS4215_DFR_LINEAR8	3
1531bd9debfSTakashi Iwai #define CS4215_DFR_STEREO	(1<<2)
1541bd9debfSTakashi Iwai static struct {
1551bd9debfSTakashi Iwai 	unsigned short freq;
1561bd9debfSTakashi Iwai 	unsigned char xtal;
1571bd9debfSTakashi Iwai 	unsigned char csval;
1581bd9debfSTakashi Iwai } CS4215_FREQ[] = {
1591bd9debfSTakashi Iwai 	{  8000, (1 << 4), (0 << 3) },
1601bd9debfSTakashi Iwai 	{ 16000, (1 << 4), (1 << 3) },
1611bd9debfSTakashi Iwai 	{ 27429, (1 << 4), (2 << 3) },	/* Actually 24428.57 */
1621bd9debfSTakashi Iwai 	{ 32000, (1 << 4), (3 << 3) },
1631bd9debfSTakashi Iwai      /* {    NA, (1 << 4), (4 << 3) }, */
1641bd9debfSTakashi Iwai      /* {    NA, (1 << 4), (5 << 3) }, */
1651bd9debfSTakashi Iwai 	{ 48000, (1 << 4), (6 << 3) },
1661bd9debfSTakashi Iwai 	{  9600, (1 << 4), (7 << 3) },
167ab93c7aeSKrzysztof Helt 	{  5512, (2 << 4), (0 << 3) },	/* Actually 5512.5 */
1681bd9debfSTakashi Iwai 	{ 11025, (2 << 4), (1 << 3) },
1691bd9debfSTakashi Iwai 	{ 18900, (2 << 4), (2 << 3) },
1701bd9debfSTakashi Iwai 	{ 22050, (2 << 4), (3 << 3) },
1711bd9debfSTakashi Iwai 	{ 37800, (2 << 4), (4 << 3) },
1721bd9debfSTakashi Iwai 	{ 44100, (2 << 4), (5 << 3) },
1731bd9debfSTakashi Iwai 	{ 33075, (2 << 4), (6 << 3) },
1741bd9debfSTakashi Iwai 	{  6615, (2 << 4), (7 << 3) },
1751bd9debfSTakashi Iwai 	{ 0, 0, 0}
1761bd9debfSTakashi Iwai };
1771bd9debfSTakashi Iwai 
1781bd9debfSTakashi Iwai #define CS4215_HPF	(1<<7)	/* High Pass Filter, 1: Enabled */
1791bd9debfSTakashi Iwai 
1801bd9debfSTakashi Iwai #define CS4215_12_MASK	0xfcbf	/* Mask off reserved bits in slot 1 & 2 */
1811bd9debfSTakashi Iwai 
1821bd9debfSTakashi Iwai /* Time Slot 3, Serial Port Control register */
1831bd9debfSTakashi Iwai #define CS4215_XEN	(1<<0)	/* 0: Enable serial output */
1841bd9debfSTakashi Iwai #define CS4215_XCLK	(1<<1)	/* 1: Master mode: Generate SCLK */
1851bd9debfSTakashi Iwai #define CS4215_BSEL_64	(0<<2)	/* Bitrate: 64 bits per frame */
1861bd9debfSTakashi Iwai #define CS4215_BSEL_128	(1<<2)
1871bd9debfSTakashi Iwai #define CS4215_BSEL_256	(2<<2)
1881bd9debfSTakashi Iwai #define CS4215_MCK_MAST (0<<4)	/* Master clock */
1891bd9debfSTakashi Iwai #define CS4215_MCK_XTL1 (1<<4)	/* 24.576 MHz clock source */
1901bd9debfSTakashi Iwai #define CS4215_MCK_XTL2 (2<<4)	/* 16.9344 MHz clock source */
1911bd9debfSTakashi Iwai #define CS4215_MCK_CLK1 (3<<4)	/* Clockin, 256 x Fs */
1921bd9debfSTakashi Iwai #define CS4215_MCK_CLK2 (4<<4)	/* Clockin, see DFR */
1931bd9debfSTakashi Iwai 
1941bd9debfSTakashi Iwai /* Time Slot 4, Test Register */
1951bd9debfSTakashi Iwai #define CS4215_DAD	(1<<0)	/* 0:Digital-Dig loop, 1:Dig-Analog-Dig loop */
1961bd9debfSTakashi Iwai #define CS4215_ENL	(1<<1)	/* Enable Loopback Testing */
1971bd9debfSTakashi Iwai 
1981bd9debfSTakashi Iwai /* Time Slot 5, Parallel Port Register */
1991bd9debfSTakashi Iwai /* Read only here and the same as the in data mode */
2001bd9debfSTakashi Iwai 
2011bd9debfSTakashi Iwai /* Time Slot 6, Reserved  */
2021bd9debfSTakashi Iwai 
2031bd9debfSTakashi Iwai /* Time Slot 7, Version Register  */
2041bd9debfSTakashi Iwai #define CS4215_VERSION_MASK 0xf	/* Known versions 0/C, 1/D, 2/E */
2051bd9debfSTakashi Iwai 
2061bd9debfSTakashi Iwai /* Time Slot 8, Reserved  */
2071bd9debfSTakashi Iwai 
2081bd9debfSTakashi Iwai /*
2091bd9debfSTakashi Iwai  * Data mode
2101bd9debfSTakashi Iwai  */
2111bd9debfSTakashi Iwai /* Time Slot 1-2: Left Channel Data, 2-3: Right Channel Data  */
2121bd9debfSTakashi Iwai 
2131bd9debfSTakashi Iwai /* Time Slot 5, Output Setting  */
2141bd9debfSTakashi Iwai #define CS4215_LO(v)	v	/* Left Output Attenuation 0x3f: -94.5 dB */
2151bd9debfSTakashi Iwai #define CS4215_LE	(1<<6)	/* Line Out Enable */
2161bd9debfSTakashi Iwai #define CS4215_HE	(1<<7)	/* Headphone Enable */
2171bd9debfSTakashi Iwai 
2181bd9debfSTakashi Iwai /* Time Slot 6, Output Setting  */
2191bd9debfSTakashi Iwai #define CS4215_RO(v)	v	/* Right Output Attenuation 0x3f: -94.5 dB */
2201bd9debfSTakashi Iwai #define CS4215_SE	(1<<6)	/* Speaker Enable */
2211bd9debfSTakashi Iwai #define CS4215_ADI	(1<<7)	/* A/D Data Invalid: Busy in calibration */
2221bd9debfSTakashi Iwai 
2231bd9debfSTakashi Iwai /* Time Slot 7, Input Setting */
2241bd9debfSTakashi Iwai #define CS4215_LG(v)	v	/* Left Gain Setting 0xf: 22.5 dB */
2251bd9debfSTakashi Iwai #define CS4215_IS	(1<<4)	/* Input Select: 1=Microphone, 0=Line */
2261bd9debfSTakashi Iwai #define CS4215_OVR	(1<<5)	/* 1: Over range condition occurred */
2271bd9debfSTakashi Iwai #define CS4215_PIO0	(1<<6)	/* Parallel I/O 0 */
2281bd9debfSTakashi Iwai #define CS4215_PIO1	(1<<7)
2291bd9debfSTakashi Iwai 
2301bd9debfSTakashi Iwai /* Time Slot 8, Input Setting */
2311bd9debfSTakashi Iwai #define CS4215_RG(v)	v	/* Right Gain Setting 0xf: 22.5 dB */
2321bd9debfSTakashi Iwai #define CS4215_MA(v)	(v<<4)	/* Monitor Path Attenuation 0xf: mute */
2331bd9debfSTakashi Iwai 
2341bd9debfSTakashi Iwai /***************************************************************************
2351bd9debfSTakashi Iwai 		DBRI specific definitions and structures
2361bd9debfSTakashi Iwai ****************************************************************************/
2371bd9debfSTakashi Iwai 
2381bd9debfSTakashi Iwai /* DBRI main registers */
239cf68d212SKrzysztof Helt #define REG0	0x00		/* Status and Control */
240cf68d212SKrzysztof Helt #define REG1	0x04		/* Mode and Interrupt */
241cf68d212SKrzysztof Helt #define REG2	0x08		/* Parallel IO */
242cf68d212SKrzysztof Helt #define REG3	0x0c		/* Test */
243cf68d212SKrzysztof Helt #define REG8	0x20		/* Command Queue Pointer */
244cf68d212SKrzysztof Helt #define REG9	0x24		/* Interrupt Queue Pointer */
2451bd9debfSTakashi Iwai 
2461bd9debfSTakashi Iwai #define DBRI_NO_CMDS	64
2471bd9debfSTakashi Iwai #define DBRI_INT_BLK	64
2481bd9debfSTakashi Iwai #define DBRI_NO_DESCS	64
2491bd9debfSTakashi Iwai #define DBRI_NO_PIPES	32
250470f1f1aSKrzysztof Helt #define DBRI_MAX_PIPE	(DBRI_NO_PIPES - 1)
2511bd9debfSTakashi Iwai 
2521bd9debfSTakashi Iwai #define DBRI_REC	0
2531bd9debfSTakashi Iwai #define DBRI_PLAY	1
2541bd9debfSTakashi Iwai #define DBRI_NO_STREAMS	2
2551bd9debfSTakashi Iwai 
2561bd9debfSTakashi Iwai /* One transmit/receive descriptor */
257c2735446SKrzysztof Helt /* When ba != 0 descriptor is used */
2581bd9debfSTakashi Iwai struct dbri_mem {
2591bd9debfSTakashi Iwai 	volatile __u32 word1;
26016727d94SKrzysztof Helt 	__u32 ba;	/* Transmit/Receive Buffer Address */
26116727d94SKrzysztof Helt 	__u32 nda;	/* Next Descriptor Address */
2621bd9debfSTakashi Iwai 	volatile __u32 word4;
2631bd9debfSTakashi Iwai };
2641bd9debfSTakashi Iwai 
2651bd9debfSTakashi Iwai /* This structure is in a DMA region where it can accessed by both
2661bd9debfSTakashi Iwai  * the CPU and the DBRI
2671bd9debfSTakashi Iwai  */
2681bd9debfSTakashi Iwai struct dbri_dma {
2691be54c82SKrzysztof Helt 	s32 cmd[DBRI_NO_CMDS];			/* Place for commands */
2706fb98280SKrzysztof Helt 	volatile s32 intr[DBRI_INT_BLK];	/* Interrupt field  */
2711bd9debfSTakashi Iwai 	struct dbri_mem desc[DBRI_NO_DESCS];	/* Xmit/receive descriptors */
2721bd9debfSTakashi Iwai };
2731bd9debfSTakashi Iwai 
2741bd9debfSTakashi Iwai #define dbri_dma_off(member, elem)	\
2751bd9debfSTakashi Iwai 	((u32)(unsigned long)		\
2761bd9debfSTakashi Iwai 	 (&(((struct dbri_dma *)0)->member[elem])))
2771bd9debfSTakashi Iwai 
2781bd9debfSTakashi Iwai enum in_or_out { PIPEinput, PIPEoutput };
2791bd9debfSTakashi Iwai 
2801bd9debfSTakashi Iwai struct dbri_pipe {
2811bd9debfSTakashi Iwai 	u32 sdp;		/* SDP command word */
2821bd9debfSTakashi Iwai 	int nextpipe;		/* Next pipe in linked list */
2831bd9debfSTakashi Iwai 	int length;		/* Length of timeslot (bits) */
2841bd9debfSTakashi Iwai 	int first_desc;		/* Index of first descriptor */
2851bd9debfSTakashi Iwai 	int desc;		/* Index of active descriptor */
2861bd9debfSTakashi Iwai 	volatile __u32 *recv_fixed_ptr;	/* Ptr to receive fixed data */
2871bd9debfSTakashi Iwai };
2881bd9debfSTakashi Iwai 
2891bd9debfSTakashi Iwai /* Per stream (playback or record) information */
290475675d6STakashi Iwai struct dbri_streaminfo {
291475675d6STakashi Iwai 	struct snd_pcm_substream *substream;
292098ccbc5SKrzysztof Helt 	u32 dvma_buffer;	/* Device view of ALSA DMA buffer */
2931bd9debfSTakashi Iwai 	int size;		/* Size of DMA buffer             */
2941bd9debfSTakashi Iwai 	size_t offset;		/* offset in user buffer          */
2951bd9debfSTakashi Iwai 	int pipe;		/* Data pipe used                 */
2961bd9debfSTakashi Iwai 	int left_gain;		/* mixer elements                 */
2971bd9debfSTakashi Iwai 	int right_gain;
298475675d6STakashi Iwai };
2991bd9debfSTakashi Iwai 
3001bd9debfSTakashi Iwai /* This structure holds the information for both chips (DBRI & CS4215) */
301475675d6STakashi Iwai struct snd_dbri {
3021bd9debfSTakashi Iwai 	int regs_size, irq;	/* Needed for unload */
3032dc11581SGrant Likely 	struct platform_device *op;	/* OF device info */
3041bd9debfSTakashi Iwai 	spinlock_t lock;
3051bd9debfSTakashi Iwai 
30616727d94SKrzysztof Helt 	struct dbri_dma *dma;	/* Pointer to our DMA block */
30716f46050STushar Dave 	dma_addr_t dma_dvma;	/* DBRI visible DMA address */
3081bd9debfSTakashi Iwai 
3091bd9debfSTakashi Iwai 	void __iomem *regs;	/* dbri HW regs */
3101bd9debfSTakashi Iwai 	int dbri_irqp;		/* intr queue pointer */
3111bd9debfSTakashi Iwai 
3121bd9debfSTakashi Iwai 	struct dbri_pipe pipes[DBRI_NO_PIPES];	/* DBRI's 32 data pipes */
313c2735446SKrzysztof Helt 	int next_desc[DBRI_NO_DESCS];		/* Index of next desc, or -1 */
3141be54c82SKrzysztof Helt 	spinlock_t cmdlock;	/* Protects cmd queue accesses */
3151be54c82SKrzysztof Helt 	s32 *cmdptr;		/* Pointer to the last queued cmd */
3161bd9debfSTakashi Iwai 
3171bd9debfSTakashi Iwai 	int chi_bpf;
3181bd9debfSTakashi Iwai 
3191bd9debfSTakashi Iwai 	struct cs4215 mm;	/* mmcodec special info */
3201bd9debfSTakashi Iwai 				/* per stream (playback/record) info */
3211bd9debfSTakashi Iwai 	struct dbri_streaminfo stream_info[DBRI_NO_STREAMS];
322475675d6STakashi Iwai };
3231bd9debfSTakashi Iwai 
3241bd9debfSTakashi Iwai #define DBRI_MAX_VOLUME		63	/* Output volume */
3251bd9debfSTakashi Iwai #define DBRI_MAX_GAIN		15	/* Input gain */
3261bd9debfSTakashi Iwai 
3271bd9debfSTakashi Iwai /* DBRI Reg0 - Status Control Register - defines. (Page 17) */
3281bd9debfSTakashi Iwai #define D_P		(1<<15)	/* Program command & queue pointer valid */
3291bd9debfSTakashi Iwai #define D_G		(1<<14)	/* Allow 4-Word SBus Burst */
3301bd9debfSTakashi Iwai #define D_S		(1<<13)	/* Allow 16-Word SBus Burst */
3311bd9debfSTakashi Iwai #define D_E		(1<<12)	/* Allow 8-Word SBus Burst */
3321bd9debfSTakashi Iwai #define D_X		(1<<7)	/* Sanity Timer Disable */
3331bd9debfSTakashi Iwai #define D_T		(1<<6)	/* Permit activation of the TE interface */
3341bd9debfSTakashi Iwai #define D_N		(1<<5)	/* Permit activation of the NT interface */
3351bd9debfSTakashi Iwai #define D_C		(1<<4)	/* Permit activation of the CHI interface */
3361bd9debfSTakashi Iwai #define D_F		(1<<3)	/* Force Sanity Timer Time-Out */
3371bd9debfSTakashi Iwai #define D_D		(1<<2)	/* Disable Master Mode */
3381bd9debfSTakashi Iwai #define D_H		(1<<1)	/* Halt for Analysis */
3391bd9debfSTakashi Iwai #define D_R		(1<<0)	/* Soft Reset */
3401bd9debfSTakashi Iwai 
3411bd9debfSTakashi Iwai /* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */
3421bd9debfSTakashi Iwai #define D_LITTLE_END	(1<<8)	/* Byte Order */
3431bd9debfSTakashi Iwai #define D_BIG_END	(0<<8)	/* Byte Order */
3441bd9debfSTakashi Iwai #define D_MRR		(1<<4)	/* Multiple Error Ack on SBus (read only) */
3451bd9debfSTakashi Iwai #define D_MLE		(1<<3)	/* Multiple Late Error on SBus (read only) */
3461bd9debfSTakashi Iwai #define D_LBG		(1<<2)	/* Lost Bus Grant on SBus (read only) */
3471bd9debfSTakashi Iwai #define D_MBE		(1<<1)	/* Burst Error on SBus (read only) */
3481bd9debfSTakashi Iwai #define D_IR		(1<<0)	/* Interrupt Indicator (read only) */
3491bd9debfSTakashi Iwai 
3501bd9debfSTakashi Iwai /* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */
3511bd9debfSTakashi Iwai #define D_ENPIO3	(1<<7)	/* Enable Pin 3 */
3521bd9debfSTakashi Iwai #define D_ENPIO2	(1<<6)	/* Enable Pin 2 */
3531bd9debfSTakashi Iwai #define D_ENPIO1	(1<<5)	/* Enable Pin 1 */
3541bd9debfSTakashi Iwai #define D_ENPIO0	(1<<4)	/* Enable Pin 0 */
3551bd9debfSTakashi Iwai #define D_ENPIO		(0xf0)	/* Enable all the pins */
3561bd9debfSTakashi Iwai #define D_PIO3		(1<<3)	/* Pin 3: 1: Data mode, 0: Ctrl mode */
3571bd9debfSTakashi Iwai #define D_PIO2		(1<<2)	/* Pin 2: 1: Onboard PDN */
3581bd9debfSTakashi Iwai #define D_PIO1		(1<<1)	/* Pin 1: 0: Reset */
3591bd9debfSTakashi Iwai #define D_PIO0		(1<<0)	/* Pin 0: 1: Speakerbox PDN */
3601bd9debfSTakashi Iwai 
3611bd9debfSTakashi Iwai /* DBRI Commands (Page 20) */
3621bd9debfSTakashi Iwai #define D_WAIT		0x0	/* Stop execution */
3631bd9debfSTakashi Iwai #define D_PAUSE		0x1	/* Flush long pipes */
3641bd9debfSTakashi Iwai #define D_JUMP		0x2	/* New command queue */
3651bd9debfSTakashi Iwai #define D_IIQ		0x3	/* Initialize Interrupt Queue */
3661bd9debfSTakashi Iwai #define D_REX		0x4	/* Report command execution via interrupt */
3671bd9debfSTakashi Iwai #define D_SDP		0x5	/* Setup Data Pipe */
3681bd9debfSTakashi Iwai #define D_CDP		0x6	/* Continue Data Pipe (reread NULL Pointer) */
3691bd9debfSTakashi Iwai #define D_DTS		0x7	/* Define Time Slot */
3701bd9debfSTakashi Iwai #define D_SSP		0x8	/* Set short Data Pipe */
3711bd9debfSTakashi Iwai #define D_CHI		0x9	/* Set CHI Global Mode */
3721bd9debfSTakashi Iwai #define D_NT		0xa	/* NT Command */
3731bd9debfSTakashi Iwai #define D_TE		0xb	/* TE Command */
3741bd9debfSTakashi Iwai #define D_CDEC		0xc	/* Codec setup */
3751bd9debfSTakashi Iwai #define D_TEST		0xd	/* No comment */
3761bd9debfSTakashi Iwai #define D_CDM		0xe	/* CHI Data mode command */
3771bd9debfSTakashi Iwai 
3781bd9debfSTakashi Iwai /* Special bits for some commands */
379098ccbc5SKrzysztof Helt #define D_PIPE(v)      ((v)<<0)	/* Pipe No.: 0-15 long, 16-21 short */
3801bd9debfSTakashi Iwai 
3811bd9debfSTakashi Iwai /* Setup Data Pipe */
3821bd9debfSTakashi Iwai /* IRM */
383098ccbc5SKrzysztof Helt #define D_SDP_2SAME	(1<<18)	/* Report 2nd time in a row value received */
3841bd9debfSTakashi Iwai #define D_SDP_CHANGE	(2<<18)	/* Report any changes */
3851bd9debfSTakashi Iwai #define D_SDP_EVERY	(3<<18)	/* Report any changes */
3861bd9debfSTakashi Iwai #define D_SDP_EOL	(1<<17)	/* EOL interrupt enable */
3871bd9debfSTakashi Iwai #define D_SDP_IDLE	(1<<16)	/* HDLC idle interrupt enable */
3881bd9debfSTakashi Iwai 
3891bd9debfSTakashi Iwai /* Pipe data MODE */
3901bd9debfSTakashi Iwai #define D_SDP_MEM	(0<<13)	/* To/from memory */
3911bd9debfSTakashi Iwai #define D_SDP_HDLC	(2<<13)
3921bd9debfSTakashi Iwai #define D_SDP_HDLC_D	(3<<13)	/* D Channel (prio control) */
3931bd9debfSTakashi Iwai #define D_SDP_SER	(4<<13)	/* Serial to serial */
3941bd9debfSTakashi Iwai #define D_SDP_FIXED	(6<<13)	/* Short only */
3951bd9debfSTakashi Iwai #define D_SDP_MODE(v)	((v)&(7<<13))
3961bd9debfSTakashi Iwai 
3971bd9debfSTakashi Iwai #define D_SDP_TO_SER	(1<<12)	/* Direction */
3981bd9debfSTakashi Iwai #define D_SDP_FROM_SER	(0<<12)	/* Direction */
3991bd9debfSTakashi Iwai #define D_SDP_MSB	(1<<11)	/* Bit order within Byte */
4001bd9debfSTakashi Iwai #define D_SDP_LSB	(0<<11)	/* Bit order within Byte */
4011bd9debfSTakashi Iwai #define D_SDP_P		(1<<10)	/* Pointer Valid */
4021bd9debfSTakashi Iwai #define D_SDP_A		(1<<8)	/* Abort */
4031bd9debfSTakashi Iwai #define D_SDP_C		(1<<7)	/* Clear */
4041bd9debfSTakashi Iwai 
4051bd9debfSTakashi Iwai /* Define Time Slot */
4061bd9debfSTakashi Iwai #define D_DTS_VI	(1<<17)	/* Valid Input Time-Slot Descriptor */
4071bd9debfSTakashi Iwai #define D_DTS_VO	(1<<16)	/* Valid Output Time-Slot Descriptor */
4081bd9debfSTakashi Iwai #define D_DTS_INS	(1<<15)	/* Insert Time Slot */
4091bd9debfSTakashi Iwai #define D_DTS_DEL	(0<<15)	/* Delete Time Slot */
4101bd9debfSTakashi Iwai #define D_DTS_PRVIN(v) ((v)<<10)	/* Previous In Pipe */
4111bd9debfSTakashi Iwai #define D_DTS_PRVOUT(v)        ((v)<<5)	/* Previous Out Pipe */
4121bd9debfSTakashi Iwai 
4131bd9debfSTakashi Iwai /* Time Slot defines */
4141bd9debfSTakashi Iwai #define D_TS_LEN(v)	((v)<<24)	/* Number of bits in this time slot */
4151bd9debfSTakashi Iwai #define D_TS_CYCLE(v)	((v)<<14)	/* Bit Count at start of TS */
4161bd9debfSTakashi Iwai #define D_TS_DI		(1<<13)	/* Data Invert */
4171bd9debfSTakashi Iwai #define D_TS_1CHANNEL	(0<<10)	/* Single Channel / Normal mode */
4181bd9debfSTakashi Iwai #define D_TS_MONITOR	(2<<10)	/* Monitor pipe */
4191bd9debfSTakashi Iwai #define D_TS_NONCONTIG	(3<<10)	/* Non contiguous mode */
4201bd9debfSTakashi Iwai #define D_TS_ANCHOR	(7<<10)	/* Starting short pipes */
4211bd9debfSTakashi Iwai #define D_TS_MON(v)    ((v)<<5)	/* Monitor Pipe */
422098ccbc5SKrzysztof Helt #define D_TS_NEXT(v)   ((v)<<0)	/* Pipe no.: 0-15 long, 16-21 short */
4231bd9debfSTakashi Iwai 
4241bd9debfSTakashi Iwai /* Concentration Highway Interface Modes */
4251bd9debfSTakashi Iwai #define D_CHI_CHICM(v)	((v)<<16)	/* Clock mode */
4261bd9debfSTakashi Iwai #define D_CHI_IR	(1<<15)	/* Immediate Interrupt Report */
4271bd9debfSTakashi Iwai #define D_CHI_EN	(1<<14)	/* CHIL Interrupt enabled */
4281bd9debfSTakashi Iwai #define D_CHI_OD	(1<<13)	/* Open Drain Enable */
4291bd9debfSTakashi Iwai #define D_CHI_FE	(1<<12)	/* Sample CHIFS on Rising Frame Edge */
4301bd9debfSTakashi Iwai #define D_CHI_FD	(1<<11)	/* Frame Drive */
4311bd9debfSTakashi Iwai #define D_CHI_BPF(v)	((v)<<0)	/* Bits per Frame */
4321bd9debfSTakashi Iwai 
4331bd9debfSTakashi Iwai /* NT: These are here for completeness */
4341bd9debfSTakashi Iwai #define D_NT_FBIT	(1<<17)	/* Frame Bit */
4351bd9debfSTakashi Iwai #define D_NT_NBF	(1<<16)	/* Number of bad frames to loose framing */
4361bd9debfSTakashi Iwai #define D_NT_IRM_IMM	(1<<15)	/* Interrupt Report & Mask: Immediate */
4371bd9debfSTakashi Iwai #define D_NT_IRM_EN	(1<<14)	/* Interrupt Report & Mask: Enable */
438098ccbc5SKrzysztof Helt #define D_NT_ISNT	(1<<13)	/* Configure interface as NT */
4391bd9debfSTakashi Iwai #define D_NT_FT		(1<<12)	/* Fixed Timing */
4401bd9debfSTakashi Iwai #define D_NT_EZ		(1<<11)	/* Echo Channel is Zeros */
4411bd9debfSTakashi Iwai #define D_NT_IFA	(1<<10)	/* Inhibit Final Activation */
4421bd9debfSTakashi Iwai #define D_NT_ACT	(1<<9)	/* Activate Interface */
4431bd9debfSTakashi Iwai #define D_NT_MFE	(1<<8)	/* Multiframe Enable */
4441bd9debfSTakashi Iwai #define D_NT_RLB(v)	((v)<<5)	/* Remote Loopback */
4451bd9debfSTakashi Iwai #define D_NT_LLB(v)	((v)<<2)	/* Local Loopback */
4461bd9debfSTakashi Iwai #define D_NT_FACT	(1<<1)	/* Force Activation */
4471bd9debfSTakashi Iwai #define D_NT_ABV	(1<<0)	/* Activate Bipolar Violation */
4481bd9debfSTakashi Iwai 
4491bd9debfSTakashi Iwai /* Codec Setup */
4501bd9debfSTakashi Iwai #define D_CDEC_CK(v)	((v)<<24)	/* Clock Select */
4511bd9debfSTakashi Iwai #define D_CDEC_FED(v)	((v)<<12)	/* FSCOD Falling Edge Delay */
4521bd9debfSTakashi Iwai #define D_CDEC_RED(v)	((v)<<0)	/* FSCOD Rising Edge Delay */
4531bd9debfSTakashi Iwai 
4541bd9debfSTakashi Iwai /* Test */
4551bd9debfSTakashi Iwai #define D_TEST_RAM(v)	((v)<<16)	/* RAM Pointer */
4561bd9debfSTakashi Iwai #define D_TEST_SIZE(v)	((v)<<11)	/* */
4571bd9debfSTakashi Iwai #define D_TEST_ROMONOFF	0x5	/* Toggle ROM opcode monitor on/off */
458098ccbc5SKrzysztof Helt #define D_TEST_PROC	0x6	/* Microprocessor test */
4591bd9debfSTakashi Iwai #define D_TEST_SER	0x7	/* Serial-Controller test */
4601bd9debfSTakashi Iwai #define D_TEST_RAMREAD	0x8	/* Copy from Ram to system memory */
4611bd9debfSTakashi Iwai #define D_TEST_RAMWRITE	0x9	/* Copy into Ram from system memory */
4621bd9debfSTakashi Iwai #define D_TEST_RAMBIST	0xa	/* RAM Built-In Self Test */
4631bd9debfSTakashi Iwai #define D_TEST_MCBIST	0xb	/* Microcontroller Built-In Self Test */
4641bd9debfSTakashi Iwai #define D_TEST_DUMP	0xe	/* ROM Dump */
4651bd9debfSTakashi Iwai 
4661bd9debfSTakashi Iwai /* CHI Data Mode */
4671bd9debfSTakashi Iwai #define D_CDM_THI	(1 << 8)	/* Transmit Data on CHIDR Pin */
4681bd9debfSTakashi Iwai #define D_CDM_RHI	(1 << 7)	/* Receive Data on CHIDX Pin */
4691bd9debfSTakashi Iwai #define D_CDM_RCE	(1 << 6)	/* Receive on Rising Edge of CHICK */
4701bd9debfSTakashi Iwai #define D_CDM_XCE	(1 << 2) /* Transmit Data on Rising Edge of CHICK */
4711bd9debfSTakashi Iwai #define D_CDM_XEN	(1 << 1)	/* Transmit Highway Enable */
4721bd9debfSTakashi Iwai #define D_CDM_REN	(1 << 0)	/* Receive Highway Enable */
4731bd9debfSTakashi Iwai 
4741bd9debfSTakashi Iwai /* The Interrupts */
4751bd9debfSTakashi Iwai #define D_INTR_BRDY	1	/* Buffer Ready for processing */
4761bd9debfSTakashi Iwai #define D_INTR_MINT	2	/* Marked Interrupt in RD/TD */
4771bd9debfSTakashi Iwai #define D_INTR_IBEG	3	/* Flag to idle transition detected (HDLC) */
4781bd9debfSTakashi Iwai #define D_INTR_IEND	4	/* Idle to flag transition detected (HDLC) */
4791bd9debfSTakashi Iwai #define D_INTR_EOL	5	/* End of List */
4801bd9debfSTakashi Iwai #define D_INTR_CMDI	6	/* Command has bean read */
4811bd9debfSTakashi Iwai #define D_INTR_XCMP	8	/* Transmission of frame complete */
4821bd9debfSTakashi Iwai #define D_INTR_SBRI	9	/* BRI status change info */
4831bd9debfSTakashi Iwai #define D_INTR_FXDT	10	/* Fixed data change */
4841bd9debfSTakashi Iwai #define D_INTR_CHIL	11	/* CHI lost frame sync (channel 36 only) */
4851bd9debfSTakashi Iwai #define D_INTR_COLL	11	/* Unrecoverable D-Channel collision */
4861bd9debfSTakashi Iwai #define D_INTR_DBYT	12	/* Dropped by frame slip */
4871bd9debfSTakashi Iwai #define D_INTR_RBYT	13	/* Repeated by frame slip */
4881bd9debfSTakashi Iwai #define D_INTR_LINT	14	/* Lost Interrupt */
4891bd9debfSTakashi Iwai #define D_INTR_UNDR	15	/* DMA underrun */
4901bd9debfSTakashi Iwai 
4911bd9debfSTakashi Iwai #define D_INTR_TE	32
4921bd9debfSTakashi Iwai #define D_INTR_NT	34
4931bd9debfSTakashi Iwai #define D_INTR_CHI	36
4941bd9debfSTakashi Iwai #define D_INTR_CMD	38
4951bd9debfSTakashi Iwai 
4961bd9debfSTakashi Iwai #define D_INTR_GETCHAN(v)	(((v) >> 24) & 0x3f)
4971bd9debfSTakashi Iwai #define D_INTR_GETCODE(v)	(((v) >> 20) & 0xf)
4981bd9debfSTakashi Iwai #define D_INTR_GETCMD(v)	(((v) >> 16) & 0xf)
4991bd9debfSTakashi Iwai #define D_INTR_GETVAL(v)	((v) & 0xffff)
5001bd9debfSTakashi Iwai #define D_INTR_GETRVAL(v)	((v) & 0xfffff)
5011bd9debfSTakashi Iwai 
5021bd9debfSTakashi Iwai #define D_P_0		0	/* TE receive anchor */
5031bd9debfSTakashi Iwai #define D_P_1		1	/* TE transmit anchor */
5041bd9debfSTakashi Iwai #define D_P_2		2	/* NT transmit anchor */
5051bd9debfSTakashi Iwai #define D_P_3		3	/* NT receive anchor */
5061bd9debfSTakashi Iwai #define D_P_4		4	/* CHI send data */
5071bd9debfSTakashi Iwai #define D_P_5		5	/* CHI receive data */
5081bd9debfSTakashi Iwai #define D_P_6		6	/* */
5091bd9debfSTakashi Iwai #define D_P_7		7	/* */
5101bd9debfSTakashi Iwai #define D_P_8		8	/* */
5111bd9debfSTakashi Iwai #define D_P_9		9	/* */
5121bd9debfSTakashi Iwai #define D_P_10		10	/* */
5131bd9debfSTakashi Iwai #define D_P_11		11	/* */
5141bd9debfSTakashi Iwai #define D_P_12		12	/* */
5151bd9debfSTakashi Iwai #define D_P_13		13	/* */
5161bd9debfSTakashi Iwai #define D_P_14		14	/* */
5171bd9debfSTakashi Iwai #define D_P_15		15	/* */
5181bd9debfSTakashi Iwai #define D_P_16		16	/* CHI anchor pipe */
5191bd9debfSTakashi Iwai #define D_P_17		17	/* CHI send */
5201bd9debfSTakashi Iwai #define D_P_18		18	/* CHI receive */
5211bd9debfSTakashi Iwai #define D_P_19		19	/* CHI receive */
5221bd9debfSTakashi Iwai #define D_P_20		20	/* CHI receive */
5231bd9debfSTakashi Iwai #define D_P_21		21	/* */
5241bd9debfSTakashi Iwai #define D_P_22		22	/* */
5251bd9debfSTakashi Iwai #define D_P_23		23	/* */
5261bd9debfSTakashi Iwai #define D_P_24		24	/* */
5271bd9debfSTakashi Iwai #define D_P_25		25	/* */
5281bd9debfSTakashi Iwai #define D_P_26		26	/* */
5291bd9debfSTakashi Iwai #define D_P_27		27	/* */
5301bd9debfSTakashi Iwai #define D_P_28		28	/* */
5311bd9debfSTakashi Iwai #define D_P_29		29	/* */
5321bd9debfSTakashi Iwai #define D_P_30		30	/* */
5331bd9debfSTakashi Iwai #define D_P_31		31	/* */
5341bd9debfSTakashi Iwai 
5351bd9debfSTakashi Iwai /* Transmit descriptor defines */
5361bd9debfSTakashi Iwai #define DBRI_TD_F	(1 << 31)	/* End of Frame */
5371bd9debfSTakashi Iwai #define DBRI_TD_D	(1 << 30)	/* Do not append CRC */
5381bd9debfSTakashi Iwai #define DBRI_TD_CNT(v)	((v) << 16) /* Number of valid bytes in the buffer */
5391bd9debfSTakashi Iwai #define DBRI_TD_B	(1 << 15)	/* Final interrupt */
5401bd9debfSTakashi Iwai #define DBRI_TD_M	(1 << 14)	/* Marker interrupt */
5411bd9debfSTakashi Iwai #define DBRI_TD_I	(1 << 13)	/* Transmit Idle Characters */
5421bd9debfSTakashi Iwai #define DBRI_TD_FCNT(v)	(v)		/* Flag Count */
5431bd9debfSTakashi Iwai #define DBRI_TD_UNR	(1 << 3) /* Underrun: transmitter is out of data */
5441bd9debfSTakashi Iwai #define DBRI_TD_ABT	(1 << 2)	/* Abort: frame aborted */
5451bd9debfSTakashi Iwai #define DBRI_TD_TBC	(1 << 0)	/* Transmit buffer Complete */
5461bd9debfSTakashi Iwai #define DBRI_TD_STATUS(v)       ((v) & 0xff)	/* Transmit status */
547098ccbc5SKrzysztof Helt 			/* Maximum buffer size per TD: almost 8KB */
5481be54c82SKrzysztof Helt #define DBRI_TD_MAXCNT	((1 << 13) - 4)
5491bd9debfSTakashi Iwai 
5501bd9debfSTakashi Iwai /* Receive descriptor defines */
5511bd9debfSTakashi Iwai #define DBRI_RD_F	(1 << 31)	/* End of Frame */
5521bd9debfSTakashi Iwai #define DBRI_RD_C	(1 << 30)	/* Completed buffer */
5531bd9debfSTakashi Iwai #define DBRI_RD_B	(1 << 15)	/* Final interrupt */
5541bd9debfSTakashi Iwai #define DBRI_RD_M	(1 << 14)	/* Marker interrupt */
5551bd9debfSTakashi Iwai #define DBRI_RD_BCNT(v)	(v)		/* Buffer size */
5561bd9debfSTakashi Iwai #define DBRI_RD_CRC	(1 << 7)	/* 0: CRC is correct */
5571bd9debfSTakashi Iwai #define DBRI_RD_BBC	(1 << 6)	/* 1: Bad Byte received */
5581bd9debfSTakashi Iwai #define DBRI_RD_ABT	(1 << 5)	/* Abort: frame aborted */
5591bd9debfSTakashi Iwai #define DBRI_RD_OVRN	(1 << 3)	/* Overrun: data lost */
5601bd9debfSTakashi Iwai #define DBRI_RD_STATUS(v)      ((v) & 0xff)	/* Receive status */
5611bd9debfSTakashi Iwai #define DBRI_RD_CNT(v) (((v) >> 16) & 0x1fff)	/* Valid bytes in the buffer */
5621bd9debfSTakashi Iwai 
5631bd9debfSTakashi Iwai /* stream_info[] access */
5641bd9debfSTakashi Iwai /* Translate the ALSA direction into the array index */
5651bd9debfSTakashi Iwai #define DBRI_STREAMNO(substream)				\
5661bd9debfSTakashi Iwai 		(substream->stream ==				\
5671bd9debfSTakashi Iwai 		 SNDRV_PCM_STREAM_PLAYBACK ? DBRI_PLAY: DBRI_REC)
5681bd9debfSTakashi Iwai 
5691bd9debfSTakashi Iwai /* Return a pointer to dbri_streaminfo */
570098ccbc5SKrzysztof Helt #define DBRI_STREAM(dbri, substream)	\
571098ccbc5SKrzysztof Helt 		&dbri->stream_info[DBRI_STREAMNO(substream)]
5721bd9debfSTakashi Iwai 
5731bd9debfSTakashi Iwai /*
5741bd9debfSTakashi Iwai  * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
5751bd9debfSTakashi Iwai  * So we have to reverse the bits. Note: not all bit lengths are supported
5761bd9debfSTakashi Iwai  */
reverse_bytes(__u32 b,int len)5771bd9debfSTakashi Iwai static __u32 reverse_bytes(__u32 b, int len)
5781bd9debfSTakashi Iwai {
5791bd9debfSTakashi Iwai 	switch (len) {
5801bd9debfSTakashi Iwai 	case 32:
5811bd9debfSTakashi Iwai 		b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16);
582c0dbbdadSGustavo A. R. Silva 		fallthrough;
5831bd9debfSTakashi Iwai 	case 16:
5841bd9debfSTakashi Iwai 		b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8);
585c0dbbdadSGustavo A. R. Silva 		fallthrough;
5861bd9debfSTakashi Iwai 	case 8:
5871bd9debfSTakashi Iwai 		b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4);
588c0dbbdadSGustavo A. R. Silva 		fallthrough;
5891bd9debfSTakashi Iwai 	case 4:
5901bd9debfSTakashi Iwai 		b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2);
591c0dbbdadSGustavo A. R. Silva 		fallthrough;
5921bd9debfSTakashi Iwai 	case 2:
5931bd9debfSTakashi Iwai 		b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);
5941bd9debfSTakashi Iwai 	case 1:
5951bd9debfSTakashi Iwai 	case 0:
5961bd9debfSTakashi Iwai 		break;
5971bd9debfSTakashi Iwai 	default:
5981bd9debfSTakashi Iwai 		printk(KERN_ERR "DBRI reverse_bytes: unsupported length\n");
599395d9dd5SPeter Senna Tschudin 	}
6001bd9debfSTakashi Iwai 
6011bd9debfSTakashi Iwai 	return b;
6021bd9debfSTakashi Iwai }
6031bd9debfSTakashi Iwai 
6041bd9debfSTakashi Iwai /*
6051bd9debfSTakashi Iwai ****************************************************************************
6061bd9debfSTakashi Iwai ************** DBRI initialization and command synchronization *************
6071bd9debfSTakashi Iwai ****************************************************************************
6081bd9debfSTakashi Iwai 
6091bd9debfSTakashi Iwai Commands are sent to the DBRI by building a list of them in memory,
6101bd9debfSTakashi Iwai then writing the address of the first list item to DBRI register 8.
6114338829eSMartin Habets The list is terminated with a WAIT command, which generates a
6124338829eSMartin Habets CPU interrupt to signal completion.
6131bd9debfSTakashi Iwai 
6141bd9debfSTakashi Iwai Since the DBRI can run in parallel with the CPU, several means of
615cf68d212SKrzysztof Helt synchronization present themselves. The method implemented here uses
616cf68d212SKrzysztof Helt the dbri_cmdwait() to wait for execution of batch of sent commands.
6171bd9debfSTakashi Iwai 
6181be54c82SKrzysztof Helt A circular command buffer is used here. A new command is being added
619aaad3653SKrzysztof Helt while another can be executed. The scheme works by adding two WAIT commands
6201be54c82SKrzysztof Helt after each sent batch of commands. When the next batch is prepared it is
6211be54c82SKrzysztof Helt added after the WAIT commands then the WAITs are replaced with single JUMP
622a97cbcd0SRandy Dunlap command to the new batch. Then the DBRI is forced to reread the last WAIT
6231be54c82SKrzysztof Helt command (replaced by the JUMP by then). If the DBRI is still executing
6241be54c82SKrzysztof Helt previous commands the request to reread the WAIT command is ignored.
6251bd9debfSTakashi Iwai 
6261bd9debfSTakashi Iwai Every time a routine wants to write commands to the DBRI, it must
6271be54c82SKrzysztof Helt first call dbri_cmdlock() and get pointer to a free space in
6281be54c82SKrzysztof Helt dbri->dma->cmd buffer. After this, the commands can be written to
6291be54c82SKrzysztof Helt the buffer, and dbri_cmdsend() is called with the final pointer value
6301be54c82SKrzysztof Helt to send them to the DBRI.
6311bd9debfSTakashi Iwai 
6321bd9debfSTakashi Iwai */
6331bd9debfSTakashi Iwai 
634aaad3653SKrzysztof Helt #define MAXLOOPS 20
6351be54c82SKrzysztof Helt /*
6361be54c82SKrzysztof Helt  * Wait for the current command string to execute
6371be54c82SKrzysztof Helt  */
dbri_cmdwait(struct snd_dbri * dbri)6381be54c82SKrzysztof Helt static void dbri_cmdwait(struct snd_dbri *dbri)
6391bd9debfSTakashi Iwai {
6404338829eSMartin Habets 	int maxloops = MAXLOOPS;
641ea543f1eSKrzysztof Helt 	unsigned long flags;
6424338829eSMartin Habets 
6434338829eSMartin Habets 	/* Delay if previous commands are still being processed */
644ea543f1eSKrzysztof Helt 	spin_lock_irqsave(&dbri->lock, flags);
645ea543f1eSKrzysztof Helt 	while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) {
646ea543f1eSKrzysztof Helt 		spin_unlock_irqrestore(&dbri->lock, flags);
6474338829eSMartin Habets 		msleep_interruptible(1);
648ea543f1eSKrzysztof Helt 		spin_lock_irqsave(&dbri->lock, flags);
649ea543f1eSKrzysztof Helt 	}
650ea543f1eSKrzysztof Helt 	spin_unlock_irqrestore(&dbri->lock, flags);
6511be54c82SKrzysztof Helt 
652cf68d212SKrzysztof Helt 	if (maxloops == 0)
6531be54c82SKrzysztof Helt 		printk(KERN_ERR "DBRI: Chip never completed command buffer\n");
654cf68d212SKrzysztof Helt 	else
6554338829eSMartin Habets 		dprintk(D_CMD, "Chip completed command buffer (%d)\n",
6564338829eSMartin Habets 			MAXLOOPS - maxloops - 1);
6574338829eSMartin Habets }
6581be54c82SKrzysztof Helt /*
659cf68d212SKrzysztof Helt  * Lock the command queue and return pointer to space for len cmd words
6601be54c82SKrzysztof Helt  * It locks the cmdlock spinlock.
6611be54c82SKrzysztof Helt  */
dbri_cmdlock(struct snd_dbri * dbri,int len)6621be54c82SKrzysztof Helt static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len)
6631be54c82SKrzysztof Helt {
66416f46050STushar Dave 	u32 dvma_addr = (u32)dbri->dma_dvma;
66516f46050STushar Dave 
6661be54c82SKrzysztof Helt 	/* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */
6671be54c82SKrzysztof Helt 	len += 2;
6681be54c82SKrzysztof Helt 	spin_lock(&dbri->cmdlock);
6691be54c82SKrzysztof Helt 	if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2)
6701be54c82SKrzysztof Helt 		return dbri->cmdptr + 2;
67116f46050STushar Dave 	else if (len < sbus_readl(dbri->regs + REG8) - dvma_addr)
6721be54c82SKrzysztof Helt 		return dbri->dma->cmd;
6731be54c82SKrzysztof Helt 	else
6741be54c82SKrzysztof Helt 		printk(KERN_ERR "DBRI: no space for commands.");
6754338829eSMartin Habets 
676ae97dd9aSAl Viro 	return NULL;
6771bd9debfSTakashi Iwai }
6781bd9debfSTakashi Iwai 
6791be54c82SKrzysztof Helt /*
680beb7dd86SRobert P. J. Day  * Send prepared cmd string. It works by writing a JUMP cmd into
6811be54c82SKrzysztof Helt  * the last WAIT cmd and force DBRI to reread the cmd.
682ab93c7aeSKrzysztof Helt  * The JUMP cmd points to the new cmd string.
6831be54c82SKrzysztof Helt  * It also releases the cmdlock spinlock.
684ea543f1eSKrzysztof Helt  *
685ca405870SKrzysztof Helt  * Lock must be held before calling this.
6861be54c82SKrzysztof Helt  */
dbri_cmdsend(struct snd_dbri * dbri,s32 * cmd,int len)6871be54c82SKrzysztof Helt static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len)
6881bd9debfSTakashi Iwai {
68916f46050STushar Dave 	u32 dvma_addr = (u32)dbri->dma_dvma;
6901be54c82SKrzysztof Helt 	s32 tmp, addr;
691808709d7SJason Wang 	static int wait_id;
6921bd9debfSTakashi Iwai 
6931be54c82SKrzysztof Helt 	wait_id++;
6941be54c82SKrzysztof Helt 	wait_id &= 0xffff;	/* restrict it to a 16 bit counter. */
6951be54c82SKrzysztof Helt 	*(cmd) = DBRI_CMD(D_WAIT, 1, wait_id);
6961be54c82SKrzysztof Helt 	*(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id);
6971be54c82SKrzysztof Helt 
6981be54c82SKrzysztof Helt 	/* Replace the last command with JUMP */
69916f46050STushar Dave 	addr = dvma_addr + (cmd - len - dbri->dma->cmd) * sizeof(s32);
7001be54c82SKrzysztof Helt 	*(dbri->cmdptr+1) = addr;
7011be54c82SKrzysztof Helt 	*(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0);
7021be54c82SKrzysztof Helt 
7031be54c82SKrzysztof Helt #ifdef DBRI_DEBUG
704ab93c7aeSKrzysztof Helt 	if (cmd > dbri->cmdptr) {
705ab93c7aeSKrzysztof Helt 		s32 *ptr;
706ab93c7aeSKrzysztof Helt 
707aaad3653SKrzysztof Helt 		for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++)
708098ccbc5SKrzysztof Helt 			dprintk(D_CMD, "cmd: %lx:%08x\n",
709098ccbc5SKrzysztof Helt 				(unsigned long)ptr, *ptr);
710ab93c7aeSKrzysztof Helt 	} else {
711ab93c7aeSKrzysztof Helt 		s32 *ptr = dbri->cmdptr;
712ab93c7aeSKrzysztof Helt 
7131be54c82SKrzysztof Helt 		dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
714ab93c7aeSKrzysztof Helt 		ptr++;
7151be54c82SKrzysztof Helt 		dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
716098ccbc5SKrzysztof Helt 		for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++)
717098ccbc5SKrzysztof Helt 			dprintk(D_CMD, "cmd: %lx:%08x\n",
718098ccbc5SKrzysztof Helt 				(unsigned long)ptr, *ptr);
7191be54c82SKrzysztof Helt 	}
7201be54c82SKrzysztof Helt #endif
7211bd9debfSTakashi Iwai 
7221be54c82SKrzysztof Helt 	/* Reread the last command */
7231be54c82SKrzysztof Helt 	tmp = sbus_readl(dbri->regs + REG0);
7241be54c82SKrzysztof Helt 	tmp |= D_P;
7251be54c82SKrzysztof Helt 	sbus_writel(tmp, dbri->regs + REG0);
7264338829eSMartin Habets 
7271be54c82SKrzysztof Helt 	dbri->cmdptr = cmd;
7281be54c82SKrzysztof Helt 	spin_unlock(&dbri->cmdlock);
7291bd9debfSTakashi Iwai }
7301bd9debfSTakashi Iwai 
7311bd9debfSTakashi Iwai /* Lock must be held when calling this */
dbri_reset(struct snd_dbri * dbri)732475675d6STakashi Iwai static void dbri_reset(struct snd_dbri *dbri)
7331bd9debfSTakashi Iwai {
7341bd9debfSTakashi Iwai 	int i;
735d1fdf07eSKrzysztof Helt 	u32 tmp;
7361bd9debfSTakashi Iwai 
7371bd9debfSTakashi Iwai 	dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n",
7381bd9debfSTakashi Iwai 		sbus_readl(dbri->regs + REG0),
7391bd9debfSTakashi Iwai 		sbus_readl(dbri->regs + REG2),
7401bd9debfSTakashi Iwai 		sbus_readl(dbri->regs + REG8), sbus_readl(dbri->regs + REG9));
7411bd9debfSTakashi Iwai 
7421bd9debfSTakashi Iwai 	sbus_writel(D_R, dbri->regs + REG0);	/* Soft Reset */
7431bd9debfSTakashi Iwai 	for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++)
7441bd9debfSTakashi Iwai 		udelay(10);
745d1fdf07eSKrzysztof Helt 
746d1fdf07eSKrzysztof Helt 	/* A brute approach - DBRI falls back to working burst size by itself
747d1fdf07eSKrzysztof Helt 	 * On SS20 D_S does not work, so do not try so high. */
748d1fdf07eSKrzysztof Helt 	tmp = sbus_readl(dbri->regs + REG0);
749d1fdf07eSKrzysztof Helt 	tmp |= D_G | D_E;
750d1fdf07eSKrzysztof Helt 	tmp &= ~D_S;
751d1fdf07eSKrzysztof Helt 	sbus_writel(tmp, dbri->regs + REG0);
7521bd9debfSTakashi Iwai }
7531bd9debfSTakashi Iwai 
7541bd9debfSTakashi Iwai /* Lock must not be held before calling this */
dbri_initialize(struct snd_dbri * dbri)75532e02a7bSBill Pemberton static void dbri_initialize(struct snd_dbri *dbri)
7561bd9debfSTakashi Iwai {
75716f46050STushar Dave 	u32 dvma_addr = (u32)dbri->dma_dvma;
7581be54c82SKrzysztof Helt 	s32 *cmd;
759d1fdf07eSKrzysztof Helt 	u32 dma_addr;
7601bd9debfSTakashi Iwai 	unsigned long flags;
7611bd9debfSTakashi Iwai 	int n;
7621bd9debfSTakashi Iwai 
7631bd9debfSTakashi Iwai 	spin_lock_irqsave(&dbri->lock, flags);
7641bd9debfSTakashi Iwai 
7651bd9debfSTakashi Iwai 	dbri_reset(dbri);
7661bd9debfSTakashi Iwai 
7671bd9debfSTakashi Iwai 	/* Initialize pipes */
7681bd9debfSTakashi Iwai 	for (n = 0; n < DBRI_NO_PIPES; n++)
7691bd9debfSTakashi Iwai 		dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;
7701bd9debfSTakashi Iwai 
7711be54c82SKrzysztof Helt 	spin_lock_init(&dbri->cmdlock);
7721bd9debfSTakashi Iwai 	/*
7736fb98280SKrzysztof Helt 	 * Initialize the interrupt ring buffer.
7741bd9debfSTakashi Iwai 	 */
77516f46050STushar Dave 	dma_addr = dvma_addr + dbri_dma_off(intr, 0);
7766fb98280SKrzysztof Helt 	dbri->dma->intr[0] = dma_addr;
7776fb98280SKrzysztof Helt 	dbri->dbri_irqp = 1;
7786fb98280SKrzysztof Helt 	/*
7796fb98280SKrzysztof Helt 	 * Set up the interrupt queue
7806fb98280SKrzysztof Helt 	 */
7811be54c82SKrzysztof Helt 	spin_lock(&dbri->cmdlock);
7821be54c82SKrzysztof Helt 	cmd = dbri->cmdptr = dbri->dma->cmd;
7831bd9debfSTakashi Iwai 	*(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
7841bd9debfSTakashi Iwai 	*(cmd++) = dma_addr;
7851be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
7861be54c82SKrzysztof Helt 	dbri->cmdptr = cmd;
7871be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
7881be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
78916f46050STushar Dave 	dma_addr = dvma_addr + dbri_dma_off(cmd, 0);
7901be54c82SKrzysztof Helt 	sbus_writel(dma_addr, dbri->regs + REG8);
7911be54c82SKrzysztof Helt 	spin_unlock(&dbri->cmdlock);
7921bd9debfSTakashi Iwai 
7931bd9debfSTakashi Iwai 	spin_unlock_irqrestore(&dbri->lock, flags);
794ea543f1eSKrzysztof Helt 	dbri_cmdwait(dbri);
7951bd9debfSTakashi Iwai }
7961bd9debfSTakashi Iwai 
7971bd9debfSTakashi Iwai /*
7981bd9debfSTakashi Iwai ****************************************************************************
7991bd9debfSTakashi Iwai ************************** DBRI data pipe management ***********************
8001bd9debfSTakashi Iwai ****************************************************************************
8011bd9debfSTakashi Iwai 
8021bd9debfSTakashi Iwai While DBRI control functions use the command and interrupt buffers, the
8031bd9debfSTakashi Iwai main data path takes the form of data pipes, which can be short (command
8041bd9debfSTakashi Iwai and interrupt driven), or long (attached to DMA buffers).  These functions
8051bd9debfSTakashi Iwai provide a rudimentary means of setting up and managing the DBRI's pipes,
8061bd9debfSTakashi Iwai but the calling functions have to make sure they respect the pipes' linked
8071bd9debfSTakashi Iwai list ordering, among other things.  The transmit and receive functions
8081bd9debfSTakashi Iwai here interface closely with the transmit and receive interrupt code.
8091bd9debfSTakashi Iwai 
8101bd9debfSTakashi Iwai */
pipe_active(struct snd_dbri * dbri,int pipe)811cf68d212SKrzysztof Helt static inline int pipe_active(struct snd_dbri *dbri, int pipe)
8121bd9debfSTakashi Iwai {
8131bd9debfSTakashi Iwai 	return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1));
8141bd9debfSTakashi Iwai }
8151bd9debfSTakashi Iwai 
8161bd9debfSTakashi Iwai /* reset_pipe(dbri, pipe)
8171bd9debfSTakashi Iwai  *
8181bd9debfSTakashi Iwai  * Called on an in-use pipe to clear anything being transmitted or received
8191bd9debfSTakashi Iwai  * Lock must be held before calling this.
8201bd9debfSTakashi Iwai  */
reset_pipe(struct snd_dbri * dbri,int pipe)821475675d6STakashi Iwai static void reset_pipe(struct snd_dbri *dbri, int pipe)
8221bd9debfSTakashi Iwai {
8231bd9debfSTakashi Iwai 	int sdp;
8241bd9debfSTakashi Iwai 	int desc;
8251be54c82SKrzysztof Helt 	s32 *cmd;
8261bd9debfSTakashi Iwai 
827470f1f1aSKrzysztof Helt 	if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
828098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: reset_pipe called with "
829098ccbc5SKrzysztof Helt 			"illegal pipe number\n");
8301bd9debfSTakashi Iwai 		return;
8311bd9debfSTakashi Iwai 	}
8321bd9debfSTakashi Iwai 
8331bd9debfSTakashi Iwai 	sdp = dbri->pipes[pipe].sdp;
8341bd9debfSTakashi Iwai 	if (sdp == 0) {
835098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: reset_pipe called "
836098ccbc5SKrzysztof Helt 			"on uninitialized pipe\n");
8371bd9debfSTakashi Iwai 		return;
8381bd9debfSTakashi Iwai 	}
8391bd9debfSTakashi Iwai 
8401be54c82SKrzysztof Helt 	cmd = dbri_cmdlock(dbri, 3);
8411bd9debfSTakashi Iwai 	*(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
8421bd9debfSTakashi Iwai 	*(cmd++) = 0;
8431be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
8441be54c82SKrzysztof Helt 	dbri_cmdsend(dbri, cmd, 3);
8451bd9debfSTakashi Iwai 
8461bd9debfSTakashi Iwai 	desc = dbri->pipes[pipe].first_desc;
8471be54c82SKrzysztof Helt 	if (desc >= 0)
8481be54c82SKrzysztof Helt 		do {
849098ccbc5SKrzysztof Helt 			dbri->dma->desc[desc].ba = 0;
850098ccbc5SKrzysztof Helt 			dbri->dma->desc[desc].nda = 0;
851c2735446SKrzysztof Helt 			desc = dbri->next_desc[desc];
8521be54c82SKrzysztof Helt 		} while (desc != -1 && desc != dbri->pipes[pipe].first_desc);
8531bd9debfSTakashi Iwai 
8541bd9debfSTakashi Iwai 	dbri->pipes[pipe].desc = -1;
8551bd9debfSTakashi Iwai 	dbri->pipes[pipe].first_desc = -1;
8561bd9debfSTakashi Iwai }
8571bd9debfSTakashi Iwai 
858ea543f1eSKrzysztof Helt /*
859ea543f1eSKrzysztof Helt  * Lock must be held before calling this.
860ea543f1eSKrzysztof Helt  */
setup_pipe(struct snd_dbri * dbri,int pipe,int sdp)861475675d6STakashi Iwai static void setup_pipe(struct snd_dbri *dbri, int pipe, int sdp)
8621bd9debfSTakashi Iwai {
863470f1f1aSKrzysztof Helt 	if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
864098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: setup_pipe called "
865098ccbc5SKrzysztof Helt 			"with illegal pipe number\n");
8661bd9debfSTakashi Iwai 		return;
8671bd9debfSTakashi Iwai 	}
8681bd9debfSTakashi Iwai 
8691bd9debfSTakashi Iwai 	if ((sdp & 0xf800) != sdp) {
870098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: setup_pipe called "
871098ccbc5SKrzysztof Helt 			"with strange SDP value\n");
8721bd9debfSTakashi Iwai 		/* sdp &= 0xf800; */
8731bd9debfSTakashi Iwai 	}
8741bd9debfSTakashi Iwai 
8751bd9debfSTakashi Iwai 	/* If this is a fixed receive pipe, arrange for an interrupt
8761bd9debfSTakashi Iwai 	 * every time its data changes
8771bd9debfSTakashi Iwai 	 */
8781bd9debfSTakashi Iwai 	if (D_SDP_MODE(sdp) == D_SDP_FIXED && !(sdp & D_SDP_TO_SER))
8791bd9debfSTakashi Iwai 		sdp |= D_SDP_CHANGE;
8801bd9debfSTakashi Iwai 
8811bd9debfSTakashi Iwai 	sdp |= D_PIPE(pipe);
8821bd9debfSTakashi Iwai 	dbri->pipes[pipe].sdp = sdp;
8831bd9debfSTakashi Iwai 	dbri->pipes[pipe].desc = -1;
8841bd9debfSTakashi Iwai 	dbri->pipes[pipe].first_desc = -1;
8851bd9debfSTakashi Iwai 
8861bd9debfSTakashi Iwai 	reset_pipe(dbri, pipe);
8871bd9debfSTakashi Iwai }
8881bd9debfSTakashi Iwai 
889ea543f1eSKrzysztof Helt /*
890ea543f1eSKrzysztof Helt  * Lock must be held before calling this.
891ea543f1eSKrzysztof Helt  */
link_time_slot(struct snd_dbri * dbri,int pipe,int prevpipe,int nextpipe,int length,int cycle)892475675d6STakashi Iwai static void link_time_slot(struct snd_dbri *dbri, int pipe,
893294a30dcSKrzysztof Helt 			   int prevpipe, int nextpipe,
8941bd9debfSTakashi Iwai 			   int length, int cycle)
8951bd9debfSTakashi Iwai {
8961be54c82SKrzysztof Helt 	s32 *cmd;
8971bd9debfSTakashi Iwai 	int val;
8981bd9debfSTakashi Iwai 
899294a30dcSKrzysztof Helt 	if (pipe < 0 || pipe > DBRI_MAX_PIPE
900294a30dcSKrzysztof Helt 			|| prevpipe < 0 || prevpipe > DBRI_MAX_PIPE
901294a30dcSKrzysztof Helt 			|| nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {
9024338829eSMartin Habets 		printk(KERN_ERR
9034338829eSMartin Habets 		    "DBRI: link_time_slot called with illegal pipe number\n");
9041bd9debfSTakashi Iwai 		return;
9051bd9debfSTakashi Iwai 	}
9061bd9debfSTakashi Iwai 
907294a30dcSKrzysztof Helt 	if (dbri->pipes[pipe].sdp == 0
908294a30dcSKrzysztof Helt 			|| dbri->pipes[prevpipe].sdp == 0
909294a30dcSKrzysztof Helt 			|| dbri->pipes[nextpipe].sdp == 0) {
910098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: link_time_slot called "
911098ccbc5SKrzysztof Helt 			"on uninitialized pipe\n");
9121bd9debfSTakashi Iwai 		return;
9131bd9debfSTakashi Iwai 	}
9141bd9debfSTakashi Iwai 
915294a30dcSKrzysztof Helt 	dbri->pipes[prevpipe].nextpipe = pipe;
916294a30dcSKrzysztof Helt 	dbri->pipes[pipe].nextpipe = nextpipe;
917294a30dcSKrzysztof Helt 	dbri->pipes[pipe].length = length;
918294a30dcSKrzysztof Helt 
9191be54c82SKrzysztof Helt 	cmd = dbri_cmdlock(dbri, 4);
920294a30dcSKrzysztof Helt 
921294a30dcSKrzysztof Helt 	if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
9221bd9debfSTakashi Iwai 		/* Deal with CHI special case:
9231bd9debfSTakashi Iwai 		 * "If transmission on edges 0 or 1 is desired, then cycle n
9241bd9debfSTakashi Iwai 		 *  (where n = # of bit times per frame...) must be used."
9251bd9debfSTakashi Iwai 		 *                  - DBRI data sheet, page 11
9261bd9debfSTakashi Iwai 		 */
927294a30dcSKrzysztof Helt 		if (prevpipe == 16 && cycle == 0)
9281bd9debfSTakashi Iwai 			cycle = dbri->chi_bpf;
9291bd9debfSTakashi Iwai 
9301bd9debfSTakashi Iwai 		val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
9311bd9debfSTakashi Iwai 		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
9321bd9debfSTakashi Iwai 		*(cmd++) = 0;
9331bd9debfSTakashi Iwai 		*(cmd++) =
9341bd9debfSTakashi Iwai 		    D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
935294a30dcSKrzysztof Helt 	} else {
936294a30dcSKrzysztof Helt 		val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
937294a30dcSKrzysztof Helt 		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
938294a30dcSKrzysztof Helt 		*(cmd++) =
939294a30dcSKrzysztof Helt 		    D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
940294a30dcSKrzysztof Helt 		*(cmd++) = 0;
9411bd9debfSTakashi Iwai 	}
9421be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
9431bd9debfSTakashi Iwai 
9441be54c82SKrzysztof Helt 	dbri_cmdsend(dbri, cmd, 4);
9451bd9debfSTakashi Iwai }
9461bd9debfSTakashi Iwai 
947ea543f1eSKrzysztof Helt #if 0
948ea543f1eSKrzysztof Helt /*
949ea543f1eSKrzysztof Helt  * Lock must be held before calling this.
950ea543f1eSKrzysztof Helt  */
951475675d6STakashi Iwai static void unlink_time_slot(struct snd_dbri *dbri, int pipe,
9521bd9debfSTakashi Iwai 			     enum in_or_out direction, int prevpipe,
9531bd9debfSTakashi Iwai 			     int nextpipe)
9541bd9debfSTakashi Iwai {
9551be54c82SKrzysztof Helt 	s32 *cmd;
9561bd9debfSTakashi Iwai 	int val;
9571bd9debfSTakashi Iwai 
958470f1f1aSKrzysztof Helt 	if (pipe < 0 || pipe > DBRI_MAX_PIPE
9591be54c82SKrzysztof Helt 			|| prevpipe < 0 || prevpipe > DBRI_MAX_PIPE
9601be54c82SKrzysztof Helt 			|| nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {
9614338829eSMartin Habets 		printk(KERN_ERR
9624338829eSMartin Habets 		    "DBRI: unlink_time_slot called with illegal pipe number\n");
9631bd9debfSTakashi Iwai 		return;
9641bd9debfSTakashi Iwai 	}
9651bd9debfSTakashi Iwai 
9661be54c82SKrzysztof Helt 	cmd = dbri_cmdlock(dbri, 4);
9671bd9debfSTakashi Iwai 
9681bd9debfSTakashi Iwai 	if (direction == PIPEinput) {
9691bd9debfSTakashi Iwai 		val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;
9701bd9debfSTakashi Iwai 		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
9711bd9debfSTakashi Iwai 		*(cmd++) = D_TS_NEXT(nextpipe);
9721bd9debfSTakashi Iwai 		*(cmd++) = 0;
9731bd9debfSTakashi Iwai 	} else {
9741bd9debfSTakashi Iwai 		val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe;
9751bd9debfSTakashi Iwai 		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
9761bd9debfSTakashi Iwai 		*(cmd++) = 0;
9771bd9debfSTakashi Iwai 		*(cmd++) = D_TS_NEXT(nextpipe);
9781bd9debfSTakashi Iwai 	}
9791be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
9801bd9debfSTakashi Iwai 
9811be54c82SKrzysztof Helt 	dbri_cmdsend(dbri, cmd, 4);
9821bd9debfSTakashi Iwai }
983ea543f1eSKrzysztof Helt #endif
9841bd9debfSTakashi Iwai 
9851bd9debfSTakashi Iwai /* xmit_fixed() / recv_fixed()
9861bd9debfSTakashi Iwai  *
9871bd9debfSTakashi Iwai  * Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not
9881bd9debfSTakashi Iwai  * expected to change much, and which we don't need to buffer.
9891bd9debfSTakashi Iwai  * The DBRI only interrupts us when the data changes (receive pipes),
9901bd9debfSTakashi Iwai  * or only changes the data when this function is called (transmit pipes).
9911bd9debfSTakashi Iwai  * Only short pipes (numbers 16-31) can be used in fixed data mode.
9921bd9debfSTakashi Iwai  *
9931bd9debfSTakashi Iwai  * These function operate on a 32-bit field, no matter how large
9941bd9debfSTakashi Iwai  * the actual time slot is.  The interrupt handler takes care of bit
9951bd9debfSTakashi Iwai  * ordering and alignment.  An 8-bit time slot will always end up
9961bd9debfSTakashi Iwai  * in the low-order 8 bits, filled either MSB-first or LSB-first,
997ea543f1eSKrzysztof Helt  * depending on the settings passed to setup_pipe().
998ea543f1eSKrzysztof Helt  *
999ea543f1eSKrzysztof Helt  * Lock must not be held before calling it.
10001bd9debfSTakashi Iwai  */
xmit_fixed(struct snd_dbri * dbri,int pipe,unsigned int data)1001475675d6STakashi Iwai static void xmit_fixed(struct snd_dbri *dbri, int pipe, unsigned int data)
10021bd9debfSTakashi Iwai {
10031be54c82SKrzysztof Helt 	s32 *cmd;
1004ea543f1eSKrzysztof Helt 	unsigned long flags;
10051bd9debfSTakashi Iwai 
1006470f1f1aSKrzysztof Helt 	if (pipe < 16 || pipe > DBRI_MAX_PIPE) {
10074338829eSMartin Habets 		printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n");
10081bd9debfSTakashi Iwai 		return;
10091bd9debfSTakashi Iwai 	}
10101bd9debfSTakashi Iwai 
10111bd9debfSTakashi Iwai 	if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) {
1012098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: xmit_fixed: "
1013098ccbc5SKrzysztof Helt 			"Uninitialized pipe %d\n", pipe);
10141bd9debfSTakashi Iwai 		return;
10151bd9debfSTakashi Iwai 	}
10161bd9debfSTakashi Iwai 
10171bd9debfSTakashi Iwai 	if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
10184338829eSMartin Habets 		printk(KERN_ERR "DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe);
10191bd9debfSTakashi Iwai 		return;
10201bd9debfSTakashi Iwai 	}
10211bd9debfSTakashi Iwai 
10221bd9debfSTakashi Iwai 	if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) {
1023098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n",
1024098ccbc5SKrzysztof Helt 			pipe);
10251bd9debfSTakashi Iwai 		return;
10261bd9debfSTakashi Iwai 	}
10271bd9debfSTakashi Iwai 
10281bd9debfSTakashi Iwai 	/* DBRI short pipes always transmit LSB first */
10291bd9debfSTakashi Iwai 
10301bd9debfSTakashi Iwai 	if (dbri->pipes[pipe].sdp & D_SDP_MSB)
10311bd9debfSTakashi Iwai 		data = reverse_bytes(data, dbri->pipes[pipe].length);
10321bd9debfSTakashi Iwai 
10331be54c82SKrzysztof Helt 	cmd = dbri_cmdlock(dbri, 3);
10341bd9debfSTakashi Iwai 
10351bd9debfSTakashi Iwai 	*(cmd++) = DBRI_CMD(D_SSP, 0, pipe);
10361bd9debfSTakashi Iwai 	*(cmd++) = data;
10371be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
10381bd9debfSTakashi Iwai 
1039ea543f1eSKrzysztof Helt 	spin_lock_irqsave(&dbri->lock, flags);
10401be54c82SKrzysztof Helt 	dbri_cmdsend(dbri, cmd, 3);
1041ea543f1eSKrzysztof Helt 	spin_unlock_irqrestore(&dbri->lock, flags);
10421be54c82SKrzysztof Helt 	dbri_cmdwait(dbri);
1043ea543f1eSKrzysztof Helt 
10441bd9debfSTakashi Iwai }
10451bd9debfSTakashi Iwai 
recv_fixed(struct snd_dbri * dbri,int pipe,volatile __u32 * ptr)1046475675d6STakashi Iwai static void recv_fixed(struct snd_dbri *dbri, int pipe, volatile __u32 *ptr)
10471bd9debfSTakashi Iwai {
1048470f1f1aSKrzysztof Helt 	if (pipe < 16 || pipe > DBRI_MAX_PIPE) {
1049098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: recv_fixed called with "
1050098ccbc5SKrzysztof Helt 			"illegal pipe number\n");
10511bd9debfSTakashi Iwai 		return;
10521bd9debfSTakashi Iwai 	}
10531bd9debfSTakashi Iwai 
10541bd9debfSTakashi Iwai 	if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
1055098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: recv_fixed called on "
1056098ccbc5SKrzysztof Helt 			"non-fixed pipe %d\n", pipe);
10571bd9debfSTakashi Iwai 		return;
10581bd9debfSTakashi Iwai 	}
10591bd9debfSTakashi Iwai 
10601bd9debfSTakashi Iwai 	if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
1061098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: recv_fixed called on "
1062098ccbc5SKrzysztof Helt 			"transmit pipe %d\n", pipe);
10631bd9debfSTakashi Iwai 		return;
10641bd9debfSTakashi Iwai 	}
10651bd9debfSTakashi Iwai 
10661bd9debfSTakashi Iwai 	dbri->pipes[pipe].recv_fixed_ptr = ptr;
10671bd9debfSTakashi Iwai }
10681bd9debfSTakashi Iwai 
10691bd9debfSTakashi Iwai /* setup_descs()
10701bd9debfSTakashi Iwai  *
10711bd9debfSTakashi Iwai  * Setup transmit/receive data on a "long" pipe - i.e, one associated
10721bd9debfSTakashi Iwai  * with a DMA buffer.
10731bd9debfSTakashi Iwai  *
10741bd9debfSTakashi Iwai  * Only pipe numbers 0-15 can be used in this mode.
10751bd9debfSTakashi Iwai  *
10761bd9debfSTakashi Iwai  * This function takes a stream number pointing to a data buffer,
10771bd9debfSTakashi Iwai  * and work by building chains of descriptors which identify the
10781bd9debfSTakashi Iwai  * data buffers.  Buffers too large for a single descriptor will
10791bd9debfSTakashi Iwai  * be spread across multiple descriptors.
10801be54c82SKrzysztof Helt  *
10811be54c82SKrzysztof Helt  * All descriptors create a ring buffer.
1082ea543f1eSKrzysztof Helt  *
1083ea543f1eSKrzysztof Helt  * Lock must be held before calling this.
10841bd9debfSTakashi Iwai  */
setup_descs(struct snd_dbri * dbri,int streamno,unsigned int period)1085475675d6STakashi Iwai static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period)
10861bd9debfSTakashi Iwai {
1087475675d6STakashi Iwai 	struct dbri_streaminfo *info = &dbri->stream_info[streamno];
108816f46050STushar Dave 	u32 dvma_addr = (u32)dbri->dma_dvma;
10891bd9debfSTakashi Iwai 	__u32 dvma_buffer;
109099dabfe7SKrzysztof Helt 	int desc;
10911bd9debfSTakashi Iwai 	int len;
10921bd9debfSTakashi Iwai 	int first_desc = -1;
10931bd9debfSTakashi Iwai 	int last_desc = -1;
10941bd9debfSTakashi Iwai 
10951bd9debfSTakashi Iwai 	if (info->pipe < 0 || info->pipe > 15) {
10964338829eSMartin Habets 		printk(KERN_ERR "DBRI: setup_descs: Illegal pipe number\n");
10971bd9debfSTakashi Iwai 		return -2;
10981bd9debfSTakashi Iwai 	}
10991bd9debfSTakashi Iwai 
11001bd9debfSTakashi Iwai 	if (dbri->pipes[info->pipe].sdp == 0) {
11014338829eSMartin Habets 		printk(KERN_ERR "DBRI: setup_descs: Uninitialized pipe %d\n",
11021bd9debfSTakashi Iwai 		       info->pipe);
11031bd9debfSTakashi Iwai 		return -2;
11041bd9debfSTakashi Iwai 	}
11051bd9debfSTakashi Iwai 
11061bd9debfSTakashi Iwai 	dvma_buffer = info->dvma_buffer;
11071bd9debfSTakashi Iwai 	len = info->size;
11081bd9debfSTakashi Iwai 
11091bd9debfSTakashi Iwai 	if (streamno == DBRI_PLAY) {
11101bd9debfSTakashi Iwai 		if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) {
1111098ccbc5SKrzysztof Helt 			printk(KERN_ERR "DBRI: setup_descs: "
1112098ccbc5SKrzysztof Helt 				"Called on receive pipe %d\n", info->pipe);
11131bd9debfSTakashi Iwai 			return -2;
11141bd9debfSTakashi Iwai 		}
11151bd9debfSTakashi Iwai 	} else {
11161bd9debfSTakashi Iwai 		if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) {
11174338829eSMartin Habets 			printk(KERN_ERR
11184338829eSMartin Habets 			    "DBRI: setup_descs: Called on transmit pipe %d\n",
11191bd9debfSTakashi Iwai 			     info->pipe);
11201bd9debfSTakashi Iwai 			return -2;
11211bd9debfSTakashi Iwai 		}
1122098ccbc5SKrzysztof Helt 		/* Should be able to queue multiple buffers
1123098ccbc5SKrzysztof Helt 		 * to receive on a pipe
1124098ccbc5SKrzysztof Helt 		 */
11251bd9debfSTakashi Iwai 		if (pipe_active(dbri, info->pipe)) {
1126098ccbc5SKrzysztof Helt 			printk(KERN_ERR "DBRI: recv_on_pipe: "
1127098ccbc5SKrzysztof Helt 				"Called on active pipe %d\n", info->pipe);
11281bd9debfSTakashi Iwai 			return -2;
11291bd9debfSTakashi Iwai 		}
11301bd9debfSTakashi Iwai 
11311bd9debfSTakashi Iwai 		/* Make sure buffer size is multiple of four */
11321bd9debfSTakashi Iwai 		len &= ~3;
11331bd9debfSTakashi Iwai 	}
11341bd9debfSTakashi Iwai 
113599dabfe7SKrzysztof Helt 	/* Free descriptors if pipe has any */
113699dabfe7SKrzysztof Helt 	desc = dbri->pipes[info->pipe].first_desc;
113799dabfe7SKrzysztof Helt 	if (desc >= 0)
113899dabfe7SKrzysztof Helt 		do {
1139098ccbc5SKrzysztof Helt 			dbri->dma->desc[desc].ba = 0;
1140098ccbc5SKrzysztof Helt 			dbri->dma->desc[desc].nda = 0;
114199dabfe7SKrzysztof Helt 			desc = dbri->next_desc[desc];
1142098ccbc5SKrzysztof Helt 		} while (desc != -1 &&
1143098ccbc5SKrzysztof Helt 			 desc != dbri->pipes[info->pipe].first_desc);
114499dabfe7SKrzysztof Helt 
114599dabfe7SKrzysztof Helt 	dbri->pipes[info->pipe].desc = -1;
114699dabfe7SKrzysztof Helt 	dbri->pipes[info->pipe].first_desc = -1;
114799dabfe7SKrzysztof Helt 
114899dabfe7SKrzysztof Helt 	desc = 0;
11491bd9debfSTakashi Iwai 	while (len > 0) {
11501bd9debfSTakashi Iwai 		int mylen;
11511bd9debfSTakashi Iwai 
11521bd9debfSTakashi Iwai 		for (; desc < DBRI_NO_DESCS; desc++) {
1153c2735446SKrzysztof Helt 			if (!dbri->dma->desc[desc].ba)
11541bd9debfSTakashi Iwai 				break;
11551bd9debfSTakashi Iwai 		}
1156cf68d212SKrzysztof Helt 
11571bd9debfSTakashi Iwai 		if (desc == DBRI_NO_DESCS) {
11584338829eSMartin Habets 			printk(KERN_ERR "DBRI: setup_descs: No descriptors\n");
11591bd9debfSTakashi Iwai 			return -1;
11601bd9debfSTakashi Iwai 		}
11611bd9debfSTakashi Iwai 
11621be54c82SKrzysztof Helt 		if (len > DBRI_TD_MAXCNT)
11631be54c82SKrzysztof Helt 			mylen = DBRI_TD_MAXCNT;	/* 8KB - 4 */
11641be54c82SKrzysztof Helt 		else
11651bd9debfSTakashi Iwai 			mylen = len;
11661be54c82SKrzysztof Helt 
11671be54c82SKrzysztof Helt 		if (mylen > period)
11681bd9debfSTakashi Iwai 			mylen = period;
11691bd9debfSTakashi Iwai 
1170c2735446SKrzysztof Helt 		dbri->next_desc[desc] = -1;
11711bd9debfSTakashi Iwai 		dbri->dma->desc[desc].ba = dvma_buffer;
11721bd9debfSTakashi Iwai 		dbri->dma->desc[desc].nda = 0;
11731bd9debfSTakashi Iwai 
11741bd9debfSTakashi Iwai 		if (streamno == DBRI_PLAY) {
11751bd9debfSTakashi Iwai 			dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen);
11761bd9debfSTakashi Iwai 			dbri->dma->desc[desc].word4 = 0;
1177098ccbc5SKrzysztof Helt 			dbri->dma->desc[desc].word1 |= DBRI_TD_F | DBRI_TD_B;
11781bd9debfSTakashi Iwai 		} else {
11791bd9debfSTakashi Iwai 			dbri->dma->desc[desc].word1 = 0;
11801bd9debfSTakashi Iwai 			dbri->dma->desc[desc].word4 =
11811bd9debfSTakashi Iwai 			    DBRI_RD_B | DBRI_RD_BCNT(mylen);
11821bd9debfSTakashi Iwai 		}
11831bd9debfSTakashi Iwai 
11841be54c82SKrzysztof Helt 		if (first_desc == -1)
11851bd9debfSTakashi Iwai 			first_desc = desc;
11861be54c82SKrzysztof Helt 		else {
1187c2735446SKrzysztof Helt 			dbri->next_desc[last_desc] = desc;
11881bd9debfSTakashi Iwai 			dbri->dma->desc[last_desc].nda =
118916f46050STushar Dave 			    dvma_addr + dbri_dma_off(desc, desc);
11901bd9debfSTakashi Iwai 		}
11911bd9debfSTakashi Iwai 
11921bd9debfSTakashi Iwai 		last_desc = desc;
11931bd9debfSTakashi Iwai 		dvma_buffer += mylen;
11941bd9debfSTakashi Iwai 		len -= mylen;
11951bd9debfSTakashi Iwai 	}
11961bd9debfSTakashi Iwai 
11971bd9debfSTakashi Iwai 	if (first_desc == -1 || last_desc == -1) {
1198098ccbc5SKrzysztof Helt 		printk(KERN_ERR "DBRI: setup_descs: "
1199098ccbc5SKrzysztof Helt 			" Not enough descriptors available\n");
12001bd9debfSTakashi Iwai 		return -1;
12011bd9debfSTakashi Iwai 	}
12021bd9debfSTakashi Iwai 
12031be54c82SKrzysztof Helt 	dbri->dma->desc[last_desc].nda =
120416f46050STushar Dave 	    dvma_addr + dbri_dma_off(desc, first_desc);
12051be54c82SKrzysztof Helt 	dbri->next_desc[last_desc] = first_desc;
12061bd9debfSTakashi Iwai 	dbri->pipes[info->pipe].first_desc = first_desc;
12071bd9debfSTakashi Iwai 	dbri->pipes[info->pipe].desc = first_desc;
12081bd9debfSTakashi Iwai 
12091be54c82SKrzysztof Helt #ifdef DBRI_DEBUG
12101be54c82SKrzysztof Helt 	for (desc = first_desc; desc != -1;) {
12111bd9debfSTakashi Iwai 		dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n",
12121bd9debfSTakashi Iwai 			desc,
12131bd9debfSTakashi Iwai 			dbri->dma->desc[desc].word1,
12141bd9debfSTakashi Iwai 			dbri->dma->desc[desc].ba,
12151bd9debfSTakashi Iwai 			dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4);
12161be54c82SKrzysztof Helt 			desc = dbri->next_desc[desc];
12171be54c82SKrzysztof Helt 			if (desc == first_desc)
12181be54c82SKrzysztof Helt 				break;
12191bd9debfSTakashi Iwai 	}
12201be54c82SKrzysztof Helt #endif
12211bd9debfSTakashi Iwai 	return 0;
12221bd9debfSTakashi Iwai }
12231bd9debfSTakashi Iwai 
12241bd9debfSTakashi Iwai /*
12251bd9debfSTakashi Iwai ****************************************************************************
12261bd9debfSTakashi Iwai ************************** DBRI - CHI interface ****************************
12271bd9debfSTakashi Iwai ****************************************************************************
12281bd9debfSTakashi Iwai 
12291bd9debfSTakashi Iwai The CHI is a four-wire (clock, frame sync, data in, data out) time-division
12301bd9debfSTakashi Iwai multiplexed serial interface which the DBRI can operate in either master
12311bd9debfSTakashi Iwai (give clock/frame sync) or slave (take clock/frame sync) mode.
12321bd9debfSTakashi Iwai 
12331bd9debfSTakashi Iwai */
12341bd9debfSTakashi Iwai 
12351bd9debfSTakashi Iwai enum master_or_slave { CHImaster, CHIslave };
12361bd9debfSTakashi Iwai 
1237ea543f1eSKrzysztof Helt /*
1238ea543f1eSKrzysztof Helt  * Lock must not be held before calling it.
1239ea543f1eSKrzysztof Helt  */
reset_chi(struct snd_dbri * dbri,enum master_or_slave master_or_slave,int bits_per_frame)1240098ccbc5SKrzysztof Helt static void reset_chi(struct snd_dbri *dbri,
1241098ccbc5SKrzysztof Helt 		      enum master_or_slave master_or_slave,
12421bd9debfSTakashi Iwai 		      int bits_per_frame)
12431bd9debfSTakashi Iwai {
12441be54c82SKrzysztof Helt 	s32 *cmd;
12451bd9debfSTakashi Iwai 	int val;
12461bd9debfSTakashi Iwai 
12471bd9debfSTakashi Iwai 	/* Set CHI Anchor: Pipe 16 */
12481bd9debfSTakashi Iwai 
12491be54c82SKrzysztof Helt 	cmd = dbri_cmdlock(dbri, 4);
1250470f1f1aSKrzysztof Helt 	val = D_DTS_VO | D_DTS_VI | D_DTS_INS
1251470f1f1aSKrzysztof Helt 		| D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16);
12521bd9debfSTakashi Iwai 	*(cmd++) = DBRI_CMD(D_DTS, 0, val);
12531bd9debfSTakashi Iwai 	*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
12541bd9debfSTakashi Iwai 	*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
12551be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
12561be54c82SKrzysztof Helt 	dbri_cmdsend(dbri, cmd, 4);
12571bd9debfSTakashi Iwai 
12581bd9debfSTakashi Iwai 	dbri->pipes[16].sdp = 1;
12591bd9debfSTakashi Iwai 	dbri->pipes[16].nextpipe = 16;
12601bd9debfSTakashi Iwai 
12611be54c82SKrzysztof Helt 	cmd = dbri_cmdlock(dbri, 4);
12621bd9debfSTakashi Iwai 
12631bd9debfSTakashi Iwai 	if (master_or_slave == CHIslave) {
12641bd9debfSTakashi Iwai 		/* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
12651bd9debfSTakashi Iwai 		 *
12661bd9debfSTakashi Iwai 		 * CHICM  = 0 (slave mode, 8 kHz frame rate)
12671bd9debfSTakashi Iwai 		 * IR     = give immediate CHI status interrupt
12681bd9debfSTakashi Iwai 		 * EN     = give CHI status interrupt upon change
12691bd9debfSTakashi Iwai 		 */
12701bd9debfSTakashi Iwai 		*(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));
12711bd9debfSTakashi Iwai 	} else {
12721bd9debfSTakashi Iwai 		/* Setup DBRI for CHI Master - generate clock, FS
12731bd9debfSTakashi Iwai 		 *
12741bd9debfSTakashi Iwai 		 * BPF				=  bits per 8 kHz frame
12751bd9debfSTakashi Iwai 		 * 12.288 MHz / CHICM_divisor	= clock rate
12761bd9debfSTakashi Iwai 		 * FD = 1 - drive CHIFS on rising edge of CHICK
12771bd9debfSTakashi Iwai 		 */
12781bd9debfSTakashi Iwai 		int clockrate = bits_per_frame * 8;
12791bd9debfSTakashi Iwai 		int divisor = 12288 / clockrate;
12801bd9debfSTakashi Iwai 
12811bd9debfSTakashi Iwai 		if (divisor > 255 || divisor * clockrate != 12288)
1282098ccbc5SKrzysztof Helt 			printk(KERN_ERR "DBRI: illegal bits_per_frame "
1283098ccbc5SKrzysztof Helt 				"in setup_chi\n");
12841bd9debfSTakashi Iwai 
12851bd9debfSTakashi Iwai 		*(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
12861bd9debfSTakashi Iwai 				    | D_CHI_BPF(bits_per_frame));
12871bd9debfSTakashi Iwai 	}
12881bd9debfSTakashi Iwai 
12891bd9debfSTakashi Iwai 	dbri->chi_bpf = bits_per_frame;
12901bd9debfSTakashi Iwai 
12911bd9debfSTakashi Iwai 	/* CHI Data Mode
12921bd9debfSTakashi Iwai 	 *
12931bd9debfSTakashi Iwai 	 * RCE   =  0 - receive on falling edge of CHICK
12941bd9debfSTakashi Iwai 	 * XCE   =  1 - transmit on rising edge of CHICK
12951bd9debfSTakashi Iwai 	 * XEN   =  1 - enable transmitter
12961bd9debfSTakashi Iwai 	 * REN   =  1 - enable receiver
12971bd9debfSTakashi Iwai 	 */
12981bd9debfSTakashi Iwai 
12991bd9debfSTakashi Iwai 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
13001bd9debfSTakashi Iwai 	*(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN);
13011be54c82SKrzysztof Helt 	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
13021bd9debfSTakashi Iwai 
13031be54c82SKrzysztof Helt 	dbri_cmdsend(dbri, cmd, 4);
13041bd9debfSTakashi Iwai }
13051bd9debfSTakashi Iwai 
13061bd9debfSTakashi Iwai /*
13071bd9debfSTakashi Iwai ****************************************************************************
13081bd9debfSTakashi Iwai *********************** CS4215 audio codec management **********************
13091bd9debfSTakashi Iwai ****************************************************************************
13101bd9debfSTakashi Iwai 
13111bd9debfSTakashi Iwai In the standard SPARC audio configuration, the CS4215 codec is attached
13121bd9debfSTakashi Iwai to the DBRI via the CHI interface and few of the DBRI's PIO pins.
13131bd9debfSTakashi Iwai 
1314ea543f1eSKrzysztof Helt  * Lock must not be held before calling it.
1315ea543f1eSKrzysztof Helt 
13161bd9debfSTakashi Iwai */
cs4215_setup_pipes(struct snd_dbri * dbri)131732e02a7bSBill Pemberton static void cs4215_setup_pipes(struct snd_dbri *dbri)
13181bd9debfSTakashi Iwai {
1319ea543f1eSKrzysztof Helt 	unsigned long flags;
1320ea543f1eSKrzysztof Helt 
1321ea543f1eSKrzysztof Helt 	spin_lock_irqsave(&dbri->lock, flags);
13221bd9debfSTakashi Iwai 	/*
13231bd9debfSTakashi Iwai 	 * Data mode:
13241bd9debfSTakashi Iwai 	 * Pipe  4: Send timeslots 1-4 (audio data)
13251bd9debfSTakashi Iwai 	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)
13261bd9debfSTakashi Iwai 	 * Pipe  6: Receive timeslots 1-4 (audio data)
13271bd9debfSTakashi Iwai 	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
13281bd9debfSTakashi Iwai 	 *          interrupt, and the rest of the data (slot 5 and 8) is
13291bd9debfSTakashi Iwai 	 *          not relevant for us (only for doublechecking).
13301bd9debfSTakashi Iwai 	 *
13311bd9debfSTakashi Iwai 	 * Control mode:
13321bd9debfSTakashi Iwai 	 * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only)
13331bd9debfSTakashi Iwai 	 * Pipe 18: Receive timeslot 1 (clb).
13341bd9debfSTakashi Iwai 	 * Pipe 19: Receive timeslot 7 (version).
13351bd9debfSTakashi Iwai 	 */
13361bd9debfSTakashi Iwai 
13371bd9debfSTakashi Iwai 	setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB);
13381bd9debfSTakashi Iwai 	setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
13391bd9debfSTakashi Iwai 	setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB);
13401bd9debfSTakashi Iwai 	setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
13411bd9debfSTakashi Iwai 
13421bd9debfSTakashi Iwai 	setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
13431bd9debfSTakashi Iwai 	setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
13441bd9debfSTakashi Iwai 	setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
1345ea543f1eSKrzysztof Helt 	spin_unlock_irqrestore(&dbri->lock, flags);
13461be54c82SKrzysztof Helt 
13471be54c82SKrzysztof Helt 	dbri_cmdwait(dbri);
13481bd9debfSTakashi Iwai }
13491bd9debfSTakashi Iwai 
cs4215_init_data(struct cs4215 * mm)135032e02a7bSBill Pemberton static int cs4215_init_data(struct cs4215 *mm)
13511bd9debfSTakashi Iwai {
13521bd9debfSTakashi Iwai 	/*
13531bd9debfSTakashi Iwai 	 * No action, memory resetting only.
13541bd9debfSTakashi Iwai 	 *
13551bd9debfSTakashi Iwai 	 * Data Time Slot 5-8
13561bd9debfSTakashi Iwai 	 * Speaker,Line and Headphone enable. Gain set to the half.
13571bd9debfSTakashi Iwai 	 * Input is mike.
13581bd9debfSTakashi Iwai 	 */
13591bd9debfSTakashi Iwai 	mm->data[0] = CS4215_LO(0x20) | CS4215_HE | CS4215_LE;
13601bd9debfSTakashi Iwai 	mm->data[1] = CS4215_RO(0x20) | CS4215_SE;
13611bd9debfSTakashi Iwai 	mm->data[2] = CS4215_LG(0x8) | CS4215_IS | CS4215_PIO0 | CS4215_PIO1;
13621bd9debfSTakashi Iwai 	mm->data[3] = CS4215_RG(0x8) | CS4215_MA(0xf);
13631bd9debfSTakashi Iwai 
13641bd9debfSTakashi Iwai 	/*
13651bd9debfSTakashi Iwai 	 * Control Time Slot 1-4
13661bd9debfSTakashi Iwai 	 * 0: Default I/O voltage scale
13671bd9debfSTakashi Iwai 	 * 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled
13681bd9debfSTakashi Iwai 	 * 2: Serial enable, CHI master, 128 bits per frame, clock 1
13691bd9debfSTakashi Iwai 	 * 3: Tests disabled
13701bd9debfSTakashi Iwai 	 */
13711bd9debfSTakashi Iwai 	mm->ctrl[0] = CS4215_RSRVD_1 | CS4215_MLB;
13721bd9debfSTakashi Iwai 	mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;
13731bd9debfSTakashi Iwai 	mm->ctrl[2] = CS4215_XCLK | CS4215_BSEL_128 | CS4215_FREQ[0].xtal;
13741bd9debfSTakashi Iwai 	mm->ctrl[3] = 0;
13751bd9debfSTakashi Iwai 
13761bd9debfSTakashi Iwai 	mm->status = 0;
13771bd9debfSTakashi Iwai 	mm->version = 0xff;
13781bd9debfSTakashi Iwai 	mm->precision = 8;	/* For ULAW */
13791be54c82SKrzysztof Helt 	mm->channels = 1;
13801bd9debfSTakashi Iwai 
13811bd9debfSTakashi Iwai 	return 0;
13821bd9debfSTakashi Iwai }
13831bd9debfSTakashi Iwai 
cs4215_setdata(struct snd_dbri * dbri,int muted)1384475675d6STakashi Iwai static void cs4215_setdata(struct snd_dbri *dbri, int muted)
13851bd9debfSTakashi Iwai {
13861bd9debfSTakashi Iwai 	if (muted) {
13871bd9debfSTakashi Iwai 		dbri->mm.data[0] |= 63;
13881bd9debfSTakashi Iwai 		dbri->mm.data[1] |= 63;
13891bd9debfSTakashi Iwai 		dbri->mm.data[2] &= ~15;
13901bd9debfSTakashi Iwai 		dbri->mm.data[3] &= ~15;
13911bd9debfSTakashi Iwai 	} else {
13921bd9debfSTakashi Iwai 		/* Start by setting the playback attenuation. */
1393475675d6STakashi Iwai 		struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY];
1394470f1f1aSKrzysztof Helt 		int left_gain = info->left_gain & 0x3f;
1395470f1f1aSKrzysztof Helt 		int right_gain = info->right_gain & 0x3f;
13961bd9debfSTakashi Iwai 
13971bd9debfSTakashi Iwai 		dbri->mm.data[0] &= ~0x3f;	/* Reset the volume bits */
13981bd9debfSTakashi Iwai 		dbri->mm.data[1] &= ~0x3f;
13991bd9debfSTakashi Iwai 		dbri->mm.data[0] |= (DBRI_MAX_VOLUME - left_gain);
14001bd9debfSTakashi Iwai 		dbri->mm.data[1] |= (DBRI_MAX_VOLUME - right_gain);
14011bd9debfSTakashi Iwai 
14021bd9debfSTakashi Iwai 		/* Now set the recording gain. */
14031bd9debfSTakashi Iwai 		info = &dbri->stream_info[DBRI_REC];
1404470f1f1aSKrzysztof Helt 		left_gain = info->left_gain & 0xf;
1405470f1f1aSKrzysztof Helt 		right_gain = info->right_gain & 0xf;
14061bd9debfSTakashi Iwai 		dbri->mm.data[2] |= CS4215_LG(left_gain);
14071bd9debfSTakashi Iwai 		dbri->mm.data[3] |= CS4215_RG(right_gain);
14081bd9debfSTakashi Iwai 	}
14091bd9debfSTakashi Iwai 
14101bd9debfSTakashi Iwai 	xmit_fixed(dbri, 20, *(int *)dbri->mm.data);
14111bd9debfSTakashi Iwai }
14121bd9debfSTakashi Iwai 
14131bd9debfSTakashi Iwai /*
14141bd9debfSTakashi Iwai  * Set the CS4215 to data mode.
14151bd9debfSTakashi Iwai  */
cs4215_open(struct snd_dbri * dbri)1416475675d6STakashi Iwai static void cs4215_open(struct snd_dbri *dbri)
14171bd9debfSTakashi Iwai {
14181bd9debfSTakashi Iwai 	int data_width;
14191bd9debfSTakashi Iwai 	u32 tmp;
1420ea543f1eSKrzysztof Helt 	unsigned long flags;
14211bd9debfSTakashi Iwai 
14221bd9debfSTakashi Iwai 	dprintk(D_MM, "cs4215_open: %d channels, %d bits\n",
14231bd9debfSTakashi Iwai 		dbri->mm.channels, dbri->mm.precision);
14241bd9debfSTakashi Iwai 
14251bd9debfSTakashi Iwai 	/* Temporarily mute outputs, and wait 1/8000 sec (125 us)
14261bd9debfSTakashi Iwai 	 * to make sure this takes.  This avoids clicking noises.
14271bd9debfSTakashi Iwai 	 */
14281bd9debfSTakashi Iwai 
14291bd9debfSTakashi Iwai 	cs4215_setdata(dbri, 1);
14301bd9debfSTakashi Iwai 	udelay(125);
14311bd9debfSTakashi Iwai 
14321bd9debfSTakashi Iwai 	/*
14331bd9debfSTakashi Iwai 	 * Data mode:
14341bd9debfSTakashi Iwai 	 * Pipe  4: Send timeslots 1-4 (audio data)
14351bd9debfSTakashi Iwai 	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)
14361bd9debfSTakashi Iwai 	 * Pipe  6: Receive timeslots 1-4 (audio data)
14371bd9debfSTakashi Iwai 	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
14381bd9debfSTakashi Iwai 	 *          interrupt, and the rest of the data (slot 5 and 8) is
14391bd9debfSTakashi Iwai 	 *          not relevant for us (only for doublechecking).
14401bd9debfSTakashi Iwai 	 *
14411bd9debfSTakashi Iwai 	 * Just like in control mode, the time slots are all offset by eight
14421bd9debfSTakashi Iwai 	 * bits.  The CS4215, it seems, observes TSIN (the delayed signal)
14431bd9debfSTakashi Iwai 	 * even if it's the CHI master.  Don't ask me...
14441bd9debfSTakashi Iwai 	 */
1445ea543f1eSKrzysztof Helt 	spin_lock_irqsave(&dbri->lock, flags);
14461bd9debfSTakashi Iwai 	tmp = sbus_readl(dbri->regs + REG0);
14471bd9debfSTakashi Iwai 	tmp &= ~(D_C);		/* Disable CHI */
14481bd9debfSTakashi Iwai 	sbus_writel(tmp, dbri->regs + REG0);
14491bd9debfSTakashi Iwai 
14501bd9debfSTakashi Iwai 	/* Switch CS4215 to data mode - set PIO3 to 1 */
14511bd9debfSTakashi Iwai 	sbus_writel(D_ENPIO | D_PIO1 | D_PIO3 |
14521bd9debfSTakashi Iwai 		    (dbri->mm.onboard ? D_PIO0 : D_PIO2), dbri->regs + REG2);
14531bd9debfSTakashi Iwai 
14541bd9debfSTakashi Iwai 	reset_chi(dbri, CHIslave, 128);
14551bd9debfSTakashi Iwai 
14561bd9debfSTakashi Iwai 	/* Note: this next doesn't work for 8-bit stereo, because the two
14571bd9debfSTakashi Iwai 	 * channels would be on timeslots 1 and 3, with 2 and 4 idle.
14581bd9debfSTakashi Iwai 	 * (See CS4215 datasheet Fig 15)
14591bd9debfSTakashi Iwai 	 *
14601bd9debfSTakashi Iwai 	 * DBRI non-contiguous mode would be required to make this work.
14611bd9debfSTakashi Iwai 	 */
14621bd9debfSTakashi Iwai 	data_width = dbri->mm.channels * dbri->mm.precision;
14631bd9debfSTakashi Iwai 
1464294a30dcSKrzysztof Helt 	link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset);
1465294a30dcSKrzysztof Helt 	link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32);
1466294a30dcSKrzysztof Helt 	link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset);
1467294a30dcSKrzysztof Helt 	link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40);
14681bd9debfSTakashi Iwai 
14691bd9debfSTakashi Iwai 	/* FIXME: enable CHI after _setdata? */
14701bd9debfSTakashi Iwai 	tmp = sbus_readl(dbri->regs + REG0);
14711bd9debfSTakashi Iwai 	tmp |= D_C;		/* Enable CHI */
14721bd9debfSTakashi Iwai 	sbus_writel(tmp, dbri->regs + REG0);
1473ea543f1eSKrzysztof Helt 	spin_unlock_irqrestore(&dbri->lock, flags);
14741bd9debfSTakashi Iwai 
14751bd9debfSTakashi Iwai 	cs4215_setdata(dbri, 0);
14761bd9debfSTakashi Iwai }
14771bd9debfSTakashi Iwai 
14781bd9debfSTakashi Iwai /*
14791bd9debfSTakashi Iwai  * Send the control information (i.e. audio format)
14801bd9debfSTakashi Iwai  */
cs4215_setctrl(struct snd_dbri * dbri)1481475675d6STakashi Iwai static int cs4215_setctrl(struct snd_dbri *dbri)
14821bd9debfSTakashi Iwai {
14831bd9debfSTakashi Iwai 	int i, val;
14841bd9debfSTakashi Iwai 	u32 tmp;
1485ea543f1eSKrzysztof Helt 	unsigned long flags;
14861bd9debfSTakashi Iwai 
14871bd9debfSTakashi Iwai 	/* FIXME - let the CPU do something useful during these delays */
14881bd9debfSTakashi Iwai 
14891bd9debfSTakashi Iwai 	/* Temporarily mute outputs, and wait 1/8000 sec (125 us)
14901bd9debfSTakashi Iwai 	 * to make sure this takes.  This avoids clicking noises.
14911bd9debfSTakashi Iwai 	 */
14921bd9debfSTakashi Iwai 	cs4215_setdata(dbri, 1);
14931bd9debfSTakashi Iwai 	udelay(125);
14941bd9debfSTakashi Iwai 
14951bd9debfSTakashi Iwai 	/*
14961bd9debfSTakashi Iwai 	 * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
14971bd9debfSTakashi Iwai 	 * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec
14981bd9debfSTakashi Iwai 	 */
14991bd9debfSTakashi Iwai 	val = D_ENPIO | D_PIO1 | (dbri->mm.onboard ? D_PIO0 : D_PIO2);
15001bd9debfSTakashi Iwai 	sbus_writel(val, dbri->regs + REG2);
15011bd9debfSTakashi Iwai 	dprintk(D_MM, "cs4215_setctrl: reg2=0x%x\n", val);
15021bd9debfSTakashi Iwai 	udelay(34);
15031bd9debfSTakashi Iwai 
15041bd9debfSTakashi Iwai 	/* In Control mode, the CS4215 is a slave device, so the DBRI must
15051bd9debfSTakashi Iwai 	 * operate as CHI master, supplying clocking and frame synchronization.
15061bd9debfSTakashi Iwai 	 *
15071bd9debfSTakashi Iwai 	 * In Data mode, however, the CS4215 must be CHI master to insure
15081bd9debfSTakashi Iwai 	 * that its data stream is synchronous with its codec.
15091bd9debfSTakashi Iwai 	 *
15101bd9debfSTakashi Iwai 	 * The upshot of all this?  We start by putting the DBRI into master
15111bd9debfSTakashi Iwai 	 * mode, program the CS4215 in Control mode, then switch the CS4215
15121bd9debfSTakashi Iwai 	 * into Data mode and put the DBRI into slave mode.  Various timing
15131bd9debfSTakashi Iwai 	 * requirements must be observed along the way.
15141bd9debfSTakashi Iwai 	 *
15151bd9debfSTakashi Iwai 	 * Oh, and one more thing, on a SPARCStation 20 (and maybe
15161bd9debfSTakashi Iwai 	 * others?), the addressing of the CS4215's time slots is
15171bd9debfSTakashi Iwai 	 * offset by eight bits, so we add eight to all the "cycle"
15181bd9debfSTakashi Iwai 	 * values in the Define Time Slot (DTS) commands.  This is
15191bd9debfSTakashi Iwai 	 * done in hardware by a TI 248 that delays the DBRI->4215
15201bd9debfSTakashi Iwai 	 * frame sync signal by eight clock cycles.  Anybody know why?
15211bd9debfSTakashi Iwai 	 */
1522ea543f1eSKrzysztof Helt 	spin_lock_irqsave(&dbri->lock, flags);
15231bd9debfSTakashi Iwai 	tmp = sbus_readl(dbri->regs + REG0);
15241bd9debfSTakashi Iwai 	tmp &= ~D_C;		/* Disable CHI */
15251bd9debfSTakashi Iwai 	sbus_writel(tmp, dbri->regs + REG0);
15261bd9debfSTakashi Iwai 
15271bd9debfSTakashi Iwai 	reset_chi(dbri, CHImaster, 128);
15281bd9debfSTakashi Iwai 
15291bd9debfSTakashi Iwai 	/*
15301bd9debfSTakashi Iwai 	 * Control mode:
15311bd9debfSTakashi Iwai 	 * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only)
15321bd9debfSTakashi Iwai 	 * Pipe 18: Receive timeslot 1 (clb).
15331bd9debfSTakashi Iwai 	 * Pipe 19: Receive timeslot 7 (version).
15341bd9debfSTakashi Iwai 	 */
15351bd9debfSTakashi Iwai 
1536294a30dcSKrzysztof Helt 	link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset);
1537294a30dcSKrzysztof Helt 	link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset);
1538294a30dcSKrzysztof Helt 	link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48);
1539ea543f1eSKrzysztof Helt 	spin_unlock_irqrestore(&dbri->lock, flags);
15401bd9debfSTakashi Iwai 
15411bd9debfSTakashi Iwai 	/* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
15421bd9debfSTakashi Iwai 	dbri->mm.ctrl[0] &= ~CS4215_CLB;
15431bd9debfSTakashi Iwai 	xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
15441bd9debfSTakashi Iwai 
1545ea543f1eSKrzysztof Helt 	spin_lock_irqsave(&dbri->lock, flags);
15461bd9debfSTakashi Iwai 	tmp = sbus_readl(dbri->regs + REG0);
15471bd9debfSTakashi Iwai 	tmp |= D_C;		/* Enable CHI */
15481bd9debfSTakashi Iwai 	sbus_writel(tmp, dbri->regs + REG0);
1549ea543f1eSKrzysztof Helt 	spin_unlock_irqrestore(&dbri->lock, flags);
15501bd9debfSTakashi Iwai 
1551098ccbc5SKrzysztof Helt 	for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i)
15524338829eSMartin Habets 		msleep_interruptible(1);
1553098ccbc5SKrzysztof Helt 
15541bd9debfSTakashi Iwai 	if (i == 0) {
15551bd9debfSTakashi Iwai 		dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n",
15561bd9debfSTakashi Iwai 			dbri->mm.status);
15571bd9debfSTakashi Iwai 		return -1;
15581bd9debfSTakashi Iwai 	}
15591bd9debfSTakashi Iwai 
15601bd9debfSTakashi Iwai 	/* Disable changes to our copy of the version number, as we are about
15611bd9debfSTakashi Iwai 	 * to leave control mode.
15621bd9debfSTakashi Iwai 	 */
15631bd9debfSTakashi Iwai 	recv_fixed(dbri, 19, NULL);
15641bd9debfSTakashi Iwai 
15651bd9debfSTakashi Iwai 	/* Terminate CS4215 control mode - data sheet says
15661bd9debfSTakashi Iwai 	 * "Set CLB=1 and send two more frames of valid control info"
15671bd9debfSTakashi Iwai 	 */
15681bd9debfSTakashi Iwai 	dbri->mm.ctrl[0] |= CS4215_CLB;
15691bd9debfSTakashi Iwai 	xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
15701bd9debfSTakashi Iwai 
15711bd9debfSTakashi Iwai 	/* Two frames of control info @ 8kHz frame rate = 250 us delay */
15721bd9debfSTakashi Iwai 	udelay(250);
15731bd9debfSTakashi Iwai 
15741bd9debfSTakashi Iwai 	cs4215_setdata(dbri, 0);
15751bd9debfSTakashi Iwai 
15761bd9debfSTakashi Iwai 	return 0;
15771bd9debfSTakashi Iwai }
15781bd9debfSTakashi Iwai 
15791bd9debfSTakashi Iwai /*
15801bd9debfSTakashi Iwai  * Setup the codec with the sampling rate, audio format and number of
15811bd9debfSTakashi Iwai  * channels.
15821bd9debfSTakashi Iwai  * As part of the process we resend the settings for the data
15831bd9debfSTakashi Iwai  * timeslots as well.
15841bd9debfSTakashi Iwai  */
cs4215_prepare(struct snd_dbri * dbri,unsigned int rate,snd_pcm_format_t format,unsigned int channels)1585475675d6STakashi Iwai static int cs4215_prepare(struct snd_dbri *dbri, unsigned int rate,
15861bd9debfSTakashi Iwai 			  snd_pcm_format_t format, unsigned int channels)
15871bd9debfSTakashi Iwai {
15881bd9debfSTakashi Iwai 	int freq_idx;
15891bd9debfSTakashi Iwai 	int ret = 0;
15901bd9debfSTakashi Iwai 
15911bd9debfSTakashi Iwai 	/* Lookup index for this rate */
15921bd9debfSTakashi Iwai 	for (freq_idx = 0; CS4215_FREQ[freq_idx].freq != 0; freq_idx++) {
15931bd9debfSTakashi Iwai 		if (CS4215_FREQ[freq_idx].freq == rate)
15941bd9debfSTakashi Iwai 			break;
15951bd9debfSTakashi Iwai 	}
15961bd9debfSTakashi Iwai 	if (CS4215_FREQ[freq_idx].freq != rate) {
15971bd9debfSTakashi Iwai 		printk(KERN_WARNING "DBRI: Unsupported rate %d Hz\n", rate);
15981bd9debfSTakashi Iwai 		return -1;
15991bd9debfSTakashi Iwai 	}
16001bd9debfSTakashi Iwai 
16011bd9debfSTakashi Iwai 	switch (format) {
16021bd9debfSTakashi Iwai 	case SNDRV_PCM_FORMAT_MU_LAW:
16031bd9debfSTakashi Iwai 		dbri->mm.ctrl[1] = CS4215_DFR_ULAW;
16041bd9debfSTakashi Iwai 		dbri->mm.precision = 8;
16051bd9debfSTakashi Iwai 		break;
16061bd9debfSTakashi Iwai 	case SNDRV_PCM_FORMAT_A_LAW:
16071bd9debfSTakashi Iwai 		dbri->mm.ctrl[1] = CS4215_DFR_ALAW;
16081bd9debfSTakashi Iwai 		dbri->mm.precision = 8;
16091bd9debfSTakashi Iwai 		break;
16101bd9debfSTakashi Iwai 	case SNDRV_PCM_FORMAT_U8:
16111bd9debfSTakashi Iwai 		dbri->mm.ctrl[1] = CS4215_DFR_LINEAR8;
16121bd9debfSTakashi Iwai 		dbri->mm.precision = 8;
16131bd9debfSTakashi Iwai 		break;
16141bd9debfSTakashi Iwai 	case SNDRV_PCM_FORMAT_S16_BE:
16151bd9debfSTakashi Iwai 		dbri->mm.ctrl[1] = CS4215_DFR_LINEAR16;
16161bd9debfSTakashi Iwai 		dbri->mm.precision = 16;
16171bd9debfSTakashi Iwai 		break;
16181bd9debfSTakashi Iwai 	default:
16191bd9debfSTakashi Iwai 		printk(KERN_WARNING "DBRI: Unsupported format %d\n", format);
16201bd9debfSTakashi Iwai 		return -1;
16211bd9debfSTakashi Iwai 	}
16221bd9debfSTakashi Iwai 
16231bd9debfSTakashi Iwai 	/* Add rate parameters */
16241bd9debfSTakashi Iwai 	dbri->mm.ctrl[1] |= CS4215_FREQ[freq_idx].csval;
16251bd9debfSTakashi Iwai 	dbri->mm.ctrl[2] = CS4215_XCLK |
16261bd9debfSTakashi Iwai 	    CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal;
16271bd9debfSTakashi Iwai 
16281bd9debfSTakashi Iwai 	dbri->mm.channels = channels;
1629ab93c7aeSKrzysztof Helt 	if (channels == 2)
16301bd9debfSTakashi Iwai 		dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;
16311bd9debfSTakashi Iwai 
16321bd9debfSTakashi Iwai 	ret = cs4215_setctrl(dbri);
16331bd9debfSTakashi Iwai 	if (ret == 0)
16341bd9debfSTakashi Iwai 		cs4215_open(dbri);	/* set codec to data mode */
16351bd9debfSTakashi Iwai 
16361bd9debfSTakashi Iwai 	return ret;
16371bd9debfSTakashi Iwai }
16381bd9debfSTakashi Iwai 
16391bd9debfSTakashi Iwai /*
16401bd9debfSTakashi Iwai  *
16411bd9debfSTakashi Iwai  */
cs4215_init(struct snd_dbri * dbri)164232e02a7bSBill Pemberton static int cs4215_init(struct snd_dbri *dbri)
16431bd9debfSTakashi Iwai {
16441bd9debfSTakashi Iwai 	u32 reg2 = sbus_readl(dbri->regs + REG2);
16451bd9debfSTakashi Iwai 	dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2);
16461bd9debfSTakashi Iwai 
16471bd9debfSTakashi Iwai 	/* Look for the cs4215 chips */
16481bd9debfSTakashi Iwai 	if (reg2 & D_PIO2) {
16491bd9debfSTakashi Iwai 		dprintk(D_MM, "Onboard CS4215 detected\n");
16501bd9debfSTakashi Iwai 		dbri->mm.onboard = 1;
16511bd9debfSTakashi Iwai 	}
16521bd9debfSTakashi Iwai 	if (reg2 & D_PIO0) {
16531bd9debfSTakashi Iwai 		dprintk(D_MM, "Speakerbox detected\n");
16541bd9debfSTakashi Iwai 		dbri->mm.onboard = 0;
16551bd9debfSTakashi Iwai 
16561bd9debfSTakashi Iwai 		if (reg2 & D_PIO2) {
16571bd9debfSTakashi Iwai 			printk(KERN_INFO "DBRI: Using speakerbox / "
16581bd9debfSTakashi Iwai 			       "ignoring onboard mmcodec.\n");
16591bd9debfSTakashi Iwai 			sbus_writel(D_ENPIO2, dbri->regs + REG2);
16601bd9debfSTakashi Iwai 		}
16611bd9debfSTakashi Iwai 	}
16621bd9debfSTakashi Iwai 
16631bd9debfSTakashi Iwai 	if (!(reg2 & (D_PIO0 | D_PIO2))) {
16641bd9debfSTakashi Iwai 		printk(KERN_ERR "DBRI: no mmcodec found.\n");
16651bd9debfSTakashi Iwai 		return -EIO;
16661bd9debfSTakashi Iwai 	}
16671bd9debfSTakashi Iwai 
16681bd9debfSTakashi Iwai 	cs4215_setup_pipes(dbri);
16691bd9debfSTakashi Iwai 	cs4215_init_data(&dbri->mm);
16701bd9debfSTakashi Iwai 
16711bd9debfSTakashi Iwai 	/* Enable capture of the status & version timeslots. */
16721bd9debfSTakashi Iwai 	recv_fixed(dbri, 18, &dbri->mm.status);
16731bd9debfSTakashi Iwai 	recv_fixed(dbri, 19, &dbri->mm.version);
16741bd9debfSTakashi Iwai 
16751bd9debfSTakashi Iwai 	dbri->mm.offset = dbri->mm.onboard ? 0 : 8;
16761bd9debfSTakashi Iwai 	if (cs4215_setctrl(dbri) == -1 || dbri->mm.version == 0xff) {
16771bd9debfSTakashi Iwai 		dprintk(D_MM, "CS4215 failed probe at offset %d\n",
16781bd9debfSTakashi Iwai 			dbri->mm.offset);
16791bd9debfSTakashi Iwai 		return -EIO;
16801bd9debfSTakashi Iwai 	}
16811bd9debfSTakashi Iwai 	dprintk(D_MM, "Found CS4215 at offset %d\n", dbri->mm.offset);
16821bd9debfSTakashi Iwai 
16831bd9debfSTakashi Iwai 	return 0;
16841bd9debfSTakashi Iwai }
16851bd9debfSTakashi Iwai 
16861bd9debfSTakashi Iwai /*
16871bd9debfSTakashi Iwai ****************************************************************************
16881bd9debfSTakashi Iwai *************************** DBRI interrupt handler *************************
16891bd9debfSTakashi Iwai ****************************************************************************
16901bd9debfSTakashi Iwai 
16911bd9debfSTakashi Iwai The DBRI communicates with the CPU mainly via a circular interrupt
16921bd9debfSTakashi Iwai buffer.  When an interrupt is signaled, the CPU walks through the
16931bd9debfSTakashi Iwai buffer and calls dbri_process_one_interrupt() for each interrupt word.
16941bd9debfSTakashi Iwai Complicated interrupts are handled by dedicated functions (which
16951bd9debfSTakashi Iwai appear first in this file).  Any pending interrupts can be serviced by
16961bd9debfSTakashi Iwai calling dbri_process_interrupt_buffer(), which works even if the CPU's
16971be54c82SKrzysztof Helt interrupts are disabled.
16981bd9debfSTakashi Iwai 
16991bd9debfSTakashi Iwai */
17001bd9debfSTakashi Iwai 
17011bd9debfSTakashi Iwai /* xmit_descs()
17021bd9debfSTakashi Iwai  *
1703098ccbc5SKrzysztof Helt  * Starts transmitting the current TD's for recording/playing.
17041bd9debfSTakashi Iwai  * For playback, ALSA has filled the DMA memory with new data (we hope).
17051bd9debfSTakashi Iwai  */
xmit_descs(struct snd_dbri * dbri)17061be54c82SKrzysztof Helt static void xmit_descs(struct snd_dbri *dbri)
17071bd9debfSTakashi Iwai {
1708475675d6STakashi Iwai 	struct dbri_streaminfo *info;
1709163117e8SDan Carpenter 	u32 dvma_addr;
17101be54c82SKrzysztof Helt 	s32 *cmd;
17111bd9debfSTakashi Iwai 	unsigned long flags;
17121bd9debfSTakashi Iwai 	int first_td;
17131bd9debfSTakashi Iwai 
17141bd9debfSTakashi Iwai 	if (dbri == NULL)
17151bd9debfSTakashi Iwai 		return;		/* Disabled */
17161bd9debfSTakashi Iwai 
1717163117e8SDan Carpenter 	dvma_addr = (u32)dbri->dma_dvma;
17181bd9debfSTakashi Iwai 	info = &dbri->stream_info[DBRI_REC];
17191bd9debfSTakashi Iwai 	spin_lock_irqsave(&dbri->lock, flags);
17201bd9debfSTakashi Iwai 
17211be54c82SKrzysztof Helt 	if (info->pipe >= 0) {
17221bd9debfSTakashi Iwai 		first_td = dbri->pipes[info->pipe].first_desc;
17231bd9debfSTakashi Iwai 
17241bd9debfSTakashi Iwai 		dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td);
17251bd9debfSTakashi Iwai 
17261bd9debfSTakashi Iwai 		/* Stream could be closed by the time we run. */
1727aaad3653SKrzysztof Helt 		if (first_td >= 0) {
17281be54c82SKrzysztof Helt 			cmd = dbri_cmdlock(dbri, 2);
17291bd9debfSTakashi Iwai 			*(cmd++) = DBRI_CMD(D_SDP, 0,
17301bd9debfSTakashi Iwai 					    dbri->pipes[info->pipe].sdp
17311bd9debfSTakashi Iwai 					    | D_SDP_P | D_SDP_EVERY | D_SDP_C);
173216f46050STushar Dave 			*(cmd++) = dvma_addr +
1733098ccbc5SKrzysztof Helt 				   dbri_dma_off(desc, first_td);
17341be54c82SKrzysztof Helt 			dbri_cmdsend(dbri, cmd, 2);
17351bd9debfSTakashi Iwai 
1736aaad3653SKrzysztof Helt 			/* Reset our admin of the pipe. */
17371bd9debfSTakashi Iwai 			dbri->pipes[info->pipe].desc = first_td;
17381bd9debfSTakashi Iwai 		}
1739aaad3653SKrzysztof Helt 	}
17401bd9debfSTakashi Iwai 
17411bd9debfSTakashi Iwai 	info = &dbri->stream_info[DBRI_PLAY];
17421bd9debfSTakashi Iwai 
17431be54c82SKrzysztof Helt 	if (info->pipe >= 0) {
17441bd9debfSTakashi Iwai 		first_td = dbri->pipes[info->pipe].first_desc;
17451bd9debfSTakashi Iwai 
17461bd9debfSTakashi Iwai 		dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td);
17471bd9debfSTakashi Iwai 
17481bd9debfSTakashi Iwai 		/* Stream could be closed by the time we run. */
17491be54c82SKrzysztof Helt 		if (first_td >= 0) {
17501be54c82SKrzysztof Helt 			cmd = dbri_cmdlock(dbri, 2);
17511bd9debfSTakashi Iwai 			*(cmd++) = DBRI_CMD(D_SDP, 0,
17521bd9debfSTakashi Iwai 					    dbri->pipes[info->pipe].sdp
17531bd9debfSTakashi Iwai 					    | D_SDP_P | D_SDP_EVERY | D_SDP_C);
175416f46050STushar Dave 			*(cmd++) = dvma_addr +
1755098ccbc5SKrzysztof Helt 				   dbri_dma_off(desc, first_td);
17561be54c82SKrzysztof Helt 			dbri_cmdsend(dbri, cmd, 2);
17571bd9debfSTakashi Iwai 
1758aaad3653SKrzysztof Helt 			/* Reset our admin of the pipe. */
17591bd9debfSTakashi Iwai 			dbri->pipes[info->pipe].desc = first_td;
17601be54c82SKrzysztof Helt 		}
17611bd9debfSTakashi Iwai 	}
1762ea543f1eSKrzysztof Helt 
17631bd9debfSTakashi Iwai 	spin_unlock_irqrestore(&dbri->lock, flags);
17641bd9debfSTakashi Iwai }
17651bd9debfSTakashi Iwai 
17661bd9debfSTakashi Iwai /* transmission_complete_intr()
17671bd9debfSTakashi Iwai  *
17681bd9debfSTakashi Iwai  * Called by main interrupt handler when DBRI signals transmission complete
17691bd9debfSTakashi Iwai  * on a pipe (interrupt triggered by the B bit in a transmit descriptor).
17701bd9debfSTakashi Iwai  *
17714338829eSMartin Habets  * Walks through the pipe's list of transmit buffer descriptors and marks
17724338829eSMartin Habets  * them as available. Stops when the first descriptor is found without
17731bd9debfSTakashi Iwai  * TBC (Transmit Buffer Complete) set, or we've run through them all.
17744338829eSMartin Habets  *
1775ab93c7aeSKrzysztof Helt  * The DMA buffers are not released. They form a ring buffer and
1776ab93c7aeSKrzysztof Helt  * they are filled by ALSA while others are transmitted by DMA.
1777ab93c7aeSKrzysztof Helt  *
17781bd9debfSTakashi Iwai  */
17791bd9debfSTakashi Iwai 
transmission_complete_intr(struct snd_dbri * dbri,int pipe)1780475675d6STakashi Iwai static void transmission_complete_intr(struct snd_dbri *dbri, int pipe)
17811bd9debfSTakashi Iwai {
1782cf68d212SKrzysztof Helt 	struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY];
1783cf68d212SKrzysztof Helt 	int td = dbri->pipes[pipe].desc;
17841bd9debfSTakashi Iwai 	int status;
17851bd9debfSTakashi Iwai 
17861bd9debfSTakashi Iwai 	while (td >= 0) {
17871bd9debfSTakashi Iwai 		if (td >= DBRI_NO_DESCS) {
17881bd9debfSTakashi Iwai 			printk(KERN_ERR "DBRI: invalid td on pipe %d\n", pipe);
17891bd9debfSTakashi Iwai 			return;
17901bd9debfSTakashi Iwai 		}
17911bd9debfSTakashi Iwai 
17921bd9debfSTakashi Iwai 		status = DBRI_TD_STATUS(dbri->dma->desc[td].word4);
1793098ccbc5SKrzysztof Helt 		if (!(status & DBRI_TD_TBC))
17941bd9debfSTakashi Iwai 			break;
17951bd9debfSTakashi Iwai 
17961bd9debfSTakashi Iwai 		dprintk(D_INT, "TD %d, status 0x%02x\n", td, status);
17971bd9debfSTakashi Iwai 
17981bd9debfSTakashi Iwai 		dbri->dma->desc[td].word4 = 0;	/* Reset it for next time. */
17991be54c82SKrzysztof Helt 		info->offset += DBRI_RD_CNT(dbri->dma->desc[td].word1);
18001bd9debfSTakashi Iwai 
1801c2735446SKrzysztof Helt 		td = dbri->next_desc[td];
18021bd9debfSTakashi Iwai 		dbri->pipes[pipe].desc = td;
18031bd9debfSTakashi Iwai 	}
18041bd9debfSTakashi Iwai 
18051bd9debfSTakashi Iwai 	/* Notify ALSA */
18061bd9debfSTakashi Iwai 	spin_unlock(&dbri->lock);
18071bd9debfSTakashi Iwai 	snd_pcm_period_elapsed(info->substream);
18081bd9debfSTakashi Iwai 	spin_lock(&dbri->lock);
18091bd9debfSTakashi Iwai }
18101bd9debfSTakashi Iwai 
reception_complete_intr(struct snd_dbri * dbri,int pipe)1811475675d6STakashi Iwai static void reception_complete_intr(struct snd_dbri *dbri, int pipe)
18121bd9debfSTakashi Iwai {
1813475675d6STakashi Iwai 	struct dbri_streaminfo *info;
18141bd9debfSTakashi Iwai 	int rd = dbri->pipes[pipe].desc;
18151bd9debfSTakashi Iwai 	s32 status;
18161bd9debfSTakashi Iwai 
18171bd9debfSTakashi Iwai 	if (rd < 0 || rd >= DBRI_NO_DESCS) {
18181bd9debfSTakashi Iwai 		printk(KERN_ERR "DBRI: invalid rd on pipe %d\n", pipe);
18191bd9debfSTakashi Iwai 		return;
18201bd9debfSTakashi Iwai 	}
18211bd9debfSTakashi Iwai 
1822c2735446SKrzysztof Helt 	dbri->pipes[pipe].desc = dbri->next_desc[rd];
18231bd9debfSTakashi Iwai 	status = dbri->dma->desc[rd].word1;
18241bd9debfSTakashi Iwai 	dbri->dma->desc[rd].word1 = 0;	/* Reset it for next time. */
18251bd9debfSTakashi Iwai 
18261bd9debfSTakashi Iwai 	info = &dbri->stream_info[DBRI_REC];
18271bd9debfSTakashi Iwai 	info->offset += DBRI_RD_CNT(status);
18281bd9debfSTakashi Iwai 
18291bd9debfSTakashi Iwai 	/* FIXME: Check status */
18301bd9debfSTakashi Iwai 
18311bd9debfSTakashi Iwai 	dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n",
18321bd9debfSTakashi Iwai 		rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status));
18331bd9debfSTakashi Iwai 
18341bd9debfSTakashi Iwai 	/* Notify ALSA */
18351bd9debfSTakashi Iwai 	spin_unlock(&dbri->lock);
18361bd9debfSTakashi Iwai 	snd_pcm_period_elapsed(info->substream);
18371bd9debfSTakashi Iwai 	spin_lock(&dbri->lock);
18381bd9debfSTakashi Iwai }
18391bd9debfSTakashi Iwai 
dbri_process_one_interrupt(struct snd_dbri * dbri,int x)1840475675d6STakashi Iwai static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x)
18411bd9debfSTakashi Iwai {
18421bd9debfSTakashi Iwai 	int val = D_INTR_GETVAL(x);
18431bd9debfSTakashi Iwai 	int channel = D_INTR_GETCHAN(x);
18441bd9debfSTakashi Iwai 	int command = D_INTR_GETCMD(x);
18451bd9debfSTakashi Iwai 	int code = D_INTR_GETCODE(x);
18461bd9debfSTakashi Iwai #ifdef DBRI_DEBUG
18471bd9debfSTakashi Iwai 	int rval = D_INTR_GETRVAL(x);
18481bd9debfSTakashi Iwai #endif
18491bd9debfSTakashi Iwai 
18501bd9debfSTakashi Iwai 	if (channel == D_INTR_CMD) {
18511bd9debfSTakashi Iwai 		dprintk(D_CMD, "INTR: Command: %-5s  Value:%d\n",
18521bd9debfSTakashi Iwai 			cmds[command], val);
18531bd9debfSTakashi Iwai 	} else {
18541bd9debfSTakashi Iwai 		dprintk(D_INT, "INTR: Chan:%d Code:%d Val:%#x\n",
18551bd9debfSTakashi Iwai 			channel, code, rval);
18561bd9debfSTakashi Iwai 	}
18571bd9debfSTakashi Iwai 
18581bd9debfSTakashi Iwai 	switch (code) {
18591be54c82SKrzysztof Helt 	case D_INTR_CMDI:
18601be54c82SKrzysztof Helt 		if (command != D_WAIT)
18611be54c82SKrzysztof Helt 			printk(KERN_ERR "DBRI: Command read interrupt\n");
18621be54c82SKrzysztof Helt 		break;
18631bd9debfSTakashi Iwai 	case D_INTR_BRDY:
18641bd9debfSTakashi Iwai 		reception_complete_intr(dbri, channel);
18651bd9debfSTakashi Iwai 		break;
18661bd9debfSTakashi Iwai 	case D_INTR_XCMP:
18671bd9debfSTakashi Iwai 	case D_INTR_MINT:
18681bd9debfSTakashi Iwai 		transmission_complete_intr(dbri, channel);
18691bd9debfSTakashi Iwai 		break;
18701bd9debfSTakashi Iwai 	case D_INTR_UNDR:
18711bd9debfSTakashi Iwai 		/* UNDR - Transmission underrun
18721bd9debfSTakashi Iwai 		 * resend SDP command with clear pipe bit (C) set
18731bd9debfSTakashi Iwai 		 */
18741bd9debfSTakashi Iwai 		{
18751be54c82SKrzysztof Helt 	/* FIXME: do something useful in case of underrun */
18761be54c82SKrzysztof Helt 			printk(KERN_ERR "DBRI: Underrun error\n");
18771be54c82SKrzysztof Helt #if 0
18781be54c82SKrzysztof Helt 			s32 *cmd;
18791bd9debfSTakashi Iwai 			int pipe = channel;
18801bd9debfSTakashi Iwai 			int td = dbri->pipes[pipe].desc;
18811bd9debfSTakashi Iwai 
18821bd9debfSTakashi Iwai 			dbri->dma->desc[td].word4 = 0;
18831bd9debfSTakashi Iwai 			cmd = dbri_cmdlock(dbri, NoGetLock);
18841bd9debfSTakashi Iwai 			*(cmd++) = DBRI_CMD(D_SDP, 0,
18851bd9debfSTakashi Iwai 					    dbri->pipes[pipe].sdp
18861bd9debfSTakashi Iwai 					    | D_SDP_P | D_SDP_C | D_SDP_2SAME);
18871bd9debfSTakashi Iwai 			*(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td);
18881bd9debfSTakashi Iwai 			dbri_cmdsend(dbri, cmd);
18891be54c82SKrzysztof Helt #endif
18901bd9debfSTakashi Iwai 		}
18911bd9debfSTakashi Iwai 		break;
18921bd9debfSTakashi Iwai 	case D_INTR_FXDT:
18931bd9debfSTakashi Iwai 		/* FXDT - Fixed data change */
18941bd9debfSTakashi Iwai 		if (dbri->pipes[channel].sdp & D_SDP_MSB)
18951bd9debfSTakashi Iwai 			val = reverse_bytes(val, dbri->pipes[channel].length);
18961bd9debfSTakashi Iwai 
18971bd9debfSTakashi Iwai 		if (dbri->pipes[channel].recv_fixed_ptr)
18981bd9debfSTakashi Iwai 			*(dbri->pipes[channel].recv_fixed_ptr) = val;
18991bd9debfSTakashi Iwai 		break;
19001bd9debfSTakashi Iwai 	default:
19011bd9debfSTakashi Iwai 		if (channel != D_INTR_CMD)
19021bd9debfSTakashi Iwai 			printk(KERN_WARNING
19031bd9debfSTakashi Iwai 			       "DBRI: Ignored Interrupt: %d (0x%x)\n", code, x);
19041bd9debfSTakashi Iwai 	}
19051bd9debfSTakashi Iwai }
19061bd9debfSTakashi Iwai 
19071bd9debfSTakashi Iwai /* dbri_process_interrupt_buffer advances through the DBRI's interrupt
19081bd9debfSTakashi Iwai  * buffer until it finds a zero word (indicating nothing more to do
19091bd9debfSTakashi Iwai  * right now).  Non-zero words require processing and are handed off
19101be54c82SKrzysztof Helt  * to dbri_process_one_interrupt AFTER advancing the pointer.
19111bd9debfSTakashi Iwai  */
dbri_process_interrupt_buffer(struct snd_dbri * dbri)1912475675d6STakashi Iwai static void dbri_process_interrupt_buffer(struct snd_dbri *dbri)
19131bd9debfSTakashi Iwai {
19141bd9debfSTakashi Iwai 	s32 x;
19151bd9debfSTakashi Iwai 
19161bd9debfSTakashi Iwai 	while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {
19171bd9debfSTakashi Iwai 		dbri->dma->intr[dbri->dbri_irqp] = 0;
19181bd9debfSTakashi Iwai 		dbri->dbri_irqp++;
19196fb98280SKrzysztof Helt 		if (dbri->dbri_irqp == DBRI_INT_BLK)
19201bd9debfSTakashi Iwai 			dbri->dbri_irqp = 1;
19211bd9debfSTakashi Iwai 
19221bd9debfSTakashi Iwai 		dbri_process_one_interrupt(dbri, x);
19231bd9debfSTakashi Iwai 	}
19241bd9debfSTakashi Iwai }
19251bd9debfSTakashi Iwai 
snd_dbri_interrupt(int irq,void * dev_id)19267d12e780SDavid Howells static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id)
19271bd9debfSTakashi Iwai {
1928475675d6STakashi Iwai 	struct snd_dbri *dbri = dev_id;
1929808709d7SJason Wang 	static int errcnt;
19301bd9debfSTakashi Iwai 	int x;
19311bd9debfSTakashi Iwai 
19321bd9debfSTakashi Iwai 	if (dbri == NULL)
19331bd9debfSTakashi Iwai 		return IRQ_NONE;
19341bd9debfSTakashi Iwai 	spin_lock(&dbri->lock);
19351bd9debfSTakashi Iwai 
19361bd9debfSTakashi Iwai 	/*
19371bd9debfSTakashi Iwai 	 * Read it, so the interrupt goes away.
19381bd9debfSTakashi Iwai 	 */
19391bd9debfSTakashi Iwai 	x = sbus_readl(dbri->regs + REG1);
19401bd9debfSTakashi Iwai 
19411bd9debfSTakashi Iwai 	if (x & (D_MRR | D_MLE | D_LBG | D_MBE)) {
19421bd9debfSTakashi Iwai 		u32 tmp;
19431bd9debfSTakashi Iwai 
19441bd9debfSTakashi Iwai 		if (x & D_MRR)
19451bd9debfSTakashi Iwai 			printk(KERN_ERR
19461bd9debfSTakashi Iwai 			       "DBRI: Multiple Error Ack on SBus reg1=0x%x\n",
19471bd9debfSTakashi Iwai 			       x);
19481bd9debfSTakashi Iwai 		if (x & D_MLE)
19491bd9debfSTakashi Iwai 			printk(KERN_ERR
19501bd9debfSTakashi Iwai 			       "DBRI: Multiple Late Error on SBus reg1=0x%x\n",
19511bd9debfSTakashi Iwai 			       x);
19521bd9debfSTakashi Iwai 		if (x & D_LBG)
19531bd9debfSTakashi Iwai 			printk(KERN_ERR
19541bd9debfSTakashi Iwai 			       "DBRI: Lost Bus Grant on SBus reg1=0x%x\n", x);
19551bd9debfSTakashi Iwai 		if (x & D_MBE)
19561bd9debfSTakashi Iwai 			printk(KERN_ERR
19571bd9debfSTakashi Iwai 			       "DBRI: Burst Error on SBus reg1=0x%x\n", x);
19581bd9debfSTakashi Iwai 
19591bd9debfSTakashi Iwai 		/* Some of these SBus errors cause the chip's SBus circuitry
19601bd9debfSTakashi Iwai 		 * to be disabled, so just re-enable and try to keep going.
19611bd9debfSTakashi Iwai 		 *
19621bd9debfSTakashi Iwai 		 * The only one I've seen is MRR, which will be triggered
19631bd9debfSTakashi Iwai 		 * if you let a transmit pipe underrun, then try to CDP it.
19641bd9debfSTakashi Iwai 		 *
19654338829eSMartin Habets 		 * If these things persist, we reset the chip.
19661bd9debfSTakashi Iwai 		 */
19671bd9debfSTakashi Iwai 		if ((++errcnt) % 10 == 0) {
19681bd9debfSTakashi Iwai 			dprintk(D_INT, "Interrupt errors exceeded.\n");
19691bd9debfSTakashi Iwai 			dbri_reset(dbri);
19701bd9debfSTakashi Iwai 		} else {
19711bd9debfSTakashi Iwai 			tmp = sbus_readl(dbri->regs + REG0);
19721bd9debfSTakashi Iwai 			tmp &= ~(D_D);
19731bd9debfSTakashi Iwai 			sbus_writel(tmp, dbri->regs + REG0);
19741bd9debfSTakashi Iwai 		}
19751bd9debfSTakashi Iwai 	}
19761bd9debfSTakashi Iwai 
19771bd9debfSTakashi Iwai 	dbri_process_interrupt_buffer(dbri);
19781bd9debfSTakashi Iwai 
19791bd9debfSTakashi Iwai 	spin_unlock(&dbri->lock);
19801bd9debfSTakashi Iwai 
19811bd9debfSTakashi Iwai 	return IRQ_HANDLED;
19821bd9debfSTakashi Iwai }
19831bd9debfSTakashi Iwai 
19841bd9debfSTakashi Iwai /****************************************************************************
19851bd9debfSTakashi Iwai 		PCM Interface
19861bd9debfSTakashi Iwai ****************************************************************************/
1987688ed206SBhumika Goyal static const struct snd_pcm_hardware snd_dbri_pcm_hw = {
1988cf68d212SKrzysztof Helt 	.info		= SNDRV_PCM_INFO_MMAP |
19891bd9debfSTakashi Iwai 			  SNDRV_PCM_INFO_INTERLEAVED |
19901bd9debfSTakashi Iwai 			  SNDRV_PCM_INFO_BLOCK_TRANSFER |
19912008f137STakashi Iwai 			  SNDRV_PCM_INFO_MMAP_VALID |
19922008f137STakashi Iwai 			  SNDRV_PCM_INFO_BATCH,
19931bd9debfSTakashi Iwai 	.formats	= SNDRV_PCM_FMTBIT_MU_LAW |
19941bd9debfSTakashi Iwai 			  SNDRV_PCM_FMTBIT_A_LAW |
19951bd9debfSTakashi Iwai 			  SNDRV_PCM_FMTBIT_U8 |
19961bd9debfSTakashi Iwai 			  SNDRV_PCM_FMTBIT_S16_BE,
1997ab93c7aeSKrzysztof Helt 	.rates		= SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512,
1998ab93c7aeSKrzysztof Helt 	.rate_min		= 5512,
19991bd9debfSTakashi Iwai 	.rate_max		= 48000,
20001bd9debfSTakashi Iwai 	.channels_min		= 1,
20011bd9debfSTakashi Iwai 	.channels_max		= 2,
2002cf68d212SKrzysztof Helt 	.buffer_bytes_max	= 64 * 1024,
20031bd9debfSTakashi Iwai 	.period_bytes_min	= 1,
20041bd9debfSTakashi Iwai 	.period_bytes_max	= DBRI_TD_MAXCNT,
20051bd9debfSTakashi Iwai 	.periods_min		= 1,
20061bd9debfSTakashi Iwai 	.periods_max		= 1024,
20071bd9debfSTakashi Iwai };
20081bd9debfSTakashi Iwai 
snd_hw_rule_format(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)2009ab93c7aeSKrzysztof Helt static int snd_hw_rule_format(struct snd_pcm_hw_params *params,
2010ab93c7aeSKrzysztof Helt 			      struct snd_pcm_hw_rule *rule)
2011ab93c7aeSKrzysztof Helt {
2012ab93c7aeSKrzysztof Helt 	struct snd_interval *c = hw_param_interval(params,
2013ab93c7aeSKrzysztof Helt 				SNDRV_PCM_HW_PARAM_CHANNELS);
2014ab93c7aeSKrzysztof Helt 	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
2015ab93c7aeSKrzysztof Helt 	struct snd_mask fmt;
2016ab93c7aeSKrzysztof Helt 
2017ab93c7aeSKrzysztof Helt 	snd_mask_any(&fmt);
2018ab93c7aeSKrzysztof Helt 	if (c->min > 1) {
2019ab93c7aeSKrzysztof Helt 		fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_BE;
2020ab93c7aeSKrzysztof Helt 		return snd_mask_refine(f, &fmt);
2021ab93c7aeSKrzysztof Helt 	}
2022ab93c7aeSKrzysztof Helt 	return 0;
2023ab93c7aeSKrzysztof Helt }
2024ab93c7aeSKrzysztof Helt 
snd_hw_rule_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)2025ab93c7aeSKrzysztof Helt static int snd_hw_rule_channels(struct snd_pcm_hw_params *params,
2026ab93c7aeSKrzysztof Helt 				struct snd_pcm_hw_rule *rule)
2027ab93c7aeSKrzysztof Helt {
2028ab93c7aeSKrzysztof Helt 	struct snd_interval *c = hw_param_interval(params,
2029ab93c7aeSKrzysztof Helt 				SNDRV_PCM_HW_PARAM_CHANNELS);
2030ab93c7aeSKrzysztof Helt 	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
2031ab93c7aeSKrzysztof Helt 	struct snd_interval ch;
2032ab93c7aeSKrzysztof Helt 
2033ab93c7aeSKrzysztof Helt 	snd_interval_any(&ch);
2034ab93c7aeSKrzysztof Helt 	if (!(f->bits[0] & SNDRV_PCM_FMTBIT_S16_BE)) {
2035098ccbc5SKrzysztof Helt 		ch.min = 1;
2036098ccbc5SKrzysztof Helt 		ch.max = 1;
2037ab93c7aeSKrzysztof Helt 		ch.integer = 1;
2038ab93c7aeSKrzysztof Helt 		return snd_interval_refine(c, &ch);
2039ab93c7aeSKrzysztof Helt 	}
2040ab93c7aeSKrzysztof Helt 	return 0;
2041ab93c7aeSKrzysztof Helt }
2042ab93c7aeSKrzysztof Helt 
snd_dbri_open(struct snd_pcm_substream * substream)2043475675d6STakashi Iwai static int snd_dbri_open(struct snd_pcm_substream *substream)
20441bd9debfSTakashi Iwai {
2045475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
2046475675d6STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
2047475675d6STakashi Iwai 	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
20481bd9debfSTakashi Iwai 	unsigned long flags;
20491bd9debfSTakashi Iwai 
20501bd9debfSTakashi Iwai 	dprintk(D_USR, "open audio output.\n");
20511bd9debfSTakashi Iwai 	runtime->hw = snd_dbri_pcm_hw;
20521bd9debfSTakashi Iwai 
20531bd9debfSTakashi Iwai 	spin_lock_irqsave(&dbri->lock, flags);
20541bd9debfSTakashi Iwai 	info->substream = substream;
20551bd9debfSTakashi Iwai 	info->offset = 0;
20561bd9debfSTakashi Iwai 	info->dvma_buffer = 0;
20571bd9debfSTakashi Iwai 	info->pipe = -1;
20581bd9debfSTakashi Iwai 	spin_unlock_irqrestore(&dbri->lock, flags);
20591bd9debfSTakashi Iwai 
2060ab93c7aeSKrzysztof Helt 	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
2061ae97dd9aSAl Viro 			    snd_hw_rule_format, NULL, SNDRV_PCM_HW_PARAM_FORMAT,
2062ab93c7aeSKrzysztof Helt 			    -1);
2063ab93c7aeSKrzysztof Helt 	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
2064ae97dd9aSAl Viro 			    snd_hw_rule_channels, NULL,
2065ab93c7aeSKrzysztof Helt 			    SNDRV_PCM_HW_PARAM_CHANNELS,
2066ab93c7aeSKrzysztof Helt 			    -1);
2067ab93c7aeSKrzysztof Helt 
20681bd9debfSTakashi Iwai 	cs4215_open(dbri);
20691bd9debfSTakashi Iwai 
20701bd9debfSTakashi Iwai 	return 0;
20711bd9debfSTakashi Iwai }
20721bd9debfSTakashi Iwai 
snd_dbri_close(struct snd_pcm_substream * substream)2073475675d6STakashi Iwai static int snd_dbri_close(struct snd_pcm_substream *substream)
20741bd9debfSTakashi Iwai {
2075475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
2076475675d6STakashi Iwai 	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
20771bd9debfSTakashi Iwai 
20781bd9debfSTakashi Iwai 	dprintk(D_USR, "close audio output.\n");
20791bd9debfSTakashi Iwai 	info->substream = NULL;
20801bd9debfSTakashi Iwai 	info->offset = 0;
20811bd9debfSTakashi Iwai 
20821bd9debfSTakashi Iwai 	return 0;
20831bd9debfSTakashi Iwai }
20841bd9debfSTakashi Iwai 
snd_dbri_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)2085475675d6STakashi Iwai static int snd_dbri_hw_params(struct snd_pcm_substream *substream,
2086475675d6STakashi Iwai 			      struct snd_pcm_hw_params *hw_params)
20871bd9debfSTakashi Iwai {
2088475675d6STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
2089475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
2090475675d6STakashi Iwai 	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
20911bd9debfSTakashi Iwai 	int direction;
20921bd9debfSTakashi Iwai 	int ret;
20931bd9debfSTakashi Iwai 
20941bd9debfSTakashi Iwai 	/* set sampling rate, audio format and number of channels */
20951bd9debfSTakashi Iwai 	ret = cs4215_prepare(dbri, params_rate(hw_params),
20961bd9debfSTakashi Iwai 			     params_format(hw_params),
20971bd9debfSTakashi Iwai 			     params_channels(hw_params));
20981bd9debfSTakashi Iwai 	if (ret != 0)
20991bd9debfSTakashi Iwai 		return ret;
21001bd9debfSTakashi Iwai 
21011bd9debfSTakashi Iwai 	/* hw_params can get called multiple times. Only map the DMA once.
21021bd9debfSTakashi Iwai 	 */
21031bd9debfSTakashi Iwai 	if (info->dvma_buffer == 0) {
21041bd9debfSTakashi Iwai 		if (DBRI_STREAMNO(substream) == DBRI_PLAY)
2105738f2b7bSDavid S. Miller 			direction = DMA_TO_DEVICE;
21061bd9debfSTakashi Iwai 		else
2107738f2b7bSDavid S. Miller 			direction = DMA_FROM_DEVICE;
21081bd9debfSTakashi Iwai 
21097a715f46SDavid S. Miller 		info->dvma_buffer =
21102bd320f8SDavid S. Miller 			dma_map_single(&dbri->op->dev,
21111bd9debfSTakashi Iwai 				       runtime->dma_area,
21121bd9debfSTakashi Iwai 				       params_buffer_bytes(hw_params),
21131bd9debfSTakashi Iwai 				       direction);
21141bd9debfSTakashi Iwai 	}
21151bd9debfSTakashi Iwai 
21161bd9debfSTakashi Iwai 	direction = params_buffer_bytes(hw_params);
21171bd9debfSTakashi Iwai 	dprintk(D_USR, "hw_params: %d bytes, dvma=%x\n",
21181bd9debfSTakashi Iwai 		direction, info->dvma_buffer);
21191bd9debfSTakashi Iwai 	return 0;
21201bd9debfSTakashi Iwai }
21211bd9debfSTakashi Iwai 
snd_dbri_hw_free(struct snd_pcm_substream * substream)2122475675d6STakashi Iwai static int snd_dbri_hw_free(struct snd_pcm_substream *substream)
21231bd9debfSTakashi Iwai {
2124475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
2125475675d6STakashi Iwai 	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
21261bd9debfSTakashi Iwai 	int direction;
212799dabfe7SKrzysztof Helt 
21281bd9debfSTakashi Iwai 	dprintk(D_USR, "hw_free.\n");
21291bd9debfSTakashi Iwai 
21301bd9debfSTakashi Iwai 	/* hw_free can get called multiple times. Only unmap the DMA once.
21311bd9debfSTakashi Iwai 	 */
21321bd9debfSTakashi Iwai 	if (info->dvma_buffer) {
21331bd9debfSTakashi Iwai 		if (DBRI_STREAMNO(substream) == DBRI_PLAY)
2134738f2b7bSDavid S. Miller 			direction = DMA_TO_DEVICE;
21351bd9debfSTakashi Iwai 		else
2136738f2b7bSDavid S. Miller 			direction = DMA_FROM_DEVICE;
21371bd9debfSTakashi Iwai 
21382bd320f8SDavid S. Miller 		dma_unmap_single(&dbri->op->dev, info->dvma_buffer,
21391bd9debfSTakashi Iwai 				 substream->runtime->buffer_size, direction);
21401bd9debfSTakashi Iwai 		info->dvma_buffer = 0;
21411bd9debfSTakashi Iwai 	}
214299dabfe7SKrzysztof Helt 	if (info->pipe != -1) {
214399dabfe7SKrzysztof Helt 		reset_pipe(dbri, info->pipe);
21441bd9debfSTakashi Iwai 		info->pipe = -1;
214599dabfe7SKrzysztof Helt 	}
21461bd9debfSTakashi Iwai 
2147786e90b0STakashi Iwai 	return 0;
21481bd9debfSTakashi Iwai }
21491bd9debfSTakashi Iwai 
snd_dbri_prepare(struct snd_pcm_substream * substream)2150475675d6STakashi Iwai static int snd_dbri_prepare(struct snd_pcm_substream *substream)
21511bd9debfSTakashi Iwai {
2152475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
2153475675d6STakashi Iwai 	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
21541bd9debfSTakashi Iwai 	int ret;
21551bd9debfSTakashi Iwai 
21561bd9debfSTakashi Iwai 	info->size = snd_pcm_lib_buffer_bytes(substream);
21571bd9debfSTakashi Iwai 	if (DBRI_STREAMNO(substream) == DBRI_PLAY)
21581bd9debfSTakashi Iwai 		info->pipe = 4;	/* Send pipe */
21591be54c82SKrzysztof Helt 	else
21601bd9debfSTakashi Iwai 		info->pipe = 6;	/* Receive pipe */
21611bd9debfSTakashi Iwai 
21621bd9debfSTakashi Iwai 	spin_lock_irq(&dbri->lock);
2163aaad3653SKrzysztof Helt 	info->offset = 0;
21641bd9debfSTakashi Iwai 
2165098ccbc5SKrzysztof Helt 	/* Setup the all the transmit/receive descriptors to cover the
21661bd9debfSTakashi Iwai 	 * whole DMA buffer.
21671bd9debfSTakashi Iwai 	 */
21681bd9debfSTakashi Iwai 	ret = setup_descs(dbri, DBRI_STREAMNO(substream),
21691bd9debfSTakashi Iwai 			  snd_pcm_lib_period_bytes(substream));
21701bd9debfSTakashi Iwai 
21711bd9debfSTakashi Iwai 	spin_unlock_irq(&dbri->lock);
21721bd9debfSTakashi Iwai 
21731bd9debfSTakashi Iwai 	dprintk(D_USR, "prepare audio output. %d bytes\n", info->size);
21741bd9debfSTakashi Iwai 	return ret;
21751bd9debfSTakashi Iwai }
21761bd9debfSTakashi Iwai 
snd_dbri_trigger(struct snd_pcm_substream * substream,int cmd)2177475675d6STakashi Iwai static int snd_dbri_trigger(struct snd_pcm_substream *substream, int cmd)
21781bd9debfSTakashi Iwai {
2179475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
2180475675d6STakashi Iwai 	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
21811bd9debfSTakashi Iwai 	int ret = 0;
21821bd9debfSTakashi Iwai 
21831bd9debfSTakashi Iwai 	switch (cmd) {
21841bd9debfSTakashi Iwai 	case SNDRV_PCM_TRIGGER_START:
21851bd9debfSTakashi Iwai 		dprintk(D_USR, "start audio, period is %d bytes\n",
21861bd9debfSTakashi Iwai 			(int)snd_pcm_lib_period_bytes(substream));
21871be54c82SKrzysztof Helt 		/* Re-submit the TDs. */
21881be54c82SKrzysztof Helt 		xmit_descs(dbri);
21891bd9debfSTakashi Iwai 		break;
21901bd9debfSTakashi Iwai 	case SNDRV_PCM_TRIGGER_STOP:
21911bd9debfSTakashi Iwai 		dprintk(D_USR, "stop audio.\n");
21921bd9debfSTakashi Iwai 		reset_pipe(dbri, info->pipe);
21931bd9debfSTakashi Iwai 		break;
21941bd9debfSTakashi Iwai 	default:
21951bd9debfSTakashi Iwai 		ret = -EINVAL;
21961bd9debfSTakashi Iwai 	}
21971bd9debfSTakashi Iwai 
21981bd9debfSTakashi Iwai 	return ret;
21991bd9debfSTakashi Iwai }
22001bd9debfSTakashi Iwai 
snd_dbri_pointer(struct snd_pcm_substream * substream)2201475675d6STakashi Iwai static snd_pcm_uframes_t snd_dbri_pointer(struct snd_pcm_substream *substream)
22021bd9debfSTakashi Iwai {
2203475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);
2204475675d6STakashi Iwai 	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);
22051bd9debfSTakashi Iwai 	snd_pcm_uframes_t ret;
22061bd9debfSTakashi Iwai 
22071bd9debfSTakashi Iwai 	ret = bytes_to_frames(substream->runtime, info->offset)
22081bd9debfSTakashi Iwai 		% substream->runtime->buffer_size;
22091be54c82SKrzysztof Helt 	dprintk(D_USR, "I/O pointer: %ld frames of %ld.\n",
22101be54c82SKrzysztof Helt 		ret, substream->runtime->buffer_size);
22111bd9debfSTakashi Iwai 	return ret;
22121bd9debfSTakashi Iwai }
22131bd9debfSTakashi Iwai 
2214544d6272SArvind Yadav static const struct snd_pcm_ops snd_dbri_ops = {
22151bd9debfSTakashi Iwai 	.open = snd_dbri_open,
22161bd9debfSTakashi Iwai 	.close = snd_dbri_close,
22171bd9debfSTakashi Iwai 	.hw_params = snd_dbri_hw_params,
22181bd9debfSTakashi Iwai 	.hw_free = snd_dbri_hw_free,
22191bd9debfSTakashi Iwai 	.prepare = snd_dbri_prepare,
22201bd9debfSTakashi Iwai 	.trigger = snd_dbri_trigger,
22211bd9debfSTakashi Iwai 	.pointer = snd_dbri_pointer,
22221bd9debfSTakashi Iwai };
22231bd9debfSTakashi Iwai 
snd_dbri_pcm(struct snd_card * card)222432e02a7bSBill Pemberton static int snd_dbri_pcm(struct snd_card *card)
22251bd9debfSTakashi Iwai {
2226475675d6STakashi Iwai 	struct snd_pcm *pcm;
22271bd9debfSTakashi Iwai 	int err;
22281bd9debfSTakashi Iwai 
2229bdab9e5cSTakashi Iwai 	err = snd_pcm_new(card,
22301bd9debfSTakashi Iwai 			  /* ID */	    "sun_dbri",
22311bd9debfSTakashi Iwai 			  /* device */	    0,
22321bd9debfSTakashi Iwai 			  /* playback count */ 1,
2233bdab9e5cSTakashi Iwai 			  /* capture count */  1, &pcm);
2234bdab9e5cSTakashi Iwai 	if (err < 0)
22351bd9debfSTakashi Iwai 		return err;
22361bd9debfSTakashi Iwai 
22371bd9debfSTakashi Iwai 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops);
22381bd9debfSTakashi Iwai 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops);
22391bd9debfSTakashi Iwai 
2240afeacfd5SKrzysztof Helt 	pcm->private_data = card->private_data;
22411bd9debfSTakashi Iwai 	pcm->info_flags = 0;
2242afeacfd5SKrzysztof Helt 	strcpy(pcm->name, card->shortname);
22431bd9debfSTakashi Iwai 
2244786e90b0STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
2245786e90b0STakashi Iwai 				       NULL, 64 * 1024, 64 * 1024);
22461bd9debfSTakashi Iwai 	return 0;
22471bd9debfSTakashi Iwai }
22481bd9debfSTakashi Iwai 
22491bd9debfSTakashi Iwai /*****************************************************************************
22501bd9debfSTakashi Iwai 			Mixer interface
22511bd9debfSTakashi Iwai *****************************************************************************/
22521bd9debfSTakashi Iwai 
snd_cs4215_info_volume(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2253475675d6STakashi Iwai static int snd_cs4215_info_volume(struct snd_kcontrol *kcontrol,
2254475675d6STakashi Iwai 				  struct snd_ctl_elem_info *uinfo)
22551bd9debfSTakashi Iwai {
22561bd9debfSTakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
22571bd9debfSTakashi Iwai 	uinfo->count = 2;
22581bd9debfSTakashi Iwai 	uinfo->value.integer.min = 0;
2259cf68d212SKrzysztof Helt 	if (kcontrol->private_value == DBRI_PLAY)
22601bd9debfSTakashi Iwai 		uinfo->value.integer.max = DBRI_MAX_VOLUME;
2261cf68d212SKrzysztof Helt 	else
22621bd9debfSTakashi Iwai 		uinfo->value.integer.max = DBRI_MAX_GAIN;
22631bd9debfSTakashi Iwai 	return 0;
22641bd9debfSTakashi Iwai }
22651bd9debfSTakashi Iwai 
snd_cs4215_get_volume(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2266475675d6STakashi Iwai static int snd_cs4215_get_volume(struct snd_kcontrol *kcontrol,
2267475675d6STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
22681bd9debfSTakashi Iwai {
2269475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
2270475675d6STakashi Iwai 	struct dbri_streaminfo *info;
22715e246b85STakashi Iwai 
22725e246b85STakashi Iwai 	if (snd_BUG_ON(!dbri))
22735e246b85STakashi Iwai 		return -EINVAL;
22741bd9debfSTakashi Iwai 	info = &dbri->stream_info[kcontrol->private_value];
22751bd9debfSTakashi Iwai 
22761bd9debfSTakashi Iwai 	ucontrol->value.integer.value[0] = info->left_gain;
22771bd9debfSTakashi Iwai 	ucontrol->value.integer.value[1] = info->right_gain;
22781bd9debfSTakashi Iwai 	return 0;
22791bd9debfSTakashi Iwai }
22801bd9debfSTakashi Iwai 
snd_cs4215_put_volume(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2281475675d6STakashi Iwai static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol,
2282475675d6STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
22831bd9debfSTakashi Iwai {
2284475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
2285098ccbc5SKrzysztof Helt 	struct dbri_streaminfo *info =
2286098ccbc5SKrzysztof Helt 				&dbri->stream_info[kcontrol->private_value];
22873b892467STakashi Iwai 	unsigned int vol[2];
22881bd9debfSTakashi Iwai 	int changed = 0;
22891bd9debfSTakashi Iwai 
22903b892467STakashi Iwai 	vol[0] = ucontrol->value.integer.value[0];
22913b892467STakashi Iwai 	vol[1] = ucontrol->value.integer.value[1];
22923b892467STakashi Iwai 	if (kcontrol->private_value == DBRI_PLAY) {
22933b892467STakashi Iwai 		if (vol[0] > DBRI_MAX_VOLUME || vol[1] > DBRI_MAX_VOLUME)
22943b892467STakashi Iwai 			return -EINVAL;
22953b892467STakashi Iwai 	} else {
22963b892467STakashi Iwai 		if (vol[0] > DBRI_MAX_GAIN || vol[1] > DBRI_MAX_GAIN)
22973b892467STakashi Iwai 			return -EINVAL;
22983b892467STakashi Iwai 	}
22993b892467STakashi Iwai 
23004581aa36STakashi Iwai 	if (info->left_gain != vol[0]) {
23014581aa36STakashi Iwai 		info->left_gain = vol[0];
23021bd9debfSTakashi Iwai 		changed = 1;
23031bd9debfSTakashi Iwai 	}
23044581aa36STakashi Iwai 	if (info->right_gain != vol[1]) {
23054581aa36STakashi Iwai 		info->right_gain = vol[1];
23061bd9debfSTakashi Iwai 		changed = 1;
23071bd9debfSTakashi Iwai 	}
2308cf68d212SKrzysztof Helt 	if (changed) {
23091bd9debfSTakashi Iwai 		/* First mute outputs, and wait 1/8000 sec (125 us)
23101bd9debfSTakashi Iwai 		 * to make sure this takes.  This avoids clicking noises.
23111bd9debfSTakashi Iwai 		 */
23121bd9debfSTakashi Iwai 		cs4215_setdata(dbri, 1);
23131bd9debfSTakashi Iwai 		udelay(125);
23141bd9debfSTakashi Iwai 		cs4215_setdata(dbri, 0);
23151bd9debfSTakashi Iwai 	}
23161bd9debfSTakashi Iwai 	return changed;
23171bd9debfSTakashi Iwai }
23181bd9debfSTakashi Iwai 
snd_cs4215_info_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2319475675d6STakashi Iwai static int snd_cs4215_info_single(struct snd_kcontrol *kcontrol,
2320475675d6STakashi Iwai 				  struct snd_ctl_elem_info *uinfo)
23211bd9debfSTakashi Iwai {
23221bd9debfSTakashi Iwai 	int mask = (kcontrol->private_value >> 16) & 0xff;
23231bd9debfSTakashi Iwai 
23241bd9debfSTakashi Iwai 	uinfo->type = (mask == 1) ?
23251bd9debfSTakashi Iwai 	    SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
23261bd9debfSTakashi Iwai 	uinfo->count = 1;
23271bd9debfSTakashi Iwai 	uinfo->value.integer.min = 0;
23281bd9debfSTakashi Iwai 	uinfo->value.integer.max = mask;
23291bd9debfSTakashi Iwai 	return 0;
23301bd9debfSTakashi Iwai }
23311bd9debfSTakashi Iwai 
snd_cs4215_get_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2332475675d6STakashi Iwai static int snd_cs4215_get_single(struct snd_kcontrol *kcontrol,
2333475675d6STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
23341bd9debfSTakashi Iwai {
2335475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
23361bd9debfSTakashi Iwai 	int elem = kcontrol->private_value & 0xff;
23371bd9debfSTakashi Iwai 	int shift = (kcontrol->private_value >> 8) & 0xff;
23381bd9debfSTakashi Iwai 	int mask = (kcontrol->private_value >> 16) & 0xff;
23391bd9debfSTakashi Iwai 	int invert = (kcontrol->private_value >> 24) & 1;
23405e246b85STakashi Iwai 
23415e246b85STakashi Iwai 	if (snd_BUG_ON(!dbri))
23425e246b85STakashi Iwai 		return -EINVAL;
23431bd9debfSTakashi Iwai 
2344098ccbc5SKrzysztof Helt 	if (elem < 4)
23451bd9debfSTakashi Iwai 		ucontrol->value.integer.value[0] =
23461bd9debfSTakashi Iwai 		    (dbri->mm.data[elem] >> shift) & mask;
2347098ccbc5SKrzysztof Helt 	else
23481bd9debfSTakashi Iwai 		ucontrol->value.integer.value[0] =
23491bd9debfSTakashi Iwai 		    (dbri->mm.ctrl[elem - 4] >> shift) & mask;
23501bd9debfSTakashi Iwai 
2351098ccbc5SKrzysztof Helt 	if (invert == 1)
23521bd9debfSTakashi Iwai 		ucontrol->value.integer.value[0] =
23531bd9debfSTakashi Iwai 		    mask - ucontrol->value.integer.value[0];
23541bd9debfSTakashi Iwai 	return 0;
23551bd9debfSTakashi Iwai }
23561bd9debfSTakashi Iwai 
snd_cs4215_put_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2357475675d6STakashi Iwai static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol,
2358475675d6STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
23591bd9debfSTakashi Iwai {
2360475675d6STakashi Iwai 	struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
23611bd9debfSTakashi Iwai 	int elem = kcontrol->private_value & 0xff;
23621bd9debfSTakashi Iwai 	int shift = (kcontrol->private_value >> 8) & 0xff;
23631bd9debfSTakashi Iwai 	int mask = (kcontrol->private_value >> 16) & 0xff;
23641bd9debfSTakashi Iwai 	int invert = (kcontrol->private_value >> 24) & 1;
23651bd9debfSTakashi Iwai 	int changed = 0;
23661bd9debfSTakashi Iwai 	unsigned short val;
23675e246b85STakashi Iwai 
23685e246b85STakashi Iwai 	if (snd_BUG_ON(!dbri))
23695e246b85STakashi Iwai 		return -EINVAL;
23701bd9debfSTakashi Iwai 
23711bd9debfSTakashi Iwai 	val = (ucontrol->value.integer.value[0] & mask);
23721bd9debfSTakashi Iwai 	if (invert == 1)
23731bd9debfSTakashi Iwai 		val = mask - val;
23741bd9debfSTakashi Iwai 	val <<= shift;
23751bd9debfSTakashi Iwai 
23761bd9debfSTakashi Iwai 	if (elem < 4) {
23771bd9debfSTakashi Iwai 		dbri->mm.data[elem] = (dbri->mm.data[elem] &
23781bd9debfSTakashi Iwai 				       ~(mask << shift)) | val;
23791bd9debfSTakashi Iwai 		changed = (val != dbri->mm.data[elem]);
23801bd9debfSTakashi Iwai 	} else {
23811bd9debfSTakashi Iwai 		dbri->mm.ctrl[elem - 4] = (dbri->mm.ctrl[elem - 4] &
23821bd9debfSTakashi Iwai 					   ~(mask << shift)) | val;
23831bd9debfSTakashi Iwai 		changed = (val != dbri->mm.ctrl[elem - 4]);
23841bd9debfSTakashi Iwai 	}
23851bd9debfSTakashi Iwai 
23861bd9debfSTakashi Iwai 	dprintk(D_GEN, "put_single: mask=0x%x, changed=%d, "
23871bd9debfSTakashi Iwai 		"mixer-value=%ld, mm-value=0x%x\n",
23881bd9debfSTakashi Iwai 		mask, changed, ucontrol->value.integer.value[0],
23891bd9debfSTakashi Iwai 		dbri->mm.data[elem & 3]);
23901bd9debfSTakashi Iwai 
23911bd9debfSTakashi Iwai 	if (changed) {
23921bd9debfSTakashi Iwai 		/* First mute outputs, and wait 1/8000 sec (125 us)
23931bd9debfSTakashi Iwai 		 * to make sure this takes.  This avoids clicking noises.
23941bd9debfSTakashi Iwai 		 */
23951bd9debfSTakashi Iwai 		cs4215_setdata(dbri, 1);
23961bd9debfSTakashi Iwai 		udelay(125);
23971bd9debfSTakashi Iwai 		cs4215_setdata(dbri, 0);
23981bd9debfSTakashi Iwai 	}
23991bd9debfSTakashi Iwai 	return changed;
24001bd9debfSTakashi Iwai }
24011bd9debfSTakashi Iwai 
24021bd9debfSTakashi Iwai /* Entries 0-3 map to the 4 data timeslots, entries 4-7 map to the 4 control
24031bd9debfSTakashi Iwai    timeslots. Shift is the bit offset in the timeslot, mask defines the
24041bd9debfSTakashi Iwai    number of bits. invert is a boolean for use with attenuation.
24051bd9debfSTakashi Iwai  */
24061bd9debfSTakashi Iwai #define CS4215_SINGLE(xname, entry, shift, mask, invert)	\
2407098ccbc5SKrzysztof Helt { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),		\
24081bd9debfSTakashi Iwai   .info = snd_cs4215_info_single,				\
24091bd9debfSTakashi Iwai   .get = snd_cs4215_get_single, .put = snd_cs4215_put_single,	\
2410098ccbc5SKrzysztof Helt   .private_value = (entry) | ((shift) << 8) | ((mask) << 16) |	\
2411098ccbc5SKrzysztof Helt 			((invert) << 24) },
24121bd9debfSTakashi Iwai 
2413f8a32d94STakashi Iwai static const struct snd_kcontrol_new dbri_controls[] = {
24141bd9debfSTakashi Iwai 	{
24151bd9debfSTakashi Iwai 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
24161bd9debfSTakashi Iwai 	 .name  = "Playback Volume",
24171bd9debfSTakashi Iwai 	 .info  = snd_cs4215_info_volume,
24181bd9debfSTakashi Iwai 	 .get   = snd_cs4215_get_volume,
24191bd9debfSTakashi Iwai 	 .put   = snd_cs4215_put_volume,
24201bd9debfSTakashi Iwai 	 .private_value = DBRI_PLAY,
24211bd9debfSTakashi Iwai 	 },
24221bd9debfSTakashi Iwai 	CS4215_SINGLE("Headphone switch", 0, 7, 1, 0)
24231bd9debfSTakashi Iwai 	CS4215_SINGLE("Line out switch", 0, 6, 1, 0)
24241bd9debfSTakashi Iwai 	CS4215_SINGLE("Speaker switch", 1, 6, 1, 0)
24251bd9debfSTakashi Iwai 	{
24261bd9debfSTakashi Iwai 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
24271bd9debfSTakashi Iwai 	 .name  = "Capture Volume",
24281bd9debfSTakashi Iwai 	 .info  = snd_cs4215_info_volume,
24291bd9debfSTakashi Iwai 	 .get   = snd_cs4215_get_volume,
24301bd9debfSTakashi Iwai 	 .put   = snd_cs4215_put_volume,
24311bd9debfSTakashi Iwai 	 .private_value = DBRI_REC,
24321bd9debfSTakashi Iwai 	 },
24331bd9debfSTakashi Iwai 	/* FIXME: mic/line switch */
24341bd9debfSTakashi Iwai 	CS4215_SINGLE("Line in switch", 2, 4, 1, 0)
24351bd9debfSTakashi Iwai 	CS4215_SINGLE("High Pass Filter switch", 5, 7, 1, 0)
24361bd9debfSTakashi Iwai 	CS4215_SINGLE("Monitor Volume", 3, 4, 0xf, 1)
24371bd9debfSTakashi Iwai 	CS4215_SINGLE("Mic boost", 4, 4, 1, 1)
24381bd9debfSTakashi Iwai };
24391bd9debfSTakashi Iwai 
snd_dbri_mixer(struct snd_card * card)244032e02a7bSBill Pemberton static int snd_dbri_mixer(struct snd_card *card)
24411bd9debfSTakashi Iwai {
24421bd9debfSTakashi Iwai 	int idx, err;
2443afeacfd5SKrzysztof Helt 	struct snd_dbri *dbri;
24441bd9debfSTakashi Iwai 
24455e246b85STakashi Iwai 	if (snd_BUG_ON(!card || !card->private_data))
24465e246b85STakashi Iwai 		return -EINVAL;
2447afeacfd5SKrzysztof Helt 	dbri = card->private_data;
24481bd9debfSTakashi Iwai 
24491bd9debfSTakashi Iwai 	strcpy(card->mixername, card->shortname);
24501bd9debfSTakashi Iwai 
24516c2d8b5dSTobias Klauser 	for (idx = 0; idx < ARRAY_SIZE(dbri_controls); idx++) {
2452cf68d212SKrzysztof Helt 		err = snd_ctl_add(card,
2453cf68d212SKrzysztof Helt 				snd_ctl_new1(&dbri_controls[idx], dbri));
2454cf68d212SKrzysztof Helt 		if (err < 0)
24551bd9debfSTakashi Iwai 			return err;
24561bd9debfSTakashi Iwai 	}
24571bd9debfSTakashi Iwai 
24581bd9debfSTakashi Iwai 	for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) {
24591bd9debfSTakashi Iwai 		dbri->stream_info[idx].left_gain = 0;
24601bd9debfSTakashi Iwai 		dbri->stream_info[idx].right_gain = 0;
24611bd9debfSTakashi Iwai 	}
24621bd9debfSTakashi Iwai 
24631bd9debfSTakashi Iwai 	return 0;
24641bd9debfSTakashi Iwai }
24651bd9debfSTakashi Iwai 
24661bd9debfSTakashi Iwai /****************************************************************************
24671bd9debfSTakashi Iwai 			/proc interface
24681bd9debfSTakashi Iwai ****************************************************************************/
dbri_regs_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)2469098ccbc5SKrzysztof Helt static void dbri_regs_read(struct snd_info_entry *entry,
2470098ccbc5SKrzysztof Helt 			   struct snd_info_buffer *buffer)
24711bd9debfSTakashi Iwai {
2472475675d6STakashi Iwai 	struct snd_dbri *dbri = entry->private_data;
24731bd9debfSTakashi Iwai 
24741bd9debfSTakashi Iwai 	snd_iprintf(buffer, "REG0: 0x%x\n", sbus_readl(dbri->regs + REG0));
24751bd9debfSTakashi Iwai 	snd_iprintf(buffer, "REG2: 0x%x\n", sbus_readl(dbri->regs + REG2));
24761bd9debfSTakashi Iwai 	snd_iprintf(buffer, "REG8: 0x%x\n", sbus_readl(dbri->regs + REG8));
24771bd9debfSTakashi Iwai 	snd_iprintf(buffer, "REG9: 0x%x\n", sbus_readl(dbri->regs + REG9));
24781bd9debfSTakashi Iwai }
24791bd9debfSTakashi Iwai 
24801bd9debfSTakashi Iwai #ifdef DBRI_DEBUG
dbri_debug_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)2481475675d6STakashi Iwai static void dbri_debug_read(struct snd_info_entry *entry,
2482475675d6STakashi Iwai 			    struct snd_info_buffer *buffer)
24831bd9debfSTakashi Iwai {
2484475675d6STakashi Iwai 	struct snd_dbri *dbri = entry->private_data;
24851bd9debfSTakashi Iwai 	int pipe;
24861bd9debfSTakashi Iwai 	snd_iprintf(buffer, "debug=%d\n", dbri_debug);
24871bd9debfSTakashi Iwai 
24881bd9debfSTakashi Iwai 	for (pipe = 0; pipe < 32; pipe++) {
24891bd9debfSTakashi Iwai 		if (pipe_active(dbri, pipe)) {
24901bd9debfSTakashi Iwai 			struct dbri_pipe *pptr = &dbri->pipes[pipe];
24911bd9debfSTakashi Iwai 			snd_iprintf(buffer,
24921bd9debfSTakashi Iwai 				    "Pipe %d: %s SDP=0x%x desc=%d, "
2493294a30dcSKrzysztof Helt 				    "len=%d next %d\n",
24941bd9debfSTakashi Iwai 				    pipe,
2495cf68d212SKrzysztof Helt 				   (pptr->sdp & D_SDP_TO_SER) ? "output" :
2496cf68d212SKrzysztof Helt 								 "input",
24975fc3a2b2SKrzysztof Helt 				    pptr->sdp, pptr->desc,
2498294a30dcSKrzysztof Helt 				    pptr->length, pptr->nextpipe);
24991bd9debfSTakashi Iwai 		}
25001bd9debfSTakashi Iwai 	}
25011bd9debfSTakashi Iwai }
25021bd9debfSTakashi Iwai #endif
25031bd9debfSTakashi Iwai 
snd_dbri_proc(struct snd_card * card)250432e02a7bSBill Pemberton static void snd_dbri_proc(struct snd_card *card)
25051bd9debfSTakashi Iwai {
2506afeacfd5SKrzysztof Helt 	struct snd_dbri *dbri = card->private_data;
25071bd9debfSTakashi Iwai 
25083c6ee770STakashi Iwai 	snd_card_ro_proc_new(card, "regs", dbri, dbri_regs_read);
25091bd9debfSTakashi Iwai #ifdef DBRI_DEBUG
25103c6ee770STakashi Iwai 	snd_card_ro_proc_new(card, "debug", dbri, dbri_debug_read);
25111bd9debfSTakashi Iwai #endif
25121bd9debfSTakashi Iwai }
25131bd9debfSTakashi Iwai 
25141bd9debfSTakashi Iwai /*
25151bd9debfSTakashi Iwai ****************************************************************************
25161bd9debfSTakashi Iwai **************************** Initialization ********************************
25171bd9debfSTakashi Iwai ****************************************************************************
25181bd9debfSTakashi Iwai */
2519475675d6STakashi Iwai static void snd_dbri_free(struct snd_dbri *dbri);
25201bd9debfSTakashi Iwai 
snd_dbri_create(struct snd_card * card,struct platform_device * op,int irq,int dev)252132e02a7bSBill Pemberton static int snd_dbri_create(struct snd_card *card,
25222dc11581SGrant Likely 			   struct platform_device *op,
2523afeacfd5SKrzysztof Helt 			   int irq, int dev)
25241bd9debfSTakashi Iwai {
2525475675d6STakashi Iwai 	struct snd_dbri *dbri = card->private_data;
25261bd9debfSTakashi Iwai 	int err;
25271bd9debfSTakashi Iwai 
25281bd9debfSTakashi Iwai 	spin_lock_init(&dbri->lock);
25292bd320f8SDavid S. Miller 	dbri->op = op;
2530afeacfd5SKrzysztof Helt 	dbri->irq = irq;
25311bd9debfSTakashi Iwai 
2532750afb08SLuis Chamberlain 	dbri->dma = dma_alloc_coherent(&op->dev, sizeof(struct dbri_dma),
2533207459a2STakashi Iwai 				       &dbri->dma_dvma, GFP_KERNEL);
2534be376649SFUJITA Tomonori 	if (!dbri->dma)
2535be376649SFUJITA Tomonori 		return -ENOMEM;
25361bd9debfSTakashi Iwai 
253716f46050STushar Dave 	dprintk(D_GEN, "DMA Cmd Block 0x%p (%pad)\n",
25381bd9debfSTakashi Iwai 		dbri->dma, dbri->dma_dvma);
25391bd9debfSTakashi Iwai 
25401bd9debfSTakashi Iwai 	/* Map the registers into memory. */
25412bd320f8SDavid S. Miller 	dbri->regs_size = resource_size(&op->resource[0]);
25422bd320f8SDavid S. Miller 	dbri->regs = of_ioremap(&op->resource[0], 0,
25431bd9debfSTakashi Iwai 				dbri->regs_size, "DBRI Registers");
25441bd9debfSTakashi Iwai 	if (!dbri->regs) {
25451bd9debfSTakashi Iwai 		printk(KERN_ERR "DBRI: could not allocate registers\n");
25462bd320f8SDavid S. Miller 		dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
25471bd9debfSTakashi Iwai 				  (void *)dbri->dma, dbri->dma_dvma);
25481bd9debfSTakashi Iwai 		return -EIO;
25491bd9debfSTakashi Iwai 	}
25501bd9debfSTakashi Iwai 
255165ca68b3SThomas Gleixner 	err = request_irq(dbri->irq, snd_dbri_interrupt, IRQF_SHARED,
25521bd9debfSTakashi Iwai 			  "DBRI audio", dbri);
25531bd9debfSTakashi Iwai 	if (err) {
25541bd9debfSTakashi Iwai 		printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
25552bd320f8SDavid S. Miller 		of_iounmap(&op->resource[0], dbri->regs, dbri->regs_size);
25562bd320f8SDavid S. Miller 		dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
25571bd9debfSTakashi Iwai 				  (void *)dbri->dma, dbri->dma_dvma);
25581bd9debfSTakashi Iwai 		return err;
25591bd9debfSTakashi Iwai 	}
25601bd9debfSTakashi Iwai 
25611bd9debfSTakashi Iwai 	/* Do low level initialization of the DBRI and CS4215 chips */
25621bd9debfSTakashi Iwai 	dbri_initialize(dbri);
25631bd9debfSTakashi Iwai 	err = cs4215_init(dbri);
25641bd9debfSTakashi Iwai 	if (err) {
25651bd9debfSTakashi Iwai 		snd_dbri_free(dbri);
25661bd9debfSTakashi Iwai 		return err;
25671bd9debfSTakashi Iwai 	}
25681bd9debfSTakashi Iwai 
25691bd9debfSTakashi Iwai 	return 0;
25701bd9debfSTakashi Iwai }
25711bd9debfSTakashi Iwai 
snd_dbri_free(struct snd_dbri * dbri)2572475675d6STakashi Iwai static void snd_dbri_free(struct snd_dbri *dbri)
25731bd9debfSTakashi Iwai {
25741bd9debfSTakashi Iwai 	dprintk(D_GEN, "snd_dbri_free\n");
25751bd9debfSTakashi Iwai 	dbri_reset(dbri);
25761bd9debfSTakashi Iwai 
25771bd9debfSTakashi Iwai 	if (dbri->irq)
25781bd9debfSTakashi Iwai 		free_irq(dbri->irq, dbri);
25791bd9debfSTakashi Iwai 
25801bd9debfSTakashi Iwai 	if (dbri->regs)
25812bd320f8SDavid S. Miller 		of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size);
25821bd9debfSTakashi Iwai 
25831bd9debfSTakashi Iwai 	if (dbri->dma)
25842bd320f8SDavid S. Miller 		dma_free_coherent(&dbri->op->dev,
25857a715f46SDavid S. Miller 				  sizeof(struct dbri_dma),
25861bd9debfSTakashi Iwai 				  (void *)dbri->dma, dbri->dma_dvma);
25871bd9debfSTakashi Iwai }
25881bd9debfSTakashi Iwai 
dbri_probe(struct platform_device * op)258932e02a7bSBill Pemberton static int dbri_probe(struct platform_device *op)
25901bd9debfSTakashi Iwai {
2591475675d6STakashi Iwai 	struct snd_dbri *dbri;
25921bd9debfSTakashi Iwai 	struct resource *rp;
2593475675d6STakashi Iwai 	struct snd_card *card;
2594808709d7SJason Wang 	static int dev;
25952bd320f8SDavid S. Miller 	int irq;
25961bd9debfSTakashi Iwai 	int err;
25971bd9debfSTakashi Iwai 
25981bd9debfSTakashi Iwai 	if (dev >= SNDRV_CARDS)
25991bd9debfSTakashi Iwai 		return -ENODEV;
26001bd9debfSTakashi Iwai 	if (!enable[dev]) {
26011bd9debfSTakashi Iwai 		dev++;
26021bd9debfSTakashi Iwai 		return -ENOENT;
26031bd9debfSTakashi Iwai 	}
26041bd9debfSTakashi Iwai 
26051636f8acSGrant Likely 	irq = op->archdata.irqs[0];
2606afeacfd5SKrzysztof Helt 	if (irq <= 0) {
2607afeacfd5SKrzysztof Helt 		printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
26084338829eSMartin Habets 		return -ENODEV;
26094338829eSMartin Habets 	}
26101bd9debfSTakashi Iwai 
2611a2fefc35STakashi Iwai 	err = snd_card_new(&op->dev, index[dev], id[dev], THIS_MODULE,
2612bd7dd77cSTakashi Iwai 			   sizeof(struct snd_dbri), &card);
2613bd7dd77cSTakashi Iwai 	if (err < 0)
2614bd7dd77cSTakashi Iwai 		return err;
26151bd9debfSTakashi Iwai 
26161bd9debfSTakashi Iwai 	strcpy(card->driver, "DBRI");
26171bd9debfSTakashi Iwai 	strcpy(card->shortname, "Sun DBRI");
26182bd320f8SDavid S. Miller 	rp = &op->resource[0];
26195863aa65SAndrew Morton 	sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
26201bd9debfSTakashi Iwai 		card->shortname,
2621afeacfd5SKrzysztof Helt 		rp->flags & 0xffL, (unsigned long long)rp->start, irq);
26221bd9debfSTakashi Iwai 
26232bd320f8SDavid S. Miller 	err = snd_dbri_create(card, op, irq, dev);
2624afeacfd5SKrzysztof Helt 	if (err < 0) {
26251bd9debfSTakashi Iwai 		snd_card_free(card);
26261bd9debfSTakashi Iwai 		return err;
26271bd9debfSTakashi Iwai 	}
26281bd9debfSTakashi Iwai 
2629475675d6STakashi Iwai 	dbri = card->private_data;
2630afeacfd5SKrzysztof Helt 	err = snd_dbri_pcm(card);
2631cf68d212SKrzysztof Helt 	if (err < 0)
263216dab54bSTakashi Iwai 		goto _err;
26331bd9debfSTakashi Iwai 
2634afeacfd5SKrzysztof Helt 	err = snd_dbri_mixer(card);
2635cf68d212SKrzysztof Helt 	if (err < 0)
263616dab54bSTakashi Iwai 		goto _err;
26371bd9debfSTakashi Iwai 
26381bd9debfSTakashi Iwai 	/* /proc file handling */
2639afeacfd5SKrzysztof Helt 	snd_dbri_proc(card);
26402bd320f8SDavid S. Miller 	dev_set_drvdata(&op->dev, card);
26411bd9debfSTakashi Iwai 
2642098ccbc5SKrzysztof Helt 	err = snd_card_register(card);
2643098ccbc5SKrzysztof Helt 	if (err < 0)
264416dab54bSTakashi Iwai 		goto _err;
26451bd9debfSTakashi Iwai 
26461bd9debfSTakashi Iwai 	printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
26471bd9debfSTakashi Iwai 	       dev, dbri->regs,
264861c7a080SGrant Likely 	       dbri->irq, op->dev.of_node->name[9], dbri->mm.version);
26491bd9debfSTakashi Iwai 	dev++;
26501bd9debfSTakashi Iwai 
26511bd9debfSTakashi Iwai 	return 0;
265216dab54bSTakashi Iwai 
265316dab54bSTakashi Iwai _err:
265416dab54bSTakashi Iwai 	snd_dbri_free(dbri);
265516dab54bSTakashi Iwai 	snd_card_free(card);
265616dab54bSTakashi Iwai 	return err;
26571bd9debfSTakashi Iwai }
26581bd9debfSTakashi Iwai 
dbri_remove(struct platform_device * op)26599fa6137dSUwe Kleine-König static void dbri_remove(struct platform_device *op)
2660afeacfd5SKrzysztof Helt {
26612bd320f8SDavid S. Miller 	struct snd_card *card = dev_get_drvdata(&op->dev);
2662afeacfd5SKrzysztof Helt 
2663afeacfd5SKrzysztof Helt 	snd_dbri_free(card->private_data);
2664afeacfd5SKrzysztof Helt 	snd_card_free(card);
2665afeacfd5SKrzysztof Helt }
2666afeacfd5SKrzysztof Helt 
2667fd098316SDavid S. Miller static const struct of_device_id dbri_match[] = {
2668afeacfd5SKrzysztof Helt 	{
2669afeacfd5SKrzysztof Helt 		.name = "SUNW,DBRIe",
2670afeacfd5SKrzysztof Helt 	},
2671afeacfd5SKrzysztof Helt 	{
2672afeacfd5SKrzysztof Helt 		.name = "SUNW,DBRIf",
2673afeacfd5SKrzysztof Helt 	},
2674afeacfd5SKrzysztof Helt 	{},
2675afeacfd5SKrzysztof Helt };
2676afeacfd5SKrzysztof Helt 
2677afeacfd5SKrzysztof Helt MODULE_DEVICE_TABLE(of, dbri_match);
2678afeacfd5SKrzysztof Helt 
2679f07eb223SGrant Likely static struct platform_driver dbri_sbus_driver = {
26804018294bSGrant Likely 	.driver = {
2681afeacfd5SKrzysztof Helt 		.name = "dbri",
26824018294bSGrant Likely 		.of_match_table = dbri_match,
26834018294bSGrant Likely 	},
2684afeacfd5SKrzysztof Helt 	.probe		= dbri_probe,
26859fa6137dSUwe Kleine-König 	.remove_new	= dbri_remove,
2686afeacfd5SKrzysztof Helt };
2687afeacfd5SKrzysztof Helt 
2688a09452eeSAxel Lin module_platform_driver(dbri_sbus_driver);
2689