xref: /linux/sound/pci/ctxfi/cthw20k1.c (revision 8cc72361481f00253f1e468ade5795427386d593)
1*8cc72361SWai Yew CHAY /**
2*8cc72361SWai Yew CHAY  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
3*8cc72361SWai Yew CHAY  *
4*8cc72361SWai Yew CHAY  * This source file is released under GPL v2 license (no other versions).
5*8cc72361SWai Yew CHAY  * See the COPYING file included in the main directory of this source
6*8cc72361SWai Yew CHAY  * distribution for the license terms and conditions.
7*8cc72361SWai Yew CHAY  *
8*8cc72361SWai Yew CHAY  * @File	cthw20k1.c
9*8cc72361SWai Yew CHAY  *
10*8cc72361SWai Yew CHAY  * @Brief
11*8cc72361SWai Yew CHAY  * This file contains the implementation of hardware access methord for 20k1.
12*8cc72361SWai Yew CHAY  *
13*8cc72361SWai Yew CHAY  * @Author	Liu Chun
14*8cc72361SWai Yew CHAY  * @Date 	Jun 24 2008
15*8cc72361SWai Yew CHAY  *
16*8cc72361SWai Yew CHAY  */
17*8cc72361SWai Yew CHAY 
18*8cc72361SWai Yew CHAY #include "cthw20k1.h"
19*8cc72361SWai Yew CHAY #include "ct20k1reg.h"
20*8cc72361SWai Yew CHAY #include <linux/types.h>
21*8cc72361SWai Yew CHAY #include <linux/slab.h>
22*8cc72361SWai Yew CHAY #include <linux/pci.h>
23*8cc72361SWai Yew CHAY #include <linux/io.h>
24*8cc72361SWai Yew CHAY #include <linux/string.h>
25*8cc72361SWai Yew CHAY #include <linux/spinlock.h>
26*8cc72361SWai Yew CHAY #include <linux/kernel.h>
27*8cc72361SWai Yew CHAY #include <linux/interrupt.h>
28*8cc72361SWai Yew CHAY 
29*8cc72361SWai Yew CHAY #define CT_XFI_DMA_MASK		DMA_BIT_MASK(32) /* 32 bits */
30*8cc72361SWai Yew CHAY 
31*8cc72361SWai Yew CHAY struct hw20k1 {
32*8cc72361SWai Yew CHAY 	struct hw hw;
33*8cc72361SWai Yew CHAY 	spinlock_t reg_20k1_lock;
34*8cc72361SWai Yew CHAY 	spinlock_t reg_pci_lock;
35*8cc72361SWai Yew CHAY };
36*8cc72361SWai Yew CHAY 
37*8cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg);
38*8cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
39*8cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg);
40*8cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data);
41*8cc72361SWai Yew CHAY 
42*8cc72361SWai Yew CHAY /*
43*8cc72361SWai Yew CHAY  * Type definition block.
44*8cc72361SWai Yew CHAY  * The layout of control structures can be directly applied on 20k2 chip.
45*8cc72361SWai Yew CHAY  */
46*8cc72361SWai Yew CHAY 
47*8cc72361SWai Yew CHAY /*
48*8cc72361SWai Yew CHAY  * SRC control block definitions.
49*8cc72361SWai Yew CHAY  */
50*8cc72361SWai Yew CHAY 
51*8cc72361SWai Yew CHAY /* SRC resource control block */
52*8cc72361SWai Yew CHAY #define SRCCTL_STATE	0x00000007
53*8cc72361SWai Yew CHAY #define SRCCTL_BM	0x00000008
54*8cc72361SWai Yew CHAY #define SRCCTL_RSR	0x00000030
55*8cc72361SWai Yew CHAY #define SRCCTL_SF	0x000001C0
56*8cc72361SWai Yew CHAY #define SRCCTL_WR	0x00000200
57*8cc72361SWai Yew CHAY #define SRCCTL_PM	0x00000400
58*8cc72361SWai Yew CHAY #define SRCCTL_ROM	0x00001800
59*8cc72361SWai Yew CHAY #define SRCCTL_VO	0x00002000
60*8cc72361SWai Yew CHAY #define SRCCTL_ST	0x00004000
61*8cc72361SWai Yew CHAY #define SRCCTL_IE	0x00008000
62*8cc72361SWai Yew CHAY #define SRCCTL_ILSZ	0x000F0000
63*8cc72361SWai Yew CHAY #define SRCCTL_BP	0x00100000
64*8cc72361SWai Yew CHAY 
65*8cc72361SWai Yew CHAY #define SRCCCR_CISZ	0x000007FF
66*8cc72361SWai Yew CHAY #define SRCCCR_CWA	0x001FF800
67*8cc72361SWai Yew CHAY #define SRCCCR_D	0x00200000
68*8cc72361SWai Yew CHAY #define SRCCCR_RS	0x01C00000
69*8cc72361SWai Yew CHAY #define SRCCCR_NAL	0x3E000000
70*8cc72361SWai Yew CHAY #define SRCCCR_RA	0xC0000000
71*8cc72361SWai Yew CHAY 
72*8cc72361SWai Yew CHAY #define SRCCA_CA	0x03FFFFFF
73*8cc72361SWai Yew CHAY #define SRCCA_RS	0x1C000000
74*8cc72361SWai Yew CHAY #define SRCCA_NAL	0xE0000000
75*8cc72361SWai Yew CHAY 
76*8cc72361SWai Yew CHAY #define SRCSA_SA	0x03FFFFFF
77*8cc72361SWai Yew CHAY 
78*8cc72361SWai Yew CHAY #define SRCLA_LA	0x03FFFFFF
79*8cc72361SWai Yew CHAY 
80*8cc72361SWai Yew CHAY /* Mixer Parameter Ring ram Low and Hight register.
81*8cc72361SWai Yew CHAY  * Fixed-point value in 8.24 format for parameter channel */
82*8cc72361SWai Yew CHAY #define MPRLH_PITCH	0xFFFFFFFF
83*8cc72361SWai Yew CHAY 
84*8cc72361SWai Yew CHAY /* SRC resource register dirty flags */
85*8cc72361SWai Yew CHAY union src_dirty {
86*8cc72361SWai Yew CHAY 	struct {
87*8cc72361SWai Yew CHAY 		u16 ctl:1;
88*8cc72361SWai Yew CHAY 		u16 ccr:1;
89*8cc72361SWai Yew CHAY 		u16 sa:1;
90*8cc72361SWai Yew CHAY 		u16 la:1;
91*8cc72361SWai Yew CHAY 		u16 ca:1;
92*8cc72361SWai Yew CHAY 		u16 mpr:1;
93*8cc72361SWai Yew CHAY 		u16 czbfs:1;	/* Clear Z-Buffers */
94*8cc72361SWai Yew CHAY 		u16 rsv:9;
95*8cc72361SWai Yew CHAY 	} bf;
96*8cc72361SWai Yew CHAY 	u16 data;
97*8cc72361SWai Yew CHAY };
98*8cc72361SWai Yew CHAY 
99*8cc72361SWai Yew CHAY struct src_rsc_ctrl_blk {
100*8cc72361SWai Yew CHAY 	unsigned int	ctl;
101*8cc72361SWai Yew CHAY 	unsigned int 	ccr;
102*8cc72361SWai Yew CHAY 	unsigned int	ca;
103*8cc72361SWai Yew CHAY 	unsigned int	sa;
104*8cc72361SWai Yew CHAY 	unsigned int	la;
105*8cc72361SWai Yew CHAY 	unsigned int	mpr;
106*8cc72361SWai Yew CHAY 	union src_dirty	dirty;
107*8cc72361SWai Yew CHAY };
108*8cc72361SWai Yew CHAY 
109*8cc72361SWai Yew CHAY /* SRC manager control block */
110*8cc72361SWai Yew CHAY union src_mgr_dirty {
111*8cc72361SWai Yew CHAY 	struct {
112*8cc72361SWai Yew CHAY 		u16 enb0:1;
113*8cc72361SWai Yew CHAY 		u16 enb1:1;
114*8cc72361SWai Yew CHAY 		u16 enb2:1;
115*8cc72361SWai Yew CHAY 		u16 enb3:1;
116*8cc72361SWai Yew CHAY 		u16 enb4:1;
117*8cc72361SWai Yew CHAY 		u16 enb5:1;
118*8cc72361SWai Yew CHAY 		u16 enb6:1;
119*8cc72361SWai Yew CHAY 		u16 enb7:1;
120*8cc72361SWai Yew CHAY 		u16 enbsa:1;
121*8cc72361SWai Yew CHAY 		u16 rsv:7;
122*8cc72361SWai Yew CHAY 	} bf;
123*8cc72361SWai Yew CHAY 	u16 data;
124*8cc72361SWai Yew CHAY };
125*8cc72361SWai Yew CHAY 
126*8cc72361SWai Yew CHAY struct src_mgr_ctrl_blk {
127*8cc72361SWai Yew CHAY 	unsigned int		enbsa;
128*8cc72361SWai Yew CHAY 	unsigned int		enb[8];
129*8cc72361SWai Yew CHAY 	union src_mgr_dirty	dirty;
130*8cc72361SWai Yew CHAY };
131*8cc72361SWai Yew CHAY 
132*8cc72361SWai Yew CHAY /* SRCIMP manager control block */
133*8cc72361SWai Yew CHAY #define SRCAIM_ARC	0x00000FFF
134*8cc72361SWai Yew CHAY #define SRCAIM_NXT	0x00FF0000
135*8cc72361SWai Yew CHAY #define SRCAIM_SRC	0xFF000000
136*8cc72361SWai Yew CHAY 
137*8cc72361SWai Yew CHAY struct srcimap {
138*8cc72361SWai Yew CHAY 	unsigned int srcaim;
139*8cc72361SWai Yew CHAY 	unsigned int idx;
140*8cc72361SWai Yew CHAY };
141*8cc72361SWai Yew CHAY 
142*8cc72361SWai Yew CHAY /* SRCIMP manager register dirty flags */
143*8cc72361SWai Yew CHAY union srcimp_mgr_dirty {
144*8cc72361SWai Yew CHAY 	struct {
145*8cc72361SWai Yew CHAY 		u16 srcimap:1;
146*8cc72361SWai Yew CHAY 		u16 rsv:15;
147*8cc72361SWai Yew CHAY 	} bf;
148*8cc72361SWai Yew CHAY 	u16 data;
149*8cc72361SWai Yew CHAY };
150*8cc72361SWai Yew CHAY 
151*8cc72361SWai Yew CHAY struct srcimp_mgr_ctrl_blk {
152*8cc72361SWai Yew CHAY 	struct srcimap		srcimap;
153*8cc72361SWai Yew CHAY 	union srcimp_mgr_dirty	dirty;
154*8cc72361SWai Yew CHAY };
155*8cc72361SWai Yew CHAY 
156*8cc72361SWai Yew CHAY /*
157*8cc72361SWai Yew CHAY  * Function implementation block.
158*8cc72361SWai Yew CHAY  */
159*8cc72361SWai Yew CHAY 
160*8cc72361SWai Yew CHAY static int src_get_rsc_ctrl_blk(void **rblk)
161*8cc72361SWai Yew CHAY {
162*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *blk;
163*8cc72361SWai Yew CHAY 
164*8cc72361SWai Yew CHAY 	*rblk = NULL;
165*8cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
166*8cc72361SWai Yew CHAY 	if (NULL == blk)
167*8cc72361SWai Yew CHAY 		return -ENOMEM;
168*8cc72361SWai Yew CHAY 
169*8cc72361SWai Yew CHAY 	*rblk = blk;
170*8cc72361SWai Yew CHAY 
171*8cc72361SWai Yew CHAY 	return 0;
172*8cc72361SWai Yew CHAY }
173*8cc72361SWai Yew CHAY 
174*8cc72361SWai Yew CHAY static int src_put_rsc_ctrl_blk(void *blk)
175*8cc72361SWai Yew CHAY {
176*8cc72361SWai Yew CHAY 	kfree((struct src_rsc_ctrl_blk *)blk);
177*8cc72361SWai Yew CHAY 
178*8cc72361SWai Yew CHAY 	return 0;
179*8cc72361SWai Yew CHAY }
180*8cc72361SWai Yew CHAY 
181*8cc72361SWai Yew CHAY static int src_set_state(void *blk, unsigned int state)
182*8cc72361SWai Yew CHAY {
183*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
184*8cc72361SWai Yew CHAY 
185*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_STATE, state);
186*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
187*8cc72361SWai Yew CHAY 	return 0;
188*8cc72361SWai Yew CHAY }
189*8cc72361SWai Yew CHAY 
190*8cc72361SWai Yew CHAY static int src_set_bm(void *blk, unsigned int bm)
191*8cc72361SWai Yew CHAY {
192*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
193*8cc72361SWai Yew CHAY 
194*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_BM, bm);
195*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
196*8cc72361SWai Yew CHAY 	return 0;
197*8cc72361SWai Yew CHAY }
198*8cc72361SWai Yew CHAY 
199*8cc72361SWai Yew CHAY static int src_set_rsr(void *blk, unsigned int rsr)
200*8cc72361SWai Yew CHAY {
201*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
202*8cc72361SWai Yew CHAY 
203*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_RSR, rsr);
204*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
205*8cc72361SWai Yew CHAY 	return 0;
206*8cc72361SWai Yew CHAY }
207*8cc72361SWai Yew CHAY 
208*8cc72361SWai Yew CHAY static int src_set_sf(void *blk, unsigned int sf)
209*8cc72361SWai Yew CHAY {
210*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
211*8cc72361SWai Yew CHAY 
212*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_SF, sf);
213*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
214*8cc72361SWai Yew CHAY 	return 0;
215*8cc72361SWai Yew CHAY }
216*8cc72361SWai Yew CHAY 
217*8cc72361SWai Yew CHAY static int src_set_wr(void *blk, unsigned int wr)
218*8cc72361SWai Yew CHAY {
219*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
220*8cc72361SWai Yew CHAY 
221*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_WR, wr);
222*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
223*8cc72361SWai Yew CHAY 	return 0;
224*8cc72361SWai Yew CHAY }
225*8cc72361SWai Yew CHAY 
226*8cc72361SWai Yew CHAY static int src_set_pm(void *blk, unsigned int pm)
227*8cc72361SWai Yew CHAY {
228*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
229*8cc72361SWai Yew CHAY 
230*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_PM, pm);
231*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
232*8cc72361SWai Yew CHAY 	return 0;
233*8cc72361SWai Yew CHAY }
234*8cc72361SWai Yew CHAY 
235*8cc72361SWai Yew CHAY static int src_set_rom(void *blk, unsigned int rom)
236*8cc72361SWai Yew CHAY {
237*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
238*8cc72361SWai Yew CHAY 
239*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ROM, rom);
240*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
241*8cc72361SWai Yew CHAY 	return 0;
242*8cc72361SWai Yew CHAY }
243*8cc72361SWai Yew CHAY 
244*8cc72361SWai Yew CHAY static int src_set_vo(void *blk, unsigned int vo)
245*8cc72361SWai Yew CHAY {
246*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
247*8cc72361SWai Yew CHAY 
248*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_VO, vo);
249*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
250*8cc72361SWai Yew CHAY 	return 0;
251*8cc72361SWai Yew CHAY }
252*8cc72361SWai Yew CHAY 
253*8cc72361SWai Yew CHAY static int src_set_st(void *blk, unsigned int st)
254*8cc72361SWai Yew CHAY {
255*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
256*8cc72361SWai Yew CHAY 
257*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ST, st);
258*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
259*8cc72361SWai Yew CHAY 	return 0;
260*8cc72361SWai Yew CHAY }
261*8cc72361SWai Yew CHAY 
262*8cc72361SWai Yew CHAY static int src_set_ie(void *blk, unsigned int ie)
263*8cc72361SWai Yew CHAY {
264*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
265*8cc72361SWai Yew CHAY 
266*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_IE, ie);
267*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
268*8cc72361SWai Yew CHAY 	return 0;
269*8cc72361SWai Yew CHAY }
270*8cc72361SWai Yew CHAY 
271*8cc72361SWai Yew CHAY static int src_set_ilsz(void *blk, unsigned int ilsz)
272*8cc72361SWai Yew CHAY {
273*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
274*8cc72361SWai Yew CHAY 
275*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
276*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
277*8cc72361SWai Yew CHAY 	return 0;
278*8cc72361SWai Yew CHAY }
279*8cc72361SWai Yew CHAY 
280*8cc72361SWai Yew CHAY static int src_set_bp(void *blk, unsigned int bp)
281*8cc72361SWai Yew CHAY {
282*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
283*8cc72361SWai Yew CHAY 
284*8cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_BP, bp);
285*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
286*8cc72361SWai Yew CHAY 	return 0;
287*8cc72361SWai Yew CHAY }
288*8cc72361SWai Yew CHAY 
289*8cc72361SWai Yew CHAY static int src_set_cisz(void *blk, unsigned int cisz)
290*8cc72361SWai Yew CHAY {
291*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
292*8cc72361SWai Yew CHAY 
293*8cc72361SWai Yew CHAY 	set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
294*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ccr = 1;
295*8cc72361SWai Yew CHAY 	return 0;
296*8cc72361SWai Yew CHAY }
297*8cc72361SWai Yew CHAY 
298*8cc72361SWai Yew CHAY static int src_set_ca(void *blk, unsigned int ca)
299*8cc72361SWai Yew CHAY {
300*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
301*8cc72361SWai Yew CHAY 
302*8cc72361SWai Yew CHAY 	set_field(&ctl->ca, SRCCA_CA, ca);
303*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ca = 1;
304*8cc72361SWai Yew CHAY 	return 0;
305*8cc72361SWai Yew CHAY }
306*8cc72361SWai Yew CHAY 
307*8cc72361SWai Yew CHAY static int src_set_sa(void *blk, unsigned int sa)
308*8cc72361SWai Yew CHAY {
309*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
310*8cc72361SWai Yew CHAY 
311*8cc72361SWai Yew CHAY 	set_field(&ctl->sa, SRCSA_SA, sa);
312*8cc72361SWai Yew CHAY 	ctl->dirty.bf.sa = 1;
313*8cc72361SWai Yew CHAY 	return 0;
314*8cc72361SWai Yew CHAY }
315*8cc72361SWai Yew CHAY 
316*8cc72361SWai Yew CHAY static int src_set_la(void *blk, unsigned int la)
317*8cc72361SWai Yew CHAY {
318*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
319*8cc72361SWai Yew CHAY 
320*8cc72361SWai Yew CHAY 	set_field(&ctl->la, SRCLA_LA, la);
321*8cc72361SWai Yew CHAY 	ctl->dirty.bf.la = 1;
322*8cc72361SWai Yew CHAY 	return 0;
323*8cc72361SWai Yew CHAY }
324*8cc72361SWai Yew CHAY 
325*8cc72361SWai Yew CHAY static int src_set_pitch(void *blk, unsigned int pitch)
326*8cc72361SWai Yew CHAY {
327*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
328*8cc72361SWai Yew CHAY 
329*8cc72361SWai Yew CHAY 	set_field(&ctl->mpr, MPRLH_PITCH, pitch);
330*8cc72361SWai Yew CHAY 	ctl->dirty.bf.mpr = 1;
331*8cc72361SWai Yew CHAY 	return 0;
332*8cc72361SWai Yew CHAY }
333*8cc72361SWai Yew CHAY 
334*8cc72361SWai Yew CHAY static int src_set_clear_zbufs(void *blk, unsigned int clear)
335*8cc72361SWai Yew CHAY {
336*8cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
337*8cc72361SWai Yew CHAY 	return 0;
338*8cc72361SWai Yew CHAY }
339*8cc72361SWai Yew CHAY 
340*8cc72361SWai Yew CHAY static int src_set_dirty(void *blk, unsigned int flags)
341*8cc72361SWai Yew CHAY {
342*8cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
343*8cc72361SWai Yew CHAY 	return 0;
344*8cc72361SWai Yew CHAY }
345*8cc72361SWai Yew CHAY 
346*8cc72361SWai Yew CHAY static int src_set_dirty_all(void *blk)
347*8cc72361SWai Yew CHAY {
348*8cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
349*8cc72361SWai Yew CHAY 	return 0;
350*8cc72361SWai Yew CHAY }
351*8cc72361SWai Yew CHAY 
352*8cc72361SWai Yew CHAY #define AR_SLOT_SIZE		4096
353*8cc72361SWai Yew CHAY #define AR_SLOT_BLOCK_SIZE	16
354*8cc72361SWai Yew CHAY #define AR_PTS_PITCH		6
355*8cc72361SWai Yew CHAY #define AR_PARAM_SRC_OFFSET	0x60
356*8cc72361SWai Yew CHAY 
357*8cc72361SWai Yew CHAY static unsigned int src_param_pitch_mixer(unsigned int src_idx)
358*8cc72361SWai Yew CHAY {
359*8cc72361SWai Yew CHAY 	return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
360*8cc72361SWai Yew CHAY 			- AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
361*8cc72361SWai Yew CHAY 
362*8cc72361SWai Yew CHAY }
363*8cc72361SWai Yew CHAY 
364*8cc72361SWai Yew CHAY static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
365*8cc72361SWai Yew CHAY {
366*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
367*8cc72361SWai Yew CHAY 	int i = 0;
368*8cc72361SWai Yew CHAY 
369*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.czbfs) {
370*8cc72361SWai Yew CHAY 		/* Clear Z-Buffer registers */
371*8cc72361SWai Yew CHAY 		for (i = 0; i < 8; i++)
372*8cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0);
373*8cc72361SWai Yew CHAY 
374*8cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++)
375*8cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0);
376*8cc72361SWai Yew CHAY 
377*8cc72361SWai Yew CHAY 		for (i = 0; i < 8; i++)
378*8cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0);
379*8cc72361SWai Yew CHAY 
380*8cc72361SWai Yew CHAY 		ctl->dirty.bf.czbfs = 0;
381*8cc72361SWai Yew CHAY 	}
382*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.mpr) {
383*8cc72361SWai Yew CHAY 		/* Take the parameter mixer resource in the same group as that
384*8cc72361SWai Yew CHAY 		 * the idx src is in for simplicity. Unlike src, all conjugate
385*8cc72361SWai Yew CHAY 		 * parameter mixer resources must be programmed for
386*8cc72361SWai Yew CHAY 		 * corresponding conjugate src resources. */
387*8cc72361SWai Yew CHAY 		unsigned int pm_idx = src_param_pitch_mixer(idx);
388*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr);
389*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3);
390*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0);
391*8cc72361SWai Yew CHAY 		ctl->dirty.bf.mpr = 0;
392*8cc72361SWai Yew CHAY 	}
393*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.sa) {
394*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa);
395*8cc72361SWai Yew CHAY 		ctl->dirty.bf.sa = 0;
396*8cc72361SWai Yew CHAY 	}
397*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.la) {
398*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la);
399*8cc72361SWai Yew CHAY 		ctl->dirty.bf.la = 0;
400*8cc72361SWai Yew CHAY 	}
401*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ca) {
402*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca);
403*8cc72361SWai Yew CHAY 		ctl->dirty.bf.ca = 0;
404*8cc72361SWai Yew CHAY 	}
405*8cc72361SWai Yew CHAY 
406*8cc72361SWai Yew CHAY 	/* Write srccf register */
407*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCCF+idx*0x100, 0x0);
408*8cc72361SWai Yew CHAY 
409*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ccr) {
410*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr);
411*8cc72361SWai Yew CHAY 		ctl->dirty.bf.ccr = 0;
412*8cc72361SWai Yew CHAY 	}
413*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ctl) {
414*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl);
415*8cc72361SWai Yew CHAY 		ctl->dirty.bf.ctl = 0;
416*8cc72361SWai Yew CHAY 	}
417*8cc72361SWai Yew CHAY 
418*8cc72361SWai Yew CHAY 	return 0;
419*8cc72361SWai Yew CHAY }
420*8cc72361SWai Yew CHAY 
421*8cc72361SWai Yew CHAY static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
422*8cc72361SWai Yew CHAY {
423*8cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
424*8cc72361SWai Yew CHAY 
425*8cc72361SWai Yew CHAY 	ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100);
426*8cc72361SWai Yew CHAY 	ctl->dirty.bf.ca = 0;
427*8cc72361SWai Yew CHAY 
428*8cc72361SWai Yew CHAY 	return get_field(ctl->ca, SRCCA_CA);
429*8cc72361SWai Yew CHAY }
430*8cc72361SWai Yew CHAY 
431*8cc72361SWai Yew CHAY static unsigned int src_get_dirty(void *blk)
432*8cc72361SWai Yew CHAY {
433*8cc72361SWai Yew CHAY 	return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
434*8cc72361SWai Yew CHAY }
435*8cc72361SWai Yew CHAY 
436*8cc72361SWai Yew CHAY static unsigned int src_dirty_conj_mask(void)
437*8cc72361SWai Yew CHAY {
438*8cc72361SWai Yew CHAY 	return 0x20;
439*8cc72361SWai Yew CHAY }
440*8cc72361SWai Yew CHAY 
441*8cc72361SWai Yew CHAY static int src_mgr_enbs_src(void *blk, unsigned int idx)
442*8cc72361SWai Yew CHAY {
443*8cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0);
444*8cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
445*8cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
446*8cc72361SWai Yew CHAY 	return 0;
447*8cc72361SWai Yew CHAY }
448*8cc72361SWai Yew CHAY 
449*8cc72361SWai Yew CHAY static int src_mgr_enb_src(void *blk, unsigned int idx)
450*8cc72361SWai Yew CHAY {
451*8cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
452*8cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
453*8cc72361SWai Yew CHAY 	return 0;
454*8cc72361SWai Yew CHAY }
455*8cc72361SWai Yew CHAY 
456*8cc72361SWai Yew CHAY static int src_mgr_dsb_src(void *blk, unsigned int idx)
457*8cc72361SWai Yew CHAY {
458*8cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
459*8cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
460*8cc72361SWai Yew CHAY 	return 0;
461*8cc72361SWai Yew CHAY }
462*8cc72361SWai Yew CHAY 
463*8cc72361SWai Yew CHAY static int src_mgr_commit_write(struct hw *hw, void *blk)
464*8cc72361SWai Yew CHAY {
465*8cc72361SWai Yew CHAY 	struct src_mgr_ctrl_blk *ctl = blk;
466*8cc72361SWai Yew CHAY 	int i = 0;
467*8cc72361SWai Yew CHAY 	unsigned int ret = 0;
468*8cc72361SWai Yew CHAY 
469*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.enbsa) {
470*8cc72361SWai Yew CHAY 		do {
471*8cc72361SWai Yew CHAY 			ret = hw_read_20kx(hw, SRCENBSTAT);
472*8cc72361SWai Yew CHAY 		} while (ret & 0x1);
473*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCENBS, ctl->enbsa);
474*8cc72361SWai Yew CHAY 		ctl->dirty.bf.enbsa = 0;
475*8cc72361SWai Yew CHAY 	}
476*8cc72361SWai Yew CHAY 	for (i = 0; i < 8; i++) {
477*8cc72361SWai Yew CHAY 		if ((ctl->dirty.data & (0x1 << i))) {
478*8cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]);
479*8cc72361SWai Yew CHAY 			ctl->dirty.data &= ~(0x1 << i);
480*8cc72361SWai Yew CHAY 		}
481*8cc72361SWai Yew CHAY 	}
482*8cc72361SWai Yew CHAY 
483*8cc72361SWai Yew CHAY 	return 0;
484*8cc72361SWai Yew CHAY }
485*8cc72361SWai Yew CHAY 
486*8cc72361SWai Yew CHAY static int src_mgr_get_ctrl_blk(void **rblk)
487*8cc72361SWai Yew CHAY {
488*8cc72361SWai Yew CHAY 	struct src_mgr_ctrl_blk *blk;
489*8cc72361SWai Yew CHAY 
490*8cc72361SWai Yew CHAY 	*rblk = NULL;
491*8cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
492*8cc72361SWai Yew CHAY 	if (NULL == blk)
493*8cc72361SWai Yew CHAY 		return -ENOMEM;
494*8cc72361SWai Yew CHAY 
495*8cc72361SWai Yew CHAY 	*rblk = blk;
496*8cc72361SWai Yew CHAY 
497*8cc72361SWai Yew CHAY 	return 0;
498*8cc72361SWai Yew CHAY }
499*8cc72361SWai Yew CHAY 
500*8cc72361SWai Yew CHAY static int src_mgr_put_ctrl_blk(void *blk)
501*8cc72361SWai Yew CHAY {
502*8cc72361SWai Yew CHAY 	kfree((struct src_mgr_ctrl_blk *)blk);
503*8cc72361SWai Yew CHAY 
504*8cc72361SWai Yew CHAY 	return 0;
505*8cc72361SWai Yew CHAY }
506*8cc72361SWai Yew CHAY 
507*8cc72361SWai Yew CHAY static int srcimp_mgr_get_ctrl_blk(void **rblk)
508*8cc72361SWai Yew CHAY {
509*8cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *blk;
510*8cc72361SWai Yew CHAY 
511*8cc72361SWai Yew CHAY 	*rblk = NULL;
512*8cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
513*8cc72361SWai Yew CHAY 	if (NULL == blk)
514*8cc72361SWai Yew CHAY 		return -ENOMEM;
515*8cc72361SWai Yew CHAY 
516*8cc72361SWai Yew CHAY 	*rblk = blk;
517*8cc72361SWai Yew CHAY 
518*8cc72361SWai Yew CHAY 	return 0;
519*8cc72361SWai Yew CHAY }
520*8cc72361SWai Yew CHAY 
521*8cc72361SWai Yew CHAY static int srcimp_mgr_put_ctrl_blk(void *blk)
522*8cc72361SWai Yew CHAY {
523*8cc72361SWai Yew CHAY 	kfree((struct srcimp_mgr_ctrl_blk *)blk);
524*8cc72361SWai Yew CHAY 
525*8cc72361SWai Yew CHAY 	return 0;
526*8cc72361SWai Yew CHAY }
527*8cc72361SWai Yew CHAY 
528*8cc72361SWai Yew CHAY static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
529*8cc72361SWai Yew CHAY {
530*8cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
531*8cc72361SWai Yew CHAY 
532*8cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
533*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
534*8cc72361SWai Yew CHAY 	return 0;
535*8cc72361SWai Yew CHAY }
536*8cc72361SWai Yew CHAY 
537*8cc72361SWai Yew CHAY static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
538*8cc72361SWai Yew CHAY {
539*8cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
540*8cc72361SWai Yew CHAY 
541*8cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
542*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
543*8cc72361SWai Yew CHAY 	return 0;
544*8cc72361SWai Yew CHAY }
545*8cc72361SWai Yew CHAY 
546*8cc72361SWai Yew CHAY static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
547*8cc72361SWai Yew CHAY {
548*8cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
549*8cc72361SWai Yew CHAY 
550*8cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
551*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
552*8cc72361SWai Yew CHAY 	return 0;
553*8cc72361SWai Yew CHAY }
554*8cc72361SWai Yew CHAY 
555*8cc72361SWai Yew CHAY static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
556*8cc72361SWai Yew CHAY {
557*8cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
558*8cc72361SWai Yew CHAY 
559*8cc72361SWai Yew CHAY 	ctl->srcimap.idx = addr;
560*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
561*8cc72361SWai Yew CHAY 	return 0;
562*8cc72361SWai Yew CHAY }
563*8cc72361SWai Yew CHAY 
564*8cc72361SWai Yew CHAY static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
565*8cc72361SWai Yew CHAY {
566*8cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
567*8cc72361SWai Yew CHAY 
568*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.srcimap) {
569*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100,
570*8cc72361SWai Yew CHAY 						ctl->srcimap.srcaim);
571*8cc72361SWai Yew CHAY 		ctl->dirty.bf.srcimap = 0;
572*8cc72361SWai Yew CHAY 	}
573*8cc72361SWai Yew CHAY 
574*8cc72361SWai Yew CHAY 	return 0;
575*8cc72361SWai Yew CHAY }
576*8cc72361SWai Yew CHAY 
577*8cc72361SWai Yew CHAY /*
578*8cc72361SWai Yew CHAY  * AMIXER control block definitions.
579*8cc72361SWai Yew CHAY  */
580*8cc72361SWai Yew CHAY 
581*8cc72361SWai Yew CHAY #define AMOPLO_M	0x00000003
582*8cc72361SWai Yew CHAY #define AMOPLO_X	0x0003FFF0
583*8cc72361SWai Yew CHAY #define AMOPLO_Y	0xFFFC0000
584*8cc72361SWai Yew CHAY 
585*8cc72361SWai Yew CHAY #define AMOPHI_SADR	0x000000FF
586*8cc72361SWai Yew CHAY #define AMOPHI_SE	0x80000000
587*8cc72361SWai Yew CHAY 
588*8cc72361SWai Yew CHAY /* AMIXER resource register dirty flags */
589*8cc72361SWai Yew CHAY union amixer_dirty {
590*8cc72361SWai Yew CHAY 	struct {
591*8cc72361SWai Yew CHAY 		u16 amoplo:1;
592*8cc72361SWai Yew CHAY 		u16 amophi:1;
593*8cc72361SWai Yew CHAY 		u16 rsv:14;
594*8cc72361SWai Yew CHAY 	} bf;
595*8cc72361SWai Yew CHAY 	u16 data;
596*8cc72361SWai Yew CHAY };
597*8cc72361SWai Yew CHAY 
598*8cc72361SWai Yew CHAY /* AMIXER resource control block */
599*8cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk {
600*8cc72361SWai Yew CHAY 	unsigned int		amoplo;
601*8cc72361SWai Yew CHAY 	unsigned int		amophi;
602*8cc72361SWai Yew CHAY 	union amixer_dirty	dirty;
603*8cc72361SWai Yew CHAY };
604*8cc72361SWai Yew CHAY 
605*8cc72361SWai Yew CHAY static int amixer_set_mode(void *blk, unsigned int mode)
606*8cc72361SWai Yew CHAY {
607*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
608*8cc72361SWai Yew CHAY 
609*8cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_M, mode);
610*8cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
611*8cc72361SWai Yew CHAY 	return 0;
612*8cc72361SWai Yew CHAY }
613*8cc72361SWai Yew CHAY 
614*8cc72361SWai Yew CHAY static int amixer_set_iv(void *blk, unsigned int iv)
615*8cc72361SWai Yew CHAY {
616*8cc72361SWai Yew CHAY 	/* 20k1 amixer does not have this field */
617*8cc72361SWai Yew CHAY 	return 0;
618*8cc72361SWai Yew CHAY }
619*8cc72361SWai Yew CHAY 
620*8cc72361SWai Yew CHAY static int amixer_set_x(void *blk, unsigned int x)
621*8cc72361SWai Yew CHAY {
622*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
623*8cc72361SWai Yew CHAY 
624*8cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_X, x);
625*8cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
626*8cc72361SWai Yew CHAY 	return 0;
627*8cc72361SWai Yew CHAY }
628*8cc72361SWai Yew CHAY 
629*8cc72361SWai Yew CHAY static int amixer_set_y(void *blk, unsigned int y)
630*8cc72361SWai Yew CHAY {
631*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
632*8cc72361SWai Yew CHAY 
633*8cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_Y, y);
634*8cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
635*8cc72361SWai Yew CHAY 	return 0;
636*8cc72361SWai Yew CHAY }
637*8cc72361SWai Yew CHAY 
638*8cc72361SWai Yew CHAY static int amixer_set_sadr(void *blk, unsigned int sadr)
639*8cc72361SWai Yew CHAY {
640*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
641*8cc72361SWai Yew CHAY 
642*8cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SADR, sadr);
643*8cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
644*8cc72361SWai Yew CHAY 	return 0;
645*8cc72361SWai Yew CHAY }
646*8cc72361SWai Yew CHAY 
647*8cc72361SWai Yew CHAY static int amixer_set_se(void *blk, unsigned int se)
648*8cc72361SWai Yew CHAY {
649*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
650*8cc72361SWai Yew CHAY 
651*8cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SE, se);
652*8cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
653*8cc72361SWai Yew CHAY 	return 0;
654*8cc72361SWai Yew CHAY }
655*8cc72361SWai Yew CHAY 
656*8cc72361SWai Yew CHAY static int amixer_set_dirty(void *blk, unsigned int flags)
657*8cc72361SWai Yew CHAY {
658*8cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
659*8cc72361SWai Yew CHAY 	return 0;
660*8cc72361SWai Yew CHAY }
661*8cc72361SWai Yew CHAY 
662*8cc72361SWai Yew CHAY static int amixer_set_dirty_all(void *blk)
663*8cc72361SWai Yew CHAY {
664*8cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
665*8cc72361SWai Yew CHAY 	return 0;
666*8cc72361SWai Yew CHAY }
667*8cc72361SWai Yew CHAY 
668*8cc72361SWai Yew CHAY static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
669*8cc72361SWai Yew CHAY {
670*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
671*8cc72361SWai Yew CHAY 
672*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
673*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo);
674*8cc72361SWai Yew CHAY 		ctl->dirty.bf.amoplo = 0;
675*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi);
676*8cc72361SWai Yew CHAY 		ctl->dirty.bf.amophi = 0;
677*8cc72361SWai Yew CHAY 	}
678*8cc72361SWai Yew CHAY 
679*8cc72361SWai Yew CHAY 	return 0;
680*8cc72361SWai Yew CHAY }
681*8cc72361SWai Yew CHAY 
682*8cc72361SWai Yew CHAY static int amixer_get_y(void *blk)
683*8cc72361SWai Yew CHAY {
684*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
685*8cc72361SWai Yew CHAY 
686*8cc72361SWai Yew CHAY 	return get_field(ctl->amoplo, AMOPLO_Y);
687*8cc72361SWai Yew CHAY }
688*8cc72361SWai Yew CHAY 
689*8cc72361SWai Yew CHAY static unsigned int amixer_get_dirty(void *blk)
690*8cc72361SWai Yew CHAY {
691*8cc72361SWai Yew CHAY 	return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
692*8cc72361SWai Yew CHAY }
693*8cc72361SWai Yew CHAY 
694*8cc72361SWai Yew CHAY static int amixer_rsc_get_ctrl_blk(void **rblk)
695*8cc72361SWai Yew CHAY {
696*8cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *blk;
697*8cc72361SWai Yew CHAY 
698*8cc72361SWai Yew CHAY 	*rblk = NULL;
699*8cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
700*8cc72361SWai Yew CHAY 	if (NULL == blk)
701*8cc72361SWai Yew CHAY 		return -ENOMEM;
702*8cc72361SWai Yew CHAY 
703*8cc72361SWai Yew CHAY 	*rblk = blk;
704*8cc72361SWai Yew CHAY 
705*8cc72361SWai Yew CHAY 	return 0;
706*8cc72361SWai Yew CHAY }
707*8cc72361SWai Yew CHAY 
708*8cc72361SWai Yew CHAY static int amixer_rsc_put_ctrl_blk(void *blk)
709*8cc72361SWai Yew CHAY {
710*8cc72361SWai Yew CHAY 	kfree((struct amixer_rsc_ctrl_blk *)blk);
711*8cc72361SWai Yew CHAY 
712*8cc72361SWai Yew CHAY 	return 0;
713*8cc72361SWai Yew CHAY }
714*8cc72361SWai Yew CHAY 
715*8cc72361SWai Yew CHAY static int amixer_mgr_get_ctrl_blk(void **rblk)
716*8cc72361SWai Yew CHAY {
717*8cc72361SWai Yew CHAY 	/*amixer_mgr_ctrl_blk_t *blk;*/
718*8cc72361SWai Yew CHAY 
719*8cc72361SWai Yew CHAY 	*rblk = NULL;
720*8cc72361SWai Yew CHAY 	/*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
721*8cc72361SWai Yew CHAY 	if (NULL == blk)
722*8cc72361SWai Yew CHAY 		return -ENOMEM;
723*8cc72361SWai Yew CHAY 
724*8cc72361SWai Yew CHAY 	*rblk = blk;*/
725*8cc72361SWai Yew CHAY 
726*8cc72361SWai Yew CHAY 	return 0;
727*8cc72361SWai Yew CHAY }
728*8cc72361SWai Yew CHAY 
729*8cc72361SWai Yew CHAY static int amixer_mgr_put_ctrl_blk(void *blk)
730*8cc72361SWai Yew CHAY {
731*8cc72361SWai Yew CHAY 	/*kfree((amixer_mgr_ctrl_blk_t *)blk);*/
732*8cc72361SWai Yew CHAY 
733*8cc72361SWai Yew CHAY 	return 0;
734*8cc72361SWai Yew CHAY }
735*8cc72361SWai Yew CHAY 
736*8cc72361SWai Yew CHAY /*
737*8cc72361SWai Yew CHAY  * DAIO control block definitions.
738*8cc72361SWai Yew CHAY  */
739*8cc72361SWai Yew CHAY 
740*8cc72361SWai Yew CHAY /* Receiver Sample Rate Tracker Control register */
741*8cc72361SWai Yew CHAY #define SRTCTL_SRCR	0x000000FF
742*8cc72361SWai Yew CHAY #define SRTCTL_SRCL	0x0000FF00
743*8cc72361SWai Yew CHAY #define SRTCTL_RSR	0x00030000
744*8cc72361SWai Yew CHAY #define SRTCTL_DRAT	0x000C0000
745*8cc72361SWai Yew CHAY #define SRTCTL_RLE	0x10000000
746*8cc72361SWai Yew CHAY #define SRTCTL_RLP	0x20000000
747*8cc72361SWai Yew CHAY #define SRTCTL_EC	0x40000000
748*8cc72361SWai Yew CHAY #define SRTCTL_ET	0x80000000
749*8cc72361SWai Yew CHAY 
750*8cc72361SWai Yew CHAY /* DAIO Receiver register dirty flags */
751*8cc72361SWai Yew CHAY union dai_dirty {
752*8cc72361SWai Yew CHAY 	struct {
753*8cc72361SWai Yew CHAY 		u16 srtctl:1;
754*8cc72361SWai Yew CHAY 		u16 rsv:15;
755*8cc72361SWai Yew CHAY 	} bf;
756*8cc72361SWai Yew CHAY 	u16 data;
757*8cc72361SWai Yew CHAY };
758*8cc72361SWai Yew CHAY 
759*8cc72361SWai Yew CHAY /* DAIO Receiver control block */
760*8cc72361SWai Yew CHAY struct dai_ctrl_blk {
761*8cc72361SWai Yew CHAY 	unsigned int	srtctl;
762*8cc72361SWai Yew CHAY 	union dai_dirty	dirty;
763*8cc72361SWai Yew CHAY };
764*8cc72361SWai Yew CHAY 
765*8cc72361SWai Yew CHAY /* S/PDIF Transmitter register dirty flags */
766*8cc72361SWai Yew CHAY union dao_dirty {
767*8cc72361SWai Yew CHAY 	struct {
768*8cc72361SWai Yew CHAY 		u16 spos:1;
769*8cc72361SWai Yew CHAY 		u16 rsv:15;
770*8cc72361SWai Yew CHAY 	} bf;
771*8cc72361SWai Yew CHAY 	u16 data;
772*8cc72361SWai Yew CHAY };
773*8cc72361SWai Yew CHAY 
774*8cc72361SWai Yew CHAY /* S/PDIF Transmitter control block */
775*8cc72361SWai Yew CHAY struct dao_ctrl_blk {
776*8cc72361SWai Yew CHAY 	unsigned int 	spos; /* S/PDIF Output Channel Status Register */
777*8cc72361SWai Yew CHAY 	union dao_dirty	dirty;
778*8cc72361SWai Yew CHAY };
779*8cc72361SWai Yew CHAY 
780*8cc72361SWai Yew CHAY /* Audio Input Mapper RAM */
781*8cc72361SWai Yew CHAY #define AIM_ARC		0x00000FFF
782*8cc72361SWai Yew CHAY #define AIM_NXT		0x007F0000
783*8cc72361SWai Yew CHAY 
784*8cc72361SWai Yew CHAY struct daoimap {
785*8cc72361SWai Yew CHAY 	unsigned int aim;
786*8cc72361SWai Yew CHAY 	unsigned int idx;
787*8cc72361SWai Yew CHAY };
788*8cc72361SWai Yew CHAY 
789*8cc72361SWai Yew CHAY /* I2S Transmitter/Receiver Control register */
790*8cc72361SWai Yew CHAY #define I2SCTL_EA	0x00000004
791*8cc72361SWai Yew CHAY #define I2SCTL_EI	0x00000010
792*8cc72361SWai Yew CHAY 
793*8cc72361SWai Yew CHAY /* S/PDIF Transmitter Control register */
794*8cc72361SWai Yew CHAY #define SPOCTL_OE	0x00000001
795*8cc72361SWai Yew CHAY #define SPOCTL_OS	0x0000000E
796*8cc72361SWai Yew CHAY #define SPOCTL_RIV	0x00000010
797*8cc72361SWai Yew CHAY #define SPOCTL_LIV	0x00000020
798*8cc72361SWai Yew CHAY #define SPOCTL_SR	0x000000C0
799*8cc72361SWai Yew CHAY 
800*8cc72361SWai Yew CHAY /* S/PDIF Receiver Control register */
801*8cc72361SWai Yew CHAY #define SPICTL_EN	0x00000001
802*8cc72361SWai Yew CHAY #define SPICTL_I24	0x00000002
803*8cc72361SWai Yew CHAY #define SPICTL_IB	0x00000004
804*8cc72361SWai Yew CHAY #define SPICTL_SM	0x00000008
805*8cc72361SWai Yew CHAY #define SPICTL_VM	0x00000010
806*8cc72361SWai Yew CHAY 
807*8cc72361SWai Yew CHAY /* DAIO manager register dirty flags */
808*8cc72361SWai Yew CHAY union daio_mgr_dirty {
809*8cc72361SWai Yew CHAY 	struct {
810*8cc72361SWai Yew CHAY 		u32 i2soctl:4;
811*8cc72361SWai Yew CHAY 		u32 i2sictl:4;
812*8cc72361SWai Yew CHAY 		u32 spoctl:4;
813*8cc72361SWai Yew CHAY 		u32 spictl:4;
814*8cc72361SWai Yew CHAY 		u32 daoimap:1;
815*8cc72361SWai Yew CHAY 		u32 rsv:15;
816*8cc72361SWai Yew CHAY 	} bf;
817*8cc72361SWai Yew CHAY 	u32 data;
818*8cc72361SWai Yew CHAY };
819*8cc72361SWai Yew CHAY 
820*8cc72361SWai Yew CHAY /* DAIO manager control block */
821*8cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk {
822*8cc72361SWai Yew CHAY 	unsigned int		i2sctl;
823*8cc72361SWai Yew CHAY 	unsigned int		spoctl;
824*8cc72361SWai Yew CHAY 	unsigned int		spictl;
825*8cc72361SWai Yew CHAY 	struct daoimap		daoimap;
826*8cc72361SWai Yew CHAY 	union daio_mgr_dirty	dirty;
827*8cc72361SWai Yew CHAY };
828*8cc72361SWai Yew CHAY 
829*8cc72361SWai Yew CHAY static int dai_srt_set_srcr(void *blk, unsigned int src)
830*8cc72361SWai Yew CHAY {
831*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
832*8cc72361SWai Yew CHAY 
833*8cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_SRCR, src);
834*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
835*8cc72361SWai Yew CHAY 	return 0;
836*8cc72361SWai Yew CHAY }
837*8cc72361SWai Yew CHAY 
838*8cc72361SWai Yew CHAY static int dai_srt_set_srcl(void *blk, unsigned int src)
839*8cc72361SWai Yew CHAY {
840*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
841*8cc72361SWai Yew CHAY 
842*8cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_SRCL, src);
843*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
844*8cc72361SWai Yew CHAY 	return 0;
845*8cc72361SWai Yew CHAY }
846*8cc72361SWai Yew CHAY 
847*8cc72361SWai Yew CHAY static int dai_srt_set_rsr(void *blk, unsigned int rsr)
848*8cc72361SWai Yew CHAY {
849*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
850*8cc72361SWai Yew CHAY 
851*8cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_RSR, rsr);
852*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
853*8cc72361SWai Yew CHAY 	return 0;
854*8cc72361SWai Yew CHAY }
855*8cc72361SWai Yew CHAY 
856*8cc72361SWai Yew CHAY static int dai_srt_set_drat(void *blk, unsigned int drat)
857*8cc72361SWai Yew CHAY {
858*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
859*8cc72361SWai Yew CHAY 
860*8cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_DRAT, drat);
861*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
862*8cc72361SWai Yew CHAY 	return 0;
863*8cc72361SWai Yew CHAY }
864*8cc72361SWai Yew CHAY 
865*8cc72361SWai Yew CHAY static int dai_srt_set_ec(void *blk, unsigned int ec)
866*8cc72361SWai Yew CHAY {
867*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
868*8cc72361SWai Yew CHAY 
869*8cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0);
870*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
871*8cc72361SWai Yew CHAY 	return 0;
872*8cc72361SWai Yew CHAY }
873*8cc72361SWai Yew CHAY 
874*8cc72361SWai Yew CHAY static int dai_srt_set_et(void *blk, unsigned int et)
875*8cc72361SWai Yew CHAY {
876*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
877*8cc72361SWai Yew CHAY 
878*8cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0);
879*8cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
880*8cc72361SWai Yew CHAY 	return 0;
881*8cc72361SWai Yew CHAY }
882*8cc72361SWai Yew CHAY 
883*8cc72361SWai Yew CHAY static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
884*8cc72361SWai Yew CHAY {
885*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
886*8cc72361SWai Yew CHAY 
887*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.srtctl) {
888*8cc72361SWai Yew CHAY 		if (idx < 4) {
889*8cc72361SWai Yew CHAY 			/* S/PDIF SRTs */
890*8cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl);
891*8cc72361SWai Yew CHAY 		} else {
892*8cc72361SWai Yew CHAY 			/* I2S SRT */
893*8cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRTICTL, ctl->srtctl);
894*8cc72361SWai Yew CHAY 		}
895*8cc72361SWai Yew CHAY 		ctl->dirty.bf.srtctl = 0;
896*8cc72361SWai Yew CHAY 	}
897*8cc72361SWai Yew CHAY 
898*8cc72361SWai Yew CHAY 	return 0;
899*8cc72361SWai Yew CHAY }
900*8cc72361SWai Yew CHAY 
901*8cc72361SWai Yew CHAY static int dai_get_ctrl_blk(void **rblk)
902*8cc72361SWai Yew CHAY {
903*8cc72361SWai Yew CHAY 	struct dai_ctrl_blk *blk;
904*8cc72361SWai Yew CHAY 
905*8cc72361SWai Yew CHAY 	*rblk = NULL;
906*8cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
907*8cc72361SWai Yew CHAY 	if (NULL == blk)
908*8cc72361SWai Yew CHAY 		return -ENOMEM;
909*8cc72361SWai Yew CHAY 
910*8cc72361SWai Yew CHAY 	*rblk = blk;
911*8cc72361SWai Yew CHAY 
912*8cc72361SWai Yew CHAY 	return 0;
913*8cc72361SWai Yew CHAY }
914*8cc72361SWai Yew CHAY 
915*8cc72361SWai Yew CHAY static int dai_put_ctrl_blk(void *blk)
916*8cc72361SWai Yew CHAY {
917*8cc72361SWai Yew CHAY 	kfree((struct dai_ctrl_blk *)blk);
918*8cc72361SWai Yew CHAY 
919*8cc72361SWai Yew CHAY 	return 0;
920*8cc72361SWai Yew CHAY }
921*8cc72361SWai Yew CHAY 
922*8cc72361SWai Yew CHAY static int dao_set_spos(void *blk, unsigned int spos)
923*8cc72361SWai Yew CHAY {
924*8cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->spos = spos;
925*8cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1;
926*8cc72361SWai Yew CHAY 	return 0;
927*8cc72361SWai Yew CHAY }
928*8cc72361SWai Yew CHAY 
929*8cc72361SWai Yew CHAY static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
930*8cc72361SWai Yew CHAY {
931*8cc72361SWai Yew CHAY 	struct dao_ctrl_blk *ctl = blk;
932*8cc72361SWai Yew CHAY 
933*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spos) {
934*8cc72361SWai Yew CHAY 		if (idx < 4) {
935*8cc72361SWai Yew CHAY 			/* S/PDIF SPOSx */
936*8cc72361SWai Yew CHAY 			hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos);
937*8cc72361SWai Yew CHAY 		}
938*8cc72361SWai Yew CHAY 		ctl->dirty.bf.spos = 0;
939*8cc72361SWai Yew CHAY 	}
940*8cc72361SWai Yew CHAY 
941*8cc72361SWai Yew CHAY 	return 0;
942*8cc72361SWai Yew CHAY }
943*8cc72361SWai Yew CHAY 
944*8cc72361SWai Yew CHAY static int dao_get_spos(void *blk, unsigned int *spos)
945*8cc72361SWai Yew CHAY {
946*8cc72361SWai Yew CHAY 	*spos = ((struct dao_ctrl_blk *)blk)->spos;
947*8cc72361SWai Yew CHAY 	return 0;
948*8cc72361SWai Yew CHAY }
949*8cc72361SWai Yew CHAY 
950*8cc72361SWai Yew CHAY static int dao_get_ctrl_blk(void **rblk)
951*8cc72361SWai Yew CHAY {
952*8cc72361SWai Yew CHAY 	struct dao_ctrl_blk *blk;
953*8cc72361SWai Yew CHAY 
954*8cc72361SWai Yew CHAY 	*rblk = NULL;
955*8cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
956*8cc72361SWai Yew CHAY 	if (NULL == blk)
957*8cc72361SWai Yew CHAY 		return -ENOMEM;
958*8cc72361SWai Yew CHAY 
959*8cc72361SWai Yew CHAY 	*rblk = blk;
960*8cc72361SWai Yew CHAY 
961*8cc72361SWai Yew CHAY 	return 0;
962*8cc72361SWai Yew CHAY }
963*8cc72361SWai Yew CHAY 
964*8cc72361SWai Yew CHAY static int dao_put_ctrl_blk(void *blk)
965*8cc72361SWai Yew CHAY {
966*8cc72361SWai Yew CHAY 	kfree((struct dao_ctrl_blk *)blk);
967*8cc72361SWai Yew CHAY 
968*8cc72361SWai Yew CHAY 	return 0;
969*8cc72361SWai Yew CHAY }
970*8cc72361SWai Yew CHAY 
971*8cc72361SWai Yew CHAY static int daio_mgr_enb_dai(void *blk, unsigned int idx)
972*8cc72361SWai Yew CHAY {
973*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
974*8cc72361SWai Yew CHAY 
975*8cc72361SWai Yew CHAY 	if (idx < 4) {
976*8cc72361SWai Yew CHAY 		/* S/PDIF input */
977*8cc72361SWai Yew CHAY 		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1);
978*8cc72361SWai Yew CHAY 		ctl->dirty.bf.spictl |= (0x1 << idx);
979*8cc72361SWai Yew CHAY 	} else {
980*8cc72361SWai Yew CHAY 		/* I2S input */
981*8cc72361SWai Yew CHAY 		idx %= 4;
982*8cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1);
983*8cc72361SWai Yew CHAY 		ctl->dirty.bf.i2sictl |= (0x1 << idx);
984*8cc72361SWai Yew CHAY 	}
985*8cc72361SWai Yew CHAY 	return 0;
986*8cc72361SWai Yew CHAY }
987*8cc72361SWai Yew CHAY 
988*8cc72361SWai Yew CHAY static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
989*8cc72361SWai Yew CHAY {
990*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
991*8cc72361SWai Yew CHAY 
992*8cc72361SWai Yew CHAY 	if (idx < 4) {
993*8cc72361SWai Yew CHAY 		/* S/PDIF input */
994*8cc72361SWai Yew CHAY 		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0);
995*8cc72361SWai Yew CHAY 		ctl->dirty.bf.spictl |= (0x1 << idx);
996*8cc72361SWai Yew CHAY 	} else {
997*8cc72361SWai Yew CHAY 		/* I2S input */
998*8cc72361SWai Yew CHAY 		idx %= 4;
999*8cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0);
1000*8cc72361SWai Yew CHAY 		ctl->dirty.bf.i2sictl |= (0x1 << idx);
1001*8cc72361SWai Yew CHAY 	}
1002*8cc72361SWai Yew CHAY 	return 0;
1003*8cc72361SWai Yew CHAY }
1004*8cc72361SWai Yew CHAY 
1005*8cc72361SWai Yew CHAY static int daio_mgr_enb_dao(void *blk, unsigned int idx)
1006*8cc72361SWai Yew CHAY {
1007*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1008*8cc72361SWai Yew CHAY 
1009*8cc72361SWai Yew CHAY 	if (idx < 4) {
1010*8cc72361SWai Yew CHAY 		/* S/PDIF output */
1011*8cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1);
1012*8cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
1013*8cc72361SWai Yew CHAY 	} else {
1014*8cc72361SWai Yew CHAY 		/* I2S output */
1015*8cc72361SWai Yew CHAY 		idx %= 4;
1016*8cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1);
1017*8cc72361SWai Yew CHAY 		ctl->dirty.bf.i2soctl |= (0x1 << idx);
1018*8cc72361SWai Yew CHAY 	}
1019*8cc72361SWai Yew CHAY 	return 0;
1020*8cc72361SWai Yew CHAY }
1021*8cc72361SWai Yew CHAY 
1022*8cc72361SWai Yew CHAY static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
1023*8cc72361SWai Yew CHAY {
1024*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1025*8cc72361SWai Yew CHAY 
1026*8cc72361SWai Yew CHAY 	if (idx < 4) {
1027*8cc72361SWai Yew CHAY 		/* S/PDIF output */
1028*8cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0);
1029*8cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
1030*8cc72361SWai Yew CHAY 	} else {
1031*8cc72361SWai Yew CHAY 		/* I2S output */
1032*8cc72361SWai Yew CHAY 		idx %= 4;
1033*8cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0);
1034*8cc72361SWai Yew CHAY 		ctl->dirty.bf.i2soctl |= (0x1 << idx);
1035*8cc72361SWai Yew CHAY 	}
1036*8cc72361SWai Yew CHAY 	return 0;
1037*8cc72361SWai Yew CHAY }
1038*8cc72361SWai Yew CHAY 
1039*8cc72361SWai Yew CHAY static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
1040*8cc72361SWai Yew CHAY {
1041*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1042*8cc72361SWai Yew CHAY 
1043*8cc72361SWai Yew CHAY 	if (idx < 4) {
1044*8cc72361SWai Yew CHAY 		/* S/PDIF output */
1045*8cc72361SWai Yew CHAY 		switch ((conf & 0x7)) {
1046*8cc72361SWai Yew CHAY 		case 0:
1047*8cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3);
1048*8cc72361SWai Yew CHAY 			break; /* CDIF */
1049*8cc72361SWai Yew CHAY 		case 1:
1050*8cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0);
1051*8cc72361SWai Yew CHAY 			break;
1052*8cc72361SWai Yew CHAY 		case 2:
1053*8cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1);
1054*8cc72361SWai Yew CHAY 			break;
1055*8cc72361SWai Yew CHAY 		case 4:
1056*8cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2);
1057*8cc72361SWai Yew CHAY 			break;
1058*8cc72361SWai Yew CHAY 		default:
1059*8cc72361SWai Yew CHAY 			break;
1060*8cc72361SWai Yew CHAY 		}
1061*8cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8),
1062*8cc72361SWai Yew CHAY 			  (conf >> 4) & 0x1); /* Non-audio */
1063*8cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8),
1064*8cc72361SWai Yew CHAY 			  (conf >> 4) & 0x1); /* Non-audio */
1065*8cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OS << (idx*8),
1066*8cc72361SWai Yew CHAY 			  ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */
1067*8cc72361SWai Yew CHAY 
1068*8cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
1069*8cc72361SWai Yew CHAY 	} else {
1070*8cc72361SWai Yew CHAY 		/* I2S output */
1071*8cc72361SWai Yew CHAY 		/*idx %= 4; */
1072*8cc72361SWai Yew CHAY 	}
1073*8cc72361SWai Yew CHAY 	return 0;
1074*8cc72361SWai Yew CHAY }
1075*8cc72361SWai Yew CHAY 
1076*8cc72361SWai Yew CHAY static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
1077*8cc72361SWai Yew CHAY {
1078*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1079*8cc72361SWai Yew CHAY 
1080*8cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_ARC, slot);
1081*8cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
1082*8cc72361SWai Yew CHAY 	return 0;
1083*8cc72361SWai Yew CHAY }
1084*8cc72361SWai Yew CHAY 
1085*8cc72361SWai Yew CHAY static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
1086*8cc72361SWai Yew CHAY {
1087*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1088*8cc72361SWai Yew CHAY 
1089*8cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_NXT, next);
1090*8cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
1091*8cc72361SWai Yew CHAY 	return 0;
1092*8cc72361SWai Yew CHAY }
1093*8cc72361SWai Yew CHAY 
1094*8cc72361SWai Yew CHAY static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
1095*8cc72361SWai Yew CHAY {
1096*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1097*8cc72361SWai Yew CHAY 
1098*8cc72361SWai Yew CHAY 	ctl->daoimap.idx = addr;
1099*8cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
1100*8cc72361SWai Yew CHAY 	return 0;
1101*8cc72361SWai Yew CHAY }
1102*8cc72361SWai Yew CHAY 
1103*8cc72361SWai Yew CHAY static int daio_mgr_commit_write(struct hw *hw, void *blk)
1104*8cc72361SWai Yew CHAY {
1105*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1106*8cc72361SWai Yew CHAY 	int i = 0;
1107*8cc72361SWai Yew CHAY 
1108*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) {
1109*8cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
1110*8cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.i2sictl & (0x1 << i)))
1111*8cc72361SWai Yew CHAY 				ctl->dirty.bf.i2sictl &= ~(0x1 << i);
1112*8cc72361SWai Yew CHAY 
1113*8cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.i2soctl & (0x1 << i)))
1114*8cc72361SWai Yew CHAY 				ctl->dirty.bf.i2soctl &= ~(0x1 << i);
1115*8cc72361SWai Yew CHAY 		}
1116*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, I2SCTL, ctl->i2sctl);
1117*8cc72361SWai Yew CHAY 		mdelay(1);
1118*8cc72361SWai Yew CHAY 	}
1119*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spoctl) {
1120*8cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
1121*8cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.spoctl & (0x1 << i)))
1122*8cc72361SWai Yew CHAY 				ctl->dirty.bf.spoctl &= ~(0x1 << i);
1123*8cc72361SWai Yew CHAY 		}
1124*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SPOCTL, ctl->spoctl);
1125*8cc72361SWai Yew CHAY 		mdelay(1);
1126*8cc72361SWai Yew CHAY 	}
1127*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spictl) {
1128*8cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
1129*8cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.spictl & (0x1 << i)))
1130*8cc72361SWai Yew CHAY 				ctl->dirty.bf.spictl &= ~(0x1 << i);
1131*8cc72361SWai Yew CHAY 		}
1132*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, SPICTL, ctl->spictl);
1133*8cc72361SWai Yew CHAY 		mdelay(1);
1134*8cc72361SWai Yew CHAY 	}
1135*8cc72361SWai Yew CHAY 	if (ctl->dirty.bf.daoimap) {
1136*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4,
1137*8cc72361SWai Yew CHAY 					ctl->daoimap.aim);
1138*8cc72361SWai Yew CHAY 		ctl->dirty.bf.daoimap = 0;
1139*8cc72361SWai Yew CHAY 	}
1140*8cc72361SWai Yew CHAY 
1141*8cc72361SWai Yew CHAY 	return 0;
1142*8cc72361SWai Yew CHAY }
1143*8cc72361SWai Yew CHAY 
1144*8cc72361SWai Yew CHAY static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
1145*8cc72361SWai Yew CHAY {
1146*8cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *blk;
1147*8cc72361SWai Yew CHAY 
1148*8cc72361SWai Yew CHAY 	*rblk = NULL;
1149*8cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
1150*8cc72361SWai Yew CHAY 	if (NULL == blk)
1151*8cc72361SWai Yew CHAY 		return -ENOMEM;
1152*8cc72361SWai Yew CHAY 
1153*8cc72361SWai Yew CHAY 	blk->i2sctl = hw_read_20kx(hw, I2SCTL);
1154*8cc72361SWai Yew CHAY 	blk->spoctl = hw_read_20kx(hw, SPOCTL);
1155*8cc72361SWai Yew CHAY 	blk->spictl = hw_read_20kx(hw, SPICTL);
1156*8cc72361SWai Yew CHAY 
1157*8cc72361SWai Yew CHAY 	*rblk = blk;
1158*8cc72361SWai Yew CHAY 
1159*8cc72361SWai Yew CHAY 	return 0;
1160*8cc72361SWai Yew CHAY }
1161*8cc72361SWai Yew CHAY 
1162*8cc72361SWai Yew CHAY static int daio_mgr_put_ctrl_blk(void *blk)
1163*8cc72361SWai Yew CHAY {
1164*8cc72361SWai Yew CHAY 	kfree((struct daio_mgr_ctrl_blk *)blk);
1165*8cc72361SWai Yew CHAY 
1166*8cc72361SWai Yew CHAY 	return 0;
1167*8cc72361SWai Yew CHAY }
1168*8cc72361SWai Yew CHAY 
1169*8cc72361SWai Yew CHAY /* Card hardware initialization block */
1170*8cc72361SWai Yew CHAY struct dac_conf {
1171*8cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
1172*8cc72361SWai Yew CHAY };
1173*8cc72361SWai Yew CHAY 
1174*8cc72361SWai Yew CHAY struct adc_conf {
1175*8cc72361SWai Yew CHAY 	unsigned int msr; 	/* master sample rate in rsrs */
1176*8cc72361SWai Yew CHAY 	unsigned char input; 	/* the input source of ADC */
1177*8cc72361SWai Yew CHAY 	unsigned char mic20db; 	/* boost mic by 20db if input is microphone */
1178*8cc72361SWai Yew CHAY };
1179*8cc72361SWai Yew CHAY 
1180*8cc72361SWai Yew CHAY struct daio_conf {
1181*8cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
1182*8cc72361SWai Yew CHAY };
1183*8cc72361SWai Yew CHAY 
1184*8cc72361SWai Yew CHAY struct trn_conf {
1185*8cc72361SWai Yew CHAY 	unsigned long vm_pgt_phys;
1186*8cc72361SWai Yew CHAY };
1187*8cc72361SWai Yew CHAY 
1188*8cc72361SWai Yew CHAY static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
1189*8cc72361SWai Yew CHAY {
1190*8cc72361SWai Yew CHAY 	u32 i2sorg = 0;
1191*8cc72361SWai Yew CHAY 	u32 spdorg = 0;
1192*8cc72361SWai Yew CHAY 
1193*8cc72361SWai Yew CHAY 	/* Read I2S CTL.  Keep original value. */
1194*8cc72361SWai Yew CHAY 	/*i2sorg = hw_read_20kx(hw, I2SCTL);*/
1195*8cc72361SWai Yew CHAY 	i2sorg = 0x94040404; /* enable all audio out and I2S-D input */
1196*8cc72361SWai Yew CHAY 	/* Program I2S with proper master sample rate and enable
1197*8cc72361SWai Yew CHAY 	 * the correct I2S channel. */
1198*8cc72361SWai Yew CHAY 	i2sorg &= 0xfffffffc;
1199*8cc72361SWai Yew CHAY 
1200*8cc72361SWai Yew CHAY 	/* Enable S/PDIF-out-A in fixed 24-bit data
1201*8cc72361SWai Yew CHAY 	 * format and default to 48kHz. */
1202*8cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
1203*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, 0x0);
1204*8cc72361SWai Yew CHAY 	spdorg = 0x05;
1205*8cc72361SWai Yew CHAY 
1206*8cc72361SWai Yew CHAY 	switch (info->msr) {
1207*8cc72361SWai Yew CHAY 	case 1:
1208*8cc72361SWai Yew CHAY 		i2sorg |= 1;
1209*8cc72361SWai Yew CHAY 		spdorg |= (0x0 << 6);
1210*8cc72361SWai Yew CHAY 		break;
1211*8cc72361SWai Yew CHAY 	case 2:
1212*8cc72361SWai Yew CHAY 		i2sorg |= 2;
1213*8cc72361SWai Yew CHAY 		spdorg |= (0x1 << 6);
1214*8cc72361SWai Yew CHAY 		break;
1215*8cc72361SWai Yew CHAY 	case 4:
1216*8cc72361SWai Yew CHAY 		i2sorg |= 3;
1217*8cc72361SWai Yew CHAY 		spdorg |= (0x2 << 6);
1218*8cc72361SWai Yew CHAY 		break;
1219*8cc72361SWai Yew CHAY 	default:
1220*8cc72361SWai Yew CHAY 		i2sorg |= 1;
1221*8cc72361SWai Yew CHAY 		break;
1222*8cc72361SWai Yew CHAY 	}
1223*8cc72361SWai Yew CHAY 
1224*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2SCTL, i2sorg);
1225*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, spdorg);
1226*8cc72361SWai Yew CHAY 
1227*8cc72361SWai Yew CHAY 	/* Enable S/PDIF-in-A in fixed 24-bit data format. */
1228*8cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
1229*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, 0x0);
1230*8cc72361SWai Yew CHAY 	mdelay(1);
1231*8cc72361SWai Yew CHAY 	spdorg = 0x0a0a0a0a;
1232*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, spdorg);
1233*8cc72361SWai Yew CHAY 	mdelay(1);
1234*8cc72361SWai Yew CHAY 
1235*8cc72361SWai Yew CHAY 	return 0;
1236*8cc72361SWai Yew CHAY }
1237*8cc72361SWai Yew CHAY 
1238*8cc72361SWai Yew CHAY /* TRANSPORT operations */
1239*8cc72361SWai Yew CHAY static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
1240*8cc72361SWai Yew CHAY {
1241*8cc72361SWai Yew CHAY 	u32 trnctl = 0;
1242*8cc72361SWai Yew CHAY 	unsigned long ptp_phys_low = 0, ptp_phys_high = 0;
1243*8cc72361SWai Yew CHAY 
1244*8cc72361SWai Yew CHAY 	/* Set up device page table */
1245*8cc72361SWai Yew CHAY 	if ((~0UL) == info->vm_pgt_phys) {
1246*8cc72361SWai Yew CHAY 		printk(KERN_ERR "Wrong device page table page address!\n");
1247*8cc72361SWai Yew CHAY 		return -1;
1248*8cc72361SWai Yew CHAY 	}
1249*8cc72361SWai Yew CHAY 
1250*8cc72361SWai Yew CHAY 	trnctl = 0x13;  /* 32-bit, 4k-size page */
1251*8cc72361SWai Yew CHAY #if BITS_PER_LONG == 64
1252*8cc72361SWai Yew CHAY 	ptp_phys_low = info->vm_pgt_phys & ((1UL<<32)-1);
1253*8cc72361SWai Yew CHAY 	ptp_phys_high = (info->vm_pgt_phys>>32) & ((1UL<<32)-1);
1254*8cc72361SWai Yew CHAY 	trnctl |= (1<<2);
1255*8cc72361SWai Yew CHAY #elif BITS_PER_LONG == 32
1256*8cc72361SWai Yew CHAY 	ptp_phys_low = info->vm_pgt_phys & (~0UL);
1257*8cc72361SWai Yew CHAY 	ptp_phys_high = 0;
1258*8cc72361SWai Yew CHAY #else
1259*8cc72361SWai Yew CHAY #	error "Unknown BITS_PER_LONG!"
1260*8cc72361SWai Yew CHAY #endif
1261*8cc72361SWai Yew CHAY #if PAGE_SIZE == 8192
1262*8cc72361SWai Yew CHAY 	trnctl |= (1<<5);
1263*8cc72361SWai Yew CHAY #endif
1264*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPALX, ptp_phys_low);
1265*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPAHX, ptp_phys_high);
1266*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRNCTL, trnctl);
1267*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */
1268*8cc72361SWai Yew CHAY 
1269*8cc72361SWai Yew CHAY 	return 0;
1270*8cc72361SWai Yew CHAY }
1271*8cc72361SWai Yew CHAY 
1272*8cc72361SWai Yew CHAY /* Card initialization */
1273*8cc72361SWai Yew CHAY #define GCTL_EAC	0x00000001
1274*8cc72361SWai Yew CHAY #define GCTL_EAI	0x00000002
1275*8cc72361SWai Yew CHAY #define GCTL_BEP	0x00000004
1276*8cc72361SWai Yew CHAY #define GCTL_BES	0x00000008
1277*8cc72361SWai Yew CHAY #define GCTL_DSP	0x00000010
1278*8cc72361SWai Yew CHAY #define GCTL_DBP	0x00000020
1279*8cc72361SWai Yew CHAY #define GCTL_ABP	0x00000040
1280*8cc72361SWai Yew CHAY #define GCTL_TBP	0x00000080
1281*8cc72361SWai Yew CHAY #define GCTL_SBP	0x00000100
1282*8cc72361SWai Yew CHAY #define GCTL_FBP	0x00000200
1283*8cc72361SWai Yew CHAY #define GCTL_XA		0x00000400
1284*8cc72361SWai Yew CHAY #define GCTL_ET		0x00000800
1285*8cc72361SWai Yew CHAY #define GCTL_PR		0x00001000
1286*8cc72361SWai Yew CHAY #define GCTL_MRL	0x00002000
1287*8cc72361SWai Yew CHAY #define GCTL_SDE	0x00004000
1288*8cc72361SWai Yew CHAY #define GCTL_SDI	0x00008000
1289*8cc72361SWai Yew CHAY #define GCTL_SM		0x00010000
1290*8cc72361SWai Yew CHAY #define GCTL_SR		0x00020000
1291*8cc72361SWai Yew CHAY #define GCTL_SD		0x00040000
1292*8cc72361SWai Yew CHAY #define GCTL_SE		0x00080000
1293*8cc72361SWai Yew CHAY #define GCTL_AID	0x00100000
1294*8cc72361SWai Yew CHAY 
1295*8cc72361SWai Yew CHAY static int hw_pll_init(struct hw *hw, unsigned int rsr)
1296*8cc72361SWai Yew CHAY {
1297*8cc72361SWai Yew CHAY 	unsigned int pllctl;
1298*8cc72361SWai Yew CHAY 	int i = 0;
1299*8cc72361SWai Yew CHAY 
1300*8cc72361SWai Yew CHAY 	pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731;
1301*8cc72361SWai Yew CHAY 	for (i = 0; i < 3; i++) {
1302*8cc72361SWai Yew CHAY 		if (hw_read_20kx(hw, PLLCTL) == pllctl)
1303*8cc72361SWai Yew CHAY 			break;
1304*8cc72361SWai Yew CHAY 
1305*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, PLLCTL, pllctl);
1306*8cc72361SWai Yew CHAY 		mdelay(40);
1307*8cc72361SWai Yew CHAY 	}
1308*8cc72361SWai Yew CHAY 	if (i >= 3) {
1309*8cc72361SWai Yew CHAY 		printk(KERN_ALERT "PLL initialization failed!!!\n");
1310*8cc72361SWai Yew CHAY 		return -EBUSY;
1311*8cc72361SWai Yew CHAY 	}
1312*8cc72361SWai Yew CHAY 
1313*8cc72361SWai Yew CHAY 	return 0;
1314*8cc72361SWai Yew CHAY }
1315*8cc72361SWai Yew CHAY 
1316*8cc72361SWai Yew CHAY static int hw_auto_init(struct hw *hw)
1317*8cc72361SWai Yew CHAY {
1318*8cc72361SWai Yew CHAY 	unsigned int gctl;
1319*8cc72361SWai Yew CHAY 	int i;
1320*8cc72361SWai Yew CHAY 
1321*8cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
1322*8cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 0);
1323*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
1324*8cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 1);
1325*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
1326*8cc72361SWai Yew CHAY 	mdelay(10);
1327*8cc72361SWai Yew CHAY 	for (i = 0; i < 400000; i++) {
1328*8cc72361SWai Yew CHAY 		gctl = hw_read_20kx(hw, GCTL);
1329*8cc72361SWai Yew CHAY 		if (get_field(gctl, GCTL_AID))
1330*8cc72361SWai Yew CHAY 			break;
1331*8cc72361SWai Yew CHAY 	}
1332*8cc72361SWai Yew CHAY 	if (!get_field(gctl, GCTL_AID)) {
1333*8cc72361SWai Yew CHAY 		printk(KERN_ALERT "Card Auto-init failed!!!\n");
1334*8cc72361SWai Yew CHAY 		return -EBUSY;
1335*8cc72361SWai Yew CHAY 	}
1336*8cc72361SWai Yew CHAY 
1337*8cc72361SWai Yew CHAY 	return 0;
1338*8cc72361SWai Yew CHAY }
1339*8cc72361SWai Yew CHAY 
1340*8cc72361SWai Yew CHAY static int i2c_unlock(struct hw *hw)
1341*8cc72361SWai Yew CHAY {
1342*8cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
1343*8cc72361SWai Yew CHAY 		return 0;
1344*8cc72361SWai Yew CHAY 
1345*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0x8c);
1346*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0x0e);
1347*8cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
1348*8cc72361SWai Yew CHAY 		return 0;
1349*8cc72361SWai Yew CHAY 
1350*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xee);
1351*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xaa);
1352*8cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
1353*8cc72361SWai Yew CHAY 		return 0;
1354*8cc72361SWai Yew CHAY 
1355*8cc72361SWai Yew CHAY 	return -1;
1356*8cc72361SWai Yew CHAY }
1357*8cc72361SWai Yew CHAY 
1358*8cc72361SWai Yew CHAY static void i2c_lock(struct hw *hw)
1359*8cc72361SWai Yew CHAY {
1360*8cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
1361*8cc72361SWai Yew CHAY 		hw_write_pci(hw, 0xcc, 0x00);
1362*8cc72361SWai Yew CHAY }
1363*8cc72361SWai Yew CHAY 
1364*8cc72361SWai Yew CHAY static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data)
1365*8cc72361SWai Yew CHAY {
1366*8cc72361SWai Yew CHAY 	unsigned int ret = 0;
1367*8cc72361SWai Yew CHAY 
1368*8cc72361SWai Yew CHAY 	do {
1369*8cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
1370*8cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
1371*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE0, device);
1372*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff));
1373*8cc72361SWai Yew CHAY }
1374*8cc72361SWai Yew CHAY 
1375*8cc72361SWai Yew CHAY /* DAC operations */
1376*8cc72361SWai Yew CHAY 
1377*8cc72361SWai Yew CHAY static int hw_reset_dac(struct hw *hw)
1378*8cc72361SWai Yew CHAY {
1379*8cc72361SWai Yew CHAY 	u32 i = 0;
1380*8cc72361SWai Yew CHAY 	u16 gpioorg = 0;
1381*8cc72361SWai Yew CHAY 	unsigned int ret = 0;
1382*8cc72361SWai Yew CHAY 
1383*8cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
1384*8cc72361SWai Yew CHAY 		return -1;
1385*8cc72361SWai Yew CHAY 
1386*8cc72361SWai Yew CHAY 	do {
1387*8cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
1388*8cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
1389*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
1390*8cc72361SWai Yew CHAY 
1391*8cc72361SWai Yew CHAY 	/* To be effective, need to reset the DAC twice. */
1392*8cc72361SWai Yew CHAY 	for (i = 0; i < 2;  i++) {
1393*8cc72361SWai Yew CHAY 		/* set gpio */
1394*8cc72361SWai Yew CHAY 		mdelay(100);
1395*8cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
1396*8cc72361SWai Yew CHAY 		gpioorg &= 0xfffd;
1397*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
1398*8cc72361SWai Yew CHAY 		mdelay(1);
1399*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg | 0x2);
1400*8cc72361SWai Yew CHAY 	}
1401*8cc72361SWai Yew CHAY 
1402*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x01, 0x80);
1403*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x02, 0x10);
1404*8cc72361SWai Yew CHAY 
1405*8cc72361SWai Yew CHAY 	i2c_lock(hw);
1406*8cc72361SWai Yew CHAY 
1407*8cc72361SWai Yew CHAY 	return 0;
1408*8cc72361SWai Yew CHAY }
1409*8cc72361SWai Yew CHAY 
1410*8cc72361SWai Yew CHAY static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
1411*8cc72361SWai Yew CHAY {
1412*8cc72361SWai Yew CHAY 	u32 data = 0;
1413*8cc72361SWai Yew CHAY 	u16 gpioorg = 0;
1414*8cc72361SWai Yew CHAY 	u16 subsys_id = 0;
1415*8cc72361SWai Yew CHAY 	unsigned int ret = 0;
1416*8cc72361SWai Yew CHAY 
1417*8cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
1418*8cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
1419*8cc72361SWai Yew CHAY 		/* SB055x, unmute outputs */
1420*8cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
1421*8cc72361SWai Yew CHAY 		gpioorg &= 0xffbf;	/* set GPIO6 to low */
1422*8cc72361SWai Yew CHAY 		gpioorg |= 2;		/* set GPIO1 to high */
1423*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
1424*8cc72361SWai Yew CHAY 		return 0;
1425*8cc72361SWai Yew CHAY 	}
1426*8cc72361SWai Yew CHAY 
1427*8cc72361SWai Yew CHAY 	/* mute outputs */
1428*8cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
1429*8cc72361SWai Yew CHAY 	gpioorg &= 0xffbf;
1430*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
1431*8cc72361SWai Yew CHAY 
1432*8cc72361SWai Yew CHAY 	hw_reset_dac(hw);
1433*8cc72361SWai Yew CHAY 
1434*8cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
1435*8cc72361SWai Yew CHAY 		return -1;
1436*8cc72361SWai Yew CHAY 
1437*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
1438*8cc72361SWai Yew CHAY 	do {
1439*8cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
1440*8cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
1441*8cc72361SWai Yew CHAY 
1442*8cc72361SWai Yew CHAY 	switch (info->msr) {
1443*8cc72361SWai Yew CHAY 	case 1:
1444*8cc72361SWai Yew CHAY 		data = 0x24;
1445*8cc72361SWai Yew CHAY 		break;
1446*8cc72361SWai Yew CHAY 	case 2:
1447*8cc72361SWai Yew CHAY 		data = 0x25;
1448*8cc72361SWai Yew CHAY 		break;
1449*8cc72361SWai Yew CHAY 	case 4:
1450*8cc72361SWai Yew CHAY 		data = 0x26;
1451*8cc72361SWai Yew CHAY 		break;
1452*8cc72361SWai Yew CHAY 	default:
1453*8cc72361SWai Yew CHAY 		data = 0x24;
1454*8cc72361SWai Yew CHAY 		break;
1455*8cc72361SWai Yew CHAY 	}
1456*8cc72361SWai Yew CHAY 
1457*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x06, data);
1458*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x09, data);
1459*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0c, data);
1460*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0f, data);
1461*8cc72361SWai Yew CHAY 
1462*8cc72361SWai Yew CHAY 	i2c_lock(hw);
1463*8cc72361SWai Yew CHAY 
1464*8cc72361SWai Yew CHAY 	/* unmute outputs */
1465*8cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
1466*8cc72361SWai Yew CHAY 	gpioorg = gpioorg | 0x40;
1467*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
1468*8cc72361SWai Yew CHAY 
1469*8cc72361SWai Yew CHAY 	return 0;
1470*8cc72361SWai Yew CHAY }
1471*8cc72361SWai Yew CHAY 
1472*8cc72361SWai Yew CHAY /* ADC operations */
1473*8cc72361SWai Yew CHAY 
1474*8cc72361SWai Yew CHAY static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type)
1475*8cc72361SWai Yew CHAY {
1476*8cc72361SWai Yew CHAY 	u32 data = 0;
1477*8cc72361SWai Yew CHAY 	return data;
1478*8cc72361SWai Yew CHAY }
1479*8cc72361SWai Yew CHAY 
1480*8cc72361SWai Yew CHAY static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type)
1481*8cc72361SWai Yew CHAY {
1482*8cc72361SWai Yew CHAY 	u32 data = 0;
1483*8cc72361SWai Yew CHAY 
1484*8cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
1485*8cc72361SWai Yew CHAY 	switch (type) {
1486*8cc72361SWai Yew CHAY 	case ADC_MICIN:
1487*8cc72361SWai Yew CHAY 		data = ((data & (0x1<<7)) && (data & (0x1<<8)));
1488*8cc72361SWai Yew CHAY 		break;
1489*8cc72361SWai Yew CHAY 	case ADC_LINEIN:
1490*8cc72361SWai Yew CHAY 		data = (!(data & (0x1<<7)) && (data & (0x1<<8)));
1491*8cc72361SWai Yew CHAY 		break;
1492*8cc72361SWai Yew CHAY 	case ADC_NONE: /* Digital I/O */
1493*8cc72361SWai Yew CHAY 		data = (!(data & (0x1<<8)));
1494*8cc72361SWai Yew CHAY 		break;
1495*8cc72361SWai Yew CHAY 	default:
1496*8cc72361SWai Yew CHAY 		data = 0;
1497*8cc72361SWai Yew CHAY 	}
1498*8cc72361SWai Yew CHAY 	return data;
1499*8cc72361SWai Yew CHAY }
1500*8cc72361SWai Yew CHAY 
1501*8cc72361SWai Yew CHAY static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
1502*8cc72361SWai Yew CHAY {
1503*8cc72361SWai Yew CHAY 	u32 data = 0;
1504*8cc72361SWai Yew CHAY 
1505*8cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
1506*8cc72361SWai Yew CHAY 	switch (type) {
1507*8cc72361SWai Yew CHAY 	case ADC_MICIN:
1508*8cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 1 : 0;
1509*8cc72361SWai Yew CHAY 		break;
1510*8cc72361SWai Yew CHAY 	case ADC_LINEIN:
1511*8cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 0 : 1;
1512*8cc72361SWai Yew CHAY 		break;
1513*8cc72361SWai Yew CHAY 	default:
1514*8cc72361SWai Yew CHAY 		data = 0;
1515*8cc72361SWai Yew CHAY 	}
1516*8cc72361SWai Yew CHAY 	return data;
1517*8cc72361SWai Yew CHAY }
1518*8cc72361SWai Yew CHAY 
1519*8cc72361SWai Yew CHAY static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
1520*8cc72361SWai Yew CHAY {
1521*8cc72361SWai Yew CHAY 	u16 subsys_id = 0;
1522*8cc72361SWai Yew CHAY 
1523*8cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
1524*8cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
1525*8cc72361SWai Yew CHAY 		/* SB055x cards */
1526*8cc72361SWai Yew CHAY 		return is_adc_input_selected_SB055x(hw, type);
1527*8cc72361SWai Yew CHAY 	} else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
1528*8cc72361SWai Yew CHAY 		/* SB073x cards */
1529*8cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
1530*8cc72361SWai Yew CHAY 	} else if ((subsys_id & 0xf000) == 0x6000) {
1531*8cc72361SWai Yew CHAY 		/* Vista compatible cards */
1532*8cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
1533*8cc72361SWai Yew CHAY 	} else {
1534*8cc72361SWai Yew CHAY 		return is_adc_input_selected_SBx(hw, type);
1535*8cc72361SWai Yew CHAY 	}
1536*8cc72361SWai Yew CHAY }
1537*8cc72361SWai Yew CHAY 
1538*8cc72361SWai Yew CHAY static int
1539*8cc72361SWai Yew CHAY adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost)
1540*8cc72361SWai Yew CHAY {
1541*8cc72361SWai Yew CHAY 	u32 data = 0;
1542*8cc72361SWai Yew CHAY 
1543*8cc72361SWai Yew CHAY 	/*
1544*8cc72361SWai Yew CHAY 	 * check and set the following GPIO bits accordingly
1545*8cc72361SWai Yew CHAY 	 * ADC_Gain		= GPIO2
1546*8cc72361SWai Yew CHAY 	 * DRM_off		= GPIO3
1547*8cc72361SWai Yew CHAY 	 * Mic_Pwr_on		= GPIO7
1548*8cc72361SWai Yew CHAY 	 * Digital_IO_Sel	= GPIO8
1549*8cc72361SWai Yew CHAY 	 * Mic_Sw		= GPIO9
1550*8cc72361SWai Yew CHAY 	 * Aux/MicLine_Sw	= GPIO12
1551*8cc72361SWai Yew CHAY 	 */
1552*8cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
1553*8cc72361SWai Yew CHAY 	data &= 0xec73;
1554*8cc72361SWai Yew CHAY 	switch (type) {
1555*8cc72361SWai Yew CHAY 	case ADC_MICIN:
1556*8cc72361SWai Yew CHAY 		data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ;
1557*8cc72361SWai Yew CHAY 		data |= boost ? (0x1<<2) : 0;
1558*8cc72361SWai Yew CHAY 		break;
1559*8cc72361SWai Yew CHAY 	case ADC_LINEIN:
1560*8cc72361SWai Yew CHAY 		data |= (0x1<<8);
1561*8cc72361SWai Yew CHAY 		break;
1562*8cc72361SWai Yew CHAY 	case ADC_AUX:
1563*8cc72361SWai Yew CHAY 		data |= (0x1<<8) | (0x1<<12);
1564*8cc72361SWai Yew CHAY 		break;
1565*8cc72361SWai Yew CHAY 	case ADC_NONE:
1566*8cc72361SWai Yew CHAY 		data |= (0x1<<12);  /* set to digital */
1567*8cc72361SWai Yew CHAY 		break;
1568*8cc72361SWai Yew CHAY 	default:
1569*8cc72361SWai Yew CHAY 		return -1;
1570*8cc72361SWai Yew CHAY 	}
1571*8cc72361SWai Yew CHAY 
1572*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
1573*8cc72361SWai Yew CHAY 
1574*8cc72361SWai Yew CHAY 	return 0;
1575*8cc72361SWai Yew CHAY }
1576*8cc72361SWai Yew CHAY 
1577*8cc72361SWai Yew CHAY 
1578*8cc72361SWai Yew CHAY static int
1579*8cc72361SWai Yew CHAY adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost)
1580*8cc72361SWai Yew CHAY {
1581*8cc72361SWai Yew CHAY 	u32 data = 0;
1582*8cc72361SWai Yew CHAY 	u32 i2c_data = 0;
1583*8cc72361SWai Yew CHAY 	unsigned int ret = 0;
1584*8cc72361SWai Yew CHAY 
1585*8cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
1586*8cc72361SWai Yew CHAY 		return -1;
1587*8cc72361SWai Yew CHAY 
1588*8cc72361SWai Yew CHAY 	do {
1589*8cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
1590*8cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
1591*8cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
1592*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
1593*8cc72361SWai Yew CHAY 
1594*8cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
1595*8cc72361SWai Yew CHAY 	switch (type) {
1596*8cc72361SWai Yew CHAY 	case ADC_MICIN:
1597*8cc72361SWai Yew CHAY 		data |= ((0x1 << 7) | (0x1 << 8));
1598*8cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
1599*8cc72361SWai Yew CHAY 		break;
1600*8cc72361SWai Yew CHAY 	case ADC_LINEIN:
1601*8cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
1602*8cc72361SWai Yew CHAY 		data |= (0x1 << 8);
1603*8cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
1604*8cc72361SWai Yew CHAY 		break;
1605*8cc72361SWai Yew CHAY 	case ADC_NONE:
1606*8cc72361SWai Yew CHAY 		data &= ~(0x1 << 8);
1607*8cc72361SWai Yew CHAY 		i2c_data = 0x0; /* set to Digital */
1608*8cc72361SWai Yew CHAY 		break;
1609*8cc72361SWai Yew CHAY 	default:
1610*8cc72361SWai Yew CHAY 		i2c_lock(hw);
1611*8cc72361SWai Yew CHAY 		return -1;
1612*8cc72361SWai Yew CHAY 	}
1613*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
1614*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
1615*8cc72361SWai Yew CHAY 	if (boost) {
1616*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
1617*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
1618*8cc72361SWai Yew CHAY 	} else {
1619*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
1620*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
1621*8cc72361SWai Yew CHAY 	}
1622*8cc72361SWai Yew CHAY 
1623*8cc72361SWai Yew CHAY 	i2c_lock(hw);
1624*8cc72361SWai Yew CHAY 
1625*8cc72361SWai Yew CHAY 	return 0;
1626*8cc72361SWai Yew CHAY }
1627*8cc72361SWai Yew CHAY 
1628*8cc72361SWai Yew CHAY static int
1629*8cc72361SWai Yew CHAY adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
1630*8cc72361SWai Yew CHAY {
1631*8cc72361SWai Yew CHAY 	u32 data = 0;
1632*8cc72361SWai Yew CHAY 	u32 i2c_data = 0;
1633*8cc72361SWai Yew CHAY 	unsigned int ret = 0;
1634*8cc72361SWai Yew CHAY 
1635*8cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
1636*8cc72361SWai Yew CHAY 		return -1;
1637*8cc72361SWai Yew CHAY 
1638*8cc72361SWai Yew CHAY 	do {
1639*8cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
1640*8cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
1641*8cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
1642*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
1643*8cc72361SWai Yew CHAY 
1644*8cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
1645*8cc72361SWai Yew CHAY 	switch (type) {
1646*8cc72361SWai Yew CHAY 	case ADC_MICIN:
1647*8cc72361SWai Yew CHAY 		data |= (0x1 << 7);
1648*8cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
1649*8cc72361SWai Yew CHAY 		break;
1650*8cc72361SWai Yew CHAY 	case ADC_LINEIN:
1651*8cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
1652*8cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
1653*8cc72361SWai Yew CHAY 		break;
1654*8cc72361SWai Yew CHAY 	default:
1655*8cc72361SWai Yew CHAY 		i2c_lock(hw);
1656*8cc72361SWai Yew CHAY 		return -1;
1657*8cc72361SWai Yew CHAY 	}
1658*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
1659*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
1660*8cc72361SWai Yew CHAY 	if (boost) {
1661*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
1662*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
1663*8cc72361SWai Yew CHAY 	} else {
1664*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
1665*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
1666*8cc72361SWai Yew CHAY 	}
1667*8cc72361SWai Yew CHAY 
1668*8cc72361SWai Yew CHAY 	i2c_lock(hw);
1669*8cc72361SWai Yew CHAY 
1670*8cc72361SWai Yew CHAY 	return 0;
1671*8cc72361SWai Yew CHAY }
1672*8cc72361SWai Yew CHAY 
1673*8cc72361SWai Yew CHAY static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
1674*8cc72361SWai Yew CHAY {
1675*8cc72361SWai Yew CHAY 	u16 subsys_id = 0;
1676*8cc72361SWai Yew CHAY 
1677*8cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
1678*8cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
1679*8cc72361SWai Yew CHAY 		/* SB055x cards */
1680*8cc72361SWai Yew CHAY 		return adc_input_select_SB055x(hw, type, (ADC_MICIN == type));
1681*8cc72361SWai Yew CHAY 	} else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
1682*8cc72361SWai Yew CHAY 		/* SB073x cards */
1683*8cc72361SWai Yew CHAY 		return adc_input_select_hendrix(hw, type, (ADC_MICIN == type));
1684*8cc72361SWai Yew CHAY 	} else if ((subsys_id & 0xf000) == 0x6000) {
1685*8cc72361SWai Yew CHAY 		/* Vista compatible cards */
1686*8cc72361SWai Yew CHAY 		return adc_input_select_hendrix(hw, type, (ADC_MICIN == type));
1687*8cc72361SWai Yew CHAY 	} else {
1688*8cc72361SWai Yew CHAY 		return adc_input_select_SBx(hw, type, (ADC_MICIN == type));
1689*8cc72361SWai Yew CHAY 	}
1690*8cc72361SWai Yew CHAY }
1691*8cc72361SWai Yew CHAY 
1692*8cc72361SWai Yew CHAY static int adc_init_SB055x(struct hw *hw, int input, int mic20db)
1693*8cc72361SWai Yew CHAY {
1694*8cc72361SWai Yew CHAY 	return adc_input_select_SB055x(hw, input, mic20db);
1695*8cc72361SWai Yew CHAY }
1696*8cc72361SWai Yew CHAY 
1697*8cc72361SWai Yew CHAY static int adc_init_SBx(struct hw *hw, int input, int mic20db)
1698*8cc72361SWai Yew CHAY {
1699*8cc72361SWai Yew CHAY 	u16 gpioorg;
1700*8cc72361SWai Yew CHAY 	u16 input_source;
1701*8cc72361SWai Yew CHAY 	u32 adcdata = 0;
1702*8cc72361SWai Yew CHAY 	unsigned int ret = 0;
1703*8cc72361SWai Yew CHAY 
1704*8cc72361SWai Yew CHAY 	input_source = 0x100;  /* default to analog */
1705*8cc72361SWai Yew CHAY 	switch (input) {
1706*8cc72361SWai Yew CHAY 	case ADC_MICIN:
1707*8cc72361SWai Yew CHAY 		adcdata = 0x1;
1708*8cc72361SWai Yew CHAY 		input_source = 0x180;  /* set GPIO7 to select Mic */
1709*8cc72361SWai Yew CHAY 		break;
1710*8cc72361SWai Yew CHAY 	case ADC_LINEIN:
1711*8cc72361SWai Yew CHAY 		adcdata = 0x2;
1712*8cc72361SWai Yew CHAY 		break;
1713*8cc72361SWai Yew CHAY 	case ADC_VIDEO:
1714*8cc72361SWai Yew CHAY 		adcdata = 0x4;
1715*8cc72361SWai Yew CHAY 		break;
1716*8cc72361SWai Yew CHAY 	case ADC_AUX:
1717*8cc72361SWai Yew CHAY 		adcdata = 0x8;
1718*8cc72361SWai Yew CHAY 		break;
1719*8cc72361SWai Yew CHAY 	case ADC_NONE:
1720*8cc72361SWai Yew CHAY 		adcdata = 0x0;
1721*8cc72361SWai Yew CHAY 		input_source = 0x0;  /* set to Digital */
1722*8cc72361SWai Yew CHAY 		break;
1723*8cc72361SWai Yew CHAY 	default:
1724*8cc72361SWai Yew CHAY 		break;
1725*8cc72361SWai Yew CHAY 	}
1726*8cc72361SWai Yew CHAY 
1727*8cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
1728*8cc72361SWai Yew CHAY 		return -1;
1729*8cc72361SWai Yew CHAY 
1730*8cc72361SWai Yew CHAY 	do {
1731*8cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
1732*8cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
1733*8cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
1734*8cc72361SWai Yew CHAY 
1735*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x0e, 0x08);
1736*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x18, 0x0a);
1737*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x28, 0x86);
1738*8cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, adcdata);
1739*8cc72361SWai Yew CHAY 
1740*8cc72361SWai Yew CHAY 	if (mic20db) {
1741*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xf7);
1742*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xf7);
1743*8cc72361SWai Yew CHAY 	} else {
1744*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf);
1745*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf);
1746*8cc72361SWai Yew CHAY 	}
1747*8cc72361SWai Yew CHAY 
1748*8cc72361SWai Yew CHAY 	if (!(hw_read_20kx(hw, ID0) & 0x100))
1749*8cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x16, 0x26);
1750*8cc72361SWai Yew CHAY 
1751*8cc72361SWai Yew CHAY 	i2c_lock(hw);
1752*8cc72361SWai Yew CHAY 
1753*8cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw,  GPIO);
1754*8cc72361SWai Yew CHAY 	gpioorg &= 0xfe7f;
1755*8cc72361SWai Yew CHAY 	gpioorg |= input_source;
1756*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
1757*8cc72361SWai Yew CHAY 
1758*8cc72361SWai Yew CHAY 	return 0;
1759*8cc72361SWai Yew CHAY }
1760*8cc72361SWai Yew CHAY 
1761*8cc72361SWai Yew CHAY static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
1762*8cc72361SWai Yew CHAY {
1763*8cc72361SWai Yew CHAY 	int err = 0;
1764*8cc72361SWai Yew CHAY 	u16 subsys_id = 0;
1765*8cc72361SWai Yew CHAY 
1766*8cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
1767*8cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
1768*8cc72361SWai Yew CHAY 		/* Sb055x card */
1769*8cc72361SWai Yew CHAY 		err = adc_init_SB055x(hw, info->input, info->mic20db);
1770*8cc72361SWai Yew CHAY 	} else {
1771*8cc72361SWai Yew CHAY 		err = adc_init_SBx(hw, info->input, info->mic20db);
1772*8cc72361SWai Yew CHAY 	}
1773*8cc72361SWai Yew CHAY 
1774*8cc72361SWai Yew CHAY 	return err;
1775*8cc72361SWai Yew CHAY }
1776*8cc72361SWai Yew CHAY 
1777*8cc72361SWai Yew CHAY static int hw_have_digit_io_switch(struct hw *hw)
1778*8cc72361SWai Yew CHAY {
1779*8cc72361SWai Yew CHAY 	u16 subsys_id = 0;
1780*8cc72361SWai Yew CHAY 
1781*8cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
1782*8cc72361SWai Yew CHAY 	/* SB073x and Vista compatible cards have no digit IO switch */
1783*8cc72361SWai Yew CHAY 	return !((subsys_id == 0x0029) || (subsys_id == 0x0031)
1784*8cc72361SWai Yew CHAY 				|| ((subsys_id & 0xf000) == 0x6000));
1785*8cc72361SWai Yew CHAY }
1786*8cc72361SWai Yew CHAY 
1787*8cc72361SWai Yew CHAY #define UAA_CFG_PWRSTATUS	0x44
1788*8cc72361SWai Yew CHAY #define UAA_CFG_SPACE_FLAG	0xA0
1789*8cc72361SWai Yew CHAY #define UAA_CORE_CHANGE		0x3FFC
1790*8cc72361SWai Yew CHAY static int uaa_to_xfi(struct pci_dev *pci)
1791*8cc72361SWai Yew CHAY {
1792*8cc72361SWai Yew CHAY 	unsigned int bar0, bar1, bar2, bar3, bar4, bar5;
1793*8cc72361SWai Yew CHAY 	unsigned int cmd, irq, cl_size, l_timer, pwr;
1794*8cc72361SWai Yew CHAY 	unsigned int CTLA, CTLZ, CTLL, CTLX, CTL_, CTLF, CTLi;
1795*8cc72361SWai Yew CHAY 	unsigned int is_uaa = 0;
1796*8cc72361SWai Yew CHAY 	unsigned int data[4] = {0};
1797*8cc72361SWai Yew CHAY 	unsigned int io_base;
1798*8cc72361SWai Yew CHAY 	void *mem_base;
1799*8cc72361SWai Yew CHAY 	int i = 0;
1800*8cc72361SWai Yew CHAY 
1801*8cc72361SWai Yew CHAY 	/* By default, Hendrix card UAA Bar0 should be using memory... */
1802*8cc72361SWai Yew CHAY 	io_base = pci_resource_start(pci, 0);
1803*8cc72361SWai Yew CHAY 	mem_base = ioremap(io_base, pci_resource_len(pci, 0));
1804*8cc72361SWai Yew CHAY 	if (NULL == mem_base)
1805*8cc72361SWai Yew CHAY 		return -ENOENT;
1806*8cc72361SWai Yew CHAY 
1807*8cc72361SWai Yew CHAY 	CTLX = ___constant_swab32(*((unsigned int *)"CTLX"));
1808*8cc72361SWai Yew CHAY 	CTL_ = ___constant_swab32(*((unsigned int *)"CTL-"));
1809*8cc72361SWai Yew CHAY 	CTLF = ___constant_swab32(*((unsigned int *)"CTLF"));
1810*8cc72361SWai Yew CHAY 	CTLi = ___constant_swab32(*((unsigned int *)"CTLi"));
1811*8cc72361SWai Yew CHAY 	CTLA = ___constant_swab32(*((unsigned int *)"CTLA"));
1812*8cc72361SWai Yew CHAY 	CTLZ = ___constant_swab32(*((unsigned int *)"CTLZ"));
1813*8cc72361SWai Yew CHAY 	CTLL = ___constant_swab32(*((unsigned int *)"CTLL"));
1814*8cc72361SWai Yew CHAY 
1815*8cc72361SWai Yew CHAY 	/* Read current mode from Mode Change Register */
1816*8cc72361SWai Yew CHAY 	for (i = 0; i < 4; i++)
1817*8cc72361SWai Yew CHAY 		data[i] = readl(mem_base + UAA_CORE_CHANGE);
1818*8cc72361SWai Yew CHAY 
1819*8cc72361SWai Yew CHAY 	/* Determine current mode... */
1820*8cc72361SWai Yew CHAY 	if (data[0] == CTLA) {
1821*8cc72361SWai Yew CHAY 		is_uaa = ((data[1] == CTLZ && data[2] == CTLL
1822*8cc72361SWai Yew CHAY 			  && data[3] == CTLA) || (data[1] == CTLA
1823*8cc72361SWai Yew CHAY 			  && data[2] == CTLZ && data[3] == CTLL));
1824*8cc72361SWai Yew CHAY 	} else if (data[0] == CTLZ) {
1825*8cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLL
1826*8cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLA);
1827*8cc72361SWai Yew CHAY 	} else if (data[0] == CTLL) {
1828*8cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLA
1829*8cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLZ);
1830*8cc72361SWai Yew CHAY 	} else {
1831*8cc72361SWai Yew CHAY 		is_uaa = 0;
1832*8cc72361SWai Yew CHAY 	}
1833*8cc72361SWai Yew CHAY 
1834*8cc72361SWai Yew CHAY 	if (!is_uaa) {
1835*8cc72361SWai Yew CHAY 		/* Not in UAA mode currently. Return directly. */
1836*8cc72361SWai Yew CHAY 		iounmap(mem_base);
1837*8cc72361SWai Yew CHAY 		return 0;
1838*8cc72361SWai Yew CHAY 	}
1839*8cc72361SWai Yew CHAY 
1840*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0);
1841*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1);
1842*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2);
1843*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3);
1844*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4);
1845*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5);
1846*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq);
1847*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size);
1848*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer);
1849*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr);
1850*8cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_COMMAND, &cmd);
1851*8cc72361SWai Yew CHAY 
1852*8cc72361SWai Yew CHAY 	/* Set up X-Fi core PCI configuration space. */
1853*8cc72361SWai Yew CHAY 	/* Switch to X-Fi config space with BAR0 exposed. */
1854*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321);
1855*8cc72361SWai Yew CHAY 	/* Copy UAA's BAR5 into X-Fi BAR0 */
1856*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5);
1857*8cc72361SWai Yew CHAY 	/* Switch to X-Fi config space without BAR0 exposed. */
1858*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678);
1859*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1);
1860*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2);
1861*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3);
1862*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4);
1863*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq);
1864*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size);
1865*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer);
1866*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr);
1867*8cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_COMMAND, cmd);
1868*8cc72361SWai Yew CHAY 
1869*8cc72361SWai Yew CHAY 	/* Switch to X-Fi mode */
1870*8cc72361SWai Yew CHAY 	writel(CTLX, (mem_base + UAA_CORE_CHANGE));
1871*8cc72361SWai Yew CHAY 	writel(CTL_, (mem_base + UAA_CORE_CHANGE));
1872*8cc72361SWai Yew CHAY 	writel(CTLF, (mem_base + UAA_CORE_CHANGE));
1873*8cc72361SWai Yew CHAY 	writel(CTLi, (mem_base + UAA_CORE_CHANGE));
1874*8cc72361SWai Yew CHAY 
1875*8cc72361SWai Yew CHAY 	iounmap(mem_base);
1876*8cc72361SWai Yew CHAY 
1877*8cc72361SWai Yew CHAY 	return 0;
1878*8cc72361SWai Yew CHAY }
1879*8cc72361SWai Yew CHAY 
1880*8cc72361SWai Yew CHAY static int hw_card_start(struct hw *hw)
1881*8cc72361SWai Yew CHAY {
1882*8cc72361SWai Yew CHAY 	int err = 0;
1883*8cc72361SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
1884*8cc72361SWai Yew CHAY 	u16 subsys_id = 0;
1885*8cc72361SWai Yew CHAY 	unsigned int dma_mask = 0;
1886*8cc72361SWai Yew CHAY 
1887*8cc72361SWai Yew CHAY 	err = pci_enable_device(pci);
1888*8cc72361SWai Yew CHAY 	if (err < 0)
1889*8cc72361SWai Yew CHAY 		return err;
1890*8cc72361SWai Yew CHAY 
1891*8cc72361SWai Yew CHAY 	/* Set DMA transfer mask */
1892*8cc72361SWai Yew CHAY 	dma_mask = CT_XFI_DMA_MASK;
1893*8cc72361SWai Yew CHAY 	if (pci_set_dma_mask(pci, dma_mask) < 0 ||
1894*8cc72361SWai Yew CHAY 	    pci_set_consistent_dma_mask(pci, dma_mask) < 0) {
1895*8cc72361SWai Yew CHAY 		printk(KERN_ERR "architecture does not support PCI "
1896*8cc72361SWai Yew CHAY 				"busmaster DMA with mask 0x%x\n", dma_mask);
1897*8cc72361SWai Yew CHAY 		err = -ENXIO;
1898*8cc72361SWai Yew CHAY 		goto error1;
1899*8cc72361SWai Yew CHAY 	}
1900*8cc72361SWai Yew CHAY 
1901*8cc72361SWai Yew CHAY 	err = pci_request_regions(pci, "XFi");
1902*8cc72361SWai Yew CHAY 	if (err < 0)
1903*8cc72361SWai Yew CHAY 		goto error1;
1904*8cc72361SWai Yew CHAY 
1905*8cc72361SWai Yew CHAY 	/* Switch to X-Fi mode from UAA mode if neeeded */
1906*8cc72361SWai Yew CHAY 	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsys_id);
1907*8cc72361SWai Yew CHAY 	if ((0x5 == pci->device) && (0x6000 == (subsys_id & 0x6000))) {
1908*8cc72361SWai Yew CHAY 		err = uaa_to_xfi(pci);
1909*8cc72361SWai Yew CHAY 		if (err)
1910*8cc72361SWai Yew CHAY 			goto error2;
1911*8cc72361SWai Yew CHAY 
1912*8cc72361SWai Yew CHAY 		hw->io_base = pci_resource_start(pci, 5);
1913*8cc72361SWai Yew CHAY 	} else {
1914*8cc72361SWai Yew CHAY 		hw->io_base = pci_resource_start(pci, 0);
1915*8cc72361SWai Yew CHAY 	}
1916*8cc72361SWai Yew CHAY 
1917*8cc72361SWai Yew CHAY 	/*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED,
1918*8cc72361SWai Yew CHAY 				atc->chip_details->nm_card, hw))) {
1919*8cc72361SWai Yew CHAY 		goto error2;
1920*8cc72361SWai Yew CHAY 	}
1921*8cc72361SWai Yew CHAY 	hw->irq = pci->irq;
1922*8cc72361SWai Yew CHAY 	*/
1923*8cc72361SWai Yew CHAY 
1924*8cc72361SWai Yew CHAY 	pci_set_master(pci);
1925*8cc72361SWai Yew CHAY 
1926*8cc72361SWai Yew CHAY 	return 0;
1927*8cc72361SWai Yew CHAY 
1928*8cc72361SWai Yew CHAY error2:
1929*8cc72361SWai Yew CHAY 	pci_release_regions(pci);
1930*8cc72361SWai Yew CHAY 	hw->io_base = 0;
1931*8cc72361SWai Yew CHAY error1:
1932*8cc72361SWai Yew CHAY 	pci_disable_device(pci);
1933*8cc72361SWai Yew CHAY 	return err;
1934*8cc72361SWai Yew CHAY }
1935*8cc72361SWai Yew CHAY 
1936*8cc72361SWai Yew CHAY static int hw_card_stop(struct hw *hw)
1937*8cc72361SWai Yew CHAY {
1938*8cc72361SWai Yew CHAY 	/* TODO: Disable interrupt and so on... */
1939*8cc72361SWai Yew CHAY 	return 0;
1940*8cc72361SWai Yew CHAY }
1941*8cc72361SWai Yew CHAY 
1942*8cc72361SWai Yew CHAY static int hw_card_shutdown(struct hw *hw)
1943*8cc72361SWai Yew CHAY {
1944*8cc72361SWai Yew CHAY 	if (hw->irq >= 0)
1945*8cc72361SWai Yew CHAY 		free_irq(hw->irq, hw);
1946*8cc72361SWai Yew CHAY 
1947*8cc72361SWai Yew CHAY 	hw->irq	= -1;
1948*8cc72361SWai Yew CHAY 
1949*8cc72361SWai Yew CHAY 	if (NULL != ((void *)hw->mem_base))
1950*8cc72361SWai Yew CHAY 		iounmap((void *)hw->mem_base);
1951*8cc72361SWai Yew CHAY 
1952*8cc72361SWai Yew CHAY 	hw->mem_base = (unsigned long)NULL;
1953*8cc72361SWai Yew CHAY 
1954*8cc72361SWai Yew CHAY 	if (hw->io_base)
1955*8cc72361SWai Yew CHAY 		pci_release_regions(hw->pci);
1956*8cc72361SWai Yew CHAY 
1957*8cc72361SWai Yew CHAY 	hw->io_base = 0;
1958*8cc72361SWai Yew CHAY 
1959*8cc72361SWai Yew CHAY 	pci_disable_device(hw->pci);
1960*8cc72361SWai Yew CHAY 
1961*8cc72361SWai Yew CHAY 	return 0;
1962*8cc72361SWai Yew CHAY }
1963*8cc72361SWai Yew CHAY 
1964*8cc72361SWai Yew CHAY static int hw_card_init(struct hw *hw, struct card_conf *info)
1965*8cc72361SWai Yew CHAY {
1966*8cc72361SWai Yew CHAY 	int err;
1967*8cc72361SWai Yew CHAY 	unsigned int gctl;
1968*8cc72361SWai Yew CHAY 	u16 subsys_id = 0;
1969*8cc72361SWai Yew CHAY 	u32 data = 0;
1970*8cc72361SWai Yew CHAY 	struct dac_conf dac_info = {0};
1971*8cc72361SWai Yew CHAY 	struct adc_conf adc_info = {0};
1972*8cc72361SWai Yew CHAY 	struct daio_conf daio_info = {0};
1973*8cc72361SWai Yew CHAY 	struct trn_conf trn_info = {0};
1974*8cc72361SWai Yew CHAY 
1975*8cc72361SWai Yew CHAY 	/* Get PCI io port base address and do Hendrix switch if needed. */
1976*8cc72361SWai Yew CHAY 	if (!hw->io_base) {
1977*8cc72361SWai Yew CHAY 		err = hw_card_start(hw);
1978*8cc72361SWai Yew CHAY 		if (err)
1979*8cc72361SWai Yew CHAY 			return err;
1980*8cc72361SWai Yew CHAY 	}
1981*8cc72361SWai Yew CHAY 
1982*8cc72361SWai Yew CHAY 	/* PLL init */
1983*8cc72361SWai Yew CHAY 	err = hw_pll_init(hw, info->rsr);
1984*8cc72361SWai Yew CHAY 	if (err < 0)
1985*8cc72361SWai Yew CHAY 		return err;
1986*8cc72361SWai Yew CHAY 
1987*8cc72361SWai Yew CHAY 	/* kick off auto-init */
1988*8cc72361SWai Yew CHAY 	err = hw_auto_init(hw);
1989*8cc72361SWai Yew CHAY 	if (err < 0)
1990*8cc72361SWai Yew CHAY 		return err;
1991*8cc72361SWai Yew CHAY 
1992*8cc72361SWai Yew CHAY 	/* Enable audio ring */
1993*8cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
1994*8cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAC, 1);
1995*8cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_DBP, 1);
1996*8cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_TBP, 1);
1997*8cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_FBP, 1);
1998*8cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_ET, 1);
1999*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
2000*8cc72361SWai Yew CHAY 	mdelay(10);
2001*8cc72361SWai Yew CHAY 
2002*8cc72361SWai Yew CHAY 	/* Reset all global pending interrupts */
2003*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, GIE, 0);
2004*8cc72361SWai Yew CHAY 	/* Reset all SRC pending interrupts */
2005*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCIP, 0);
2006*8cc72361SWai Yew CHAY 	mdelay(30);
2007*8cc72361SWai Yew CHAY 
2008*8cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
2009*8cc72361SWai Yew CHAY 	/* Detect the card ID and configure GPIO accordingly. */
2010*8cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
2011*8cc72361SWai Yew CHAY 		/* SB055x cards */
2012*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x13fe);
2013*8cc72361SWai Yew CHAY 	} else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
2014*8cc72361SWai Yew CHAY 		/* SB073x cards */
2015*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00e6);
2016*8cc72361SWai Yew CHAY 	} else if ((subsys_id & 0xf000) == 0x6000) {
2017*8cc72361SWai Yew CHAY 		/* Vista compatible cards */
2018*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00c2);
2019*8cc72361SWai Yew CHAY 	} else {
2020*8cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x01e6);
2021*8cc72361SWai Yew CHAY 	}
2022*8cc72361SWai Yew CHAY 
2023*8cc72361SWai Yew CHAY 	trn_info.vm_pgt_phys = info->vm_pgt_phys;
2024*8cc72361SWai Yew CHAY 	err = hw_trn_init(hw, &trn_info);
2025*8cc72361SWai Yew CHAY 	if (err < 0)
2026*8cc72361SWai Yew CHAY 		return err;
2027*8cc72361SWai Yew CHAY 
2028*8cc72361SWai Yew CHAY 	daio_info.msr = info->msr;
2029*8cc72361SWai Yew CHAY 	err = hw_daio_init(hw, &daio_info);
2030*8cc72361SWai Yew CHAY 	if (err < 0)
2031*8cc72361SWai Yew CHAY 		return err;
2032*8cc72361SWai Yew CHAY 
2033*8cc72361SWai Yew CHAY 	dac_info.msr = info->msr;
2034*8cc72361SWai Yew CHAY 	err = hw_dac_init(hw, &dac_info);
2035*8cc72361SWai Yew CHAY 	if (err < 0)
2036*8cc72361SWai Yew CHAY 		return err;
2037*8cc72361SWai Yew CHAY 
2038*8cc72361SWai Yew CHAY 	adc_info.msr = info->msr;
2039*8cc72361SWai Yew CHAY 	adc_info.input = ADC_LINEIN;
2040*8cc72361SWai Yew CHAY 	adc_info.mic20db = 0;
2041*8cc72361SWai Yew CHAY 	err = hw_adc_init(hw, &adc_info);
2042*8cc72361SWai Yew CHAY 	if (err < 0)
2043*8cc72361SWai Yew CHAY 		return err;
2044*8cc72361SWai Yew CHAY 
2045*8cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, SRCMCTL);
2046*8cc72361SWai Yew CHAY 	data |= 0x1; /* Enables input from the audio ring */
2047*8cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCMCTL, data);
2048*8cc72361SWai Yew CHAY 
2049*8cc72361SWai Yew CHAY 	return 0;
2050*8cc72361SWai Yew CHAY }
2051*8cc72361SWai Yew CHAY 
2052*8cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg)
2053*8cc72361SWai Yew CHAY {
2054*8cc72361SWai Yew CHAY 	u32 value;
2055*8cc72361SWai Yew CHAY 	unsigned long flags;
2056*8cc72361SWai Yew CHAY 
2057*8cc72361SWai Yew CHAY 	spin_lock_irqsave(
2058*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
2059*8cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
2060*8cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x4);
2061*8cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
2062*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
2063*8cc72361SWai Yew CHAY 
2064*8cc72361SWai Yew CHAY 	return value;
2065*8cc72361SWai Yew CHAY }
2066*8cc72361SWai Yew CHAY 
2067*8cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
2068*8cc72361SWai Yew CHAY {
2069*8cc72361SWai Yew CHAY 	unsigned long flags;
2070*8cc72361SWai Yew CHAY 
2071*8cc72361SWai Yew CHAY 	spin_lock_irqsave(
2072*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
2073*8cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
2074*8cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x4);
2075*8cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
2076*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
2077*8cc72361SWai Yew CHAY 
2078*8cc72361SWai Yew CHAY }
2079*8cc72361SWai Yew CHAY 
2080*8cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg)
2081*8cc72361SWai Yew CHAY {
2082*8cc72361SWai Yew CHAY 	u32 value;
2083*8cc72361SWai Yew CHAY 	unsigned long flags;
2084*8cc72361SWai Yew CHAY 
2085*8cc72361SWai Yew CHAY 	spin_lock_irqsave(
2086*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
2087*8cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
2088*8cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x14);
2089*8cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
2090*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
2091*8cc72361SWai Yew CHAY 
2092*8cc72361SWai Yew CHAY 	return value;
2093*8cc72361SWai Yew CHAY }
2094*8cc72361SWai Yew CHAY 
2095*8cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
2096*8cc72361SWai Yew CHAY {
2097*8cc72361SWai Yew CHAY 	unsigned long flags;
2098*8cc72361SWai Yew CHAY 
2099*8cc72361SWai Yew CHAY 	spin_lock_irqsave(
2100*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
2101*8cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
2102*8cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x14);
2103*8cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
2104*8cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
2105*8cc72361SWai Yew CHAY }
2106*8cc72361SWai Yew CHAY 
2107*8cc72361SWai Yew CHAY int create_20k1_hw_obj(struct hw **rhw)
2108*8cc72361SWai Yew CHAY {
2109*8cc72361SWai Yew CHAY 	struct hw *hw;
2110*8cc72361SWai Yew CHAY 	struct hw20k1 *hw20k1;
2111*8cc72361SWai Yew CHAY 
2112*8cc72361SWai Yew CHAY 	*rhw = NULL;
2113*8cc72361SWai Yew CHAY 	hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
2114*8cc72361SWai Yew CHAY 	if (NULL == hw20k1)
2115*8cc72361SWai Yew CHAY 		return -ENOMEM;
2116*8cc72361SWai Yew CHAY 
2117*8cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_20k1_lock);
2118*8cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_pci_lock);
2119*8cc72361SWai Yew CHAY 
2120*8cc72361SWai Yew CHAY 	hw = &hw20k1->hw;
2121*8cc72361SWai Yew CHAY 
2122*8cc72361SWai Yew CHAY 	hw->io_base = 0;
2123*8cc72361SWai Yew CHAY 	hw->mem_base = (unsigned long)NULL;
2124*8cc72361SWai Yew CHAY 	hw->irq = -1;
2125*8cc72361SWai Yew CHAY 
2126*8cc72361SWai Yew CHAY 	hw->card_init = hw_card_init;
2127*8cc72361SWai Yew CHAY 	hw->card_stop = hw_card_stop;
2128*8cc72361SWai Yew CHAY 	hw->pll_init = hw_pll_init;
2129*8cc72361SWai Yew CHAY 	hw->is_adc_source_selected = hw_is_adc_input_selected;
2130*8cc72361SWai Yew CHAY 	hw->select_adc_source = hw_adc_input_select;
2131*8cc72361SWai Yew CHAY 	hw->have_digit_io_switch = hw_have_digit_io_switch;
2132*8cc72361SWai Yew CHAY 
2133*8cc72361SWai Yew CHAY 	hw->src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk;
2134*8cc72361SWai Yew CHAY 	hw->src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk;
2135*8cc72361SWai Yew CHAY 	hw->src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk;
2136*8cc72361SWai Yew CHAY 	hw->src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk;
2137*8cc72361SWai Yew CHAY 	hw->src_set_state = src_set_state;
2138*8cc72361SWai Yew CHAY 	hw->src_set_bm = src_set_bm;
2139*8cc72361SWai Yew CHAY 	hw->src_set_rsr = src_set_rsr;
2140*8cc72361SWai Yew CHAY 	hw->src_set_sf = src_set_sf;
2141*8cc72361SWai Yew CHAY 	hw->src_set_wr = src_set_wr;
2142*8cc72361SWai Yew CHAY 	hw->src_set_pm = src_set_pm;
2143*8cc72361SWai Yew CHAY 	hw->src_set_rom = src_set_rom;
2144*8cc72361SWai Yew CHAY 	hw->src_set_vo = src_set_vo;
2145*8cc72361SWai Yew CHAY 	hw->src_set_st = src_set_st;
2146*8cc72361SWai Yew CHAY 	hw->src_set_ie = src_set_ie;
2147*8cc72361SWai Yew CHAY 	hw->src_set_ilsz = src_set_ilsz;
2148*8cc72361SWai Yew CHAY 	hw->src_set_bp = src_set_bp;
2149*8cc72361SWai Yew CHAY 	hw->src_set_cisz = src_set_cisz;
2150*8cc72361SWai Yew CHAY 	hw->src_set_ca = src_set_ca;
2151*8cc72361SWai Yew CHAY 	hw->src_set_sa = src_set_sa;
2152*8cc72361SWai Yew CHAY 	hw->src_set_la = src_set_la;
2153*8cc72361SWai Yew CHAY 	hw->src_set_pitch = src_set_pitch;
2154*8cc72361SWai Yew CHAY 	hw->src_set_dirty = src_set_dirty;
2155*8cc72361SWai Yew CHAY 	hw->src_set_clear_zbufs = src_set_clear_zbufs;
2156*8cc72361SWai Yew CHAY 	hw->src_set_dirty_all = src_set_dirty_all;
2157*8cc72361SWai Yew CHAY 	hw->src_commit_write = src_commit_write;
2158*8cc72361SWai Yew CHAY 	hw->src_get_ca = src_get_ca;
2159*8cc72361SWai Yew CHAY 	hw->src_get_dirty = src_get_dirty;
2160*8cc72361SWai Yew CHAY 	hw->src_dirty_conj_mask = src_dirty_conj_mask;
2161*8cc72361SWai Yew CHAY 	hw->src_mgr_enbs_src = src_mgr_enbs_src;
2162*8cc72361SWai Yew CHAY 	hw->src_mgr_enb_src = src_mgr_enb_src;
2163*8cc72361SWai Yew CHAY 	hw->src_mgr_dsb_src = src_mgr_dsb_src;
2164*8cc72361SWai Yew CHAY 	hw->src_mgr_commit_write = src_mgr_commit_write;
2165*8cc72361SWai Yew CHAY 
2166*8cc72361SWai Yew CHAY 	hw->srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk;
2167*8cc72361SWai Yew CHAY 	hw->srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk;
2168*8cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc;
2169*8cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser;
2170*8cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt;
2171*8cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr;
2172*8cc72361SWai Yew CHAY 	hw->srcimp_mgr_commit_write = srcimp_mgr_commit_write;
2173*8cc72361SWai Yew CHAY 
2174*8cc72361SWai Yew CHAY 	hw->amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk;
2175*8cc72361SWai Yew CHAY 	hw->amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk;
2176*8cc72361SWai Yew CHAY 	hw->amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk;
2177*8cc72361SWai Yew CHAY 	hw->amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk;
2178*8cc72361SWai Yew CHAY 	hw->amixer_set_mode = amixer_set_mode;
2179*8cc72361SWai Yew CHAY 	hw->amixer_set_iv = amixer_set_iv;
2180*8cc72361SWai Yew CHAY 	hw->amixer_set_x = amixer_set_x;
2181*8cc72361SWai Yew CHAY 	hw->amixer_set_y = amixer_set_y;
2182*8cc72361SWai Yew CHAY 	hw->amixer_set_sadr = amixer_set_sadr;
2183*8cc72361SWai Yew CHAY 	hw->amixer_set_se = amixer_set_se;
2184*8cc72361SWai Yew CHAY 	hw->amixer_set_dirty = amixer_set_dirty;
2185*8cc72361SWai Yew CHAY 	hw->amixer_set_dirty_all = amixer_set_dirty_all;
2186*8cc72361SWai Yew CHAY 	hw->amixer_commit_write = amixer_commit_write;
2187*8cc72361SWai Yew CHAY 	hw->amixer_get_y = amixer_get_y;
2188*8cc72361SWai Yew CHAY 	hw->amixer_get_dirty = amixer_get_dirty;
2189*8cc72361SWai Yew CHAY 
2190*8cc72361SWai Yew CHAY 	hw->dai_get_ctrl_blk = dai_get_ctrl_blk;
2191*8cc72361SWai Yew CHAY 	hw->dai_put_ctrl_blk = dai_put_ctrl_blk;
2192*8cc72361SWai Yew CHAY 	hw->dai_srt_set_srco = dai_srt_set_srcr;
2193*8cc72361SWai Yew CHAY 	hw->dai_srt_set_srcm = dai_srt_set_srcl;
2194*8cc72361SWai Yew CHAY 	hw->dai_srt_set_rsr = dai_srt_set_rsr;
2195*8cc72361SWai Yew CHAY 	hw->dai_srt_set_drat = dai_srt_set_drat;
2196*8cc72361SWai Yew CHAY 	hw->dai_srt_set_ec = dai_srt_set_ec;
2197*8cc72361SWai Yew CHAY 	hw->dai_srt_set_et = dai_srt_set_et;
2198*8cc72361SWai Yew CHAY 	hw->dai_commit_write = dai_commit_write;
2199*8cc72361SWai Yew CHAY 
2200*8cc72361SWai Yew CHAY 	hw->dao_get_ctrl_blk = dao_get_ctrl_blk;
2201*8cc72361SWai Yew CHAY 	hw->dao_put_ctrl_blk = dao_put_ctrl_blk;
2202*8cc72361SWai Yew CHAY 	hw->dao_set_spos = dao_set_spos;
2203*8cc72361SWai Yew CHAY 	hw->dao_commit_write = dao_commit_write;
2204*8cc72361SWai Yew CHAY 	hw->dao_get_spos = dao_get_spos;
2205*8cc72361SWai Yew CHAY 
2206*8cc72361SWai Yew CHAY 	hw->daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk;
2207*8cc72361SWai Yew CHAY 	hw->daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk;
2208*8cc72361SWai Yew CHAY 	hw->daio_mgr_enb_dai = daio_mgr_enb_dai;
2209*8cc72361SWai Yew CHAY 	hw->daio_mgr_dsb_dai = daio_mgr_dsb_dai;
2210*8cc72361SWai Yew CHAY 	hw->daio_mgr_enb_dao = daio_mgr_enb_dao;
2211*8cc72361SWai Yew CHAY 	hw->daio_mgr_dsb_dao = daio_mgr_dsb_dao;
2212*8cc72361SWai Yew CHAY 	hw->daio_mgr_dao_init = daio_mgr_dao_init;
2213*8cc72361SWai Yew CHAY 	hw->daio_mgr_set_imaparc = daio_mgr_set_imaparc;
2214*8cc72361SWai Yew CHAY 	hw->daio_mgr_set_imapnxt = daio_mgr_set_imapnxt;
2215*8cc72361SWai Yew CHAY 	hw->daio_mgr_set_imapaddr = daio_mgr_set_imapaddr;
2216*8cc72361SWai Yew CHAY 	hw->daio_mgr_commit_write = daio_mgr_commit_write;
2217*8cc72361SWai Yew CHAY 
2218*8cc72361SWai Yew CHAY 	*rhw = hw;
2219*8cc72361SWai Yew CHAY 
2220*8cc72361SWai Yew CHAY 	return 0;
2221*8cc72361SWai Yew CHAY }
2222*8cc72361SWai Yew CHAY 
2223*8cc72361SWai Yew CHAY int destroy_20k1_hw_obj(struct hw *hw)
2224*8cc72361SWai Yew CHAY {
2225*8cc72361SWai Yew CHAY 	if (hw->io_base)
2226*8cc72361SWai Yew CHAY 		hw_card_shutdown(hw);
2227*8cc72361SWai Yew CHAY 
2228*8cc72361SWai Yew CHAY 	kfree(container_of(hw, struct hw20k1, hw));
2229*8cc72361SWai Yew CHAY 	return 0;
2230*8cc72361SWai Yew CHAY }
2231