xref: /linux/sound/pci/ctxfi/cthw20k1.c (revision 25985edcedea6396277003854657b5f3cb31a628)
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);
17135ebf6e7STakashi Iwai 	if (!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;
372514eef9cSTakashi Iwai 	int i;
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;
471514eef9cSTakashi Iwai 	int i;
472514eef9cSTakashi Iwai 	unsigned int ret;
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);
49735ebf6e7STakashi Iwai 	if (!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);
51835ebf6e7STakashi Iwai 	if (!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);
70535ebf6e7STakashi Iwai 	if (!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);
72635ebf6e7STakashi Iwai 	if (!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);
91235ebf6e7STakashi Iwai 	if (!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);
96135ebf6e7STakashi Iwai 	if (!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;
1111514eef9cSTakashi Iwai 	int i;
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);
115535ebf6e7STakashi Iwai 	if (!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 
1174b7bbf876STakashi Iwai /* Timer interrupt */
1175b7bbf876STakashi Iwai static int set_timer_irq(struct hw *hw, int enable)
1176b7bbf876STakashi Iwai {
1177b7bbf876STakashi Iwai 	hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
1178b7bbf876STakashi Iwai 	return 0;
1179b7bbf876STakashi Iwai }
1180b7bbf876STakashi Iwai 
1181b7bbf876STakashi Iwai static int set_timer_tick(struct hw *hw, unsigned int ticks)
1182b7bbf876STakashi Iwai {
1183b7bbf876STakashi Iwai 	if (ticks)
1184b7bbf876STakashi Iwai 		ticks |= TIMR_IE | TIMR_IP;
1185b7bbf876STakashi Iwai 	hw_write_20kx(hw, TIMR, ticks);
1186b7bbf876STakashi Iwai 	return 0;
1187b7bbf876STakashi Iwai }
1188b7bbf876STakashi Iwai 
118954de6bc8STakashi Iwai static unsigned int get_wc(struct hw *hw)
119054de6bc8STakashi Iwai {
119154de6bc8STakashi Iwai 	return hw_read_20kx(hw, WC);
119254de6bc8STakashi Iwai }
119354de6bc8STakashi Iwai 
11948cc72361SWai Yew CHAY /* Card hardware initialization block */
11958cc72361SWai Yew CHAY struct dac_conf {
11968cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
11978cc72361SWai Yew CHAY };
11988cc72361SWai Yew CHAY 
11998cc72361SWai Yew CHAY struct adc_conf {
12008cc72361SWai Yew CHAY 	unsigned int msr; 	/* master sample rate in rsrs */
12018cc72361SWai Yew CHAY 	unsigned char input; 	/* the input source of ADC */
12028cc72361SWai Yew CHAY 	unsigned char mic20db; 	/* boost mic by 20db if input is microphone */
12038cc72361SWai Yew CHAY };
12048cc72361SWai Yew CHAY 
12058cc72361SWai Yew CHAY struct daio_conf {
12068cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
12078cc72361SWai Yew CHAY };
12088cc72361SWai Yew CHAY 
12098cc72361SWai Yew CHAY struct trn_conf {
12108cc72361SWai Yew CHAY 	unsigned long vm_pgt_phys;
12118cc72361SWai Yew CHAY };
12128cc72361SWai Yew CHAY 
12138cc72361SWai Yew CHAY static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
12148cc72361SWai Yew CHAY {
1215514eef9cSTakashi Iwai 	u32 i2sorg;
1216514eef9cSTakashi Iwai 	u32 spdorg;
12178cc72361SWai Yew CHAY 
12188cc72361SWai Yew CHAY 	/* Read I2S CTL.  Keep original value. */
12198cc72361SWai Yew CHAY 	/*i2sorg = hw_read_20kx(hw, I2SCTL);*/
12208cc72361SWai Yew CHAY 	i2sorg = 0x94040404; /* enable all audio out and I2S-D input */
12218cc72361SWai Yew CHAY 	/* Program I2S with proper master sample rate and enable
12228cc72361SWai Yew CHAY 	 * the correct I2S channel. */
12238cc72361SWai Yew CHAY 	i2sorg &= 0xfffffffc;
12248cc72361SWai Yew CHAY 
12258cc72361SWai Yew CHAY 	/* Enable S/PDIF-out-A in fixed 24-bit data
12268cc72361SWai Yew CHAY 	 * format and default to 48kHz. */
12278cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
12288cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, 0x0);
12298cc72361SWai Yew CHAY 	spdorg = 0x05;
12308cc72361SWai Yew CHAY 
12318cc72361SWai Yew CHAY 	switch (info->msr) {
12328cc72361SWai Yew CHAY 	case 1:
12338cc72361SWai Yew CHAY 		i2sorg |= 1;
12348cc72361SWai Yew CHAY 		spdorg |= (0x0 << 6);
12358cc72361SWai Yew CHAY 		break;
12368cc72361SWai Yew CHAY 	case 2:
12378cc72361SWai Yew CHAY 		i2sorg |= 2;
12388cc72361SWai Yew CHAY 		spdorg |= (0x1 << 6);
12398cc72361SWai Yew CHAY 		break;
12408cc72361SWai Yew CHAY 	case 4:
12418cc72361SWai Yew CHAY 		i2sorg |= 3;
12428cc72361SWai Yew CHAY 		spdorg |= (0x2 << 6);
12438cc72361SWai Yew CHAY 		break;
12448cc72361SWai Yew CHAY 	default:
12458cc72361SWai Yew CHAY 		i2sorg |= 1;
12468cc72361SWai Yew CHAY 		break;
12478cc72361SWai Yew CHAY 	}
12488cc72361SWai Yew CHAY 
12498cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2SCTL, i2sorg);
12508cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, spdorg);
12518cc72361SWai Yew CHAY 
12528cc72361SWai Yew CHAY 	/* Enable S/PDIF-in-A in fixed 24-bit data format. */
12538cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
12548cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, 0x0);
12558cc72361SWai Yew CHAY 	mdelay(1);
12568cc72361SWai Yew CHAY 	spdorg = 0x0a0a0a0a;
12578cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, spdorg);
12588cc72361SWai Yew CHAY 	mdelay(1);
12598cc72361SWai Yew CHAY 
12608cc72361SWai Yew CHAY 	return 0;
12618cc72361SWai Yew CHAY }
12628cc72361SWai Yew CHAY 
12638cc72361SWai Yew CHAY /* TRANSPORT operations */
12648cc72361SWai Yew CHAY static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
12658cc72361SWai Yew CHAY {
1266514eef9cSTakashi Iwai 	u32 trnctl;
1267514eef9cSTakashi Iwai 	u32 ptp_phys_low, ptp_phys_high;
12688cc72361SWai Yew CHAY 
12698cc72361SWai Yew CHAY 	/* Set up device page table */
12708cc72361SWai Yew CHAY 	if ((~0UL) == info->vm_pgt_phys) {
12718cc72361SWai Yew CHAY 		printk(KERN_ERR "Wrong device page table page address!\n");
12728cc72361SWai Yew CHAY 		return -1;
12738cc72361SWai Yew CHAY 	}
12748cc72361SWai Yew CHAY 
12758cc72361SWai Yew CHAY 	trnctl = 0x13;  /* 32-bit, 4k-size page */
1276cd391e20STakashi Iwai 	ptp_phys_low = (u32)info->vm_pgt_phys;
1277cd391e20STakashi Iwai 	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
1278cd391e20STakashi Iwai 	if (sizeof(void *) == 8) /* 64bit address */
12798cc72361SWai Yew CHAY 		trnctl |= (1 << 2);
1280cd391e20STakashi Iwai #if 0 /* Only 4k h/w pages for simplicitiy */
12818cc72361SWai Yew CHAY #if PAGE_SIZE == 8192
12828cc72361SWai Yew CHAY 	trnctl |= (1<<5);
12838cc72361SWai Yew CHAY #endif
1284cd391e20STakashi Iwai #endif
12858cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPALX, ptp_phys_low);
12868cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPAHX, ptp_phys_high);
12878cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRNCTL, trnctl);
1288*25985edcSLucas De Marchi 	hw_write_20kx(hw, TRNIS, 0x200c01); /* really needed? */
12898cc72361SWai Yew CHAY 
12908cc72361SWai Yew CHAY 	return 0;
12918cc72361SWai Yew CHAY }
12928cc72361SWai Yew CHAY 
12938cc72361SWai Yew CHAY /* Card initialization */
12948cc72361SWai Yew CHAY #define GCTL_EAC	0x00000001
12958cc72361SWai Yew CHAY #define GCTL_EAI	0x00000002
12968cc72361SWai Yew CHAY #define GCTL_BEP	0x00000004
12978cc72361SWai Yew CHAY #define GCTL_BES	0x00000008
12988cc72361SWai Yew CHAY #define GCTL_DSP	0x00000010
12998cc72361SWai Yew CHAY #define GCTL_DBP	0x00000020
13008cc72361SWai Yew CHAY #define GCTL_ABP	0x00000040
13018cc72361SWai Yew CHAY #define GCTL_TBP	0x00000080
13028cc72361SWai Yew CHAY #define GCTL_SBP	0x00000100
13038cc72361SWai Yew CHAY #define GCTL_FBP	0x00000200
13048cc72361SWai Yew CHAY #define GCTL_XA		0x00000400
13058cc72361SWai Yew CHAY #define GCTL_ET		0x00000800
13068cc72361SWai Yew CHAY #define GCTL_PR		0x00001000
13078cc72361SWai Yew CHAY #define GCTL_MRL	0x00002000
13088cc72361SWai Yew CHAY #define GCTL_SDE	0x00004000
13098cc72361SWai Yew CHAY #define GCTL_SDI	0x00008000
13108cc72361SWai Yew CHAY #define GCTL_SM		0x00010000
13118cc72361SWai Yew CHAY #define GCTL_SR		0x00020000
13128cc72361SWai Yew CHAY #define GCTL_SD		0x00040000
13138cc72361SWai Yew CHAY #define GCTL_SE		0x00080000
13148cc72361SWai Yew CHAY #define GCTL_AID	0x00100000
13158cc72361SWai Yew CHAY 
13168cc72361SWai Yew CHAY static int hw_pll_init(struct hw *hw, unsigned int rsr)
13178cc72361SWai Yew CHAY {
13188cc72361SWai Yew CHAY 	unsigned int pllctl;
1319514eef9cSTakashi Iwai 	int i;
13208cc72361SWai Yew CHAY 
13218cc72361SWai Yew CHAY 	pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731;
13228cc72361SWai Yew CHAY 	for (i = 0; i < 3; i++) {
13238cc72361SWai Yew CHAY 		if (hw_read_20kx(hw, PLLCTL) == pllctl)
13248cc72361SWai Yew CHAY 			break;
13258cc72361SWai Yew CHAY 
13268cc72361SWai Yew CHAY 		hw_write_20kx(hw, PLLCTL, pllctl);
13278cc72361SWai Yew CHAY 		mdelay(40);
13288cc72361SWai Yew CHAY 	}
13298cc72361SWai Yew CHAY 	if (i >= 3) {
13308cc72361SWai Yew CHAY 		printk(KERN_ALERT "PLL initialization failed!!!\n");
13318cc72361SWai Yew CHAY 		return -EBUSY;
13328cc72361SWai Yew CHAY 	}
13338cc72361SWai Yew CHAY 
13348cc72361SWai Yew CHAY 	return 0;
13358cc72361SWai Yew CHAY }
13368cc72361SWai Yew CHAY 
13378cc72361SWai Yew CHAY static int hw_auto_init(struct hw *hw)
13388cc72361SWai Yew CHAY {
13398cc72361SWai Yew CHAY 	unsigned int gctl;
13408cc72361SWai Yew CHAY 	int i;
13418cc72361SWai Yew CHAY 
13428cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
13438cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 0);
13448cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
13458cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 1);
13468cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
13478cc72361SWai Yew CHAY 	mdelay(10);
13488cc72361SWai Yew CHAY 	for (i = 0; i < 400000; i++) {
13498cc72361SWai Yew CHAY 		gctl = hw_read_20kx(hw, GCTL);
13508cc72361SWai Yew CHAY 		if (get_field(gctl, GCTL_AID))
13518cc72361SWai Yew CHAY 			break;
13528cc72361SWai Yew CHAY 	}
13538cc72361SWai Yew CHAY 	if (!get_field(gctl, GCTL_AID)) {
13548cc72361SWai Yew CHAY 		printk(KERN_ALERT "Card Auto-init failed!!!\n");
13558cc72361SWai Yew CHAY 		return -EBUSY;
13568cc72361SWai Yew CHAY 	}
13578cc72361SWai Yew CHAY 
13588cc72361SWai Yew CHAY 	return 0;
13598cc72361SWai Yew CHAY }
13608cc72361SWai Yew CHAY 
13618cc72361SWai Yew CHAY static int i2c_unlock(struct hw *hw)
13628cc72361SWai Yew CHAY {
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, 0x8c);
13678cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0x0e);
13688cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13698cc72361SWai Yew CHAY 		return 0;
13708cc72361SWai Yew CHAY 
13718cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xee);
13728cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xaa);
13738cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13748cc72361SWai Yew CHAY 		return 0;
13758cc72361SWai Yew CHAY 
13768cc72361SWai Yew CHAY 	return -1;
13778cc72361SWai Yew CHAY }
13788cc72361SWai Yew CHAY 
13798cc72361SWai Yew CHAY static void i2c_lock(struct hw *hw)
13808cc72361SWai Yew CHAY {
13818cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13828cc72361SWai Yew CHAY 		hw_write_pci(hw, 0xcc, 0x00);
13838cc72361SWai Yew CHAY }
13848cc72361SWai Yew CHAY 
13858cc72361SWai Yew CHAY static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data)
13868cc72361SWai Yew CHAY {
1387514eef9cSTakashi Iwai 	unsigned int ret;
13888cc72361SWai Yew CHAY 
13898cc72361SWai Yew CHAY 	do {
13908cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
13918cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
13928cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE0, device);
13938cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff));
13948cc72361SWai Yew CHAY }
13958cc72361SWai Yew CHAY 
13968cc72361SWai Yew CHAY /* DAC operations */
13978cc72361SWai Yew CHAY 
13988cc72361SWai Yew CHAY static int hw_reset_dac(struct hw *hw)
13998cc72361SWai Yew CHAY {
1400514eef9cSTakashi Iwai 	u32 i;
1401514eef9cSTakashi Iwai 	u16 gpioorg;
1402514eef9cSTakashi Iwai 	unsigned int ret;
14038cc72361SWai Yew CHAY 
14048cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
14058cc72361SWai Yew CHAY 		return -1;
14068cc72361SWai Yew CHAY 
14078cc72361SWai Yew CHAY 	do {
14088cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
14098cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
14108cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
14118cc72361SWai Yew CHAY 
14128cc72361SWai Yew CHAY 	/* To be effective, need to reset the DAC twice. */
14138cc72361SWai Yew CHAY 	for (i = 0; i < 2;  i++) {
14148cc72361SWai Yew CHAY 		/* set gpio */
14158cc72361SWai Yew CHAY 		mdelay(100);
14168cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
14178cc72361SWai Yew CHAY 		gpioorg &= 0xfffd;
14188cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
14198cc72361SWai Yew CHAY 		mdelay(1);
14208cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg | 0x2);
14218cc72361SWai Yew CHAY 	}
14228cc72361SWai Yew CHAY 
14238cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x01, 0x80);
14248cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x02, 0x10);
14258cc72361SWai Yew CHAY 
14268cc72361SWai Yew CHAY 	i2c_lock(hw);
14278cc72361SWai Yew CHAY 
14288cc72361SWai Yew CHAY 	return 0;
14298cc72361SWai Yew CHAY }
14308cc72361SWai Yew CHAY 
14318cc72361SWai Yew CHAY static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
14328cc72361SWai Yew CHAY {
1433514eef9cSTakashi Iwai 	u32 data;
1434514eef9cSTakashi Iwai 	u16 gpioorg;
1435514eef9cSTakashi Iwai 	unsigned int ret;
14368cc72361SWai Yew CHAY 
14379470195aSTakashi Iwai 	if (hw->model == CTSB055X) {
14388cc72361SWai Yew CHAY 		/* SB055x, unmute outputs */
14398cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
14408cc72361SWai Yew CHAY 		gpioorg &= 0xffbf;	/* set GPIO6 to low */
14418cc72361SWai Yew CHAY 		gpioorg |= 2;		/* set GPIO1 to high */
14428cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
14438cc72361SWai Yew CHAY 		return 0;
14448cc72361SWai Yew CHAY 	}
14458cc72361SWai Yew CHAY 
14468cc72361SWai Yew CHAY 	/* mute outputs */
14478cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
14488cc72361SWai Yew CHAY 	gpioorg &= 0xffbf;
14498cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
14508cc72361SWai Yew CHAY 
14518cc72361SWai Yew CHAY 	hw_reset_dac(hw);
14528cc72361SWai Yew CHAY 
14538cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
14548cc72361SWai Yew CHAY 		return -1;
14558cc72361SWai Yew CHAY 
14568cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
14578cc72361SWai Yew CHAY 	do {
14588cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
14598cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
14608cc72361SWai Yew CHAY 
14618cc72361SWai Yew CHAY 	switch (info->msr) {
14628cc72361SWai Yew CHAY 	case 1:
14638cc72361SWai Yew CHAY 		data = 0x24;
14648cc72361SWai Yew CHAY 		break;
14658cc72361SWai Yew CHAY 	case 2:
14668cc72361SWai Yew CHAY 		data = 0x25;
14678cc72361SWai Yew CHAY 		break;
14688cc72361SWai Yew CHAY 	case 4:
14698cc72361SWai Yew CHAY 		data = 0x26;
14708cc72361SWai Yew CHAY 		break;
14718cc72361SWai Yew CHAY 	default:
14728cc72361SWai Yew CHAY 		data = 0x24;
14738cc72361SWai Yew CHAY 		break;
14748cc72361SWai Yew CHAY 	}
14758cc72361SWai Yew CHAY 
14768cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x06, data);
14778cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x09, data);
14788cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0c, data);
14798cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0f, data);
14808cc72361SWai Yew CHAY 
14818cc72361SWai Yew CHAY 	i2c_lock(hw);
14828cc72361SWai Yew CHAY 
14838cc72361SWai Yew CHAY 	/* unmute outputs */
14848cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
14858cc72361SWai Yew CHAY 	gpioorg = gpioorg | 0x40;
14868cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
14878cc72361SWai Yew CHAY 
14888cc72361SWai Yew CHAY 	return 0;
14898cc72361SWai Yew CHAY }
14908cc72361SWai Yew CHAY 
14918cc72361SWai Yew CHAY /* ADC operations */
14928cc72361SWai Yew CHAY 
14938cc72361SWai Yew CHAY static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type)
14948cc72361SWai Yew CHAY {
1495514eef9cSTakashi Iwai 	return 0;
14968cc72361SWai Yew CHAY }
14978cc72361SWai Yew CHAY 
14988cc72361SWai Yew CHAY static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type)
14998cc72361SWai Yew CHAY {
1500514eef9cSTakashi Iwai 	u32 data;
15018cc72361SWai Yew CHAY 
15028cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15038cc72361SWai Yew CHAY 	switch (type) {
15048cc72361SWai Yew CHAY 	case ADC_MICIN:
15058cc72361SWai Yew CHAY 		data = ((data & (0x1<<7)) && (data & (0x1<<8)));
15068cc72361SWai Yew CHAY 		break;
15078cc72361SWai Yew CHAY 	case ADC_LINEIN:
15088cc72361SWai Yew CHAY 		data = (!(data & (0x1<<7)) && (data & (0x1<<8)));
15098cc72361SWai Yew CHAY 		break;
15108cc72361SWai Yew CHAY 	case ADC_NONE: /* Digital I/O */
15118cc72361SWai Yew CHAY 		data = (!(data & (0x1<<8)));
15128cc72361SWai Yew CHAY 		break;
15138cc72361SWai Yew CHAY 	default:
15148cc72361SWai Yew CHAY 		data = 0;
15158cc72361SWai Yew CHAY 	}
15168cc72361SWai Yew CHAY 	return data;
15178cc72361SWai Yew CHAY }
15188cc72361SWai Yew CHAY 
15198cc72361SWai Yew CHAY static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
15208cc72361SWai Yew CHAY {
1521514eef9cSTakashi Iwai 	u32 data;
15228cc72361SWai Yew CHAY 
15238cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15248cc72361SWai Yew CHAY 	switch (type) {
15258cc72361SWai Yew CHAY 	case ADC_MICIN:
15268cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 1 : 0;
15278cc72361SWai Yew CHAY 		break;
15288cc72361SWai Yew CHAY 	case ADC_LINEIN:
15298cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 0 : 1;
15308cc72361SWai Yew CHAY 		break;
15318cc72361SWai Yew CHAY 	default:
15328cc72361SWai Yew CHAY 		data = 0;
15338cc72361SWai Yew CHAY 	}
15348cc72361SWai Yew CHAY 	return data;
15358cc72361SWai Yew CHAY }
15368cc72361SWai Yew CHAY 
15378cc72361SWai Yew CHAY static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
15388cc72361SWai Yew CHAY {
15399470195aSTakashi Iwai 	switch (hw->model) {
15409470195aSTakashi Iwai 	case CTSB055X:
15418cc72361SWai Yew CHAY 		return is_adc_input_selected_SB055x(hw, type);
15429470195aSTakashi Iwai 	case CTSB073X:
15438cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
154409521d2eSTakashi Iwai 	case CTUAA:
15458cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
15469470195aSTakashi Iwai 	default:
15478cc72361SWai Yew CHAY 		return is_adc_input_selected_SBx(hw, type);
15488cc72361SWai Yew CHAY 	}
15498cc72361SWai Yew CHAY }
15508cc72361SWai Yew CHAY 
15518cc72361SWai Yew CHAY static int
15528cc72361SWai Yew CHAY adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost)
15538cc72361SWai Yew CHAY {
1554514eef9cSTakashi Iwai 	u32 data;
15558cc72361SWai Yew CHAY 
15568cc72361SWai Yew CHAY 	/*
15578cc72361SWai Yew CHAY 	 * check and set the following GPIO bits accordingly
15588cc72361SWai Yew CHAY 	 * ADC_Gain		= GPIO2
15598cc72361SWai Yew CHAY 	 * DRM_off		= GPIO3
15608cc72361SWai Yew CHAY 	 * Mic_Pwr_on		= GPIO7
15618cc72361SWai Yew CHAY 	 * Digital_IO_Sel	= GPIO8
15628cc72361SWai Yew CHAY 	 * Mic_Sw		= GPIO9
15638cc72361SWai Yew CHAY 	 * Aux/MicLine_Sw	= GPIO12
15648cc72361SWai Yew CHAY 	 */
15658cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15668cc72361SWai Yew CHAY 	data &= 0xec73;
15678cc72361SWai Yew CHAY 	switch (type) {
15688cc72361SWai Yew CHAY 	case ADC_MICIN:
15698cc72361SWai Yew CHAY 		data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ;
15708cc72361SWai Yew CHAY 		data |= boost ? (0x1<<2) : 0;
15718cc72361SWai Yew CHAY 		break;
15728cc72361SWai Yew CHAY 	case ADC_LINEIN:
15738cc72361SWai Yew CHAY 		data |= (0x1<<8);
15748cc72361SWai Yew CHAY 		break;
15758cc72361SWai Yew CHAY 	case ADC_AUX:
15768cc72361SWai Yew CHAY 		data |= (0x1<<8) | (0x1<<12);
15778cc72361SWai Yew CHAY 		break;
15788cc72361SWai Yew CHAY 	case ADC_NONE:
15798cc72361SWai Yew CHAY 		data |= (0x1<<12);  /* set to digital */
15808cc72361SWai Yew CHAY 		break;
15818cc72361SWai Yew CHAY 	default:
15828cc72361SWai Yew CHAY 		return -1;
15838cc72361SWai Yew CHAY 	}
15848cc72361SWai Yew CHAY 
15858cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
15868cc72361SWai Yew CHAY 
15878cc72361SWai Yew CHAY 	return 0;
15888cc72361SWai Yew CHAY }
15898cc72361SWai Yew CHAY 
15908cc72361SWai Yew CHAY 
15918cc72361SWai Yew CHAY static int
15928cc72361SWai Yew CHAY adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost)
15938cc72361SWai Yew CHAY {
1594514eef9cSTakashi Iwai 	u32 data;
1595514eef9cSTakashi Iwai 	u32 i2c_data;
1596514eef9cSTakashi Iwai 	unsigned int ret;
15978cc72361SWai Yew CHAY 
15988cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
15998cc72361SWai Yew CHAY 		return -1;
16008cc72361SWai Yew CHAY 
16018cc72361SWai Yew CHAY 	do {
16028cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
16038cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
16048cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
16058cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
16068cc72361SWai Yew CHAY 
16078cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
16088cc72361SWai Yew CHAY 	switch (type) {
16098cc72361SWai Yew CHAY 	case ADC_MICIN:
16108cc72361SWai Yew CHAY 		data |= ((0x1 << 7) | (0x1 << 8));
16118cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
16128cc72361SWai Yew CHAY 		break;
16138cc72361SWai Yew CHAY 	case ADC_LINEIN:
16148cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
16158cc72361SWai Yew CHAY 		data |= (0x1 << 8);
16168cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
16178cc72361SWai Yew CHAY 		break;
16188cc72361SWai Yew CHAY 	case ADC_NONE:
16198cc72361SWai Yew CHAY 		data &= ~(0x1 << 8);
16208cc72361SWai Yew CHAY 		i2c_data = 0x0; /* set to Digital */
16218cc72361SWai Yew CHAY 		break;
16228cc72361SWai Yew CHAY 	default:
16238cc72361SWai Yew CHAY 		i2c_lock(hw);
16248cc72361SWai Yew CHAY 		return -1;
16258cc72361SWai Yew CHAY 	}
16268cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
16278cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
16288cc72361SWai Yew CHAY 	if (boost) {
16298cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
16308cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
16318cc72361SWai Yew CHAY 	} else {
16328cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
16338cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
16348cc72361SWai Yew CHAY 	}
16358cc72361SWai Yew CHAY 
16368cc72361SWai Yew CHAY 	i2c_lock(hw);
16378cc72361SWai Yew CHAY 
16388cc72361SWai Yew CHAY 	return 0;
16398cc72361SWai Yew CHAY }
16408cc72361SWai Yew CHAY 
16418cc72361SWai Yew CHAY static int
16428cc72361SWai Yew CHAY adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
16438cc72361SWai Yew CHAY {
1644514eef9cSTakashi Iwai 	u32 data;
1645514eef9cSTakashi Iwai 	u32 i2c_data;
1646514eef9cSTakashi Iwai 	unsigned int ret;
16478cc72361SWai Yew CHAY 
16488cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
16498cc72361SWai Yew CHAY 		return -1;
16508cc72361SWai Yew CHAY 
16518cc72361SWai Yew CHAY 	do {
16528cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
16538cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
16548cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
16558cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
16568cc72361SWai Yew CHAY 
16578cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
16588cc72361SWai Yew CHAY 	switch (type) {
16598cc72361SWai Yew CHAY 	case ADC_MICIN:
16608cc72361SWai Yew CHAY 		data |= (0x1 << 7);
16618cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
16628cc72361SWai Yew CHAY 		break;
16638cc72361SWai Yew CHAY 	case ADC_LINEIN:
16648cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
16658cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
16668cc72361SWai Yew CHAY 		break;
16678cc72361SWai Yew CHAY 	default:
16688cc72361SWai Yew CHAY 		i2c_lock(hw);
16698cc72361SWai Yew CHAY 		return -1;
16708cc72361SWai Yew CHAY 	}
16718cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
16728cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
16738cc72361SWai Yew CHAY 	if (boost) {
16748cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
16758cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
16768cc72361SWai Yew CHAY 	} else {
16778cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
16788cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
16798cc72361SWai Yew CHAY 	}
16808cc72361SWai Yew CHAY 
16818cc72361SWai Yew CHAY 	i2c_lock(hw);
16828cc72361SWai Yew CHAY 
16838cc72361SWai Yew CHAY 	return 0;
16848cc72361SWai Yew CHAY }
16858cc72361SWai Yew CHAY 
16868cc72361SWai Yew CHAY static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
16878cc72361SWai Yew CHAY {
16889470195aSTakashi Iwai 	int state = type == ADC_MICIN;
16898cc72361SWai Yew CHAY 
16909470195aSTakashi Iwai 	switch (hw->model) {
16919470195aSTakashi Iwai 	case CTSB055X:
16929470195aSTakashi Iwai 		return adc_input_select_SB055x(hw, type, state);
16939470195aSTakashi Iwai 	case CTSB073X:
16949470195aSTakashi Iwai 		return adc_input_select_hendrix(hw, type, state);
169509521d2eSTakashi Iwai 	case CTUAA:
16969470195aSTakashi Iwai 		return adc_input_select_hendrix(hw, type, state);
16979470195aSTakashi Iwai 	default:
16989470195aSTakashi Iwai 		return adc_input_select_SBx(hw, type, state);
16998cc72361SWai Yew CHAY 	}
17008cc72361SWai Yew CHAY }
17018cc72361SWai Yew CHAY 
17028cc72361SWai Yew CHAY static int adc_init_SB055x(struct hw *hw, int input, int mic20db)
17038cc72361SWai Yew CHAY {
17048cc72361SWai Yew CHAY 	return adc_input_select_SB055x(hw, input, mic20db);
17058cc72361SWai Yew CHAY }
17068cc72361SWai Yew CHAY 
17078cc72361SWai Yew CHAY static int adc_init_SBx(struct hw *hw, int input, int mic20db)
17088cc72361SWai Yew CHAY {
17098cc72361SWai Yew CHAY 	u16 gpioorg;
17108cc72361SWai Yew CHAY 	u16 input_source;
1711514eef9cSTakashi Iwai 	u32 adcdata;
1712514eef9cSTakashi Iwai 	unsigned int ret;
17138cc72361SWai Yew CHAY 
17148cc72361SWai Yew CHAY 	input_source = 0x100;  /* default to analog */
17158cc72361SWai Yew CHAY 	switch (input) {
17168cc72361SWai Yew CHAY 	case ADC_MICIN:
17178cc72361SWai Yew CHAY 		adcdata = 0x1;
17188cc72361SWai Yew CHAY 		input_source = 0x180;  /* set GPIO7 to select Mic */
17198cc72361SWai Yew CHAY 		break;
17208cc72361SWai Yew CHAY 	case ADC_LINEIN:
17218cc72361SWai Yew CHAY 		adcdata = 0x2;
17228cc72361SWai Yew CHAY 		break;
17238cc72361SWai Yew CHAY 	case ADC_VIDEO:
17248cc72361SWai Yew CHAY 		adcdata = 0x4;
17258cc72361SWai Yew CHAY 		break;
17268cc72361SWai Yew CHAY 	case ADC_AUX:
17278cc72361SWai Yew CHAY 		adcdata = 0x8;
17288cc72361SWai Yew CHAY 		break;
17298cc72361SWai Yew CHAY 	case ADC_NONE:
17308cc72361SWai Yew CHAY 		adcdata = 0x0;
17318cc72361SWai Yew CHAY 		input_source = 0x0;  /* set to Digital */
17328cc72361SWai Yew CHAY 		break;
17338cc72361SWai Yew CHAY 	default:
1734514eef9cSTakashi Iwai 		adcdata = 0x0;
17358cc72361SWai Yew CHAY 		break;
17368cc72361SWai Yew CHAY 	}
17378cc72361SWai Yew CHAY 
17388cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
17398cc72361SWai Yew CHAY 		return -1;
17408cc72361SWai Yew CHAY 
17418cc72361SWai Yew CHAY 	do {
17428cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
17438cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
17448cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
17458cc72361SWai Yew CHAY 
17468cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x0e, 0x08);
17478cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x18, 0x0a);
17488cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x28, 0x86);
17498cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, adcdata);
17508cc72361SWai Yew CHAY 
17518cc72361SWai Yew CHAY 	if (mic20db) {
17528cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xf7);
17538cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xf7);
17548cc72361SWai Yew CHAY 	} else {
17558cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf);
17568cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf);
17578cc72361SWai Yew CHAY 	}
17588cc72361SWai Yew CHAY 
17598cc72361SWai Yew CHAY 	if (!(hw_read_20kx(hw, ID0) & 0x100))
17608cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x16, 0x26);
17618cc72361SWai Yew CHAY 
17628cc72361SWai Yew CHAY 	i2c_lock(hw);
17638cc72361SWai Yew CHAY 
17648cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw,  GPIO);
17658cc72361SWai Yew CHAY 	gpioorg &= 0xfe7f;
17668cc72361SWai Yew CHAY 	gpioorg |= input_source;
17678cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
17688cc72361SWai Yew CHAY 
17698cc72361SWai Yew CHAY 	return 0;
17708cc72361SWai Yew CHAY }
17718cc72361SWai Yew CHAY 
17728cc72361SWai Yew CHAY static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
17738cc72361SWai Yew CHAY {
17749470195aSTakashi Iwai 	if (hw->model == CTSB055X)
17759470195aSTakashi Iwai 		return adc_init_SB055x(hw, info->input, info->mic20db);
17769470195aSTakashi Iwai 	else
17779470195aSTakashi Iwai 		return adc_init_SBx(hw, info->input, info->mic20db);
17788cc72361SWai Yew CHAY }
17798cc72361SWai Yew CHAY 
17808cc72361SWai Yew CHAY static int hw_have_digit_io_switch(struct hw *hw)
17818cc72361SWai Yew CHAY {
17828cc72361SWai Yew CHAY 	/* SB073x and Vista compatible cards have no digit IO switch */
178309521d2eSTakashi Iwai 	return !(hw->model == CTSB073X || hw->model == CTUAA);
17848cc72361SWai Yew CHAY }
17858cc72361SWai Yew CHAY 
178642a0b318STakashi Iwai #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
178742a0b318STakashi Iwai 
17888cc72361SWai Yew CHAY #define UAA_CFG_PWRSTATUS	0x44
17898cc72361SWai Yew CHAY #define UAA_CFG_SPACE_FLAG	0xA0
17908cc72361SWai Yew CHAY #define UAA_CORE_CHANGE		0x3FFC
17918cc72361SWai Yew CHAY static int uaa_to_xfi(struct pci_dev *pci)
17928cc72361SWai Yew CHAY {
17938cc72361SWai Yew CHAY 	unsigned int bar0, bar1, bar2, bar3, bar4, bar5;
17948cc72361SWai Yew CHAY 	unsigned int cmd, irq, cl_size, l_timer, pwr;
1795514eef9cSTakashi Iwai 	unsigned int is_uaa;
17968cc72361SWai Yew CHAY 	unsigned int data[4] = {0};
17978cc72361SWai Yew CHAY 	unsigned int io_base;
17988cc72361SWai Yew CHAY 	void *mem_base;
1799514eef9cSTakashi Iwai 	int i;
180042a0b318STakashi Iwai 	const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
180142a0b318STakashi Iwai 	const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
180242a0b318STakashi Iwai 	const u32 CTLF = CTLBITS('C', 'T', 'L', 'F');
180342a0b318STakashi Iwai 	const u32 CTLi = CTLBITS('C', 'T', 'L', 'i');
180442a0b318STakashi Iwai 	const u32 CTLA = CTLBITS('C', 'T', 'L', 'A');
180542a0b318STakashi Iwai 	const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z');
180642a0b318STakashi Iwai 	const u32 CTLL = CTLBITS('C', 'T', 'L', 'L');
18078cc72361SWai Yew CHAY 
18088cc72361SWai Yew CHAY 	/* By default, Hendrix card UAA Bar0 should be using memory... */
18098cc72361SWai Yew CHAY 	io_base = pci_resource_start(pci, 0);
18108cc72361SWai Yew CHAY 	mem_base = ioremap(io_base, pci_resource_len(pci, 0));
181135ebf6e7STakashi Iwai 	if (!mem_base)
18128cc72361SWai Yew CHAY 		return -ENOENT;
18138cc72361SWai Yew CHAY 
18148cc72361SWai Yew CHAY 	/* Read current mode from Mode Change Register */
18158cc72361SWai Yew CHAY 	for (i = 0; i < 4; i++)
18168cc72361SWai Yew CHAY 		data[i] = readl(mem_base + UAA_CORE_CHANGE);
18178cc72361SWai Yew CHAY 
18188cc72361SWai Yew CHAY 	/* Determine current mode... */
18198cc72361SWai Yew CHAY 	if (data[0] == CTLA) {
18208cc72361SWai Yew CHAY 		is_uaa = ((data[1] == CTLZ && data[2] == CTLL
18218cc72361SWai Yew CHAY 			  && data[3] == CTLA) || (data[1] == CTLA
18228cc72361SWai Yew CHAY 			  && data[2] == CTLZ && data[3] == CTLL));
18238cc72361SWai Yew CHAY 	} else if (data[0] == CTLZ) {
18248cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLL
18258cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLA);
18268cc72361SWai Yew CHAY 	} else if (data[0] == CTLL) {
18278cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLA
18288cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLZ);
18298cc72361SWai Yew CHAY 	} else {
18308cc72361SWai Yew CHAY 		is_uaa = 0;
18318cc72361SWai Yew CHAY 	}
18328cc72361SWai Yew CHAY 
18338cc72361SWai Yew CHAY 	if (!is_uaa) {
18348cc72361SWai Yew CHAY 		/* Not in UAA mode currently. Return directly. */
18358cc72361SWai Yew CHAY 		iounmap(mem_base);
18368cc72361SWai Yew CHAY 		return 0;
18378cc72361SWai Yew CHAY 	}
18388cc72361SWai Yew CHAY 
18398cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0);
18408cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1);
18418cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2);
18428cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3);
18438cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4);
18448cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5);
18458cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq);
18468cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size);
18478cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer);
18488cc72361SWai Yew CHAY 	pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr);
18498cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_COMMAND, &cmd);
18508cc72361SWai Yew CHAY 
18518cc72361SWai Yew CHAY 	/* Set up X-Fi core PCI configuration space. */
18528cc72361SWai Yew CHAY 	/* Switch to X-Fi config space with BAR0 exposed. */
18538cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321);
18548cc72361SWai Yew CHAY 	/* Copy UAA's BAR5 into X-Fi BAR0 */
18558cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5);
18568cc72361SWai Yew CHAY 	/* Switch to X-Fi config space without BAR0 exposed. */
18578cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678);
18588cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1);
18598cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2);
18608cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3);
18618cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4);
18628cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq);
18638cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size);
18648cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer);
18658cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr);
18668cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_COMMAND, cmd);
18678cc72361SWai Yew CHAY 
18688cc72361SWai Yew CHAY 	/* Switch to X-Fi mode */
18698cc72361SWai Yew CHAY 	writel(CTLX, (mem_base + UAA_CORE_CHANGE));
18708cc72361SWai Yew CHAY 	writel(CTL_, (mem_base + UAA_CORE_CHANGE));
18718cc72361SWai Yew CHAY 	writel(CTLF, (mem_base + UAA_CORE_CHANGE));
18728cc72361SWai Yew CHAY 	writel(CTLi, (mem_base + UAA_CORE_CHANGE));
18738cc72361SWai Yew CHAY 
18748cc72361SWai Yew CHAY 	iounmap(mem_base);
18758cc72361SWai Yew CHAY 
18768cc72361SWai Yew CHAY 	return 0;
18778cc72361SWai Yew CHAY }
18788cc72361SWai Yew CHAY 
1879b7bbf876STakashi Iwai static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
1880b7bbf876STakashi Iwai {
1881b7bbf876STakashi Iwai 	struct hw *hw = dev_id;
1882b7bbf876STakashi Iwai 	unsigned int status;
1883b7bbf876STakashi Iwai 
1884b7bbf876STakashi Iwai 	status = hw_read_20kx(hw, GIP);
1885b7bbf876STakashi Iwai 	if (!status)
1886b7bbf876STakashi Iwai 		return IRQ_NONE;
1887b7bbf876STakashi Iwai 
1888b7bbf876STakashi Iwai 	if (hw->irq_callback)
1889b7bbf876STakashi Iwai 		hw->irq_callback(hw->irq_callback_data, status);
1890b7bbf876STakashi Iwai 
1891b7bbf876STakashi Iwai 	hw_write_20kx(hw, GIP, status);
1892b7bbf876STakashi Iwai 	return IRQ_HANDLED;
1893b7bbf876STakashi Iwai }
1894b7bbf876STakashi Iwai 
18958cc72361SWai Yew CHAY static int hw_card_start(struct hw *hw)
18968cc72361SWai Yew CHAY {
1897514eef9cSTakashi Iwai 	int err;
18988cc72361SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
18998cc72361SWai Yew CHAY 
19008cc72361SWai Yew CHAY 	err = pci_enable_device(pci);
19018cc72361SWai Yew CHAY 	if (err < 0)
19028cc72361SWai Yew CHAY 		return err;
19038cc72361SWai Yew CHAY 
19048cc72361SWai Yew CHAY 	/* Set DMA transfer mask */
19056bc5874aSTakashi Iwai 	if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
19066bc5874aSTakashi Iwai 	    pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
19078cc72361SWai Yew CHAY 		printk(KERN_ERR "architecture does not support PCI "
19086bc5874aSTakashi Iwai 				"busmaster DMA with mask 0x%llx\n",
19096bc5874aSTakashi Iwai 		       CT_XFI_DMA_MASK);
19108cc72361SWai Yew CHAY 		err = -ENXIO;
19118cc72361SWai Yew CHAY 		goto error1;
19128cc72361SWai Yew CHAY 	}
19138cc72361SWai Yew CHAY 
191429959a09SWai Yew CHAY 	if (!hw->io_base) {
19158cc72361SWai Yew CHAY 		err = pci_request_regions(pci, "XFi");
19168cc72361SWai Yew CHAY 		if (err < 0)
19178cc72361SWai Yew CHAY 			goto error1;
19188cc72361SWai Yew CHAY 
191929959a09SWai Yew CHAY 		if (hw->model == CTUAA)
192029959a09SWai Yew CHAY 			hw->io_base = pci_resource_start(pci, 5);
192129959a09SWai Yew CHAY 		else
192229959a09SWai Yew CHAY 			hw->io_base = pci_resource_start(pci, 0);
192329959a09SWai Yew CHAY 
192429959a09SWai Yew CHAY 	}
192529959a09SWai Yew CHAY 
19268cc72361SWai Yew CHAY 	/* Switch to X-Fi mode from UAA mode if neeeded */
192709521d2eSTakashi Iwai 	if (hw->model == CTUAA) {
19288cc72361SWai Yew CHAY 		err = uaa_to_xfi(pci);
19298cc72361SWai Yew CHAY 		if (err)
19308cc72361SWai Yew CHAY 			goto error2;
19318cc72361SWai Yew CHAY 
19328cc72361SWai Yew CHAY 	}
19338cc72361SWai Yew CHAY 
193429959a09SWai Yew CHAY 	if (hw->irq < 0) {
1935b7bbf876STakashi Iwai 		err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
1936b7bbf876STakashi Iwai 				  "ctxfi", hw);
1937b7bbf876STakashi Iwai 		if (err < 0) {
1938b7bbf876STakashi Iwai 			printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
19398cc72361SWai Yew CHAY 			goto error2;
19408cc72361SWai Yew CHAY 		}
19418cc72361SWai Yew CHAY 		hw->irq = pci->irq;
194229959a09SWai Yew CHAY 	}
19438cc72361SWai Yew CHAY 
19448cc72361SWai Yew CHAY 	pci_set_master(pci);
19458cc72361SWai Yew CHAY 
19468cc72361SWai Yew CHAY 	return 0;
19478cc72361SWai Yew CHAY 
19488cc72361SWai Yew CHAY error2:
19498cc72361SWai Yew CHAY 	pci_release_regions(pci);
19508cc72361SWai Yew CHAY 	hw->io_base = 0;
19518cc72361SWai Yew CHAY error1:
19528cc72361SWai Yew CHAY 	pci_disable_device(pci);
19538cc72361SWai Yew CHAY 	return err;
19548cc72361SWai Yew CHAY }
19558cc72361SWai Yew CHAY 
19568cc72361SWai Yew CHAY static int hw_card_stop(struct hw *hw)
19578cc72361SWai Yew CHAY {
195829959a09SWai Yew CHAY 	unsigned int data;
195929959a09SWai Yew CHAY 
196029959a09SWai Yew CHAY 	/* disable transport bus master and queueing of request */
196129959a09SWai Yew CHAY 	hw_write_20kx(hw, TRNCTL, 0x00);
196229959a09SWai Yew CHAY 
196329959a09SWai Yew CHAY 	/* disable pll */
196429959a09SWai Yew CHAY 	data = hw_read_20kx(hw, PLLCTL);
196529959a09SWai Yew CHAY 	hw_write_20kx(hw, PLLCTL, (data & (~(0x0F<<12))));
196629959a09SWai Yew CHAY 
19678cc72361SWai Yew CHAY 	/* TODO: Disable interrupt and so on... */
1968b7bbf876STakashi Iwai 	if (hw->irq >= 0)
1969b7bbf876STakashi Iwai 		synchronize_irq(hw->irq);
19708cc72361SWai Yew CHAY 	return 0;
19718cc72361SWai Yew CHAY }
19728cc72361SWai Yew CHAY 
19738cc72361SWai Yew CHAY static int hw_card_shutdown(struct hw *hw)
19748cc72361SWai Yew CHAY {
19758cc72361SWai Yew CHAY 	if (hw->irq >= 0)
19768cc72361SWai Yew CHAY 		free_irq(hw->irq, hw);
19778cc72361SWai Yew CHAY 
19788cc72361SWai Yew CHAY 	hw->irq	= -1;
19798cc72361SWai Yew CHAY 
198035ebf6e7STakashi Iwai 	if (hw->mem_base)
19818cc72361SWai Yew CHAY 		iounmap((void *)hw->mem_base);
19828cc72361SWai Yew CHAY 
19838cc72361SWai Yew CHAY 	hw->mem_base = (unsigned long)NULL;
19848cc72361SWai Yew CHAY 
19858cc72361SWai Yew CHAY 	if (hw->io_base)
19868cc72361SWai Yew CHAY 		pci_release_regions(hw->pci);
19878cc72361SWai Yew CHAY 
19888cc72361SWai Yew CHAY 	hw->io_base = 0;
19898cc72361SWai Yew CHAY 
19908cc72361SWai Yew CHAY 	pci_disable_device(hw->pci);
19918cc72361SWai Yew CHAY 
19928cc72361SWai Yew CHAY 	return 0;
19938cc72361SWai Yew CHAY }
19948cc72361SWai Yew CHAY 
19958cc72361SWai Yew CHAY static int hw_card_init(struct hw *hw, struct card_conf *info)
19968cc72361SWai Yew CHAY {
19978cc72361SWai Yew CHAY 	int err;
19988cc72361SWai Yew CHAY 	unsigned int gctl;
1999514eef9cSTakashi Iwai 	u32 data;
20008cc72361SWai Yew CHAY 	struct dac_conf dac_info = {0};
20018cc72361SWai Yew CHAY 	struct adc_conf adc_info = {0};
20028cc72361SWai Yew CHAY 	struct daio_conf daio_info = {0};
20038cc72361SWai Yew CHAY 	struct trn_conf trn_info = {0};
20048cc72361SWai Yew CHAY 
20058cc72361SWai Yew CHAY 	/* Get PCI io port base address and do Hendrix switch if needed. */
20068cc72361SWai Yew CHAY 	err = hw_card_start(hw);
20078cc72361SWai Yew CHAY 	if (err)
20088cc72361SWai Yew CHAY 		return err;
20098cc72361SWai Yew CHAY 
20108cc72361SWai Yew CHAY 	/* PLL init */
20118cc72361SWai Yew CHAY 	err = hw_pll_init(hw, info->rsr);
20128cc72361SWai Yew CHAY 	if (err < 0)
20138cc72361SWai Yew CHAY 		return err;
20148cc72361SWai Yew CHAY 
20158cc72361SWai Yew CHAY 	/* kick off auto-init */
20168cc72361SWai Yew CHAY 	err = hw_auto_init(hw);
20178cc72361SWai Yew CHAY 	if (err < 0)
20188cc72361SWai Yew CHAY 		return err;
20198cc72361SWai Yew CHAY 
20208cc72361SWai Yew CHAY 	/* Enable audio ring */
20218cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
20228cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAC, 1);
20238cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_DBP, 1);
20248cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_TBP, 1);
20258cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_FBP, 1);
20268cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_ET, 1);
20278cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
20288cc72361SWai Yew CHAY 	mdelay(10);
20298cc72361SWai Yew CHAY 
20308cc72361SWai Yew CHAY 	/* Reset all global pending interrupts */
20318cc72361SWai Yew CHAY 	hw_write_20kx(hw, GIE, 0);
20328cc72361SWai Yew CHAY 	/* Reset all SRC pending interrupts */
20338cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCIP, 0);
20348cc72361SWai Yew CHAY 	mdelay(30);
20358cc72361SWai Yew CHAY 
20368cc72361SWai Yew CHAY 	/* Detect the card ID and configure GPIO accordingly. */
20379470195aSTakashi Iwai 	switch (hw->model) {
20389470195aSTakashi Iwai 	case CTSB055X:
20398cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x13fe);
20409470195aSTakashi Iwai 		break;
20419470195aSTakashi Iwai 	case CTSB073X:
20428cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00e6);
20439470195aSTakashi Iwai 		break;
204409521d2eSTakashi Iwai 	case CTUAA:
20458cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00c2);
20469470195aSTakashi Iwai 		break;
20479470195aSTakashi Iwai 	default:
20488cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x01e6);
20499470195aSTakashi Iwai 		break;
20508cc72361SWai Yew CHAY 	}
20518cc72361SWai Yew CHAY 
20528cc72361SWai Yew CHAY 	trn_info.vm_pgt_phys = info->vm_pgt_phys;
20538cc72361SWai Yew CHAY 	err = hw_trn_init(hw, &trn_info);
20548cc72361SWai Yew CHAY 	if (err < 0)
20558cc72361SWai Yew CHAY 		return err;
20568cc72361SWai Yew CHAY 
20578cc72361SWai Yew CHAY 	daio_info.msr = info->msr;
20588cc72361SWai Yew CHAY 	err = hw_daio_init(hw, &daio_info);
20598cc72361SWai Yew CHAY 	if (err < 0)
20608cc72361SWai Yew CHAY 		return err;
20618cc72361SWai Yew CHAY 
20628cc72361SWai Yew CHAY 	dac_info.msr = info->msr;
20638cc72361SWai Yew CHAY 	err = hw_dac_init(hw, &dac_info);
20648cc72361SWai Yew CHAY 	if (err < 0)
20658cc72361SWai Yew CHAY 		return err;
20668cc72361SWai Yew CHAY 
20678cc72361SWai Yew CHAY 	adc_info.msr = info->msr;
20688cc72361SWai Yew CHAY 	adc_info.input = ADC_LINEIN;
20698cc72361SWai Yew CHAY 	adc_info.mic20db = 0;
20708cc72361SWai Yew CHAY 	err = hw_adc_init(hw, &adc_info);
20718cc72361SWai Yew CHAY 	if (err < 0)
20728cc72361SWai Yew CHAY 		return err;
20738cc72361SWai Yew CHAY 
20748cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, SRCMCTL);
20758cc72361SWai Yew CHAY 	data |= 0x1; /* Enables input from the audio ring */
20768cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCMCTL, data);
20778cc72361SWai Yew CHAY 
20788cc72361SWai Yew CHAY 	return 0;
20798cc72361SWai Yew CHAY }
20808cc72361SWai Yew CHAY 
208129959a09SWai Yew CHAY #ifdef CONFIG_PM
208229959a09SWai Yew CHAY static int hw_suspend(struct hw *hw, pm_message_t state)
208329959a09SWai Yew CHAY {
208429959a09SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
208529959a09SWai Yew CHAY 
208629959a09SWai Yew CHAY 	hw_card_stop(hw);
208729959a09SWai Yew CHAY 
208829959a09SWai Yew CHAY 	if (hw->model == CTUAA) {
208929959a09SWai Yew CHAY 		/* Switch to UAA config space. */
209029959a09SWai Yew CHAY 		pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
209129959a09SWai Yew CHAY 	}
209229959a09SWai Yew CHAY 
209329959a09SWai Yew CHAY 	pci_disable_device(pci);
209429959a09SWai Yew CHAY 	pci_save_state(pci);
209529959a09SWai Yew CHAY 	pci_set_power_state(pci, pci_choose_state(pci, state));
209629959a09SWai Yew CHAY 
209729959a09SWai Yew CHAY 	return 0;
209829959a09SWai Yew CHAY }
209929959a09SWai Yew CHAY 
210029959a09SWai Yew CHAY static int hw_resume(struct hw *hw, struct card_conf *info)
210129959a09SWai Yew CHAY {
210229959a09SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
210329959a09SWai Yew CHAY 
210429959a09SWai Yew CHAY 	pci_set_power_state(pci, PCI_D0);
210529959a09SWai Yew CHAY 	pci_restore_state(pci);
210629959a09SWai Yew CHAY 
210729959a09SWai Yew CHAY 	/* Re-initialize card hardware. */
210829959a09SWai Yew CHAY 	return hw_card_init(hw, info);
210929959a09SWai Yew CHAY }
211029959a09SWai Yew CHAY #endif
211129959a09SWai Yew CHAY 
21128cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg)
21138cc72361SWai Yew CHAY {
21148cc72361SWai Yew CHAY 	u32 value;
21158cc72361SWai Yew CHAY 	unsigned long flags;
21168cc72361SWai Yew CHAY 
21178cc72361SWai Yew CHAY 	spin_lock_irqsave(
21188cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21198cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
21208cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x4);
21218cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21228cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21238cc72361SWai Yew CHAY 
21248cc72361SWai Yew CHAY 	return value;
21258cc72361SWai Yew CHAY }
21268cc72361SWai Yew CHAY 
21278cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
21288cc72361SWai Yew CHAY {
21298cc72361SWai Yew CHAY 	unsigned long flags;
21308cc72361SWai Yew CHAY 
21318cc72361SWai Yew CHAY 	spin_lock_irqsave(
21328cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21338cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
21348cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x4);
21358cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21368cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21378cc72361SWai Yew CHAY 
21388cc72361SWai Yew CHAY }
21398cc72361SWai Yew CHAY 
21408cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg)
21418cc72361SWai Yew CHAY {
21428cc72361SWai Yew CHAY 	u32 value;
21438cc72361SWai Yew CHAY 	unsigned long flags;
21448cc72361SWai Yew CHAY 
21458cc72361SWai Yew CHAY 	spin_lock_irqsave(
21468cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21478cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
21488cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x14);
21498cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21508cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21518cc72361SWai Yew CHAY 
21528cc72361SWai Yew CHAY 	return value;
21538cc72361SWai Yew CHAY }
21548cc72361SWai Yew CHAY 
21558cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
21568cc72361SWai Yew CHAY {
21578cc72361SWai Yew CHAY 	unsigned long flags;
21588cc72361SWai Yew CHAY 
21598cc72361SWai Yew CHAY 	spin_lock_irqsave(
21608cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21618cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
21628cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x14);
21638cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21648cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21658cc72361SWai Yew CHAY }
21668cc72361SWai Yew CHAY 
21672a36f67fSTakashi Iwai static struct hw ct20k1_preset __devinitdata = {
21682a36f67fSTakashi Iwai 	.irq = -1,
21692a36f67fSTakashi Iwai 
21702a36f67fSTakashi Iwai 	.card_init = hw_card_init,
21712a36f67fSTakashi Iwai 	.card_stop = hw_card_stop,
21722a36f67fSTakashi Iwai 	.pll_init = hw_pll_init,
21732a36f67fSTakashi Iwai 	.is_adc_source_selected = hw_is_adc_input_selected,
21742a36f67fSTakashi Iwai 	.select_adc_source = hw_adc_input_select,
21752a36f67fSTakashi Iwai 	.have_digit_io_switch = hw_have_digit_io_switch,
217629959a09SWai Yew CHAY #ifdef CONFIG_PM
217729959a09SWai Yew CHAY 	.suspend = hw_suspend,
217829959a09SWai Yew CHAY 	.resume = hw_resume,
217929959a09SWai Yew CHAY #endif
21802a36f67fSTakashi Iwai 
21812a36f67fSTakashi Iwai 	.src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
21822a36f67fSTakashi Iwai 	.src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
21832a36f67fSTakashi Iwai 	.src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
21842a36f67fSTakashi Iwai 	.src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
21852a36f67fSTakashi Iwai 	.src_set_state = src_set_state,
21862a36f67fSTakashi Iwai 	.src_set_bm = src_set_bm,
21872a36f67fSTakashi Iwai 	.src_set_rsr = src_set_rsr,
21882a36f67fSTakashi Iwai 	.src_set_sf = src_set_sf,
21892a36f67fSTakashi Iwai 	.src_set_wr = src_set_wr,
21902a36f67fSTakashi Iwai 	.src_set_pm = src_set_pm,
21912a36f67fSTakashi Iwai 	.src_set_rom = src_set_rom,
21922a36f67fSTakashi Iwai 	.src_set_vo = src_set_vo,
21932a36f67fSTakashi Iwai 	.src_set_st = src_set_st,
21942a36f67fSTakashi Iwai 	.src_set_ie = src_set_ie,
21952a36f67fSTakashi Iwai 	.src_set_ilsz = src_set_ilsz,
21962a36f67fSTakashi Iwai 	.src_set_bp = src_set_bp,
21972a36f67fSTakashi Iwai 	.src_set_cisz = src_set_cisz,
21982a36f67fSTakashi Iwai 	.src_set_ca = src_set_ca,
21992a36f67fSTakashi Iwai 	.src_set_sa = src_set_sa,
22002a36f67fSTakashi Iwai 	.src_set_la = src_set_la,
22012a36f67fSTakashi Iwai 	.src_set_pitch = src_set_pitch,
22022a36f67fSTakashi Iwai 	.src_set_dirty = src_set_dirty,
22032a36f67fSTakashi Iwai 	.src_set_clear_zbufs = src_set_clear_zbufs,
22042a36f67fSTakashi Iwai 	.src_set_dirty_all = src_set_dirty_all,
22052a36f67fSTakashi Iwai 	.src_commit_write = src_commit_write,
22062a36f67fSTakashi Iwai 	.src_get_ca = src_get_ca,
22072a36f67fSTakashi Iwai 	.src_get_dirty = src_get_dirty,
22082a36f67fSTakashi Iwai 	.src_dirty_conj_mask = src_dirty_conj_mask,
22092a36f67fSTakashi Iwai 	.src_mgr_enbs_src = src_mgr_enbs_src,
22102a36f67fSTakashi Iwai 	.src_mgr_enb_src = src_mgr_enb_src,
22112a36f67fSTakashi Iwai 	.src_mgr_dsb_src = src_mgr_dsb_src,
22122a36f67fSTakashi Iwai 	.src_mgr_commit_write = src_mgr_commit_write,
22132a36f67fSTakashi Iwai 
22142a36f67fSTakashi Iwai 	.srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
22152a36f67fSTakashi Iwai 	.srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
22162a36f67fSTakashi Iwai 	.srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
22172a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
22182a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
22192a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
22202a36f67fSTakashi Iwai 	.srcimp_mgr_commit_write = srcimp_mgr_commit_write,
22212a36f67fSTakashi Iwai 
22222a36f67fSTakashi Iwai 	.amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
22232a36f67fSTakashi Iwai 	.amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
22242a36f67fSTakashi Iwai 	.amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
22252a36f67fSTakashi Iwai 	.amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
22262a36f67fSTakashi Iwai 	.amixer_set_mode = amixer_set_mode,
22272a36f67fSTakashi Iwai 	.amixer_set_iv = amixer_set_iv,
22282a36f67fSTakashi Iwai 	.amixer_set_x = amixer_set_x,
22292a36f67fSTakashi Iwai 	.amixer_set_y = amixer_set_y,
22302a36f67fSTakashi Iwai 	.amixer_set_sadr = amixer_set_sadr,
22312a36f67fSTakashi Iwai 	.amixer_set_se = amixer_set_se,
22322a36f67fSTakashi Iwai 	.amixer_set_dirty = amixer_set_dirty,
22332a36f67fSTakashi Iwai 	.amixer_set_dirty_all = amixer_set_dirty_all,
22342a36f67fSTakashi Iwai 	.amixer_commit_write = amixer_commit_write,
22352a36f67fSTakashi Iwai 	.amixer_get_y = amixer_get_y,
22362a36f67fSTakashi Iwai 	.amixer_get_dirty = amixer_get_dirty,
22372a36f67fSTakashi Iwai 
22382a36f67fSTakashi Iwai 	.dai_get_ctrl_blk = dai_get_ctrl_blk,
22392a36f67fSTakashi Iwai 	.dai_put_ctrl_blk = dai_put_ctrl_blk,
22402a36f67fSTakashi Iwai 	.dai_srt_set_srco = dai_srt_set_srcr,
22412a36f67fSTakashi Iwai 	.dai_srt_set_srcm = dai_srt_set_srcl,
22422a36f67fSTakashi Iwai 	.dai_srt_set_rsr = dai_srt_set_rsr,
22432a36f67fSTakashi Iwai 	.dai_srt_set_drat = dai_srt_set_drat,
22442a36f67fSTakashi Iwai 	.dai_srt_set_ec = dai_srt_set_ec,
22452a36f67fSTakashi Iwai 	.dai_srt_set_et = dai_srt_set_et,
22462a36f67fSTakashi Iwai 	.dai_commit_write = dai_commit_write,
22472a36f67fSTakashi Iwai 
22482a36f67fSTakashi Iwai 	.dao_get_ctrl_blk = dao_get_ctrl_blk,
22492a36f67fSTakashi Iwai 	.dao_put_ctrl_blk = dao_put_ctrl_blk,
22502a36f67fSTakashi Iwai 	.dao_set_spos = dao_set_spos,
22512a36f67fSTakashi Iwai 	.dao_commit_write = dao_commit_write,
22522a36f67fSTakashi Iwai 	.dao_get_spos = dao_get_spos,
22532a36f67fSTakashi Iwai 
22542a36f67fSTakashi Iwai 	.daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
22552a36f67fSTakashi Iwai 	.daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
22562a36f67fSTakashi Iwai 	.daio_mgr_enb_dai = daio_mgr_enb_dai,
22572a36f67fSTakashi Iwai 	.daio_mgr_dsb_dai = daio_mgr_dsb_dai,
22582a36f67fSTakashi Iwai 	.daio_mgr_enb_dao = daio_mgr_enb_dao,
22592a36f67fSTakashi Iwai 	.daio_mgr_dsb_dao = daio_mgr_dsb_dao,
22602a36f67fSTakashi Iwai 	.daio_mgr_dao_init = daio_mgr_dao_init,
22612a36f67fSTakashi Iwai 	.daio_mgr_set_imaparc = daio_mgr_set_imaparc,
22622a36f67fSTakashi Iwai 	.daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
22632a36f67fSTakashi Iwai 	.daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
22642a36f67fSTakashi Iwai 	.daio_mgr_commit_write = daio_mgr_commit_write,
22652a36f67fSTakashi Iwai 
22662a36f67fSTakashi Iwai 	.set_timer_irq = set_timer_irq,
22672a36f67fSTakashi Iwai 	.set_timer_tick = set_timer_tick,
226854de6bc8STakashi Iwai 	.get_wc = get_wc,
22692a36f67fSTakashi Iwai };
22702a36f67fSTakashi Iwai 
22712a36f67fSTakashi Iwai int __devinit create_20k1_hw_obj(struct hw **rhw)
22728cc72361SWai Yew CHAY {
22738cc72361SWai Yew CHAY 	struct hw20k1 *hw20k1;
22748cc72361SWai Yew CHAY 
22758cc72361SWai Yew CHAY 	*rhw = NULL;
22768cc72361SWai Yew CHAY 	hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
227735ebf6e7STakashi Iwai 	if (!hw20k1)
22788cc72361SWai Yew CHAY 		return -ENOMEM;
22798cc72361SWai Yew CHAY 
22808cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_20k1_lock);
22818cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_pci_lock);
22828cc72361SWai Yew CHAY 
22832a36f67fSTakashi Iwai 	hw20k1->hw = ct20k1_preset;
22848cc72361SWai Yew CHAY 
22852a36f67fSTakashi Iwai 	*rhw = &hw20k1->hw;
22868cc72361SWai Yew CHAY 
22878cc72361SWai Yew CHAY 	return 0;
22888cc72361SWai Yew CHAY }
22898cc72361SWai Yew CHAY 
22908cc72361SWai Yew CHAY int destroy_20k1_hw_obj(struct hw *hw)
22918cc72361SWai Yew CHAY {
22928cc72361SWai Yew CHAY 	if (hw->io_base)
22938cc72361SWai Yew CHAY 		hw_card_shutdown(hw);
22948cc72361SWai Yew CHAY 
22958cc72361SWai Yew CHAY 	kfree(container_of(hw, struct hw20k1, hw));
22968cc72361SWai Yew CHAY 	return 0;
22978cc72361SWai Yew CHAY }
2298