xref: /openbmc/linux/sound/pci/ctxfi/cthw20k2.c (revision e23e7a14)
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	cthw20k2.c
98cc72361SWai Yew CHAY  *
108cc72361SWai Yew CHAY  * @Brief
1155309216SHarry Butterworth  * This file contains the implementation of hardware access method for 20k2.
128cc72361SWai Yew CHAY  *
138cc72361SWai Yew CHAY  * @Author	Liu Chun
148cc72361SWai Yew CHAY  * @Date 	May 14 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/kernel.h>
248cc72361SWai Yew CHAY #include <linux/interrupt.h>
25d0da727eSTakashi Iwai #include <linux/delay.h>
26d362af62STakashi Iwai #include "cthw20k2.h"
27d362af62STakashi Iwai #include "ct20k2reg.h"
288cc72361SWai Yew CHAY 
294836ac65STakashi Iwai #if BITS_PER_LONG == 32
304836ac65STakashi Iwai #define CT_XFI_DMA_MASK		DMA_BIT_MASK(32) /* 32 bit PTE */
314836ac65STakashi Iwai #else
324836ac65STakashi Iwai #define CT_XFI_DMA_MASK		DMA_BIT_MASK(64) /* 64 bit PTE */
334836ac65STakashi Iwai #endif
348cc72361SWai Yew CHAY 
35d362af62STakashi Iwai struct hw20k2 {
36d362af62STakashi Iwai 	struct hw hw;
37d362af62STakashi Iwai 	/* for i2c */
38d362af62STakashi Iwai 	unsigned char dev_id;
39d362af62STakashi Iwai 	unsigned char addr_size;
40d362af62STakashi Iwai 	unsigned char data_size;
4155309216SHarry Butterworth 
4255309216SHarry Butterworth 	int mic_source;
43d362af62STakashi Iwai };
44d362af62STakashi Iwai 
458cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg);
468cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
478cc72361SWai Yew CHAY 
488cc72361SWai Yew CHAY /*
498cc72361SWai Yew CHAY  * Type definition block.
508cc72361SWai Yew CHAY  * The layout of control structures can be directly applied on 20k2 chip.
518cc72361SWai Yew CHAY  */
528cc72361SWai Yew CHAY 
538cc72361SWai Yew CHAY /*
548cc72361SWai Yew CHAY  * SRC control block definitions.
558cc72361SWai Yew CHAY  */
568cc72361SWai Yew CHAY 
578cc72361SWai Yew CHAY /* SRC resource control block */
588cc72361SWai Yew CHAY #define SRCCTL_STATE	0x00000007
598cc72361SWai Yew CHAY #define SRCCTL_BM	0x00000008
608cc72361SWai Yew CHAY #define SRCCTL_RSR	0x00000030
618cc72361SWai Yew CHAY #define SRCCTL_SF	0x000001C0
628cc72361SWai Yew CHAY #define SRCCTL_WR	0x00000200
638cc72361SWai Yew CHAY #define SRCCTL_PM	0x00000400
648cc72361SWai Yew CHAY #define SRCCTL_ROM	0x00001800
658cc72361SWai Yew CHAY #define SRCCTL_VO	0x00002000
668cc72361SWai Yew CHAY #define SRCCTL_ST	0x00004000
678cc72361SWai Yew CHAY #define SRCCTL_IE	0x00008000
688cc72361SWai Yew CHAY #define SRCCTL_ILSZ	0x000F0000
698cc72361SWai Yew CHAY #define SRCCTL_BP	0x00100000
708cc72361SWai Yew CHAY 
718cc72361SWai Yew CHAY #define SRCCCR_CISZ	0x000007FF
728cc72361SWai Yew CHAY #define SRCCCR_CWA	0x001FF800
738cc72361SWai Yew CHAY #define SRCCCR_D	0x00200000
748cc72361SWai Yew CHAY #define SRCCCR_RS	0x01C00000
758cc72361SWai Yew CHAY #define SRCCCR_NAL	0x3E000000
768cc72361SWai Yew CHAY #define SRCCCR_RA	0xC0000000
778cc72361SWai Yew CHAY 
788cc72361SWai Yew CHAY #define SRCCA_CA	0x0FFFFFFF
798cc72361SWai Yew CHAY #define SRCCA_RS	0xE0000000
808cc72361SWai Yew CHAY 
818cc72361SWai Yew CHAY #define SRCSA_SA	0x0FFFFFFF
828cc72361SWai Yew CHAY 
838cc72361SWai Yew CHAY #define SRCLA_LA	0x0FFFFFFF
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 {
181514eef9cSTakashi Iwai 	kfree(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, SRC_UPZ+idx*0x100+i*0x4, 0);
3788cc72361SWai Yew CHAY 
3798cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++)
3808cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0);
3818cc72361SWai Yew CHAY 
3828cc72361SWai Yew CHAY 		for (i = 0; i < 8; i++)
3838cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRC_DN1Z+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, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr);
3948cc72361SWai Yew CHAY 		hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3);
3958cc72361SWai Yew CHAY 		hw_write_20kx(hw, MIXER_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, SRC_SA+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, SRC_LA+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, SRC_CA+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, SRC_CF+idx*0x100, 0x0);
4138cc72361SWai Yew CHAY 
4148cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ccr) {
4158cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRC_CCR+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, SRC_CTL+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, SRC_CA+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 |= (0x1 << ((idx%128)/4));
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, SRC_ENBSTAT);
4778cc72361SWai Yew CHAY 		} while (ret & 0x1);
4788cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRC_ENBSA, 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, SRC_ENB+(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 {
507514eef9cSTakashi Iwai 	kfree(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 {
528514eef9cSTakashi Iwai 	kfree(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 *)blk)->srcimap.idx = addr;
5638cc72361SWai Yew CHAY 	((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1;
5648cc72361SWai Yew CHAY 	return 0;
5658cc72361SWai Yew CHAY }
5668cc72361SWai Yew CHAY 
5678cc72361SWai Yew CHAY static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
5688cc72361SWai Yew CHAY {
5698cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5708cc72361SWai Yew CHAY 
5718cc72361SWai Yew CHAY 	if (ctl->dirty.bf.srcimap) {
5728cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100,
5738cc72361SWai Yew CHAY 						ctl->srcimap.srcaim);
5748cc72361SWai Yew CHAY 		ctl->dirty.bf.srcimap = 0;
5758cc72361SWai Yew CHAY 	}
5768cc72361SWai Yew CHAY 
5778cc72361SWai Yew CHAY 	return 0;
5788cc72361SWai Yew CHAY }
5798cc72361SWai Yew CHAY 
5808cc72361SWai Yew CHAY /*
5818cc72361SWai Yew CHAY  * AMIXER control block definitions.
5828cc72361SWai Yew CHAY  */
5838cc72361SWai Yew CHAY 
5848cc72361SWai Yew CHAY #define AMOPLO_M	0x00000003
5858cc72361SWai Yew CHAY #define AMOPLO_IV	0x00000004
5868cc72361SWai Yew CHAY #define AMOPLO_X	0x0003FFF0
5878cc72361SWai Yew CHAY #define AMOPLO_Y	0xFFFC0000
5888cc72361SWai Yew CHAY 
5898cc72361SWai Yew CHAY #define AMOPHI_SADR	0x000000FF
5908cc72361SWai Yew CHAY #define AMOPHI_SE	0x80000000
5918cc72361SWai Yew CHAY 
5928cc72361SWai Yew CHAY /* AMIXER resource register dirty flags */
5938cc72361SWai Yew CHAY union amixer_dirty {
5948cc72361SWai Yew CHAY 	struct {
5958cc72361SWai Yew CHAY 		u16 amoplo:1;
5968cc72361SWai Yew CHAY 		u16 amophi:1;
5978cc72361SWai Yew CHAY 		u16 rsv:14;
5988cc72361SWai Yew CHAY 	} bf;
5998cc72361SWai Yew CHAY 	u16 data;
6008cc72361SWai Yew CHAY };
6018cc72361SWai Yew CHAY 
6028cc72361SWai Yew CHAY /* AMIXER resource control block */
6038cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk {
6048cc72361SWai Yew CHAY 	unsigned int		amoplo;
6058cc72361SWai Yew CHAY 	unsigned int		amophi;
6068cc72361SWai Yew CHAY 	union amixer_dirty	dirty;
6078cc72361SWai Yew CHAY };
6088cc72361SWai Yew CHAY 
6098cc72361SWai Yew CHAY static int amixer_set_mode(void *blk, unsigned int mode)
6108cc72361SWai Yew CHAY {
6118cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6128cc72361SWai Yew CHAY 
6138cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_M, mode);
6148cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6158cc72361SWai Yew CHAY 	return 0;
6168cc72361SWai Yew CHAY }
6178cc72361SWai Yew CHAY 
6188cc72361SWai Yew CHAY static int amixer_set_iv(void *blk, unsigned int iv)
6198cc72361SWai Yew CHAY {
6208cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6218cc72361SWai Yew CHAY 
6228cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_IV, iv);
6238cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6248cc72361SWai Yew CHAY 	return 0;
6258cc72361SWai Yew CHAY }
6268cc72361SWai Yew CHAY 
6278cc72361SWai Yew CHAY static int amixer_set_x(void *blk, unsigned int x)
6288cc72361SWai Yew CHAY {
6298cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6308cc72361SWai Yew CHAY 
6318cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_X, x);
6328cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6338cc72361SWai Yew CHAY 	return 0;
6348cc72361SWai Yew CHAY }
6358cc72361SWai Yew CHAY 
6368cc72361SWai Yew CHAY static int amixer_set_y(void *blk, unsigned int y)
6378cc72361SWai Yew CHAY {
6388cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6398cc72361SWai Yew CHAY 
6408cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_Y, y);
6418cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6428cc72361SWai Yew CHAY 	return 0;
6438cc72361SWai Yew CHAY }
6448cc72361SWai Yew CHAY 
6458cc72361SWai Yew CHAY static int amixer_set_sadr(void *blk, unsigned int sadr)
6468cc72361SWai Yew CHAY {
6478cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6488cc72361SWai Yew CHAY 
6498cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SADR, sadr);
6508cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
6518cc72361SWai Yew CHAY 	return 0;
6528cc72361SWai Yew CHAY }
6538cc72361SWai Yew CHAY 
6548cc72361SWai Yew CHAY static int amixer_set_se(void *blk, unsigned int se)
6558cc72361SWai Yew CHAY {
6568cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6578cc72361SWai Yew CHAY 
6588cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SE, se);
6598cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
6608cc72361SWai Yew CHAY 	return 0;
6618cc72361SWai Yew CHAY }
6628cc72361SWai Yew CHAY 
6638cc72361SWai Yew CHAY static int amixer_set_dirty(void *blk, unsigned int flags)
6648cc72361SWai Yew CHAY {
6658cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
6668cc72361SWai Yew CHAY 	return 0;
6678cc72361SWai Yew CHAY }
6688cc72361SWai Yew CHAY 
6698cc72361SWai Yew CHAY static int amixer_set_dirty_all(void *blk)
6708cc72361SWai Yew CHAY {
6718cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
6728cc72361SWai Yew CHAY 	return 0;
6738cc72361SWai Yew CHAY }
6748cc72361SWai Yew CHAY 
6758cc72361SWai Yew CHAY static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
6768cc72361SWai Yew CHAY {
6778cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6788cc72361SWai Yew CHAY 
6798cc72361SWai Yew CHAY 	if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
6808cc72361SWai Yew CHAY 		hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo);
6818cc72361SWai Yew CHAY 		ctl->dirty.bf.amoplo = 0;
6828cc72361SWai Yew CHAY 		hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi);
6838cc72361SWai Yew CHAY 		ctl->dirty.bf.amophi = 0;
6848cc72361SWai Yew CHAY 	}
6858cc72361SWai Yew CHAY 
6868cc72361SWai Yew CHAY 	return 0;
6878cc72361SWai Yew CHAY }
6888cc72361SWai Yew CHAY 
6898cc72361SWai Yew CHAY static int amixer_get_y(void *blk)
6908cc72361SWai Yew CHAY {
6918cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6928cc72361SWai Yew CHAY 
6938cc72361SWai Yew CHAY 	return get_field(ctl->amoplo, AMOPLO_Y);
6948cc72361SWai Yew CHAY }
6958cc72361SWai Yew CHAY 
6968cc72361SWai Yew CHAY static unsigned int amixer_get_dirty(void *blk)
6978cc72361SWai Yew CHAY {
6988cc72361SWai Yew CHAY 	return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
6998cc72361SWai Yew CHAY }
7008cc72361SWai Yew CHAY 
7018cc72361SWai Yew CHAY static int amixer_rsc_get_ctrl_blk(void **rblk)
7028cc72361SWai Yew CHAY {
7038cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *blk;
7048cc72361SWai Yew CHAY 
7058cc72361SWai Yew CHAY 	*rblk = NULL;
7068cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
70735ebf6e7STakashi Iwai 	if (!blk)
7088cc72361SWai Yew CHAY 		return -ENOMEM;
7098cc72361SWai Yew CHAY 
7108cc72361SWai Yew CHAY 	*rblk = blk;
7118cc72361SWai Yew CHAY 
7128cc72361SWai Yew CHAY 	return 0;
7138cc72361SWai Yew CHAY }
7148cc72361SWai Yew CHAY 
7158cc72361SWai Yew CHAY static int amixer_rsc_put_ctrl_blk(void *blk)
7168cc72361SWai Yew CHAY {
717514eef9cSTakashi Iwai 	kfree(blk);
7188cc72361SWai Yew CHAY 
7198cc72361SWai Yew CHAY 	return 0;
7208cc72361SWai Yew CHAY }
7218cc72361SWai Yew CHAY 
7228cc72361SWai Yew CHAY static int amixer_mgr_get_ctrl_blk(void **rblk)
7238cc72361SWai Yew CHAY {
7248cc72361SWai Yew CHAY 	*rblk = NULL;
7258cc72361SWai Yew CHAY 
7268cc72361SWai Yew CHAY 	return 0;
7278cc72361SWai Yew CHAY }
7288cc72361SWai Yew CHAY 
7298cc72361SWai Yew CHAY static int amixer_mgr_put_ctrl_blk(void *blk)
7308cc72361SWai Yew CHAY {
7318cc72361SWai Yew CHAY 	return 0;
7328cc72361SWai Yew CHAY }
7338cc72361SWai Yew CHAY 
7348cc72361SWai Yew CHAY /*
7358cc72361SWai Yew CHAY  * DAIO control block definitions.
7368cc72361SWai Yew CHAY  */
7378cc72361SWai Yew CHAY 
7388cc72361SWai Yew CHAY /* Receiver Sample Rate Tracker Control register */
7398cc72361SWai Yew CHAY #define SRTCTL_SRCO	0x000000FF
7408cc72361SWai Yew CHAY #define SRTCTL_SRCM	0x0000FF00
7418cc72361SWai Yew CHAY #define SRTCTL_RSR	0x00030000
7428cc72361SWai Yew CHAY #define SRTCTL_DRAT	0x00300000
7438cc72361SWai Yew CHAY #define SRTCTL_EC	0x01000000
7448cc72361SWai Yew CHAY #define SRTCTL_ET	0x10000000
7458cc72361SWai Yew CHAY 
7468cc72361SWai Yew CHAY /* DAIO Receiver register dirty flags */
7478cc72361SWai Yew CHAY union dai_dirty {
7488cc72361SWai Yew CHAY 	struct {
7498cc72361SWai Yew CHAY 		u16 srt:1;
7508cc72361SWai Yew CHAY 		u16 rsv:15;
7518cc72361SWai Yew CHAY 	} bf;
7528cc72361SWai Yew CHAY 	u16 data;
7538cc72361SWai Yew CHAY };
7548cc72361SWai Yew CHAY 
7558cc72361SWai Yew CHAY /* DAIO Receiver control block */
7568cc72361SWai Yew CHAY struct dai_ctrl_blk {
7578cc72361SWai Yew CHAY 	unsigned int	srt;
7588cc72361SWai Yew CHAY 	union dai_dirty	dirty;
7598cc72361SWai Yew CHAY };
7608cc72361SWai Yew CHAY 
7618cc72361SWai Yew CHAY /* Audio Input Mapper RAM */
7628cc72361SWai Yew CHAY #define AIM_ARC		0x00000FFF
7638cc72361SWai Yew CHAY #define AIM_NXT		0x007F0000
7648cc72361SWai Yew CHAY 
7658cc72361SWai Yew CHAY struct daoimap {
7668cc72361SWai Yew CHAY 	unsigned int aim;
7678cc72361SWai Yew CHAY 	unsigned int idx;
7688cc72361SWai Yew CHAY };
7698cc72361SWai Yew CHAY 
7708cc72361SWai Yew CHAY /* Audio Transmitter Control and Status register */
7718cc72361SWai Yew CHAY #define ATXCTL_EN	0x00000001
7728cc72361SWai Yew CHAY #define ATXCTL_MODE	0x00000010
7738cc72361SWai Yew CHAY #define ATXCTL_CD	0x00000020
7748cc72361SWai Yew CHAY #define ATXCTL_RAW	0x00000100
7758cc72361SWai Yew CHAY #define ATXCTL_MT	0x00000200
7768cc72361SWai Yew CHAY #define ATXCTL_NUC	0x00003000
7778cc72361SWai Yew CHAY #define ATXCTL_BEN	0x00010000
7788cc72361SWai Yew CHAY #define ATXCTL_BMUX	0x00700000
7798cc72361SWai Yew CHAY #define ATXCTL_B24	0x01000000
7808cc72361SWai Yew CHAY #define ATXCTL_CPF	0x02000000
7818cc72361SWai Yew CHAY #define ATXCTL_RIV	0x10000000
7828cc72361SWai Yew CHAY #define ATXCTL_LIV	0x20000000
7838cc72361SWai Yew CHAY #define ATXCTL_RSAT	0x40000000
7848cc72361SWai Yew CHAY #define ATXCTL_LSAT	0x80000000
7858cc72361SWai Yew CHAY 
7868cc72361SWai Yew CHAY /* XDIF Transmitter register dirty flags */
7878cc72361SWai Yew CHAY union dao_dirty {
7888cc72361SWai Yew CHAY 	struct {
7898cc72361SWai Yew CHAY 		u16 atxcsl:1;
7908cc72361SWai Yew CHAY 		u16 rsv:15;
7918cc72361SWai Yew CHAY 	} bf;
7928cc72361SWai Yew CHAY 	u16 data;
7938cc72361SWai Yew CHAY };
7948cc72361SWai Yew CHAY 
7958cc72361SWai Yew CHAY /* XDIF Transmitter control block */
7968cc72361SWai Yew CHAY struct dao_ctrl_blk {
7978cc72361SWai Yew CHAY 	/* XDIF Transmitter Channel Status Low Register */
7988cc72361SWai Yew CHAY 	unsigned int	atxcsl;
7998cc72361SWai Yew CHAY 	union dao_dirty	dirty;
8008cc72361SWai Yew CHAY };
8018cc72361SWai Yew CHAY 
8028cc72361SWai Yew CHAY /* Audio Receiver Control register */
8038cc72361SWai Yew CHAY #define ARXCTL_EN	0x00000001
8048cc72361SWai Yew CHAY 
8058cc72361SWai Yew CHAY /* DAIO manager register dirty flags */
8068cc72361SWai Yew CHAY union daio_mgr_dirty {
8078cc72361SWai Yew CHAY 	struct {
8088cc72361SWai Yew CHAY 		u32 atxctl:8;
8098cc72361SWai Yew CHAY 		u32 arxctl:8;
8108cc72361SWai Yew CHAY 		u32 daoimap:1;
8118cc72361SWai Yew CHAY 		u32 rsv:15;
8128cc72361SWai Yew CHAY 	} bf;
8138cc72361SWai Yew CHAY 	u32 data;
8148cc72361SWai Yew CHAY };
8158cc72361SWai Yew CHAY 
8168cc72361SWai Yew CHAY /* DAIO manager control block */
8178cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk {
8188cc72361SWai Yew CHAY 	struct daoimap		daoimap;
8198cc72361SWai Yew CHAY 	unsigned int		txctl[8];
8208cc72361SWai Yew CHAY 	unsigned int		rxctl[8];
8218cc72361SWai Yew CHAY 	union daio_mgr_dirty	dirty;
8228cc72361SWai Yew CHAY };
8238cc72361SWai Yew CHAY 
8248cc72361SWai Yew CHAY static int dai_srt_set_srco(void *blk, unsigned int src)
8258cc72361SWai Yew CHAY {
8268cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8278cc72361SWai Yew CHAY 
8288cc72361SWai Yew CHAY 	set_field(&ctl->srt, SRTCTL_SRCO, src);
8298cc72361SWai Yew CHAY 	ctl->dirty.bf.srt = 1;
8308cc72361SWai Yew CHAY 	return 0;
8318cc72361SWai Yew CHAY }
8328cc72361SWai Yew CHAY 
8338cc72361SWai Yew CHAY static int dai_srt_set_srcm(void *blk, unsigned int src)
8348cc72361SWai Yew CHAY {
8358cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8368cc72361SWai Yew CHAY 
8378cc72361SWai Yew CHAY 	set_field(&ctl->srt, SRTCTL_SRCM, src);
8388cc72361SWai Yew CHAY 	ctl->dirty.bf.srt = 1;
8398cc72361SWai Yew CHAY 	return 0;
8408cc72361SWai Yew CHAY }
8418cc72361SWai Yew CHAY 
8428cc72361SWai Yew CHAY static int dai_srt_set_rsr(void *blk, unsigned int rsr)
8438cc72361SWai Yew CHAY {
8448cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8458cc72361SWai Yew CHAY 
8468cc72361SWai Yew CHAY 	set_field(&ctl->srt, SRTCTL_RSR, rsr);
8478cc72361SWai Yew CHAY 	ctl->dirty.bf.srt = 1;
8488cc72361SWai Yew CHAY 	return 0;
8498cc72361SWai Yew CHAY }
8508cc72361SWai Yew CHAY 
8518cc72361SWai Yew CHAY static int dai_srt_set_drat(void *blk, unsigned int drat)
8528cc72361SWai Yew CHAY {
8538cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8548cc72361SWai Yew CHAY 
8558cc72361SWai Yew CHAY 	set_field(&ctl->srt, SRTCTL_DRAT, drat);
8568cc72361SWai Yew CHAY 	ctl->dirty.bf.srt = 1;
8578cc72361SWai Yew CHAY 	return 0;
8588cc72361SWai Yew CHAY }
8598cc72361SWai Yew CHAY 
8608cc72361SWai Yew CHAY static int dai_srt_set_ec(void *blk, unsigned int ec)
8618cc72361SWai Yew CHAY {
8628cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8638cc72361SWai Yew CHAY 
8648cc72361SWai Yew CHAY 	set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0);
8658cc72361SWai Yew CHAY 	ctl->dirty.bf.srt = 1;
8668cc72361SWai Yew CHAY 	return 0;
8678cc72361SWai Yew CHAY }
8688cc72361SWai Yew CHAY 
8698cc72361SWai Yew CHAY static int dai_srt_set_et(void *blk, unsigned int et)
8708cc72361SWai Yew CHAY {
8718cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8728cc72361SWai Yew CHAY 
8738cc72361SWai Yew CHAY 	set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0);
8748cc72361SWai Yew CHAY 	ctl->dirty.bf.srt = 1;
8758cc72361SWai Yew CHAY 	return 0;
8768cc72361SWai Yew CHAY }
8778cc72361SWai Yew CHAY 
8788cc72361SWai Yew CHAY static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
8798cc72361SWai Yew CHAY {
8808cc72361SWai Yew CHAY 	struct dai_ctrl_blk *ctl = blk;
8818cc72361SWai Yew CHAY 
8828cc72361SWai Yew CHAY 	if (ctl->dirty.bf.srt) {
8838cc72361SWai Yew CHAY 		hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt);
8848cc72361SWai Yew CHAY 		ctl->dirty.bf.srt = 0;
8858cc72361SWai Yew CHAY 	}
8868cc72361SWai Yew CHAY 
8878cc72361SWai Yew CHAY 	return 0;
8888cc72361SWai Yew CHAY }
8898cc72361SWai Yew CHAY 
8908cc72361SWai Yew CHAY static int dai_get_ctrl_blk(void **rblk)
8918cc72361SWai Yew CHAY {
8928cc72361SWai Yew CHAY 	struct dai_ctrl_blk *blk;
8938cc72361SWai Yew CHAY 
8948cc72361SWai Yew CHAY 	*rblk = NULL;
8958cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
89635ebf6e7STakashi Iwai 	if (!blk)
8978cc72361SWai Yew CHAY 		return -ENOMEM;
8988cc72361SWai Yew CHAY 
8998cc72361SWai Yew CHAY 	*rblk = blk;
9008cc72361SWai Yew CHAY 
9018cc72361SWai Yew CHAY 	return 0;
9028cc72361SWai Yew CHAY }
9038cc72361SWai Yew CHAY 
9048cc72361SWai Yew CHAY static int dai_put_ctrl_blk(void *blk)
9058cc72361SWai Yew CHAY {
906514eef9cSTakashi Iwai 	kfree(blk);
9078cc72361SWai Yew CHAY 
9088cc72361SWai Yew CHAY 	return 0;
9098cc72361SWai Yew CHAY }
9108cc72361SWai Yew CHAY 
9118cc72361SWai Yew CHAY static int dao_set_spos(void *blk, unsigned int spos)
9128cc72361SWai Yew CHAY {
9138cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->atxcsl = spos;
9148cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1;
9158cc72361SWai Yew CHAY 	return 0;
9168cc72361SWai Yew CHAY }
9178cc72361SWai Yew CHAY 
9188cc72361SWai Yew CHAY static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
9198cc72361SWai Yew CHAY {
9208cc72361SWai Yew CHAY 	struct dao_ctrl_blk *ctl = blk;
9218cc72361SWai Yew CHAY 
9228cc72361SWai Yew CHAY 	if (ctl->dirty.bf.atxcsl) {
9238cc72361SWai Yew CHAY 		if (idx < 4) {
9248cc72361SWai Yew CHAY 			/* S/PDIF SPOSx */
9258cc72361SWai Yew CHAY 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx,
9268cc72361SWai Yew CHAY 							ctl->atxcsl);
9278cc72361SWai Yew CHAY 		}
9288cc72361SWai Yew CHAY 		ctl->dirty.bf.atxcsl = 0;
9298cc72361SWai Yew CHAY 	}
9308cc72361SWai Yew CHAY 
9318cc72361SWai Yew CHAY 	return 0;
9328cc72361SWai Yew CHAY }
9338cc72361SWai Yew CHAY 
9348cc72361SWai Yew CHAY static int dao_get_spos(void *blk, unsigned int *spos)
9358cc72361SWai Yew CHAY {
9368cc72361SWai Yew CHAY 	*spos = ((struct dao_ctrl_blk *)blk)->atxcsl;
9378cc72361SWai Yew CHAY 	return 0;
9388cc72361SWai Yew CHAY }
9398cc72361SWai Yew CHAY 
9408cc72361SWai Yew CHAY static int dao_get_ctrl_blk(void **rblk)
9418cc72361SWai Yew CHAY {
9428cc72361SWai Yew CHAY 	struct dao_ctrl_blk *blk;
9438cc72361SWai Yew CHAY 
9448cc72361SWai Yew CHAY 	*rblk = NULL;
9458cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
94635ebf6e7STakashi Iwai 	if (!blk)
9478cc72361SWai Yew CHAY 		return -ENOMEM;
9488cc72361SWai Yew CHAY 
9498cc72361SWai Yew CHAY 	*rblk = blk;
9508cc72361SWai Yew CHAY 
9518cc72361SWai Yew CHAY 	return 0;
9528cc72361SWai Yew CHAY }
9538cc72361SWai Yew CHAY 
9548cc72361SWai Yew CHAY static int dao_put_ctrl_blk(void *blk)
9558cc72361SWai Yew CHAY {
956514eef9cSTakashi Iwai 	kfree(blk);
9578cc72361SWai Yew CHAY 
9588cc72361SWai Yew CHAY 	return 0;
9598cc72361SWai Yew CHAY }
9608cc72361SWai Yew CHAY 
9618cc72361SWai Yew CHAY static int daio_mgr_enb_dai(void *blk, unsigned int idx)
9628cc72361SWai Yew CHAY {
9638cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9648cc72361SWai Yew CHAY 
9658cc72361SWai Yew CHAY 	set_field(&ctl->rxctl[idx], ARXCTL_EN, 1);
9668cc72361SWai Yew CHAY 	ctl->dirty.bf.arxctl |= (0x1 << idx);
9678cc72361SWai Yew CHAY 	return 0;
9688cc72361SWai Yew CHAY }
9698cc72361SWai Yew CHAY 
9708cc72361SWai Yew CHAY static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
9718cc72361SWai Yew CHAY {
9728cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9738cc72361SWai Yew CHAY 
9748cc72361SWai Yew CHAY 	set_field(&ctl->rxctl[idx], ARXCTL_EN, 0);
9758cc72361SWai Yew CHAY 
9768cc72361SWai Yew CHAY 	ctl->dirty.bf.arxctl |= (0x1 << idx);
9778cc72361SWai Yew CHAY 	return 0;
9788cc72361SWai Yew CHAY }
9798cc72361SWai Yew CHAY 
9808cc72361SWai Yew CHAY static int daio_mgr_enb_dao(void *blk, unsigned int idx)
9818cc72361SWai Yew CHAY {
9828cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9838cc72361SWai Yew CHAY 
9848cc72361SWai Yew CHAY 	set_field(&ctl->txctl[idx], ATXCTL_EN, 1);
9858cc72361SWai Yew CHAY 	ctl->dirty.bf.atxctl |= (0x1 << idx);
9868cc72361SWai Yew CHAY 	return 0;
9878cc72361SWai Yew CHAY }
9888cc72361SWai Yew CHAY 
9898cc72361SWai Yew CHAY static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
9908cc72361SWai Yew CHAY {
9918cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9928cc72361SWai Yew CHAY 
9938cc72361SWai Yew CHAY 	set_field(&ctl->txctl[idx], ATXCTL_EN, 0);
9948cc72361SWai Yew CHAY 	ctl->dirty.bf.atxctl |= (0x1 << idx);
9958cc72361SWai Yew CHAY 	return 0;
9968cc72361SWai Yew CHAY }
9978cc72361SWai Yew CHAY 
9988cc72361SWai Yew CHAY static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
9998cc72361SWai Yew CHAY {
10008cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10018cc72361SWai Yew CHAY 
10028cc72361SWai Yew CHAY 	if (idx < 4) {
10038cc72361SWai Yew CHAY 		/* S/PDIF output */
10048cc72361SWai Yew CHAY 		switch ((conf & 0x7)) {
10058cc72361SWai Yew CHAY 		case 1:
10068cc72361SWai Yew CHAY 			set_field(&ctl->txctl[idx], ATXCTL_NUC, 0);
10078cc72361SWai Yew CHAY 			break;
10088cc72361SWai Yew CHAY 		case 2:
10098cc72361SWai Yew CHAY 			set_field(&ctl->txctl[idx], ATXCTL_NUC, 1);
10108cc72361SWai Yew CHAY 			break;
10118cc72361SWai Yew CHAY 		case 4:
10128cc72361SWai Yew CHAY 			set_field(&ctl->txctl[idx], ATXCTL_NUC, 2);
10138cc72361SWai Yew CHAY 			break;
10148cc72361SWai Yew CHAY 		case 8:
10158cc72361SWai Yew CHAY 			set_field(&ctl->txctl[idx], ATXCTL_NUC, 3);
10168cc72361SWai Yew CHAY 			break;
10178cc72361SWai Yew CHAY 		default:
10188cc72361SWai Yew CHAY 			break;
10198cc72361SWai Yew CHAY 		}
10208cc72361SWai Yew CHAY 		/* CDIF */
10218cc72361SWai Yew CHAY 		set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7)));
10228cc72361SWai Yew CHAY 		/* Non-audio */
10238cc72361SWai Yew CHAY 		set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1);
10248cc72361SWai Yew CHAY 		/* Non-audio */
10258cc72361SWai Yew CHAY 		set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1);
10268cc72361SWai Yew CHAY 		set_field(&ctl->txctl[idx], ATXCTL_RAW,
10278cc72361SWai Yew CHAY 			  ((conf >> 3) & 0x1) ? 0 : 0);
10288cc72361SWai Yew CHAY 		ctl->dirty.bf.atxctl |= (0x1 << idx);
10298cc72361SWai Yew CHAY 	} else {
10308cc72361SWai Yew CHAY 		/* I2S output */
10318cc72361SWai Yew CHAY 		/*idx %= 4; */
10328cc72361SWai Yew CHAY 	}
10338cc72361SWai Yew CHAY 	return 0;
10348cc72361SWai Yew CHAY }
10358cc72361SWai Yew CHAY 
10368cc72361SWai Yew CHAY static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
10378cc72361SWai Yew CHAY {
10388cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10398cc72361SWai Yew CHAY 
10408cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_ARC, slot);
10418cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
10428cc72361SWai Yew CHAY 	return 0;
10438cc72361SWai Yew CHAY }
10448cc72361SWai Yew CHAY 
10458cc72361SWai Yew CHAY static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
10468cc72361SWai Yew CHAY {
10478cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10488cc72361SWai Yew CHAY 
10498cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_NXT, next);
10508cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
10518cc72361SWai Yew CHAY 	return 0;
10528cc72361SWai Yew CHAY }
10538cc72361SWai Yew CHAY 
10548cc72361SWai Yew CHAY static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
10558cc72361SWai Yew CHAY {
10568cc72361SWai Yew CHAY 	((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr;
10578cc72361SWai Yew CHAY 	((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1;
10588cc72361SWai Yew CHAY 	return 0;
10598cc72361SWai Yew CHAY }
10608cc72361SWai Yew CHAY 
10618cc72361SWai Yew CHAY static int daio_mgr_commit_write(struct hw *hw, void *blk)
10628cc72361SWai Yew CHAY {
10638cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1064514eef9cSTakashi Iwai 	unsigned int data;
1065514eef9cSTakashi Iwai 	int i;
10668cc72361SWai Yew CHAY 
10678cc72361SWai Yew CHAY 	for (i = 0; i < 8; i++) {
10688cc72361SWai Yew CHAY 		if ((ctl->dirty.bf.atxctl & (0x1 << i))) {
10698cc72361SWai Yew CHAY 			data = ctl->txctl[i];
10708cc72361SWai Yew CHAY 			hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
10718cc72361SWai Yew CHAY 			ctl->dirty.bf.atxctl &= ~(0x1 << i);
10728cc72361SWai Yew CHAY 			mdelay(1);
10738cc72361SWai Yew CHAY 		}
10748cc72361SWai Yew CHAY 		if ((ctl->dirty.bf.arxctl & (0x1 << i))) {
10758cc72361SWai Yew CHAY 			data = ctl->rxctl[i];
10768cc72361SWai Yew CHAY 			hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
10778cc72361SWai Yew CHAY 			ctl->dirty.bf.arxctl &= ~(0x1 << i);
10788cc72361SWai Yew CHAY 			mdelay(1);
10798cc72361SWai Yew CHAY 		}
10808cc72361SWai Yew CHAY 	}
10818cc72361SWai Yew CHAY 	if (ctl->dirty.bf.daoimap) {
10828cc72361SWai Yew CHAY 		hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4,
10838cc72361SWai Yew CHAY 						ctl->daoimap.aim);
10848cc72361SWai Yew CHAY 		ctl->dirty.bf.daoimap = 0;
10858cc72361SWai Yew CHAY 	}
10868cc72361SWai Yew CHAY 
10878cc72361SWai Yew CHAY 	return 0;
10888cc72361SWai Yew CHAY }
10898cc72361SWai Yew CHAY 
10908cc72361SWai Yew CHAY static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
10918cc72361SWai Yew CHAY {
10928cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *blk;
1093514eef9cSTakashi Iwai 	int i;
10948cc72361SWai Yew CHAY 
10958cc72361SWai Yew CHAY 	*rblk = NULL;
10968cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
109735ebf6e7STakashi Iwai 	if (!blk)
10988cc72361SWai Yew CHAY 		return -ENOMEM;
10998cc72361SWai Yew CHAY 
11008cc72361SWai Yew CHAY 	for (i = 0; i < 8; i++) {
11018cc72361SWai Yew CHAY 		blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i));
11028cc72361SWai Yew CHAY 		blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i));
11038cc72361SWai Yew CHAY 	}
11048cc72361SWai Yew CHAY 
11058cc72361SWai Yew CHAY 	*rblk = blk;
11068cc72361SWai Yew CHAY 
11078cc72361SWai Yew CHAY 	return 0;
11088cc72361SWai Yew CHAY }
11098cc72361SWai Yew CHAY 
11108cc72361SWai Yew CHAY static int daio_mgr_put_ctrl_blk(void *blk)
11118cc72361SWai Yew CHAY {
1112514eef9cSTakashi Iwai 	kfree(blk);
11138cc72361SWai Yew CHAY 
11148cc72361SWai Yew CHAY 	return 0;
11158cc72361SWai Yew CHAY }
11168cc72361SWai Yew CHAY 
1117bc5304b6STakashi Iwai /* Timer interrupt */
1118bc5304b6STakashi Iwai static int set_timer_irq(struct hw *hw, int enable)
1119bc5304b6STakashi Iwai {
1120bc5304b6STakashi Iwai 	hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
1121bc5304b6STakashi Iwai 	return 0;
1122bc5304b6STakashi Iwai }
1123bc5304b6STakashi Iwai 
1124bc5304b6STakashi Iwai static int set_timer_tick(struct hw *hw, unsigned int ticks)
1125bc5304b6STakashi Iwai {
1126bc5304b6STakashi Iwai 	if (ticks)
1127bc5304b6STakashi Iwai 		ticks |= TIMR_IE | TIMR_IP;
1128bc5304b6STakashi Iwai 	hw_write_20kx(hw, TIMR, ticks);
1129bc5304b6STakashi Iwai 	return 0;
1130bc5304b6STakashi Iwai }
1131bc5304b6STakashi Iwai 
1132bc5304b6STakashi Iwai static unsigned int get_wc(struct hw *hw)
1133bc5304b6STakashi Iwai {
1134bc5304b6STakashi Iwai 	return hw_read_20kx(hw, WC);
1135bc5304b6STakashi Iwai }
1136bc5304b6STakashi Iwai 
11378cc72361SWai Yew CHAY /* Card hardware initialization block */
11388cc72361SWai Yew CHAY struct dac_conf {
11398cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
11408cc72361SWai Yew CHAY };
11418cc72361SWai Yew CHAY 
11428cc72361SWai Yew CHAY struct adc_conf {
11438cc72361SWai Yew CHAY 	unsigned int msr; 	/* master sample rate in rsrs */
11448cc72361SWai Yew CHAY 	unsigned char input; 	/* the input source of ADC */
11458cc72361SWai Yew CHAY 	unsigned char mic20db; 	/* boost mic by 20db if input is microphone */
11468cc72361SWai Yew CHAY };
11478cc72361SWai Yew CHAY 
11488cc72361SWai Yew CHAY struct daio_conf {
11498cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
11508cc72361SWai Yew CHAY };
11518cc72361SWai Yew CHAY 
11528cc72361SWai Yew CHAY struct trn_conf {
11538cc72361SWai Yew CHAY 	unsigned long vm_pgt_phys;
11548cc72361SWai Yew CHAY };
11558cc72361SWai Yew CHAY 
11568cc72361SWai Yew CHAY static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
11578cc72361SWai Yew CHAY {
1158d362af62STakashi Iwai 	u32 data;
11598cc72361SWai Yew CHAY 	int i;
11608cc72361SWai Yew CHAY 
11618cc72361SWai Yew CHAY 	/* Program I2S with proper sample rate and enable the correct I2S
11628cc72361SWai Yew CHAY 	 * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */
11638cc72361SWai Yew CHAY 	if (1 == info->msr) {
11648cc72361SWai Yew CHAY 		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101);
11658cc72361SWai Yew CHAY 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
11668cc72361SWai Yew CHAY 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
11678cc72361SWai Yew CHAY 	} else if (2 == info->msr) {
116855309216SHarry Butterworth 		if (hw->model != CTSB1270) {
11698cc72361SWai Yew CHAY 			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
117055309216SHarry Butterworth 		} else {
117155309216SHarry Butterworth 			/* PCM4220 on Titanium HD is different. */
117255309216SHarry Butterworth 			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111);
117355309216SHarry Butterworth 		}
11748cc72361SWai Yew CHAY 		/* Specify all playing 96khz
11758cc72361SWai Yew CHAY 		 * EA [0]	- Enabled
11768cc72361SWai Yew CHAY 		 * RTA [4:5]	- 96kHz
11778cc72361SWai Yew CHAY 		 * EB [8]	- Enabled
11788cc72361SWai Yew CHAY 		 * RTB [12:13]	- 96kHz
11798cc72361SWai Yew CHAY 		 * EC [16]	- Enabled
11808cc72361SWai Yew CHAY 		 * RTC [20:21]	- 96kHz
11818cc72361SWai Yew CHAY 		 * ED [24]	- Enabled
11828cc72361SWai Yew CHAY 		 * RTD [28:29]	- 96kHz */
11838cc72361SWai Yew CHAY 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
11848cc72361SWai Yew CHAY 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
118555309216SHarry Butterworth 	} else if ((4 == info->msr) && (hw->model == CTSB1270)) {
118655309216SHarry Butterworth 		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
118755309216SHarry Butterworth 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
118855309216SHarry Butterworth 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
11898cc72361SWai Yew CHAY 	} else {
1190b3e0afe6STakashi Iwai 		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
11918cc72361SWai Yew CHAY 		return -EINVAL;
11928cc72361SWai Yew CHAY 	}
11938cc72361SWai Yew CHAY 
11948cc72361SWai Yew CHAY 	for (i = 0; i < 8; i++) {
11958cc72361SWai Yew CHAY 		if (i <= 3) {
119655309216SHarry Butterworth 			/* This comment looks wrong since loop is over 4  */
119755309216SHarry Butterworth 			/* channels and emu20k2 supports 4 spdif IOs.     */
11988cc72361SWai Yew CHAY 			/* 1st 3 channels are SPDIFs (SB0960) */
11998cc72361SWai Yew CHAY 			if (i == 3)
1200d362af62STakashi Iwai 				data = 0x1001001;
12018cc72361SWai Yew CHAY 			else
1202d362af62STakashi Iwai 				data = 0x1000001;
12038cc72361SWai Yew CHAY 
1204d362af62STakashi Iwai 			hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
1205d362af62STakashi Iwai 			hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
12068cc72361SWai Yew CHAY 
12078cc72361SWai Yew CHAY 			/* Initialize the SPDIF Out Channel status registers.
12088cc72361SWai Yew CHAY 			 * The value specified here is based on the typical
12098cc72361SWai Yew CHAY 			 * values provided in the specification, namely: Clock
12108cc72361SWai Yew CHAY 			 * Accuracy of 1000ppm, Sample Rate of 48KHz,
12118cc72361SWai Yew CHAY 			 * unspecified source number, Generation status = 1,
12128cc72361SWai Yew CHAY 			 * Category code = 0x12 (Digital Signal Mixer),
12138cc72361SWai Yew CHAY 			 * Mode = 0, Emph = 0, Copy Permitted, AN = 0
12148cc72361SWai Yew CHAY 			 * (indicating that we're transmitting digital audio,
12158cc72361SWai Yew CHAY 			 * and the Professional Use bit is 0. */
12168cc72361SWai Yew CHAY 
12178cc72361SWai Yew CHAY 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i),
12188cc72361SWai Yew CHAY 					0x02109204); /* Default to 48kHz */
12198cc72361SWai Yew CHAY 
12208cc72361SWai Yew CHAY 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
12218cc72361SWai Yew CHAY 		} else {
122255309216SHarry Butterworth 			/* Again, loop is over 4 channels not 5. */
12238cc72361SWai Yew CHAY 			/* Next 5 channels are I2S (SB0960) */
1224d362af62STakashi Iwai 			data = 0x11;
1225d362af62STakashi Iwai 			hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
12268cc72361SWai Yew CHAY 			if (2 == info->msr) {
12278cc72361SWai Yew CHAY 				/* Four channels per sample period */
1228d362af62STakashi Iwai 				data |= 0x1000;
122955309216SHarry Butterworth 			} else if (4 == info->msr) {
123055309216SHarry Butterworth 				/* FIXME: check this against the chip spec */
123155309216SHarry Butterworth 				data |= 0x2000;
12328cc72361SWai Yew CHAY 			}
1233d362af62STakashi Iwai 			hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
12348cc72361SWai Yew CHAY 		}
12358cc72361SWai Yew CHAY 	}
12368cc72361SWai Yew CHAY 
12378cc72361SWai Yew CHAY 	return 0;
12388cc72361SWai Yew CHAY }
12398cc72361SWai Yew CHAY 
12408cc72361SWai Yew CHAY /* TRANSPORT operations */
12418cc72361SWai Yew CHAY static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
12428cc72361SWai Yew CHAY {
1243514eef9cSTakashi Iwai 	u32 vmctl, data;
1244514eef9cSTakashi Iwai 	u32 ptp_phys_low, ptp_phys_high;
1245514eef9cSTakashi Iwai 	int i;
12468cc72361SWai Yew CHAY 
12478cc72361SWai Yew CHAY 	/* Set up device page table */
12488cc72361SWai Yew CHAY 	if ((~0UL) == info->vm_pgt_phys) {
1249b3e0afe6STakashi Iwai 		printk(KERN_ALERT "ctxfi: "
1250b3e0afe6STakashi Iwai 		       "Wrong device page table page address!!!\n");
12518cc72361SWai Yew CHAY 		return -1;
12528cc72361SWai Yew CHAY 	}
12538cc72361SWai Yew CHAY 
12548cc72361SWai Yew CHAY 	vmctl = 0x80000C0F;  /* 32-bit, 4k-size page */
1255cd391e20STakashi Iwai 	ptp_phys_low = (u32)info->vm_pgt_phys;
1256cd391e20STakashi Iwai 	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
1257cd391e20STakashi Iwai 	if (sizeof(void *) == 8) /* 64bit address */
12588cc72361SWai Yew CHAY 		vmctl |= (3 << 8);
12598cc72361SWai Yew CHAY 	/* Write page table physical address to all PTPAL registers */
12608cc72361SWai Yew CHAY 	for (i = 0; i < 64; i++) {
12618cc72361SWai Yew CHAY 		hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low);
12628cc72361SWai Yew CHAY 		hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high);
12638cc72361SWai Yew CHAY 	}
12648cc72361SWai Yew CHAY 	/* Enable virtual memory transfer */
12658cc72361SWai Yew CHAY 	hw_write_20kx(hw, VMEM_CTL, vmctl);
12668cc72361SWai Yew CHAY 	/* Enable transport bus master and queueing of request */
12678cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRANSPORT_CTL, 0x03);
12688cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRANSPORT_INT, 0x200c01);
12698cc72361SWai Yew CHAY 	/* Enable transport ring */
12708cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, TRANSPORT_ENB);
12718cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03));
12728cc72361SWai Yew CHAY 
12738cc72361SWai Yew CHAY 	return 0;
12748cc72361SWai Yew CHAY }
12758cc72361SWai Yew CHAY 
12768cc72361SWai Yew CHAY /* Card initialization */
12778cc72361SWai Yew CHAY #define GCTL_AIE	0x00000001
12788cc72361SWai Yew CHAY #define GCTL_UAA	0x00000002
12798cc72361SWai Yew CHAY #define GCTL_DPC	0x00000004
12808cc72361SWai Yew CHAY #define GCTL_DBP	0x00000008
12818cc72361SWai Yew CHAY #define GCTL_ABP	0x00000010
12828cc72361SWai Yew CHAY #define GCTL_TBP	0x00000020
12838cc72361SWai Yew CHAY #define GCTL_SBP	0x00000040
12848cc72361SWai Yew CHAY #define GCTL_FBP	0x00000080
12858cc72361SWai Yew CHAY #define GCTL_ME		0x00000100
12868cc72361SWai Yew CHAY #define GCTL_AID	0x00001000
12878cc72361SWai Yew CHAY 
12888cc72361SWai Yew CHAY #define PLLCTL_SRC	0x00000007
12898cc72361SWai Yew CHAY #define PLLCTL_SPE	0x00000008
12908cc72361SWai Yew CHAY #define PLLCTL_RD	0x000000F0
12918cc72361SWai Yew CHAY #define PLLCTL_FD	0x0001FF00
12928cc72361SWai Yew CHAY #define PLLCTL_OD	0x00060000
12938cc72361SWai Yew CHAY #define PLLCTL_B	0x00080000
12948cc72361SWai Yew CHAY #define PLLCTL_AS	0x00100000
12958cc72361SWai Yew CHAY #define PLLCTL_LF	0x03E00000
12968cc72361SWai Yew CHAY #define PLLCTL_SPS	0x1C000000
12978cc72361SWai Yew CHAY #define PLLCTL_AD	0x60000000
12988cc72361SWai Yew CHAY 
12998cc72361SWai Yew CHAY #define PLLSTAT_CCS	0x00000007
13008cc72361SWai Yew CHAY #define PLLSTAT_SPL	0x00000008
13018cc72361SWai Yew CHAY #define PLLSTAT_CRD	0x000000F0
13028cc72361SWai Yew CHAY #define PLLSTAT_CFD	0x0001FF00
13038cc72361SWai Yew CHAY #define PLLSTAT_SL	0x00020000
13048cc72361SWai Yew CHAY #define PLLSTAT_FAS	0x00040000
13058cc72361SWai Yew CHAY #define PLLSTAT_B	0x00080000
13068cc72361SWai Yew CHAY #define PLLSTAT_PD	0x00100000
13078cc72361SWai Yew CHAY #define PLLSTAT_OCA	0x00200000
13088cc72361SWai Yew CHAY #define PLLSTAT_NCA	0x00400000
13098cc72361SWai Yew CHAY 
13108cc72361SWai Yew CHAY static int hw_pll_init(struct hw *hw, unsigned int rsr)
13118cc72361SWai Yew CHAY {
13128cc72361SWai Yew CHAY 	unsigned int pllenb;
13138cc72361SWai Yew CHAY 	unsigned int pllctl;
13148cc72361SWai Yew CHAY 	unsigned int pllstat;
13158cc72361SWai Yew CHAY 	int i;
13168cc72361SWai Yew CHAY 
13178cc72361SWai Yew CHAY 	pllenb = 0xB;
13188cc72361SWai Yew CHAY 	hw_write_20kx(hw, PLL_ENB, pllenb);
1319030aba53SHarry Butterworth 	pllctl = 0x20C00000;
13208cc72361SWai Yew CHAY 	set_field(&pllctl, PLLCTL_B, 0);
1321030aba53SHarry Butterworth 	set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4);
1322030aba53SHarry Butterworth 	set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1);
13238cc72361SWai Yew CHAY 	hw_write_20kx(hw, PLL_CTL, pllctl);
13248cc72361SWai Yew CHAY 	mdelay(40);
1325030aba53SHarry Butterworth 
1326030aba53SHarry Butterworth 	pllctl = hw_read_20kx(hw, PLL_CTL);
1327030aba53SHarry Butterworth 	set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2);
1328030aba53SHarry Butterworth 	hw_write_20kx(hw, PLL_CTL, pllctl);
1329030aba53SHarry Butterworth 	mdelay(40);
1330030aba53SHarry Butterworth 
13318cc72361SWai Yew CHAY 	for (i = 0; i < 1000; i++) {
13328cc72361SWai Yew CHAY 		pllstat = hw_read_20kx(hw, PLL_STAT);
13338cc72361SWai Yew CHAY 		if (get_field(pllstat, PLLSTAT_PD))
13348cc72361SWai Yew CHAY 			continue;
13358cc72361SWai Yew CHAY 
13368cc72361SWai Yew CHAY 		if (get_field(pllstat, PLLSTAT_B) !=
13378cc72361SWai Yew CHAY 					get_field(pllctl, PLLCTL_B))
13388cc72361SWai Yew CHAY 			continue;
13398cc72361SWai Yew CHAY 
13408cc72361SWai Yew CHAY 		if (get_field(pllstat, PLLSTAT_CCS) !=
13418cc72361SWai Yew CHAY 					get_field(pllctl, PLLCTL_SRC))
13428cc72361SWai Yew CHAY 			continue;
13438cc72361SWai Yew CHAY 
13448cc72361SWai Yew CHAY 		if (get_field(pllstat, PLLSTAT_CRD) !=
13458cc72361SWai Yew CHAY 					get_field(pllctl, PLLCTL_RD))
13468cc72361SWai Yew CHAY 			continue;
13478cc72361SWai Yew CHAY 
13488cc72361SWai Yew CHAY 		if (get_field(pllstat, PLLSTAT_CFD) !=
13498cc72361SWai Yew CHAY 					get_field(pllctl, PLLCTL_FD))
13508cc72361SWai Yew CHAY 			continue;
13518cc72361SWai Yew CHAY 
13528cc72361SWai Yew CHAY 		break;
13538cc72361SWai Yew CHAY 	}
13548cc72361SWai Yew CHAY 	if (i >= 1000) {
1355b3e0afe6STakashi Iwai 		printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
13568cc72361SWai Yew CHAY 		return -EBUSY;
13578cc72361SWai Yew CHAY 	}
13588cc72361SWai Yew CHAY 
13598cc72361SWai Yew CHAY 	return 0;
13608cc72361SWai Yew CHAY }
13618cc72361SWai Yew CHAY 
13628cc72361SWai Yew CHAY static int hw_auto_init(struct hw *hw)
13638cc72361SWai Yew CHAY {
13648cc72361SWai Yew CHAY 	unsigned int gctl;
13658cc72361SWai Yew CHAY 	int i;
13668cc72361SWai Yew CHAY 
13678cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
13688cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_AIE, 0);
13698cc72361SWai Yew CHAY 	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
13708cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_AIE, 1);
13718cc72361SWai Yew CHAY 	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
13728cc72361SWai Yew CHAY 	mdelay(10);
13738cc72361SWai Yew CHAY 	for (i = 0; i < 400000; i++) {
13748cc72361SWai Yew CHAY 		gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
13758cc72361SWai Yew CHAY 		if (get_field(gctl, GCTL_AID))
13768cc72361SWai Yew CHAY 			break;
13778cc72361SWai Yew CHAY 	}
13788cc72361SWai Yew CHAY 	if (!get_field(gctl, GCTL_AID)) {
1379b3e0afe6STakashi Iwai 		printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n");
13808cc72361SWai Yew CHAY 		return -EBUSY;
13818cc72361SWai Yew CHAY 	}
13828cc72361SWai Yew CHAY 
13838cc72361SWai Yew CHAY 	return 0;
13848cc72361SWai Yew CHAY }
13858cc72361SWai Yew CHAY 
13868cc72361SWai Yew CHAY /* DAC operations */
13878cc72361SWai Yew CHAY 
13888cc72361SWai Yew CHAY #define CS4382_MC1 		0x1
13898cc72361SWai Yew CHAY #define CS4382_MC2 		0x2
13908cc72361SWai Yew CHAY #define CS4382_MC3		0x3
13918cc72361SWai Yew CHAY #define CS4382_FC		0x4
13928cc72361SWai Yew CHAY #define CS4382_IC		0x5
13938cc72361SWai Yew CHAY #define CS4382_XC1		0x6
13948cc72361SWai Yew CHAY #define CS4382_VCA1 		0x7
13958cc72361SWai Yew CHAY #define CS4382_VCB1 		0x8
13968cc72361SWai Yew CHAY #define CS4382_XC2		0x9
13978cc72361SWai Yew CHAY #define CS4382_VCA2 		0xA
13988cc72361SWai Yew CHAY #define CS4382_VCB2 		0xB
13998cc72361SWai Yew CHAY #define CS4382_XC3		0xC
14008cc72361SWai Yew CHAY #define CS4382_VCA3		0xD
14018cc72361SWai Yew CHAY #define CS4382_VCB3		0xE
14028cc72361SWai Yew CHAY #define CS4382_XC4 		0xF
14038cc72361SWai Yew CHAY #define CS4382_VCA4 		0x10
14048cc72361SWai Yew CHAY #define CS4382_VCB4 		0x11
14058cc72361SWai Yew CHAY #define CS4382_CREV 		0x12
14068cc72361SWai Yew CHAY 
14078cc72361SWai Yew CHAY /* I2C status */
14088cc72361SWai Yew CHAY #define STATE_LOCKED		0x00
14098cc72361SWai Yew CHAY #define STATE_UNLOCKED		0xAA
14108cc72361SWai Yew CHAY #define DATA_READY		0x800000    /* Used with I2C_IF_STATUS */
14118cc72361SWai Yew CHAY #define DATA_ABORT		0x10000     /* Used with I2C_IF_STATUS */
14128cc72361SWai Yew CHAY 
14138cc72361SWai Yew CHAY #define I2C_STATUS_DCM	0x00000001
14148cc72361SWai Yew CHAY #define I2C_STATUS_BC	0x00000006
14158cc72361SWai Yew CHAY #define I2C_STATUS_APD	0x00000008
14168cc72361SWai Yew CHAY #define I2C_STATUS_AB	0x00010000
14178cc72361SWai Yew CHAY #define I2C_STATUS_DR	0x00800000
14188cc72361SWai Yew CHAY 
14198cc72361SWai Yew CHAY #define I2C_ADDRESS_PTAD	0x0000FFFF
14208cc72361SWai Yew CHAY #define I2C_ADDRESS_SLAD	0x007F0000
14218cc72361SWai Yew CHAY 
1422d362af62STakashi Iwai struct regs_cs4382 {
1423d362af62STakashi Iwai 	u32 mode_control_1;
1424d362af62STakashi Iwai 	u32 mode_control_2;
1425d362af62STakashi Iwai 	u32 mode_control_3;
14268cc72361SWai Yew CHAY 
1427d362af62STakashi Iwai 	u32 filter_control;
1428d362af62STakashi Iwai 	u32 invert_control;
14298cc72361SWai Yew CHAY 
1430d362af62STakashi Iwai 	u32 mix_control_P1;
1431d362af62STakashi Iwai 	u32 vol_control_A1;
1432d362af62STakashi Iwai 	u32 vol_control_B1;
14338cc72361SWai Yew CHAY 
1434d362af62STakashi Iwai 	u32 mix_control_P2;
1435d362af62STakashi Iwai 	u32 vol_control_A2;
1436d362af62STakashi Iwai 	u32 vol_control_B2;
14378cc72361SWai Yew CHAY 
1438d362af62STakashi Iwai 	u32 mix_control_P3;
1439d362af62STakashi Iwai 	u32 vol_control_A3;
1440d362af62STakashi Iwai 	u32 vol_control_B3;
14418cc72361SWai Yew CHAY 
1442d362af62STakashi Iwai 	u32 mix_control_P4;
1443d362af62STakashi Iwai 	u32 vol_control_A4;
1444d362af62STakashi Iwai 	u32 vol_control_B4;
14458cc72361SWai Yew CHAY };
14468cc72361SWai Yew CHAY 
1447d362af62STakashi Iwai static int hw20k2_i2c_unlock_full_access(struct hw *hw)
14488cc72361SWai Yew CHAY {
14498cc72361SWai Yew CHAY 	u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] =  {0xB3, 0xD4};
14508cc72361SWai Yew CHAY 
14518cc72361SWai Yew CHAY 	/* Send keys for forced BIOS mode */
14528cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2C_IF_WLOCK,
14538cc72361SWai Yew CHAY 			UnlockKeySequence_FLASH_FULLACCESS_MODE[0]);
14548cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2C_IF_WLOCK,
14558cc72361SWai Yew CHAY 			UnlockKeySequence_FLASH_FULLACCESS_MODE[1]);
14568cc72361SWai Yew CHAY 	/* Check whether the chip is unlocked */
14578cc72361SWai Yew CHAY 	if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED)
14588cc72361SWai Yew CHAY 		return 0;
14598cc72361SWai Yew CHAY 
14608cc72361SWai Yew CHAY 	return -1;
14618cc72361SWai Yew CHAY }
14628cc72361SWai Yew CHAY 
1463d362af62STakashi Iwai static int hw20k2_i2c_lock_chip(struct hw *hw)
14648cc72361SWai Yew CHAY {
14658cc72361SWai Yew CHAY 	/* Write twice */
14668cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
14678cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
14688cc72361SWai Yew CHAY 	if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED)
14698cc72361SWai Yew CHAY 		return 0;
14708cc72361SWai Yew CHAY 
14718cc72361SWai Yew CHAY 	return -1;
14728cc72361SWai Yew CHAY }
14738cc72361SWai Yew CHAY 
1474d362af62STakashi Iwai static int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size)
14758cc72361SWai Yew CHAY {
1476d362af62STakashi Iwai 	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
1477514eef9cSTakashi Iwai 	int err;
1478d362af62STakashi Iwai 	unsigned int i2c_status;
1479d362af62STakashi Iwai 	unsigned int i2c_addr;
14808cc72361SWai Yew CHAY 
1481d362af62STakashi Iwai 	err = hw20k2_i2c_unlock_full_access(hw);
14828cc72361SWai Yew CHAY 	if (err < 0)
14838cc72361SWai Yew CHAY 		return err;
14848cc72361SWai Yew CHAY 
1485d362af62STakashi Iwai 	hw20k2->addr_size = addr_size;
1486d362af62STakashi Iwai 	hw20k2->data_size = data_size;
1487d362af62STakashi Iwai 	hw20k2->dev_id = dev_id;
14888cc72361SWai Yew CHAY 
1489d362af62STakashi Iwai 	i2c_addr = 0;
1490d362af62STakashi Iwai 	set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id);
14918cc72361SWai Yew CHAY 
1492d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
14938cc72361SWai Yew CHAY 
1494d362af62STakashi Iwai 	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
14958cc72361SWai Yew CHAY 
1496d362af62STakashi Iwai 	set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */
14978cc72361SWai Yew CHAY 
1498d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
14998cc72361SWai Yew CHAY 
15008cc72361SWai Yew CHAY 	return 0;
15018cc72361SWai Yew CHAY }
15028cc72361SWai Yew CHAY 
1503d362af62STakashi Iwai static int hw20k2_i2c_uninit(struct hw *hw)
15048cc72361SWai Yew CHAY {
1505d362af62STakashi Iwai 	unsigned int i2c_status;
1506d362af62STakashi Iwai 	unsigned int i2c_addr;
15078cc72361SWai Yew CHAY 
1508d362af62STakashi Iwai 	i2c_addr = 0;
1509d362af62STakashi Iwai 	set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */
15108cc72361SWai Yew CHAY 
1511d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
15128cc72361SWai Yew CHAY 
1513d362af62STakashi Iwai 	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
15148cc72361SWai Yew CHAY 
1515d362af62STakashi Iwai 	set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */
15168cc72361SWai Yew CHAY 
1517d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
15188cc72361SWai Yew CHAY 
1519d362af62STakashi Iwai 	return hw20k2_i2c_lock_chip(hw);
15208cc72361SWai Yew CHAY }
15218cc72361SWai Yew CHAY 
1522d362af62STakashi Iwai static int hw20k2_i2c_wait_data_ready(struct hw *hw)
15238cc72361SWai Yew CHAY {
15248cc72361SWai Yew CHAY 	int i = 0x400000;
1525514eef9cSTakashi Iwai 	unsigned int ret;
15268cc72361SWai Yew CHAY 
15278cc72361SWai Yew CHAY 	do {
15288cc72361SWai Yew CHAY 		ret = hw_read_20kx(hw, I2C_IF_STATUS);
15298cc72361SWai Yew CHAY 	} while ((!(ret & DATA_READY)) && --i);
15308cc72361SWai Yew CHAY 
15318cc72361SWai Yew CHAY 	return i;
15328cc72361SWai Yew CHAY }
15338cc72361SWai Yew CHAY 
1534d362af62STakashi Iwai static int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap)
15358cc72361SWai Yew CHAY {
1536d362af62STakashi Iwai 	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
1537d362af62STakashi Iwai 	unsigned int i2c_status;
15388cc72361SWai Yew CHAY 
1539d362af62STakashi Iwai 	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
1540d362af62STakashi Iwai 	set_field(&i2c_status, I2C_STATUS_BC,
1541d362af62STakashi Iwai 		  (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size);
1542d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
1543d362af62STakashi Iwai 	if (!hw20k2_i2c_wait_data_ready(hw))
15448cc72361SWai Yew CHAY 		return -1;
15458cc72361SWai Yew CHAY 
1546d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_WDATA, addr);
1547d362af62STakashi Iwai 	if (!hw20k2_i2c_wait_data_ready(hw))
15488cc72361SWai Yew CHAY 		return -1;
15498cc72361SWai Yew CHAY 
15508cc72361SWai Yew CHAY 	/* Force a read operation */
15518cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2C_IF_RDATA, 0);
1552d362af62STakashi Iwai 	if (!hw20k2_i2c_wait_data_ready(hw))
15538cc72361SWai Yew CHAY 		return -1;
15548cc72361SWai Yew CHAY 
1555d362af62STakashi Iwai 	*datap = hw_read_20kx(hw, I2C_IF_RDATA);
15568cc72361SWai Yew CHAY 
15578cc72361SWai Yew CHAY 	return 0;
15588cc72361SWai Yew CHAY }
15598cc72361SWai Yew CHAY 
1560d362af62STakashi Iwai static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
15618cc72361SWai Yew CHAY {
1562d362af62STakashi Iwai 	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
1563d362af62STakashi Iwai 	unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr;
1564d362af62STakashi Iwai 	unsigned int i2c_status;
15658cc72361SWai Yew CHAY 
1566d362af62STakashi Iwai 	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
15678cc72361SWai Yew CHAY 
1568d362af62STakashi Iwai 	set_field(&i2c_status, I2C_STATUS_BC,
1569d362af62STakashi Iwai 		  (4 == (hw20k2->addr_size + hw20k2->data_size)) ?
1570d362af62STakashi Iwai 		  0 : (hw20k2->addr_size + hw20k2->data_size));
15718cc72361SWai Yew CHAY 
1572d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
1573d362af62STakashi Iwai 	hw20k2_i2c_wait_data_ready(hw);
157455309216SHarry Butterworth 	/* Dummy write to trigger the write operation */
15758cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2C_IF_WDATA, 0);
1576d362af62STakashi Iwai 	hw20k2_i2c_wait_data_ready(hw);
15778cc72361SWai Yew CHAY 
15788cc72361SWai Yew CHAY 	/* This is the real data */
1579d362af62STakashi Iwai 	hw_write_20kx(hw, I2C_IF_WDATA, i2c_data);
1580d362af62STakashi Iwai 	hw20k2_i2c_wait_data_ready(hw);
15818cc72361SWai Yew CHAY 
15828cc72361SWai Yew CHAY 	return 0;
15838cc72361SWai Yew CHAY }
15848cc72361SWai Yew CHAY 
158555309216SHarry Butterworth static void hw_dac_stop(struct hw *hw)
158655309216SHarry Butterworth {
158755309216SHarry Butterworth 	u32 data;
158855309216SHarry Butterworth 	data = hw_read_20kx(hw, GPIO_DATA);
158955309216SHarry Butterworth 	data &= 0xFFFFFFFD;
159055309216SHarry Butterworth 	hw_write_20kx(hw, GPIO_DATA, data);
159155309216SHarry Butterworth 	mdelay(10);
159255309216SHarry Butterworth }
159355309216SHarry Butterworth 
159455309216SHarry Butterworth static void hw_dac_start(struct hw *hw)
159555309216SHarry Butterworth {
159655309216SHarry Butterworth 	u32 data;
159755309216SHarry Butterworth 	data = hw_read_20kx(hw, GPIO_DATA);
159855309216SHarry Butterworth 	data |= 0x2;
159955309216SHarry Butterworth 	hw_write_20kx(hw, GPIO_DATA, data);
160055309216SHarry Butterworth 	mdelay(50);
160155309216SHarry Butterworth }
160255309216SHarry Butterworth 
160355309216SHarry Butterworth static void hw_dac_reset(struct hw *hw)
160455309216SHarry Butterworth {
160555309216SHarry Butterworth 	hw_dac_stop(hw);
160655309216SHarry Butterworth 	hw_dac_start(hw);
160755309216SHarry Butterworth }
160855309216SHarry Butterworth 
16098cc72361SWai Yew CHAY static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
16108cc72361SWai Yew CHAY {
1611514eef9cSTakashi Iwai 	int err;
1612d362af62STakashi Iwai 	u32 data;
1613514eef9cSTakashi Iwai 	int i;
1614d362af62STakashi Iwai 	struct regs_cs4382 cs_read = {0};
1615d362af62STakashi Iwai 	struct regs_cs4382 cs_def = {
16168cc72361SWai Yew CHAY 				   0x00000001,  /* Mode Control 1 */
16178cc72361SWai Yew CHAY 				   0x00000000,  /* Mode Control 2 */
16188cc72361SWai Yew CHAY 				   0x00000084,  /* Mode Control 3 */
16198cc72361SWai Yew CHAY 				   0x00000000,  /* Filter Control */
16208cc72361SWai Yew CHAY 				   0x00000000,  /* Invert Control */
16218cc72361SWai Yew CHAY 				   0x00000024,  /* Mixing Control Pair 1 */
16228cc72361SWai Yew CHAY 				   0x00000000,  /* Vol Control A1 */
16238cc72361SWai Yew CHAY 				   0x00000000,  /* Vol Control B1 */
16248cc72361SWai Yew CHAY 				   0x00000024,  /* Mixing Control Pair 2 */
16258cc72361SWai Yew CHAY 				   0x00000000,  /* Vol Control A2 */
16268cc72361SWai Yew CHAY 				   0x00000000,  /* Vol Control B2 */
16278cc72361SWai Yew CHAY 				   0x00000024,  /* Mixing Control Pair 3 */
16288cc72361SWai Yew CHAY 				   0x00000000,  /* Vol Control A3 */
16298cc72361SWai Yew CHAY 				   0x00000000,  /* Vol Control B3 */
16308cc72361SWai Yew CHAY 				   0x00000024,  /* Mixing Control Pair 4 */
16318cc72361SWai Yew CHAY 				   0x00000000,  /* Vol Control A4 */
16328cc72361SWai Yew CHAY 				   0x00000000   /* Vol Control B4 */
16338cc72361SWai Yew CHAY 				 };
16348cc72361SWai Yew CHAY 
163555309216SHarry Butterworth 	if (hw->model == CTSB1270) {
163655309216SHarry Butterworth 		hw_dac_stop(hw);
163755309216SHarry Butterworth 		data = hw_read_20kx(hw, GPIO_DATA);
163855309216SHarry Butterworth 		data &= ~0x0600;
163955309216SHarry Butterworth 		if (1 == info->msr)
164055309216SHarry Butterworth 			data |= 0x0000; /* Single Speed Mode 0-50kHz */
164155309216SHarry Butterworth 		else if (2 == info->msr)
164255309216SHarry Butterworth 			data |= 0x0200; /* Double Speed Mode 50-100kHz */
164355309216SHarry Butterworth 		else
164455309216SHarry Butterworth 			data |= 0x0600; /* Quad Speed Mode 100-200kHz */
164555309216SHarry Butterworth 		hw_write_20kx(hw, GPIO_DATA, data);
164655309216SHarry Butterworth 		hw_dac_start(hw);
164755309216SHarry Butterworth 		return 0;
164855309216SHarry Butterworth 	}
164955309216SHarry Butterworth 
16508cc72361SWai Yew CHAY 	/* Set DAC reset bit as output */
1651d362af62STakashi Iwai 	data = hw_read_20kx(hw, GPIO_CTRL);
1652d362af62STakashi Iwai 	data |= 0x02;
1653d362af62STakashi Iwai 	hw_write_20kx(hw, GPIO_CTRL, data);
16548cc72361SWai Yew CHAY 
1655d362af62STakashi Iwai 	err = hw20k2_i2c_init(hw, 0x18, 1, 1);
16568cc72361SWai Yew CHAY 	if (err < 0)
16578cc72361SWai Yew CHAY 		goto End;
16588cc72361SWai Yew CHAY 
16598cc72361SWai Yew CHAY 	for (i = 0; i < 2; i++) {
16608cc72361SWai Yew CHAY 		/* Reset DAC twice just in-case the chip
16618cc72361SWai Yew CHAY 		 * didn't initialized properly */
166255309216SHarry Butterworth 		hw_dac_reset(hw);
166355309216SHarry Butterworth 		hw_dac_reset(hw);
16648cc72361SWai Yew CHAY 
1665d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
16668cc72361SWai Yew CHAY 			continue;
16678cc72361SWai Yew CHAY 
1668d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_MC2,  &cs_read.mode_control_2))
16698cc72361SWai Yew CHAY 			continue;
16708cc72361SWai Yew CHAY 
1671d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_MC3,  &cs_read.mode_control_3))
16728cc72361SWai Yew CHAY 			continue;
16738cc72361SWai Yew CHAY 
1674d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_FC,   &cs_read.filter_control))
16758cc72361SWai Yew CHAY 			continue;
16768cc72361SWai Yew CHAY 
1677d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_IC,   &cs_read.invert_control))
16788cc72361SWai Yew CHAY 			continue;
16798cc72361SWai Yew CHAY 
1680d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_XC1,  &cs_read.mix_control_P1))
16818cc72361SWai Yew CHAY 			continue;
16828cc72361SWai Yew CHAY 
1683d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1))
16848cc72361SWai Yew CHAY 			continue;
16858cc72361SWai Yew CHAY 
1686d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1))
16878cc72361SWai Yew CHAY 			continue;
16888cc72361SWai Yew CHAY 
1689d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_XC2,  &cs_read.mix_control_P2))
16908cc72361SWai Yew CHAY 			continue;
16918cc72361SWai Yew CHAY 
1692d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2))
16938cc72361SWai Yew CHAY 			continue;
16948cc72361SWai Yew CHAY 
1695d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2))
16968cc72361SWai Yew CHAY 			continue;
16978cc72361SWai Yew CHAY 
1698d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_XC3,  &cs_read.mix_control_P3))
16998cc72361SWai Yew CHAY 			continue;
17008cc72361SWai Yew CHAY 
1701d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3))
17028cc72361SWai Yew CHAY 			continue;
17038cc72361SWai Yew CHAY 
1704d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3))
17058cc72361SWai Yew CHAY 			continue;
17068cc72361SWai Yew CHAY 
1707d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_XC4,  &cs_read.mix_control_P4))
17088cc72361SWai Yew CHAY 			continue;
17098cc72361SWai Yew CHAY 
1710d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4))
17118cc72361SWai Yew CHAY 			continue;
17128cc72361SWai Yew CHAY 
1713d362af62STakashi Iwai 		if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4))
17148cc72361SWai Yew CHAY 			continue;
17158cc72361SWai Yew CHAY 
1716d362af62STakashi Iwai 		if (memcmp(&cs_read, &cs_def, sizeof(cs_read)))
17178cc72361SWai Yew CHAY 			continue;
17188cc72361SWai Yew CHAY 		else
17198cc72361SWai Yew CHAY 			break;
17208cc72361SWai Yew CHAY 	}
17218cc72361SWai Yew CHAY 
17228cc72361SWai Yew CHAY 	if (i >= 2)
17238cc72361SWai Yew CHAY 		goto End;
17248cc72361SWai Yew CHAY 
17258cc72361SWai Yew CHAY 	/* Note: Every I2C write must have some delay.
17268cc72361SWai Yew CHAY 	 * This is not a requirement but the delay works here... */
1727d362af62STakashi Iwai 	hw20k2_i2c_write(hw, CS4382_MC1, 0x80);
1728d362af62STakashi Iwai 	hw20k2_i2c_write(hw, CS4382_MC2, 0x10);
17298cc72361SWai Yew CHAY 	if (1 == info->msr) {
1730d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC1, 0x24);
1731d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC2, 0x24);
1732d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC3, 0x24);
1733d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC4, 0x24);
17348cc72361SWai Yew CHAY 	} else if (2 == info->msr) {
1735d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC1, 0x25);
1736d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC2, 0x25);
1737d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC3, 0x25);
1738d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC4, 0x25);
17398cc72361SWai Yew CHAY 	} else {
1740d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC1, 0x26);
1741d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC2, 0x26);
1742d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC3, 0x26);
1743d362af62STakashi Iwai 		hw20k2_i2c_write(hw, CS4382_XC4, 0x26);
17448cc72361SWai Yew CHAY 	}
17458cc72361SWai Yew CHAY 
17468cc72361SWai Yew CHAY 	return 0;
17478cc72361SWai Yew CHAY End:
17488cc72361SWai Yew CHAY 
1749d362af62STakashi Iwai 	hw20k2_i2c_uninit(hw);
17508cc72361SWai Yew CHAY 	return -1;
17518cc72361SWai Yew CHAY }
17528cc72361SWai Yew CHAY 
17538cc72361SWai Yew CHAY /* ADC operations */
17548cc72361SWai Yew CHAY #define MAKE_WM8775_ADDR(addr, data)	(u32)(((addr<<1)&0xFE)|((data>>8)&0x1))
17558cc72361SWai Yew CHAY #define MAKE_WM8775_DATA(data)	(u32)(data&0xFF)
17568cc72361SWai Yew CHAY 
17578cc72361SWai Yew CHAY #define WM8775_IC       0x0B
17588cc72361SWai Yew CHAY #define WM8775_MMC      0x0C
17598cc72361SWai Yew CHAY #define WM8775_AADCL    0x0E
17608cc72361SWai Yew CHAY #define WM8775_AADCR    0x0F
17618cc72361SWai Yew CHAY #define WM8775_ADCMC    0x15
17628cc72361SWai Yew CHAY #define WM8775_RESET    0x17
17638cc72361SWai Yew CHAY 
17648cc72361SWai Yew CHAY static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
17658cc72361SWai Yew CHAY {
1766514eef9cSTakashi Iwai 	u32 data;
176755309216SHarry Butterworth 	if (hw->model == CTSB1270) {
176855309216SHarry Butterworth 		/* Titanium HD has two ADC chips, one for line in and one */
176955309216SHarry Butterworth 		/* for MIC. We don't need to switch the ADC input. */
177055309216SHarry Butterworth 		return 1;
177155309216SHarry Butterworth 	}
17728cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO_DATA);
17738cc72361SWai Yew CHAY 	switch (type) {
17748cc72361SWai Yew CHAY 	case ADC_MICIN:
17758cc72361SWai Yew CHAY 		data = (data & (0x1 << 14)) ? 1 : 0;
17768cc72361SWai Yew CHAY 		break;
17778cc72361SWai Yew CHAY 	case ADC_LINEIN:
17788cc72361SWai Yew CHAY 		data = (data & (0x1 << 14)) ? 0 : 1;
17798cc72361SWai Yew CHAY 		break;
17808cc72361SWai Yew CHAY 	default:
17818cc72361SWai Yew CHAY 		data = 0;
17828cc72361SWai Yew CHAY 	}
17838cc72361SWai Yew CHAY 	return data;
17848cc72361SWai Yew CHAY }
17858cc72361SWai Yew CHAY 
178619002fd5SPrzemyslaw Bruski #define MIC_BOOST_0DB 0xCF
178719002fd5SPrzemyslaw Bruski #define MIC_BOOST_STEPS_PER_DB 2
178855309216SHarry Butterworth 
178955309216SHarry Butterworth static void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db)
179055309216SHarry Butterworth {
179155309216SHarry Butterworth 	u32 adcmc, gain;
179255309216SHarry Butterworth 
179355309216SHarry Butterworth 	if (input > 3)
179455309216SHarry Butterworth 		input = 3;
179555309216SHarry Butterworth 
179655309216SHarry Butterworth 	adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */
179755309216SHarry Butterworth 
179855309216SHarry Butterworth 	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc),
179955309216SHarry Butterworth 				MAKE_WM8775_DATA(adcmc));
180055309216SHarry Butterworth 
180155309216SHarry Butterworth 	if (gain_in_db < -103)
180255309216SHarry Butterworth 		gain_in_db = -103;
180355309216SHarry Butterworth 	if (gain_in_db > 24)
180455309216SHarry Butterworth 		gain_in_db = 24;
180555309216SHarry Butterworth 
180655309216SHarry Butterworth 	gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB;
180755309216SHarry Butterworth 
180855309216SHarry Butterworth 	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain),
180955309216SHarry Butterworth 				MAKE_WM8775_DATA(gain));
181055309216SHarry Butterworth 	/* ...so there should be no need for the following. */
181155309216SHarry Butterworth 	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain),
181255309216SHarry Butterworth 				MAKE_WM8775_DATA(gain));
181355309216SHarry Butterworth }
181419002fd5SPrzemyslaw Bruski 
18158cc72361SWai Yew CHAY static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
18168cc72361SWai Yew CHAY {
1817514eef9cSTakashi Iwai 	u32 data;
18188cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO_DATA);
18198cc72361SWai Yew CHAY 	switch (type) {
18208cc72361SWai Yew CHAY 	case ADC_MICIN:
18218cc72361SWai Yew CHAY 		data |= (0x1 << 14);
18228cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO_DATA, data);
182355309216SHarry Butterworth 		hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */
18248cc72361SWai Yew CHAY 		break;
18258cc72361SWai Yew CHAY 	case ADC_LINEIN:
18268cc72361SWai Yew CHAY 		data &= ~(0x1 << 14);
18278cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO_DATA, data);
182855309216SHarry Butterworth 		hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */
18298cc72361SWai Yew CHAY 		break;
18308cc72361SWai Yew CHAY 	default:
18318cc72361SWai Yew CHAY 		break;
18328cc72361SWai Yew CHAY 	}
18338cc72361SWai Yew CHAY 
18348cc72361SWai Yew CHAY 	return 0;
18358cc72361SWai Yew CHAY }
18368cc72361SWai Yew CHAY 
18378cc72361SWai Yew CHAY static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
18388cc72361SWai Yew CHAY {
1839514eef9cSTakashi Iwai 	int err;
184055309216SHarry Butterworth 	u32 data, ctl;
18418cc72361SWai Yew CHAY 
18428cc72361SWai Yew CHAY 	/*  Set ADC reset bit as output */
1843d362af62STakashi Iwai 	data = hw_read_20kx(hw, GPIO_CTRL);
1844d362af62STakashi Iwai 	data |= (0x1 << 15);
1845d362af62STakashi Iwai 	hw_write_20kx(hw, GPIO_CTRL, data);
18468cc72361SWai Yew CHAY 
18478cc72361SWai Yew CHAY 	/* Initialize I2C */
1848d362af62STakashi Iwai 	err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
18498cc72361SWai Yew CHAY 	if (err < 0) {
1850b3e0afe6STakashi Iwai 		printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n");
18518cc72361SWai Yew CHAY 		goto error;
18528cc72361SWai Yew CHAY 	}
18538cc72361SWai Yew CHAY 
185455309216SHarry Butterworth 	/* Reset the ADC (reset is active low). */
1855d362af62STakashi Iwai 	data = hw_read_20kx(hw, GPIO_DATA);
1856d362af62STakashi Iwai 	data &= ~(0x1 << 15);
185755309216SHarry Butterworth 	hw_write_20kx(hw, GPIO_DATA, data);
185855309216SHarry Butterworth 
185955309216SHarry Butterworth 	if (hw->model == CTSB1270) {
186055309216SHarry Butterworth 		/* Set up the PCM4220 ADC on Titanium HD */
186155309216SHarry Butterworth 		data &= ~0x0C;
186255309216SHarry Butterworth 		if (1 == info->msr)
186355309216SHarry Butterworth 			data |= 0x00; /* Single Speed Mode 32-50kHz */
186455309216SHarry Butterworth 		else if (2 == info->msr)
186555309216SHarry Butterworth 			data |= 0x08; /* Double Speed Mode 50-108kHz */
186655309216SHarry Butterworth 		else
186755309216SHarry Butterworth 			data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */
186855309216SHarry Butterworth 		hw_write_20kx(hw, GPIO_DATA, data);
186955309216SHarry Butterworth 	}
187055309216SHarry Butterworth 
18718cc72361SWai Yew CHAY 	mdelay(10);
187255309216SHarry Butterworth 	/* Return the ADC to normal operation. */
1873d362af62STakashi Iwai 	data |= (0x1 << 15);
1874d362af62STakashi Iwai 	hw_write_20kx(hw, GPIO_DATA, data);
18758cc72361SWai Yew CHAY 	mdelay(50);
18768cc72361SWai Yew CHAY 
187755309216SHarry Butterworth 	/* I2C write to register offset 0x0B to set ADC LRCLK polarity */
187855309216SHarry Butterworth 	/* invert bit, interface format to I2S, word length to 24-bit, */
187955309216SHarry Butterworth 	/* enable ADC high pass filter. Fixes bug 5323?		*/
188055309216SHarry Butterworth 	hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26),
188155309216SHarry Butterworth 			 MAKE_WM8775_DATA(0x26));
188255309216SHarry Butterworth 
18838cc72361SWai Yew CHAY 	/* Set the master mode (256fs) */
18848cc72361SWai Yew CHAY 	if (1 == info->msr) {
188555309216SHarry Butterworth 		/* slave mode, 128x oversampling 256fs */
1886d362af62STakashi Iwai 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
18878cc72361SWai Yew CHAY 						MAKE_WM8775_DATA(0x02));
188855309216SHarry Butterworth 	} else if ((2 == info->msr) || (4 == info->msr)) {
188955309216SHarry Butterworth 		/* slave mode, 64x oversampling, 256fs */
1890d362af62STakashi Iwai 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
18918cc72361SWai Yew CHAY 						MAKE_WM8775_DATA(0x0A));
18928cc72361SWai Yew CHAY 	} else {
1893b3e0afe6STakashi Iwai 		printk(KERN_ALERT "ctxfi: Invalid master sampling "
18948cc72361SWai Yew CHAY 				  "rate (msr %d)!!!\n", info->msr);
18958cc72361SWai Yew CHAY 		err = -EINVAL;
18968cc72361SWai Yew CHAY 		goto error;
18978cc72361SWai Yew CHAY 	}
18988cc72361SWai Yew CHAY 
189955309216SHarry Butterworth 	if (hw->model != CTSB1270) {
19008cc72361SWai Yew CHAY 		/* Configure GPIO bit 14 change to line-in/mic-in */
1901d362af62STakashi Iwai 		ctl = hw_read_20kx(hw, GPIO_CTRL);
1902d362af62STakashi Iwai 		ctl |= 0x1 << 14;
1903d362af62STakashi Iwai 		hw_write_20kx(hw, GPIO_CTRL, ctl);
190455309216SHarry Butterworth 		hw_adc_input_select(hw, ADC_LINEIN);
19058cc72361SWai Yew CHAY 	} else {
190655309216SHarry Butterworth 		hw_wm8775_input_select(hw, 0, 0);
19078cc72361SWai Yew CHAY 	}
19088cc72361SWai Yew CHAY 
19098cc72361SWai Yew CHAY 	return 0;
19108cc72361SWai Yew CHAY error:
1911d362af62STakashi Iwai 	hw20k2_i2c_uninit(hw);
19128cc72361SWai Yew CHAY 	return err;
19138cc72361SWai Yew CHAY }
19148cc72361SWai Yew CHAY 
1915b028b818SHarry Butterworth static struct capabilities hw_capabilities(struct hw *hw)
19168cc72361SWai Yew CHAY {
1917b028b818SHarry Butterworth 	struct capabilities cap;
19188cc72361SWai Yew CHAY 
1919b028b818SHarry Butterworth 	cap.digit_io_switch = 0;
1920b028b818SHarry Butterworth 	cap.dedicated_mic = hw->model == CTSB1270;
1921b028b818SHarry Butterworth 	cap.output_switch = hw->model == CTSB1270;
1922b028b818SHarry Butterworth 	cap.mic_source_switch = hw->model == CTSB1270;
192355309216SHarry Butterworth 
1924b028b818SHarry Butterworth 	return cap;
192555309216SHarry Butterworth }
192655309216SHarry Butterworth 
192755309216SHarry Butterworth static int hw_output_switch_get(struct hw *hw)
192855309216SHarry Butterworth {
192955309216SHarry Butterworth 	u32 data = hw_read_20kx(hw, GPIO_EXT_DATA);
193055309216SHarry Butterworth 
193155309216SHarry Butterworth 	switch (data & 0x30) {
193255309216SHarry Butterworth 	case 0x00:
193355309216SHarry Butterworth 	     return 0;
193455309216SHarry Butterworth 	case 0x10:
193555309216SHarry Butterworth 	     return 1;
193655309216SHarry Butterworth 	case 0x20:
193755309216SHarry Butterworth 	     return 2;
193855309216SHarry Butterworth 	default:
193955309216SHarry Butterworth 	     return 3;
194055309216SHarry Butterworth 	}
194155309216SHarry Butterworth }
194255309216SHarry Butterworth 
194355309216SHarry Butterworth static int hw_output_switch_put(struct hw *hw, int position)
194455309216SHarry Butterworth {
194555309216SHarry Butterworth 	u32 data;
194655309216SHarry Butterworth 
194755309216SHarry Butterworth 	if (position == hw_output_switch_get(hw))
194855309216SHarry Butterworth 		return 0;
194955309216SHarry Butterworth 
195055309216SHarry Butterworth 	/* Mute line and headphones (intended for anti-pop). */
195155309216SHarry Butterworth 	data = hw_read_20kx(hw, GPIO_DATA);
195255309216SHarry Butterworth 	data |= (0x03 << 11);
195355309216SHarry Butterworth 	hw_write_20kx(hw, GPIO_DATA, data);
195455309216SHarry Butterworth 
195555309216SHarry Butterworth 	data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30;
195655309216SHarry Butterworth 	switch (position) {
195755309216SHarry Butterworth 	case 0:
195855309216SHarry Butterworth 		break;
195955309216SHarry Butterworth 	case 1:
196055309216SHarry Butterworth 		data |= 0x10;
196155309216SHarry Butterworth 		break;
196255309216SHarry Butterworth 	default:
196355309216SHarry Butterworth 		data |= 0x20;
196455309216SHarry Butterworth 	}
196555309216SHarry Butterworth 	hw_write_20kx(hw, GPIO_EXT_DATA, data);
196655309216SHarry Butterworth 
196755309216SHarry Butterworth 	/* Unmute line and headphones. */
196855309216SHarry Butterworth 	data = hw_read_20kx(hw, GPIO_DATA);
196955309216SHarry Butterworth 	data &= ~(0x03 << 11);
197055309216SHarry Butterworth 	hw_write_20kx(hw, GPIO_DATA, data);
197155309216SHarry Butterworth 
197255309216SHarry Butterworth 	return 1;
197355309216SHarry Butterworth }
197455309216SHarry Butterworth 
197555309216SHarry Butterworth static int hw_mic_source_switch_get(struct hw *hw)
197655309216SHarry Butterworth {
197755309216SHarry Butterworth 	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
197855309216SHarry Butterworth 
197955309216SHarry Butterworth 	return hw20k2->mic_source;
198055309216SHarry Butterworth }
198155309216SHarry Butterworth 
198255309216SHarry Butterworth static int hw_mic_source_switch_put(struct hw *hw, int position)
198355309216SHarry Butterworth {
198455309216SHarry Butterworth 	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
198555309216SHarry Butterworth 
198655309216SHarry Butterworth 	if (position == hw20k2->mic_source)
198755309216SHarry Butterworth 		return 0;
198855309216SHarry Butterworth 
198955309216SHarry Butterworth 	switch (position) {
199055309216SHarry Butterworth 	case 0:
199155309216SHarry Butterworth 		hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */
199255309216SHarry Butterworth 		break;
199355309216SHarry Butterworth 	case 1:
199455309216SHarry Butterworth 		hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */
199555309216SHarry Butterworth 		break;
199655309216SHarry Butterworth 	case 2:
199755309216SHarry Butterworth 		hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */
199855309216SHarry Butterworth 		break;
199955309216SHarry Butterworth 	default:
200055309216SHarry Butterworth 		return 0;
200155309216SHarry Butterworth 	}
200255309216SHarry Butterworth 
200355309216SHarry Butterworth 	hw20k2->mic_source = position;
200455309216SHarry Butterworth 
200555309216SHarry Butterworth 	return 1;
200655309216SHarry Butterworth }
200755309216SHarry Butterworth 
2008bc5304b6STakashi Iwai static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
2009bc5304b6STakashi Iwai {
2010bc5304b6STakashi Iwai 	struct hw *hw = dev_id;
2011bc5304b6STakashi Iwai 	unsigned int status;
2012bc5304b6STakashi Iwai 
2013bc5304b6STakashi Iwai 	status = hw_read_20kx(hw, GIP);
2014bc5304b6STakashi Iwai 	if (!status)
2015bc5304b6STakashi Iwai 		return IRQ_NONE;
2016bc5304b6STakashi Iwai 
2017bc5304b6STakashi Iwai 	if (hw->irq_callback)
2018bc5304b6STakashi Iwai 		hw->irq_callback(hw->irq_callback_data, status);
2019bc5304b6STakashi Iwai 
2020bc5304b6STakashi Iwai 	hw_write_20kx(hw, GIP, status);
2021bc5304b6STakashi Iwai 	return IRQ_HANDLED;
2022bc5304b6STakashi Iwai }
2023bc5304b6STakashi Iwai 
20248cc72361SWai Yew CHAY static int hw_card_start(struct hw *hw)
20258cc72361SWai Yew CHAY {
20268cc72361SWai Yew CHAY 	int err = 0;
20278cc72361SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
20288cc72361SWai Yew CHAY 	unsigned int gctl;
20298cc72361SWai Yew CHAY 
20308cc72361SWai Yew CHAY 	err = pci_enable_device(pci);
20318cc72361SWai Yew CHAY 	if (err < 0)
20328cc72361SWai Yew CHAY 		return err;
20338cc72361SWai Yew CHAY 
20348cc72361SWai Yew CHAY 	/* Set DMA transfer mask */
20354836ac65STakashi Iwai 	if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
20364836ac65STakashi Iwai 	    pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
2037b3e0afe6STakashi Iwai 		printk(KERN_ERR "ctxfi: architecture does not support PCI "
20384836ac65STakashi Iwai 		"busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK);
20398cc72361SWai Yew CHAY 		err = -ENXIO;
20408cc72361SWai Yew CHAY 		goto error1;
20418cc72361SWai Yew CHAY 	}
20428cc72361SWai Yew CHAY 
204329959a09SWai Yew CHAY 	if (!hw->io_base) {
20448cc72361SWai Yew CHAY 		err = pci_request_regions(pci, "XFi");
20458cc72361SWai Yew CHAY 		if (err < 0)
20468cc72361SWai Yew CHAY 			goto error1;
20478cc72361SWai Yew CHAY 
20488cc72361SWai Yew CHAY 		hw->io_base = pci_resource_start(hw->pci, 2);
20498cc72361SWai Yew CHAY 		hw->mem_base = (unsigned long)ioremap(hw->io_base,
20508cc72361SWai Yew CHAY 					pci_resource_len(hw->pci, 2));
205135ebf6e7STakashi Iwai 		if (!hw->mem_base) {
20528cc72361SWai Yew CHAY 			err = -ENOENT;
20538cc72361SWai Yew CHAY 			goto error2;
20548cc72361SWai Yew CHAY 		}
205529959a09SWai Yew CHAY 	}
20568cc72361SWai Yew CHAY 
20578cc72361SWai Yew CHAY 	/* Switch to 20k2 mode from UAA mode. */
20588cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
20598cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_UAA, 0);
20608cc72361SWai Yew CHAY 	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
20618cc72361SWai Yew CHAY 
2062bc5304b6STakashi Iwai 	if (hw->irq < 0) {
2063bc5304b6STakashi Iwai 		err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
2064934c2b6dSTakashi Iwai 				  KBUILD_MODNAME, hw);
2065bc5304b6STakashi Iwai 		if (err < 0) {
2066bc5304b6STakashi Iwai 			printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
2067bc5304b6STakashi Iwai 			goto error2;
20688cc72361SWai Yew CHAY 		}
20698cc72361SWai Yew CHAY 		hw->irq = pci->irq;
2070bc5304b6STakashi Iwai 	}
20718cc72361SWai Yew CHAY 
20728cc72361SWai Yew CHAY 	pci_set_master(pci);
20738cc72361SWai Yew CHAY 
20748cc72361SWai Yew CHAY 	return 0;
20758cc72361SWai Yew CHAY 
20768cc72361SWai Yew CHAY /*error3:
20778cc72361SWai Yew CHAY 	iounmap((void *)hw->mem_base);
20788cc72361SWai Yew CHAY 	hw->mem_base = (unsigned long)NULL;*/
20798cc72361SWai Yew CHAY error2:
20808cc72361SWai Yew CHAY 	pci_release_regions(pci);
20818cc72361SWai Yew CHAY 	hw->io_base = 0;
20828cc72361SWai Yew CHAY error1:
20838cc72361SWai Yew CHAY 	pci_disable_device(pci);
20848cc72361SWai Yew CHAY 	return err;
20858cc72361SWai Yew CHAY }
20868cc72361SWai Yew CHAY 
20878cc72361SWai Yew CHAY static int hw_card_stop(struct hw *hw)
20888cc72361SWai Yew CHAY {
208929959a09SWai Yew CHAY 	unsigned int data;
209029959a09SWai Yew CHAY 
209129959a09SWai Yew CHAY 	/* disable transport bus master and queueing of request */
209229959a09SWai Yew CHAY 	hw_write_20kx(hw, TRANSPORT_CTL, 0x00);
209329959a09SWai Yew CHAY 
209429959a09SWai Yew CHAY 	/* disable pll */
209529959a09SWai Yew CHAY 	data = hw_read_20kx(hw, PLL_ENB);
209629959a09SWai Yew CHAY 	hw_write_20kx(hw, PLL_ENB, (data & (~0x07)));
209729959a09SWai Yew CHAY 
20988cc72361SWai Yew CHAY 	/* TODO: Disable interrupt and so on... */
20998cc72361SWai Yew CHAY 	return 0;
21008cc72361SWai Yew CHAY }
21018cc72361SWai Yew CHAY 
21028cc72361SWai Yew CHAY static int hw_card_shutdown(struct hw *hw)
21038cc72361SWai Yew CHAY {
21048cc72361SWai Yew CHAY 	if (hw->irq >= 0)
21058cc72361SWai Yew CHAY 		free_irq(hw->irq, hw);
21068cc72361SWai Yew CHAY 
21078cc72361SWai Yew CHAY 	hw->irq	= -1;
21088cc72361SWai Yew CHAY 
210935ebf6e7STakashi Iwai 	if (hw->mem_base)
21108cc72361SWai Yew CHAY 		iounmap((void *)hw->mem_base);
21118cc72361SWai Yew CHAY 
21128cc72361SWai Yew CHAY 	hw->mem_base = (unsigned long)NULL;
21138cc72361SWai Yew CHAY 
21148cc72361SWai Yew CHAY 	if (hw->io_base)
21158cc72361SWai Yew CHAY 		pci_release_regions(hw->pci);
21168cc72361SWai Yew CHAY 
21178cc72361SWai Yew CHAY 	hw->io_base = 0;
21188cc72361SWai Yew CHAY 
21198cc72361SWai Yew CHAY 	pci_disable_device(hw->pci);
21208cc72361SWai Yew CHAY 
21218cc72361SWai Yew CHAY 	return 0;
21228cc72361SWai Yew CHAY }
21238cc72361SWai Yew CHAY 
21248cc72361SWai Yew CHAY static int hw_card_init(struct hw *hw, struct card_conf *info)
21258cc72361SWai Yew CHAY {
21268cc72361SWai Yew CHAY 	int err;
21278cc72361SWai Yew CHAY 	unsigned int gctl;
21288cc72361SWai Yew CHAY 	u32 data = 0;
21298cc72361SWai Yew CHAY 	struct dac_conf dac_info = {0};
21308cc72361SWai Yew CHAY 	struct adc_conf adc_info = {0};
21318cc72361SWai Yew CHAY 	struct daio_conf daio_info = {0};
21328cc72361SWai Yew CHAY 	struct trn_conf trn_info = {0};
21338cc72361SWai Yew CHAY 
21348cc72361SWai Yew CHAY 	/* Get PCI io port/memory base address and
21358cc72361SWai Yew CHAY 	 * do 20kx core switch if needed. */
21368cc72361SWai Yew CHAY 	err = hw_card_start(hw);
21378cc72361SWai Yew CHAY 	if (err)
21388cc72361SWai Yew CHAY 		return err;
21398cc72361SWai Yew CHAY 
21408cc72361SWai Yew CHAY 	/* PLL init */
21418cc72361SWai Yew CHAY 	err = hw_pll_init(hw, info->rsr);
21428cc72361SWai Yew CHAY 	if (err < 0)
21438cc72361SWai Yew CHAY 		return err;
21448cc72361SWai Yew CHAY 
21458cc72361SWai Yew CHAY 	/* kick off auto-init */
21468cc72361SWai Yew CHAY 	err = hw_auto_init(hw);
21478cc72361SWai Yew CHAY 	if (err < 0)
21488cc72361SWai Yew CHAY 		return err;
21498cc72361SWai Yew CHAY 
21508cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
21518cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_DBP, 1);
21528cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_TBP, 1);
21538cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_FBP, 1);
21548cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_DPC, 0);
21558cc72361SWai Yew CHAY 	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
21568cc72361SWai Yew CHAY 
21578cc72361SWai Yew CHAY 	/* Reset all global pending interrupts */
2158bc5304b6STakashi Iwai 	hw_write_20kx(hw, GIE, 0);
21598cc72361SWai Yew CHAY 	/* Reset all SRC pending interrupts */
21608cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRC_IP, 0);
21618cc72361SWai Yew CHAY 
216255309216SHarry Butterworth 	if (hw->model != CTSB1270) {
21638cc72361SWai Yew CHAY 		/* TODO: detect the card ID and configure GPIO accordingly. */
21648cc72361SWai Yew CHAY 		/* Configures GPIO (0xD802 0x98028) */
21658cc72361SWai Yew CHAY 		/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
21668cc72361SWai Yew CHAY 		/* Configures GPIO (SB0880) */
21678cc72361SWai Yew CHAY 		/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
21688cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO_CTRL, 0xD802);
216955309216SHarry Butterworth 	} else {
217055309216SHarry Butterworth 		hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
217155309216SHarry Butterworth 	}
21728cc72361SWai Yew CHAY 	/* Enable audio ring */
21738cc72361SWai Yew CHAY 	hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
21748cc72361SWai Yew CHAY 
21758cc72361SWai Yew CHAY 	trn_info.vm_pgt_phys = info->vm_pgt_phys;
21768cc72361SWai Yew CHAY 	err = hw_trn_init(hw, &trn_info);
21778cc72361SWai Yew CHAY 	if (err < 0)
21788cc72361SWai Yew CHAY 		return err;
21798cc72361SWai Yew CHAY 
21808cc72361SWai Yew CHAY 	daio_info.msr = info->msr;
21818cc72361SWai Yew CHAY 	err = hw_daio_init(hw, &daio_info);
21828cc72361SWai Yew CHAY 	if (err < 0)
21838cc72361SWai Yew CHAY 		return err;
21848cc72361SWai Yew CHAY 
21858cc72361SWai Yew CHAY 	dac_info.msr = info->msr;
21868cc72361SWai Yew CHAY 	err = hw_dac_init(hw, &dac_info);
21878cc72361SWai Yew CHAY 	if (err < 0)
21888cc72361SWai Yew CHAY 		return err;
21898cc72361SWai Yew CHAY 
21908cc72361SWai Yew CHAY 	adc_info.msr = info->msr;
21918cc72361SWai Yew CHAY 	adc_info.input = ADC_LINEIN;
21928cc72361SWai Yew CHAY 	adc_info.mic20db = 0;
21938cc72361SWai Yew CHAY 	err = hw_adc_init(hw, &adc_info);
21948cc72361SWai Yew CHAY 	if (err < 0)
21958cc72361SWai Yew CHAY 		return err;
21968cc72361SWai Yew CHAY 
21978cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, SRC_MCTL);
21988cc72361SWai Yew CHAY 	data |= 0x1; /* Enables input from the audio ring */
21998cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRC_MCTL, data);
22008cc72361SWai Yew CHAY 
22018cc72361SWai Yew CHAY 	return 0;
22028cc72361SWai Yew CHAY }
22038cc72361SWai Yew CHAY 
2204c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
220568cb2b55STakashi Iwai static int hw_suspend(struct hw *hw)
220629959a09SWai Yew CHAY {
220729959a09SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
220829959a09SWai Yew CHAY 
220929959a09SWai Yew CHAY 	hw_card_stop(hw);
221029959a09SWai Yew CHAY 
221129959a09SWai Yew CHAY 	pci_disable_device(pci);
221229959a09SWai Yew CHAY 	pci_save_state(pci);
221368cb2b55STakashi Iwai 	pci_set_power_state(pci, PCI_D3hot);
221429959a09SWai Yew CHAY 
221529959a09SWai Yew CHAY 	return 0;
221629959a09SWai Yew CHAY }
221729959a09SWai Yew CHAY 
221829959a09SWai Yew CHAY static int hw_resume(struct hw *hw, struct card_conf *info)
221929959a09SWai Yew CHAY {
222029959a09SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
222129959a09SWai Yew CHAY 
222229959a09SWai Yew CHAY 	pci_set_power_state(pci, PCI_D0);
222329959a09SWai Yew CHAY 	pci_restore_state(pci);
222429959a09SWai Yew CHAY 
222529959a09SWai Yew CHAY 	/* Re-initialize card hardware. */
222629959a09SWai Yew CHAY 	return hw_card_init(hw, info);
222729959a09SWai Yew CHAY }
222829959a09SWai Yew CHAY #endif
222929959a09SWai Yew CHAY 
22308cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg)
22318cc72361SWai Yew CHAY {
22328cc72361SWai Yew CHAY 	return readl((void *)(hw->mem_base + reg));
22338cc72361SWai Yew CHAY }
22348cc72361SWai Yew CHAY 
22358cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
22368cc72361SWai Yew CHAY {
22378cc72361SWai Yew CHAY 	writel(data, (void *)(hw->mem_base + reg));
22388cc72361SWai Yew CHAY }
22398cc72361SWai Yew CHAY 
2240e23e7a14SBill Pemberton static struct hw ct20k2_preset = {
22412a36f67fSTakashi Iwai 	.irq = -1,
22422a36f67fSTakashi Iwai 
22432a36f67fSTakashi Iwai 	.card_init = hw_card_init,
22442a36f67fSTakashi Iwai 	.card_stop = hw_card_stop,
22452a36f67fSTakashi Iwai 	.pll_init = hw_pll_init,
22462a36f67fSTakashi Iwai 	.is_adc_source_selected = hw_is_adc_input_selected,
22472a36f67fSTakashi Iwai 	.select_adc_source = hw_adc_input_select,
2248b028b818SHarry Butterworth 	.capabilities = hw_capabilities,
224955309216SHarry Butterworth 	.output_switch_get = hw_output_switch_get,
225055309216SHarry Butterworth 	.output_switch_put = hw_output_switch_put,
225155309216SHarry Butterworth 	.mic_source_switch_get = hw_mic_source_switch_get,
225255309216SHarry Butterworth 	.mic_source_switch_put = hw_mic_source_switch_put,
2253c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
225429959a09SWai Yew CHAY 	.suspend = hw_suspend,
225529959a09SWai Yew CHAY 	.resume = hw_resume,
225629959a09SWai Yew CHAY #endif
22572a36f67fSTakashi Iwai 
22582a36f67fSTakashi Iwai 	.src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
22592a36f67fSTakashi Iwai 	.src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
22602a36f67fSTakashi Iwai 	.src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
22612a36f67fSTakashi Iwai 	.src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
22622a36f67fSTakashi Iwai 	.src_set_state = src_set_state,
22632a36f67fSTakashi Iwai 	.src_set_bm = src_set_bm,
22642a36f67fSTakashi Iwai 	.src_set_rsr = src_set_rsr,
22652a36f67fSTakashi Iwai 	.src_set_sf = src_set_sf,
22662a36f67fSTakashi Iwai 	.src_set_wr = src_set_wr,
22672a36f67fSTakashi Iwai 	.src_set_pm = src_set_pm,
22682a36f67fSTakashi Iwai 	.src_set_rom = src_set_rom,
22692a36f67fSTakashi Iwai 	.src_set_vo = src_set_vo,
22702a36f67fSTakashi Iwai 	.src_set_st = src_set_st,
22712a36f67fSTakashi Iwai 	.src_set_ie = src_set_ie,
22722a36f67fSTakashi Iwai 	.src_set_ilsz = src_set_ilsz,
22732a36f67fSTakashi Iwai 	.src_set_bp = src_set_bp,
22742a36f67fSTakashi Iwai 	.src_set_cisz = src_set_cisz,
22752a36f67fSTakashi Iwai 	.src_set_ca = src_set_ca,
22762a36f67fSTakashi Iwai 	.src_set_sa = src_set_sa,
22772a36f67fSTakashi Iwai 	.src_set_la = src_set_la,
22782a36f67fSTakashi Iwai 	.src_set_pitch = src_set_pitch,
22792a36f67fSTakashi Iwai 	.src_set_dirty = src_set_dirty,
22802a36f67fSTakashi Iwai 	.src_set_clear_zbufs = src_set_clear_zbufs,
22812a36f67fSTakashi Iwai 	.src_set_dirty_all = src_set_dirty_all,
22822a36f67fSTakashi Iwai 	.src_commit_write = src_commit_write,
22832a36f67fSTakashi Iwai 	.src_get_ca = src_get_ca,
22842a36f67fSTakashi Iwai 	.src_get_dirty = src_get_dirty,
22852a36f67fSTakashi Iwai 	.src_dirty_conj_mask = src_dirty_conj_mask,
22862a36f67fSTakashi Iwai 	.src_mgr_enbs_src = src_mgr_enbs_src,
22872a36f67fSTakashi Iwai 	.src_mgr_enb_src = src_mgr_enb_src,
22882a36f67fSTakashi Iwai 	.src_mgr_dsb_src = src_mgr_dsb_src,
22892a36f67fSTakashi Iwai 	.src_mgr_commit_write = src_mgr_commit_write,
22902a36f67fSTakashi Iwai 
22912a36f67fSTakashi Iwai 	.srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
22922a36f67fSTakashi Iwai 	.srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
22932a36f67fSTakashi Iwai 	.srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
22942a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
22952a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
22962a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
22972a36f67fSTakashi Iwai 	.srcimp_mgr_commit_write = srcimp_mgr_commit_write,
22982a36f67fSTakashi Iwai 
22992a36f67fSTakashi Iwai 	.amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
23002a36f67fSTakashi Iwai 	.amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
23012a36f67fSTakashi Iwai 	.amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
23022a36f67fSTakashi Iwai 	.amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
23032a36f67fSTakashi Iwai 	.amixer_set_mode = amixer_set_mode,
23042a36f67fSTakashi Iwai 	.amixer_set_iv = amixer_set_iv,
23052a36f67fSTakashi Iwai 	.amixer_set_x = amixer_set_x,
23062a36f67fSTakashi Iwai 	.amixer_set_y = amixer_set_y,
23072a36f67fSTakashi Iwai 	.amixer_set_sadr = amixer_set_sadr,
23082a36f67fSTakashi Iwai 	.amixer_set_se = amixer_set_se,
23092a36f67fSTakashi Iwai 	.amixer_set_dirty = amixer_set_dirty,
23102a36f67fSTakashi Iwai 	.amixer_set_dirty_all = amixer_set_dirty_all,
23112a36f67fSTakashi Iwai 	.amixer_commit_write = amixer_commit_write,
23122a36f67fSTakashi Iwai 	.amixer_get_y = amixer_get_y,
23132a36f67fSTakashi Iwai 	.amixer_get_dirty = amixer_get_dirty,
23142a36f67fSTakashi Iwai 
23152a36f67fSTakashi Iwai 	.dai_get_ctrl_blk = dai_get_ctrl_blk,
23162a36f67fSTakashi Iwai 	.dai_put_ctrl_blk = dai_put_ctrl_blk,
23172a36f67fSTakashi Iwai 	.dai_srt_set_srco = dai_srt_set_srco,
23182a36f67fSTakashi Iwai 	.dai_srt_set_srcm = dai_srt_set_srcm,
23192a36f67fSTakashi Iwai 	.dai_srt_set_rsr = dai_srt_set_rsr,
23202a36f67fSTakashi Iwai 	.dai_srt_set_drat = dai_srt_set_drat,
23212a36f67fSTakashi Iwai 	.dai_srt_set_ec = dai_srt_set_ec,
23222a36f67fSTakashi Iwai 	.dai_srt_set_et = dai_srt_set_et,
23232a36f67fSTakashi Iwai 	.dai_commit_write = dai_commit_write,
23242a36f67fSTakashi Iwai 
23252a36f67fSTakashi Iwai 	.dao_get_ctrl_blk = dao_get_ctrl_blk,
23262a36f67fSTakashi Iwai 	.dao_put_ctrl_blk = dao_put_ctrl_blk,
23272a36f67fSTakashi Iwai 	.dao_set_spos = dao_set_spos,
23282a36f67fSTakashi Iwai 	.dao_commit_write = dao_commit_write,
23292a36f67fSTakashi Iwai 	.dao_get_spos = dao_get_spos,
23302a36f67fSTakashi Iwai 
23312a36f67fSTakashi Iwai 	.daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
23322a36f67fSTakashi Iwai 	.daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
23332a36f67fSTakashi Iwai 	.daio_mgr_enb_dai = daio_mgr_enb_dai,
23342a36f67fSTakashi Iwai 	.daio_mgr_dsb_dai = daio_mgr_dsb_dai,
23352a36f67fSTakashi Iwai 	.daio_mgr_enb_dao = daio_mgr_enb_dao,
23362a36f67fSTakashi Iwai 	.daio_mgr_dsb_dao = daio_mgr_dsb_dao,
23372a36f67fSTakashi Iwai 	.daio_mgr_dao_init = daio_mgr_dao_init,
23382a36f67fSTakashi Iwai 	.daio_mgr_set_imaparc = daio_mgr_set_imaparc,
23392a36f67fSTakashi Iwai 	.daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
23402a36f67fSTakashi Iwai 	.daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
23412a36f67fSTakashi Iwai 	.daio_mgr_commit_write = daio_mgr_commit_write,
2342bc5304b6STakashi Iwai 
2343bc5304b6STakashi Iwai 	.set_timer_irq = set_timer_irq,
2344bc5304b6STakashi Iwai 	.set_timer_tick = set_timer_tick,
2345bc5304b6STakashi Iwai 	.get_wc = get_wc,
23462a36f67fSTakashi Iwai };
23472a36f67fSTakashi Iwai 
2348e23e7a14SBill Pemberton int create_20k2_hw_obj(struct hw **rhw)
23498cc72361SWai Yew CHAY {
2350d362af62STakashi Iwai 	struct hw20k2 *hw20k2;
23518cc72361SWai Yew CHAY 
23528cc72361SWai Yew CHAY 	*rhw = NULL;
2353d362af62STakashi Iwai 	hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL);
2354d362af62STakashi Iwai 	if (!hw20k2)
23558cc72361SWai Yew CHAY 		return -ENOMEM;
23568cc72361SWai Yew CHAY 
2357d362af62STakashi Iwai 	hw20k2->hw = ct20k2_preset;
2358d362af62STakashi Iwai 	*rhw = &hw20k2->hw;
23598cc72361SWai Yew CHAY 
23608cc72361SWai Yew CHAY 	return 0;
23618cc72361SWai Yew CHAY }
23628cc72361SWai Yew CHAY 
23638cc72361SWai Yew CHAY int destroy_20k2_hw_obj(struct hw *hw)
23648cc72361SWai Yew CHAY {
23658cc72361SWai Yew CHAY 	if (hw->io_base)
23668cc72361SWai Yew CHAY 		hw_card_shutdown(hw);
23678cc72361SWai Yew CHAY 
23688cc72361SWai Yew CHAY 	kfree(hw);
23698cc72361SWai Yew CHAY 	return 0;
23708cc72361SWai Yew CHAY }
2371