xref: /linux/sound/pci/ctxfi/cthw20k1.c (revision b7bbf876087e0e2c0ba723a8398083c9a9ac1dfd)
18cc72361SWai Yew CHAY /**
28cc72361SWai Yew CHAY  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
38cc72361SWai Yew CHAY  *
48cc72361SWai Yew CHAY  * This source file is released under GPL v2 license (no other versions).
58cc72361SWai Yew CHAY  * See the COPYING file included in the main directory of this source
68cc72361SWai Yew CHAY  * distribution for the license terms and conditions.
78cc72361SWai Yew CHAY  *
88cc72361SWai Yew CHAY  * @File	cthw20k1.c
98cc72361SWai Yew CHAY  *
108cc72361SWai Yew CHAY  * @Brief
118cc72361SWai Yew CHAY  * This file contains the implementation of hardware access methord for 20k1.
128cc72361SWai Yew CHAY  *
138cc72361SWai Yew CHAY  * @Author	Liu Chun
148cc72361SWai Yew CHAY  * @Date 	Jun 24 2008
158cc72361SWai Yew CHAY  *
168cc72361SWai Yew CHAY  */
178cc72361SWai Yew CHAY 
188cc72361SWai Yew CHAY #include <linux/types.h>
198cc72361SWai Yew CHAY #include <linux/slab.h>
208cc72361SWai Yew CHAY #include <linux/pci.h>
218cc72361SWai Yew CHAY #include <linux/io.h>
228cc72361SWai Yew CHAY #include <linux/string.h>
238cc72361SWai Yew CHAY #include <linux/spinlock.h>
248cc72361SWai Yew CHAY #include <linux/kernel.h>
258cc72361SWai Yew CHAY #include <linux/interrupt.h>
26d0da727eSTakashi Iwai #include <linux/delay.h>
276d74b86dSTakashi Iwai #include "cthw20k1.h"
286d74b86dSTakashi Iwai #include "ct20k1reg.h"
298cc72361SWai Yew CHAY 
306d74b86dSTakashi Iwai #if BITS_PER_LONG == 32
316d74b86dSTakashi Iwai #define CT_XFI_DMA_MASK		DMA_BIT_MASK(32) /* 32 bit PTE */
326d74b86dSTakashi Iwai #else
336d74b86dSTakashi Iwai #define CT_XFI_DMA_MASK		DMA_BIT_MASK(64) /* 64 bit PTE */
346d74b86dSTakashi Iwai #endif
358cc72361SWai Yew CHAY 
368cc72361SWai Yew CHAY struct hw20k1 {
378cc72361SWai Yew CHAY 	struct hw hw;
388cc72361SWai Yew CHAY 	spinlock_t reg_20k1_lock;
398cc72361SWai Yew CHAY 	spinlock_t reg_pci_lock;
408cc72361SWai Yew CHAY };
418cc72361SWai Yew CHAY 
428cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg);
438cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
448cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg);
458cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data);
468cc72361SWai Yew CHAY 
478cc72361SWai Yew CHAY /*
488cc72361SWai Yew CHAY  * Type definition block.
498cc72361SWai Yew CHAY  * The layout of control structures can be directly applied on 20k2 chip.
508cc72361SWai Yew CHAY  */
518cc72361SWai Yew CHAY 
528cc72361SWai Yew CHAY /*
538cc72361SWai Yew CHAY  * SRC control block definitions.
548cc72361SWai Yew CHAY  */
558cc72361SWai Yew CHAY 
568cc72361SWai Yew CHAY /* SRC resource control block */
578cc72361SWai Yew CHAY #define SRCCTL_STATE	0x00000007
588cc72361SWai Yew CHAY #define SRCCTL_BM	0x00000008
598cc72361SWai Yew CHAY #define SRCCTL_RSR	0x00000030
608cc72361SWai Yew CHAY #define SRCCTL_SF	0x000001C0
618cc72361SWai Yew CHAY #define SRCCTL_WR	0x00000200
628cc72361SWai Yew CHAY #define SRCCTL_PM	0x00000400
638cc72361SWai Yew CHAY #define SRCCTL_ROM	0x00001800
648cc72361SWai Yew CHAY #define SRCCTL_VO	0x00002000
658cc72361SWai Yew CHAY #define SRCCTL_ST	0x00004000
668cc72361SWai Yew CHAY #define SRCCTL_IE	0x00008000
678cc72361SWai Yew CHAY #define SRCCTL_ILSZ	0x000F0000
688cc72361SWai Yew CHAY #define SRCCTL_BP	0x00100000
698cc72361SWai Yew CHAY 
708cc72361SWai Yew CHAY #define SRCCCR_CISZ	0x000007FF
718cc72361SWai Yew CHAY #define SRCCCR_CWA	0x001FF800
728cc72361SWai Yew CHAY #define SRCCCR_D	0x00200000
738cc72361SWai Yew CHAY #define SRCCCR_RS	0x01C00000
748cc72361SWai Yew CHAY #define SRCCCR_NAL	0x3E000000
758cc72361SWai Yew CHAY #define SRCCCR_RA	0xC0000000
768cc72361SWai Yew CHAY 
778cc72361SWai Yew CHAY #define SRCCA_CA	0x03FFFFFF
788cc72361SWai Yew CHAY #define SRCCA_RS	0x1C000000
798cc72361SWai Yew CHAY #define SRCCA_NAL	0xE0000000
808cc72361SWai Yew CHAY 
818cc72361SWai Yew CHAY #define SRCSA_SA	0x03FFFFFF
828cc72361SWai Yew CHAY 
838cc72361SWai Yew CHAY #define SRCLA_LA	0x03FFFFFF
848cc72361SWai Yew CHAY 
858cc72361SWai Yew CHAY /* Mixer Parameter Ring ram Low and Hight register.
868cc72361SWai Yew CHAY  * Fixed-point value in 8.24 format for parameter channel */
878cc72361SWai Yew CHAY #define MPRLH_PITCH	0xFFFFFFFF
888cc72361SWai Yew CHAY 
898cc72361SWai Yew CHAY /* SRC resource register dirty flags */
908cc72361SWai Yew CHAY union src_dirty {
918cc72361SWai Yew CHAY 	struct {
928cc72361SWai Yew CHAY 		u16 ctl:1;
938cc72361SWai Yew CHAY 		u16 ccr:1;
948cc72361SWai Yew CHAY 		u16 sa:1;
958cc72361SWai Yew CHAY 		u16 la:1;
968cc72361SWai Yew CHAY 		u16 ca:1;
978cc72361SWai Yew CHAY 		u16 mpr:1;
988cc72361SWai Yew CHAY 		u16 czbfs:1;	/* Clear Z-Buffers */
998cc72361SWai Yew CHAY 		u16 rsv:9;
1008cc72361SWai Yew CHAY 	} bf;
1018cc72361SWai Yew CHAY 	u16 data;
1028cc72361SWai Yew CHAY };
1038cc72361SWai Yew CHAY 
1048cc72361SWai Yew CHAY struct src_rsc_ctrl_blk {
1058cc72361SWai Yew CHAY 	unsigned int	ctl;
1068cc72361SWai Yew CHAY 	unsigned int 	ccr;
1078cc72361SWai Yew CHAY 	unsigned int	ca;
1088cc72361SWai Yew CHAY 	unsigned int	sa;
1098cc72361SWai Yew CHAY 	unsigned int	la;
1108cc72361SWai Yew CHAY 	unsigned int	mpr;
1118cc72361SWai Yew CHAY 	union src_dirty	dirty;
1128cc72361SWai Yew CHAY };
1138cc72361SWai Yew CHAY 
1148cc72361SWai Yew CHAY /* SRC manager control block */
1158cc72361SWai Yew CHAY union src_mgr_dirty {
1168cc72361SWai Yew CHAY 	struct {
1178cc72361SWai Yew CHAY 		u16 enb0:1;
1188cc72361SWai Yew CHAY 		u16 enb1:1;
1198cc72361SWai Yew CHAY 		u16 enb2:1;
1208cc72361SWai Yew CHAY 		u16 enb3:1;
1218cc72361SWai Yew CHAY 		u16 enb4:1;
1228cc72361SWai Yew CHAY 		u16 enb5:1;
1238cc72361SWai Yew CHAY 		u16 enb6:1;
1248cc72361SWai Yew CHAY 		u16 enb7:1;
1258cc72361SWai Yew CHAY 		u16 enbsa:1;
1268cc72361SWai Yew CHAY 		u16 rsv:7;
1278cc72361SWai Yew CHAY 	} bf;
1288cc72361SWai Yew CHAY 	u16 data;
1298cc72361SWai Yew CHAY };
1308cc72361SWai Yew CHAY 
1318cc72361SWai Yew CHAY struct src_mgr_ctrl_blk {
1328cc72361SWai Yew CHAY 	unsigned int		enbsa;
1338cc72361SWai Yew CHAY 	unsigned int		enb[8];
1348cc72361SWai Yew CHAY 	union src_mgr_dirty	dirty;
1358cc72361SWai Yew CHAY };
1368cc72361SWai Yew CHAY 
1378cc72361SWai Yew CHAY /* SRCIMP manager control block */
1388cc72361SWai Yew CHAY #define SRCAIM_ARC	0x00000FFF
1398cc72361SWai Yew CHAY #define SRCAIM_NXT	0x00FF0000
1408cc72361SWai Yew CHAY #define SRCAIM_SRC	0xFF000000
1418cc72361SWai Yew CHAY 
1428cc72361SWai Yew CHAY struct srcimap {
1438cc72361SWai Yew CHAY 	unsigned int srcaim;
1448cc72361SWai Yew CHAY 	unsigned int idx;
1458cc72361SWai Yew CHAY };
1468cc72361SWai Yew CHAY 
1478cc72361SWai Yew CHAY /* SRCIMP manager register dirty flags */
1488cc72361SWai Yew CHAY union srcimp_mgr_dirty {
1498cc72361SWai Yew CHAY 	struct {
1508cc72361SWai Yew CHAY 		u16 srcimap:1;
1518cc72361SWai Yew CHAY 		u16 rsv:15;
1528cc72361SWai Yew CHAY 	} bf;
1538cc72361SWai Yew CHAY 	u16 data;
1548cc72361SWai Yew CHAY };
1558cc72361SWai Yew CHAY 
1568cc72361SWai Yew CHAY struct srcimp_mgr_ctrl_blk {
1578cc72361SWai Yew CHAY 	struct srcimap		srcimap;
1588cc72361SWai Yew CHAY 	union srcimp_mgr_dirty	dirty;
1598cc72361SWai Yew CHAY };
1608cc72361SWai Yew CHAY 
1618cc72361SWai Yew CHAY /*
1628cc72361SWai Yew CHAY  * Function implementation block.
1638cc72361SWai Yew CHAY  */
1648cc72361SWai Yew CHAY 
1658cc72361SWai Yew CHAY static int src_get_rsc_ctrl_blk(void **rblk)
1668cc72361SWai Yew CHAY {
1678cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *blk;
1688cc72361SWai Yew CHAY 
1698cc72361SWai Yew CHAY 	*rblk = NULL;
1708cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
1718cc72361SWai Yew CHAY 	if (NULL == blk)
1728cc72361SWai Yew CHAY 		return -ENOMEM;
1738cc72361SWai Yew CHAY 
1748cc72361SWai Yew CHAY 	*rblk = blk;
1758cc72361SWai Yew CHAY 
1768cc72361SWai Yew CHAY 	return 0;
1778cc72361SWai Yew CHAY }
1788cc72361SWai Yew CHAY 
1798cc72361SWai Yew CHAY static int src_put_rsc_ctrl_blk(void *blk)
1808cc72361SWai Yew CHAY {
1818cc72361SWai Yew CHAY 	kfree((struct src_rsc_ctrl_blk *)blk);
1828cc72361SWai Yew CHAY 
1838cc72361SWai Yew CHAY 	return 0;
1848cc72361SWai Yew CHAY }
1858cc72361SWai Yew CHAY 
1868cc72361SWai Yew CHAY static int src_set_state(void *blk, unsigned int state)
1878cc72361SWai Yew CHAY {
1888cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
1898cc72361SWai Yew CHAY 
1908cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_STATE, state);
1918cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
1928cc72361SWai Yew CHAY 	return 0;
1938cc72361SWai Yew CHAY }
1948cc72361SWai Yew CHAY 
1958cc72361SWai Yew CHAY static int src_set_bm(void *blk, unsigned int bm)
1968cc72361SWai Yew CHAY {
1978cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
1988cc72361SWai Yew CHAY 
1998cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_BM, bm);
2008cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2018cc72361SWai Yew CHAY 	return 0;
2028cc72361SWai Yew CHAY }
2038cc72361SWai Yew CHAY 
2048cc72361SWai Yew CHAY static int src_set_rsr(void *blk, unsigned int rsr)
2058cc72361SWai Yew CHAY {
2068cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2078cc72361SWai Yew CHAY 
2088cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_RSR, rsr);
2098cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2108cc72361SWai Yew CHAY 	return 0;
2118cc72361SWai Yew CHAY }
2128cc72361SWai Yew CHAY 
2138cc72361SWai Yew CHAY static int src_set_sf(void *blk, unsigned int sf)
2148cc72361SWai Yew CHAY {
2158cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2168cc72361SWai Yew CHAY 
2178cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_SF, sf);
2188cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2198cc72361SWai Yew CHAY 	return 0;
2208cc72361SWai Yew CHAY }
2218cc72361SWai Yew CHAY 
2228cc72361SWai Yew CHAY static int src_set_wr(void *blk, unsigned int wr)
2238cc72361SWai Yew CHAY {
2248cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2258cc72361SWai Yew CHAY 
2268cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_WR, wr);
2278cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2288cc72361SWai Yew CHAY 	return 0;
2298cc72361SWai Yew CHAY }
2308cc72361SWai Yew CHAY 
2318cc72361SWai Yew CHAY static int src_set_pm(void *blk, unsigned int pm)
2328cc72361SWai Yew CHAY {
2338cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2348cc72361SWai Yew CHAY 
2358cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_PM, pm);
2368cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2378cc72361SWai Yew CHAY 	return 0;
2388cc72361SWai Yew CHAY }
2398cc72361SWai Yew CHAY 
2408cc72361SWai Yew CHAY static int src_set_rom(void *blk, unsigned int rom)
2418cc72361SWai Yew CHAY {
2428cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2438cc72361SWai Yew CHAY 
2448cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ROM, rom);
2458cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2468cc72361SWai Yew CHAY 	return 0;
2478cc72361SWai Yew CHAY }
2488cc72361SWai Yew CHAY 
2498cc72361SWai Yew CHAY static int src_set_vo(void *blk, unsigned int vo)
2508cc72361SWai Yew CHAY {
2518cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2528cc72361SWai Yew CHAY 
2538cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_VO, vo);
2548cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2558cc72361SWai Yew CHAY 	return 0;
2568cc72361SWai Yew CHAY }
2578cc72361SWai Yew CHAY 
2588cc72361SWai Yew CHAY static int src_set_st(void *blk, unsigned int st)
2598cc72361SWai Yew CHAY {
2608cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2618cc72361SWai Yew CHAY 
2628cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ST, st);
2638cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2648cc72361SWai Yew CHAY 	return 0;
2658cc72361SWai Yew CHAY }
2668cc72361SWai Yew CHAY 
2678cc72361SWai Yew CHAY static int src_set_ie(void *blk, unsigned int ie)
2688cc72361SWai Yew CHAY {
2698cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2708cc72361SWai Yew CHAY 
2718cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_IE, ie);
2728cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2738cc72361SWai Yew CHAY 	return 0;
2748cc72361SWai Yew CHAY }
2758cc72361SWai Yew CHAY 
2768cc72361SWai Yew CHAY static int src_set_ilsz(void *blk, unsigned int ilsz)
2778cc72361SWai Yew CHAY {
2788cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2798cc72361SWai Yew CHAY 
2808cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
2818cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2828cc72361SWai Yew CHAY 	return 0;
2838cc72361SWai Yew CHAY }
2848cc72361SWai Yew CHAY 
2858cc72361SWai Yew CHAY static int src_set_bp(void *blk, unsigned int bp)
2868cc72361SWai Yew CHAY {
2878cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2888cc72361SWai Yew CHAY 
2898cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_BP, bp);
2908cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2918cc72361SWai Yew CHAY 	return 0;
2928cc72361SWai Yew CHAY }
2938cc72361SWai Yew CHAY 
2948cc72361SWai Yew CHAY static int src_set_cisz(void *blk, unsigned int cisz)
2958cc72361SWai Yew CHAY {
2968cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2978cc72361SWai Yew CHAY 
2988cc72361SWai Yew CHAY 	set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
2998cc72361SWai Yew CHAY 	ctl->dirty.bf.ccr = 1;
3008cc72361SWai Yew CHAY 	return 0;
3018cc72361SWai Yew CHAY }
3028cc72361SWai Yew CHAY 
3038cc72361SWai Yew CHAY static int src_set_ca(void *blk, unsigned int ca)
3048cc72361SWai Yew CHAY {
3058cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3068cc72361SWai Yew CHAY 
3078cc72361SWai Yew CHAY 	set_field(&ctl->ca, SRCCA_CA, ca);
3088cc72361SWai Yew CHAY 	ctl->dirty.bf.ca = 1;
3098cc72361SWai Yew CHAY 	return 0;
3108cc72361SWai Yew CHAY }
3118cc72361SWai Yew CHAY 
3128cc72361SWai Yew CHAY static int src_set_sa(void *blk, unsigned int sa)
3138cc72361SWai Yew CHAY {
3148cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3158cc72361SWai Yew CHAY 
3168cc72361SWai Yew CHAY 	set_field(&ctl->sa, SRCSA_SA, sa);
3178cc72361SWai Yew CHAY 	ctl->dirty.bf.sa = 1;
3188cc72361SWai Yew CHAY 	return 0;
3198cc72361SWai Yew CHAY }
3208cc72361SWai Yew CHAY 
3218cc72361SWai Yew CHAY static int src_set_la(void *blk, unsigned int la)
3228cc72361SWai Yew CHAY {
3238cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3248cc72361SWai Yew CHAY 
3258cc72361SWai Yew CHAY 	set_field(&ctl->la, SRCLA_LA, la);
3268cc72361SWai Yew CHAY 	ctl->dirty.bf.la = 1;
3278cc72361SWai Yew CHAY 	return 0;
3288cc72361SWai Yew CHAY }
3298cc72361SWai Yew CHAY 
3308cc72361SWai Yew CHAY static int src_set_pitch(void *blk, unsigned int pitch)
3318cc72361SWai Yew CHAY {
3328cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3338cc72361SWai Yew CHAY 
3348cc72361SWai Yew CHAY 	set_field(&ctl->mpr, MPRLH_PITCH, pitch);
3358cc72361SWai Yew CHAY 	ctl->dirty.bf.mpr = 1;
3368cc72361SWai Yew CHAY 	return 0;
3378cc72361SWai Yew CHAY }
3388cc72361SWai Yew CHAY 
3398cc72361SWai Yew CHAY static int src_set_clear_zbufs(void *blk, unsigned int clear)
3408cc72361SWai Yew CHAY {
3418cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
3428cc72361SWai Yew CHAY 	return 0;
3438cc72361SWai Yew CHAY }
3448cc72361SWai Yew CHAY 
3458cc72361SWai Yew CHAY static int src_set_dirty(void *blk, unsigned int flags)
3468cc72361SWai Yew CHAY {
3478cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
3488cc72361SWai Yew CHAY 	return 0;
3498cc72361SWai Yew CHAY }
3508cc72361SWai Yew CHAY 
3518cc72361SWai Yew CHAY static int src_set_dirty_all(void *blk)
3528cc72361SWai Yew CHAY {
3538cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
3548cc72361SWai Yew CHAY 	return 0;
3558cc72361SWai Yew CHAY }
3568cc72361SWai Yew CHAY 
3578cc72361SWai Yew CHAY #define AR_SLOT_SIZE		4096
3588cc72361SWai Yew CHAY #define AR_SLOT_BLOCK_SIZE	16
3598cc72361SWai Yew CHAY #define AR_PTS_PITCH		6
3608cc72361SWai Yew CHAY #define AR_PARAM_SRC_OFFSET	0x60
3618cc72361SWai Yew CHAY 
3628cc72361SWai Yew CHAY static unsigned int src_param_pitch_mixer(unsigned int src_idx)
3638cc72361SWai Yew CHAY {
3648cc72361SWai Yew CHAY 	return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
3658cc72361SWai Yew CHAY 			- AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
3668cc72361SWai Yew CHAY 
3678cc72361SWai Yew CHAY }
3688cc72361SWai Yew CHAY 
3698cc72361SWai Yew CHAY static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
3708cc72361SWai Yew CHAY {
3718cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3728cc72361SWai Yew CHAY 	int i = 0;
3738cc72361SWai Yew CHAY 
3748cc72361SWai Yew CHAY 	if (ctl->dirty.bf.czbfs) {
3758cc72361SWai Yew CHAY 		/* Clear Z-Buffer registers */
3768cc72361SWai Yew CHAY 		for (i = 0; i < 8; i++)
3778cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0);
3788cc72361SWai Yew CHAY 
3798cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++)
3808cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0);
3818cc72361SWai Yew CHAY 
3828cc72361SWai Yew CHAY 		for (i = 0; i < 8; i++)
3838cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0);
3848cc72361SWai Yew CHAY 
3858cc72361SWai Yew CHAY 		ctl->dirty.bf.czbfs = 0;
3868cc72361SWai Yew CHAY 	}
3878cc72361SWai Yew CHAY 	if (ctl->dirty.bf.mpr) {
3888cc72361SWai Yew CHAY 		/* Take the parameter mixer resource in the same group as that
3898cc72361SWai Yew CHAY 		 * the idx src is in for simplicity. Unlike src, all conjugate
3908cc72361SWai Yew CHAY 		 * parameter mixer resources must be programmed for
3918cc72361SWai Yew CHAY 		 * corresponding conjugate src resources. */
3928cc72361SWai Yew CHAY 		unsigned int pm_idx = src_param_pitch_mixer(idx);
3938cc72361SWai Yew CHAY 		hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr);
3948cc72361SWai Yew CHAY 		hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3);
3958cc72361SWai Yew CHAY 		hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0);
3968cc72361SWai Yew CHAY 		ctl->dirty.bf.mpr = 0;
3978cc72361SWai Yew CHAY 	}
3988cc72361SWai Yew CHAY 	if (ctl->dirty.bf.sa) {
3998cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa);
4008cc72361SWai Yew CHAY 		ctl->dirty.bf.sa = 0;
4018cc72361SWai Yew CHAY 	}
4028cc72361SWai Yew CHAY 	if (ctl->dirty.bf.la) {
4038cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la);
4048cc72361SWai Yew CHAY 		ctl->dirty.bf.la = 0;
4058cc72361SWai Yew CHAY 	}
4068cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ca) {
4078cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca);
4088cc72361SWai Yew CHAY 		ctl->dirty.bf.ca = 0;
4098cc72361SWai Yew CHAY 	}
4108cc72361SWai Yew CHAY 
4118cc72361SWai Yew CHAY 	/* Write srccf register */
4128cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCCF+idx*0x100, 0x0);
4138cc72361SWai Yew CHAY 
4148cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ccr) {
4158cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr);
4168cc72361SWai Yew CHAY 		ctl->dirty.bf.ccr = 0;
4178cc72361SWai Yew CHAY 	}
4188cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ctl) {
4198cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl);
4208cc72361SWai Yew CHAY 		ctl->dirty.bf.ctl = 0;
4218cc72361SWai Yew CHAY 	}
4228cc72361SWai Yew CHAY 
4238cc72361SWai Yew CHAY 	return 0;
4248cc72361SWai Yew CHAY }
4258cc72361SWai Yew CHAY 
4268cc72361SWai Yew CHAY static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
4278cc72361SWai Yew CHAY {
4288cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
4298cc72361SWai Yew CHAY 
4308cc72361SWai Yew CHAY 	ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100);
4318cc72361SWai Yew CHAY 	ctl->dirty.bf.ca = 0;
4328cc72361SWai Yew CHAY 
4338cc72361SWai Yew CHAY 	return get_field(ctl->ca, SRCCA_CA);
4348cc72361SWai Yew CHAY }
4358cc72361SWai Yew CHAY 
4368cc72361SWai Yew CHAY static unsigned int src_get_dirty(void *blk)
4378cc72361SWai Yew CHAY {
4388cc72361SWai Yew CHAY 	return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
4398cc72361SWai Yew CHAY }
4408cc72361SWai Yew CHAY 
4418cc72361SWai Yew CHAY static unsigned int src_dirty_conj_mask(void)
4428cc72361SWai Yew CHAY {
4438cc72361SWai Yew CHAY 	return 0x20;
4448cc72361SWai Yew CHAY }
4458cc72361SWai Yew CHAY 
4468cc72361SWai Yew CHAY static int src_mgr_enbs_src(void *blk, unsigned int idx)
4478cc72361SWai Yew CHAY {
4488cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0);
4498cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
4508cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
4518cc72361SWai Yew CHAY 	return 0;
4528cc72361SWai Yew CHAY }
4538cc72361SWai Yew CHAY 
4548cc72361SWai Yew CHAY static int src_mgr_enb_src(void *blk, unsigned int idx)
4558cc72361SWai Yew CHAY {
4568cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
4578cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
4588cc72361SWai Yew CHAY 	return 0;
4598cc72361SWai Yew CHAY }
4608cc72361SWai Yew CHAY 
4618cc72361SWai Yew CHAY static int src_mgr_dsb_src(void *blk, unsigned int idx)
4628cc72361SWai Yew CHAY {
4638cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
4648cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
4658cc72361SWai Yew CHAY 	return 0;
4668cc72361SWai Yew CHAY }
4678cc72361SWai Yew CHAY 
4688cc72361SWai Yew CHAY static int src_mgr_commit_write(struct hw *hw, void *blk)
4698cc72361SWai Yew CHAY {
4708cc72361SWai Yew CHAY 	struct src_mgr_ctrl_blk *ctl = blk;
4718cc72361SWai Yew CHAY 	int i = 0;
4728cc72361SWai Yew CHAY 	unsigned int ret = 0;
4738cc72361SWai Yew CHAY 
4748cc72361SWai Yew CHAY 	if (ctl->dirty.bf.enbsa) {
4758cc72361SWai Yew CHAY 		do {
4768cc72361SWai Yew CHAY 			ret = hw_read_20kx(hw, SRCENBSTAT);
4778cc72361SWai Yew CHAY 		} while (ret & 0x1);
4788cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCENBS, ctl->enbsa);
4798cc72361SWai Yew CHAY 		ctl->dirty.bf.enbsa = 0;
4808cc72361SWai Yew CHAY 	}
4818cc72361SWai Yew CHAY 	for (i = 0; i < 8; i++) {
4828cc72361SWai Yew CHAY 		if ((ctl->dirty.data & (0x1 << i))) {
4838cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]);
4848cc72361SWai Yew CHAY 			ctl->dirty.data &= ~(0x1 << i);
4858cc72361SWai Yew CHAY 		}
4868cc72361SWai Yew CHAY 	}
4878cc72361SWai Yew CHAY 
4888cc72361SWai Yew CHAY 	return 0;
4898cc72361SWai Yew CHAY }
4908cc72361SWai Yew CHAY 
4918cc72361SWai Yew CHAY static int src_mgr_get_ctrl_blk(void **rblk)
4928cc72361SWai Yew CHAY {
4938cc72361SWai Yew CHAY 	struct src_mgr_ctrl_blk *blk;
4948cc72361SWai Yew CHAY 
4958cc72361SWai Yew CHAY 	*rblk = NULL;
4968cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
4978cc72361SWai Yew CHAY 	if (NULL == blk)
4988cc72361SWai Yew CHAY 		return -ENOMEM;
4998cc72361SWai Yew CHAY 
5008cc72361SWai Yew CHAY 	*rblk = blk;
5018cc72361SWai Yew CHAY 
5028cc72361SWai Yew CHAY 	return 0;
5038cc72361SWai Yew CHAY }
5048cc72361SWai Yew CHAY 
5058cc72361SWai Yew CHAY static int src_mgr_put_ctrl_blk(void *blk)
5068cc72361SWai Yew CHAY {
5078cc72361SWai Yew CHAY 	kfree((struct src_mgr_ctrl_blk *)blk);
5088cc72361SWai Yew CHAY 
5098cc72361SWai Yew CHAY 	return 0;
5108cc72361SWai Yew CHAY }
5118cc72361SWai Yew CHAY 
5128cc72361SWai Yew CHAY static int srcimp_mgr_get_ctrl_blk(void **rblk)
5138cc72361SWai Yew CHAY {
5148cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *blk;
5158cc72361SWai Yew CHAY 
5168cc72361SWai Yew CHAY 	*rblk = NULL;
5178cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
5188cc72361SWai Yew CHAY 	if (NULL == blk)
5198cc72361SWai Yew CHAY 		return -ENOMEM;
5208cc72361SWai Yew CHAY 
5218cc72361SWai Yew CHAY 	*rblk = blk;
5228cc72361SWai Yew CHAY 
5238cc72361SWai Yew CHAY 	return 0;
5248cc72361SWai Yew CHAY }
5258cc72361SWai Yew CHAY 
5268cc72361SWai Yew CHAY static int srcimp_mgr_put_ctrl_blk(void *blk)
5278cc72361SWai Yew CHAY {
5288cc72361SWai Yew CHAY 	kfree((struct srcimp_mgr_ctrl_blk *)blk);
5298cc72361SWai Yew CHAY 
5308cc72361SWai Yew CHAY 	return 0;
5318cc72361SWai Yew CHAY }
5328cc72361SWai Yew CHAY 
5338cc72361SWai Yew CHAY static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
5348cc72361SWai Yew CHAY {
5358cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5368cc72361SWai Yew CHAY 
5378cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
5388cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5398cc72361SWai Yew CHAY 	return 0;
5408cc72361SWai Yew CHAY }
5418cc72361SWai Yew CHAY 
5428cc72361SWai Yew CHAY static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
5438cc72361SWai Yew CHAY {
5448cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5458cc72361SWai Yew CHAY 
5468cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
5478cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5488cc72361SWai Yew CHAY 	return 0;
5498cc72361SWai Yew CHAY }
5508cc72361SWai Yew CHAY 
5518cc72361SWai Yew CHAY static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
5528cc72361SWai Yew CHAY {
5538cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5548cc72361SWai Yew CHAY 
5558cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
5568cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5578cc72361SWai Yew CHAY 	return 0;
5588cc72361SWai Yew CHAY }
5598cc72361SWai Yew CHAY 
5608cc72361SWai Yew CHAY static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
5618cc72361SWai Yew CHAY {
5628cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5638cc72361SWai Yew CHAY 
5648cc72361SWai Yew CHAY 	ctl->srcimap.idx = addr;
5658cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5668cc72361SWai Yew CHAY 	return 0;
5678cc72361SWai Yew CHAY }
5688cc72361SWai Yew CHAY 
5698cc72361SWai Yew CHAY static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
5708cc72361SWai Yew CHAY {
5718cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5728cc72361SWai Yew CHAY 
5738cc72361SWai Yew CHAY 	if (ctl->dirty.bf.srcimap) {
5748cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100,
5758cc72361SWai Yew CHAY 						ctl->srcimap.srcaim);
5768cc72361SWai Yew CHAY 		ctl->dirty.bf.srcimap = 0;
5778cc72361SWai Yew CHAY 	}
5788cc72361SWai Yew CHAY 
5798cc72361SWai Yew CHAY 	return 0;
5808cc72361SWai Yew CHAY }
5818cc72361SWai Yew CHAY 
5828cc72361SWai Yew CHAY /*
5838cc72361SWai Yew CHAY  * AMIXER control block definitions.
5848cc72361SWai Yew CHAY  */
5858cc72361SWai Yew CHAY 
5868cc72361SWai Yew CHAY #define AMOPLO_M	0x00000003
5878cc72361SWai Yew CHAY #define AMOPLO_X	0x0003FFF0
5888cc72361SWai Yew CHAY #define AMOPLO_Y	0xFFFC0000
5898cc72361SWai Yew CHAY 
5908cc72361SWai Yew CHAY #define AMOPHI_SADR	0x000000FF
5918cc72361SWai Yew CHAY #define AMOPHI_SE	0x80000000
5928cc72361SWai Yew CHAY 
5938cc72361SWai Yew CHAY /* AMIXER resource register dirty flags */
5948cc72361SWai Yew CHAY union amixer_dirty {
5958cc72361SWai Yew CHAY 	struct {
5968cc72361SWai Yew CHAY 		u16 amoplo:1;
5978cc72361SWai Yew CHAY 		u16 amophi:1;
5988cc72361SWai Yew CHAY 		u16 rsv:14;
5998cc72361SWai Yew CHAY 	} bf;
6008cc72361SWai Yew CHAY 	u16 data;
6018cc72361SWai Yew CHAY };
6028cc72361SWai Yew CHAY 
6038cc72361SWai Yew CHAY /* AMIXER resource control block */
6048cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk {
6058cc72361SWai Yew CHAY 	unsigned int		amoplo;
6068cc72361SWai Yew CHAY 	unsigned int		amophi;
6078cc72361SWai Yew CHAY 	union amixer_dirty	dirty;
6088cc72361SWai Yew CHAY };
6098cc72361SWai Yew CHAY 
6108cc72361SWai Yew CHAY static int amixer_set_mode(void *blk, unsigned int mode)
6118cc72361SWai Yew CHAY {
6128cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6138cc72361SWai Yew CHAY 
6148cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_M, mode);
6158cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6168cc72361SWai Yew CHAY 	return 0;
6178cc72361SWai Yew CHAY }
6188cc72361SWai Yew CHAY 
6198cc72361SWai Yew CHAY static int amixer_set_iv(void *blk, unsigned int iv)
6208cc72361SWai Yew CHAY {
6218cc72361SWai Yew CHAY 	/* 20k1 amixer does not have this field */
6228cc72361SWai Yew CHAY 	return 0;
6238cc72361SWai Yew CHAY }
6248cc72361SWai Yew CHAY 
6258cc72361SWai Yew CHAY static int amixer_set_x(void *blk, unsigned int x)
6268cc72361SWai Yew CHAY {
6278cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6288cc72361SWai Yew CHAY 
6298cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_X, x);
6308cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6318cc72361SWai Yew CHAY 	return 0;
6328cc72361SWai Yew CHAY }
6338cc72361SWai Yew CHAY 
6348cc72361SWai Yew CHAY static int amixer_set_y(void *blk, unsigned int y)
6358cc72361SWai Yew CHAY {
6368cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6378cc72361SWai Yew CHAY 
6388cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_Y, y);
6398cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6408cc72361SWai Yew CHAY 	return 0;
6418cc72361SWai Yew CHAY }
6428cc72361SWai Yew CHAY 
6438cc72361SWai Yew CHAY static int amixer_set_sadr(void *blk, unsigned int sadr)
6448cc72361SWai Yew CHAY {
6458cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6468cc72361SWai Yew CHAY 
6478cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SADR, sadr);
6488cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
6498cc72361SWai Yew CHAY 	return 0;
6508cc72361SWai Yew CHAY }
6518cc72361SWai Yew CHAY 
6528cc72361SWai Yew CHAY static int amixer_set_se(void *blk, unsigned int se)
6538cc72361SWai Yew CHAY {
6548cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6558cc72361SWai Yew CHAY 
6568cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SE, se);
6578cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
6588cc72361SWai Yew CHAY 	return 0;
6598cc72361SWai Yew CHAY }
6608cc72361SWai Yew CHAY 
6618cc72361SWai Yew CHAY static int amixer_set_dirty(void *blk, unsigned int flags)
6628cc72361SWai Yew CHAY {
6638cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
6648cc72361SWai Yew CHAY 	return 0;
6658cc72361SWai Yew CHAY }
6668cc72361SWai Yew CHAY 
6678cc72361SWai Yew CHAY static int amixer_set_dirty_all(void *blk)
6688cc72361SWai Yew CHAY {
6698cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
6708cc72361SWai Yew CHAY 	return 0;
6718cc72361SWai Yew CHAY }
6728cc72361SWai Yew CHAY 
6738cc72361SWai Yew CHAY static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
6748cc72361SWai Yew CHAY {
6758cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6768cc72361SWai Yew CHAY 
6778cc72361SWai Yew CHAY 	if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
6788cc72361SWai Yew CHAY 		hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo);
6798cc72361SWai Yew CHAY 		ctl->dirty.bf.amoplo = 0;
6808cc72361SWai Yew CHAY 		hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi);
6818cc72361SWai Yew CHAY 		ctl->dirty.bf.amophi = 0;
6828cc72361SWai Yew CHAY 	}
6838cc72361SWai Yew CHAY 
6848cc72361SWai Yew CHAY 	return 0;
6858cc72361SWai Yew CHAY }
6868cc72361SWai Yew CHAY 
6878cc72361SWai Yew CHAY static int amixer_get_y(void *blk)
6888cc72361SWai Yew CHAY {
6898cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6908cc72361SWai Yew CHAY 
6918cc72361SWai Yew CHAY 	return get_field(ctl->amoplo, AMOPLO_Y);
6928cc72361SWai Yew CHAY }
6938cc72361SWai Yew CHAY 
6948cc72361SWai Yew CHAY static unsigned int amixer_get_dirty(void *blk)
6958cc72361SWai Yew CHAY {
6968cc72361SWai Yew CHAY 	return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
6978cc72361SWai Yew CHAY }
6988cc72361SWai Yew CHAY 
6998cc72361SWai Yew CHAY static int amixer_rsc_get_ctrl_blk(void **rblk)
7008cc72361SWai Yew CHAY {
7018cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *blk;
7028cc72361SWai Yew CHAY 
7038cc72361SWai Yew CHAY 	*rblk = NULL;
7048cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
7058cc72361SWai Yew CHAY 	if (NULL == blk)
7068cc72361SWai Yew CHAY 		return -ENOMEM;
7078cc72361SWai Yew CHAY 
7088cc72361SWai Yew CHAY 	*rblk = blk;
7098cc72361SWai Yew CHAY 
7108cc72361SWai Yew CHAY 	return 0;
7118cc72361SWai Yew CHAY }
7128cc72361SWai Yew CHAY 
7138cc72361SWai Yew CHAY static int amixer_rsc_put_ctrl_blk(void *blk)
7148cc72361SWai Yew CHAY {
7158cc72361SWai Yew CHAY 	kfree((struct amixer_rsc_ctrl_blk *)blk);
7168cc72361SWai Yew CHAY 
7178cc72361SWai Yew CHAY 	return 0;
7188cc72361SWai Yew CHAY }
7198cc72361SWai Yew CHAY 
7208cc72361SWai Yew CHAY static int amixer_mgr_get_ctrl_blk(void **rblk)
7218cc72361SWai Yew CHAY {
7228cc72361SWai Yew CHAY 	/*amixer_mgr_ctrl_blk_t *blk;*/
7238cc72361SWai Yew CHAY 
7248cc72361SWai Yew CHAY 	*rblk = NULL;
7258cc72361SWai Yew CHAY 	/*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
7268cc72361SWai Yew CHAY 	if (NULL == blk)
7278cc72361SWai Yew CHAY 		return -ENOMEM;
7288cc72361SWai Yew CHAY 
7298cc72361SWai Yew CHAY 	*rblk = blk;*/
7308cc72361SWai Yew CHAY 
7318cc72361SWai Yew CHAY 	return 0;
7328cc72361SWai Yew CHAY }
7338cc72361SWai Yew CHAY 
7348cc72361SWai Yew CHAY static int amixer_mgr_put_ctrl_blk(void *blk)
7358cc72361SWai Yew CHAY {
7368cc72361SWai Yew CHAY 	/*kfree((amixer_mgr_ctrl_blk_t *)blk);*/
7378cc72361SWai Yew CHAY 
7388cc72361SWai Yew CHAY 	return 0;
7398cc72361SWai Yew CHAY }
7408cc72361SWai Yew CHAY 
7418cc72361SWai Yew CHAY /*
7428cc72361SWai Yew CHAY  * DAIO control block definitions.
7438cc72361SWai Yew CHAY  */
7448cc72361SWai Yew CHAY 
7458cc72361SWai Yew CHAY /* Receiver Sample Rate Tracker Control register */
7468cc72361SWai Yew CHAY #define SRTCTL_SRCR	0x000000FF
7478cc72361SWai Yew CHAY #define SRTCTL_SRCL	0x0000FF00
7488cc72361SWai Yew CHAY #define SRTCTL_RSR	0x00030000
7498cc72361SWai Yew CHAY #define SRTCTL_DRAT	0x000C0000
7508cc72361SWai Yew CHAY #define SRTCTL_RLE	0x10000000
7518cc72361SWai Yew CHAY #define SRTCTL_RLP	0x20000000
7528cc72361SWai Yew CHAY #define SRTCTL_EC	0x40000000
7538cc72361SWai Yew CHAY #define SRTCTL_ET	0x80000000
7548cc72361SWai Yew CHAY 
7558cc72361SWai Yew CHAY /* DAIO Receiver register dirty flags */
7568cc72361SWai Yew CHAY union dai_dirty {
7578cc72361SWai Yew CHAY 	struct {
7588cc72361SWai Yew CHAY 		u16 srtctl:1;
7598cc72361SWai Yew CHAY 		u16 rsv:15;
7608cc72361SWai Yew CHAY 	} bf;
7618cc72361SWai Yew CHAY 	u16 data;
7628cc72361SWai Yew CHAY };
7638cc72361SWai Yew CHAY 
7648cc72361SWai Yew CHAY /* DAIO Receiver control block */
7658cc72361SWai Yew CHAY struct dai_ctrl_blk {
7668cc72361SWai Yew CHAY 	unsigned int	srtctl;
7678cc72361SWai Yew CHAY 	union dai_dirty	dirty;
7688cc72361SWai Yew CHAY };
7698cc72361SWai Yew CHAY 
7708cc72361SWai Yew CHAY /* S/PDIF Transmitter register dirty flags */
7718cc72361SWai Yew CHAY union dao_dirty {
7728cc72361SWai Yew CHAY 	struct {
7738cc72361SWai Yew CHAY 		u16 spos:1;
7748cc72361SWai Yew CHAY 		u16 rsv:15;
7758cc72361SWai Yew CHAY 	} bf;
7768cc72361SWai Yew CHAY 	u16 data;
7778cc72361SWai Yew CHAY };
7788cc72361SWai Yew CHAY 
7798cc72361SWai Yew CHAY /* S/PDIF Transmitter control block */
7808cc72361SWai Yew CHAY struct dao_ctrl_blk {
7818cc72361SWai Yew CHAY 	unsigned int 	spos; /* S/PDIF Output Channel Status Register */
7828cc72361SWai Yew CHAY 	union dao_dirty	dirty;
7838cc72361SWai Yew CHAY };
7848cc72361SWai Yew CHAY 
7858cc72361SWai Yew CHAY /* Audio Input Mapper RAM */
7868cc72361SWai Yew CHAY #define AIM_ARC		0x00000FFF
7878cc72361SWai Yew CHAY #define AIM_NXT		0x007F0000
7888cc72361SWai Yew CHAY 
7898cc72361SWai Yew CHAY struct daoimap {
7908cc72361SWai Yew CHAY 	unsigned int aim;
7918cc72361SWai Yew CHAY 	unsigned int idx;
7928cc72361SWai Yew CHAY };
7938cc72361SWai Yew CHAY 
7948cc72361SWai Yew CHAY /* I2S Transmitter/Receiver Control register */
7958cc72361SWai Yew CHAY #define I2SCTL_EA	0x00000004
7968cc72361SWai Yew CHAY #define I2SCTL_EI	0x00000010
7978cc72361SWai Yew CHAY 
7988cc72361SWai Yew CHAY /* S/PDIF Transmitter Control register */
7998cc72361SWai Yew CHAY #define SPOCTL_OE	0x00000001
8008cc72361SWai Yew CHAY #define SPOCTL_OS	0x0000000E
8018cc72361SWai Yew CHAY #define SPOCTL_RIV	0x00000010
8028cc72361SWai Yew CHAY #define SPOCTL_LIV	0x00000020
8038cc72361SWai Yew CHAY #define SPOCTL_SR	0x000000C0
8048cc72361SWai Yew CHAY 
8058cc72361SWai Yew CHAY /* S/PDIF Receiver Control register */
8068cc72361SWai Yew CHAY #define SPICTL_EN	0x00000001
8078cc72361SWai Yew CHAY #define SPICTL_I24	0x00000002
8088cc72361SWai Yew CHAY #define SPICTL_IB	0x00000004
8098cc72361SWai Yew CHAY #define SPICTL_SM	0x00000008
8108cc72361SWai Yew CHAY #define SPICTL_VM	0x00000010
8118cc72361SWai Yew CHAY 
8128cc72361SWai Yew CHAY /* DAIO manager register dirty flags */
8138cc72361SWai Yew CHAY union daio_mgr_dirty {
8148cc72361SWai Yew CHAY 	struct {
8158cc72361SWai Yew CHAY 		u32 i2soctl:4;
8168cc72361SWai Yew CHAY 		u32 i2sictl:4;
8178cc72361SWai Yew CHAY 		u32 spoctl:4;
8188cc72361SWai Yew CHAY 		u32 spictl:4;
8198cc72361SWai Yew CHAY 		u32 daoimap:1;
8208cc72361SWai Yew CHAY 		u32 rsv:15;
8218cc72361SWai Yew CHAY 	} bf;
8228cc72361SWai Yew CHAY 	u32 data;
8238cc72361SWai Yew CHAY };
8248cc72361SWai Yew CHAY 
8258cc72361SWai Yew CHAY /* DAIO manager control block */
8268cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk {
8278cc72361SWai Yew CHAY 	unsigned int		i2sctl;
8288cc72361SWai Yew CHAY 	unsigned int		spoctl;
8298cc72361SWai Yew CHAY 	unsigned int		spictl;
8308cc72361SWai Yew CHAY 	struct daoimap		daoimap;
8318cc72361SWai Yew CHAY 	union daio_mgr_dirty	dirty;
8328cc72361SWai Yew CHAY };
8338cc72361SWai Yew CHAY 
8348cc72361SWai Yew CHAY static int dai_srt_set_srcr(void *blk, unsigned int src)
8358cc72361SWai Yew CHAY {
8368cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8378cc72361SWai Yew CHAY 
8388cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_SRCR, src);
8398cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
8408cc72361SWai Yew CHAY 	return 0;
8418cc72361SWai Yew CHAY }
8428cc72361SWai Yew CHAY 
8438cc72361SWai Yew CHAY static int dai_srt_set_srcl(void *blk, unsigned int src)
8448cc72361SWai Yew CHAY {
8458cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8468cc72361SWai Yew CHAY 
8478cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_SRCL, src);
8488cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
8498cc72361SWai Yew CHAY 	return 0;
8508cc72361SWai Yew CHAY }
8518cc72361SWai Yew CHAY 
8528cc72361SWai Yew CHAY static int dai_srt_set_rsr(void *blk, unsigned int rsr)
8538cc72361SWai Yew CHAY {
8548cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8558cc72361SWai Yew CHAY 
8568cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_RSR, rsr);
8578cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
8588cc72361SWai Yew CHAY 	return 0;
8598cc72361SWai Yew CHAY }
8608cc72361SWai Yew CHAY 
8618cc72361SWai Yew CHAY static int dai_srt_set_drat(void *blk, unsigned int drat)
8628cc72361SWai Yew CHAY {
8638cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8648cc72361SWai Yew CHAY 
8658cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_DRAT, drat);
8668cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
8678cc72361SWai Yew CHAY 	return 0;
8688cc72361SWai Yew CHAY }
8698cc72361SWai Yew CHAY 
8708cc72361SWai Yew CHAY static int dai_srt_set_ec(void *blk, unsigned int ec)
8718cc72361SWai Yew CHAY {
8728cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8738cc72361SWai Yew CHAY 
8748cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0);
8758cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
8768cc72361SWai Yew CHAY 	return 0;
8778cc72361SWai Yew CHAY }
8788cc72361SWai Yew CHAY 
8798cc72361SWai Yew CHAY static int dai_srt_set_et(void *blk, unsigned int et)
8808cc72361SWai Yew CHAY {
8818cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8828cc72361SWai Yew CHAY 
8838cc72361SWai Yew CHAY 	set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0);
8848cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
8858cc72361SWai Yew CHAY 	return 0;
8868cc72361SWai Yew CHAY }
8878cc72361SWai Yew CHAY 
8888cc72361SWai Yew CHAY static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
8898cc72361SWai Yew CHAY {
8908cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8918cc72361SWai Yew CHAY 
8928cc72361SWai Yew CHAY 	if (ctl->dirty.bf.srtctl) {
8938cc72361SWai Yew CHAY 		if (idx < 4) {
8948cc72361SWai Yew CHAY 			/* S/PDIF SRTs */
8958cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl);
8968cc72361SWai Yew CHAY 		} else {
8978cc72361SWai Yew CHAY 			/* I2S SRT */
8988cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRTICTL, ctl->srtctl);
8998cc72361SWai Yew CHAY 		}
9008cc72361SWai Yew CHAY 		ctl->dirty.bf.srtctl = 0;
9018cc72361SWai Yew CHAY 	}
9028cc72361SWai Yew CHAY 
9038cc72361SWai Yew CHAY 	return 0;
9048cc72361SWai Yew CHAY }
9058cc72361SWai Yew CHAY 
9068cc72361SWai Yew CHAY static int dai_get_ctrl_blk(void **rblk)
9078cc72361SWai Yew CHAY {
9088cc72361SWai Yew CHAY 	struct dai_ctrl_blk *blk;
9098cc72361SWai Yew CHAY 
9108cc72361SWai Yew CHAY 	*rblk = NULL;
9118cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
9128cc72361SWai Yew CHAY 	if (NULL == blk)
9138cc72361SWai Yew CHAY 		return -ENOMEM;
9148cc72361SWai Yew CHAY 
9158cc72361SWai Yew CHAY 	*rblk = blk;
9168cc72361SWai Yew CHAY 
9178cc72361SWai Yew CHAY 	return 0;
9188cc72361SWai Yew CHAY }
9198cc72361SWai Yew CHAY 
9208cc72361SWai Yew CHAY static int dai_put_ctrl_blk(void *blk)
9218cc72361SWai Yew CHAY {
9228cc72361SWai Yew CHAY 	kfree((struct dai_ctrl_blk *)blk);
9238cc72361SWai Yew CHAY 
9248cc72361SWai Yew CHAY 	return 0;
9258cc72361SWai Yew CHAY }
9268cc72361SWai Yew CHAY 
9278cc72361SWai Yew CHAY static int dao_set_spos(void *blk, unsigned int spos)
9288cc72361SWai Yew CHAY {
9298cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->spos = spos;
9308cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1;
9318cc72361SWai Yew CHAY 	return 0;
9328cc72361SWai Yew CHAY }
9338cc72361SWai Yew CHAY 
9348cc72361SWai Yew CHAY static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
9358cc72361SWai Yew CHAY {
9368cc72361SWai Yew CHAY 	struct dao_ctrl_blk *ctl = blk;
9378cc72361SWai Yew CHAY 
9388cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spos) {
9398cc72361SWai Yew CHAY 		if (idx < 4) {
9408cc72361SWai Yew CHAY 			/* S/PDIF SPOSx */
9418cc72361SWai Yew CHAY 			hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos);
9428cc72361SWai Yew CHAY 		}
9438cc72361SWai Yew CHAY 		ctl->dirty.bf.spos = 0;
9448cc72361SWai Yew CHAY 	}
9458cc72361SWai Yew CHAY 
9468cc72361SWai Yew CHAY 	return 0;
9478cc72361SWai Yew CHAY }
9488cc72361SWai Yew CHAY 
9498cc72361SWai Yew CHAY static int dao_get_spos(void *blk, unsigned int *spos)
9508cc72361SWai Yew CHAY {
9518cc72361SWai Yew CHAY 	*spos = ((struct dao_ctrl_blk *)blk)->spos;
9528cc72361SWai Yew CHAY 	return 0;
9538cc72361SWai Yew CHAY }
9548cc72361SWai Yew CHAY 
9558cc72361SWai Yew CHAY static int dao_get_ctrl_blk(void **rblk)
9568cc72361SWai Yew CHAY {
9578cc72361SWai Yew CHAY 	struct dao_ctrl_blk *blk;
9588cc72361SWai Yew CHAY 
9598cc72361SWai Yew CHAY 	*rblk = NULL;
9608cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
9618cc72361SWai Yew CHAY 	if (NULL == blk)
9628cc72361SWai Yew CHAY 		return -ENOMEM;
9638cc72361SWai Yew CHAY 
9648cc72361SWai Yew CHAY 	*rblk = blk;
9658cc72361SWai Yew CHAY 
9668cc72361SWai Yew CHAY 	return 0;
9678cc72361SWai Yew CHAY }
9688cc72361SWai Yew CHAY 
9698cc72361SWai Yew CHAY static int dao_put_ctrl_blk(void *blk)
9708cc72361SWai Yew CHAY {
9718cc72361SWai Yew CHAY 	kfree((struct dao_ctrl_blk *)blk);
9728cc72361SWai Yew CHAY 
9738cc72361SWai Yew CHAY 	return 0;
9748cc72361SWai Yew CHAY }
9758cc72361SWai Yew CHAY 
9768cc72361SWai Yew CHAY static int daio_mgr_enb_dai(void *blk, unsigned int idx)
9778cc72361SWai Yew CHAY {
9788cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9798cc72361SWai Yew CHAY 
9808cc72361SWai Yew CHAY 	if (idx < 4) {
9818cc72361SWai Yew CHAY 		/* S/PDIF input */
9828cc72361SWai Yew CHAY 		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1);
9838cc72361SWai Yew CHAY 		ctl->dirty.bf.spictl |= (0x1 << idx);
9848cc72361SWai Yew CHAY 	} else {
9858cc72361SWai Yew CHAY 		/* I2S input */
9868cc72361SWai Yew CHAY 		idx %= 4;
9878cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1);
9888cc72361SWai Yew CHAY 		ctl->dirty.bf.i2sictl |= (0x1 << idx);
9898cc72361SWai Yew CHAY 	}
9908cc72361SWai Yew CHAY 	return 0;
9918cc72361SWai Yew CHAY }
9928cc72361SWai Yew CHAY 
9938cc72361SWai Yew CHAY static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
9948cc72361SWai Yew CHAY {
9958cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9968cc72361SWai Yew CHAY 
9978cc72361SWai Yew CHAY 	if (idx < 4) {
9988cc72361SWai Yew CHAY 		/* S/PDIF input */
9998cc72361SWai Yew CHAY 		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0);
10008cc72361SWai Yew CHAY 		ctl->dirty.bf.spictl |= (0x1 << idx);
10018cc72361SWai Yew CHAY 	} else {
10028cc72361SWai Yew CHAY 		/* I2S input */
10038cc72361SWai Yew CHAY 		idx %= 4;
10048cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0);
10058cc72361SWai Yew CHAY 		ctl->dirty.bf.i2sictl |= (0x1 << idx);
10068cc72361SWai Yew CHAY 	}
10078cc72361SWai Yew CHAY 	return 0;
10088cc72361SWai Yew CHAY }
10098cc72361SWai Yew CHAY 
10108cc72361SWai Yew CHAY static int daio_mgr_enb_dao(void *blk, unsigned int idx)
10118cc72361SWai Yew CHAY {
10128cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10138cc72361SWai Yew CHAY 
10148cc72361SWai Yew CHAY 	if (idx < 4) {
10158cc72361SWai Yew CHAY 		/* S/PDIF output */
10168cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1);
10178cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
10188cc72361SWai Yew CHAY 	} else {
10198cc72361SWai Yew CHAY 		/* I2S output */
10208cc72361SWai Yew CHAY 		idx %= 4;
10218cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1);
10228cc72361SWai Yew CHAY 		ctl->dirty.bf.i2soctl |= (0x1 << idx);
10238cc72361SWai Yew CHAY 	}
10248cc72361SWai Yew CHAY 	return 0;
10258cc72361SWai Yew CHAY }
10268cc72361SWai Yew CHAY 
10278cc72361SWai Yew CHAY static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
10288cc72361SWai Yew CHAY {
10298cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10308cc72361SWai Yew CHAY 
10318cc72361SWai Yew CHAY 	if (idx < 4) {
10328cc72361SWai Yew CHAY 		/* S/PDIF output */
10338cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0);
10348cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
10358cc72361SWai Yew CHAY 	} else {
10368cc72361SWai Yew CHAY 		/* I2S output */
10378cc72361SWai Yew CHAY 		idx %= 4;
10388cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0);
10398cc72361SWai Yew CHAY 		ctl->dirty.bf.i2soctl |= (0x1 << idx);
10408cc72361SWai Yew CHAY 	}
10418cc72361SWai Yew CHAY 	return 0;
10428cc72361SWai Yew CHAY }
10438cc72361SWai Yew CHAY 
10448cc72361SWai Yew CHAY static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
10458cc72361SWai Yew CHAY {
10468cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10478cc72361SWai Yew CHAY 
10488cc72361SWai Yew CHAY 	if (idx < 4) {
10498cc72361SWai Yew CHAY 		/* S/PDIF output */
10508cc72361SWai Yew CHAY 		switch ((conf & 0x7)) {
10518cc72361SWai Yew CHAY 		case 0:
10528cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3);
10538cc72361SWai Yew CHAY 			break; /* CDIF */
10548cc72361SWai Yew CHAY 		case 1:
10558cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0);
10568cc72361SWai Yew CHAY 			break;
10578cc72361SWai Yew CHAY 		case 2:
10588cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1);
10598cc72361SWai Yew CHAY 			break;
10608cc72361SWai Yew CHAY 		case 4:
10618cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2);
10628cc72361SWai Yew CHAY 			break;
10638cc72361SWai Yew CHAY 		default:
10648cc72361SWai Yew CHAY 			break;
10658cc72361SWai Yew CHAY 		}
10668cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8),
10678cc72361SWai Yew CHAY 			  (conf >> 4) & 0x1); /* Non-audio */
10688cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8),
10698cc72361SWai Yew CHAY 			  (conf >> 4) & 0x1); /* Non-audio */
10708cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OS << (idx*8),
10718cc72361SWai Yew CHAY 			  ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */
10728cc72361SWai Yew CHAY 
10738cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
10748cc72361SWai Yew CHAY 	} else {
10758cc72361SWai Yew CHAY 		/* I2S output */
10768cc72361SWai Yew CHAY 		/*idx %= 4; */
10778cc72361SWai Yew CHAY 	}
10788cc72361SWai Yew CHAY 	return 0;
10798cc72361SWai Yew CHAY }
10808cc72361SWai Yew CHAY 
10818cc72361SWai Yew CHAY static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
10828cc72361SWai Yew CHAY {
10838cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10848cc72361SWai Yew CHAY 
10858cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_ARC, slot);
10868cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
10878cc72361SWai Yew CHAY 	return 0;
10888cc72361SWai Yew CHAY }
10898cc72361SWai Yew CHAY 
10908cc72361SWai Yew CHAY static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
10918cc72361SWai Yew CHAY {
10928cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10938cc72361SWai Yew CHAY 
10948cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_NXT, next);
10958cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
10968cc72361SWai Yew CHAY 	return 0;
10978cc72361SWai Yew CHAY }
10988cc72361SWai Yew CHAY 
10998cc72361SWai Yew CHAY static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
11008cc72361SWai Yew CHAY {
11018cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
11028cc72361SWai Yew CHAY 
11038cc72361SWai Yew CHAY 	ctl->daoimap.idx = addr;
11048cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
11058cc72361SWai Yew CHAY 	return 0;
11068cc72361SWai Yew CHAY }
11078cc72361SWai Yew CHAY 
11088cc72361SWai Yew CHAY static int daio_mgr_commit_write(struct hw *hw, void *blk)
11098cc72361SWai Yew CHAY {
11108cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
11118cc72361SWai Yew CHAY 	int i = 0;
11128cc72361SWai Yew CHAY 
11138cc72361SWai Yew CHAY 	if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) {
11148cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
11158cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.i2sictl & (0x1 << i)))
11168cc72361SWai Yew CHAY 				ctl->dirty.bf.i2sictl &= ~(0x1 << i);
11178cc72361SWai Yew CHAY 
11188cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.i2soctl & (0x1 << i)))
11198cc72361SWai Yew CHAY 				ctl->dirty.bf.i2soctl &= ~(0x1 << i);
11208cc72361SWai Yew CHAY 		}
11218cc72361SWai Yew CHAY 		hw_write_20kx(hw, I2SCTL, ctl->i2sctl);
11228cc72361SWai Yew CHAY 		mdelay(1);
11238cc72361SWai Yew CHAY 	}
11248cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spoctl) {
11258cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
11268cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.spoctl & (0x1 << i)))
11278cc72361SWai Yew CHAY 				ctl->dirty.bf.spoctl &= ~(0x1 << i);
11288cc72361SWai Yew CHAY 		}
11298cc72361SWai Yew CHAY 		hw_write_20kx(hw, SPOCTL, ctl->spoctl);
11308cc72361SWai Yew CHAY 		mdelay(1);
11318cc72361SWai Yew CHAY 	}
11328cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spictl) {
11338cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
11348cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.spictl & (0x1 << i)))
11358cc72361SWai Yew CHAY 				ctl->dirty.bf.spictl &= ~(0x1 << i);
11368cc72361SWai Yew CHAY 		}
11378cc72361SWai Yew CHAY 		hw_write_20kx(hw, SPICTL, ctl->spictl);
11388cc72361SWai Yew CHAY 		mdelay(1);
11398cc72361SWai Yew CHAY 	}
11408cc72361SWai Yew CHAY 	if (ctl->dirty.bf.daoimap) {
11418cc72361SWai Yew CHAY 		hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4,
11428cc72361SWai Yew CHAY 					ctl->daoimap.aim);
11438cc72361SWai Yew CHAY 		ctl->dirty.bf.daoimap = 0;
11448cc72361SWai Yew CHAY 	}
11458cc72361SWai Yew CHAY 
11468cc72361SWai Yew CHAY 	return 0;
11478cc72361SWai Yew CHAY }
11488cc72361SWai Yew CHAY 
11498cc72361SWai Yew CHAY static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
11508cc72361SWai Yew CHAY {
11518cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *blk;
11528cc72361SWai Yew CHAY 
11538cc72361SWai Yew CHAY 	*rblk = NULL;
11548cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
11558cc72361SWai Yew CHAY 	if (NULL == blk)
11568cc72361SWai Yew CHAY 		return -ENOMEM;
11578cc72361SWai Yew CHAY 
11588cc72361SWai Yew CHAY 	blk->i2sctl = hw_read_20kx(hw, I2SCTL);
11598cc72361SWai Yew CHAY 	blk->spoctl = hw_read_20kx(hw, SPOCTL);
11608cc72361SWai Yew CHAY 	blk->spictl = hw_read_20kx(hw, SPICTL);
11618cc72361SWai Yew CHAY 
11628cc72361SWai Yew CHAY 	*rblk = blk;
11638cc72361SWai Yew CHAY 
11648cc72361SWai Yew CHAY 	return 0;
11658cc72361SWai Yew CHAY }
11668cc72361SWai Yew CHAY 
11678cc72361SWai Yew CHAY static int daio_mgr_put_ctrl_blk(void *blk)
11688cc72361SWai Yew CHAY {
11698cc72361SWai Yew CHAY 	kfree((struct daio_mgr_ctrl_blk *)blk);
11708cc72361SWai Yew CHAY 
11718cc72361SWai Yew CHAY 	return 0;
11728cc72361SWai Yew CHAY }
11738cc72361SWai Yew CHAY 
1174*b7bbf876STakashi Iwai /* Timer interrupt */
1175*b7bbf876STakashi Iwai static int set_timer_irq(struct hw *hw, int enable)
1176*b7bbf876STakashi Iwai {
1177*b7bbf876STakashi Iwai 	hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
1178*b7bbf876STakashi Iwai 	return 0;
1179*b7bbf876STakashi Iwai }
1180*b7bbf876STakashi Iwai 
1181*b7bbf876STakashi Iwai static int set_timer_tick(struct hw *hw, unsigned int ticks)
1182*b7bbf876STakashi Iwai {
1183*b7bbf876STakashi Iwai 	if (ticks)
1184*b7bbf876STakashi Iwai 		ticks |= TIMR_IE | TIMR_IP;
1185*b7bbf876STakashi Iwai 	hw_write_20kx(hw, TIMR, ticks);
1186*b7bbf876STakashi Iwai 	return 0;
1187*b7bbf876STakashi Iwai }
1188*b7bbf876STakashi Iwai 
11898cc72361SWai Yew CHAY /* Card hardware initialization block */
11908cc72361SWai Yew CHAY struct dac_conf {
11918cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
11928cc72361SWai Yew CHAY };
11938cc72361SWai Yew CHAY 
11948cc72361SWai Yew CHAY struct adc_conf {
11958cc72361SWai Yew CHAY 	unsigned int msr; 	/* master sample rate in rsrs */
11968cc72361SWai Yew CHAY 	unsigned char input; 	/* the input source of ADC */
11978cc72361SWai Yew CHAY 	unsigned char mic20db; 	/* boost mic by 20db if input is microphone */
11988cc72361SWai Yew CHAY };
11998cc72361SWai Yew CHAY 
12008cc72361SWai Yew CHAY struct daio_conf {
12018cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
12028cc72361SWai Yew CHAY };
12038cc72361SWai Yew CHAY 
12048cc72361SWai Yew CHAY struct trn_conf {
12058cc72361SWai Yew CHAY 	unsigned long vm_pgt_phys;
12068cc72361SWai Yew CHAY };
12078cc72361SWai Yew CHAY 
12088cc72361SWai Yew CHAY static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
12098cc72361SWai Yew CHAY {
12108cc72361SWai Yew CHAY 	u32 i2sorg = 0;
12118cc72361SWai Yew CHAY 	u32 spdorg = 0;
12128cc72361SWai Yew CHAY 
12138cc72361SWai Yew CHAY 	/* Read I2S CTL.  Keep original value. */
12148cc72361SWai Yew CHAY 	/*i2sorg = hw_read_20kx(hw, I2SCTL);*/
12158cc72361SWai Yew CHAY 	i2sorg = 0x94040404; /* enable all audio out and I2S-D input */
12168cc72361SWai Yew CHAY 	/* Program I2S with proper master sample rate and enable
12178cc72361SWai Yew CHAY 	 * the correct I2S channel. */
12188cc72361SWai Yew CHAY 	i2sorg &= 0xfffffffc;
12198cc72361SWai Yew CHAY 
12208cc72361SWai Yew CHAY 	/* Enable S/PDIF-out-A in fixed 24-bit data
12218cc72361SWai Yew CHAY 	 * format and default to 48kHz. */
12228cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
12238cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, 0x0);
12248cc72361SWai Yew CHAY 	spdorg = 0x05;
12258cc72361SWai Yew CHAY 
12268cc72361SWai Yew CHAY 	switch (info->msr) {
12278cc72361SWai Yew CHAY 	case 1:
12288cc72361SWai Yew CHAY 		i2sorg |= 1;
12298cc72361SWai Yew CHAY 		spdorg |= (0x0 << 6);
12308cc72361SWai Yew CHAY 		break;
12318cc72361SWai Yew CHAY 	case 2:
12328cc72361SWai Yew CHAY 		i2sorg |= 2;
12338cc72361SWai Yew CHAY 		spdorg |= (0x1 << 6);
12348cc72361SWai Yew CHAY 		break;
12358cc72361SWai Yew CHAY 	case 4:
12368cc72361SWai Yew CHAY 		i2sorg |= 3;
12378cc72361SWai Yew CHAY 		spdorg |= (0x2 << 6);
12388cc72361SWai Yew CHAY 		break;
12398cc72361SWai Yew CHAY 	default:
12408cc72361SWai Yew CHAY 		i2sorg |= 1;
12418cc72361SWai Yew CHAY 		break;
12428cc72361SWai Yew CHAY 	}
12438cc72361SWai Yew CHAY 
12448cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2SCTL, i2sorg);
12458cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, spdorg);
12468cc72361SWai Yew CHAY 
12478cc72361SWai Yew CHAY 	/* Enable S/PDIF-in-A in fixed 24-bit data format. */
12488cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
12498cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, 0x0);
12508cc72361SWai Yew CHAY 	mdelay(1);
12518cc72361SWai Yew CHAY 	spdorg = 0x0a0a0a0a;
12528cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, spdorg);
12538cc72361SWai Yew CHAY 	mdelay(1);
12548cc72361SWai Yew CHAY 
12558cc72361SWai Yew CHAY 	return 0;
12568cc72361SWai Yew CHAY }
12578cc72361SWai Yew CHAY 
12588cc72361SWai Yew CHAY /* TRANSPORT operations */
12598cc72361SWai Yew CHAY static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
12608cc72361SWai Yew CHAY {
12618cc72361SWai Yew CHAY 	u32 trnctl = 0;
12628cc72361SWai Yew CHAY 	unsigned long ptp_phys_low = 0, ptp_phys_high = 0;
12638cc72361SWai Yew CHAY 
12648cc72361SWai Yew CHAY 	/* Set up device page table */
12658cc72361SWai Yew CHAY 	if ((~0UL) == info->vm_pgt_phys) {
12668cc72361SWai Yew CHAY 		printk(KERN_ERR "Wrong device page table page address!\n");
12678cc72361SWai Yew CHAY 		return -1;
12688cc72361SWai Yew CHAY 	}
12698cc72361SWai Yew CHAY 
12708cc72361SWai Yew CHAY 	trnctl = 0x13;  /* 32-bit, 4k-size page */
1271cd391e20STakashi Iwai 	ptp_phys_low = (u32)info->vm_pgt_phys;
1272cd391e20STakashi Iwai 	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
1273cd391e20STakashi Iwai 	if (sizeof(void *) == 8) /* 64bit address */
12748cc72361SWai Yew CHAY 		trnctl |= (1 << 2);
1275cd391e20STakashi Iwai #if 0 /* Only 4k h/w pages for simplicitiy */
12768cc72361SWai Yew CHAY #if PAGE_SIZE == 8192
12778cc72361SWai Yew CHAY 	trnctl |= (1<<5);
12788cc72361SWai Yew CHAY #endif
1279cd391e20STakashi Iwai #endif
12808cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPALX, ptp_phys_low);
12818cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPAHX, ptp_phys_high);
12828cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRNCTL, trnctl);
12838cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */
12848cc72361SWai Yew CHAY 
12858cc72361SWai Yew CHAY 	return 0;
12868cc72361SWai Yew CHAY }
12878cc72361SWai Yew CHAY 
12888cc72361SWai Yew CHAY /* Card initialization */
12898cc72361SWai Yew CHAY #define GCTL_EAC	0x00000001
12908cc72361SWai Yew CHAY #define GCTL_EAI	0x00000002
12918cc72361SWai Yew CHAY #define GCTL_BEP	0x00000004
12928cc72361SWai Yew CHAY #define GCTL_BES	0x00000008
12938cc72361SWai Yew CHAY #define GCTL_DSP	0x00000010
12948cc72361SWai Yew CHAY #define GCTL_DBP	0x00000020
12958cc72361SWai Yew CHAY #define GCTL_ABP	0x00000040
12968cc72361SWai Yew CHAY #define GCTL_TBP	0x00000080
12978cc72361SWai Yew CHAY #define GCTL_SBP	0x00000100
12988cc72361SWai Yew CHAY #define GCTL_FBP	0x00000200
12998cc72361SWai Yew CHAY #define GCTL_XA		0x00000400
13008cc72361SWai Yew CHAY #define GCTL_ET		0x00000800
13018cc72361SWai Yew CHAY #define GCTL_PR		0x00001000
13028cc72361SWai Yew CHAY #define GCTL_MRL	0x00002000
13038cc72361SWai Yew CHAY #define GCTL_SDE	0x00004000
13048cc72361SWai Yew CHAY #define GCTL_SDI	0x00008000
13058cc72361SWai Yew CHAY #define GCTL_SM		0x00010000
13068cc72361SWai Yew CHAY #define GCTL_SR		0x00020000
13078cc72361SWai Yew CHAY #define GCTL_SD		0x00040000
13088cc72361SWai Yew CHAY #define GCTL_SE		0x00080000
13098cc72361SWai Yew CHAY #define GCTL_AID	0x00100000
13108cc72361SWai Yew CHAY 
13118cc72361SWai Yew CHAY static int hw_pll_init(struct hw *hw, unsigned int rsr)
13128cc72361SWai Yew CHAY {
13138cc72361SWai Yew CHAY 	unsigned int pllctl;
13148cc72361SWai Yew CHAY 	int i = 0;
13158cc72361SWai Yew CHAY 
13168cc72361SWai Yew CHAY 	pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731;
13178cc72361SWai Yew CHAY 	for (i = 0; i < 3; i++) {
13188cc72361SWai Yew CHAY 		if (hw_read_20kx(hw, PLLCTL) == pllctl)
13198cc72361SWai Yew CHAY 			break;
13208cc72361SWai Yew CHAY 
13218cc72361SWai Yew CHAY 		hw_write_20kx(hw, PLLCTL, pllctl);
13228cc72361SWai Yew CHAY 		mdelay(40);
13238cc72361SWai Yew CHAY 	}
13248cc72361SWai Yew CHAY 	if (i >= 3) {
13258cc72361SWai Yew CHAY 		printk(KERN_ALERT "PLL initialization failed!!!\n");
13268cc72361SWai Yew CHAY 		return -EBUSY;
13278cc72361SWai Yew CHAY 	}
13288cc72361SWai Yew CHAY 
13298cc72361SWai Yew CHAY 	return 0;
13308cc72361SWai Yew CHAY }
13318cc72361SWai Yew CHAY 
13328cc72361SWai Yew CHAY static int hw_auto_init(struct hw *hw)
13338cc72361SWai Yew CHAY {
13348cc72361SWai Yew CHAY 	unsigned int gctl;
13358cc72361SWai Yew CHAY 	int i;
13368cc72361SWai Yew CHAY 
13378cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
13388cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 0);
13398cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
13408cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 1);
13418cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
13428cc72361SWai Yew CHAY 	mdelay(10);
13438cc72361SWai Yew CHAY 	for (i = 0; i < 400000; i++) {
13448cc72361SWai Yew CHAY 		gctl = hw_read_20kx(hw, GCTL);
13458cc72361SWai Yew CHAY 		if (get_field(gctl, GCTL_AID))
13468cc72361SWai Yew CHAY 			break;
13478cc72361SWai Yew CHAY 	}
13488cc72361SWai Yew CHAY 	if (!get_field(gctl, GCTL_AID)) {
13498cc72361SWai Yew CHAY 		printk(KERN_ALERT "Card Auto-init failed!!!\n");
13508cc72361SWai Yew CHAY 		return -EBUSY;
13518cc72361SWai Yew CHAY 	}
13528cc72361SWai Yew CHAY 
13538cc72361SWai Yew CHAY 	return 0;
13548cc72361SWai Yew CHAY }
13558cc72361SWai Yew CHAY 
13568cc72361SWai Yew CHAY static int i2c_unlock(struct hw *hw)
13578cc72361SWai Yew CHAY {
13588cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13598cc72361SWai Yew CHAY 		return 0;
13608cc72361SWai Yew CHAY 
13618cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0x8c);
13628cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0x0e);
13638cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13648cc72361SWai Yew CHAY 		return 0;
13658cc72361SWai Yew CHAY 
13668cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xee);
13678cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xaa);
13688cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13698cc72361SWai Yew CHAY 		return 0;
13708cc72361SWai Yew CHAY 
13718cc72361SWai Yew CHAY 	return -1;
13728cc72361SWai Yew CHAY }
13738cc72361SWai Yew CHAY 
13748cc72361SWai Yew CHAY static void i2c_lock(struct hw *hw)
13758cc72361SWai Yew CHAY {
13768cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13778cc72361SWai Yew CHAY 		hw_write_pci(hw, 0xcc, 0x00);
13788cc72361SWai Yew CHAY }
13798cc72361SWai Yew CHAY 
13808cc72361SWai Yew CHAY static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data)
13818cc72361SWai Yew CHAY {
13828cc72361SWai Yew CHAY 	unsigned int ret = 0;
13838cc72361SWai Yew CHAY 
13848cc72361SWai Yew CHAY 	do {
13858cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
13868cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
13878cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE0, device);
13888cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff));
13898cc72361SWai Yew CHAY }
13908cc72361SWai Yew CHAY 
13918cc72361SWai Yew CHAY /* DAC operations */
13928cc72361SWai Yew CHAY 
13938cc72361SWai Yew CHAY static int hw_reset_dac(struct hw *hw)
13948cc72361SWai Yew CHAY {
13958cc72361SWai Yew CHAY 	u32 i = 0;
13968cc72361SWai Yew CHAY 	u16 gpioorg = 0;
13978cc72361SWai Yew CHAY 	unsigned int ret = 0;
13988cc72361SWai Yew CHAY 
13998cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
14008cc72361SWai Yew CHAY 		return -1;
14018cc72361SWai Yew CHAY 
14028cc72361SWai Yew CHAY 	do {
14038cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
14048cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
14058cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
14068cc72361SWai Yew CHAY 
14078cc72361SWai Yew CHAY 	/* To be effective, need to reset the DAC twice. */
14088cc72361SWai Yew CHAY 	for (i = 0; i < 2;  i++) {
14098cc72361SWai Yew CHAY 		/* set gpio */
14108cc72361SWai Yew CHAY 		mdelay(100);
14118cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
14128cc72361SWai Yew CHAY 		gpioorg &= 0xfffd;
14138cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
14148cc72361SWai Yew CHAY 		mdelay(1);
14158cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg | 0x2);
14168cc72361SWai Yew CHAY 	}
14178cc72361SWai Yew CHAY 
14188cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x01, 0x80);
14198cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x02, 0x10);
14208cc72361SWai Yew CHAY 
14218cc72361SWai Yew CHAY 	i2c_lock(hw);
14228cc72361SWai Yew CHAY 
14238cc72361SWai Yew CHAY 	return 0;
14248cc72361SWai Yew CHAY }
14258cc72361SWai Yew CHAY 
14268cc72361SWai Yew CHAY static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
14278cc72361SWai Yew CHAY {
14288cc72361SWai Yew CHAY 	u32 data = 0;
14298cc72361SWai Yew CHAY 	u16 gpioorg = 0;
14308cc72361SWai Yew CHAY 	u16 subsys_id = 0;
14318cc72361SWai Yew CHAY 	unsigned int ret = 0;
14328cc72361SWai Yew CHAY 
14338cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
14348cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
14358cc72361SWai Yew CHAY 		/* SB055x, unmute outputs */
14368cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
14378cc72361SWai Yew CHAY 		gpioorg &= 0xffbf;	/* set GPIO6 to low */
14388cc72361SWai Yew CHAY 		gpioorg |= 2;		/* set GPIO1 to high */
14398cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
14408cc72361SWai Yew CHAY 		return 0;
14418cc72361SWai Yew CHAY 	}
14428cc72361SWai Yew CHAY 
14438cc72361SWai Yew CHAY 	/* mute outputs */
14448cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
14458cc72361SWai Yew CHAY 	gpioorg &= 0xffbf;
14468cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
14478cc72361SWai Yew CHAY 
14488cc72361SWai Yew CHAY 	hw_reset_dac(hw);
14498cc72361SWai Yew CHAY 
14508cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
14518cc72361SWai Yew CHAY 		return -1;
14528cc72361SWai Yew CHAY 
14538cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
14548cc72361SWai Yew CHAY 	do {
14558cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
14568cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
14578cc72361SWai Yew CHAY 
14588cc72361SWai Yew CHAY 	switch (info->msr) {
14598cc72361SWai Yew CHAY 	case 1:
14608cc72361SWai Yew CHAY 		data = 0x24;
14618cc72361SWai Yew CHAY 		break;
14628cc72361SWai Yew CHAY 	case 2:
14638cc72361SWai Yew CHAY 		data = 0x25;
14648cc72361SWai Yew CHAY 		break;
14658cc72361SWai Yew CHAY 	case 4:
14668cc72361SWai Yew CHAY 		data = 0x26;
14678cc72361SWai Yew CHAY 		break;
14688cc72361SWai Yew CHAY 	default:
14698cc72361SWai Yew CHAY 		data = 0x24;
14708cc72361SWai Yew CHAY 		break;
14718cc72361SWai Yew CHAY 	}
14728cc72361SWai Yew CHAY 
14738cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x06, data);
14748cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x09, data);
14758cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0c, data);
14768cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0f, data);
14778cc72361SWai Yew CHAY 
14788cc72361SWai Yew CHAY 	i2c_lock(hw);
14798cc72361SWai Yew CHAY 
14808cc72361SWai Yew CHAY 	/* unmute outputs */
14818cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
14828cc72361SWai Yew CHAY 	gpioorg = gpioorg | 0x40;
14838cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
14848cc72361SWai Yew CHAY 
14858cc72361SWai Yew CHAY 	return 0;
14868cc72361SWai Yew CHAY }
14878cc72361SWai Yew CHAY 
14888cc72361SWai Yew CHAY /* ADC operations */
14898cc72361SWai Yew CHAY 
14908cc72361SWai Yew CHAY static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type)
14918cc72361SWai Yew CHAY {
14928cc72361SWai Yew CHAY 	u32 data = 0;
14938cc72361SWai Yew CHAY 	return data;
14948cc72361SWai Yew CHAY }
14958cc72361SWai Yew CHAY 
14968cc72361SWai Yew CHAY static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type)
14978cc72361SWai Yew CHAY {
14988cc72361SWai Yew CHAY 	u32 data = 0;
14998cc72361SWai Yew CHAY 
15008cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15018cc72361SWai Yew CHAY 	switch (type) {
15028cc72361SWai Yew CHAY 	case ADC_MICIN:
15038cc72361SWai Yew CHAY 		data = ((data & (0x1<<7)) && (data & (0x1<<8)));
15048cc72361SWai Yew CHAY 		break;
15058cc72361SWai Yew CHAY 	case ADC_LINEIN:
15068cc72361SWai Yew CHAY 		data = (!(data & (0x1<<7)) && (data & (0x1<<8)));
15078cc72361SWai Yew CHAY 		break;
15088cc72361SWai Yew CHAY 	case ADC_NONE: /* Digital I/O */
15098cc72361SWai Yew CHAY 		data = (!(data & (0x1<<8)));
15108cc72361SWai Yew CHAY 		break;
15118cc72361SWai Yew CHAY 	default:
15128cc72361SWai Yew CHAY 		data = 0;
15138cc72361SWai Yew CHAY 	}
15148cc72361SWai Yew CHAY 	return data;
15158cc72361SWai Yew CHAY }
15168cc72361SWai Yew CHAY 
15178cc72361SWai Yew CHAY static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
15188cc72361SWai Yew CHAY {
15198cc72361SWai Yew CHAY 	u32 data = 0;
15208cc72361SWai Yew CHAY 
15218cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15228cc72361SWai Yew CHAY 	switch (type) {
15238cc72361SWai Yew CHAY 	case ADC_MICIN:
15248cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 1 : 0;
15258cc72361SWai Yew CHAY 		break;
15268cc72361SWai Yew CHAY 	case ADC_LINEIN:
15278cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 0 : 1;
15288cc72361SWai Yew CHAY 		break;
15298cc72361SWai Yew CHAY 	default:
15308cc72361SWai Yew CHAY 		data = 0;
15318cc72361SWai Yew CHAY 	}
15328cc72361SWai Yew CHAY 	return data;
15338cc72361SWai Yew CHAY }
15348cc72361SWai Yew CHAY 
15358cc72361SWai Yew CHAY static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
15368cc72361SWai Yew CHAY {
15378cc72361SWai Yew CHAY 	u16 subsys_id = 0;
15388cc72361SWai Yew CHAY 
15398cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
15408cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
15418cc72361SWai Yew CHAY 		/* SB055x cards */
15428cc72361SWai Yew CHAY 		return is_adc_input_selected_SB055x(hw, type);
15438cc72361SWai Yew CHAY 	} else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
15448cc72361SWai Yew CHAY 		/* SB073x cards */
15458cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
15468cc72361SWai Yew CHAY 	} else if ((subsys_id & 0xf000) == 0x6000) {
15478cc72361SWai Yew CHAY 		/* Vista compatible cards */
15488cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
15498cc72361SWai Yew CHAY 	} else {
15508cc72361SWai Yew CHAY 		return is_adc_input_selected_SBx(hw, type);
15518cc72361SWai Yew CHAY 	}
15528cc72361SWai Yew CHAY }
15538cc72361SWai Yew CHAY 
15548cc72361SWai Yew CHAY static int
15558cc72361SWai Yew CHAY adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost)
15568cc72361SWai Yew CHAY {
15578cc72361SWai Yew CHAY 	u32 data = 0;
15588cc72361SWai Yew CHAY 
15598cc72361SWai Yew CHAY 	/*
15608cc72361SWai Yew CHAY 	 * check and set the following GPIO bits accordingly
15618cc72361SWai Yew CHAY 	 * ADC_Gain		= GPIO2
15628cc72361SWai Yew CHAY 	 * DRM_off		= GPIO3
15638cc72361SWai Yew CHAY 	 * Mic_Pwr_on		= GPIO7
15648cc72361SWai Yew CHAY 	 * Digital_IO_Sel	= GPIO8
15658cc72361SWai Yew CHAY 	 * Mic_Sw		= GPIO9
15668cc72361SWai Yew CHAY 	 * Aux/MicLine_Sw	= GPIO12
15678cc72361SWai Yew CHAY 	 */
15688cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15698cc72361SWai Yew CHAY 	data &= 0xec73;
15708cc72361SWai Yew CHAY 	switch (type) {
15718cc72361SWai Yew CHAY 	case ADC_MICIN:
15728cc72361SWai Yew CHAY 		data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ;
15738cc72361SWai Yew CHAY 		data |= boost ? (0x1<<2) : 0;
15748cc72361SWai Yew CHAY 		break;
15758cc72361SWai Yew CHAY 	case ADC_LINEIN:
15768cc72361SWai Yew CHAY 		data |= (0x1<<8);
15778cc72361SWai Yew CHAY 		break;
15788cc72361SWai Yew CHAY 	case ADC_AUX:
15798cc72361SWai Yew CHAY 		data |= (0x1<<8) | (0x1<<12);
15808cc72361SWai Yew CHAY 		break;
15818cc72361SWai Yew CHAY 	case ADC_NONE:
15828cc72361SWai Yew CHAY 		data |= (0x1<<12);  /* set to digital */
15838cc72361SWai Yew CHAY 		break;
15848cc72361SWai Yew CHAY 	default:
15858cc72361SWai Yew CHAY 		return -1;
15868cc72361SWai Yew CHAY 	}
15878cc72361SWai Yew CHAY 
15888cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
15898cc72361SWai Yew CHAY 
15908cc72361SWai Yew CHAY 	return 0;
15918cc72361SWai Yew CHAY }
15928cc72361SWai Yew CHAY 
15938cc72361SWai Yew CHAY 
15948cc72361SWai Yew CHAY static int
15958cc72361SWai Yew CHAY adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost)
15968cc72361SWai Yew CHAY {
15978cc72361SWai Yew CHAY 	u32 data = 0;
15988cc72361SWai Yew CHAY 	u32 i2c_data = 0;
15998cc72361SWai Yew CHAY 	unsigned int ret = 0;
16008cc72361SWai Yew CHAY 
16018cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
16028cc72361SWai Yew CHAY 		return -1;
16038cc72361SWai Yew CHAY 
16048cc72361SWai Yew CHAY 	do {
16058cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
16068cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
16078cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
16088cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
16098cc72361SWai Yew CHAY 
16108cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
16118cc72361SWai Yew CHAY 	switch (type) {
16128cc72361SWai Yew CHAY 	case ADC_MICIN:
16138cc72361SWai Yew CHAY 		data |= ((0x1 << 7) | (0x1 << 8));
16148cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
16158cc72361SWai Yew CHAY 		break;
16168cc72361SWai Yew CHAY 	case ADC_LINEIN:
16178cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
16188cc72361SWai Yew CHAY 		data |= (0x1 << 8);
16198cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
16208cc72361SWai Yew CHAY 		break;
16218cc72361SWai Yew CHAY 	case ADC_NONE:
16228cc72361SWai Yew CHAY 		data &= ~(0x1 << 8);
16238cc72361SWai Yew CHAY 		i2c_data = 0x0; /* set to Digital */
16248cc72361SWai Yew CHAY 		break;
16258cc72361SWai Yew CHAY 	default:
16268cc72361SWai Yew CHAY 		i2c_lock(hw);
16278cc72361SWai Yew CHAY 		return -1;
16288cc72361SWai Yew CHAY 	}
16298cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
16308cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
16318cc72361SWai Yew CHAY 	if (boost) {
16328cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
16338cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
16348cc72361SWai Yew CHAY 	} else {
16358cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
16368cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
16378cc72361SWai Yew CHAY 	}
16388cc72361SWai Yew CHAY 
16398cc72361SWai Yew CHAY 	i2c_lock(hw);
16408cc72361SWai Yew CHAY 
16418cc72361SWai Yew CHAY 	return 0;
16428cc72361SWai Yew CHAY }
16438cc72361SWai Yew CHAY 
16448cc72361SWai Yew CHAY static int
16458cc72361SWai Yew CHAY adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
16468cc72361SWai Yew CHAY {
16478cc72361SWai Yew CHAY 	u32 data = 0;
16488cc72361SWai Yew CHAY 	u32 i2c_data = 0;
16498cc72361SWai Yew CHAY 	unsigned int ret = 0;
16508cc72361SWai Yew CHAY 
16518cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
16528cc72361SWai Yew CHAY 		return -1;
16538cc72361SWai Yew CHAY 
16548cc72361SWai Yew CHAY 	do {
16558cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
16568cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
16578cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
16588cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
16598cc72361SWai Yew CHAY 
16608cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
16618cc72361SWai Yew CHAY 	switch (type) {
16628cc72361SWai Yew CHAY 	case ADC_MICIN:
16638cc72361SWai Yew CHAY 		data |= (0x1 << 7);
16648cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
16658cc72361SWai Yew CHAY 		break;
16668cc72361SWai Yew CHAY 	case ADC_LINEIN:
16678cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
16688cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
16698cc72361SWai Yew CHAY 		break;
16708cc72361SWai Yew CHAY 	default:
16718cc72361SWai Yew CHAY 		i2c_lock(hw);
16728cc72361SWai Yew CHAY 		return -1;
16738cc72361SWai Yew CHAY 	}
16748cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
16758cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
16768cc72361SWai Yew CHAY 	if (boost) {
16778cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
16788cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
16798cc72361SWai Yew CHAY 	} else {
16808cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
16818cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
16828cc72361SWai Yew CHAY 	}
16838cc72361SWai Yew CHAY 
16848cc72361SWai Yew CHAY 	i2c_lock(hw);
16858cc72361SWai Yew CHAY 
16868cc72361SWai Yew CHAY 	return 0;
16878cc72361SWai Yew CHAY }
16888cc72361SWai Yew CHAY 
16898cc72361SWai Yew CHAY static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
16908cc72361SWai Yew CHAY {
16918cc72361SWai Yew CHAY 	u16 subsys_id = 0;
16928cc72361SWai Yew CHAY 
16938cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
16948cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
16958cc72361SWai Yew CHAY 		/* SB055x cards */
16968cc72361SWai Yew CHAY 		return adc_input_select_SB055x(hw, type, (ADC_MICIN == type));
16978cc72361SWai Yew CHAY 	} else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
16988cc72361SWai Yew CHAY 		/* SB073x cards */
16998cc72361SWai Yew CHAY 		return adc_input_select_hendrix(hw, type, (ADC_MICIN == type));
17008cc72361SWai Yew CHAY 	} else if ((subsys_id & 0xf000) == 0x6000) {
17018cc72361SWai Yew CHAY 		/* Vista compatible cards */
17028cc72361SWai Yew CHAY 		return adc_input_select_hendrix(hw, type, (ADC_MICIN == type));
17038cc72361SWai Yew CHAY 	} else {
17048cc72361SWai Yew CHAY 		return adc_input_select_SBx(hw, type, (ADC_MICIN == type));
17058cc72361SWai Yew CHAY 	}
17068cc72361SWai Yew CHAY }
17078cc72361SWai Yew CHAY 
17088cc72361SWai Yew CHAY static int adc_init_SB055x(struct hw *hw, int input, int mic20db)
17098cc72361SWai Yew CHAY {
17108cc72361SWai Yew CHAY 	return adc_input_select_SB055x(hw, input, mic20db);
17118cc72361SWai Yew CHAY }
17128cc72361SWai Yew CHAY 
17138cc72361SWai Yew CHAY static int adc_init_SBx(struct hw *hw, int input, int mic20db)
17148cc72361SWai Yew CHAY {
17158cc72361SWai Yew CHAY 	u16 gpioorg;
17168cc72361SWai Yew CHAY 	u16 input_source;
17178cc72361SWai Yew CHAY 	u32 adcdata = 0;
17188cc72361SWai Yew CHAY 	unsigned int ret = 0;
17198cc72361SWai Yew CHAY 
17208cc72361SWai Yew CHAY 	input_source = 0x100;  /* default to analog */
17218cc72361SWai Yew CHAY 	switch (input) {
17228cc72361SWai Yew CHAY 	case ADC_MICIN:
17238cc72361SWai Yew CHAY 		adcdata = 0x1;
17248cc72361SWai Yew CHAY 		input_source = 0x180;  /* set GPIO7 to select Mic */
17258cc72361SWai Yew CHAY 		break;
17268cc72361SWai Yew CHAY 	case ADC_LINEIN:
17278cc72361SWai Yew CHAY 		adcdata = 0x2;
17288cc72361SWai Yew CHAY 		break;
17298cc72361SWai Yew CHAY 	case ADC_VIDEO:
17308cc72361SWai Yew CHAY 		adcdata = 0x4;
17318cc72361SWai Yew CHAY 		break;
17328cc72361SWai Yew CHAY 	case ADC_AUX:
17338cc72361SWai Yew CHAY 		adcdata = 0x8;
17348cc72361SWai Yew CHAY 		break;
17358cc72361SWai Yew CHAY 	case ADC_NONE:
17368cc72361SWai Yew CHAY 		adcdata = 0x0;
17378cc72361SWai Yew CHAY 		input_source = 0x0;  /* set to Digital */
17388cc72361SWai Yew CHAY 		break;
17398cc72361SWai Yew CHAY 	default:
17408cc72361SWai Yew CHAY 		break;
17418cc72361SWai Yew CHAY 	}
17428cc72361SWai Yew CHAY 
17438cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
17448cc72361SWai Yew CHAY 		return -1;
17458cc72361SWai Yew CHAY 
17468cc72361SWai Yew CHAY 	do {
17478cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
17488cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
17498cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
17508cc72361SWai Yew CHAY 
17518cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x0e, 0x08);
17528cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x18, 0x0a);
17538cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x28, 0x86);
17548cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, adcdata);
17558cc72361SWai Yew CHAY 
17568cc72361SWai Yew CHAY 	if (mic20db) {
17578cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xf7);
17588cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xf7);
17598cc72361SWai Yew CHAY 	} else {
17608cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf);
17618cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf);
17628cc72361SWai Yew CHAY 	}
17638cc72361SWai Yew CHAY 
17648cc72361SWai Yew CHAY 	if (!(hw_read_20kx(hw, ID0) & 0x100))
17658cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x16, 0x26);
17668cc72361SWai Yew CHAY 
17678cc72361SWai Yew CHAY 	i2c_lock(hw);
17688cc72361SWai Yew CHAY 
17698cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw,  GPIO);
17708cc72361SWai Yew CHAY 	gpioorg &= 0xfe7f;
17718cc72361SWai Yew CHAY 	gpioorg |= input_source;
17728cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
17738cc72361SWai Yew CHAY 
17748cc72361SWai Yew CHAY 	return 0;
17758cc72361SWai Yew CHAY }
17768cc72361SWai Yew CHAY 
17778cc72361SWai Yew CHAY static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
17788cc72361SWai Yew CHAY {
17798cc72361SWai Yew CHAY 	int err = 0;
17808cc72361SWai Yew CHAY 	u16 subsys_id = 0;
17818cc72361SWai Yew CHAY 
17828cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
17838cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
17848cc72361SWai Yew CHAY 		/* Sb055x card */
17858cc72361SWai Yew CHAY 		err = adc_init_SB055x(hw, info->input, info->mic20db);
17868cc72361SWai Yew CHAY 	} else {
17878cc72361SWai Yew CHAY 		err = adc_init_SBx(hw, info->input, info->mic20db);
17888cc72361SWai Yew CHAY 	}
17898cc72361SWai Yew CHAY 
17908cc72361SWai Yew CHAY 	return err;
17918cc72361SWai Yew CHAY }
17928cc72361SWai Yew CHAY 
17938cc72361SWai Yew CHAY static int hw_have_digit_io_switch(struct hw *hw)
17948cc72361SWai Yew CHAY {
17958cc72361SWai Yew CHAY 	u16 subsys_id = 0;
17968cc72361SWai Yew CHAY 
17978cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
17988cc72361SWai Yew CHAY 	/* SB073x and Vista compatible cards have no digit IO switch */
17998cc72361SWai Yew CHAY 	return !((subsys_id == 0x0029) || (subsys_id == 0x0031)
18008cc72361SWai Yew CHAY 				|| ((subsys_id & 0xf000) == 0x6000));
18018cc72361SWai Yew CHAY }
18028cc72361SWai Yew CHAY 
180342a0b318STakashi Iwai #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
180442a0b318STakashi Iwai 
18058cc72361SWai Yew CHAY #define UAA_CFG_PWRSTATUS	0x44
18068cc72361SWai Yew CHAY #define UAA_CFG_SPACE_FLAG	0xA0
18078cc72361SWai Yew CHAY #define UAA_CORE_CHANGE		0x3FFC
18088cc72361SWai Yew CHAY static int uaa_to_xfi(struct pci_dev *pci)
18098cc72361SWai Yew CHAY {
18108cc72361SWai Yew CHAY 	unsigned int bar0, bar1, bar2, bar3, bar4, bar5;
18118cc72361SWai Yew CHAY 	unsigned int cmd, irq, cl_size, l_timer, pwr;
18128cc72361SWai Yew CHAY 	unsigned int is_uaa = 0;
18138cc72361SWai Yew CHAY 	unsigned int data[4] = {0};
18148cc72361SWai Yew CHAY 	unsigned int io_base;
18158cc72361SWai Yew CHAY 	void *mem_base;
18168cc72361SWai Yew CHAY 	int i = 0;
181742a0b318STakashi Iwai 	const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
181842a0b318STakashi Iwai 	const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
181942a0b318STakashi Iwai 	const u32 CTLF = CTLBITS('C', 'T', 'L', 'F');
182042a0b318STakashi Iwai 	const u32 CTLi = CTLBITS('C', 'T', 'L', 'i');
182142a0b318STakashi Iwai 	const u32 CTLA = CTLBITS('C', 'T', 'L', 'A');
182242a0b318STakashi Iwai 	const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z');
182342a0b318STakashi Iwai 	const u32 CTLL = CTLBITS('C', 'T', 'L', 'L');
18248cc72361SWai Yew CHAY 
18258cc72361SWai Yew CHAY 	/* By default, Hendrix card UAA Bar0 should be using memory... */
18268cc72361SWai Yew CHAY 	io_base = pci_resource_start(pci, 0);
18278cc72361SWai Yew CHAY 	mem_base = ioremap(io_base, pci_resource_len(pci, 0));
18288cc72361SWai Yew CHAY 	if (NULL == mem_base)
18298cc72361SWai Yew CHAY 		return -ENOENT;
18308cc72361SWai Yew CHAY 
18318cc72361SWai Yew CHAY 	/* Read current mode from Mode Change Register */
18328cc72361SWai Yew CHAY 	for (i = 0; i < 4; i++)
18338cc72361SWai Yew CHAY 		data[i] = readl(mem_base + UAA_CORE_CHANGE);
18348cc72361SWai Yew CHAY 
18358cc72361SWai Yew CHAY 	/* Determine current mode... */
18368cc72361SWai Yew CHAY 	if (data[0] == CTLA) {
18378cc72361SWai Yew CHAY 		is_uaa = ((data[1] == CTLZ && data[2] == CTLL
18388cc72361SWai Yew CHAY 			  && data[3] == CTLA) || (data[1] == CTLA
18398cc72361SWai Yew CHAY 			  && data[2] == CTLZ && data[3] == CTLL));
18408cc72361SWai Yew CHAY 	} else if (data[0] == CTLZ) {
18418cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLL
18428cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLA);
18438cc72361SWai Yew CHAY 	} else if (data[0] == CTLL) {
18448cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLA
18458cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLZ);
18468cc72361SWai Yew CHAY 	} else {
18478cc72361SWai Yew CHAY 		is_uaa = 0;
18488cc72361SWai Yew CHAY 	}
18498cc72361SWai Yew CHAY 
18508cc72361SWai Yew CHAY 	if (!is_uaa) {
18518cc72361SWai Yew CHAY 		/* Not in UAA mode currently. Return directly. */
18528cc72361SWai Yew CHAY 		iounmap(mem_base);
18538cc72361SWai Yew CHAY 		return 0;
18548cc72361SWai Yew CHAY 	}
18558cc72361SWai Yew CHAY 
18568cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0);
18578cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1);
18588cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2);
18598cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3);
18608cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4);
18618cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5);
18628cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq);
18638cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size);
18648cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer);
18658cc72361SWai Yew CHAY 	pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr);
18668cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_COMMAND, &cmd);
18678cc72361SWai Yew CHAY 
18688cc72361SWai Yew CHAY 	/* Set up X-Fi core PCI configuration space. */
18698cc72361SWai Yew CHAY 	/* Switch to X-Fi config space with BAR0 exposed. */
18708cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321);
18718cc72361SWai Yew CHAY 	/* Copy UAA's BAR5 into X-Fi BAR0 */
18728cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5);
18738cc72361SWai Yew CHAY 	/* Switch to X-Fi config space without BAR0 exposed. */
18748cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678);
18758cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1);
18768cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2);
18778cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3);
18788cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4);
18798cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq);
18808cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size);
18818cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer);
18828cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr);
18838cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_COMMAND, cmd);
18848cc72361SWai Yew CHAY 
18858cc72361SWai Yew CHAY 	/* Switch to X-Fi mode */
18868cc72361SWai Yew CHAY 	writel(CTLX, (mem_base + UAA_CORE_CHANGE));
18878cc72361SWai Yew CHAY 	writel(CTL_, (mem_base + UAA_CORE_CHANGE));
18888cc72361SWai Yew CHAY 	writel(CTLF, (mem_base + UAA_CORE_CHANGE));
18898cc72361SWai Yew CHAY 	writel(CTLi, (mem_base + UAA_CORE_CHANGE));
18908cc72361SWai Yew CHAY 
18918cc72361SWai Yew CHAY 	iounmap(mem_base);
18928cc72361SWai Yew CHAY 
18938cc72361SWai Yew CHAY 	return 0;
18948cc72361SWai Yew CHAY }
18958cc72361SWai Yew CHAY 
1896*b7bbf876STakashi Iwai static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
1897*b7bbf876STakashi Iwai {
1898*b7bbf876STakashi Iwai 	struct hw *hw = dev_id;
1899*b7bbf876STakashi Iwai 	unsigned int status;
1900*b7bbf876STakashi Iwai 
1901*b7bbf876STakashi Iwai 	status = hw_read_20kx(hw, GIP);
1902*b7bbf876STakashi Iwai 	if (!status)
1903*b7bbf876STakashi Iwai 		return IRQ_NONE;
1904*b7bbf876STakashi Iwai 
1905*b7bbf876STakashi Iwai 	if (hw->irq_callback)
1906*b7bbf876STakashi Iwai 		hw->irq_callback(hw->irq_callback_data, status);
1907*b7bbf876STakashi Iwai 
1908*b7bbf876STakashi Iwai 	hw_write_20kx(hw, GIP, status);
1909*b7bbf876STakashi Iwai 	return IRQ_HANDLED;
1910*b7bbf876STakashi Iwai }
1911*b7bbf876STakashi Iwai 
19128cc72361SWai Yew CHAY static int hw_card_start(struct hw *hw)
19138cc72361SWai Yew CHAY {
19148cc72361SWai Yew CHAY 	int err = 0;
19158cc72361SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
19168cc72361SWai Yew CHAY 	u16 subsys_id = 0;
19178cc72361SWai Yew CHAY 
19188cc72361SWai Yew CHAY 	err = pci_enable_device(pci);
19198cc72361SWai Yew CHAY 	if (err < 0)
19208cc72361SWai Yew CHAY 		return err;
19218cc72361SWai Yew CHAY 
19228cc72361SWai Yew CHAY 	/* Set DMA transfer mask */
19236bc5874aSTakashi Iwai 	if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
19246bc5874aSTakashi Iwai 	    pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
19258cc72361SWai Yew CHAY 		printk(KERN_ERR "architecture does not support PCI "
19266bc5874aSTakashi Iwai 				"busmaster DMA with mask 0x%llx\n",
19276bc5874aSTakashi Iwai 		       CT_XFI_DMA_MASK);
19288cc72361SWai Yew CHAY 		err = -ENXIO;
19298cc72361SWai Yew CHAY 		goto error1;
19308cc72361SWai Yew CHAY 	}
19318cc72361SWai Yew CHAY 
19328cc72361SWai Yew CHAY 	err = pci_request_regions(pci, "XFi");
19338cc72361SWai Yew CHAY 	if (err < 0)
19348cc72361SWai Yew CHAY 		goto error1;
19358cc72361SWai Yew CHAY 
19368cc72361SWai Yew CHAY 	/* Switch to X-Fi mode from UAA mode if neeeded */
19378cc72361SWai Yew CHAY 	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsys_id);
19388cc72361SWai Yew CHAY 	if ((0x5 == pci->device) && (0x6000 == (subsys_id & 0x6000))) {
19398cc72361SWai Yew CHAY 		err = uaa_to_xfi(pci);
19408cc72361SWai Yew CHAY 		if (err)
19418cc72361SWai Yew CHAY 			goto error2;
19428cc72361SWai Yew CHAY 
19438cc72361SWai Yew CHAY 		hw->io_base = pci_resource_start(pci, 5);
19448cc72361SWai Yew CHAY 	} else {
19458cc72361SWai Yew CHAY 		hw->io_base = pci_resource_start(pci, 0);
19468cc72361SWai Yew CHAY 	}
19478cc72361SWai Yew CHAY 
1948*b7bbf876STakashi Iwai 	err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
1949*b7bbf876STakashi Iwai 			  "ctxfi", hw);
1950*b7bbf876STakashi Iwai 	if (err < 0) {
1951*b7bbf876STakashi Iwai 		printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
19528cc72361SWai Yew CHAY 		goto error2;
19538cc72361SWai Yew CHAY 	}
19548cc72361SWai Yew CHAY 	hw->irq = pci->irq;
19558cc72361SWai Yew CHAY 
19568cc72361SWai Yew CHAY 	pci_set_master(pci);
19578cc72361SWai Yew CHAY 
19588cc72361SWai Yew CHAY 	return 0;
19598cc72361SWai Yew CHAY 
19608cc72361SWai Yew CHAY error2:
19618cc72361SWai Yew CHAY 	pci_release_regions(pci);
19628cc72361SWai Yew CHAY 	hw->io_base = 0;
19638cc72361SWai Yew CHAY error1:
19648cc72361SWai Yew CHAY 	pci_disable_device(pci);
19658cc72361SWai Yew CHAY 	return err;
19668cc72361SWai Yew CHAY }
19678cc72361SWai Yew CHAY 
19688cc72361SWai Yew CHAY static int hw_card_stop(struct hw *hw)
19698cc72361SWai Yew CHAY {
19708cc72361SWai Yew CHAY 	/* TODO: Disable interrupt and so on... */
1971*b7bbf876STakashi Iwai 	if (hw->irq >= 0)
1972*b7bbf876STakashi Iwai 		synchronize_irq(hw->irq);
19738cc72361SWai Yew CHAY 	return 0;
19748cc72361SWai Yew CHAY }
19758cc72361SWai Yew CHAY 
19768cc72361SWai Yew CHAY static int hw_card_shutdown(struct hw *hw)
19778cc72361SWai Yew CHAY {
19788cc72361SWai Yew CHAY 	if (hw->irq >= 0)
19798cc72361SWai Yew CHAY 		free_irq(hw->irq, hw);
19808cc72361SWai Yew CHAY 
19818cc72361SWai Yew CHAY 	hw->irq	= -1;
19828cc72361SWai Yew CHAY 
19838cc72361SWai Yew CHAY 	if (NULL != ((void *)hw->mem_base))
19848cc72361SWai Yew CHAY 		iounmap((void *)hw->mem_base);
19858cc72361SWai Yew CHAY 
19868cc72361SWai Yew CHAY 	hw->mem_base = (unsigned long)NULL;
19878cc72361SWai Yew CHAY 
19888cc72361SWai Yew CHAY 	if (hw->io_base)
19898cc72361SWai Yew CHAY 		pci_release_regions(hw->pci);
19908cc72361SWai Yew CHAY 
19918cc72361SWai Yew CHAY 	hw->io_base = 0;
19928cc72361SWai Yew CHAY 
19938cc72361SWai Yew CHAY 	pci_disable_device(hw->pci);
19948cc72361SWai Yew CHAY 
19958cc72361SWai Yew CHAY 	return 0;
19968cc72361SWai Yew CHAY }
19978cc72361SWai Yew CHAY 
19988cc72361SWai Yew CHAY static int hw_card_init(struct hw *hw, struct card_conf *info)
19998cc72361SWai Yew CHAY {
20008cc72361SWai Yew CHAY 	int err;
20018cc72361SWai Yew CHAY 	unsigned int gctl;
20028cc72361SWai Yew CHAY 	u16 subsys_id = 0;
20038cc72361SWai Yew CHAY 	u32 data = 0;
20048cc72361SWai Yew CHAY 	struct dac_conf dac_info = {0};
20058cc72361SWai Yew CHAY 	struct adc_conf adc_info = {0};
20068cc72361SWai Yew CHAY 	struct daio_conf daio_info = {0};
20078cc72361SWai Yew CHAY 	struct trn_conf trn_info = {0};
20088cc72361SWai Yew CHAY 
20098cc72361SWai Yew CHAY 	/* Get PCI io port base address and do Hendrix switch if needed. */
20108cc72361SWai Yew CHAY 	if (!hw->io_base) {
20118cc72361SWai Yew CHAY 		err = hw_card_start(hw);
20128cc72361SWai Yew CHAY 		if (err)
20138cc72361SWai Yew CHAY 			return err;
20148cc72361SWai Yew CHAY 	}
20158cc72361SWai Yew CHAY 
20168cc72361SWai Yew CHAY 	/* PLL init */
20178cc72361SWai Yew CHAY 	err = hw_pll_init(hw, info->rsr);
20188cc72361SWai Yew CHAY 	if (err < 0)
20198cc72361SWai Yew CHAY 		return err;
20208cc72361SWai Yew CHAY 
20218cc72361SWai Yew CHAY 	/* kick off auto-init */
20228cc72361SWai Yew CHAY 	err = hw_auto_init(hw);
20238cc72361SWai Yew CHAY 	if (err < 0)
20248cc72361SWai Yew CHAY 		return err;
20258cc72361SWai Yew CHAY 
20268cc72361SWai Yew CHAY 	/* Enable audio ring */
20278cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
20288cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAC, 1);
20298cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_DBP, 1);
20308cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_TBP, 1);
20318cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_FBP, 1);
20328cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_ET, 1);
20338cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
20348cc72361SWai Yew CHAY 	mdelay(10);
20358cc72361SWai Yew CHAY 
20368cc72361SWai Yew CHAY 	/* Reset all global pending interrupts */
20378cc72361SWai Yew CHAY 	hw_write_20kx(hw, GIE, 0);
20388cc72361SWai Yew CHAY 	/* Reset all SRC pending interrupts */
20398cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCIP, 0);
20408cc72361SWai Yew CHAY 	mdelay(30);
20418cc72361SWai Yew CHAY 
20428cc72361SWai Yew CHAY 	pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
20438cc72361SWai Yew CHAY 	/* Detect the card ID and configure GPIO accordingly. */
20448cc72361SWai Yew CHAY 	if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
20458cc72361SWai Yew CHAY 		/* SB055x cards */
20468cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x13fe);
20478cc72361SWai Yew CHAY 	} else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
20488cc72361SWai Yew CHAY 		/* SB073x cards */
20498cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00e6);
20508cc72361SWai Yew CHAY 	} else if ((subsys_id & 0xf000) == 0x6000) {
20518cc72361SWai Yew CHAY 		/* Vista compatible cards */
20528cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00c2);
20538cc72361SWai Yew CHAY 	} else {
20548cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x01e6);
20558cc72361SWai Yew CHAY 	}
20568cc72361SWai Yew CHAY 
20578cc72361SWai Yew CHAY 	trn_info.vm_pgt_phys = info->vm_pgt_phys;
20588cc72361SWai Yew CHAY 	err = hw_trn_init(hw, &trn_info);
20598cc72361SWai Yew CHAY 	if (err < 0)
20608cc72361SWai Yew CHAY 		return err;
20618cc72361SWai Yew CHAY 
20628cc72361SWai Yew CHAY 	daio_info.msr = info->msr;
20638cc72361SWai Yew CHAY 	err = hw_daio_init(hw, &daio_info);
20648cc72361SWai Yew CHAY 	if (err < 0)
20658cc72361SWai Yew CHAY 		return err;
20668cc72361SWai Yew CHAY 
20678cc72361SWai Yew CHAY 	dac_info.msr = info->msr;
20688cc72361SWai Yew CHAY 	err = hw_dac_init(hw, &dac_info);
20698cc72361SWai Yew CHAY 	if (err < 0)
20708cc72361SWai Yew CHAY 		return err;
20718cc72361SWai Yew CHAY 
20728cc72361SWai Yew CHAY 	adc_info.msr = info->msr;
20738cc72361SWai Yew CHAY 	adc_info.input = ADC_LINEIN;
20748cc72361SWai Yew CHAY 	adc_info.mic20db = 0;
20758cc72361SWai Yew CHAY 	err = hw_adc_init(hw, &adc_info);
20768cc72361SWai Yew CHAY 	if (err < 0)
20778cc72361SWai Yew CHAY 		return err;
20788cc72361SWai Yew CHAY 
20798cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, SRCMCTL);
20808cc72361SWai Yew CHAY 	data |= 0x1; /* Enables input from the audio ring */
20818cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCMCTL, data);
20828cc72361SWai Yew CHAY 
20838cc72361SWai Yew CHAY 	return 0;
20848cc72361SWai Yew CHAY }
20858cc72361SWai Yew CHAY 
20868cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg)
20878cc72361SWai Yew CHAY {
20888cc72361SWai Yew CHAY 	u32 value;
20898cc72361SWai Yew CHAY 	unsigned long flags;
20908cc72361SWai Yew CHAY 
20918cc72361SWai Yew CHAY 	spin_lock_irqsave(
20928cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
20938cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
20948cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x4);
20958cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
20968cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
20978cc72361SWai Yew CHAY 
20988cc72361SWai Yew CHAY 	return value;
20998cc72361SWai Yew CHAY }
21008cc72361SWai Yew CHAY 
21018cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
21028cc72361SWai Yew CHAY {
21038cc72361SWai Yew CHAY 	unsigned long flags;
21048cc72361SWai Yew CHAY 
21058cc72361SWai Yew CHAY 	spin_lock_irqsave(
21068cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21078cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
21088cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x4);
21098cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21108cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21118cc72361SWai Yew CHAY 
21128cc72361SWai Yew CHAY }
21138cc72361SWai Yew CHAY 
21148cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg)
21158cc72361SWai Yew CHAY {
21168cc72361SWai Yew CHAY 	u32 value;
21178cc72361SWai Yew CHAY 	unsigned long flags;
21188cc72361SWai Yew CHAY 
21198cc72361SWai Yew CHAY 	spin_lock_irqsave(
21208cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21218cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
21228cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x14);
21238cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21248cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21258cc72361SWai Yew CHAY 
21268cc72361SWai Yew CHAY 	return value;
21278cc72361SWai Yew CHAY }
21288cc72361SWai Yew CHAY 
21298cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
21308cc72361SWai Yew CHAY {
21318cc72361SWai Yew CHAY 	unsigned long flags;
21328cc72361SWai Yew CHAY 
21338cc72361SWai Yew CHAY 	spin_lock_irqsave(
21348cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21358cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
21368cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x14);
21378cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21388cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21398cc72361SWai Yew CHAY }
21408cc72361SWai Yew CHAY 
21418cc72361SWai Yew CHAY int create_20k1_hw_obj(struct hw **rhw)
21428cc72361SWai Yew CHAY {
21438cc72361SWai Yew CHAY 	struct hw *hw;
21448cc72361SWai Yew CHAY 	struct hw20k1 *hw20k1;
21458cc72361SWai Yew CHAY 
21468cc72361SWai Yew CHAY 	*rhw = NULL;
21478cc72361SWai Yew CHAY 	hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
21488cc72361SWai Yew CHAY 	if (NULL == hw20k1)
21498cc72361SWai Yew CHAY 		return -ENOMEM;
21508cc72361SWai Yew CHAY 
21518cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_20k1_lock);
21528cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_pci_lock);
21538cc72361SWai Yew CHAY 
21548cc72361SWai Yew CHAY 	hw = &hw20k1->hw;
21558cc72361SWai Yew CHAY 
21568cc72361SWai Yew CHAY 	hw->io_base = 0;
21578cc72361SWai Yew CHAY 	hw->mem_base = (unsigned long)NULL;
21588cc72361SWai Yew CHAY 	hw->irq = -1;
21598cc72361SWai Yew CHAY 
21608cc72361SWai Yew CHAY 	hw->card_init = hw_card_init;
21618cc72361SWai Yew CHAY 	hw->card_stop = hw_card_stop;
21628cc72361SWai Yew CHAY 	hw->pll_init = hw_pll_init;
21638cc72361SWai Yew CHAY 	hw->is_adc_source_selected = hw_is_adc_input_selected;
21648cc72361SWai Yew CHAY 	hw->select_adc_source = hw_adc_input_select;
21658cc72361SWai Yew CHAY 	hw->have_digit_io_switch = hw_have_digit_io_switch;
21668cc72361SWai Yew CHAY 
21678cc72361SWai Yew CHAY 	hw->src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk;
21688cc72361SWai Yew CHAY 	hw->src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk;
21698cc72361SWai Yew CHAY 	hw->src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk;
21708cc72361SWai Yew CHAY 	hw->src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk;
21718cc72361SWai Yew CHAY 	hw->src_set_state = src_set_state;
21728cc72361SWai Yew CHAY 	hw->src_set_bm = src_set_bm;
21738cc72361SWai Yew CHAY 	hw->src_set_rsr = src_set_rsr;
21748cc72361SWai Yew CHAY 	hw->src_set_sf = src_set_sf;
21758cc72361SWai Yew CHAY 	hw->src_set_wr = src_set_wr;
21768cc72361SWai Yew CHAY 	hw->src_set_pm = src_set_pm;
21778cc72361SWai Yew CHAY 	hw->src_set_rom = src_set_rom;
21788cc72361SWai Yew CHAY 	hw->src_set_vo = src_set_vo;
21798cc72361SWai Yew CHAY 	hw->src_set_st = src_set_st;
21808cc72361SWai Yew CHAY 	hw->src_set_ie = src_set_ie;
21818cc72361SWai Yew CHAY 	hw->src_set_ilsz = src_set_ilsz;
21828cc72361SWai Yew CHAY 	hw->src_set_bp = src_set_bp;
21838cc72361SWai Yew CHAY 	hw->src_set_cisz = src_set_cisz;
21848cc72361SWai Yew CHAY 	hw->src_set_ca = src_set_ca;
21858cc72361SWai Yew CHAY 	hw->src_set_sa = src_set_sa;
21868cc72361SWai Yew CHAY 	hw->src_set_la = src_set_la;
21878cc72361SWai Yew CHAY 	hw->src_set_pitch = src_set_pitch;
21888cc72361SWai Yew CHAY 	hw->src_set_dirty = src_set_dirty;
21898cc72361SWai Yew CHAY 	hw->src_set_clear_zbufs = src_set_clear_zbufs;
21908cc72361SWai Yew CHAY 	hw->src_set_dirty_all = src_set_dirty_all;
21918cc72361SWai Yew CHAY 	hw->src_commit_write = src_commit_write;
21928cc72361SWai Yew CHAY 	hw->src_get_ca = src_get_ca;
21938cc72361SWai Yew CHAY 	hw->src_get_dirty = src_get_dirty;
21948cc72361SWai Yew CHAY 	hw->src_dirty_conj_mask = src_dirty_conj_mask;
21958cc72361SWai Yew CHAY 	hw->src_mgr_enbs_src = src_mgr_enbs_src;
21968cc72361SWai Yew CHAY 	hw->src_mgr_enb_src = src_mgr_enb_src;
21978cc72361SWai Yew CHAY 	hw->src_mgr_dsb_src = src_mgr_dsb_src;
21988cc72361SWai Yew CHAY 	hw->src_mgr_commit_write = src_mgr_commit_write;
21998cc72361SWai Yew CHAY 
22008cc72361SWai Yew CHAY 	hw->srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk;
22018cc72361SWai Yew CHAY 	hw->srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk;
22028cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc;
22038cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser;
22048cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt;
22058cc72361SWai Yew CHAY 	hw->srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr;
22068cc72361SWai Yew CHAY 	hw->srcimp_mgr_commit_write = srcimp_mgr_commit_write;
22078cc72361SWai Yew CHAY 
22088cc72361SWai Yew CHAY 	hw->amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk;
22098cc72361SWai Yew CHAY 	hw->amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk;
22108cc72361SWai Yew CHAY 	hw->amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk;
22118cc72361SWai Yew CHAY 	hw->amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk;
22128cc72361SWai Yew CHAY 	hw->amixer_set_mode = amixer_set_mode;
22138cc72361SWai Yew CHAY 	hw->amixer_set_iv = amixer_set_iv;
22148cc72361SWai Yew CHAY 	hw->amixer_set_x = amixer_set_x;
22158cc72361SWai Yew CHAY 	hw->amixer_set_y = amixer_set_y;
22168cc72361SWai Yew CHAY 	hw->amixer_set_sadr = amixer_set_sadr;
22178cc72361SWai Yew CHAY 	hw->amixer_set_se = amixer_set_se;
22188cc72361SWai Yew CHAY 	hw->amixer_set_dirty = amixer_set_dirty;
22198cc72361SWai Yew CHAY 	hw->amixer_set_dirty_all = amixer_set_dirty_all;
22208cc72361SWai Yew CHAY 	hw->amixer_commit_write = amixer_commit_write;
22218cc72361SWai Yew CHAY 	hw->amixer_get_y = amixer_get_y;
22228cc72361SWai Yew CHAY 	hw->amixer_get_dirty = amixer_get_dirty;
22238cc72361SWai Yew CHAY 
22248cc72361SWai Yew CHAY 	hw->dai_get_ctrl_blk = dai_get_ctrl_blk;
22258cc72361SWai Yew CHAY 	hw->dai_put_ctrl_blk = dai_put_ctrl_blk;
22268cc72361SWai Yew CHAY 	hw->dai_srt_set_srco = dai_srt_set_srcr;
22278cc72361SWai Yew CHAY 	hw->dai_srt_set_srcm = dai_srt_set_srcl;
22288cc72361SWai Yew CHAY 	hw->dai_srt_set_rsr = dai_srt_set_rsr;
22298cc72361SWai Yew CHAY 	hw->dai_srt_set_drat = dai_srt_set_drat;
22308cc72361SWai Yew CHAY 	hw->dai_srt_set_ec = dai_srt_set_ec;
22318cc72361SWai Yew CHAY 	hw->dai_srt_set_et = dai_srt_set_et;
22328cc72361SWai Yew CHAY 	hw->dai_commit_write = dai_commit_write;
22338cc72361SWai Yew CHAY 
22348cc72361SWai Yew CHAY 	hw->dao_get_ctrl_blk = dao_get_ctrl_blk;
22358cc72361SWai Yew CHAY 	hw->dao_put_ctrl_blk = dao_put_ctrl_blk;
22368cc72361SWai Yew CHAY 	hw->dao_set_spos = dao_set_spos;
22378cc72361SWai Yew CHAY 	hw->dao_commit_write = dao_commit_write;
22388cc72361SWai Yew CHAY 	hw->dao_get_spos = dao_get_spos;
22398cc72361SWai Yew CHAY 
22408cc72361SWai Yew CHAY 	hw->daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk;
22418cc72361SWai Yew CHAY 	hw->daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk;
22428cc72361SWai Yew CHAY 	hw->daio_mgr_enb_dai = daio_mgr_enb_dai;
22438cc72361SWai Yew CHAY 	hw->daio_mgr_dsb_dai = daio_mgr_dsb_dai;
22448cc72361SWai Yew CHAY 	hw->daio_mgr_enb_dao = daio_mgr_enb_dao;
22458cc72361SWai Yew CHAY 	hw->daio_mgr_dsb_dao = daio_mgr_dsb_dao;
22468cc72361SWai Yew CHAY 	hw->daio_mgr_dao_init = daio_mgr_dao_init;
22478cc72361SWai Yew CHAY 	hw->daio_mgr_set_imaparc = daio_mgr_set_imaparc;
22488cc72361SWai Yew CHAY 	hw->daio_mgr_set_imapnxt = daio_mgr_set_imapnxt;
22498cc72361SWai Yew CHAY 	hw->daio_mgr_set_imapaddr = daio_mgr_set_imapaddr;
22508cc72361SWai Yew CHAY 	hw->daio_mgr_commit_write = daio_mgr_commit_write;
22518cc72361SWai Yew CHAY 
2252*b7bbf876STakashi Iwai 	hw->set_timer_irq = set_timer_irq;
2253*b7bbf876STakashi Iwai 	hw->set_timer_tick = set_timer_tick;
2254*b7bbf876STakashi Iwai 
22558cc72361SWai Yew CHAY 	*rhw = hw;
22568cc72361SWai Yew CHAY 
22578cc72361SWai Yew CHAY 	return 0;
22588cc72361SWai Yew CHAY }
22598cc72361SWai Yew CHAY 
22608cc72361SWai Yew CHAY int destroy_20k1_hw_obj(struct hw *hw)
22618cc72361SWai Yew CHAY {
22628cc72361SWai Yew CHAY 	if (hw->io_base)
22638cc72361SWai Yew CHAY 		hw_card_shutdown(hw);
22648cc72361SWai Yew CHAY 
22658cc72361SWai Yew CHAY 	kfree(container_of(hw, struct hw20k1, hw));
22668cc72361SWai Yew CHAY 	return 0;
22678cc72361SWai Yew CHAY }
2268