xref: /openbmc/linux/sound/mips/hal2.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
182c29810SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2787dba37SThomas Bogendoerfer /*
3787dba37SThomas Bogendoerfer  *  Driver for A2 audio system used in SGI machines
4787dba37SThomas Bogendoerfer  *  Copyright (c) 2008 Thomas Bogendoerfer <tsbogend@alpha.fanken.de>
5787dba37SThomas Bogendoerfer  *
6787dba37SThomas Bogendoerfer  *  Based on OSS code from Ladislav Michl <ladis@linux-mips.org>, which
7787dba37SThomas Bogendoerfer  *  was based on code from Ulf Carlsson
8787dba37SThomas Bogendoerfer  */
9787dba37SThomas Bogendoerfer #include <linux/kernel.h>
10787dba37SThomas Bogendoerfer #include <linux/init.h>
11787dba37SThomas Bogendoerfer #include <linux/interrupt.h>
12787dba37SThomas Bogendoerfer #include <linux/dma-mapping.h>
13787dba37SThomas Bogendoerfer #include <linux/platform_device.h>
14787dba37SThomas Bogendoerfer #include <linux/io.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
16da155d5bSPaul Gortmaker #include <linux/module.h>
17787dba37SThomas Bogendoerfer 
18787dba37SThomas Bogendoerfer #include <asm/sgi/hpc3.h>
19787dba37SThomas Bogendoerfer #include <asm/sgi/ip22.h>
20787dba37SThomas Bogendoerfer 
21787dba37SThomas Bogendoerfer #include <sound/core.h>
22787dba37SThomas Bogendoerfer #include <sound/control.h>
23787dba37SThomas Bogendoerfer #include <sound/pcm.h>
24787dba37SThomas Bogendoerfer #include <sound/pcm-indirect.h>
25787dba37SThomas Bogendoerfer #include <sound/initval.h>
26787dba37SThomas Bogendoerfer 
27787dba37SThomas Bogendoerfer #include "hal2.h"
28787dba37SThomas Bogendoerfer 
29787dba37SThomas Bogendoerfer static int index = SNDRV_DEFAULT_IDX1;  /* Index 0-MAX */
30787dba37SThomas Bogendoerfer static char *id = SNDRV_DEFAULT_STR1;   /* ID for this card */
31787dba37SThomas Bogendoerfer 
32787dba37SThomas Bogendoerfer module_param(index, int, 0444);
33787dba37SThomas Bogendoerfer MODULE_PARM_DESC(index, "Index value for SGI HAL2 soundcard.");
34787dba37SThomas Bogendoerfer module_param(id, charp, 0444);
35787dba37SThomas Bogendoerfer MODULE_PARM_DESC(id, "ID string for SGI HAL2 soundcard.");
36787dba37SThomas Bogendoerfer MODULE_DESCRIPTION("ALSA driver for SGI HAL2 audio");
37787dba37SThomas Bogendoerfer MODULE_AUTHOR("Thomas Bogendoerfer");
38787dba37SThomas Bogendoerfer MODULE_LICENSE("GPL");
39787dba37SThomas Bogendoerfer 
40787dba37SThomas Bogendoerfer 
41787dba37SThomas Bogendoerfer #define H2_BLOCK_SIZE	1024
42787dba37SThomas Bogendoerfer #define H2_BUF_SIZE	16384
43787dba37SThomas Bogendoerfer 
44787dba37SThomas Bogendoerfer struct hal2_pbus {
45787dba37SThomas Bogendoerfer 	struct hpc3_pbus_dmacregs *pbus;
46787dba37SThomas Bogendoerfer 	int pbusnr;
47787dba37SThomas Bogendoerfer 	unsigned int ctrl;		/* Current state of pbus->pbdma_ctrl */
48787dba37SThomas Bogendoerfer };
49787dba37SThomas Bogendoerfer 
50787dba37SThomas Bogendoerfer struct hal2_desc {
51787dba37SThomas Bogendoerfer 	struct hpc_dma_desc desc;
52787dba37SThomas Bogendoerfer 	u32 pad;			/* padding */
53787dba37SThomas Bogendoerfer };
54787dba37SThomas Bogendoerfer 
55787dba37SThomas Bogendoerfer struct hal2_codec {
56787dba37SThomas Bogendoerfer 	struct snd_pcm_indirect pcm_indirect;
57787dba37SThomas Bogendoerfer 	struct snd_pcm_substream *substream;
58787dba37SThomas Bogendoerfer 
59787dba37SThomas Bogendoerfer 	unsigned char *buffer;
60787dba37SThomas Bogendoerfer 	dma_addr_t buffer_dma;
61787dba37SThomas Bogendoerfer 	struct hal2_desc *desc;
62787dba37SThomas Bogendoerfer 	dma_addr_t desc_dma;
63787dba37SThomas Bogendoerfer 	int desc_count;
64787dba37SThomas Bogendoerfer 	struct hal2_pbus pbus;
65787dba37SThomas Bogendoerfer 	int voices;			/* mono/stereo */
66787dba37SThomas Bogendoerfer 	unsigned int sample_rate;
67787dba37SThomas Bogendoerfer 	unsigned int master;		/* Master frequency */
68787dba37SThomas Bogendoerfer 	unsigned short mod;		/* MOD value */
69787dba37SThomas Bogendoerfer 	unsigned short inc;		/* INC value */
70787dba37SThomas Bogendoerfer };
71787dba37SThomas Bogendoerfer 
72787dba37SThomas Bogendoerfer #define H2_MIX_OUTPUT_ATT	0
73787dba37SThomas Bogendoerfer #define H2_MIX_INPUT_GAIN	1
74787dba37SThomas Bogendoerfer 
75787dba37SThomas Bogendoerfer struct snd_hal2 {
76787dba37SThomas Bogendoerfer 	struct snd_card *card;
77787dba37SThomas Bogendoerfer 
78787dba37SThomas Bogendoerfer 	struct hal2_ctl_regs *ctl_regs;	/* HAL2 ctl registers */
79787dba37SThomas Bogendoerfer 	struct hal2_aes_regs *aes_regs;	/* HAL2 aes registers */
80787dba37SThomas Bogendoerfer 	struct hal2_vol_regs *vol_regs;	/* HAL2 vol registers */
81787dba37SThomas Bogendoerfer 	struct hal2_syn_regs *syn_regs;	/* HAL2 syn registers */
82787dba37SThomas Bogendoerfer 
83787dba37SThomas Bogendoerfer 	struct hal2_codec dac;
84787dba37SThomas Bogendoerfer 	struct hal2_codec adc;
85787dba37SThomas Bogendoerfer };
86787dba37SThomas Bogendoerfer 
87787dba37SThomas Bogendoerfer #define H2_INDIRECT_WAIT(regs)	while (hal2_read(&regs->isr) & H2_ISR_TSTATUS);
88787dba37SThomas Bogendoerfer 
89787dba37SThomas Bogendoerfer #define H2_READ_ADDR(addr)	(addr | (1<<7))
90787dba37SThomas Bogendoerfer #define H2_WRITE_ADDR(addr)	(addr)
91787dba37SThomas Bogendoerfer 
hal2_read(u32 * reg)92787dba37SThomas Bogendoerfer static inline u32 hal2_read(u32 *reg)
93787dba37SThomas Bogendoerfer {
94787dba37SThomas Bogendoerfer 	return __raw_readl(reg);
95787dba37SThomas Bogendoerfer }
96787dba37SThomas Bogendoerfer 
hal2_write(u32 val,u32 * reg)97787dba37SThomas Bogendoerfer static inline void hal2_write(u32 val, u32 *reg)
98787dba37SThomas Bogendoerfer {
99787dba37SThomas Bogendoerfer 	__raw_writel(val, reg);
100787dba37SThomas Bogendoerfer }
101787dba37SThomas Bogendoerfer 
102787dba37SThomas Bogendoerfer 
hal2_i_read32(struct snd_hal2 * hal2,u16 addr)103787dba37SThomas Bogendoerfer static u32 hal2_i_read32(struct snd_hal2 *hal2, u16 addr)
104787dba37SThomas Bogendoerfer {
105787dba37SThomas Bogendoerfer 	u32 ret;
106787dba37SThomas Bogendoerfer 	struct hal2_ctl_regs *regs = hal2->ctl_regs;
107787dba37SThomas Bogendoerfer 
108787dba37SThomas Bogendoerfer 	hal2_write(H2_READ_ADDR(addr), &regs->iar);
109787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
110787dba37SThomas Bogendoerfer 	ret = hal2_read(&regs->idr0) & 0xffff;
111787dba37SThomas Bogendoerfer 	hal2_write(H2_READ_ADDR(addr) | 0x1, &regs->iar);
112787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
113787dba37SThomas Bogendoerfer 	ret |= (hal2_read(&regs->idr0) & 0xffff) << 16;
114787dba37SThomas Bogendoerfer 	return ret;
115787dba37SThomas Bogendoerfer }
116787dba37SThomas Bogendoerfer 
hal2_i_write16(struct snd_hal2 * hal2,u16 addr,u16 val)117787dba37SThomas Bogendoerfer static void hal2_i_write16(struct snd_hal2 *hal2, u16 addr, u16 val)
118787dba37SThomas Bogendoerfer {
119787dba37SThomas Bogendoerfer 	struct hal2_ctl_regs *regs = hal2->ctl_regs;
120787dba37SThomas Bogendoerfer 
121787dba37SThomas Bogendoerfer 	hal2_write(val, &regs->idr0);
122787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr1);
123787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr2);
124787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr3);
125787dba37SThomas Bogendoerfer 	hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
126787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
127787dba37SThomas Bogendoerfer }
128787dba37SThomas Bogendoerfer 
hal2_i_write32(struct snd_hal2 * hal2,u16 addr,u32 val)129787dba37SThomas Bogendoerfer static void hal2_i_write32(struct snd_hal2 *hal2, u16 addr, u32 val)
130787dba37SThomas Bogendoerfer {
131787dba37SThomas Bogendoerfer 	struct hal2_ctl_regs *regs = hal2->ctl_regs;
132787dba37SThomas Bogendoerfer 
133787dba37SThomas Bogendoerfer 	hal2_write(val & 0xffff, &regs->idr0);
134787dba37SThomas Bogendoerfer 	hal2_write(val >> 16, &regs->idr1);
135787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr2);
136787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr3);
137787dba37SThomas Bogendoerfer 	hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
138787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
139787dba37SThomas Bogendoerfer }
140787dba37SThomas Bogendoerfer 
hal2_i_setbit16(struct snd_hal2 * hal2,u16 addr,u16 bit)141787dba37SThomas Bogendoerfer static void hal2_i_setbit16(struct snd_hal2 *hal2, u16 addr, u16 bit)
142787dba37SThomas Bogendoerfer {
143787dba37SThomas Bogendoerfer 	struct hal2_ctl_regs *regs = hal2->ctl_regs;
144787dba37SThomas Bogendoerfer 
145787dba37SThomas Bogendoerfer 	hal2_write(H2_READ_ADDR(addr), &regs->iar);
146787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
147787dba37SThomas Bogendoerfer 	hal2_write((hal2_read(&regs->idr0) & 0xffff) | bit, &regs->idr0);
148787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr1);
149787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr2);
150787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr3);
151787dba37SThomas Bogendoerfer 	hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
152787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
153787dba37SThomas Bogendoerfer }
154787dba37SThomas Bogendoerfer 
hal2_i_clearbit16(struct snd_hal2 * hal2,u16 addr,u16 bit)155787dba37SThomas Bogendoerfer static void hal2_i_clearbit16(struct snd_hal2 *hal2, u16 addr, u16 bit)
156787dba37SThomas Bogendoerfer {
157787dba37SThomas Bogendoerfer 	struct hal2_ctl_regs *regs = hal2->ctl_regs;
158787dba37SThomas Bogendoerfer 
159787dba37SThomas Bogendoerfer 	hal2_write(H2_READ_ADDR(addr), &regs->iar);
160787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
161787dba37SThomas Bogendoerfer 	hal2_write((hal2_read(&regs->idr0) & 0xffff) & ~bit, &regs->idr0);
162787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr1);
163787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr2);
164787dba37SThomas Bogendoerfer 	hal2_write(0, &regs->idr3);
165787dba37SThomas Bogendoerfer 	hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
166787dba37SThomas Bogendoerfer 	H2_INDIRECT_WAIT(regs);
167787dba37SThomas Bogendoerfer }
168787dba37SThomas Bogendoerfer 
hal2_gain_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)169787dba37SThomas Bogendoerfer static int hal2_gain_info(struct snd_kcontrol *kcontrol,
170787dba37SThomas Bogendoerfer 			       struct snd_ctl_elem_info *uinfo)
171787dba37SThomas Bogendoerfer {
172787dba37SThomas Bogendoerfer 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
173787dba37SThomas Bogendoerfer 	uinfo->count = 2;
174787dba37SThomas Bogendoerfer 	uinfo->value.integer.min = 0;
175787dba37SThomas Bogendoerfer 	switch ((int)kcontrol->private_value) {
176787dba37SThomas Bogendoerfer 	case H2_MIX_OUTPUT_ATT:
177787dba37SThomas Bogendoerfer 		uinfo->value.integer.max = 31;
178787dba37SThomas Bogendoerfer 		break;
179787dba37SThomas Bogendoerfer 	case H2_MIX_INPUT_GAIN:
180787dba37SThomas Bogendoerfer 		uinfo->value.integer.max = 15;
181787dba37SThomas Bogendoerfer 		break;
182787dba37SThomas Bogendoerfer 	}
183787dba37SThomas Bogendoerfer 	return 0;
184787dba37SThomas Bogendoerfer }
185787dba37SThomas Bogendoerfer 
hal2_gain_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)186787dba37SThomas Bogendoerfer static int hal2_gain_get(struct snd_kcontrol *kcontrol,
187787dba37SThomas Bogendoerfer 			       struct snd_ctl_elem_value *ucontrol)
188787dba37SThomas Bogendoerfer {
189787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol);
190787dba37SThomas Bogendoerfer 	u32 tmp;
191787dba37SThomas Bogendoerfer 	int l, r;
192787dba37SThomas Bogendoerfer 
193787dba37SThomas Bogendoerfer 	switch ((int)kcontrol->private_value) {
194787dba37SThomas Bogendoerfer 	case H2_MIX_OUTPUT_ATT:
195787dba37SThomas Bogendoerfer 		tmp = hal2_i_read32(hal2, H2I_DAC_C2);
196787dba37SThomas Bogendoerfer 		if (tmp & H2I_C2_MUTE) {
197787dba37SThomas Bogendoerfer 			l = 0;
198787dba37SThomas Bogendoerfer 			r = 0;
199787dba37SThomas Bogendoerfer 		} else {
200787dba37SThomas Bogendoerfer 			l = 31 - ((tmp >> H2I_C2_L_ATT_SHIFT) & 31);
201787dba37SThomas Bogendoerfer 			r = 31 - ((tmp >> H2I_C2_R_ATT_SHIFT) & 31);
202787dba37SThomas Bogendoerfer 		}
203787dba37SThomas Bogendoerfer 		break;
204787dba37SThomas Bogendoerfer 	case H2_MIX_INPUT_GAIN:
205787dba37SThomas Bogendoerfer 		tmp = hal2_i_read32(hal2, H2I_ADC_C2);
206787dba37SThomas Bogendoerfer 		l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15;
207787dba37SThomas Bogendoerfer 		r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15;
208787dba37SThomas Bogendoerfer 		break;
2098b169cb2SArnd Bergmann 	default:
2108b169cb2SArnd Bergmann 		return -EINVAL;
211787dba37SThomas Bogendoerfer 	}
212787dba37SThomas Bogendoerfer 	ucontrol->value.integer.value[0] = l;
213787dba37SThomas Bogendoerfer 	ucontrol->value.integer.value[1] = r;
214787dba37SThomas Bogendoerfer 
215787dba37SThomas Bogendoerfer 	return 0;
216787dba37SThomas Bogendoerfer }
217787dba37SThomas Bogendoerfer 
hal2_gain_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)218787dba37SThomas Bogendoerfer static int hal2_gain_put(struct snd_kcontrol *kcontrol,
219787dba37SThomas Bogendoerfer 			 struct snd_ctl_elem_value *ucontrol)
220787dba37SThomas Bogendoerfer {
221787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol);
222787dba37SThomas Bogendoerfer 	u32 old, new;
223787dba37SThomas Bogendoerfer 	int l, r;
224787dba37SThomas Bogendoerfer 
225787dba37SThomas Bogendoerfer 	l = ucontrol->value.integer.value[0];
226787dba37SThomas Bogendoerfer 	r = ucontrol->value.integer.value[1];
227787dba37SThomas Bogendoerfer 
228787dba37SThomas Bogendoerfer 	switch ((int)kcontrol->private_value) {
229787dba37SThomas Bogendoerfer 	case H2_MIX_OUTPUT_ATT:
230787dba37SThomas Bogendoerfer 		old = hal2_i_read32(hal2, H2I_DAC_C2);
231787dba37SThomas Bogendoerfer 		new = old & ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
232787dba37SThomas Bogendoerfer 		if (l | r) {
233787dba37SThomas Bogendoerfer 			l = 31 - l;
234787dba37SThomas Bogendoerfer 			r = 31 - r;
235787dba37SThomas Bogendoerfer 			new |= (l << H2I_C2_L_ATT_SHIFT);
236787dba37SThomas Bogendoerfer 			new |= (r << H2I_C2_R_ATT_SHIFT);
237787dba37SThomas Bogendoerfer 		} else
238787dba37SThomas Bogendoerfer 			new |= H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE;
239787dba37SThomas Bogendoerfer 		hal2_i_write32(hal2, H2I_DAC_C2, new);
240787dba37SThomas Bogendoerfer 		break;
241787dba37SThomas Bogendoerfer 	case H2_MIX_INPUT_GAIN:
242787dba37SThomas Bogendoerfer 		old = hal2_i_read32(hal2, H2I_ADC_C2);
243787dba37SThomas Bogendoerfer 		new = old & ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M);
244787dba37SThomas Bogendoerfer 		new |= (l << H2I_C2_L_GAIN_SHIFT);
245787dba37SThomas Bogendoerfer 		new |= (r << H2I_C2_R_GAIN_SHIFT);
246787dba37SThomas Bogendoerfer 		hal2_i_write32(hal2, H2I_ADC_C2, new);
247787dba37SThomas Bogendoerfer 		break;
2488b169cb2SArnd Bergmann 	default:
2498b169cb2SArnd Bergmann 		return -EINVAL;
250787dba37SThomas Bogendoerfer 	}
251787dba37SThomas Bogendoerfer 	return old != new;
252787dba37SThomas Bogendoerfer }
253787dba37SThomas Bogendoerfer 
254905e46acSBhumika Goyal static const struct snd_kcontrol_new hal2_ctrl_headphone = {
255787dba37SThomas Bogendoerfer 	.iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
256787dba37SThomas Bogendoerfer 	.name           = "Headphone Playback Volume",
257787dba37SThomas Bogendoerfer 	.access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
258787dba37SThomas Bogendoerfer 	.private_value  = H2_MIX_OUTPUT_ATT,
259787dba37SThomas Bogendoerfer 	.info           = hal2_gain_info,
260787dba37SThomas Bogendoerfer 	.get            = hal2_gain_get,
261787dba37SThomas Bogendoerfer 	.put            = hal2_gain_put,
262787dba37SThomas Bogendoerfer };
263787dba37SThomas Bogendoerfer 
264905e46acSBhumika Goyal static const struct snd_kcontrol_new hal2_ctrl_mic = {
265787dba37SThomas Bogendoerfer 	.iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
266787dba37SThomas Bogendoerfer 	.name           = "Mic Capture Volume",
267787dba37SThomas Bogendoerfer 	.access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
268787dba37SThomas Bogendoerfer 	.private_value  = H2_MIX_INPUT_GAIN,
269787dba37SThomas Bogendoerfer 	.info           = hal2_gain_info,
270787dba37SThomas Bogendoerfer 	.get            = hal2_gain_get,
271787dba37SThomas Bogendoerfer 	.put            = hal2_gain_put,
272787dba37SThomas Bogendoerfer };
273787dba37SThomas Bogendoerfer 
hal2_mixer_create(struct snd_hal2 * hal2)274e0f8cb5fSBill Pemberton static int hal2_mixer_create(struct snd_hal2 *hal2)
275787dba37SThomas Bogendoerfer {
276787dba37SThomas Bogendoerfer 	int err;
277787dba37SThomas Bogendoerfer 
278787dba37SThomas Bogendoerfer 	/* mute DAC */
279787dba37SThomas Bogendoerfer 	hal2_i_write32(hal2, H2I_DAC_C2,
280787dba37SThomas Bogendoerfer 		       H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
281787dba37SThomas Bogendoerfer 	/* mute ADC */
282787dba37SThomas Bogendoerfer 	hal2_i_write32(hal2, H2I_ADC_C2, 0);
283787dba37SThomas Bogendoerfer 
284787dba37SThomas Bogendoerfer 	err = snd_ctl_add(hal2->card,
285787dba37SThomas Bogendoerfer 			  snd_ctl_new1(&hal2_ctrl_headphone, hal2));
286787dba37SThomas Bogendoerfer 	if (err < 0)
287787dba37SThomas Bogendoerfer 		return err;
288787dba37SThomas Bogendoerfer 
289787dba37SThomas Bogendoerfer 	err = snd_ctl_add(hal2->card,
290787dba37SThomas Bogendoerfer 			  snd_ctl_new1(&hal2_ctrl_mic, hal2));
291787dba37SThomas Bogendoerfer 	if (err < 0)
292787dba37SThomas Bogendoerfer 		return err;
293787dba37SThomas Bogendoerfer 
294787dba37SThomas Bogendoerfer 	return 0;
295787dba37SThomas Bogendoerfer }
296787dba37SThomas Bogendoerfer 
hal2_interrupt(int irq,void * dev_id)297787dba37SThomas Bogendoerfer static irqreturn_t hal2_interrupt(int irq, void *dev_id)
298787dba37SThomas Bogendoerfer {
299787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = dev_id;
300787dba37SThomas Bogendoerfer 	irqreturn_t ret = IRQ_NONE;
301787dba37SThomas Bogendoerfer 
302787dba37SThomas Bogendoerfer 	/* decide what caused this interrupt */
303787dba37SThomas Bogendoerfer 	if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
304787dba37SThomas Bogendoerfer 		snd_pcm_period_elapsed(hal2->dac.substream);
305787dba37SThomas Bogendoerfer 		ret = IRQ_HANDLED;
306787dba37SThomas Bogendoerfer 	}
307787dba37SThomas Bogendoerfer 	if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
308787dba37SThomas Bogendoerfer 		snd_pcm_period_elapsed(hal2->adc.substream);
309787dba37SThomas Bogendoerfer 		ret = IRQ_HANDLED;
310787dba37SThomas Bogendoerfer 	}
311787dba37SThomas Bogendoerfer 	return ret;
312787dba37SThomas Bogendoerfer }
313787dba37SThomas Bogendoerfer 
hal2_compute_rate(struct hal2_codec * codec,unsigned int rate)314787dba37SThomas Bogendoerfer static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate)
315787dba37SThomas Bogendoerfer {
316787dba37SThomas Bogendoerfer 	unsigned short mod;
317787dba37SThomas Bogendoerfer 
318787dba37SThomas Bogendoerfer 	if (44100 % rate < 48000 % rate) {
319787dba37SThomas Bogendoerfer 		mod = 4 * 44100 / rate;
320787dba37SThomas Bogendoerfer 		codec->master = 44100;
321787dba37SThomas Bogendoerfer 	} else {
322787dba37SThomas Bogendoerfer 		mod = 4 * 48000 / rate;
323787dba37SThomas Bogendoerfer 		codec->master = 48000;
324787dba37SThomas Bogendoerfer 	}
325787dba37SThomas Bogendoerfer 
326787dba37SThomas Bogendoerfer 	codec->inc = 4;
327787dba37SThomas Bogendoerfer 	codec->mod = mod;
328787dba37SThomas Bogendoerfer 	rate = 4 * codec->master / mod;
329787dba37SThomas Bogendoerfer 
330787dba37SThomas Bogendoerfer 	return rate;
331787dba37SThomas Bogendoerfer }
332787dba37SThomas Bogendoerfer 
hal2_set_dac_rate(struct snd_hal2 * hal2)333787dba37SThomas Bogendoerfer static void hal2_set_dac_rate(struct snd_hal2 *hal2)
334787dba37SThomas Bogendoerfer {
335787dba37SThomas Bogendoerfer 	unsigned int master = hal2->dac.master;
336787dba37SThomas Bogendoerfer 	int inc = hal2->dac.inc;
337787dba37SThomas Bogendoerfer 	int mod = hal2->dac.mod;
338787dba37SThomas Bogendoerfer 
339787dba37SThomas Bogendoerfer 	hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0);
340787dba37SThomas Bogendoerfer 	hal2_i_write32(hal2, H2I_BRES1_C2,
341787dba37SThomas Bogendoerfer 		       ((0xffff & (inc - mod - 1)) << 16) | inc);
342787dba37SThomas Bogendoerfer }
343787dba37SThomas Bogendoerfer 
hal2_set_adc_rate(struct snd_hal2 * hal2)344787dba37SThomas Bogendoerfer static void hal2_set_adc_rate(struct snd_hal2 *hal2)
345787dba37SThomas Bogendoerfer {
346787dba37SThomas Bogendoerfer 	unsigned int master = hal2->adc.master;
347787dba37SThomas Bogendoerfer 	int inc = hal2->adc.inc;
348787dba37SThomas Bogendoerfer 	int mod = hal2->adc.mod;
349787dba37SThomas Bogendoerfer 
350787dba37SThomas Bogendoerfer 	hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0);
351787dba37SThomas Bogendoerfer 	hal2_i_write32(hal2, H2I_BRES2_C2,
352787dba37SThomas Bogendoerfer 		       ((0xffff & (inc - mod - 1)) << 16) | inc);
353787dba37SThomas Bogendoerfer }
354787dba37SThomas Bogendoerfer 
hal2_setup_dac(struct snd_hal2 * hal2)355787dba37SThomas Bogendoerfer static void hal2_setup_dac(struct snd_hal2 *hal2)
356787dba37SThomas Bogendoerfer {
357787dba37SThomas Bogendoerfer 	unsigned int fifobeg, fifoend, highwater, sample_size;
358787dba37SThomas Bogendoerfer 	struct hal2_pbus *pbus = &hal2->dac.pbus;
359787dba37SThomas Bogendoerfer 
360787dba37SThomas Bogendoerfer 	/* Now we set up some PBUS information. The PBUS needs information about
361787dba37SThomas Bogendoerfer 	 * what portion of the fifo it will use. If it's receiving or
362787dba37SThomas Bogendoerfer 	 * transmitting, and finally whether the stream is little endian or big
363787dba37SThomas Bogendoerfer 	 * endian. The information is written later, on the start call.
364787dba37SThomas Bogendoerfer 	 */
365787dba37SThomas Bogendoerfer 	sample_size = 2 * hal2->dac.voices;
366787dba37SThomas Bogendoerfer 	/* Fifo should be set to hold exactly four samples. Highwater mark
367787dba37SThomas Bogendoerfer 	 * should be set to two samples. */
368787dba37SThomas Bogendoerfer 	highwater = (sample_size * 2) >> 1;	/* halfwords */
369787dba37SThomas Bogendoerfer 	fifobeg = 0;				/* playback is first */
370787dba37SThomas Bogendoerfer 	fifoend = (sample_size * 4) >> 3;	/* doublewords */
371787dba37SThomas Bogendoerfer 	pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD |
372787dba37SThomas Bogendoerfer 		     (highwater << 8) | (fifobeg << 16) | (fifoend << 24);
373787dba37SThomas Bogendoerfer 	/* We disable everything before we do anything at all */
374787dba37SThomas Bogendoerfer 	pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
375787dba37SThomas Bogendoerfer 	hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
376787dba37SThomas Bogendoerfer 	/* Setup the HAL2 for playback */
377787dba37SThomas Bogendoerfer 	hal2_set_dac_rate(hal2);
378787dba37SThomas Bogendoerfer 	/* Set endianess */
379787dba37SThomas Bogendoerfer 	hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
380787dba37SThomas Bogendoerfer 	/* Set DMA bus */
381787dba37SThomas Bogendoerfer 	hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
382787dba37SThomas Bogendoerfer 	/* We are using 1st Bresenham clock generator for playback */
383787dba37SThomas Bogendoerfer 	hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
384787dba37SThomas Bogendoerfer 			| (1 << H2I_C1_CLKID_SHIFT)
385787dba37SThomas Bogendoerfer 			| (hal2->dac.voices << H2I_C1_DATAT_SHIFT));
386787dba37SThomas Bogendoerfer }
387787dba37SThomas Bogendoerfer 
hal2_setup_adc(struct snd_hal2 * hal2)388787dba37SThomas Bogendoerfer static void hal2_setup_adc(struct snd_hal2 *hal2)
389787dba37SThomas Bogendoerfer {
390787dba37SThomas Bogendoerfer 	unsigned int fifobeg, fifoend, highwater, sample_size;
391787dba37SThomas Bogendoerfer 	struct hal2_pbus *pbus = &hal2->adc.pbus;
392787dba37SThomas Bogendoerfer 
393787dba37SThomas Bogendoerfer 	sample_size = 2 * hal2->adc.voices;
394787dba37SThomas Bogendoerfer 	highwater = (sample_size * 2) >> 1;		/* halfwords */
395787dba37SThomas Bogendoerfer 	fifobeg = (4 * 4) >> 3;				/* record is second */
396787dba37SThomas Bogendoerfer 	fifoend = (4 * 4 + sample_size * 4) >> 3;	/* doublewords */
397787dba37SThomas Bogendoerfer 	pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD |
398787dba37SThomas Bogendoerfer 		     (highwater << 8) | (fifobeg << 16) | (fifoend << 24);
399787dba37SThomas Bogendoerfer 	pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
400787dba37SThomas Bogendoerfer 	hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
401787dba37SThomas Bogendoerfer 	/* Setup the HAL2 for record */
402787dba37SThomas Bogendoerfer 	hal2_set_adc_rate(hal2);
403787dba37SThomas Bogendoerfer 	/* Set endianess */
404787dba37SThomas Bogendoerfer 	hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
405787dba37SThomas Bogendoerfer 	/* Set DMA bus */
406787dba37SThomas Bogendoerfer 	hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
407787dba37SThomas Bogendoerfer 	/* We are using 2nd Bresenham clock generator for record */
408787dba37SThomas Bogendoerfer 	hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
409787dba37SThomas Bogendoerfer 			| (2 << H2I_C1_CLKID_SHIFT)
410787dba37SThomas Bogendoerfer 			| (hal2->adc.voices << H2I_C1_DATAT_SHIFT));
411787dba37SThomas Bogendoerfer }
412787dba37SThomas Bogendoerfer 
hal2_start_dac(struct snd_hal2 * hal2)413787dba37SThomas Bogendoerfer static void hal2_start_dac(struct snd_hal2 *hal2)
414787dba37SThomas Bogendoerfer {
415787dba37SThomas Bogendoerfer 	struct hal2_pbus *pbus = &hal2->dac.pbus;
416787dba37SThomas Bogendoerfer 
417787dba37SThomas Bogendoerfer 	pbus->pbus->pbdma_dptr = hal2->dac.desc_dma;
418787dba37SThomas Bogendoerfer 	pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
419787dba37SThomas Bogendoerfer 	/* enable DAC */
420787dba37SThomas Bogendoerfer 	hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
421787dba37SThomas Bogendoerfer }
422787dba37SThomas Bogendoerfer 
hal2_start_adc(struct snd_hal2 * hal2)423787dba37SThomas Bogendoerfer static void hal2_start_adc(struct snd_hal2 *hal2)
424787dba37SThomas Bogendoerfer {
425787dba37SThomas Bogendoerfer 	struct hal2_pbus *pbus = &hal2->adc.pbus;
426787dba37SThomas Bogendoerfer 
427787dba37SThomas Bogendoerfer 	pbus->pbus->pbdma_dptr = hal2->adc.desc_dma;
428787dba37SThomas Bogendoerfer 	pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
429787dba37SThomas Bogendoerfer 	/* enable ADC */
430787dba37SThomas Bogendoerfer 	hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
431787dba37SThomas Bogendoerfer }
432787dba37SThomas Bogendoerfer 
hal2_stop_dac(struct snd_hal2 * hal2)433787dba37SThomas Bogendoerfer static inline void hal2_stop_dac(struct snd_hal2 *hal2)
434787dba37SThomas Bogendoerfer {
435787dba37SThomas Bogendoerfer 	hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
436787dba37SThomas Bogendoerfer 	/* The HAL2 itself may remain enabled safely */
437787dba37SThomas Bogendoerfer }
438787dba37SThomas Bogendoerfer 
hal2_stop_adc(struct snd_hal2 * hal2)439787dba37SThomas Bogendoerfer static inline void hal2_stop_adc(struct snd_hal2 *hal2)
440787dba37SThomas Bogendoerfer {
441787dba37SThomas Bogendoerfer 	hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
442787dba37SThomas Bogendoerfer }
443787dba37SThomas Bogendoerfer 
hal2_alloc_dmabuf(struct snd_hal2 * hal2,struct hal2_codec * codec,enum dma_data_direction buffer_dir)444ed4bc189SChristoph Hellwig static int hal2_alloc_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec,
445ed4bc189SChristoph Hellwig 		enum dma_data_direction buffer_dir)
446787dba37SThomas Bogendoerfer {
4479f7d35d9SChristoph Hellwig 	struct device *dev = hal2->card->dev;
448787dba37SThomas Bogendoerfer 	struct hal2_desc *desc;
449787dba37SThomas Bogendoerfer 	dma_addr_t desc_dma, buffer_dma;
450787dba37SThomas Bogendoerfer 	int count = H2_BUF_SIZE / H2_BLOCK_SIZE;
451787dba37SThomas Bogendoerfer 	int i;
452787dba37SThomas Bogendoerfer 
453ed4bc189SChristoph Hellwig 	codec->buffer = dma_alloc_noncoherent(dev, H2_BUF_SIZE, &buffer_dma,
454ed4bc189SChristoph Hellwig 					buffer_dir, GFP_KERNEL);
455787dba37SThomas Bogendoerfer 	if (!codec->buffer)
456787dba37SThomas Bogendoerfer 		return -ENOMEM;
457ed4bc189SChristoph Hellwig 	desc = dma_alloc_noncoherent(dev, count * sizeof(struct hal2_desc),
458ed4bc189SChristoph Hellwig 			&desc_dma, DMA_BIDIRECTIONAL, GFP_KERNEL);
459787dba37SThomas Bogendoerfer 	if (!desc) {
460ed4bc189SChristoph Hellwig 		dma_free_noncoherent(dev, H2_BUF_SIZE, codec->buffer, buffer_dma,
461ed4bc189SChristoph Hellwig 				buffer_dir);
462787dba37SThomas Bogendoerfer 		return -ENOMEM;
463787dba37SThomas Bogendoerfer 	}
464787dba37SThomas Bogendoerfer 	codec->buffer_dma = buffer_dma;
465787dba37SThomas Bogendoerfer 	codec->desc_dma = desc_dma;
466787dba37SThomas Bogendoerfer 	codec->desc = desc;
467787dba37SThomas Bogendoerfer 	for (i = 0; i < count; i++) {
468787dba37SThomas Bogendoerfer 		desc->desc.pbuf = buffer_dma + i * H2_BLOCK_SIZE;
469787dba37SThomas Bogendoerfer 		desc->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE;
470787dba37SThomas Bogendoerfer 		desc->desc.pnext = (i == count - 1) ?
471787dba37SThomas Bogendoerfer 		      desc_dma : desc_dma + (i + 1) * sizeof(struct hal2_desc);
472787dba37SThomas Bogendoerfer 		desc++;
473787dba37SThomas Bogendoerfer 	}
474ed4bc189SChristoph Hellwig 	dma_sync_single_for_device(dev, codec->desc_dma,
475ed4bc189SChristoph Hellwig 				   count * sizeof(struct hal2_desc),
476ed4bc189SChristoph Hellwig 				   DMA_BIDIRECTIONAL);
477787dba37SThomas Bogendoerfer 	codec->desc_count = count;
478787dba37SThomas Bogendoerfer 	return 0;
479787dba37SThomas Bogendoerfer }
480787dba37SThomas Bogendoerfer 
hal2_free_dmabuf(struct snd_hal2 * hal2,struct hal2_codec * codec,enum dma_data_direction buffer_dir)481ed4bc189SChristoph Hellwig static void hal2_free_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec,
482ed4bc189SChristoph Hellwig 		enum dma_data_direction buffer_dir)
483787dba37SThomas Bogendoerfer {
4849f7d35d9SChristoph Hellwig 	struct device *dev = hal2->card->dev;
4859f7d35d9SChristoph Hellwig 
486ed4bc189SChristoph Hellwig 	dma_free_noncoherent(dev, codec->desc_count * sizeof(struct hal2_desc),
487ed4bc189SChristoph Hellwig 		       codec->desc, codec->desc_dma, DMA_BIDIRECTIONAL);
488ed4bc189SChristoph Hellwig 	dma_free_noncoherent(dev, H2_BUF_SIZE, codec->buffer, codec->buffer_dma,
489ed4bc189SChristoph Hellwig 			buffer_dir);
490787dba37SThomas Bogendoerfer }
491787dba37SThomas Bogendoerfer 
4923068116fSBhumika Goyal static const struct snd_pcm_hardware hal2_pcm_hw = {
493787dba37SThomas Bogendoerfer 	.info = (SNDRV_PCM_INFO_MMAP |
494787dba37SThomas Bogendoerfer 		 SNDRV_PCM_INFO_MMAP_VALID |
495787dba37SThomas Bogendoerfer 		 SNDRV_PCM_INFO_INTERLEAVED |
496dc0d1c45STakashi Iwai 		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
497dc0d1c45STakashi Iwai 		 SNDRV_PCM_INFO_SYNC_APPLPTR),
498787dba37SThomas Bogendoerfer 	.formats =          SNDRV_PCM_FMTBIT_S16_BE,
499787dba37SThomas Bogendoerfer 	.rates =            SNDRV_PCM_RATE_8000_48000,
500787dba37SThomas Bogendoerfer 	.rate_min =         8000,
501787dba37SThomas Bogendoerfer 	.rate_max =         48000,
502787dba37SThomas Bogendoerfer 	.channels_min =     2,
503787dba37SThomas Bogendoerfer 	.channels_max =     2,
504787dba37SThomas Bogendoerfer 	.buffer_bytes_max = 65536,
505787dba37SThomas Bogendoerfer 	.period_bytes_min = 1024,
506787dba37SThomas Bogendoerfer 	.period_bytes_max = 65536,
507787dba37SThomas Bogendoerfer 	.periods_min =      2,
508787dba37SThomas Bogendoerfer 	.periods_max =      1024,
509787dba37SThomas Bogendoerfer };
510787dba37SThomas Bogendoerfer 
hal2_playback_open(struct snd_pcm_substream * substream)511787dba37SThomas Bogendoerfer static int hal2_playback_open(struct snd_pcm_substream *substream)
512787dba37SThomas Bogendoerfer {
513787dba37SThomas Bogendoerfer 	struct snd_pcm_runtime *runtime = substream->runtime;
514787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
515787dba37SThomas Bogendoerfer 
516787dba37SThomas Bogendoerfer 	runtime->hw = hal2_pcm_hw;
517ed4bc189SChristoph Hellwig 	return hal2_alloc_dmabuf(hal2, &hal2->dac, DMA_TO_DEVICE);
518787dba37SThomas Bogendoerfer }
519787dba37SThomas Bogendoerfer 
hal2_playback_close(struct snd_pcm_substream * substream)520787dba37SThomas Bogendoerfer static int hal2_playback_close(struct snd_pcm_substream *substream)
521787dba37SThomas Bogendoerfer {
522787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
523787dba37SThomas Bogendoerfer 
524ed4bc189SChristoph Hellwig 	hal2_free_dmabuf(hal2, &hal2->dac, DMA_TO_DEVICE);
525787dba37SThomas Bogendoerfer 	return 0;
526787dba37SThomas Bogendoerfer }
527787dba37SThomas Bogendoerfer 
hal2_playback_prepare(struct snd_pcm_substream * substream)528787dba37SThomas Bogendoerfer static int hal2_playback_prepare(struct snd_pcm_substream *substream)
529787dba37SThomas Bogendoerfer {
530787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
531787dba37SThomas Bogendoerfer 	struct snd_pcm_runtime *runtime = substream->runtime;
532787dba37SThomas Bogendoerfer 	struct hal2_codec *dac = &hal2->dac;
533787dba37SThomas Bogendoerfer 
534787dba37SThomas Bogendoerfer 	dac->voices = runtime->channels;
535787dba37SThomas Bogendoerfer 	dac->sample_rate = hal2_compute_rate(dac, runtime->rate);
536787dba37SThomas Bogendoerfer 	memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
537787dba37SThomas Bogendoerfer 	dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
538d873d5eaSTakashi Iwai 	dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
539d873d5eaSTakashi Iwai 	dac->pcm_indirect.hw_io = dac->buffer_dma;
540787dba37SThomas Bogendoerfer 	dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
541787dba37SThomas Bogendoerfer 	dac->substream = substream;
542787dba37SThomas Bogendoerfer 	hal2_setup_dac(hal2);
543787dba37SThomas Bogendoerfer 	return 0;
544787dba37SThomas Bogendoerfer }
545787dba37SThomas Bogendoerfer 
hal2_playback_trigger(struct snd_pcm_substream * substream,int cmd)546787dba37SThomas Bogendoerfer static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd)
547787dba37SThomas Bogendoerfer {
548787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
549787dba37SThomas Bogendoerfer 
550787dba37SThomas Bogendoerfer 	switch (cmd) {
551787dba37SThomas Bogendoerfer 	case SNDRV_PCM_TRIGGER_START:
552787dba37SThomas Bogendoerfer 		hal2_start_dac(hal2);
553787dba37SThomas Bogendoerfer 		break;
554787dba37SThomas Bogendoerfer 	case SNDRV_PCM_TRIGGER_STOP:
555787dba37SThomas Bogendoerfer 		hal2_stop_dac(hal2);
556787dba37SThomas Bogendoerfer 		break;
557787dba37SThomas Bogendoerfer 	default:
558787dba37SThomas Bogendoerfer 		return -EINVAL;
559787dba37SThomas Bogendoerfer 	}
560787dba37SThomas Bogendoerfer 	return 0;
561787dba37SThomas Bogendoerfer }
562787dba37SThomas Bogendoerfer 
563787dba37SThomas Bogendoerfer static snd_pcm_uframes_t
hal2_playback_pointer(struct snd_pcm_substream * substream)564787dba37SThomas Bogendoerfer hal2_playback_pointer(struct snd_pcm_substream *substream)
565787dba37SThomas Bogendoerfer {
566787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
567787dba37SThomas Bogendoerfer 	struct hal2_codec *dac = &hal2->dac;
568787dba37SThomas Bogendoerfer 
569787dba37SThomas Bogendoerfer 	return snd_pcm_indirect_playback_pointer(substream, &dac->pcm_indirect,
570787dba37SThomas Bogendoerfer 						 dac->pbus.pbus->pbdma_bptr);
571787dba37SThomas Bogendoerfer }
572787dba37SThomas Bogendoerfer 
hal2_playback_transfer(struct snd_pcm_substream * substream,struct snd_pcm_indirect * rec,size_t bytes)573787dba37SThomas Bogendoerfer static void hal2_playback_transfer(struct snd_pcm_substream *substream,
574787dba37SThomas Bogendoerfer 				   struct snd_pcm_indirect *rec, size_t bytes)
575787dba37SThomas Bogendoerfer {
576787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
577787dba37SThomas Bogendoerfer 	unsigned char *buf = hal2->dac.buffer + rec->hw_data;
578787dba37SThomas Bogendoerfer 
579787dba37SThomas Bogendoerfer 	memcpy(buf, substream->runtime->dma_area + rec->sw_data, bytes);
580ed4bc189SChristoph Hellwig 	dma_sync_single_for_device(hal2->card->dev,
581ed4bc189SChristoph Hellwig 			hal2->dac.buffer_dma + rec->hw_data, bytes,
582ed4bc189SChristoph Hellwig 			DMA_TO_DEVICE);
583787dba37SThomas Bogendoerfer 
584787dba37SThomas Bogendoerfer }
585787dba37SThomas Bogendoerfer 
hal2_playback_ack(struct snd_pcm_substream * substream)586787dba37SThomas Bogendoerfer static int hal2_playback_ack(struct snd_pcm_substream *substream)
587787dba37SThomas Bogendoerfer {
588787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
589787dba37SThomas Bogendoerfer 	struct hal2_codec *dac = &hal2->dac;
590787dba37SThomas Bogendoerfer 
5910f21e57dSTakashi Iwai 	return snd_pcm_indirect_playback_transfer(substream,
592787dba37SThomas Bogendoerfer 						  &dac->pcm_indirect,
593787dba37SThomas Bogendoerfer 						  hal2_playback_transfer);
594787dba37SThomas Bogendoerfer }
595787dba37SThomas Bogendoerfer 
hal2_capture_open(struct snd_pcm_substream * substream)596787dba37SThomas Bogendoerfer static int hal2_capture_open(struct snd_pcm_substream *substream)
597787dba37SThomas Bogendoerfer {
598787dba37SThomas Bogendoerfer 	struct snd_pcm_runtime *runtime = substream->runtime;
599787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
600787dba37SThomas Bogendoerfer 
601787dba37SThomas Bogendoerfer 	runtime->hw = hal2_pcm_hw;
602ed4bc189SChristoph Hellwig 	return hal2_alloc_dmabuf(hal2, &hal2->adc, DMA_FROM_DEVICE);
603787dba37SThomas Bogendoerfer }
604787dba37SThomas Bogendoerfer 
hal2_capture_close(struct snd_pcm_substream * substream)605787dba37SThomas Bogendoerfer static int hal2_capture_close(struct snd_pcm_substream *substream)
606787dba37SThomas Bogendoerfer {
607787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
608787dba37SThomas Bogendoerfer 
609ed4bc189SChristoph Hellwig 	hal2_free_dmabuf(hal2, &hal2->adc, DMA_FROM_DEVICE);
610787dba37SThomas Bogendoerfer 	return 0;
611787dba37SThomas Bogendoerfer }
612787dba37SThomas Bogendoerfer 
hal2_capture_prepare(struct snd_pcm_substream * substream)613787dba37SThomas Bogendoerfer static int hal2_capture_prepare(struct snd_pcm_substream *substream)
614787dba37SThomas Bogendoerfer {
615787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
616787dba37SThomas Bogendoerfer 	struct snd_pcm_runtime *runtime = substream->runtime;
617787dba37SThomas Bogendoerfer 	struct hal2_codec *adc = &hal2->adc;
618787dba37SThomas Bogendoerfer 
619787dba37SThomas Bogendoerfer 	adc->voices = runtime->channels;
620787dba37SThomas Bogendoerfer 	adc->sample_rate = hal2_compute_rate(adc, runtime->rate);
621787dba37SThomas Bogendoerfer 	memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect));
622787dba37SThomas Bogendoerfer 	adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
623787dba37SThomas Bogendoerfer 	adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
624d873d5eaSTakashi Iwai 	adc->pcm_indirect.hw_io = adc->buffer_dma;
625787dba37SThomas Bogendoerfer 	adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
626787dba37SThomas Bogendoerfer 	adc->substream = substream;
627787dba37SThomas Bogendoerfer 	hal2_setup_adc(hal2);
628787dba37SThomas Bogendoerfer 	return 0;
629787dba37SThomas Bogendoerfer }
630787dba37SThomas Bogendoerfer 
hal2_capture_trigger(struct snd_pcm_substream * substream,int cmd)631787dba37SThomas Bogendoerfer static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd)
632787dba37SThomas Bogendoerfer {
633787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
634787dba37SThomas Bogendoerfer 
635787dba37SThomas Bogendoerfer 	switch (cmd) {
636787dba37SThomas Bogendoerfer 	case SNDRV_PCM_TRIGGER_START:
637787dba37SThomas Bogendoerfer 		hal2_start_adc(hal2);
638787dba37SThomas Bogendoerfer 		break;
639787dba37SThomas Bogendoerfer 	case SNDRV_PCM_TRIGGER_STOP:
640787dba37SThomas Bogendoerfer 		hal2_stop_adc(hal2);
641787dba37SThomas Bogendoerfer 		break;
642787dba37SThomas Bogendoerfer 	default:
643787dba37SThomas Bogendoerfer 		return -EINVAL;
644787dba37SThomas Bogendoerfer 	}
645787dba37SThomas Bogendoerfer 	return 0;
646787dba37SThomas Bogendoerfer }
647787dba37SThomas Bogendoerfer 
648787dba37SThomas Bogendoerfer static snd_pcm_uframes_t
hal2_capture_pointer(struct snd_pcm_substream * substream)649787dba37SThomas Bogendoerfer hal2_capture_pointer(struct snd_pcm_substream *substream)
650787dba37SThomas Bogendoerfer {
651787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
652787dba37SThomas Bogendoerfer 	struct hal2_codec *adc = &hal2->adc;
653787dba37SThomas Bogendoerfer 
654787dba37SThomas Bogendoerfer 	return snd_pcm_indirect_capture_pointer(substream, &adc->pcm_indirect,
655787dba37SThomas Bogendoerfer 						adc->pbus.pbus->pbdma_bptr);
656787dba37SThomas Bogendoerfer }
657787dba37SThomas Bogendoerfer 
hal2_capture_transfer(struct snd_pcm_substream * substream,struct snd_pcm_indirect * rec,size_t bytes)658787dba37SThomas Bogendoerfer static void hal2_capture_transfer(struct snd_pcm_substream *substream,
659787dba37SThomas Bogendoerfer 				  struct snd_pcm_indirect *rec, size_t bytes)
660787dba37SThomas Bogendoerfer {
661787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
662787dba37SThomas Bogendoerfer 	unsigned char *buf = hal2->adc.buffer + rec->hw_data;
663787dba37SThomas Bogendoerfer 
664ed4bc189SChristoph Hellwig 	dma_sync_single_for_cpu(hal2->card->dev,
665ed4bc189SChristoph Hellwig 			hal2->adc.buffer_dma + rec->hw_data, bytes,
666ed4bc189SChristoph Hellwig 			DMA_FROM_DEVICE);
667787dba37SThomas Bogendoerfer 	memcpy(substream->runtime->dma_area + rec->sw_data, buf, bytes);
668787dba37SThomas Bogendoerfer }
669787dba37SThomas Bogendoerfer 
hal2_capture_ack(struct snd_pcm_substream * substream)670787dba37SThomas Bogendoerfer static int hal2_capture_ack(struct snd_pcm_substream *substream)
671787dba37SThomas Bogendoerfer {
672787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
673787dba37SThomas Bogendoerfer 	struct hal2_codec *adc = &hal2->adc;
674787dba37SThomas Bogendoerfer 
6750f21e57dSTakashi Iwai 	return snd_pcm_indirect_capture_transfer(substream,
676787dba37SThomas Bogendoerfer 						 &adc->pcm_indirect,
677787dba37SThomas Bogendoerfer 						 hal2_capture_transfer);
678787dba37SThomas Bogendoerfer }
679787dba37SThomas Bogendoerfer 
680915a38d3SArvind Yadav static const struct snd_pcm_ops hal2_playback_ops = {
681787dba37SThomas Bogendoerfer 	.open =        hal2_playback_open,
682787dba37SThomas Bogendoerfer 	.close =       hal2_playback_close,
683787dba37SThomas Bogendoerfer 	.prepare =     hal2_playback_prepare,
684787dba37SThomas Bogendoerfer 	.trigger =     hal2_playback_trigger,
685787dba37SThomas Bogendoerfer 	.pointer =     hal2_playback_pointer,
686787dba37SThomas Bogendoerfer 	.ack =         hal2_playback_ack,
687787dba37SThomas Bogendoerfer };
688787dba37SThomas Bogendoerfer 
689915a38d3SArvind Yadav static const struct snd_pcm_ops hal2_capture_ops = {
690787dba37SThomas Bogendoerfer 	.open =        hal2_capture_open,
691787dba37SThomas Bogendoerfer 	.close =       hal2_capture_close,
692787dba37SThomas Bogendoerfer 	.prepare =     hal2_capture_prepare,
693787dba37SThomas Bogendoerfer 	.trigger =     hal2_capture_trigger,
694787dba37SThomas Bogendoerfer 	.pointer =     hal2_capture_pointer,
695787dba37SThomas Bogendoerfer 	.ack =         hal2_capture_ack,
696787dba37SThomas Bogendoerfer };
697787dba37SThomas Bogendoerfer 
hal2_pcm_create(struct snd_hal2 * hal2)698e0f8cb5fSBill Pemberton static int hal2_pcm_create(struct snd_hal2 *hal2)
699787dba37SThomas Bogendoerfer {
700787dba37SThomas Bogendoerfer 	struct snd_pcm *pcm;
701787dba37SThomas Bogendoerfer 	int err;
702787dba37SThomas Bogendoerfer 
703787dba37SThomas Bogendoerfer 	/* create first pcm device with one outputs and one input */
704787dba37SThomas Bogendoerfer 	err = snd_pcm_new(hal2->card, "SGI HAL2 Audio", 0, 1, 1, &pcm);
705787dba37SThomas Bogendoerfer 	if (err < 0)
706787dba37SThomas Bogendoerfer 		return err;
707787dba37SThomas Bogendoerfer 
708787dba37SThomas Bogendoerfer 	pcm->private_data = hal2;
709787dba37SThomas Bogendoerfer 	strcpy(pcm->name, "SGI HAL2");
710787dba37SThomas Bogendoerfer 
711787dba37SThomas Bogendoerfer 	/* set operators */
712787dba37SThomas Bogendoerfer 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
713787dba37SThomas Bogendoerfer 			&hal2_playback_ops);
714787dba37SThomas Bogendoerfer 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
715787dba37SThomas Bogendoerfer 			&hal2_capture_ops);
716ee88f4ebSTakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
71798733426STakashi Iwai 				       NULL, 0, 1024 * 1024);
718787dba37SThomas Bogendoerfer 
719787dba37SThomas Bogendoerfer 	return 0;
720787dba37SThomas Bogendoerfer }
721787dba37SThomas Bogendoerfer 
hal2_dev_free(struct snd_device * device)722787dba37SThomas Bogendoerfer static int hal2_dev_free(struct snd_device *device)
723787dba37SThomas Bogendoerfer {
724787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2 = device->device_data;
725787dba37SThomas Bogendoerfer 
726787dba37SThomas Bogendoerfer 	free_irq(SGI_HPCDMA_IRQ, hal2);
727787dba37SThomas Bogendoerfer 	kfree(hal2);
728787dba37SThomas Bogendoerfer 	return 0;
729787dba37SThomas Bogendoerfer }
730787dba37SThomas Bogendoerfer 
73135a76585STakashi Iwai static const struct snd_device_ops hal2_ops = {
732787dba37SThomas Bogendoerfer 	.dev_free = hal2_dev_free,
733787dba37SThomas Bogendoerfer };
734787dba37SThomas Bogendoerfer 
hal2_init_codec(struct hal2_codec * codec,struct hpc3_regs * hpc3,int index)735787dba37SThomas Bogendoerfer static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3,
736787dba37SThomas Bogendoerfer 			    int index)
737787dba37SThomas Bogendoerfer {
738787dba37SThomas Bogendoerfer 	codec->pbus.pbusnr = index;
739787dba37SThomas Bogendoerfer 	codec->pbus.pbus = &hpc3->pbdma[index];
740787dba37SThomas Bogendoerfer }
741787dba37SThomas Bogendoerfer 
hal2_detect(struct snd_hal2 * hal2)742787dba37SThomas Bogendoerfer static int hal2_detect(struct snd_hal2 *hal2)
743787dba37SThomas Bogendoerfer {
744787dba37SThomas Bogendoerfer 	unsigned short board, major, minor;
745787dba37SThomas Bogendoerfer 	unsigned short rev;
746787dba37SThomas Bogendoerfer 
747787dba37SThomas Bogendoerfer 	/* reset HAL2 */
748787dba37SThomas Bogendoerfer 	hal2_write(0, &hal2->ctl_regs->isr);
749787dba37SThomas Bogendoerfer 
750787dba37SThomas Bogendoerfer 	/* release reset */
751787dba37SThomas Bogendoerfer 	hal2_write(H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N,
752787dba37SThomas Bogendoerfer 		   &hal2->ctl_regs->isr);
753787dba37SThomas Bogendoerfer 
754787dba37SThomas Bogendoerfer 
755787dba37SThomas Bogendoerfer 	hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE);
756787dba37SThomas Bogendoerfer 	rev = hal2_read(&hal2->ctl_regs->rev);
757787dba37SThomas Bogendoerfer 	if (rev & H2_REV_AUDIO_PRESENT)
758787dba37SThomas Bogendoerfer 		return -ENODEV;
759787dba37SThomas Bogendoerfer 
760787dba37SThomas Bogendoerfer 	board = (rev & H2_REV_BOARD_M) >> 12;
761787dba37SThomas Bogendoerfer 	major = (rev & H2_REV_MAJOR_CHIP_M) >> 4;
762787dba37SThomas Bogendoerfer 	minor = (rev & H2_REV_MINOR_CHIP_M);
763787dba37SThomas Bogendoerfer 
764787dba37SThomas Bogendoerfer 	printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n",
765787dba37SThomas Bogendoerfer 	       board, major, minor);
766787dba37SThomas Bogendoerfer 
767787dba37SThomas Bogendoerfer 	return 0;
768787dba37SThomas Bogendoerfer }
769787dba37SThomas Bogendoerfer 
hal2_create(struct snd_card * card,struct snd_hal2 ** rchip)770787dba37SThomas Bogendoerfer static int hal2_create(struct snd_card *card, struct snd_hal2 **rchip)
771787dba37SThomas Bogendoerfer {
772787dba37SThomas Bogendoerfer 	struct snd_hal2 *hal2;
773787dba37SThomas Bogendoerfer 	struct hpc3_regs *hpc3 = hpc3c0;
774787dba37SThomas Bogendoerfer 	int err;
775787dba37SThomas Bogendoerfer 
776044ace5eSMarkus Elfring 	hal2 = kzalloc(sizeof(*hal2), GFP_KERNEL);
777787dba37SThomas Bogendoerfer 	if (!hal2)
778787dba37SThomas Bogendoerfer 		return -ENOMEM;
779787dba37SThomas Bogendoerfer 
780787dba37SThomas Bogendoerfer 	hal2->card = card;
781787dba37SThomas Bogendoerfer 
782787dba37SThomas Bogendoerfer 	if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED,
783787dba37SThomas Bogendoerfer 			"SGI HAL2", hal2)) {
784787dba37SThomas Bogendoerfer 		printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ);
785787dba37SThomas Bogendoerfer 		kfree(hal2);
786787dba37SThomas Bogendoerfer 		return -EAGAIN;
787787dba37SThomas Bogendoerfer 	}
788787dba37SThomas Bogendoerfer 
789787dba37SThomas Bogendoerfer 	hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0];
790787dba37SThomas Bogendoerfer 	hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1];
791787dba37SThomas Bogendoerfer 	hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2];
792787dba37SThomas Bogendoerfer 	hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3];
793787dba37SThomas Bogendoerfer 
794787dba37SThomas Bogendoerfer 	if (hal2_detect(hal2) < 0) {
795787dba37SThomas Bogendoerfer 		kfree(hal2);
796787dba37SThomas Bogendoerfer 		return -ENODEV;
797787dba37SThomas Bogendoerfer 	}
798787dba37SThomas Bogendoerfer 
799787dba37SThomas Bogendoerfer 	hal2_init_codec(&hal2->dac, hpc3, 0);
800787dba37SThomas Bogendoerfer 	hal2_init_codec(&hal2->adc, hpc3, 1);
801787dba37SThomas Bogendoerfer 
802787dba37SThomas Bogendoerfer 	/*
803787dba37SThomas Bogendoerfer 	 * All DMA channel interfaces in HAL2 are designed to operate with
804787dba37SThomas Bogendoerfer 	 * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles
805787dba37SThomas Bogendoerfer 	 * in D5. HAL2 is a 16-bit device which can accept both big and little
806787dba37SThomas Bogendoerfer 	 * endian format. It assumes that even address bytes are on high
807787dba37SThomas Bogendoerfer 	 * portion of PBUS (15:8) and assumes that HPC3 is programmed to
808787dba37SThomas Bogendoerfer 	 * accept a live (unsynchronized) version of P_DREQ_N from HAL2.
809787dba37SThomas Bogendoerfer 	 */
810787dba37SThomas Bogendoerfer #define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \
811787dba37SThomas Bogendoerfer 			  (2 << HPC3_DMACFG_D4R_SHIFT) | \
812787dba37SThomas Bogendoerfer 			  (2 << HPC3_DMACFG_D5R_SHIFT) | \
813787dba37SThomas Bogendoerfer 			  (0 << HPC3_DMACFG_D3W_SHIFT) | \
814787dba37SThomas Bogendoerfer 			  (2 << HPC3_DMACFG_D4W_SHIFT) | \
815787dba37SThomas Bogendoerfer 			  (2 << HPC3_DMACFG_D5W_SHIFT) | \
816787dba37SThomas Bogendoerfer 				HPC3_DMACFG_DS16 | \
817787dba37SThomas Bogendoerfer 				HPC3_DMACFG_EVENHI | \
818787dba37SThomas Bogendoerfer 				HPC3_DMACFG_RTIME | \
819787dba37SThomas Bogendoerfer 			  (8 << HPC3_DMACFG_BURST_SHIFT) | \
820787dba37SThomas Bogendoerfer 				HPC3_DMACFG_DRQLIVE)
821787dba37SThomas Bogendoerfer 	/*
822787dba37SThomas Bogendoerfer 	 * Ignore what's mentioned in the specification and write value which
823787dba37SThomas Bogendoerfer 	 * works in The Real World (TM)
824787dba37SThomas Bogendoerfer 	 */
825787dba37SThomas Bogendoerfer 	hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844;
826787dba37SThomas Bogendoerfer 	hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844;
827787dba37SThomas Bogendoerfer 
828787dba37SThomas Bogendoerfer 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, hal2, &hal2_ops);
829787dba37SThomas Bogendoerfer 	if (err < 0) {
830787dba37SThomas Bogendoerfer 		free_irq(SGI_HPCDMA_IRQ, hal2);
831787dba37SThomas Bogendoerfer 		kfree(hal2);
832787dba37SThomas Bogendoerfer 		return err;
833787dba37SThomas Bogendoerfer 	}
834787dba37SThomas Bogendoerfer 	*rchip = hal2;
835787dba37SThomas Bogendoerfer 	return 0;
836787dba37SThomas Bogendoerfer }
837787dba37SThomas Bogendoerfer 
hal2_probe(struct platform_device * pdev)838e0f8cb5fSBill Pemberton static int hal2_probe(struct platform_device *pdev)
839787dba37SThomas Bogendoerfer {
840787dba37SThomas Bogendoerfer 	struct snd_card *card;
841787dba37SThomas Bogendoerfer 	struct snd_hal2 *chip;
842787dba37SThomas Bogendoerfer 	int err;
843787dba37SThomas Bogendoerfer 
844bee1bb19STakashi Iwai 	err = snd_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card);
845bd7dd77cSTakashi Iwai 	if (err < 0)
846bd7dd77cSTakashi Iwai 		return err;
847787dba37SThomas Bogendoerfer 
848787dba37SThomas Bogendoerfer 	err = hal2_create(card, &chip);
849787dba37SThomas Bogendoerfer 	if (err < 0) {
850787dba37SThomas Bogendoerfer 		snd_card_free(card);
851787dba37SThomas Bogendoerfer 		return err;
852787dba37SThomas Bogendoerfer 	}
853787dba37SThomas Bogendoerfer 
854787dba37SThomas Bogendoerfer 	err = hal2_pcm_create(chip);
855787dba37SThomas Bogendoerfer 	if (err < 0) {
856787dba37SThomas Bogendoerfer 		snd_card_free(card);
857787dba37SThomas Bogendoerfer 		return err;
858787dba37SThomas Bogendoerfer 	}
859787dba37SThomas Bogendoerfer 	err = hal2_mixer_create(chip);
860787dba37SThomas Bogendoerfer 	if (err < 0) {
861787dba37SThomas Bogendoerfer 		snd_card_free(card);
862787dba37SThomas Bogendoerfer 		return err;
863787dba37SThomas Bogendoerfer 	}
864787dba37SThomas Bogendoerfer 
865787dba37SThomas Bogendoerfer 	strcpy(card->driver, "SGI HAL2 Audio");
866787dba37SThomas Bogendoerfer 	strcpy(card->shortname, "SGI HAL2 Audio");
867787dba37SThomas Bogendoerfer 	sprintf(card->longname, "%s irq %i",
868787dba37SThomas Bogendoerfer 		card->shortname,
869787dba37SThomas Bogendoerfer 		SGI_HPCDMA_IRQ);
870787dba37SThomas Bogendoerfer 
871787dba37SThomas Bogendoerfer 	err = snd_card_register(card);
872787dba37SThomas Bogendoerfer 	if (err < 0) {
873787dba37SThomas Bogendoerfer 		snd_card_free(card);
874787dba37SThomas Bogendoerfer 		return err;
875787dba37SThomas Bogendoerfer 	}
876787dba37SThomas Bogendoerfer 	platform_set_drvdata(pdev, card);
877787dba37SThomas Bogendoerfer 	return 0;
878787dba37SThomas Bogendoerfer }
879787dba37SThomas Bogendoerfer 
hal2_remove(struct platform_device * pdev)880*b54a2377SUwe Kleine-König static void hal2_remove(struct platform_device *pdev)
881787dba37SThomas Bogendoerfer {
882787dba37SThomas Bogendoerfer 	struct snd_card *card = platform_get_drvdata(pdev);
883787dba37SThomas Bogendoerfer 
884787dba37SThomas Bogendoerfer 	snd_card_free(card);
885787dba37SThomas Bogendoerfer }
886787dba37SThomas Bogendoerfer 
887787dba37SThomas Bogendoerfer static struct platform_driver hal2_driver = {
888787dba37SThomas Bogendoerfer 	.probe	= hal2_probe,
889*b54a2377SUwe Kleine-König 	.remove_new = hal2_remove,
890787dba37SThomas Bogendoerfer 	.driver = {
891787dba37SThomas Bogendoerfer 		.name	= "sgihal2",
892787dba37SThomas Bogendoerfer 	}
893787dba37SThomas Bogendoerfer };
894787dba37SThomas Bogendoerfer 
89551451b8dSAxel Lin module_platform_driver(hal2_driver);
896