xref: /linux/sound/pci/ctxfi/cthw20k1.c (revision 1693e265e0a5dbe11fba21b48272dd15dbb71ec0)
15765e78eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fe372850SPierre-Louis Bossart /*
38cc72361SWai Yew CHAY  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
48cc72361SWai Yew CHAY  *
58cc72361SWai Yew CHAY  * @File	cthw20k1.c
68cc72361SWai Yew CHAY  *
78cc72361SWai Yew CHAY  * @Brief
88cc72361SWai Yew CHAY  * This file contains the implementation of hardware access methord for 20k1.
98cc72361SWai Yew CHAY  *
108cc72361SWai Yew CHAY  * @Author	Liu Chun
118cc72361SWai Yew CHAY  * @Date 	Jun 24 2008
128cc72361SWai Yew CHAY  */
138cc72361SWai Yew CHAY 
148cc72361SWai Yew CHAY #include <linux/types.h>
158cc72361SWai Yew CHAY #include <linux/slab.h>
168cc72361SWai Yew CHAY #include <linux/pci.h>
178cc72361SWai Yew CHAY #include <linux/io.h>
188cc72361SWai Yew CHAY #include <linux/string.h>
198cc72361SWai Yew CHAY #include <linux/spinlock.h>
208cc72361SWai Yew CHAY #include <linux/kernel.h>
218cc72361SWai Yew CHAY #include <linux/interrupt.h>
22d0da727eSTakashi Iwai #include <linux/delay.h>
236d74b86dSTakashi Iwai #include "cthw20k1.h"
246d74b86dSTakashi Iwai #include "ct20k1reg.h"
258cc72361SWai Yew CHAY 
268cc72361SWai Yew CHAY struct hw20k1 {
278cc72361SWai Yew CHAY 	struct hw hw;
288cc72361SWai Yew CHAY 	spinlock_t reg_20k1_lock;
298cc72361SWai Yew CHAY 	spinlock_t reg_pci_lock;
308cc72361SWai Yew CHAY };
318cc72361SWai Yew CHAY 
328cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg);
338cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
348cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg);
358cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data);
368cc72361SWai Yew CHAY 
378cc72361SWai Yew CHAY /*
388cc72361SWai Yew CHAY  * Type definition block.
398cc72361SWai Yew CHAY  * The layout of control structures can be directly applied on 20k2 chip.
408cc72361SWai Yew CHAY  */
418cc72361SWai Yew CHAY 
428cc72361SWai Yew CHAY /*
438cc72361SWai Yew CHAY  * SRC control block definitions.
448cc72361SWai Yew CHAY  */
458cc72361SWai Yew CHAY 
468cc72361SWai Yew CHAY /* SRC resource control block */
478cc72361SWai Yew CHAY #define SRCCTL_STATE	0x00000007
488cc72361SWai Yew CHAY #define SRCCTL_BM	0x00000008
498cc72361SWai Yew CHAY #define SRCCTL_RSR	0x00000030
508cc72361SWai Yew CHAY #define SRCCTL_SF	0x000001C0
518cc72361SWai Yew CHAY #define SRCCTL_WR	0x00000200
528cc72361SWai Yew CHAY #define SRCCTL_PM	0x00000400
538cc72361SWai Yew CHAY #define SRCCTL_ROM	0x00001800
548cc72361SWai Yew CHAY #define SRCCTL_VO	0x00002000
558cc72361SWai Yew CHAY #define SRCCTL_ST	0x00004000
568cc72361SWai Yew CHAY #define SRCCTL_IE	0x00008000
578cc72361SWai Yew CHAY #define SRCCTL_ILSZ	0x000F0000
588cc72361SWai Yew CHAY #define SRCCTL_BP	0x00100000
598cc72361SWai Yew CHAY 
608cc72361SWai Yew CHAY #define SRCCCR_CISZ	0x000007FF
618cc72361SWai Yew CHAY #define SRCCCR_CWA	0x001FF800
628cc72361SWai Yew CHAY #define SRCCCR_D	0x00200000
638cc72361SWai Yew CHAY #define SRCCCR_RS	0x01C00000
648cc72361SWai Yew CHAY #define SRCCCR_NAL	0x3E000000
658cc72361SWai Yew CHAY #define SRCCCR_RA	0xC0000000
668cc72361SWai Yew CHAY 
678cc72361SWai Yew CHAY #define SRCCA_CA	0x03FFFFFF
688cc72361SWai Yew CHAY #define SRCCA_RS	0x1C000000
698cc72361SWai Yew CHAY #define SRCCA_NAL	0xE0000000
708cc72361SWai Yew CHAY 
718cc72361SWai Yew CHAY #define SRCSA_SA	0x03FFFFFF
728cc72361SWai Yew CHAY 
738cc72361SWai Yew CHAY #define SRCLA_LA	0x03FFFFFF
748cc72361SWai Yew CHAY 
758cc72361SWai Yew CHAY /* Mixer Parameter Ring ram Low and Hight register.
768cc72361SWai Yew CHAY  * Fixed-point value in 8.24 format for parameter channel */
778cc72361SWai Yew CHAY #define MPRLH_PITCH	0xFFFFFFFF
788cc72361SWai Yew CHAY 
798cc72361SWai Yew CHAY /* SRC resource register dirty flags */
808cc72361SWai Yew CHAY union src_dirty {
818cc72361SWai Yew CHAY 	struct {
828cc72361SWai Yew CHAY 		u16 ctl:1;
838cc72361SWai Yew CHAY 		u16 ccr:1;
848cc72361SWai Yew CHAY 		u16 sa:1;
858cc72361SWai Yew CHAY 		u16 la:1;
868cc72361SWai Yew CHAY 		u16 ca:1;
878cc72361SWai Yew CHAY 		u16 mpr:1;
888cc72361SWai Yew CHAY 		u16 czbfs:1;	/* Clear Z-Buffers */
898cc72361SWai Yew CHAY 		u16 rsv:9;
908cc72361SWai Yew CHAY 	} bf;
918cc72361SWai Yew CHAY 	u16 data;
928cc72361SWai Yew CHAY };
938cc72361SWai Yew CHAY 
948cc72361SWai Yew CHAY struct src_rsc_ctrl_blk {
958cc72361SWai Yew CHAY 	unsigned int	ctl;
968cc72361SWai Yew CHAY 	unsigned int 	ccr;
978cc72361SWai Yew CHAY 	unsigned int	ca;
988cc72361SWai Yew CHAY 	unsigned int	sa;
998cc72361SWai Yew CHAY 	unsigned int	la;
1008cc72361SWai Yew CHAY 	unsigned int	mpr;
1018cc72361SWai Yew CHAY 	union src_dirty	dirty;
1028cc72361SWai Yew CHAY };
1038cc72361SWai Yew CHAY 
1048cc72361SWai Yew CHAY /* SRC manager control block */
1058cc72361SWai Yew CHAY union src_mgr_dirty {
1068cc72361SWai Yew CHAY 	struct {
1078cc72361SWai Yew CHAY 		u16 enb0:1;
1088cc72361SWai Yew CHAY 		u16 enb1:1;
1098cc72361SWai Yew CHAY 		u16 enb2:1;
1108cc72361SWai Yew CHAY 		u16 enb3:1;
1118cc72361SWai Yew CHAY 		u16 enb4:1;
1128cc72361SWai Yew CHAY 		u16 enb5:1;
1138cc72361SWai Yew CHAY 		u16 enb6:1;
1148cc72361SWai Yew CHAY 		u16 enb7:1;
1158cc72361SWai Yew CHAY 		u16 enbsa:1;
1168cc72361SWai Yew CHAY 		u16 rsv:7;
1178cc72361SWai Yew CHAY 	} bf;
1188cc72361SWai Yew CHAY 	u16 data;
1198cc72361SWai Yew CHAY };
1208cc72361SWai Yew CHAY 
1218cc72361SWai Yew CHAY struct src_mgr_ctrl_blk {
1228cc72361SWai Yew CHAY 	unsigned int		enbsa;
1238cc72361SWai Yew CHAY 	unsigned int		enb[8];
1248cc72361SWai Yew CHAY 	union src_mgr_dirty	dirty;
1258cc72361SWai Yew CHAY };
1268cc72361SWai Yew CHAY 
1278cc72361SWai Yew CHAY /* SRCIMP manager control block */
1288cc72361SWai Yew CHAY #define SRCAIM_ARC	0x00000FFF
1298cc72361SWai Yew CHAY #define SRCAIM_NXT	0x00FF0000
1308cc72361SWai Yew CHAY #define SRCAIM_SRC	0xFF000000
1318cc72361SWai Yew CHAY 
1328cc72361SWai Yew CHAY struct srcimap {
1338cc72361SWai Yew CHAY 	unsigned int srcaim;
1348cc72361SWai Yew CHAY 	unsigned int idx;
1358cc72361SWai Yew CHAY };
1368cc72361SWai Yew CHAY 
1378cc72361SWai Yew CHAY /* SRCIMP manager register dirty flags */
1388cc72361SWai Yew CHAY union srcimp_mgr_dirty {
1398cc72361SWai Yew CHAY 	struct {
1408cc72361SWai Yew CHAY 		u16 srcimap:1;
1418cc72361SWai Yew CHAY 		u16 rsv:15;
1428cc72361SWai Yew CHAY 	} bf;
1438cc72361SWai Yew CHAY 	u16 data;
1448cc72361SWai Yew CHAY };
1458cc72361SWai Yew CHAY 
1468cc72361SWai Yew CHAY struct srcimp_mgr_ctrl_blk {
1478cc72361SWai Yew CHAY 	struct srcimap		srcimap;
1488cc72361SWai Yew CHAY 	union srcimp_mgr_dirty	dirty;
1498cc72361SWai Yew CHAY };
1508cc72361SWai Yew CHAY 
1518cc72361SWai Yew CHAY /*
1528cc72361SWai Yew CHAY  * Function implementation block.
1538cc72361SWai Yew CHAY  */
1548cc72361SWai Yew CHAY 
1558cc72361SWai Yew CHAY static int src_get_rsc_ctrl_blk(void **rblk)
1568cc72361SWai Yew CHAY {
1578cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *blk;
1588cc72361SWai Yew CHAY 
1598cc72361SWai Yew CHAY 	*rblk = NULL;
1608cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
16135ebf6e7STakashi Iwai 	if (!blk)
1628cc72361SWai Yew CHAY 		return -ENOMEM;
1638cc72361SWai Yew CHAY 
1648cc72361SWai Yew CHAY 	*rblk = blk;
1658cc72361SWai Yew CHAY 
1668cc72361SWai Yew CHAY 	return 0;
1678cc72361SWai Yew CHAY }
1688cc72361SWai Yew CHAY 
1698cc72361SWai Yew CHAY static int src_put_rsc_ctrl_blk(void *blk)
1708cc72361SWai Yew CHAY {
1714df93325SXu Wang 	kfree(blk);
1728cc72361SWai Yew CHAY 
1738cc72361SWai Yew CHAY 	return 0;
1748cc72361SWai Yew CHAY }
1758cc72361SWai Yew CHAY 
1768cc72361SWai Yew CHAY static int src_set_state(void *blk, unsigned int state)
1778cc72361SWai Yew CHAY {
1788cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
1798cc72361SWai Yew CHAY 
1808cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_STATE, state);
1818cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
1828cc72361SWai Yew CHAY 	return 0;
1838cc72361SWai Yew CHAY }
1848cc72361SWai Yew CHAY 
1858cc72361SWai Yew CHAY static int src_set_bm(void *blk, unsigned int bm)
1868cc72361SWai Yew CHAY {
1878cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
1888cc72361SWai Yew CHAY 
1898cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_BM, bm);
1908cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
1918cc72361SWai Yew CHAY 	return 0;
1928cc72361SWai Yew CHAY }
1938cc72361SWai Yew CHAY 
1948cc72361SWai Yew CHAY static int src_set_rsr(void *blk, unsigned int rsr)
1958cc72361SWai Yew CHAY {
1968cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
1978cc72361SWai Yew CHAY 
1988cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_RSR, rsr);
1998cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2008cc72361SWai Yew CHAY 	return 0;
2018cc72361SWai Yew CHAY }
2028cc72361SWai Yew CHAY 
2038cc72361SWai Yew CHAY static int src_set_sf(void *blk, unsigned int sf)
2048cc72361SWai Yew CHAY {
2058cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2068cc72361SWai Yew CHAY 
2078cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_SF, sf);
2088cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2098cc72361SWai Yew CHAY 	return 0;
2108cc72361SWai Yew CHAY }
2118cc72361SWai Yew CHAY 
2128cc72361SWai Yew CHAY static int src_set_wr(void *blk, unsigned int wr)
2138cc72361SWai Yew CHAY {
2148cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2158cc72361SWai Yew CHAY 
2168cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_WR, wr);
2178cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2188cc72361SWai Yew CHAY 	return 0;
2198cc72361SWai Yew CHAY }
2208cc72361SWai Yew CHAY 
2218cc72361SWai Yew CHAY static int src_set_pm(void *blk, unsigned int pm)
2228cc72361SWai Yew CHAY {
2238cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2248cc72361SWai Yew CHAY 
2258cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_PM, pm);
2268cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2278cc72361SWai Yew CHAY 	return 0;
2288cc72361SWai Yew CHAY }
2298cc72361SWai Yew CHAY 
2308cc72361SWai Yew CHAY static int src_set_rom(void *blk, unsigned int rom)
2318cc72361SWai Yew CHAY {
2328cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2338cc72361SWai Yew CHAY 
2348cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ROM, rom);
2358cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2368cc72361SWai Yew CHAY 	return 0;
2378cc72361SWai Yew CHAY }
2388cc72361SWai Yew CHAY 
2398cc72361SWai Yew CHAY static int src_set_vo(void *blk, unsigned int vo)
2408cc72361SWai Yew CHAY {
2418cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2428cc72361SWai Yew CHAY 
2438cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_VO, vo);
2448cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2458cc72361SWai Yew CHAY 	return 0;
2468cc72361SWai Yew CHAY }
2478cc72361SWai Yew CHAY 
2488cc72361SWai Yew CHAY static int src_set_st(void *blk, unsigned int st)
2498cc72361SWai Yew CHAY {
2508cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2518cc72361SWai Yew CHAY 
2528cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ST, st);
2538cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2548cc72361SWai Yew CHAY 	return 0;
2558cc72361SWai Yew CHAY }
2568cc72361SWai Yew CHAY 
2578cc72361SWai Yew CHAY static int src_set_ie(void *blk, unsigned int ie)
2588cc72361SWai Yew CHAY {
2598cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2608cc72361SWai Yew CHAY 
2618cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_IE, ie);
2628cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2638cc72361SWai Yew CHAY 	return 0;
2648cc72361SWai Yew CHAY }
2658cc72361SWai Yew CHAY 
2668cc72361SWai Yew CHAY static int src_set_ilsz(void *blk, unsigned int ilsz)
2678cc72361SWai Yew CHAY {
2688cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2698cc72361SWai Yew CHAY 
2708cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
2718cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2728cc72361SWai Yew CHAY 	return 0;
2738cc72361SWai Yew CHAY }
2748cc72361SWai Yew CHAY 
2758cc72361SWai Yew CHAY static int src_set_bp(void *blk, unsigned int bp)
2768cc72361SWai Yew CHAY {
2778cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2788cc72361SWai Yew CHAY 
2798cc72361SWai Yew CHAY 	set_field(&ctl->ctl, SRCCTL_BP, bp);
2808cc72361SWai Yew CHAY 	ctl->dirty.bf.ctl = 1;
2818cc72361SWai Yew CHAY 	return 0;
2828cc72361SWai Yew CHAY }
2838cc72361SWai Yew CHAY 
2848cc72361SWai Yew CHAY static int src_set_cisz(void *blk, unsigned int cisz)
2858cc72361SWai Yew CHAY {
2868cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2878cc72361SWai Yew CHAY 
2888cc72361SWai Yew CHAY 	set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
2898cc72361SWai Yew CHAY 	ctl->dirty.bf.ccr = 1;
2908cc72361SWai Yew CHAY 	return 0;
2918cc72361SWai Yew CHAY }
2928cc72361SWai Yew CHAY 
2938cc72361SWai Yew CHAY static int src_set_ca(void *blk, unsigned int ca)
2948cc72361SWai Yew CHAY {
2958cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
2968cc72361SWai Yew CHAY 
2978cc72361SWai Yew CHAY 	set_field(&ctl->ca, SRCCA_CA, ca);
2988cc72361SWai Yew CHAY 	ctl->dirty.bf.ca = 1;
2998cc72361SWai Yew CHAY 	return 0;
3008cc72361SWai Yew CHAY }
3018cc72361SWai Yew CHAY 
3028cc72361SWai Yew CHAY static int src_set_sa(void *blk, unsigned int sa)
3038cc72361SWai Yew CHAY {
3048cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3058cc72361SWai Yew CHAY 
3068cc72361SWai Yew CHAY 	set_field(&ctl->sa, SRCSA_SA, sa);
3078cc72361SWai Yew CHAY 	ctl->dirty.bf.sa = 1;
3088cc72361SWai Yew CHAY 	return 0;
3098cc72361SWai Yew CHAY }
3108cc72361SWai Yew CHAY 
3118cc72361SWai Yew CHAY static int src_set_la(void *blk, unsigned int la)
3128cc72361SWai Yew CHAY {
3138cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3148cc72361SWai Yew CHAY 
3158cc72361SWai Yew CHAY 	set_field(&ctl->la, SRCLA_LA, la);
3168cc72361SWai Yew CHAY 	ctl->dirty.bf.la = 1;
3178cc72361SWai Yew CHAY 	return 0;
3188cc72361SWai Yew CHAY }
3198cc72361SWai Yew CHAY 
3208cc72361SWai Yew CHAY static int src_set_pitch(void *blk, unsigned int pitch)
3218cc72361SWai Yew CHAY {
3228cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
3238cc72361SWai Yew CHAY 
3248cc72361SWai Yew CHAY 	set_field(&ctl->mpr, MPRLH_PITCH, pitch);
3258cc72361SWai Yew CHAY 	ctl->dirty.bf.mpr = 1;
3268cc72361SWai Yew CHAY 	return 0;
3278cc72361SWai Yew CHAY }
3288cc72361SWai Yew CHAY 
3298cc72361SWai Yew CHAY static int src_set_clear_zbufs(void *blk, unsigned int clear)
3308cc72361SWai Yew CHAY {
3318cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
3328cc72361SWai Yew CHAY 	return 0;
3338cc72361SWai Yew CHAY }
3348cc72361SWai Yew CHAY 
3358cc72361SWai Yew CHAY static int src_set_dirty(void *blk, unsigned int flags)
3368cc72361SWai Yew CHAY {
3378cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
3388cc72361SWai Yew CHAY 	return 0;
3398cc72361SWai Yew CHAY }
3408cc72361SWai Yew CHAY 
3418cc72361SWai Yew CHAY static int src_set_dirty_all(void *blk)
3428cc72361SWai Yew CHAY {
3438cc72361SWai Yew CHAY 	((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
3448cc72361SWai Yew CHAY 	return 0;
3458cc72361SWai Yew CHAY }
3468cc72361SWai Yew CHAY 
3478cc72361SWai Yew CHAY #define AR_SLOT_SIZE		4096
3488cc72361SWai Yew CHAY #define AR_SLOT_BLOCK_SIZE	16
3498cc72361SWai Yew CHAY #define AR_PTS_PITCH		6
3508cc72361SWai Yew CHAY #define AR_PARAM_SRC_OFFSET	0x60
3518cc72361SWai Yew CHAY 
3528cc72361SWai Yew CHAY static unsigned int src_param_pitch_mixer(unsigned int src_idx)
3538cc72361SWai Yew CHAY {
3548cc72361SWai Yew CHAY 	return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
3558cc72361SWai Yew CHAY 			- AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
3568cc72361SWai Yew CHAY 
3578cc72361SWai Yew CHAY }
3588cc72361SWai Yew CHAY 
3598cc72361SWai Yew CHAY static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
3608cc72361SWai Yew CHAY {
3618cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
362514eef9cSTakashi Iwai 	int i;
3638cc72361SWai Yew CHAY 
3648cc72361SWai Yew CHAY 	if (ctl->dirty.bf.czbfs) {
3658cc72361SWai Yew CHAY 		/* Clear Z-Buffer registers */
3668cc72361SWai Yew CHAY 		for (i = 0; i < 8; i++)
3678cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0);
3688cc72361SWai Yew CHAY 
3698cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++)
3708cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0);
3718cc72361SWai Yew CHAY 
3728cc72361SWai Yew CHAY 		for (i = 0; i < 8; i++)
3738cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0);
3748cc72361SWai Yew CHAY 
3758cc72361SWai Yew CHAY 		ctl->dirty.bf.czbfs = 0;
3768cc72361SWai Yew CHAY 	}
3778cc72361SWai Yew CHAY 	if (ctl->dirty.bf.mpr) {
3788cc72361SWai Yew CHAY 		/* Take the parameter mixer resource in the same group as that
3798cc72361SWai Yew CHAY 		 * the idx src is in for simplicity. Unlike src, all conjugate
3808cc72361SWai Yew CHAY 		 * parameter mixer resources must be programmed for
3818cc72361SWai Yew CHAY 		 * corresponding conjugate src resources. */
3828cc72361SWai Yew CHAY 		unsigned int pm_idx = src_param_pitch_mixer(idx);
3838cc72361SWai Yew CHAY 		hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr);
3848cc72361SWai Yew CHAY 		hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3);
3858cc72361SWai Yew CHAY 		hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0);
3868cc72361SWai Yew CHAY 		ctl->dirty.bf.mpr = 0;
3878cc72361SWai Yew CHAY 	}
3888cc72361SWai Yew CHAY 	if (ctl->dirty.bf.sa) {
3898cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa);
3908cc72361SWai Yew CHAY 		ctl->dirty.bf.sa = 0;
3918cc72361SWai Yew CHAY 	}
3928cc72361SWai Yew CHAY 	if (ctl->dirty.bf.la) {
3938cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la);
3948cc72361SWai Yew CHAY 		ctl->dirty.bf.la = 0;
3958cc72361SWai Yew CHAY 	}
3968cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ca) {
3978cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca);
3988cc72361SWai Yew CHAY 		ctl->dirty.bf.ca = 0;
3998cc72361SWai Yew CHAY 	}
4008cc72361SWai Yew CHAY 
4018cc72361SWai Yew CHAY 	/* Write srccf register */
4028cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCCF+idx*0x100, 0x0);
4038cc72361SWai Yew CHAY 
4048cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ccr) {
4058cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr);
4068cc72361SWai Yew CHAY 		ctl->dirty.bf.ccr = 0;
4078cc72361SWai Yew CHAY 	}
4088cc72361SWai Yew CHAY 	if (ctl->dirty.bf.ctl) {
4098cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl);
4108cc72361SWai Yew CHAY 		ctl->dirty.bf.ctl = 0;
4118cc72361SWai Yew CHAY 	}
4128cc72361SWai Yew CHAY 
4138cc72361SWai Yew CHAY 	return 0;
4148cc72361SWai Yew CHAY }
4158cc72361SWai Yew CHAY 
4168cc72361SWai Yew CHAY static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
4178cc72361SWai Yew CHAY {
4188cc72361SWai Yew CHAY 	struct src_rsc_ctrl_blk *ctl = blk;
4198cc72361SWai Yew CHAY 
4208cc72361SWai Yew CHAY 	ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100);
4218cc72361SWai Yew CHAY 	ctl->dirty.bf.ca = 0;
4228cc72361SWai Yew CHAY 
4238cc72361SWai Yew CHAY 	return get_field(ctl->ca, SRCCA_CA);
4248cc72361SWai Yew CHAY }
4258cc72361SWai Yew CHAY 
4268cc72361SWai Yew CHAY static unsigned int src_get_dirty(void *blk)
4278cc72361SWai Yew CHAY {
4288cc72361SWai Yew CHAY 	return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
4298cc72361SWai Yew CHAY }
4308cc72361SWai Yew CHAY 
4318cc72361SWai Yew CHAY static unsigned int src_dirty_conj_mask(void)
4328cc72361SWai Yew CHAY {
4338cc72361SWai Yew CHAY 	return 0x20;
4348cc72361SWai Yew CHAY }
4358cc72361SWai Yew CHAY 
4368cc72361SWai Yew CHAY static int src_mgr_enbs_src(void *blk, unsigned int idx)
4378cc72361SWai Yew CHAY {
4388cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0);
4398cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
4408cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
4418cc72361SWai Yew CHAY 	return 0;
4428cc72361SWai Yew CHAY }
4438cc72361SWai Yew CHAY 
4448cc72361SWai Yew CHAY static int src_mgr_enb_src(void *blk, unsigned int idx)
4458cc72361SWai Yew CHAY {
4468cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
4478cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
4488cc72361SWai Yew CHAY 	return 0;
4498cc72361SWai Yew CHAY }
4508cc72361SWai Yew CHAY 
4518cc72361SWai Yew CHAY static int src_mgr_dsb_src(void *blk, unsigned int idx)
4528cc72361SWai Yew CHAY {
4538cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
4548cc72361SWai Yew CHAY 	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
4558cc72361SWai Yew CHAY 	return 0;
4568cc72361SWai Yew CHAY }
4578cc72361SWai Yew CHAY 
4588cc72361SWai Yew CHAY static int src_mgr_commit_write(struct hw *hw, void *blk)
4598cc72361SWai Yew CHAY {
4608cc72361SWai Yew CHAY 	struct src_mgr_ctrl_blk *ctl = blk;
461514eef9cSTakashi Iwai 	int i;
462514eef9cSTakashi Iwai 	unsigned int ret;
4638cc72361SWai Yew CHAY 
4648cc72361SWai Yew CHAY 	if (ctl->dirty.bf.enbsa) {
4658cc72361SWai Yew CHAY 		do {
4668cc72361SWai Yew CHAY 			ret = hw_read_20kx(hw, SRCENBSTAT);
4678cc72361SWai Yew CHAY 		} while (ret & 0x1);
4688cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCENBS, ctl->enbsa);
4698cc72361SWai Yew CHAY 		ctl->dirty.bf.enbsa = 0;
4708cc72361SWai Yew CHAY 	}
4718cc72361SWai Yew CHAY 	for (i = 0; i < 8; i++) {
4728cc72361SWai Yew CHAY 		if ((ctl->dirty.data & (0x1 << i))) {
4738cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]);
4748cc72361SWai Yew CHAY 			ctl->dirty.data &= ~(0x1 << i);
4758cc72361SWai Yew CHAY 		}
4768cc72361SWai Yew CHAY 	}
4778cc72361SWai Yew CHAY 
4788cc72361SWai Yew CHAY 	return 0;
4798cc72361SWai Yew CHAY }
4808cc72361SWai Yew CHAY 
4818cc72361SWai Yew CHAY static int src_mgr_get_ctrl_blk(void **rblk)
4828cc72361SWai Yew CHAY {
4838cc72361SWai Yew CHAY 	struct src_mgr_ctrl_blk *blk;
4848cc72361SWai Yew CHAY 
4858cc72361SWai Yew CHAY 	*rblk = NULL;
4868cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
48735ebf6e7STakashi Iwai 	if (!blk)
4888cc72361SWai Yew CHAY 		return -ENOMEM;
4898cc72361SWai Yew CHAY 
4908cc72361SWai Yew CHAY 	*rblk = blk;
4918cc72361SWai Yew CHAY 
4928cc72361SWai Yew CHAY 	return 0;
4938cc72361SWai Yew CHAY }
4948cc72361SWai Yew CHAY 
4958cc72361SWai Yew CHAY static int src_mgr_put_ctrl_blk(void *blk)
4968cc72361SWai Yew CHAY {
4974df93325SXu Wang 	kfree(blk);
4988cc72361SWai Yew CHAY 
4998cc72361SWai Yew CHAY 	return 0;
5008cc72361SWai Yew CHAY }
5018cc72361SWai Yew CHAY 
5028cc72361SWai Yew CHAY static int srcimp_mgr_get_ctrl_blk(void **rblk)
5038cc72361SWai Yew CHAY {
5048cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *blk;
5058cc72361SWai Yew CHAY 
5068cc72361SWai Yew CHAY 	*rblk = NULL;
5078cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
50835ebf6e7STakashi Iwai 	if (!blk)
5098cc72361SWai Yew CHAY 		return -ENOMEM;
5108cc72361SWai Yew CHAY 
5118cc72361SWai Yew CHAY 	*rblk = blk;
5128cc72361SWai Yew CHAY 
5138cc72361SWai Yew CHAY 	return 0;
5148cc72361SWai Yew CHAY }
5158cc72361SWai Yew CHAY 
5168cc72361SWai Yew CHAY static int srcimp_mgr_put_ctrl_blk(void *blk)
5178cc72361SWai Yew CHAY {
5184df93325SXu Wang 	kfree(blk);
5198cc72361SWai Yew CHAY 
5208cc72361SWai Yew CHAY 	return 0;
5218cc72361SWai Yew CHAY }
5228cc72361SWai Yew CHAY 
5238cc72361SWai Yew CHAY static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
5248cc72361SWai Yew CHAY {
5258cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5268cc72361SWai Yew CHAY 
5278cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
5288cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5298cc72361SWai Yew CHAY 	return 0;
5308cc72361SWai Yew CHAY }
5318cc72361SWai Yew CHAY 
5328cc72361SWai Yew CHAY static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
5338cc72361SWai Yew CHAY {
5348cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5358cc72361SWai Yew CHAY 
5368cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
5378cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5388cc72361SWai Yew CHAY 	return 0;
5398cc72361SWai Yew CHAY }
5408cc72361SWai Yew CHAY 
5418cc72361SWai Yew CHAY static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
5428cc72361SWai Yew CHAY {
5438cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5448cc72361SWai Yew CHAY 
5458cc72361SWai Yew CHAY 	set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
5468cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5478cc72361SWai Yew CHAY 	return 0;
5488cc72361SWai Yew CHAY }
5498cc72361SWai Yew CHAY 
5508cc72361SWai Yew CHAY static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
5518cc72361SWai Yew CHAY {
5528cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5538cc72361SWai Yew CHAY 
5548cc72361SWai Yew CHAY 	ctl->srcimap.idx = addr;
5558cc72361SWai Yew CHAY 	ctl->dirty.bf.srcimap = 1;
5568cc72361SWai Yew CHAY 	return 0;
5578cc72361SWai Yew CHAY }
5588cc72361SWai Yew CHAY 
5598cc72361SWai Yew CHAY static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
5608cc72361SWai Yew CHAY {
5618cc72361SWai Yew CHAY 	struct srcimp_mgr_ctrl_blk *ctl = blk;
5628cc72361SWai Yew CHAY 
5638cc72361SWai Yew CHAY 	if (ctl->dirty.bf.srcimap) {
5648cc72361SWai Yew CHAY 		hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100,
5658cc72361SWai Yew CHAY 						ctl->srcimap.srcaim);
5668cc72361SWai Yew CHAY 		ctl->dirty.bf.srcimap = 0;
5678cc72361SWai Yew CHAY 	}
5688cc72361SWai Yew CHAY 
5698cc72361SWai Yew CHAY 	return 0;
5708cc72361SWai Yew CHAY }
5718cc72361SWai Yew CHAY 
5728cc72361SWai Yew CHAY /*
5738cc72361SWai Yew CHAY  * AMIXER control block definitions.
5748cc72361SWai Yew CHAY  */
5758cc72361SWai Yew CHAY 
5768cc72361SWai Yew CHAY #define AMOPLO_M	0x00000003
5778cc72361SWai Yew CHAY #define AMOPLO_X	0x0003FFF0
5788cc72361SWai Yew CHAY #define AMOPLO_Y	0xFFFC0000
5798cc72361SWai Yew CHAY 
5808cc72361SWai Yew CHAY #define AMOPHI_SADR	0x000000FF
5818cc72361SWai Yew CHAY #define AMOPHI_SE	0x80000000
5828cc72361SWai Yew CHAY 
5838cc72361SWai Yew CHAY /* AMIXER resource register dirty flags */
5848cc72361SWai Yew CHAY union amixer_dirty {
5858cc72361SWai Yew CHAY 	struct {
5868cc72361SWai Yew CHAY 		u16 amoplo:1;
5878cc72361SWai Yew CHAY 		u16 amophi:1;
5888cc72361SWai Yew CHAY 		u16 rsv:14;
5898cc72361SWai Yew CHAY 	} bf;
5908cc72361SWai Yew CHAY 	u16 data;
5918cc72361SWai Yew CHAY };
5928cc72361SWai Yew CHAY 
5938cc72361SWai Yew CHAY /* AMIXER resource control block */
5948cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk {
5958cc72361SWai Yew CHAY 	unsigned int		amoplo;
5968cc72361SWai Yew CHAY 	unsigned int		amophi;
5978cc72361SWai Yew CHAY 	union amixer_dirty	dirty;
5988cc72361SWai Yew CHAY };
5998cc72361SWai Yew CHAY 
6008cc72361SWai Yew CHAY static int amixer_set_mode(void *blk, unsigned int mode)
6018cc72361SWai Yew CHAY {
6028cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6038cc72361SWai Yew CHAY 
6048cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_M, mode);
6058cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6068cc72361SWai Yew CHAY 	return 0;
6078cc72361SWai Yew CHAY }
6088cc72361SWai Yew CHAY 
6098cc72361SWai Yew CHAY static int amixer_set_iv(void *blk, unsigned int iv)
6108cc72361SWai Yew CHAY {
6118cc72361SWai Yew CHAY 	/* 20k1 amixer does not have this field */
6128cc72361SWai Yew CHAY 	return 0;
6138cc72361SWai Yew CHAY }
6148cc72361SWai Yew CHAY 
6158cc72361SWai Yew CHAY static int amixer_set_x(void *blk, unsigned int x)
6168cc72361SWai Yew CHAY {
6178cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6188cc72361SWai Yew CHAY 
6198cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_X, x);
6208cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6218cc72361SWai Yew CHAY 	return 0;
6228cc72361SWai Yew CHAY }
6238cc72361SWai Yew CHAY 
6248cc72361SWai Yew CHAY static int amixer_set_y(void *blk, unsigned int y)
6258cc72361SWai Yew CHAY {
6268cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6278cc72361SWai Yew CHAY 
6288cc72361SWai Yew CHAY 	set_field(&ctl->amoplo, AMOPLO_Y, y);
6298cc72361SWai Yew CHAY 	ctl->dirty.bf.amoplo = 1;
6308cc72361SWai Yew CHAY 	return 0;
6318cc72361SWai Yew CHAY }
6328cc72361SWai Yew CHAY 
6338cc72361SWai Yew CHAY static int amixer_set_sadr(void *blk, unsigned int sadr)
6348cc72361SWai Yew CHAY {
6358cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6368cc72361SWai Yew CHAY 
6378cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SADR, sadr);
6388cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
6398cc72361SWai Yew CHAY 	return 0;
6408cc72361SWai Yew CHAY }
6418cc72361SWai Yew CHAY 
6428cc72361SWai Yew CHAY static int amixer_set_se(void *blk, unsigned int se)
6438cc72361SWai Yew CHAY {
6448cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6458cc72361SWai Yew CHAY 
6468cc72361SWai Yew CHAY 	set_field(&ctl->amophi, AMOPHI_SE, se);
6478cc72361SWai Yew CHAY 	ctl->dirty.bf.amophi = 1;
6488cc72361SWai Yew CHAY 	return 0;
6498cc72361SWai Yew CHAY }
6508cc72361SWai Yew CHAY 
6518cc72361SWai Yew CHAY static int amixer_set_dirty(void *blk, unsigned int flags)
6528cc72361SWai Yew CHAY {
6538cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
6548cc72361SWai Yew CHAY 	return 0;
6558cc72361SWai Yew CHAY }
6568cc72361SWai Yew CHAY 
6578cc72361SWai Yew CHAY static int amixer_set_dirty_all(void *blk)
6588cc72361SWai Yew CHAY {
6598cc72361SWai Yew CHAY 	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
6608cc72361SWai Yew CHAY 	return 0;
6618cc72361SWai Yew CHAY }
6628cc72361SWai Yew CHAY 
6638cc72361SWai Yew CHAY static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
6648cc72361SWai Yew CHAY {
6658cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6668cc72361SWai Yew CHAY 
6678cc72361SWai Yew CHAY 	if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
6688cc72361SWai Yew CHAY 		hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo);
6698cc72361SWai Yew CHAY 		ctl->dirty.bf.amoplo = 0;
6708cc72361SWai Yew CHAY 		hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi);
6718cc72361SWai Yew CHAY 		ctl->dirty.bf.amophi = 0;
6728cc72361SWai Yew CHAY 	}
6738cc72361SWai Yew CHAY 
6748cc72361SWai Yew CHAY 	return 0;
6758cc72361SWai Yew CHAY }
6768cc72361SWai Yew CHAY 
6778cc72361SWai Yew CHAY static int amixer_get_y(void *blk)
6788cc72361SWai Yew CHAY {
6798cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *ctl = blk;
6808cc72361SWai Yew CHAY 
6818cc72361SWai Yew CHAY 	return get_field(ctl->amoplo, AMOPLO_Y);
6828cc72361SWai Yew CHAY }
6838cc72361SWai Yew CHAY 
6848cc72361SWai Yew CHAY static unsigned int amixer_get_dirty(void *blk)
6858cc72361SWai Yew CHAY {
6868cc72361SWai Yew CHAY 	return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
6878cc72361SWai Yew CHAY }
6888cc72361SWai Yew CHAY 
6898cc72361SWai Yew CHAY static int amixer_rsc_get_ctrl_blk(void **rblk)
6908cc72361SWai Yew CHAY {
6918cc72361SWai Yew CHAY 	struct amixer_rsc_ctrl_blk *blk;
6928cc72361SWai Yew CHAY 
6938cc72361SWai Yew CHAY 	*rblk = NULL;
6948cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
69535ebf6e7STakashi Iwai 	if (!blk)
6968cc72361SWai Yew CHAY 		return -ENOMEM;
6978cc72361SWai Yew CHAY 
6988cc72361SWai Yew CHAY 	*rblk = blk;
6998cc72361SWai Yew CHAY 
7008cc72361SWai Yew CHAY 	return 0;
7018cc72361SWai Yew CHAY }
7028cc72361SWai Yew CHAY 
7038cc72361SWai Yew CHAY static int amixer_rsc_put_ctrl_blk(void *blk)
7048cc72361SWai Yew CHAY {
7054df93325SXu Wang 	kfree(blk);
7068cc72361SWai Yew CHAY 
7078cc72361SWai Yew CHAY 	return 0;
7088cc72361SWai Yew CHAY }
7098cc72361SWai Yew CHAY 
7108cc72361SWai Yew CHAY static int amixer_mgr_get_ctrl_blk(void **rblk)
7118cc72361SWai Yew CHAY {
7128cc72361SWai Yew CHAY 	/*amixer_mgr_ctrl_blk_t *blk;*/
7138cc72361SWai Yew CHAY 
7148cc72361SWai Yew CHAY 	*rblk = NULL;
7158cc72361SWai Yew CHAY 	/*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
71635ebf6e7STakashi Iwai 	if (!blk)
7178cc72361SWai Yew CHAY 		return -ENOMEM;
7188cc72361SWai Yew CHAY 
7198cc72361SWai Yew CHAY 	*rblk = blk;*/
7208cc72361SWai Yew CHAY 
7218cc72361SWai Yew CHAY 	return 0;
7228cc72361SWai Yew CHAY }
7238cc72361SWai Yew CHAY 
7248cc72361SWai Yew CHAY static int amixer_mgr_put_ctrl_blk(void *blk)
7258cc72361SWai Yew CHAY {
7268cc72361SWai Yew CHAY 	/*kfree((amixer_mgr_ctrl_blk_t *)blk);*/
7278cc72361SWai Yew CHAY 
7288cc72361SWai Yew CHAY 	return 0;
7298cc72361SWai Yew CHAY }
7308cc72361SWai Yew CHAY 
7318cc72361SWai Yew CHAY /*
7328cc72361SWai Yew CHAY  * DAIO control block definitions.
7338cc72361SWai Yew CHAY  */
7348cc72361SWai Yew CHAY 
7358cc72361SWai Yew CHAY /* Receiver Sample Rate Tracker Control register */
7368cc72361SWai Yew CHAY #define SRTCTL_SRCR	0x000000FF
7378cc72361SWai Yew CHAY #define SRTCTL_SRCL	0x0000FF00
7388cc72361SWai Yew CHAY #define SRTCTL_RSR	0x00030000
7398cc72361SWai Yew CHAY #define SRTCTL_DRAT	0x000C0000
7408cc72361SWai Yew CHAY #define SRTCTL_RLE	0x10000000
7418cc72361SWai Yew CHAY #define SRTCTL_RLP	0x20000000
7428cc72361SWai Yew CHAY #define SRTCTL_EC	0x40000000
7438cc72361SWai Yew CHAY #define SRTCTL_ET	0x80000000
7448cc72361SWai Yew CHAY 
7458cc72361SWai Yew CHAY /* DAIO Receiver register dirty flags */
7468cc72361SWai Yew CHAY union dai_dirty {
7478cc72361SWai Yew CHAY 	struct {
7488cc72361SWai Yew CHAY 		u16 srtctl:1;
7498cc72361SWai Yew CHAY 		u16 rsv:15;
7508cc72361SWai Yew CHAY 	} bf;
7518cc72361SWai Yew CHAY 	u16 data;
7528cc72361SWai Yew CHAY };
7538cc72361SWai Yew CHAY 
7548cc72361SWai Yew CHAY /* DAIO Receiver control block */
7558cc72361SWai Yew CHAY struct dai_ctrl_blk {
7568cc72361SWai Yew CHAY 	unsigned int	srtctl;
7578cc72361SWai Yew CHAY 	union dai_dirty	dirty;
7588cc72361SWai Yew CHAY };
7598cc72361SWai Yew CHAY 
7608cc72361SWai Yew CHAY /* S/PDIF Transmitter register dirty flags */
7618cc72361SWai Yew CHAY union dao_dirty {
7628cc72361SWai Yew CHAY 	struct {
7638cc72361SWai Yew CHAY 		u16 spos:1;
7648cc72361SWai Yew CHAY 		u16 rsv:15;
7658cc72361SWai Yew CHAY 	} bf;
7668cc72361SWai Yew CHAY 	u16 data;
7678cc72361SWai Yew CHAY };
7688cc72361SWai Yew CHAY 
7698cc72361SWai Yew CHAY /* S/PDIF Transmitter control block */
7708cc72361SWai Yew CHAY struct dao_ctrl_blk {
7718cc72361SWai Yew CHAY 	unsigned int 	spos; /* S/PDIF Output Channel Status Register */
7728cc72361SWai Yew CHAY 	union dao_dirty	dirty;
7738cc72361SWai Yew CHAY };
7748cc72361SWai Yew CHAY 
7758cc72361SWai Yew CHAY /* Audio Input Mapper RAM */
7768cc72361SWai Yew CHAY #define AIM_ARC		0x00000FFF
7778cc72361SWai Yew CHAY #define AIM_NXT		0x007F0000
7788cc72361SWai Yew CHAY 
7798cc72361SWai Yew CHAY struct daoimap {
7808cc72361SWai Yew CHAY 	unsigned int aim;
7818cc72361SWai Yew CHAY 	unsigned int idx;
7828cc72361SWai Yew CHAY };
7838cc72361SWai Yew CHAY 
7848cc72361SWai Yew CHAY /* I2S Transmitter/Receiver Control register */
7858cc72361SWai Yew CHAY #define I2SCTL_EA	0x00000004
7868cc72361SWai Yew CHAY #define I2SCTL_EI	0x00000010
7878cc72361SWai Yew CHAY 
7888cc72361SWai Yew CHAY /* S/PDIF Transmitter Control register */
7898cc72361SWai Yew CHAY #define SPOCTL_OE	0x00000001
7908cc72361SWai Yew CHAY #define SPOCTL_OS	0x0000000E
7918cc72361SWai Yew CHAY #define SPOCTL_RIV	0x00000010
7928cc72361SWai Yew CHAY #define SPOCTL_LIV	0x00000020
7938cc72361SWai Yew CHAY #define SPOCTL_SR	0x000000C0
7948cc72361SWai Yew CHAY 
7958cc72361SWai Yew CHAY /* S/PDIF Receiver Control register */
7968cc72361SWai Yew CHAY #define SPICTL_EN	0x00000001
7978cc72361SWai Yew CHAY #define SPICTL_I24	0x00000002
7988cc72361SWai Yew CHAY #define SPICTL_IB	0x00000004
7998cc72361SWai Yew CHAY #define SPICTL_SM	0x00000008
8008cc72361SWai Yew CHAY #define SPICTL_VM	0x00000010
8018cc72361SWai Yew CHAY 
8028cc72361SWai Yew CHAY /* DAIO manager register dirty flags */
8038cc72361SWai Yew CHAY union daio_mgr_dirty {
8048cc72361SWai Yew CHAY 	struct {
8058cc72361SWai Yew CHAY 		u32 i2soctl:4;
8068cc72361SWai Yew CHAY 		u32 i2sictl:4;
8078cc72361SWai Yew CHAY 		u32 spoctl:4;
8088cc72361SWai Yew CHAY 		u32 spictl:4;
8098cc72361SWai Yew CHAY 		u32 daoimap:1;
8108cc72361SWai Yew CHAY 		u32 rsv:15;
8118cc72361SWai Yew CHAY 	} bf;
8128cc72361SWai Yew CHAY 	u32 data;
8138cc72361SWai Yew CHAY };
8148cc72361SWai Yew CHAY 
8158cc72361SWai Yew CHAY /* DAIO manager control block */
8168cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk {
8178cc72361SWai Yew CHAY 	unsigned int		i2sctl;
8188cc72361SWai Yew CHAY 	unsigned int		spoctl;
8198cc72361SWai Yew CHAY 	unsigned int		spictl;
8208cc72361SWai Yew CHAY 	struct daoimap		daoimap;
8218cc72361SWai Yew CHAY 	union daio_mgr_dirty	dirty;
8228cc72361SWai Yew CHAY };
8238cc72361SWai Yew CHAY 
8248cc72361SWai Yew CHAY static int dai_srt_set_srcr(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->srtctl, SRTCTL_SRCR, src);
8298cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 1;
8308cc72361SWai Yew CHAY 	return 0;
8318cc72361SWai Yew CHAY }
8328cc72361SWai Yew CHAY 
8338cc72361SWai Yew CHAY static int dai_srt_set_srcl(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->srtctl, SRTCTL_SRCL, src);
8388cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 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->srtctl, SRTCTL_RSR, rsr);
8478cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 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->srtctl, SRTCTL_DRAT, drat);
8568cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 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->srtctl, SRTCTL_EC, ec ? 1 : 0);
8658cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 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->srtctl, SRTCTL_ET, et ? 1 : 0);
8748cc72361SWai Yew CHAY 	ctl->dirty.bf.srtctl = 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.srtctl) {
8838cc72361SWai Yew CHAY 		if (idx < 4) {
8848cc72361SWai Yew CHAY 			/* S/PDIF SRTs */
8858cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl);
8868cc72361SWai Yew CHAY 		} else {
8878cc72361SWai Yew CHAY 			/* I2S SRT */
8888cc72361SWai Yew CHAY 			hw_write_20kx(hw, SRTICTL, ctl->srtctl);
8898cc72361SWai Yew CHAY 		}
8908cc72361SWai Yew CHAY 		ctl->dirty.bf.srtctl = 0;
8918cc72361SWai Yew CHAY 	}
8928cc72361SWai Yew CHAY 
8938cc72361SWai Yew CHAY 	return 0;
8948cc72361SWai Yew CHAY }
8958cc72361SWai Yew CHAY 
8968cc72361SWai Yew CHAY static int dai_get_ctrl_blk(void **rblk)
8978cc72361SWai Yew CHAY {
8988cc72361SWai Yew CHAY 	struct dai_ctrl_blk *blk;
8998cc72361SWai Yew CHAY 
9008cc72361SWai Yew CHAY 	*rblk = NULL;
9018cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
90235ebf6e7STakashi Iwai 	if (!blk)
9038cc72361SWai Yew CHAY 		return -ENOMEM;
9048cc72361SWai Yew CHAY 
9058cc72361SWai Yew CHAY 	*rblk = blk;
9068cc72361SWai Yew CHAY 
9078cc72361SWai Yew CHAY 	return 0;
9088cc72361SWai Yew CHAY }
9098cc72361SWai Yew CHAY 
9108cc72361SWai Yew CHAY static int dai_put_ctrl_blk(void *blk)
9118cc72361SWai Yew CHAY {
9124df93325SXu Wang 	kfree(blk);
9138cc72361SWai Yew CHAY 
9148cc72361SWai Yew CHAY 	return 0;
9158cc72361SWai Yew CHAY }
9168cc72361SWai Yew CHAY 
9178cc72361SWai Yew CHAY static int dao_set_spos(void *blk, unsigned int spos)
9188cc72361SWai Yew CHAY {
9198cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->spos = spos;
9208cc72361SWai Yew CHAY 	((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1;
9218cc72361SWai Yew CHAY 	return 0;
9228cc72361SWai Yew CHAY }
9238cc72361SWai Yew CHAY 
9248cc72361SWai Yew CHAY static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
9258cc72361SWai Yew CHAY {
9268cc72361SWai Yew CHAY 	struct dao_ctrl_blk *ctl = blk;
9278cc72361SWai Yew CHAY 
9288cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spos) {
9298cc72361SWai Yew CHAY 		if (idx < 4) {
9308cc72361SWai Yew CHAY 			/* S/PDIF SPOSx */
9318cc72361SWai Yew CHAY 			hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos);
9328cc72361SWai Yew CHAY 		}
9338cc72361SWai Yew CHAY 		ctl->dirty.bf.spos = 0;
9348cc72361SWai Yew CHAY 	}
9358cc72361SWai Yew CHAY 
9368cc72361SWai Yew CHAY 	return 0;
9378cc72361SWai Yew CHAY }
9388cc72361SWai Yew CHAY 
9398cc72361SWai Yew CHAY static int dao_get_spos(void *blk, unsigned int *spos)
9408cc72361SWai Yew CHAY {
9418cc72361SWai Yew CHAY 	*spos = ((struct dao_ctrl_blk *)blk)->spos;
9428cc72361SWai Yew CHAY 	return 0;
9438cc72361SWai Yew CHAY }
9448cc72361SWai Yew CHAY 
9458cc72361SWai Yew CHAY static int dao_get_ctrl_blk(void **rblk)
9468cc72361SWai Yew CHAY {
9478cc72361SWai Yew CHAY 	struct dao_ctrl_blk *blk;
9488cc72361SWai Yew CHAY 
9498cc72361SWai Yew CHAY 	*rblk = NULL;
9508cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
95135ebf6e7STakashi Iwai 	if (!blk)
9528cc72361SWai Yew CHAY 		return -ENOMEM;
9538cc72361SWai Yew CHAY 
9548cc72361SWai Yew CHAY 	*rblk = blk;
9558cc72361SWai Yew CHAY 
9568cc72361SWai Yew CHAY 	return 0;
9578cc72361SWai Yew CHAY }
9588cc72361SWai Yew CHAY 
9598cc72361SWai Yew CHAY static int dao_put_ctrl_blk(void *blk)
9608cc72361SWai Yew CHAY {
9614df93325SXu Wang 	kfree(blk);
9628cc72361SWai Yew CHAY 
9638cc72361SWai Yew CHAY 	return 0;
9648cc72361SWai Yew CHAY }
9658cc72361SWai Yew CHAY 
9668cc72361SWai Yew CHAY static int daio_mgr_enb_dai(void *blk, unsigned int idx)
9678cc72361SWai Yew CHAY {
9688cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9698cc72361SWai Yew CHAY 
9708cc72361SWai Yew CHAY 	if (idx < 4) {
9718cc72361SWai Yew CHAY 		/* S/PDIF input */
9728cc72361SWai Yew CHAY 		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1);
9738cc72361SWai Yew CHAY 		ctl->dirty.bf.spictl |= (0x1 << idx);
9748cc72361SWai Yew CHAY 	} else {
9758cc72361SWai Yew CHAY 		/* I2S input */
9768cc72361SWai Yew CHAY 		idx %= 4;
9778cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1);
9788cc72361SWai Yew CHAY 		ctl->dirty.bf.i2sictl |= (0x1 << idx);
9798cc72361SWai Yew CHAY 	}
9808cc72361SWai Yew CHAY 	return 0;
9818cc72361SWai Yew CHAY }
9828cc72361SWai Yew CHAY 
9838cc72361SWai Yew CHAY static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
9848cc72361SWai Yew CHAY {
9858cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
9868cc72361SWai Yew CHAY 
9878cc72361SWai Yew CHAY 	if (idx < 4) {
9888cc72361SWai Yew CHAY 		/* S/PDIF input */
9898cc72361SWai Yew CHAY 		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0);
9908cc72361SWai Yew CHAY 		ctl->dirty.bf.spictl |= (0x1 << idx);
9918cc72361SWai Yew CHAY 	} else {
9928cc72361SWai Yew CHAY 		/* I2S input */
9938cc72361SWai Yew CHAY 		idx %= 4;
9948cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0);
9958cc72361SWai Yew CHAY 		ctl->dirty.bf.i2sictl |= (0x1 << idx);
9968cc72361SWai Yew CHAY 	}
9978cc72361SWai Yew CHAY 	return 0;
9988cc72361SWai Yew CHAY }
9998cc72361SWai Yew CHAY 
10008cc72361SWai Yew CHAY static int daio_mgr_enb_dao(void *blk, unsigned int idx)
10018cc72361SWai Yew CHAY {
10028cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10038cc72361SWai Yew CHAY 
10048cc72361SWai Yew CHAY 	if (idx < 4) {
10058cc72361SWai Yew CHAY 		/* S/PDIF output */
10068cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1);
10078cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
10088cc72361SWai Yew CHAY 	} else {
10098cc72361SWai Yew CHAY 		/* I2S output */
10108cc72361SWai Yew CHAY 		idx %= 4;
10118cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1);
10128cc72361SWai Yew CHAY 		ctl->dirty.bf.i2soctl |= (0x1 << idx);
10138cc72361SWai Yew CHAY 	}
10148cc72361SWai Yew CHAY 	return 0;
10158cc72361SWai Yew CHAY }
10168cc72361SWai Yew CHAY 
10178cc72361SWai Yew CHAY static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
10188cc72361SWai Yew CHAY {
10198cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10208cc72361SWai Yew CHAY 
10218cc72361SWai Yew CHAY 	if (idx < 4) {
10228cc72361SWai Yew CHAY 		/* S/PDIF output */
10238cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0);
10248cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
10258cc72361SWai Yew CHAY 	} else {
10268cc72361SWai Yew CHAY 		/* I2S output */
10278cc72361SWai Yew CHAY 		idx %= 4;
10288cc72361SWai Yew CHAY 		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0);
10298cc72361SWai Yew CHAY 		ctl->dirty.bf.i2soctl |= (0x1 << idx);
10308cc72361SWai Yew CHAY 	}
10318cc72361SWai Yew CHAY 	return 0;
10328cc72361SWai Yew CHAY }
10338cc72361SWai Yew CHAY 
10348cc72361SWai Yew CHAY static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
10358cc72361SWai Yew CHAY {
10368cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10378cc72361SWai Yew CHAY 
10388cc72361SWai Yew CHAY 	if (idx < 4) {
10398cc72361SWai Yew CHAY 		/* S/PDIF output */
10408cc72361SWai Yew CHAY 		switch ((conf & 0x7)) {
10418cc72361SWai Yew CHAY 		case 0:
10428cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3);
10438cc72361SWai Yew CHAY 			break; /* CDIF */
10448cc72361SWai Yew CHAY 		case 1:
10458cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0);
10468cc72361SWai Yew CHAY 			break;
10478cc72361SWai Yew CHAY 		case 2:
10488cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1);
10498cc72361SWai Yew CHAY 			break;
10508cc72361SWai Yew CHAY 		case 4:
10518cc72361SWai Yew CHAY 			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2);
10528cc72361SWai Yew CHAY 			break;
10538cc72361SWai Yew CHAY 		default:
10548cc72361SWai Yew CHAY 			break;
10558cc72361SWai Yew CHAY 		}
10568cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8),
10578cc72361SWai Yew CHAY 			  (conf >> 4) & 0x1); /* Non-audio */
10588cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8),
10598cc72361SWai Yew CHAY 			  (conf >> 4) & 0x1); /* Non-audio */
10608cc72361SWai Yew CHAY 		set_field(&ctl->spoctl, SPOCTL_OS << (idx*8),
10618cc72361SWai Yew CHAY 			  ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */
10628cc72361SWai Yew CHAY 
10638cc72361SWai Yew CHAY 		ctl->dirty.bf.spoctl |= (0x1 << idx);
10648cc72361SWai Yew CHAY 	} else {
10658cc72361SWai Yew CHAY 		/* I2S output */
10668cc72361SWai Yew CHAY 		/*idx %= 4; */
10678cc72361SWai Yew CHAY 	}
10688cc72361SWai Yew CHAY 	return 0;
10698cc72361SWai Yew CHAY }
10708cc72361SWai Yew CHAY 
10718cc72361SWai Yew CHAY static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
10728cc72361SWai Yew CHAY {
10738cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10748cc72361SWai Yew CHAY 
10758cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_ARC, slot);
10768cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
10778cc72361SWai Yew CHAY 	return 0;
10788cc72361SWai Yew CHAY }
10798cc72361SWai Yew CHAY 
10808cc72361SWai Yew CHAY static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
10818cc72361SWai Yew CHAY {
10828cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10838cc72361SWai Yew CHAY 
10848cc72361SWai Yew CHAY 	set_field(&ctl->daoimap.aim, AIM_NXT, next);
10858cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
10868cc72361SWai Yew CHAY 	return 0;
10878cc72361SWai Yew CHAY }
10888cc72361SWai Yew CHAY 
10898cc72361SWai Yew CHAY static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
10908cc72361SWai Yew CHAY {
10918cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
10928cc72361SWai Yew CHAY 
10938cc72361SWai Yew CHAY 	ctl->daoimap.idx = addr;
10948cc72361SWai Yew CHAY 	ctl->dirty.bf.daoimap = 1;
10958cc72361SWai Yew CHAY 	return 0;
10968cc72361SWai Yew CHAY }
10978cc72361SWai Yew CHAY 
10988cc72361SWai Yew CHAY static int daio_mgr_commit_write(struct hw *hw, void *blk)
10998cc72361SWai Yew CHAY {
11008cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *ctl = blk;
1101514eef9cSTakashi Iwai 	int i;
11028cc72361SWai Yew CHAY 
11038cc72361SWai Yew CHAY 	if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) {
11048cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
11058cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.i2sictl & (0x1 << i)))
11068cc72361SWai Yew CHAY 				ctl->dirty.bf.i2sictl &= ~(0x1 << i);
11078cc72361SWai Yew CHAY 
11088cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.i2soctl & (0x1 << i)))
11098cc72361SWai Yew CHAY 				ctl->dirty.bf.i2soctl &= ~(0x1 << i);
11108cc72361SWai Yew CHAY 		}
11118cc72361SWai Yew CHAY 		hw_write_20kx(hw, I2SCTL, ctl->i2sctl);
11128cc72361SWai Yew CHAY 		mdelay(1);
11138cc72361SWai Yew CHAY 	}
11148cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spoctl) {
11158cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
11168cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.spoctl & (0x1 << i)))
11178cc72361SWai Yew CHAY 				ctl->dirty.bf.spoctl &= ~(0x1 << i);
11188cc72361SWai Yew CHAY 		}
11198cc72361SWai Yew CHAY 		hw_write_20kx(hw, SPOCTL, ctl->spoctl);
11208cc72361SWai Yew CHAY 		mdelay(1);
11218cc72361SWai Yew CHAY 	}
11228cc72361SWai Yew CHAY 	if (ctl->dirty.bf.spictl) {
11238cc72361SWai Yew CHAY 		for (i = 0; i < 4; i++) {
11248cc72361SWai Yew CHAY 			if ((ctl->dirty.bf.spictl & (0x1 << i)))
11258cc72361SWai Yew CHAY 				ctl->dirty.bf.spictl &= ~(0x1 << i);
11268cc72361SWai Yew CHAY 		}
11278cc72361SWai Yew CHAY 		hw_write_20kx(hw, SPICTL, ctl->spictl);
11288cc72361SWai Yew CHAY 		mdelay(1);
11298cc72361SWai Yew CHAY 	}
11308cc72361SWai Yew CHAY 	if (ctl->dirty.bf.daoimap) {
11318cc72361SWai Yew CHAY 		hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4,
11328cc72361SWai Yew CHAY 					ctl->daoimap.aim);
11338cc72361SWai Yew CHAY 		ctl->dirty.bf.daoimap = 0;
11348cc72361SWai Yew CHAY 	}
11358cc72361SWai Yew CHAY 
11368cc72361SWai Yew CHAY 	return 0;
11378cc72361SWai Yew CHAY }
11388cc72361SWai Yew CHAY 
11398cc72361SWai Yew CHAY static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
11408cc72361SWai Yew CHAY {
11418cc72361SWai Yew CHAY 	struct daio_mgr_ctrl_blk *blk;
11428cc72361SWai Yew CHAY 
11438cc72361SWai Yew CHAY 	*rblk = NULL;
11448cc72361SWai Yew CHAY 	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
114535ebf6e7STakashi Iwai 	if (!blk)
11468cc72361SWai Yew CHAY 		return -ENOMEM;
11478cc72361SWai Yew CHAY 
11488cc72361SWai Yew CHAY 	blk->i2sctl = hw_read_20kx(hw, I2SCTL);
11498cc72361SWai Yew CHAY 	blk->spoctl = hw_read_20kx(hw, SPOCTL);
11508cc72361SWai Yew CHAY 	blk->spictl = hw_read_20kx(hw, SPICTL);
11518cc72361SWai Yew CHAY 
11528cc72361SWai Yew CHAY 	*rblk = blk;
11538cc72361SWai Yew CHAY 
11548cc72361SWai Yew CHAY 	return 0;
11558cc72361SWai Yew CHAY }
11568cc72361SWai Yew CHAY 
11578cc72361SWai Yew CHAY static int daio_mgr_put_ctrl_blk(void *blk)
11588cc72361SWai Yew CHAY {
11594df93325SXu Wang 	kfree(blk);
11608cc72361SWai Yew CHAY 
11618cc72361SWai Yew CHAY 	return 0;
11628cc72361SWai Yew CHAY }
11638cc72361SWai Yew CHAY 
1164b7bbf876STakashi Iwai /* Timer interrupt */
1165b7bbf876STakashi Iwai static int set_timer_irq(struct hw *hw, int enable)
1166b7bbf876STakashi Iwai {
1167b7bbf876STakashi Iwai 	hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
1168b7bbf876STakashi Iwai 	return 0;
1169b7bbf876STakashi Iwai }
1170b7bbf876STakashi Iwai 
1171b7bbf876STakashi Iwai static int set_timer_tick(struct hw *hw, unsigned int ticks)
1172b7bbf876STakashi Iwai {
1173b7bbf876STakashi Iwai 	if (ticks)
1174b7bbf876STakashi Iwai 		ticks |= TIMR_IE | TIMR_IP;
1175b7bbf876STakashi Iwai 	hw_write_20kx(hw, TIMR, ticks);
1176b7bbf876STakashi Iwai 	return 0;
1177b7bbf876STakashi Iwai }
1178b7bbf876STakashi Iwai 
117954de6bc8STakashi Iwai static unsigned int get_wc(struct hw *hw)
118054de6bc8STakashi Iwai {
118154de6bc8STakashi Iwai 	return hw_read_20kx(hw, WC);
118254de6bc8STakashi Iwai }
118354de6bc8STakashi Iwai 
11848cc72361SWai Yew CHAY /* Card hardware initialization block */
11858cc72361SWai Yew CHAY struct dac_conf {
11868cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
11878cc72361SWai Yew CHAY };
11888cc72361SWai Yew CHAY 
11898cc72361SWai Yew CHAY struct adc_conf {
11908cc72361SWai Yew CHAY 	unsigned int msr; 	/* master sample rate in rsrs */
11918cc72361SWai Yew CHAY 	unsigned char input; 	/* the input source of ADC */
11928cc72361SWai Yew CHAY 	unsigned char mic20db; 	/* boost mic by 20db if input is microphone */
11938cc72361SWai Yew CHAY };
11948cc72361SWai Yew CHAY 
11958cc72361SWai Yew CHAY struct daio_conf {
11968cc72361SWai Yew CHAY 	unsigned int msr; /* master sample rate in rsrs */
11978cc72361SWai Yew CHAY };
11988cc72361SWai Yew CHAY 
11998cc72361SWai Yew CHAY struct trn_conf {
12008cc72361SWai Yew CHAY 	unsigned long vm_pgt_phys;
12018cc72361SWai Yew CHAY };
12028cc72361SWai Yew CHAY 
12038cc72361SWai Yew CHAY static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
12048cc72361SWai Yew CHAY {
1205514eef9cSTakashi Iwai 	u32 i2sorg;
1206514eef9cSTakashi Iwai 	u32 spdorg;
12078cc72361SWai Yew CHAY 
12088cc72361SWai Yew CHAY 	/* Read I2S CTL.  Keep original value. */
12098cc72361SWai Yew CHAY 	/*i2sorg = hw_read_20kx(hw, I2SCTL);*/
12108cc72361SWai Yew CHAY 	i2sorg = 0x94040404; /* enable all audio out and I2S-D input */
12118cc72361SWai Yew CHAY 	/* Program I2S with proper master sample rate and enable
12128cc72361SWai Yew CHAY 	 * the correct I2S channel. */
12138cc72361SWai Yew CHAY 	i2sorg &= 0xfffffffc;
12148cc72361SWai Yew CHAY 
12158cc72361SWai Yew CHAY 	/* Enable S/PDIF-out-A in fixed 24-bit data
12168cc72361SWai Yew CHAY 	 * format and default to 48kHz. */
12178cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
12188cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, 0x0);
12198cc72361SWai Yew CHAY 	spdorg = 0x05;
12208cc72361SWai Yew CHAY 
12218cc72361SWai Yew CHAY 	switch (info->msr) {
12228cc72361SWai Yew CHAY 	case 1:
12238cc72361SWai Yew CHAY 		i2sorg |= 1;
12248cc72361SWai Yew CHAY 		spdorg |= (0x0 << 6);
12258cc72361SWai Yew CHAY 		break;
12268cc72361SWai Yew CHAY 	case 2:
12278cc72361SWai Yew CHAY 		i2sorg |= 2;
12288cc72361SWai Yew CHAY 		spdorg |= (0x1 << 6);
12298cc72361SWai Yew CHAY 		break;
12308cc72361SWai Yew CHAY 	case 4:
12318cc72361SWai Yew CHAY 		i2sorg |= 3;
12328cc72361SWai Yew CHAY 		spdorg |= (0x2 << 6);
12338cc72361SWai Yew CHAY 		break;
12348cc72361SWai Yew CHAY 	default:
12358cc72361SWai Yew CHAY 		i2sorg |= 1;
12368cc72361SWai Yew CHAY 		break;
12378cc72361SWai Yew CHAY 	}
12388cc72361SWai Yew CHAY 
12398cc72361SWai Yew CHAY 	hw_write_20kx(hw, I2SCTL, i2sorg);
12408cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPOCTL, spdorg);
12418cc72361SWai Yew CHAY 
12428cc72361SWai Yew CHAY 	/* Enable S/PDIF-in-A in fixed 24-bit data format. */
12438cc72361SWai Yew CHAY 	/* Disable all before doing any changes. */
12448cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, 0x0);
12458cc72361SWai Yew CHAY 	mdelay(1);
12468cc72361SWai Yew CHAY 	spdorg = 0x0a0a0a0a;
12478cc72361SWai Yew CHAY 	hw_write_20kx(hw, SPICTL, spdorg);
12488cc72361SWai Yew CHAY 	mdelay(1);
12498cc72361SWai Yew CHAY 
12508cc72361SWai Yew CHAY 	return 0;
12518cc72361SWai Yew CHAY }
12528cc72361SWai Yew CHAY 
12538cc72361SWai Yew CHAY /* TRANSPORT operations */
12548cc72361SWai Yew CHAY static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
12558cc72361SWai Yew CHAY {
1256514eef9cSTakashi Iwai 	u32 trnctl;
1257514eef9cSTakashi Iwai 	u32 ptp_phys_low, ptp_phys_high;
12588cc72361SWai Yew CHAY 
12598cc72361SWai Yew CHAY 	/* Set up device page table */
12608cc72361SWai Yew CHAY 	if ((~0UL) == info->vm_pgt_phys) {
12610cae90a9SSudip Mukherjee 		dev_err(hw->card->dev,
12620cae90a9SSudip Mukherjee 			"Wrong device page table page address!\n");
12638cc72361SWai Yew CHAY 		return -1;
12648cc72361SWai Yew CHAY 	}
12658cc72361SWai Yew CHAY 
12668cc72361SWai Yew CHAY 	trnctl = 0x13;  /* 32-bit, 4k-size page */
1267cd391e20STakashi Iwai 	ptp_phys_low = (u32)info->vm_pgt_phys;
1268cd391e20STakashi Iwai 	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
1269cd391e20STakashi Iwai 	if (sizeof(void *) == 8) /* 64bit address */
12708cc72361SWai Yew CHAY 		trnctl |= (1 << 2);
1271cd391e20STakashi Iwai #if 0 /* Only 4k h/w pages for simplicitiy */
12728cc72361SWai Yew CHAY #if PAGE_SIZE == 8192
12738cc72361SWai Yew CHAY 	trnctl |= (1<<5);
12748cc72361SWai Yew CHAY #endif
1275cd391e20STakashi Iwai #endif
12768cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPALX, ptp_phys_low);
12778cc72361SWai Yew CHAY 	hw_write_20kx(hw, PTPAHX, ptp_phys_high);
12788cc72361SWai Yew CHAY 	hw_write_20kx(hw, TRNCTL, trnctl);
127925985edcSLucas De Marchi 	hw_write_20kx(hw, TRNIS, 0x200c01); /* really needed? */
12808cc72361SWai Yew CHAY 
12818cc72361SWai Yew CHAY 	return 0;
12828cc72361SWai Yew CHAY }
12838cc72361SWai Yew CHAY 
12848cc72361SWai Yew CHAY /* Card initialization */
12858cc72361SWai Yew CHAY #define GCTL_EAC	0x00000001
12868cc72361SWai Yew CHAY #define GCTL_EAI	0x00000002
12878cc72361SWai Yew CHAY #define GCTL_BEP	0x00000004
12888cc72361SWai Yew CHAY #define GCTL_BES	0x00000008
12898cc72361SWai Yew CHAY #define GCTL_DSP	0x00000010
12908cc72361SWai Yew CHAY #define GCTL_DBP	0x00000020
12918cc72361SWai Yew CHAY #define GCTL_ABP	0x00000040
12928cc72361SWai Yew CHAY #define GCTL_TBP	0x00000080
12938cc72361SWai Yew CHAY #define GCTL_SBP	0x00000100
12948cc72361SWai Yew CHAY #define GCTL_FBP	0x00000200
12958cc72361SWai Yew CHAY #define GCTL_XA		0x00000400
12968cc72361SWai Yew CHAY #define GCTL_ET		0x00000800
12978cc72361SWai Yew CHAY #define GCTL_PR		0x00001000
12988cc72361SWai Yew CHAY #define GCTL_MRL	0x00002000
12998cc72361SWai Yew CHAY #define GCTL_SDE	0x00004000
13008cc72361SWai Yew CHAY #define GCTL_SDI	0x00008000
13018cc72361SWai Yew CHAY #define GCTL_SM		0x00010000
13028cc72361SWai Yew CHAY #define GCTL_SR		0x00020000
13038cc72361SWai Yew CHAY #define GCTL_SD		0x00040000
13048cc72361SWai Yew CHAY #define GCTL_SE		0x00080000
13058cc72361SWai Yew CHAY #define GCTL_AID	0x00100000
13068cc72361SWai Yew CHAY 
13078cc72361SWai Yew CHAY static int hw_pll_init(struct hw *hw, unsigned int rsr)
13088cc72361SWai Yew CHAY {
13098cc72361SWai Yew CHAY 	unsigned int pllctl;
1310514eef9cSTakashi Iwai 	int i;
13118cc72361SWai Yew CHAY 
13128cc72361SWai Yew CHAY 	pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731;
13138cc72361SWai Yew CHAY 	for (i = 0; i < 3; i++) {
13148cc72361SWai Yew CHAY 		if (hw_read_20kx(hw, PLLCTL) == pllctl)
13158cc72361SWai Yew CHAY 			break;
13168cc72361SWai Yew CHAY 
13178cc72361SWai Yew CHAY 		hw_write_20kx(hw, PLLCTL, pllctl);
131808fd8325SJia-Ju Bai 		msleep(40);
13198cc72361SWai Yew CHAY 	}
13208cc72361SWai Yew CHAY 	if (i >= 3) {
13210cae90a9SSudip Mukherjee 		dev_alert(hw->card->dev, "PLL initialization failed!!!\n");
13228cc72361SWai Yew CHAY 		return -EBUSY;
13238cc72361SWai Yew CHAY 	}
13248cc72361SWai Yew CHAY 
13258cc72361SWai Yew CHAY 	return 0;
13268cc72361SWai Yew CHAY }
13278cc72361SWai Yew CHAY 
13288cc72361SWai Yew CHAY static int hw_auto_init(struct hw *hw)
13298cc72361SWai Yew CHAY {
13308cc72361SWai Yew CHAY 	unsigned int gctl;
13318cc72361SWai Yew CHAY 	int i;
13328cc72361SWai Yew CHAY 
13338cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
13348cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 0);
13358cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
13368cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAI, 1);
13378cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
13388cc72361SWai Yew CHAY 	mdelay(10);
13398cc72361SWai Yew CHAY 	for (i = 0; i < 400000; i++) {
13408cc72361SWai Yew CHAY 		gctl = hw_read_20kx(hw, GCTL);
13418cc72361SWai Yew CHAY 		if (get_field(gctl, GCTL_AID))
13428cc72361SWai Yew CHAY 			break;
13438cc72361SWai Yew CHAY 	}
13448cc72361SWai Yew CHAY 	if (!get_field(gctl, GCTL_AID)) {
13450cae90a9SSudip Mukherjee 		dev_alert(hw->card->dev, "Card Auto-init failed!!!\n");
13468cc72361SWai Yew CHAY 		return -EBUSY;
13478cc72361SWai Yew CHAY 	}
13488cc72361SWai Yew CHAY 
13498cc72361SWai Yew CHAY 	return 0;
13508cc72361SWai Yew CHAY }
13518cc72361SWai Yew CHAY 
13528cc72361SWai Yew CHAY static int i2c_unlock(struct hw *hw)
13538cc72361SWai Yew CHAY {
13548cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13558cc72361SWai Yew CHAY 		return 0;
13568cc72361SWai Yew CHAY 
13578cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0x8c);
13588cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0x0e);
13598cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13608cc72361SWai Yew CHAY 		return 0;
13618cc72361SWai Yew CHAY 
13628cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xee);
13638cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xcc, 0xaa);
13648cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13658cc72361SWai Yew CHAY 		return 0;
13668cc72361SWai Yew CHAY 
13678cc72361SWai Yew CHAY 	return -1;
13688cc72361SWai Yew CHAY }
13698cc72361SWai Yew CHAY 
13708cc72361SWai Yew CHAY static void i2c_lock(struct hw *hw)
13718cc72361SWai Yew CHAY {
13728cc72361SWai Yew CHAY 	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
13738cc72361SWai Yew CHAY 		hw_write_pci(hw, 0xcc, 0x00);
13748cc72361SWai Yew CHAY }
13758cc72361SWai Yew CHAY 
13768cc72361SWai Yew CHAY static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data)
13778cc72361SWai Yew CHAY {
1378514eef9cSTakashi Iwai 	unsigned int ret;
13798cc72361SWai Yew CHAY 
13808cc72361SWai Yew CHAY 	do {
13818cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
13828cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
13838cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE0, device);
13848cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff));
13858cc72361SWai Yew CHAY }
13868cc72361SWai Yew CHAY 
13878cc72361SWai Yew CHAY /* DAC operations */
13888cc72361SWai Yew CHAY 
13898cc72361SWai Yew CHAY static int hw_reset_dac(struct hw *hw)
13908cc72361SWai Yew CHAY {
1391514eef9cSTakashi Iwai 	u32 i;
1392514eef9cSTakashi Iwai 	u16 gpioorg;
1393514eef9cSTakashi Iwai 	unsigned int ret;
13948cc72361SWai Yew CHAY 
13958cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
13968cc72361SWai Yew CHAY 		return -1;
13978cc72361SWai Yew CHAY 
13988cc72361SWai Yew CHAY 	do {
13998cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
14008cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
14018cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
14028cc72361SWai Yew CHAY 
14038cc72361SWai Yew CHAY 	/* To be effective, need to reset the DAC twice. */
14048cc72361SWai Yew CHAY 	for (i = 0; i < 2;  i++) {
14058cc72361SWai Yew CHAY 		/* set gpio */
140608fd8325SJia-Ju Bai 		msleep(100);
14078cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
14088cc72361SWai Yew CHAY 		gpioorg &= 0xfffd;
14098cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
14108cc72361SWai Yew CHAY 		mdelay(1);
14118cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg | 0x2);
14128cc72361SWai Yew CHAY 	}
14138cc72361SWai Yew CHAY 
14148cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x01, 0x80);
14158cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x02, 0x10);
14168cc72361SWai Yew CHAY 
14178cc72361SWai Yew CHAY 	i2c_lock(hw);
14188cc72361SWai Yew CHAY 
14198cc72361SWai Yew CHAY 	return 0;
14208cc72361SWai Yew CHAY }
14218cc72361SWai Yew CHAY 
14228cc72361SWai Yew CHAY static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
14238cc72361SWai Yew CHAY {
1424514eef9cSTakashi Iwai 	u32 data;
1425514eef9cSTakashi Iwai 	u16 gpioorg;
1426514eef9cSTakashi Iwai 	unsigned int ret;
14278cc72361SWai Yew CHAY 
14289470195aSTakashi Iwai 	if (hw->model == CTSB055X) {
14298cc72361SWai Yew CHAY 		/* SB055x, unmute outputs */
14308cc72361SWai Yew CHAY 		gpioorg = (u16)hw_read_20kx(hw, GPIO);
14318cc72361SWai Yew CHAY 		gpioorg &= 0xffbf;	/* set GPIO6 to low */
14328cc72361SWai Yew CHAY 		gpioorg |= 2;		/* set GPIO1 to high */
14338cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIO, gpioorg);
14348cc72361SWai Yew CHAY 		return 0;
14358cc72361SWai Yew CHAY 	}
14368cc72361SWai Yew CHAY 
14378cc72361SWai Yew CHAY 	/* mute outputs */
14388cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
14398cc72361SWai Yew CHAY 	gpioorg &= 0xffbf;
14408cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
14418cc72361SWai Yew CHAY 
14428cc72361SWai Yew CHAY 	hw_reset_dac(hw);
14438cc72361SWai Yew CHAY 
14448cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
14458cc72361SWai Yew CHAY 		return -1;
14468cc72361SWai Yew CHAY 
14478cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
14488cc72361SWai Yew CHAY 	do {
14498cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
14508cc72361SWai Yew CHAY 	} while (!(ret & 0x800000));
14518cc72361SWai Yew CHAY 
14528cc72361SWai Yew CHAY 	switch (info->msr) {
14538cc72361SWai Yew CHAY 	case 1:
14548cc72361SWai Yew CHAY 		data = 0x24;
14558cc72361SWai Yew CHAY 		break;
14568cc72361SWai Yew CHAY 	case 2:
14578cc72361SWai Yew CHAY 		data = 0x25;
14588cc72361SWai Yew CHAY 		break;
14598cc72361SWai Yew CHAY 	case 4:
14608cc72361SWai Yew CHAY 		data = 0x26;
14618cc72361SWai Yew CHAY 		break;
14628cc72361SWai Yew CHAY 	default:
14638cc72361SWai Yew CHAY 		data = 0x24;
14648cc72361SWai Yew CHAY 		break;
14658cc72361SWai Yew CHAY 	}
14668cc72361SWai Yew CHAY 
14678cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x06, data);
14688cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x09, data);
14698cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0c, data);
14708cc72361SWai Yew CHAY 	i2c_write(hw, 0x00180080, 0x0f, data);
14718cc72361SWai Yew CHAY 
14728cc72361SWai Yew CHAY 	i2c_lock(hw);
14738cc72361SWai Yew CHAY 
14748cc72361SWai Yew CHAY 	/* unmute outputs */
14758cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw, GPIO);
14768cc72361SWai Yew CHAY 	gpioorg = gpioorg | 0x40;
14778cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
14788cc72361SWai Yew CHAY 
14798cc72361SWai Yew CHAY 	return 0;
14808cc72361SWai Yew CHAY }
14818cc72361SWai Yew CHAY 
14828cc72361SWai Yew CHAY /* ADC operations */
14838cc72361SWai Yew CHAY 
14848cc72361SWai Yew CHAY static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type)
14858cc72361SWai Yew CHAY {
1486514eef9cSTakashi Iwai 	return 0;
14878cc72361SWai Yew CHAY }
14888cc72361SWai Yew CHAY 
14898cc72361SWai Yew CHAY static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type)
14908cc72361SWai Yew CHAY {
1491514eef9cSTakashi Iwai 	u32 data;
14928cc72361SWai Yew CHAY 
14938cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
14948cc72361SWai Yew CHAY 	switch (type) {
14958cc72361SWai Yew CHAY 	case ADC_MICIN:
14968cc72361SWai Yew CHAY 		data = ((data & (0x1<<7)) && (data & (0x1<<8)));
14978cc72361SWai Yew CHAY 		break;
14988cc72361SWai Yew CHAY 	case ADC_LINEIN:
14998cc72361SWai Yew CHAY 		data = (!(data & (0x1<<7)) && (data & (0x1<<8)));
15008cc72361SWai Yew CHAY 		break;
15018cc72361SWai Yew CHAY 	case ADC_NONE: /* Digital I/O */
15028cc72361SWai Yew CHAY 		data = (!(data & (0x1<<8)));
15038cc72361SWai Yew CHAY 		break;
15048cc72361SWai Yew CHAY 	default:
15058cc72361SWai Yew CHAY 		data = 0;
15068cc72361SWai Yew CHAY 	}
15078cc72361SWai Yew CHAY 	return data;
15088cc72361SWai Yew CHAY }
15098cc72361SWai Yew CHAY 
15108cc72361SWai Yew CHAY static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
15118cc72361SWai Yew CHAY {
1512514eef9cSTakashi Iwai 	u32 data;
15138cc72361SWai Yew CHAY 
15148cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15158cc72361SWai Yew CHAY 	switch (type) {
15168cc72361SWai Yew CHAY 	case ADC_MICIN:
15178cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 1 : 0;
15188cc72361SWai Yew CHAY 		break;
15198cc72361SWai Yew CHAY 	case ADC_LINEIN:
15208cc72361SWai Yew CHAY 		data = (data & (0x1 << 7)) ? 0 : 1;
15218cc72361SWai Yew CHAY 		break;
15228cc72361SWai Yew CHAY 	default:
15238cc72361SWai Yew CHAY 		data = 0;
15248cc72361SWai Yew CHAY 	}
15258cc72361SWai Yew CHAY 	return data;
15268cc72361SWai Yew CHAY }
15278cc72361SWai Yew CHAY 
15288cc72361SWai Yew CHAY static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
15298cc72361SWai Yew CHAY {
15309470195aSTakashi Iwai 	switch (hw->model) {
15319470195aSTakashi Iwai 	case CTSB055X:
15328cc72361SWai Yew CHAY 		return is_adc_input_selected_SB055x(hw, type);
15339470195aSTakashi Iwai 	case CTSB073X:
15348cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
153509521d2eSTakashi Iwai 	case CTUAA:
15368cc72361SWai Yew CHAY 		return is_adc_input_selected_hendrix(hw, type);
15379470195aSTakashi Iwai 	default:
15388cc72361SWai Yew CHAY 		return is_adc_input_selected_SBx(hw, type);
15398cc72361SWai Yew CHAY 	}
15408cc72361SWai Yew CHAY }
15418cc72361SWai Yew CHAY 
15428cc72361SWai Yew CHAY static int
15438cc72361SWai Yew CHAY adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost)
15448cc72361SWai Yew CHAY {
1545514eef9cSTakashi Iwai 	u32 data;
15468cc72361SWai Yew CHAY 
15478cc72361SWai Yew CHAY 	/*
15488cc72361SWai Yew CHAY 	 * check and set the following GPIO bits accordingly
15498cc72361SWai Yew CHAY 	 * ADC_Gain		= GPIO2
15508cc72361SWai Yew CHAY 	 * DRM_off		= GPIO3
15518cc72361SWai Yew CHAY 	 * Mic_Pwr_on		= GPIO7
15528cc72361SWai Yew CHAY 	 * Digital_IO_Sel	= GPIO8
15538cc72361SWai Yew CHAY 	 * Mic_Sw		= GPIO9
15548cc72361SWai Yew CHAY 	 * Aux/MicLine_Sw	= GPIO12
15558cc72361SWai Yew CHAY 	 */
15568cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15578cc72361SWai Yew CHAY 	data &= 0xec73;
15588cc72361SWai Yew CHAY 	switch (type) {
15598cc72361SWai Yew CHAY 	case ADC_MICIN:
15608cc72361SWai Yew CHAY 		data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ;
15618cc72361SWai Yew CHAY 		data |= boost ? (0x1<<2) : 0;
15628cc72361SWai Yew CHAY 		break;
15638cc72361SWai Yew CHAY 	case ADC_LINEIN:
15648cc72361SWai Yew CHAY 		data |= (0x1<<8);
15658cc72361SWai Yew CHAY 		break;
15668cc72361SWai Yew CHAY 	case ADC_AUX:
15678cc72361SWai Yew CHAY 		data |= (0x1<<8) | (0x1<<12);
15688cc72361SWai Yew CHAY 		break;
15698cc72361SWai Yew CHAY 	case ADC_NONE:
15708cc72361SWai Yew CHAY 		data |= (0x1<<12);  /* set to digital */
15718cc72361SWai Yew CHAY 		break;
15728cc72361SWai Yew CHAY 	default:
15738cc72361SWai Yew CHAY 		return -1;
15748cc72361SWai Yew CHAY 	}
15758cc72361SWai Yew CHAY 
15768cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
15778cc72361SWai Yew CHAY 
15788cc72361SWai Yew CHAY 	return 0;
15798cc72361SWai Yew CHAY }
15808cc72361SWai Yew CHAY 
15818cc72361SWai Yew CHAY 
15828cc72361SWai Yew CHAY static int
15838cc72361SWai Yew CHAY adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost)
15848cc72361SWai Yew CHAY {
1585514eef9cSTakashi Iwai 	u32 data;
1586514eef9cSTakashi Iwai 	u32 i2c_data;
1587514eef9cSTakashi Iwai 	unsigned int ret;
15888cc72361SWai Yew CHAY 
15898cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
15908cc72361SWai Yew CHAY 		return -1;
15918cc72361SWai Yew CHAY 
15928cc72361SWai Yew CHAY 	do {
15938cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
15948cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
15958cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
15968cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
15978cc72361SWai Yew CHAY 
15988cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
15998cc72361SWai Yew CHAY 	switch (type) {
16008cc72361SWai Yew CHAY 	case ADC_MICIN:
16018cc72361SWai Yew CHAY 		data |= ((0x1 << 7) | (0x1 << 8));
16028cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
16038cc72361SWai Yew CHAY 		break;
16048cc72361SWai Yew CHAY 	case ADC_LINEIN:
16058cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
16068cc72361SWai Yew CHAY 		data |= (0x1 << 8);
16078cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
16088cc72361SWai Yew CHAY 		break;
16098cc72361SWai Yew CHAY 	case ADC_NONE:
16108cc72361SWai Yew CHAY 		data &= ~(0x1 << 8);
16118cc72361SWai Yew CHAY 		i2c_data = 0x0; /* set to Digital */
16128cc72361SWai Yew CHAY 		break;
16138cc72361SWai Yew CHAY 	default:
16148cc72361SWai Yew CHAY 		i2c_lock(hw);
16158cc72361SWai Yew CHAY 		return -1;
16168cc72361SWai Yew CHAY 	}
16178cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
16188cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
16198cc72361SWai Yew CHAY 	if (boost) {
16208cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
16218cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
16228cc72361SWai Yew CHAY 	} else {
16238cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
16248cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
16258cc72361SWai Yew CHAY 	}
16268cc72361SWai Yew CHAY 
16278cc72361SWai Yew CHAY 	i2c_lock(hw);
16288cc72361SWai Yew CHAY 
16298cc72361SWai Yew CHAY 	return 0;
16308cc72361SWai Yew CHAY }
16318cc72361SWai Yew CHAY 
16328cc72361SWai Yew CHAY static int
16338cc72361SWai Yew CHAY adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
16348cc72361SWai Yew CHAY {
1635514eef9cSTakashi Iwai 	u32 data;
1636514eef9cSTakashi Iwai 	u32 i2c_data;
1637514eef9cSTakashi Iwai 	unsigned int ret;
16388cc72361SWai Yew CHAY 
16398cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
16408cc72361SWai Yew CHAY 		return -1;
16418cc72361SWai Yew CHAY 
16428cc72361SWai Yew CHAY 	do {
16438cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
16448cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
16458cc72361SWai Yew CHAY 	/* set i2c access mode as Direct Control */
16468cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);
16478cc72361SWai Yew CHAY 
16488cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, GPIO);
16498cc72361SWai Yew CHAY 	switch (type) {
16508cc72361SWai Yew CHAY 	case ADC_MICIN:
16518cc72361SWai Yew CHAY 		data |= (0x1 << 7);
16528cc72361SWai Yew CHAY 		i2c_data = 0x1;  /* Mic-in */
16538cc72361SWai Yew CHAY 		break;
16548cc72361SWai Yew CHAY 	case ADC_LINEIN:
16558cc72361SWai Yew CHAY 		data &= ~(0x1 << 7);
16568cc72361SWai Yew CHAY 		i2c_data = 0x2; /* Line-in */
16578cc72361SWai Yew CHAY 		break;
16588cc72361SWai Yew CHAY 	default:
16598cc72361SWai Yew CHAY 		i2c_lock(hw);
16608cc72361SWai Yew CHAY 		return -1;
16618cc72361SWai Yew CHAY 	}
16628cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, data);
16638cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
16648cc72361SWai Yew CHAY 	if (boost) {
16658cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
16668cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
16678cc72361SWai Yew CHAY 	} else {
16688cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
16698cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
16708cc72361SWai Yew CHAY 	}
16718cc72361SWai Yew CHAY 
16728cc72361SWai Yew CHAY 	i2c_lock(hw);
16738cc72361SWai Yew CHAY 
16748cc72361SWai Yew CHAY 	return 0;
16758cc72361SWai Yew CHAY }
16768cc72361SWai Yew CHAY 
16778cc72361SWai Yew CHAY static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
16788cc72361SWai Yew CHAY {
16799470195aSTakashi Iwai 	int state = type == ADC_MICIN;
16808cc72361SWai Yew CHAY 
16819470195aSTakashi Iwai 	switch (hw->model) {
16829470195aSTakashi Iwai 	case CTSB055X:
16839470195aSTakashi Iwai 		return adc_input_select_SB055x(hw, type, state);
16849470195aSTakashi Iwai 	case CTSB073X:
16859470195aSTakashi Iwai 		return adc_input_select_hendrix(hw, type, state);
168609521d2eSTakashi Iwai 	case CTUAA:
16879470195aSTakashi Iwai 		return adc_input_select_hendrix(hw, type, state);
16889470195aSTakashi Iwai 	default:
16899470195aSTakashi Iwai 		return adc_input_select_SBx(hw, type, state);
16908cc72361SWai Yew CHAY 	}
16918cc72361SWai Yew CHAY }
16928cc72361SWai Yew CHAY 
16938cc72361SWai Yew CHAY static int adc_init_SB055x(struct hw *hw, int input, int mic20db)
16948cc72361SWai Yew CHAY {
16958cc72361SWai Yew CHAY 	return adc_input_select_SB055x(hw, input, mic20db);
16968cc72361SWai Yew CHAY }
16978cc72361SWai Yew CHAY 
16988cc72361SWai Yew CHAY static int adc_init_SBx(struct hw *hw, int input, int mic20db)
16998cc72361SWai Yew CHAY {
17008cc72361SWai Yew CHAY 	u16 gpioorg;
17018cc72361SWai Yew CHAY 	u16 input_source;
1702514eef9cSTakashi Iwai 	u32 adcdata;
1703514eef9cSTakashi Iwai 	unsigned int ret;
17048cc72361SWai Yew CHAY 
17058cc72361SWai Yew CHAY 	input_source = 0x100;  /* default to analog */
17068cc72361SWai Yew CHAY 	switch (input) {
17078cc72361SWai Yew CHAY 	case ADC_MICIN:
17088cc72361SWai Yew CHAY 		adcdata = 0x1;
17098cc72361SWai Yew CHAY 		input_source = 0x180;  /* set GPIO7 to select Mic */
17108cc72361SWai Yew CHAY 		break;
17118cc72361SWai Yew CHAY 	case ADC_LINEIN:
17128cc72361SWai Yew CHAY 		adcdata = 0x2;
17138cc72361SWai Yew CHAY 		break;
17148cc72361SWai Yew CHAY 	case ADC_VIDEO:
17158cc72361SWai Yew CHAY 		adcdata = 0x4;
17168cc72361SWai Yew CHAY 		break;
17178cc72361SWai Yew CHAY 	case ADC_AUX:
17188cc72361SWai Yew CHAY 		adcdata = 0x8;
17198cc72361SWai Yew CHAY 		break;
17208cc72361SWai Yew CHAY 	case ADC_NONE:
17218cc72361SWai Yew CHAY 		adcdata = 0x0;
17228cc72361SWai Yew CHAY 		input_source = 0x0;  /* set to Digital */
17238cc72361SWai Yew CHAY 		break;
17248cc72361SWai Yew CHAY 	default:
1725514eef9cSTakashi Iwai 		adcdata = 0x0;
17268cc72361SWai Yew CHAY 		break;
17278cc72361SWai Yew CHAY 	}
17288cc72361SWai Yew CHAY 
17298cc72361SWai Yew CHAY 	if (i2c_unlock(hw))
17308cc72361SWai Yew CHAY 		return -1;
17318cc72361SWai Yew CHAY 
17328cc72361SWai Yew CHAY 	do {
17338cc72361SWai Yew CHAY 		ret = hw_read_pci(hw, 0xEC);
17348cc72361SWai Yew CHAY 	} while (!(ret & 0x800000)); /* i2c ready poll */
17358cc72361SWai Yew CHAY 	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
17368cc72361SWai Yew CHAY 
17378cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x0e, 0x08);
17388cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x18, 0x0a);
17398cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x28, 0x86);
17408cc72361SWai Yew CHAY 	i2c_write(hw, 0x001a0080, 0x2a, adcdata);
17418cc72361SWai Yew CHAY 
17428cc72361SWai Yew CHAY 	if (mic20db) {
17438cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xf7);
17448cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xf7);
17458cc72361SWai Yew CHAY 	} else {
17468cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1c, 0xcf);
17478cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x1e, 0xcf);
17488cc72361SWai Yew CHAY 	}
17498cc72361SWai Yew CHAY 
17508cc72361SWai Yew CHAY 	if (!(hw_read_20kx(hw, ID0) & 0x100))
17518cc72361SWai Yew CHAY 		i2c_write(hw, 0x001a0080, 0x16, 0x26);
17528cc72361SWai Yew CHAY 
17538cc72361SWai Yew CHAY 	i2c_lock(hw);
17548cc72361SWai Yew CHAY 
17558cc72361SWai Yew CHAY 	gpioorg = (u16)hw_read_20kx(hw,  GPIO);
17568cc72361SWai Yew CHAY 	gpioorg &= 0xfe7f;
17578cc72361SWai Yew CHAY 	gpioorg |= input_source;
17588cc72361SWai Yew CHAY 	hw_write_20kx(hw, GPIO, gpioorg);
17598cc72361SWai Yew CHAY 
17608cc72361SWai Yew CHAY 	return 0;
17618cc72361SWai Yew CHAY }
17628cc72361SWai Yew CHAY 
17638cc72361SWai Yew CHAY static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
17648cc72361SWai Yew CHAY {
17659470195aSTakashi Iwai 	if (hw->model == CTSB055X)
17669470195aSTakashi Iwai 		return adc_init_SB055x(hw, info->input, info->mic20db);
17679470195aSTakashi Iwai 	else
17689470195aSTakashi Iwai 		return adc_init_SBx(hw, info->input, info->mic20db);
17698cc72361SWai Yew CHAY }
17708cc72361SWai Yew CHAY 
1771b028b818SHarry Butterworth static struct capabilities hw_capabilities(struct hw *hw)
17728cc72361SWai Yew CHAY {
1773b028b818SHarry Butterworth 	struct capabilities cap;
1774b028b818SHarry Butterworth 
17758cc72361SWai Yew CHAY 	/* SB073x and Vista compatible cards have no digit IO switch */
1776b028b818SHarry Butterworth 	cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
1777b028b818SHarry Butterworth 	cap.dedicated_mic = 0;
1778b028b818SHarry Butterworth 	cap.output_switch = 0;
1779b028b818SHarry Butterworth 	cap.mic_source_switch = 0;
17808cc72361SWai Yew CHAY 
1781b028b818SHarry Butterworth 	return cap;
178255309216SHarry Butterworth }
178355309216SHarry Butterworth 
178442a0b318STakashi Iwai #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
178542a0b318STakashi Iwai 
17868cc72361SWai Yew CHAY #define UAA_CFG_PWRSTATUS	0x44
17878cc72361SWai Yew CHAY #define UAA_CFG_SPACE_FLAG	0xA0
17888cc72361SWai Yew CHAY #define UAA_CORE_CHANGE		0x3FFC
17898cc72361SWai Yew CHAY static int uaa_to_xfi(struct pci_dev *pci)
17908cc72361SWai Yew CHAY {
17918cc72361SWai Yew CHAY 	unsigned int bar0, bar1, bar2, bar3, bar4, bar5;
17928cc72361SWai Yew CHAY 	unsigned int cmd, irq, cl_size, l_timer, pwr;
1793514eef9cSTakashi Iwai 	unsigned int is_uaa;
17948cc72361SWai Yew CHAY 	unsigned int data[4] = {0};
17958cc72361SWai Yew CHAY 	unsigned int io_base;
17967a7686bdSSudip Mukherjee 	void __iomem *mem_base;
1797514eef9cSTakashi Iwai 	int i;
179842a0b318STakashi Iwai 	const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
179942a0b318STakashi Iwai 	const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
180042a0b318STakashi Iwai 	const u32 CTLF = CTLBITS('C', 'T', 'L', 'F');
180142a0b318STakashi Iwai 	const u32 CTLi = CTLBITS('C', 'T', 'L', 'i');
180242a0b318STakashi Iwai 	const u32 CTLA = CTLBITS('C', 'T', 'L', 'A');
180342a0b318STakashi Iwai 	const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z');
180442a0b318STakashi Iwai 	const u32 CTLL = CTLBITS('C', 'T', 'L', 'L');
18058cc72361SWai Yew CHAY 
18068cc72361SWai Yew CHAY 	/* By default, Hendrix card UAA Bar0 should be using memory... */
18078cc72361SWai Yew CHAY 	io_base = pci_resource_start(pci, 0);
18088cc72361SWai Yew CHAY 	mem_base = ioremap(io_base, pci_resource_len(pci, 0));
180935ebf6e7STakashi Iwai 	if (!mem_base)
18108cc72361SWai Yew CHAY 		return -ENOENT;
18118cc72361SWai Yew CHAY 
18128cc72361SWai Yew CHAY 	/* Read current mode from Mode Change Register */
18138cc72361SWai Yew CHAY 	for (i = 0; i < 4; i++)
18148cc72361SWai Yew CHAY 		data[i] = readl(mem_base + UAA_CORE_CHANGE);
18158cc72361SWai Yew CHAY 
18168cc72361SWai Yew CHAY 	/* Determine current mode... */
18178cc72361SWai Yew CHAY 	if (data[0] == CTLA) {
18188cc72361SWai Yew CHAY 		is_uaa = ((data[1] == CTLZ && data[2] == CTLL
18198cc72361SWai Yew CHAY 			  && data[3] == CTLA) || (data[1] == CTLA
18208cc72361SWai Yew CHAY 			  && data[2] == CTLZ && data[3] == CTLL));
18218cc72361SWai Yew CHAY 	} else if (data[0] == CTLZ) {
18228cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLL
18238cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLA);
18248cc72361SWai Yew CHAY 	} else if (data[0] == CTLL) {
18258cc72361SWai Yew CHAY 		is_uaa = (data[1] == CTLA
18268cc72361SWai Yew CHAY 				&& data[2] == CTLA && data[3] == CTLZ);
18278cc72361SWai Yew CHAY 	} else {
18288cc72361SWai Yew CHAY 		is_uaa = 0;
18298cc72361SWai Yew CHAY 	}
18308cc72361SWai Yew CHAY 
18318cc72361SWai Yew CHAY 	if (!is_uaa) {
18328cc72361SWai Yew CHAY 		/* Not in UAA mode currently. Return directly. */
18338cc72361SWai Yew CHAY 		iounmap(mem_base);
18348cc72361SWai Yew CHAY 		return 0;
18358cc72361SWai Yew CHAY 	}
18368cc72361SWai Yew CHAY 
18378cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0);
18388cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1);
18398cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2);
18408cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3);
18418cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4);
18428cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5);
18438cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq);
18448cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size);
18458cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer);
18468cc72361SWai Yew CHAY 	pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr);
18478cc72361SWai Yew CHAY 	pci_read_config_dword(pci, PCI_COMMAND, &cmd);
18488cc72361SWai Yew CHAY 
18498cc72361SWai Yew CHAY 	/* Set up X-Fi core PCI configuration space. */
18508cc72361SWai Yew CHAY 	/* Switch to X-Fi config space with BAR0 exposed. */
18518cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321);
18528cc72361SWai Yew CHAY 	/* Copy UAA's BAR5 into X-Fi BAR0 */
18538cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5);
18548cc72361SWai Yew CHAY 	/* Switch to X-Fi config space without BAR0 exposed. */
18558cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678);
18568cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1);
18578cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2);
18588cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3);
18598cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4);
18608cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq);
18618cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size);
18628cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer);
18638cc72361SWai Yew CHAY 	pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr);
18648cc72361SWai Yew CHAY 	pci_write_config_dword(pci, PCI_COMMAND, cmd);
18658cc72361SWai Yew CHAY 
18668cc72361SWai Yew CHAY 	/* Switch to X-Fi mode */
18678cc72361SWai Yew CHAY 	writel(CTLX, (mem_base + UAA_CORE_CHANGE));
18688cc72361SWai Yew CHAY 	writel(CTL_, (mem_base + UAA_CORE_CHANGE));
18698cc72361SWai Yew CHAY 	writel(CTLF, (mem_base + UAA_CORE_CHANGE));
18708cc72361SWai Yew CHAY 	writel(CTLi, (mem_base + UAA_CORE_CHANGE));
18718cc72361SWai Yew CHAY 
18728cc72361SWai Yew CHAY 	iounmap(mem_base);
18738cc72361SWai Yew CHAY 
18748cc72361SWai Yew CHAY 	return 0;
18758cc72361SWai Yew CHAY }
18768cc72361SWai Yew CHAY 
1877b7bbf876STakashi Iwai static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
1878b7bbf876STakashi Iwai {
1879b7bbf876STakashi Iwai 	struct hw *hw = dev_id;
1880b7bbf876STakashi Iwai 	unsigned int status;
1881b7bbf876STakashi Iwai 
1882b7bbf876STakashi Iwai 	status = hw_read_20kx(hw, GIP);
1883b7bbf876STakashi Iwai 	if (!status)
1884b7bbf876STakashi Iwai 		return IRQ_NONE;
1885b7bbf876STakashi Iwai 
1886b7bbf876STakashi Iwai 	if (hw->irq_callback)
1887b7bbf876STakashi Iwai 		hw->irq_callback(hw->irq_callback_data, status);
1888b7bbf876STakashi Iwai 
1889b7bbf876STakashi Iwai 	hw_write_20kx(hw, GIP, status);
1890b7bbf876STakashi Iwai 	return IRQ_HANDLED;
1891b7bbf876STakashi Iwai }
1892b7bbf876STakashi Iwai 
18938cc72361SWai Yew CHAY static int hw_card_start(struct hw *hw)
18948cc72361SWai Yew CHAY {
1895514eef9cSTakashi Iwai 	int err;
18968cc72361SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
189715c75b09STakashi Iwai 	const unsigned int dma_bits = BITS_PER_LONG;
18988cc72361SWai Yew CHAY 
18998cc72361SWai Yew CHAY 	err = pci_enable_device(pci);
19008cc72361SWai Yew CHAY 	if (err < 0)
19018cc72361SWai Yew CHAY 		return err;
19028cc72361SWai Yew CHAY 
19038cc72361SWai Yew CHAY 	/* Set DMA transfer mask */
1904669f65eaSTakashi Iwai 	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(dma_bits)))
1905669f65eaSTakashi Iwai 		dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
19068cc72361SWai Yew CHAY 
190729959a09SWai Yew CHAY 	if (!hw->io_base) {
19088cc72361SWai Yew CHAY 		err = pci_request_regions(pci, "XFi");
19098cc72361SWai Yew CHAY 		if (err < 0)
19108cc72361SWai Yew CHAY 			goto error1;
19118cc72361SWai Yew CHAY 
191229959a09SWai Yew CHAY 		if (hw->model == CTUAA)
191329959a09SWai Yew CHAY 			hw->io_base = pci_resource_start(pci, 5);
191429959a09SWai Yew CHAY 		else
191529959a09SWai Yew CHAY 			hw->io_base = pci_resource_start(pci, 0);
191629959a09SWai Yew CHAY 
191729959a09SWai Yew CHAY 	}
191829959a09SWai Yew CHAY 
1919*1693e265SJulia Lawall 	/* Switch to X-Fi mode from UAA mode if needed */
192009521d2eSTakashi Iwai 	if (hw->model == CTUAA) {
19218cc72361SWai Yew CHAY 		err = uaa_to_xfi(pci);
19228cc72361SWai Yew CHAY 		if (err)
19238cc72361SWai Yew CHAY 			goto error2;
19248cc72361SWai Yew CHAY 
19258cc72361SWai Yew CHAY 	}
19268cc72361SWai Yew CHAY 
192729959a09SWai Yew CHAY 	if (hw->irq < 0) {
1928b7bbf876STakashi Iwai 		err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
1929934c2b6dSTakashi Iwai 				  KBUILD_MODNAME, hw);
1930b7bbf876STakashi Iwai 		if (err < 0) {
19310cae90a9SSudip Mukherjee 			dev_err(hw->card->dev,
19320cae90a9SSudip Mukherjee 				"XFi: Cannot get irq %d\n", pci->irq);
19338cc72361SWai Yew CHAY 			goto error2;
19348cc72361SWai Yew CHAY 		}
19358cc72361SWai Yew CHAY 		hw->irq = pci->irq;
19365e0890c1STakashi Iwai 		hw->card->sync_irq = hw->irq;
193729959a09SWai Yew CHAY 	}
19388cc72361SWai Yew CHAY 
19398cc72361SWai Yew CHAY 	pci_set_master(pci);
19408cc72361SWai Yew CHAY 
19418cc72361SWai Yew CHAY 	return 0;
19428cc72361SWai Yew CHAY 
19438cc72361SWai Yew CHAY error2:
19448cc72361SWai Yew CHAY 	pci_release_regions(pci);
19458cc72361SWai Yew CHAY 	hw->io_base = 0;
19468cc72361SWai Yew CHAY error1:
19478cc72361SWai Yew CHAY 	pci_disable_device(pci);
19488cc72361SWai Yew CHAY 	return err;
19498cc72361SWai Yew CHAY }
19508cc72361SWai Yew CHAY 
19518cc72361SWai Yew CHAY static int hw_card_stop(struct hw *hw)
19528cc72361SWai Yew CHAY {
195329959a09SWai Yew CHAY 	unsigned int data;
195429959a09SWai Yew CHAY 
195529959a09SWai Yew CHAY 	/* disable transport bus master and queueing of request */
195629959a09SWai Yew CHAY 	hw_write_20kx(hw, TRNCTL, 0x00);
195729959a09SWai Yew CHAY 
195829959a09SWai Yew CHAY 	/* disable pll */
195929959a09SWai Yew CHAY 	data = hw_read_20kx(hw, PLLCTL);
196029959a09SWai Yew CHAY 	hw_write_20kx(hw, PLLCTL, (data & (~(0x0F<<12))));
196129959a09SWai Yew CHAY 
19628cc72361SWai Yew CHAY 	return 0;
19638cc72361SWai Yew CHAY }
19648cc72361SWai Yew CHAY 
19658cc72361SWai Yew CHAY static int hw_card_shutdown(struct hw *hw)
19668cc72361SWai Yew CHAY {
19678cc72361SWai Yew CHAY 	if (hw->irq >= 0)
19688cc72361SWai Yew CHAY 		free_irq(hw->irq, hw);
19698cc72361SWai Yew CHAY 
19708cc72361SWai Yew CHAY 	hw->irq	= -1;
19717a7686bdSSudip Mukherjee 	iounmap(hw->mem_base);
19727a7686bdSSudip Mukherjee 	hw->mem_base = NULL;
19738cc72361SWai Yew CHAY 
19748cc72361SWai Yew CHAY 	if (hw->io_base)
19758cc72361SWai Yew CHAY 		pci_release_regions(hw->pci);
19768cc72361SWai Yew CHAY 
19778cc72361SWai Yew CHAY 	hw->io_base = 0;
19788cc72361SWai Yew CHAY 
19798cc72361SWai Yew CHAY 	pci_disable_device(hw->pci);
19808cc72361SWai Yew CHAY 
19818cc72361SWai Yew CHAY 	return 0;
19828cc72361SWai Yew CHAY }
19838cc72361SWai Yew CHAY 
19848cc72361SWai Yew CHAY static int hw_card_init(struct hw *hw, struct card_conf *info)
19858cc72361SWai Yew CHAY {
19868cc72361SWai Yew CHAY 	int err;
19878cc72361SWai Yew CHAY 	unsigned int gctl;
1988514eef9cSTakashi Iwai 	u32 data;
19898cc72361SWai Yew CHAY 	struct dac_conf dac_info = {0};
19908cc72361SWai Yew CHAY 	struct adc_conf adc_info = {0};
19918cc72361SWai Yew CHAY 	struct daio_conf daio_info = {0};
19928cc72361SWai Yew CHAY 	struct trn_conf trn_info = {0};
19938cc72361SWai Yew CHAY 
19948cc72361SWai Yew CHAY 	/* Get PCI io port base address and do Hendrix switch if needed. */
19958cc72361SWai Yew CHAY 	err = hw_card_start(hw);
19968cc72361SWai Yew CHAY 	if (err)
19978cc72361SWai Yew CHAY 		return err;
19988cc72361SWai Yew CHAY 
19998cc72361SWai Yew CHAY 	/* PLL init */
20008cc72361SWai Yew CHAY 	err = hw_pll_init(hw, info->rsr);
20018cc72361SWai Yew CHAY 	if (err < 0)
20028cc72361SWai Yew CHAY 		return err;
20038cc72361SWai Yew CHAY 
20048cc72361SWai Yew CHAY 	/* kick off auto-init */
20058cc72361SWai Yew CHAY 	err = hw_auto_init(hw);
20068cc72361SWai Yew CHAY 	if (err < 0)
20078cc72361SWai Yew CHAY 		return err;
20088cc72361SWai Yew CHAY 
20098cc72361SWai Yew CHAY 	/* Enable audio ring */
20108cc72361SWai Yew CHAY 	gctl = hw_read_20kx(hw, GCTL);
20118cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_EAC, 1);
20128cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_DBP, 1);
20138cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_TBP, 1);
20148cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_FBP, 1);
20158cc72361SWai Yew CHAY 	set_field(&gctl, GCTL_ET, 1);
20168cc72361SWai Yew CHAY 	hw_write_20kx(hw, GCTL, gctl);
20178cc72361SWai Yew CHAY 	mdelay(10);
20188cc72361SWai Yew CHAY 
20198cc72361SWai Yew CHAY 	/* Reset all global pending interrupts */
20208cc72361SWai Yew CHAY 	hw_write_20kx(hw, GIE, 0);
20218cc72361SWai Yew CHAY 	/* Reset all SRC pending interrupts */
20228cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCIP, 0);
202308fd8325SJia-Ju Bai 	msleep(30);
20248cc72361SWai Yew CHAY 
20258cc72361SWai Yew CHAY 	/* Detect the card ID and configure GPIO accordingly. */
20269470195aSTakashi Iwai 	switch (hw->model) {
20279470195aSTakashi Iwai 	case CTSB055X:
20288cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x13fe);
20299470195aSTakashi Iwai 		break;
20309470195aSTakashi Iwai 	case CTSB073X:
20318cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00e6);
20329470195aSTakashi Iwai 		break;
203309521d2eSTakashi Iwai 	case CTUAA:
20348cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x00c2);
20359470195aSTakashi Iwai 		break;
20369470195aSTakashi Iwai 	default:
20378cc72361SWai Yew CHAY 		hw_write_20kx(hw, GPIOCTL, 0x01e6);
20389470195aSTakashi Iwai 		break;
20398cc72361SWai Yew CHAY 	}
20408cc72361SWai Yew CHAY 
20418cc72361SWai Yew CHAY 	trn_info.vm_pgt_phys = info->vm_pgt_phys;
20428cc72361SWai Yew CHAY 	err = hw_trn_init(hw, &trn_info);
20438cc72361SWai Yew CHAY 	if (err < 0)
20448cc72361SWai Yew CHAY 		return err;
20458cc72361SWai Yew CHAY 
20468cc72361SWai Yew CHAY 	daio_info.msr = info->msr;
20478cc72361SWai Yew CHAY 	err = hw_daio_init(hw, &daio_info);
20488cc72361SWai Yew CHAY 	if (err < 0)
20498cc72361SWai Yew CHAY 		return err;
20508cc72361SWai Yew CHAY 
20518cc72361SWai Yew CHAY 	dac_info.msr = info->msr;
20528cc72361SWai Yew CHAY 	err = hw_dac_init(hw, &dac_info);
20538cc72361SWai Yew CHAY 	if (err < 0)
20548cc72361SWai Yew CHAY 		return err;
20558cc72361SWai Yew CHAY 
20568cc72361SWai Yew CHAY 	adc_info.msr = info->msr;
20578cc72361SWai Yew CHAY 	adc_info.input = ADC_LINEIN;
20588cc72361SWai Yew CHAY 	adc_info.mic20db = 0;
20598cc72361SWai Yew CHAY 	err = hw_adc_init(hw, &adc_info);
20608cc72361SWai Yew CHAY 	if (err < 0)
20618cc72361SWai Yew CHAY 		return err;
20628cc72361SWai Yew CHAY 
20638cc72361SWai Yew CHAY 	data = hw_read_20kx(hw, SRCMCTL);
20648cc72361SWai Yew CHAY 	data |= 0x1; /* Enables input from the audio ring */
20658cc72361SWai Yew CHAY 	hw_write_20kx(hw, SRCMCTL, data);
20668cc72361SWai Yew CHAY 
20678cc72361SWai Yew CHAY 	return 0;
20688cc72361SWai Yew CHAY }
20698cc72361SWai Yew CHAY 
2070c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
207168cb2b55STakashi Iwai static int hw_suspend(struct hw *hw)
207229959a09SWai Yew CHAY {
207329959a09SWai Yew CHAY 	struct pci_dev *pci = hw->pci;
207429959a09SWai Yew CHAY 
207529959a09SWai Yew CHAY 	hw_card_stop(hw);
207629959a09SWai Yew CHAY 
207729959a09SWai Yew CHAY 	if (hw->model == CTUAA) {
207829959a09SWai Yew CHAY 		/* Switch to UAA config space. */
207929959a09SWai Yew CHAY 		pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
208029959a09SWai Yew CHAY 	}
208129959a09SWai Yew CHAY 
208229959a09SWai Yew CHAY 	return 0;
208329959a09SWai Yew CHAY }
208429959a09SWai Yew CHAY 
208529959a09SWai Yew CHAY static int hw_resume(struct hw *hw, struct card_conf *info)
208629959a09SWai Yew CHAY {
208729959a09SWai Yew CHAY 	/* Re-initialize card hardware. */
208829959a09SWai Yew CHAY 	return hw_card_init(hw, info);
208929959a09SWai Yew CHAY }
209029959a09SWai Yew CHAY #endif
209129959a09SWai Yew CHAY 
20928cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg)
20938cc72361SWai Yew CHAY {
20948cc72361SWai Yew CHAY 	u32 value;
20958cc72361SWai Yew CHAY 	unsigned long flags;
20968cc72361SWai Yew CHAY 
20978cc72361SWai Yew CHAY 	spin_lock_irqsave(
20988cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
20998cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
21008cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x4);
21018cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21028cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21038cc72361SWai Yew CHAY 
21048cc72361SWai Yew CHAY 	return value;
21058cc72361SWai Yew CHAY }
21068cc72361SWai Yew CHAY 
21078cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
21088cc72361SWai Yew CHAY {
21098cc72361SWai Yew CHAY 	unsigned long flags;
21108cc72361SWai Yew CHAY 
21118cc72361SWai Yew CHAY 	spin_lock_irqsave(
21128cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21138cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x0);
21148cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x4);
21158cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21168cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
21178cc72361SWai Yew CHAY 
21188cc72361SWai Yew CHAY }
21198cc72361SWai Yew CHAY 
21208cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg)
21218cc72361SWai Yew CHAY {
21228cc72361SWai Yew CHAY 	u32 value;
21238cc72361SWai Yew CHAY 	unsigned long flags;
21248cc72361SWai Yew CHAY 
21258cc72361SWai Yew CHAY 	spin_lock_irqsave(
21268cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21278cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
21288cc72361SWai Yew CHAY 	value = inl(hw->io_base + 0x14);
21298cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21308cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21318cc72361SWai Yew CHAY 
21328cc72361SWai Yew CHAY 	return value;
21338cc72361SWai Yew CHAY }
21348cc72361SWai Yew CHAY 
21358cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
21368cc72361SWai Yew CHAY {
21378cc72361SWai Yew CHAY 	unsigned long flags;
21388cc72361SWai Yew CHAY 
21398cc72361SWai Yew CHAY 	spin_lock_irqsave(
21408cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21418cc72361SWai Yew CHAY 	outl(reg, hw->io_base + 0x10);
21428cc72361SWai Yew CHAY 	outl(data, hw->io_base + 0x14);
21438cc72361SWai Yew CHAY 	spin_unlock_irqrestore(
21448cc72361SWai Yew CHAY 		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
21458cc72361SWai Yew CHAY }
21468cc72361SWai Yew CHAY 
2147faa11909SBhumika Goyal static const struct hw ct20k1_preset = {
21482a36f67fSTakashi Iwai 	.irq = -1,
21492a36f67fSTakashi Iwai 
21502a36f67fSTakashi Iwai 	.card_init = hw_card_init,
21512a36f67fSTakashi Iwai 	.card_stop = hw_card_stop,
21522a36f67fSTakashi Iwai 	.pll_init = hw_pll_init,
21532a36f67fSTakashi Iwai 	.is_adc_source_selected = hw_is_adc_input_selected,
21542a36f67fSTakashi Iwai 	.select_adc_source = hw_adc_input_select,
2155b028b818SHarry Butterworth 	.capabilities = hw_capabilities,
2156c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
215729959a09SWai Yew CHAY 	.suspend = hw_suspend,
215829959a09SWai Yew CHAY 	.resume = hw_resume,
215929959a09SWai Yew CHAY #endif
21602a36f67fSTakashi Iwai 
21612a36f67fSTakashi Iwai 	.src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
21622a36f67fSTakashi Iwai 	.src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
21632a36f67fSTakashi Iwai 	.src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
21642a36f67fSTakashi Iwai 	.src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
21652a36f67fSTakashi Iwai 	.src_set_state = src_set_state,
21662a36f67fSTakashi Iwai 	.src_set_bm = src_set_bm,
21672a36f67fSTakashi Iwai 	.src_set_rsr = src_set_rsr,
21682a36f67fSTakashi Iwai 	.src_set_sf = src_set_sf,
21692a36f67fSTakashi Iwai 	.src_set_wr = src_set_wr,
21702a36f67fSTakashi Iwai 	.src_set_pm = src_set_pm,
21712a36f67fSTakashi Iwai 	.src_set_rom = src_set_rom,
21722a36f67fSTakashi Iwai 	.src_set_vo = src_set_vo,
21732a36f67fSTakashi Iwai 	.src_set_st = src_set_st,
21742a36f67fSTakashi Iwai 	.src_set_ie = src_set_ie,
21752a36f67fSTakashi Iwai 	.src_set_ilsz = src_set_ilsz,
21762a36f67fSTakashi Iwai 	.src_set_bp = src_set_bp,
21772a36f67fSTakashi Iwai 	.src_set_cisz = src_set_cisz,
21782a36f67fSTakashi Iwai 	.src_set_ca = src_set_ca,
21792a36f67fSTakashi Iwai 	.src_set_sa = src_set_sa,
21802a36f67fSTakashi Iwai 	.src_set_la = src_set_la,
21812a36f67fSTakashi Iwai 	.src_set_pitch = src_set_pitch,
21822a36f67fSTakashi Iwai 	.src_set_dirty = src_set_dirty,
21832a36f67fSTakashi Iwai 	.src_set_clear_zbufs = src_set_clear_zbufs,
21842a36f67fSTakashi Iwai 	.src_set_dirty_all = src_set_dirty_all,
21852a36f67fSTakashi Iwai 	.src_commit_write = src_commit_write,
21862a36f67fSTakashi Iwai 	.src_get_ca = src_get_ca,
21872a36f67fSTakashi Iwai 	.src_get_dirty = src_get_dirty,
21882a36f67fSTakashi Iwai 	.src_dirty_conj_mask = src_dirty_conj_mask,
21892a36f67fSTakashi Iwai 	.src_mgr_enbs_src = src_mgr_enbs_src,
21902a36f67fSTakashi Iwai 	.src_mgr_enb_src = src_mgr_enb_src,
21912a36f67fSTakashi Iwai 	.src_mgr_dsb_src = src_mgr_dsb_src,
21922a36f67fSTakashi Iwai 	.src_mgr_commit_write = src_mgr_commit_write,
21932a36f67fSTakashi Iwai 
21942a36f67fSTakashi Iwai 	.srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
21952a36f67fSTakashi Iwai 	.srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
21962a36f67fSTakashi Iwai 	.srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
21972a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
21982a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
21992a36f67fSTakashi Iwai 	.srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
22002a36f67fSTakashi Iwai 	.srcimp_mgr_commit_write = srcimp_mgr_commit_write,
22012a36f67fSTakashi Iwai 
22022a36f67fSTakashi Iwai 	.amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
22032a36f67fSTakashi Iwai 	.amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
22042a36f67fSTakashi Iwai 	.amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
22052a36f67fSTakashi Iwai 	.amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
22062a36f67fSTakashi Iwai 	.amixer_set_mode = amixer_set_mode,
22072a36f67fSTakashi Iwai 	.amixer_set_iv = amixer_set_iv,
22082a36f67fSTakashi Iwai 	.amixer_set_x = amixer_set_x,
22092a36f67fSTakashi Iwai 	.amixer_set_y = amixer_set_y,
22102a36f67fSTakashi Iwai 	.amixer_set_sadr = amixer_set_sadr,
22112a36f67fSTakashi Iwai 	.amixer_set_se = amixer_set_se,
22122a36f67fSTakashi Iwai 	.amixer_set_dirty = amixer_set_dirty,
22132a36f67fSTakashi Iwai 	.amixer_set_dirty_all = amixer_set_dirty_all,
22142a36f67fSTakashi Iwai 	.amixer_commit_write = amixer_commit_write,
22152a36f67fSTakashi Iwai 	.amixer_get_y = amixer_get_y,
22162a36f67fSTakashi Iwai 	.amixer_get_dirty = amixer_get_dirty,
22172a36f67fSTakashi Iwai 
22182a36f67fSTakashi Iwai 	.dai_get_ctrl_blk = dai_get_ctrl_blk,
22192a36f67fSTakashi Iwai 	.dai_put_ctrl_blk = dai_put_ctrl_blk,
22202a36f67fSTakashi Iwai 	.dai_srt_set_srco = dai_srt_set_srcr,
22212a36f67fSTakashi Iwai 	.dai_srt_set_srcm = dai_srt_set_srcl,
22222a36f67fSTakashi Iwai 	.dai_srt_set_rsr = dai_srt_set_rsr,
22232a36f67fSTakashi Iwai 	.dai_srt_set_drat = dai_srt_set_drat,
22242a36f67fSTakashi Iwai 	.dai_srt_set_ec = dai_srt_set_ec,
22252a36f67fSTakashi Iwai 	.dai_srt_set_et = dai_srt_set_et,
22262a36f67fSTakashi Iwai 	.dai_commit_write = dai_commit_write,
22272a36f67fSTakashi Iwai 
22282a36f67fSTakashi Iwai 	.dao_get_ctrl_blk = dao_get_ctrl_blk,
22292a36f67fSTakashi Iwai 	.dao_put_ctrl_blk = dao_put_ctrl_blk,
22302a36f67fSTakashi Iwai 	.dao_set_spos = dao_set_spos,
22312a36f67fSTakashi Iwai 	.dao_commit_write = dao_commit_write,
22322a36f67fSTakashi Iwai 	.dao_get_spos = dao_get_spos,
22332a36f67fSTakashi Iwai 
22342a36f67fSTakashi Iwai 	.daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
22352a36f67fSTakashi Iwai 	.daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
22362a36f67fSTakashi Iwai 	.daio_mgr_enb_dai = daio_mgr_enb_dai,
22372a36f67fSTakashi Iwai 	.daio_mgr_dsb_dai = daio_mgr_dsb_dai,
22382a36f67fSTakashi Iwai 	.daio_mgr_enb_dao = daio_mgr_enb_dao,
22392a36f67fSTakashi Iwai 	.daio_mgr_dsb_dao = daio_mgr_dsb_dao,
22402a36f67fSTakashi Iwai 	.daio_mgr_dao_init = daio_mgr_dao_init,
22412a36f67fSTakashi Iwai 	.daio_mgr_set_imaparc = daio_mgr_set_imaparc,
22422a36f67fSTakashi Iwai 	.daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
22432a36f67fSTakashi Iwai 	.daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
22442a36f67fSTakashi Iwai 	.daio_mgr_commit_write = daio_mgr_commit_write,
22452a36f67fSTakashi Iwai 
22462a36f67fSTakashi Iwai 	.set_timer_irq = set_timer_irq,
22472a36f67fSTakashi Iwai 	.set_timer_tick = set_timer_tick,
224854de6bc8STakashi Iwai 	.get_wc = get_wc,
22492a36f67fSTakashi Iwai };
22502a36f67fSTakashi Iwai 
2251e23e7a14SBill Pemberton int create_20k1_hw_obj(struct hw **rhw)
22528cc72361SWai Yew CHAY {
22538cc72361SWai Yew CHAY 	struct hw20k1 *hw20k1;
22548cc72361SWai Yew CHAY 
22558cc72361SWai Yew CHAY 	*rhw = NULL;
22568cc72361SWai Yew CHAY 	hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
225735ebf6e7STakashi Iwai 	if (!hw20k1)
22588cc72361SWai Yew CHAY 		return -ENOMEM;
22598cc72361SWai Yew CHAY 
22608cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_20k1_lock);
22618cc72361SWai Yew CHAY 	spin_lock_init(&hw20k1->reg_pci_lock);
22628cc72361SWai Yew CHAY 
22632a36f67fSTakashi Iwai 	hw20k1->hw = ct20k1_preset;
22648cc72361SWai Yew CHAY 
22652a36f67fSTakashi Iwai 	*rhw = &hw20k1->hw;
22668cc72361SWai Yew CHAY 
22678cc72361SWai Yew CHAY 	return 0;
22688cc72361SWai Yew CHAY }
22698cc72361SWai Yew CHAY 
22708cc72361SWai Yew CHAY int destroy_20k1_hw_obj(struct hw *hw)
22718cc72361SWai Yew CHAY {
22728cc72361SWai Yew CHAY 	if (hw->io_base)
22738cc72361SWai Yew CHAY 		hw_card_shutdown(hw);
22748cc72361SWai Yew CHAY 
22758cc72361SWai Yew CHAY 	kfree(container_of(hw, struct hw20k1, hw));
22768cc72361SWai Yew CHAY 	return 0;
22778cc72361SWai Yew CHAY }
2278