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(®s->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), ®s->iar);
109787dba37SThomas Bogendoerfer H2_INDIRECT_WAIT(regs);
110787dba37SThomas Bogendoerfer ret = hal2_read(®s->idr0) & 0xffff;
111787dba37SThomas Bogendoerfer hal2_write(H2_READ_ADDR(addr) | 0x1, ®s->iar);
112787dba37SThomas Bogendoerfer H2_INDIRECT_WAIT(regs);
113787dba37SThomas Bogendoerfer ret |= (hal2_read(®s->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, ®s->idr0);
122787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr1);
123787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr2);
124787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr3);
125787dba37SThomas Bogendoerfer hal2_write(H2_WRITE_ADDR(addr), ®s->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, ®s->idr0);
134787dba37SThomas Bogendoerfer hal2_write(val >> 16, ®s->idr1);
135787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr2);
136787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr3);
137787dba37SThomas Bogendoerfer hal2_write(H2_WRITE_ADDR(addr), ®s->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), ®s->iar);
146787dba37SThomas Bogendoerfer H2_INDIRECT_WAIT(regs);
147787dba37SThomas Bogendoerfer hal2_write((hal2_read(®s->idr0) & 0xffff) | bit, ®s->idr0);
148787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr1);
149787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr2);
150787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr3);
151787dba37SThomas Bogendoerfer hal2_write(H2_WRITE_ADDR(addr), ®s->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), ®s->iar);
160787dba37SThomas Bogendoerfer H2_INDIRECT_WAIT(regs);
161787dba37SThomas Bogendoerfer hal2_write((hal2_read(®s->idr0) & 0xffff) & ~bit, ®s->idr0);
162787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr1);
163787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr2);
164787dba37SThomas Bogendoerfer hal2_write(0, ®s->idr3);
165787dba37SThomas Bogendoerfer hal2_write(H2_WRITE_ADDR(addr), ®s->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