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