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