162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * @File cthw20k2.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * @Brief 862306a36Sopenharmony_ci * This file contains the implementation of hardware access method for 20k2. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * @Author Liu Chun 1162306a36Sopenharmony_ci * @Date May 14 2008 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/pci.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/string.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci#include "cthw20k2.h" 2362306a36Sopenharmony_ci#include "ct20k2reg.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct hw20k2 { 2662306a36Sopenharmony_ci struct hw hw; 2762306a36Sopenharmony_ci /* for i2c */ 2862306a36Sopenharmony_ci unsigned char dev_id; 2962306a36Sopenharmony_ci unsigned char addr_size; 3062306a36Sopenharmony_ci unsigned char data_size; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci int mic_source; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic u32 hw_read_20kx(struct hw *hw, u32 reg); 3662306a36Sopenharmony_cistatic void hw_write_20kx(struct hw *hw, u32 reg, u32 data); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Type definition block. 4062306a36Sopenharmony_ci * The layout of control structures can be directly applied on 20k2 chip. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* 4462306a36Sopenharmony_ci * SRC control block definitions. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* SRC resource control block */ 4862306a36Sopenharmony_ci#define SRCCTL_STATE 0x00000007 4962306a36Sopenharmony_ci#define SRCCTL_BM 0x00000008 5062306a36Sopenharmony_ci#define SRCCTL_RSR 0x00000030 5162306a36Sopenharmony_ci#define SRCCTL_SF 0x000001C0 5262306a36Sopenharmony_ci#define SRCCTL_WR 0x00000200 5362306a36Sopenharmony_ci#define SRCCTL_PM 0x00000400 5462306a36Sopenharmony_ci#define SRCCTL_ROM 0x00001800 5562306a36Sopenharmony_ci#define SRCCTL_VO 0x00002000 5662306a36Sopenharmony_ci#define SRCCTL_ST 0x00004000 5762306a36Sopenharmony_ci#define SRCCTL_IE 0x00008000 5862306a36Sopenharmony_ci#define SRCCTL_ILSZ 0x000F0000 5962306a36Sopenharmony_ci#define SRCCTL_BP 0x00100000 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define SRCCCR_CISZ 0x000007FF 6262306a36Sopenharmony_ci#define SRCCCR_CWA 0x001FF800 6362306a36Sopenharmony_ci#define SRCCCR_D 0x00200000 6462306a36Sopenharmony_ci#define SRCCCR_RS 0x01C00000 6562306a36Sopenharmony_ci#define SRCCCR_NAL 0x3E000000 6662306a36Sopenharmony_ci#define SRCCCR_RA 0xC0000000 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define SRCCA_CA 0x0FFFFFFF 6962306a36Sopenharmony_ci#define SRCCA_RS 0xE0000000 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define SRCSA_SA 0x0FFFFFFF 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define SRCLA_LA 0x0FFFFFFF 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Mixer Parameter Ring ram Low and Hight register. 7662306a36Sopenharmony_ci * Fixed-point value in 8.24 format for parameter channel */ 7762306a36Sopenharmony_ci#define MPRLH_PITCH 0xFFFFFFFF 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* SRC resource register dirty flags */ 8062306a36Sopenharmony_ciunion src_dirty { 8162306a36Sopenharmony_ci struct { 8262306a36Sopenharmony_ci u16 ctl:1; 8362306a36Sopenharmony_ci u16 ccr:1; 8462306a36Sopenharmony_ci u16 sa:1; 8562306a36Sopenharmony_ci u16 la:1; 8662306a36Sopenharmony_ci u16 ca:1; 8762306a36Sopenharmony_ci u16 mpr:1; 8862306a36Sopenharmony_ci u16 czbfs:1; /* Clear Z-Buffers */ 8962306a36Sopenharmony_ci u16 rsv:9; 9062306a36Sopenharmony_ci } bf; 9162306a36Sopenharmony_ci u16 data; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct src_rsc_ctrl_blk { 9562306a36Sopenharmony_ci unsigned int ctl; 9662306a36Sopenharmony_ci unsigned int ccr; 9762306a36Sopenharmony_ci unsigned int ca; 9862306a36Sopenharmony_ci unsigned int sa; 9962306a36Sopenharmony_ci unsigned int la; 10062306a36Sopenharmony_ci unsigned int mpr; 10162306a36Sopenharmony_ci union src_dirty dirty; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* SRC manager control block */ 10562306a36Sopenharmony_ciunion src_mgr_dirty { 10662306a36Sopenharmony_ci struct { 10762306a36Sopenharmony_ci u16 enb0:1; 10862306a36Sopenharmony_ci u16 enb1:1; 10962306a36Sopenharmony_ci u16 enb2:1; 11062306a36Sopenharmony_ci u16 enb3:1; 11162306a36Sopenharmony_ci u16 enb4:1; 11262306a36Sopenharmony_ci u16 enb5:1; 11362306a36Sopenharmony_ci u16 enb6:1; 11462306a36Sopenharmony_ci u16 enb7:1; 11562306a36Sopenharmony_ci u16 enbsa:1; 11662306a36Sopenharmony_ci u16 rsv:7; 11762306a36Sopenharmony_ci } bf; 11862306a36Sopenharmony_ci u16 data; 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistruct src_mgr_ctrl_blk { 12262306a36Sopenharmony_ci unsigned int enbsa; 12362306a36Sopenharmony_ci unsigned int enb[8]; 12462306a36Sopenharmony_ci union src_mgr_dirty dirty; 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* SRCIMP manager control block */ 12862306a36Sopenharmony_ci#define SRCAIM_ARC 0x00000FFF 12962306a36Sopenharmony_ci#define SRCAIM_NXT 0x00FF0000 13062306a36Sopenharmony_ci#define SRCAIM_SRC 0xFF000000 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistruct srcimap { 13362306a36Sopenharmony_ci unsigned int srcaim; 13462306a36Sopenharmony_ci unsigned int idx; 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* SRCIMP manager register dirty flags */ 13862306a36Sopenharmony_ciunion srcimp_mgr_dirty { 13962306a36Sopenharmony_ci struct { 14062306a36Sopenharmony_ci u16 srcimap:1; 14162306a36Sopenharmony_ci u16 rsv:15; 14262306a36Sopenharmony_ci } bf; 14362306a36Sopenharmony_ci u16 data; 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistruct srcimp_mgr_ctrl_blk { 14762306a36Sopenharmony_ci struct srcimap srcimap; 14862306a36Sopenharmony_ci union srcimp_mgr_dirty dirty; 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* 15262306a36Sopenharmony_ci * Function implementation block. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int src_get_rsc_ctrl_blk(void **rblk) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct src_rsc_ctrl_blk *blk; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci *rblk = NULL; 16062306a36Sopenharmony_ci blk = kzalloc(sizeof(*blk), GFP_KERNEL); 16162306a36Sopenharmony_ci if (!blk) 16262306a36Sopenharmony_ci return -ENOMEM; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci *rblk = blk; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int src_put_rsc_ctrl_blk(void *blk) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci kfree(blk); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int src_set_state(void *blk, unsigned int state) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_STATE, state); 18162306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int src_set_bm(void *blk, unsigned int bm) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_BM, bm); 19062306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int src_set_rsr(void *blk, unsigned int rsr) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_RSR, rsr); 19962306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int src_set_sf(void *blk, unsigned int sf) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_SF, sf); 20862306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int src_set_wr(void *blk, unsigned int wr) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_WR, wr); 21762306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int src_set_pm(void *blk, unsigned int pm) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_PM, pm); 22662306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int src_set_rom(void *blk, unsigned int rom) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_ROM, rom); 23562306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int src_set_vo(void *blk, unsigned int vo) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_VO, vo); 24462306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int src_set_st(void *blk, unsigned int st) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_ST, st); 25362306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int src_set_ie(void *blk, unsigned int ie) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_IE, ie); 26262306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int src_set_ilsz(void *blk, unsigned int ilsz) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz); 27162306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int src_set_bp(void *blk, unsigned int bp) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci set_field(&ctl->ctl, SRCCTL_BP, bp); 28062306a36Sopenharmony_ci ctl->dirty.bf.ctl = 1; 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int src_set_cisz(void *blk, unsigned int cisz) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci set_field(&ctl->ccr, SRCCCR_CISZ, cisz); 28962306a36Sopenharmony_ci ctl->dirty.bf.ccr = 1; 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int src_set_ca(void *blk, unsigned int ca) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci set_field(&ctl->ca, SRCCA_CA, ca); 29862306a36Sopenharmony_ci ctl->dirty.bf.ca = 1; 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int src_set_sa(void *blk, unsigned int sa) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci set_field(&ctl->sa, SRCSA_SA, sa); 30762306a36Sopenharmony_ci ctl->dirty.bf.sa = 1; 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int src_set_la(void *blk, unsigned int la) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci set_field(&ctl->la, SRCLA_LA, la); 31662306a36Sopenharmony_ci ctl->dirty.bf.la = 1; 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int src_set_pitch(void *blk, unsigned int pitch) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci set_field(&ctl->mpr, MPRLH_PITCH, pitch); 32562306a36Sopenharmony_ci ctl->dirty.bf.mpr = 1; 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int src_set_clear_zbufs(void *blk, unsigned int clear) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0); 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int src_set_dirty(void *blk, unsigned int flags) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int src_set_dirty_all(void *blk) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci#define AR_SLOT_SIZE 4096 34862306a36Sopenharmony_ci#define AR_SLOT_BLOCK_SIZE 16 34962306a36Sopenharmony_ci#define AR_PTS_PITCH 6 35062306a36Sopenharmony_ci#define AR_PARAM_SRC_OFFSET 0x60 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic unsigned int src_param_pitch_mixer(unsigned int src_idx) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE 35562306a36Sopenharmony_ci - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int src_commit_write(struct hw *hw, unsigned int idx, void *blk) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 36262306a36Sopenharmony_ci int i; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (ctl->dirty.bf.czbfs) { 36562306a36Sopenharmony_ci /* Clear Z-Buffer registers */ 36662306a36Sopenharmony_ci for (i = 0; i < 8; i++) 36762306a36Sopenharmony_ci hw_write_20kx(hw, SRC_UPZ+idx*0x100+i*0x4, 0); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci for (i = 0; i < 4; i++) 37062306a36Sopenharmony_ci hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci for (i = 0; i < 8; i++) 37362306a36Sopenharmony_ci hw_write_20kx(hw, SRC_DN1Z+idx*0x100+i*0x4, 0); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ctl->dirty.bf.czbfs = 0; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci if (ctl->dirty.bf.mpr) { 37862306a36Sopenharmony_ci /* Take the parameter mixer resource in the same group as that 37962306a36Sopenharmony_ci * the idx src is in for simplicity. Unlike src, all conjugate 38062306a36Sopenharmony_ci * parameter mixer resources must be programmed for 38162306a36Sopenharmony_ci * corresponding conjugate src resources. */ 38262306a36Sopenharmony_ci unsigned int pm_idx = src_param_pitch_mixer(idx); 38362306a36Sopenharmony_ci hw_write_20kx(hw, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr); 38462306a36Sopenharmony_ci hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3); 38562306a36Sopenharmony_ci hw_write_20kx(hw, MIXER_PMOPHI+8*pm_idx, 0x0); 38662306a36Sopenharmony_ci ctl->dirty.bf.mpr = 0; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci if (ctl->dirty.bf.sa) { 38962306a36Sopenharmony_ci hw_write_20kx(hw, SRC_SA+idx*0x100, ctl->sa); 39062306a36Sopenharmony_ci ctl->dirty.bf.sa = 0; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci if (ctl->dirty.bf.la) { 39362306a36Sopenharmony_ci hw_write_20kx(hw, SRC_LA+idx*0x100, ctl->la); 39462306a36Sopenharmony_ci ctl->dirty.bf.la = 0; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci if (ctl->dirty.bf.ca) { 39762306a36Sopenharmony_ci hw_write_20kx(hw, SRC_CA+idx*0x100, ctl->ca); 39862306a36Sopenharmony_ci ctl->dirty.bf.ca = 0; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Write srccf register */ 40262306a36Sopenharmony_ci hw_write_20kx(hw, SRC_CF+idx*0x100, 0x0); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (ctl->dirty.bf.ccr) { 40562306a36Sopenharmony_ci hw_write_20kx(hw, SRC_CCR+idx*0x100, ctl->ccr); 40662306a36Sopenharmony_ci ctl->dirty.bf.ccr = 0; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci if (ctl->dirty.bf.ctl) { 40962306a36Sopenharmony_ci hw_write_20kx(hw, SRC_CTL+idx*0x100, ctl->ctl); 41062306a36Sopenharmony_ci ctl->dirty.bf.ctl = 0; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int src_get_ca(struct hw *hw, unsigned int idx, void *blk) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct src_rsc_ctrl_blk *ctl = blk; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci ctl->ca = hw_read_20kx(hw, SRC_CA+idx*0x100); 42162306a36Sopenharmony_ci ctl->dirty.bf.ca = 0; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return get_field(ctl->ca, SRCCA_CA); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic unsigned int src_get_dirty(void *blk) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci return ((struct src_rsc_ctrl_blk *)blk)->dirty.data; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic unsigned int src_dirty_conj_mask(void) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci return 0x20; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int src_mgr_enbs_src(void *blk, unsigned int idx) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci ((struct src_mgr_ctrl_blk *)blk)->enbsa |= (0x1 << ((idx%128)/4)); 43962306a36Sopenharmony_ci ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1; 44062306a36Sopenharmony_ci ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int src_mgr_enb_src(void *blk, unsigned int idx) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); 44762306a36Sopenharmony_ci ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int src_mgr_dsb_src(void *blk, unsigned int idx) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32)); 45462306a36Sopenharmony_ci ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int src_mgr_commit_write(struct hw *hw, void *blk) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct src_mgr_ctrl_blk *ctl = blk; 46162306a36Sopenharmony_ci int i; 46262306a36Sopenharmony_ci unsigned int ret; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (ctl->dirty.bf.enbsa) { 46562306a36Sopenharmony_ci do { 46662306a36Sopenharmony_ci ret = hw_read_20kx(hw, SRC_ENBSTAT); 46762306a36Sopenharmony_ci } while (ret & 0x1); 46862306a36Sopenharmony_ci hw_write_20kx(hw, SRC_ENBSA, ctl->enbsa); 46962306a36Sopenharmony_ci ctl->dirty.bf.enbsa = 0; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 47262306a36Sopenharmony_ci if ((ctl->dirty.data & (0x1 << i))) { 47362306a36Sopenharmony_ci hw_write_20kx(hw, SRC_ENB+(i*0x100), ctl->enb[i]); 47462306a36Sopenharmony_ci ctl->dirty.data &= ~(0x1 << i); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int src_mgr_get_ctrl_blk(void **rblk) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct src_mgr_ctrl_blk *blk; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci *rblk = NULL; 48662306a36Sopenharmony_ci blk = kzalloc(sizeof(*blk), GFP_KERNEL); 48762306a36Sopenharmony_ci if (!blk) 48862306a36Sopenharmony_ci return -ENOMEM; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci *rblk = blk; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return 0; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic int src_mgr_put_ctrl_blk(void *blk) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci kfree(blk); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic int srcimp_mgr_get_ctrl_blk(void **rblk) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct srcimp_mgr_ctrl_blk *blk; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci *rblk = NULL; 50762306a36Sopenharmony_ci blk = kzalloc(sizeof(*blk), GFP_KERNEL); 50862306a36Sopenharmony_ci if (!blk) 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci *rblk = blk; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic int srcimp_mgr_put_ctrl_blk(void *blk) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci kfree(blk); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int srcimp_mgr_set_imaparc(void *blk, unsigned int slot) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct srcimp_mgr_ctrl_blk *ctl = blk; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot); 52862306a36Sopenharmony_ci ctl->dirty.bf.srcimap = 1; 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int srcimp_mgr_set_imapuser(void *blk, unsigned int user) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct srcimp_mgr_ctrl_blk *ctl = blk; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user); 53762306a36Sopenharmony_ci ctl->dirty.bf.srcimap = 1; 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int srcimp_mgr_set_imapnxt(void *blk, unsigned int next) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct srcimp_mgr_ctrl_blk *ctl = blk; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next); 54662306a36Sopenharmony_ci ctl->dirty.bf.srcimap = 1; 54762306a36Sopenharmony_ci return 0; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci ((struct srcimp_mgr_ctrl_blk *)blk)->srcimap.idx = addr; 55362306a36Sopenharmony_ci ((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1; 55462306a36Sopenharmony_ci return 0; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic int srcimp_mgr_commit_write(struct hw *hw, void *blk) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct srcimp_mgr_ctrl_blk *ctl = blk; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (ctl->dirty.bf.srcimap) { 56262306a36Sopenharmony_ci hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100, 56362306a36Sopenharmony_ci ctl->srcimap.srcaim); 56462306a36Sopenharmony_ci ctl->dirty.bf.srcimap = 0; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci/* 57162306a36Sopenharmony_ci * AMIXER control block definitions. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci#define AMOPLO_M 0x00000003 57562306a36Sopenharmony_ci#define AMOPLO_IV 0x00000004 57662306a36Sopenharmony_ci#define AMOPLO_X 0x0003FFF0 57762306a36Sopenharmony_ci#define AMOPLO_Y 0xFFFC0000 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci#define AMOPHI_SADR 0x000000FF 58062306a36Sopenharmony_ci#define AMOPHI_SE 0x80000000 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci/* AMIXER resource register dirty flags */ 58362306a36Sopenharmony_ciunion amixer_dirty { 58462306a36Sopenharmony_ci struct { 58562306a36Sopenharmony_ci u16 amoplo:1; 58662306a36Sopenharmony_ci u16 amophi:1; 58762306a36Sopenharmony_ci u16 rsv:14; 58862306a36Sopenharmony_ci } bf; 58962306a36Sopenharmony_ci u16 data; 59062306a36Sopenharmony_ci}; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/* AMIXER resource control block */ 59362306a36Sopenharmony_cistruct amixer_rsc_ctrl_blk { 59462306a36Sopenharmony_ci unsigned int amoplo; 59562306a36Sopenharmony_ci unsigned int amophi; 59662306a36Sopenharmony_ci union amixer_dirty dirty; 59762306a36Sopenharmony_ci}; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int amixer_set_mode(void *blk, unsigned int mode) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci set_field(&ctl->amoplo, AMOPLO_M, mode); 60462306a36Sopenharmony_ci ctl->dirty.bf.amoplo = 1; 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int amixer_set_iv(void *blk, unsigned int iv) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci set_field(&ctl->amoplo, AMOPLO_IV, iv); 61362306a36Sopenharmony_ci ctl->dirty.bf.amoplo = 1; 61462306a36Sopenharmony_ci return 0; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int amixer_set_x(void *blk, unsigned int x) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci set_field(&ctl->amoplo, AMOPLO_X, x); 62262306a36Sopenharmony_ci ctl->dirty.bf.amoplo = 1; 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int amixer_set_y(void *blk, unsigned int y) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci set_field(&ctl->amoplo, AMOPLO_Y, y); 63162306a36Sopenharmony_ci ctl->dirty.bf.amoplo = 1; 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int amixer_set_sadr(void *blk, unsigned int sadr) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci set_field(&ctl->amophi, AMOPHI_SADR, sadr); 64062306a36Sopenharmony_ci ctl->dirty.bf.amophi = 1; 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int amixer_set_se(void *blk, unsigned int se) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci set_field(&ctl->amophi, AMOPHI_SE, se); 64962306a36Sopenharmony_ci ctl->dirty.bf.amophi = 1; 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int amixer_set_dirty(void *blk, unsigned int flags) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic int amixer_set_dirty_all(void *blk) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); 66262306a36Sopenharmony_ci return 0; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { 67062306a36Sopenharmony_ci hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo); 67162306a36Sopenharmony_ci ctl->dirty.bf.amoplo = 0; 67262306a36Sopenharmony_ci hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi); 67362306a36Sopenharmony_ci ctl->dirty.bf.amophi = 0; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic int amixer_get_y(void *blk) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *ctl = blk; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return get_field(ctl->amoplo, AMOPLO_Y); 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic unsigned int amixer_get_dirty(void *blk) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic int amixer_rsc_get_ctrl_blk(void **rblk) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct amixer_rsc_ctrl_blk *blk; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci *rblk = NULL; 69662306a36Sopenharmony_ci blk = kzalloc(sizeof(*blk), GFP_KERNEL); 69762306a36Sopenharmony_ci if (!blk) 69862306a36Sopenharmony_ci return -ENOMEM; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci *rblk = blk; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci return 0; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic int amixer_rsc_put_ctrl_blk(void *blk) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci kfree(blk); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return 0; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic int amixer_mgr_get_ctrl_blk(void **rblk) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci *rblk = NULL; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return 0; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic int amixer_mgr_put_ctrl_blk(void *blk) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/* 72562306a36Sopenharmony_ci * DAIO control block definitions. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/* Receiver Sample Rate Tracker Control register */ 72962306a36Sopenharmony_ci#define SRTCTL_SRCO 0x000000FF 73062306a36Sopenharmony_ci#define SRTCTL_SRCM 0x0000FF00 73162306a36Sopenharmony_ci#define SRTCTL_RSR 0x00030000 73262306a36Sopenharmony_ci#define SRTCTL_DRAT 0x00300000 73362306a36Sopenharmony_ci#define SRTCTL_EC 0x01000000 73462306a36Sopenharmony_ci#define SRTCTL_ET 0x10000000 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci/* DAIO Receiver register dirty flags */ 73762306a36Sopenharmony_ciunion dai_dirty { 73862306a36Sopenharmony_ci struct { 73962306a36Sopenharmony_ci u16 srt:1; 74062306a36Sopenharmony_ci u16 rsv:15; 74162306a36Sopenharmony_ci } bf; 74262306a36Sopenharmony_ci u16 data; 74362306a36Sopenharmony_ci}; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci/* DAIO Receiver control block */ 74662306a36Sopenharmony_cistruct dai_ctrl_blk { 74762306a36Sopenharmony_ci unsigned int srt; 74862306a36Sopenharmony_ci union dai_dirty dirty; 74962306a36Sopenharmony_ci}; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/* Audio Input Mapper RAM */ 75262306a36Sopenharmony_ci#define AIM_ARC 0x00000FFF 75362306a36Sopenharmony_ci#define AIM_NXT 0x007F0000 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistruct daoimap { 75662306a36Sopenharmony_ci unsigned int aim; 75762306a36Sopenharmony_ci unsigned int idx; 75862306a36Sopenharmony_ci}; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci/* Audio Transmitter Control and Status register */ 76162306a36Sopenharmony_ci#define ATXCTL_EN 0x00000001 76262306a36Sopenharmony_ci#define ATXCTL_MODE 0x00000010 76362306a36Sopenharmony_ci#define ATXCTL_CD 0x00000020 76462306a36Sopenharmony_ci#define ATXCTL_RAW 0x00000100 76562306a36Sopenharmony_ci#define ATXCTL_MT 0x00000200 76662306a36Sopenharmony_ci#define ATXCTL_NUC 0x00003000 76762306a36Sopenharmony_ci#define ATXCTL_BEN 0x00010000 76862306a36Sopenharmony_ci#define ATXCTL_BMUX 0x00700000 76962306a36Sopenharmony_ci#define ATXCTL_B24 0x01000000 77062306a36Sopenharmony_ci#define ATXCTL_CPF 0x02000000 77162306a36Sopenharmony_ci#define ATXCTL_RIV 0x10000000 77262306a36Sopenharmony_ci#define ATXCTL_LIV 0x20000000 77362306a36Sopenharmony_ci#define ATXCTL_RSAT 0x40000000 77462306a36Sopenharmony_ci#define ATXCTL_LSAT 0x80000000 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/* XDIF Transmitter register dirty flags */ 77762306a36Sopenharmony_ciunion dao_dirty { 77862306a36Sopenharmony_ci struct { 77962306a36Sopenharmony_ci u16 atxcsl:1; 78062306a36Sopenharmony_ci u16 rsv:15; 78162306a36Sopenharmony_ci } bf; 78262306a36Sopenharmony_ci u16 data; 78362306a36Sopenharmony_ci}; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci/* XDIF Transmitter control block */ 78662306a36Sopenharmony_cistruct dao_ctrl_blk { 78762306a36Sopenharmony_ci /* XDIF Transmitter Channel Status Low Register */ 78862306a36Sopenharmony_ci unsigned int atxcsl; 78962306a36Sopenharmony_ci union dao_dirty dirty; 79062306a36Sopenharmony_ci}; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci/* Audio Receiver Control register */ 79362306a36Sopenharmony_ci#define ARXCTL_EN 0x00000001 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci/* DAIO manager register dirty flags */ 79662306a36Sopenharmony_ciunion daio_mgr_dirty { 79762306a36Sopenharmony_ci struct { 79862306a36Sopenharmony_ci u32 atxctl:8; 79962306a36Sopenharmony_ci u32 arxctl:8; 80062306a36Sopenharmony_ci u32 daoimap:1; 80162306a36Sopenharmony_ci u32 rsv:15; 80262306a36Sopenharmony_ci } bf; 80362306a36Sopenharmony_ci u32 data; 80462306a36Sopenharmony_ci}; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/* DAIO manager control block */ 80762306a36Sopenharmony_cistruct daio_mgr_ctrl_blk { 80862306a36Sopenharmony_ci struct daoimap daoimap; 80962306a36Sopenharmony_ci unsigned int txctl[8]; 81062306a36Sopenharmony_ci unsigned int rxctl[8]; 81162306a36Sopenharmony_ci union daio_mgr_dirty dirty; 81262306a36Sopenharmony_ci}; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int dai_srt_set_srco(void *blk, unsigned int src) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct dai_ctrl_blk *ctl = blk; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci set_field(&ctl->srt, SRTCTL_SRCO, src); 81962306a36Sopenharmony_ci ctl->dirty.bf.srt = 1; 82062306a36Sopenharmony_ci return 0; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic int dai_srt_set_srcm(void *blk, unsigned int src) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct dai_ctrl_blk *ctl = blk; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci set_field(&ctl->srt, SRTCTL_SRCM, src); 82862306a36Sopenharmony_ci ctl->dirty.bf.srt = 1; 82962306a36Sopenharmony_ci return 0; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic int dai_srt_set_rsr(void *blk, unsigned int rsr) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct dai_ctrl_blk *ctl = blk; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci set_field(&ctl->srt, SRTCTL_RSR, rsr); 83762306a36Sopenharmony_ci ctl->dirty.bf.srt = 1; 83862306a36Sopenharmony_ci return 0; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic int dai_srt_set_drat(void *blk, unsigned int drat) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct dai_ctrl_blk *ctl = blk; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci set_field(&ctl->srt, SRTCTL_DRAT, drat); 84662306a36Sopenharmony_ci ctl->dirty.bf.srt = 1; 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int dai_srt_set_ec(void *blk, unsigned int ec) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct dai_ctrl_blk *ctl = blk; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0); 85562306a36Sopenharmony_ci ctl->dirty.bf.srt = 1; 85662306a36Sopenharmony_ci return 0; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic int dai_srt_set_et(void *blk, unsigned int et) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct dai_ctrl_blk *ctl = blk; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0); 86462306a36Sopenharmony_ci ctl->dirty.bf.srt = 1; 86562306a36Sopenharmony_ci return 0; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci struct dai_ctrl_blk *ctl = blk; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (ctl->dirty.bf.srt) { 87362306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt); 87462306a36Sopenharmony_ci ctl->dirty.bf.srt = 0; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci return 0; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int dai_get_ctrl_blk(void **rblk) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct dai_ctrl_blk *blk; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci *rblk = NULL; 88562306a36Sopenharmony_ci blk = kzalloc(sizeof(*blk), GFP_KERNEL); 88662306a36Sopenharmony_ci if (!blk) 88762306a36Sopenharmony_ci return -ENOMEM; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci *rblk = blk; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return 0; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic int dai_put_ctrl_blk(void *blk) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci kfree(blk); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int dao_set_spos(void *blk, unsigned int spos) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci ((struct dao_ctrl_blk *)blk)->atxcsl = spos; 90462306a36Sopenharmony_ci ((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1; 90562306a36Sopenharmony_ci return 0; 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct dao_ctrl_blk *ctl = blk; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (ctl->dirty.bf.atxcsl) { 91362306a36Sopenharmony_ci if (idx < 4) { 91462306a36Sopenharmony_ci /* S/PDIF SPOSx */ 91562306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx, 91662306a36Sopenharmony_ci ctl->atxcsl); 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci ctl->dirty.bf.atxcsl = 0; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci return 0; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic int dao_get_spos(void *blk, unsigned int *spos) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci *spos = ((struct dao_ctrl_blk *)blk)->atxcsl; 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic int dao_get_ctrl_blk(void **rblk) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct dao_ctrl_blk *blk; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci *rblk = NULL; 93562306a36Sopenharmony_ci blk = kzalloc(sizeof(*blk), GFP_KERNEL); 93662306a36Sopenharmony_ci if (!blk) 93762306a36Sopenharmony_ci return -ENOMEM; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci *rblk = blk; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci return 0; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic int dao_put_ctrl_blk(void *blk) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci kfree(blk); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return 0; 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic int daio_mgr_enb_dai(void *blk, unsigned int idx) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci set_field(&ctl->rxctl[idx], ARXCTL_EN, 1); 95662306a36Sopenharmony_ci ctl->dirty.bf.arxctl |= (0x1 << idx); 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic int daio_mgr_dsb_dai(void *blk, unsigned int idx) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci set_field(&ctl->rxctl[idx], ARXCTL_EN, 0); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci ctl->dirty.bf.arxctl |= (0x1 << idx); 96762306a36Sopenharmony_ci return 0; 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic int daio_mgr_enb_dao(void *blk, unsigned int idx) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_EN, 1); 97562306a36Sopenharmony_ci ctl->dirty.bf.atxctl |= (0x1 << idx); 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic int daio_mgr_dsb_dao(void *blk, unsigned int idx) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_EN, 0); 98462306a36Sopenharmony_ci ctl->dirty.bf.atxctl |= (0x1 << idx); 98562306a36Sopenharmony_ci return 0; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (idx < 4) { 99362306a36Sopenharmony_ci /* S/PDIF output */ 99462306a36Sopenharmony_ci switch ((conf & 0xf)) { 99562306a36Sopenharmony_ci case 1: 99662306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_NUC, 0); 99762306a36Sopenharmony_ci break; 99862306a36Sopenharmony_ci case 2: 99962306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_NUC, 1); 100062306a36Sopenharmony_ci break; 100162306a36Sopenharmony_ci case 4: 100262306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_NUC, 2); 100362306a36Sopenharmony_ci break; 100462306a36Sopenharmony_ci case 8: 100562306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_NUC, 3); 100662306a36Sopenharmony_ci break; 100762306a36Sopenharmony_ci default: 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci /* CDIF */ 101162306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7))); 101262306a36Sopenharmony_ci /* Non-audio */ 101362306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1); 101462306a36Sopenharmony_ci /* Non-audio */ 101562306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1); 101662306a36Sopenharmony_ci set_field(&ctl->txctl[idx], ATXCTL_RAW, 101762306a36Sopenharmony_ci ((conf >> 3) & 0x1) ? 0 : 0); 101862306a36Sopenharmony_ci ctl->dirty.bf.atxctl |= (0x1 << idx); 101962306a36Sopenharmony_ci } else { 102062306a36Sopenharmony_ci /* I2S output */ 102162306a36Sopenharmony_ci /*idx %= 4; */ 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic int daio_mgr_set_imaparc(void *blk, unsigned int slot) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci set_field(&ctl->daoimap.aim, AIM_ARC, slot); 103162306a36Sopenharmony_ci ctl->dirty.bf.daoimap = 1; 103262306a36Sopenharmony_ci return 0; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic int daio_mgr_set_imapnxt(void *blk, unsigned int next) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci set_field(&ctl->daoimap.aim, AIM_NXT, next); 104062306a36Sopenharmony_ci ctl->dirty.bf.daoimap = 1; 104162306a36Sopenharmony_ci return 0; 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic int daio_mgr_set_imapaddr(void *blk, unsigned int addr) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci ((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr; 104762306a36Sopenharmony_ci ((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1; 104862306a36Sopenharmony_ci return 0; 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic int daio_mgr_commit_write(struct hw *hw, void *blk) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *ctl = blk; 105462306a36Sopenharmony_ci unsigned int data; 105562306a36Sopenharmony_ci int i; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 105862306a36Sopenharmony_ci if ((ctl->dirty.bf.atxctl & (0x1 << i))) { 105962306a36Sopenharmony_ci data = ctl->txctl[i]; 106062306a36Sopenharmony_ci hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); 106162306a36Sopenharmony_ci ctl->dirty.bf.atxctl &= ~(0x1 << i); 106262306a36Sopenharmony_ci mdelay(1); 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci if ((ctl->dirty.bf.arxctl & (0x1 << i))) { 106562306a36Sopenharmony_ci data = ctl->rxctl[i]; 106662306a36Sopenharmony_ci hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); 106762306a36Sopenharmony_ci ctl->dirty.bf.arxctl &= ~(0x1 << i); 106862306a36Sopenharmony_ci mdelay(1); 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci if (ctl->dirty.bf.daoimap) { 107262306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4, 107362306a36Sopenharmony_ci ctl->daoimap.aim); 107462306a36Sopenharmony_ci ctl->dirty.bf.daoimap = 0; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci return 0; 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci struct daio_mgr_ctrl_blk *blk; 108362306a36Sopenharmony_ci int i; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci *rblk = NULL; 108662306a36Sopenharmony_ci blk = kzalloc(sizeof(*blk), GFP_KERNEL); 108762306a36Sopenharmony_ci if (!blk) 108862306a36Sopenharmony_ci return -ENOMEM; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 109162306a36Sopenharmony_ci blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i)); 109262306a36Sopenharmony_ci blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i)); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci *rblk = blk; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return 0; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic int daio_mgr_put_ctrl_blk(void *blk) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci kfree(blk); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci return 0; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci/* Timer interrupt */ 110862306a36Sopenharmony_cistatic int set_timer_irq(struct hw *hw, int enable) 110962306a36Sopenharmony_ci{ 111062306a36Sopenharmony_ci hw_write_20kx(hw, GIE, enable ? IT_INT : 0); 111162306a36Sopenharmony_ci return 0; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic int set_timer_tick(struct hw *hw, unsigned int ticks) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci if (ticks) 111762306a36Sopenharmony_ci ticks |= TIMR_IE | TIMR_IP; 111862306a36Sopenharmony_ci hw_write_20kx(hw, TIMR, ticks); 111962306a36Sopenharmony_ci return 0; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic unsigned int get_wc(struct hw *hw) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci return hw_read_20kx(hw, WC); 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci/* Card hardware initialization block */ 112862306a36Sopenharmony_cistruct dac_conf { 112962306a36Sopenharmony_ci unsigned int msr; /* master sample rate in rsrs */ 113062306a36Sopenharmony_ci}; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistruct adc_conf { 113362306a36Sopenharmony_ci unsigned int msr; /* master sample rate in rsrs */ 113462306a36Sopenharmony_ci unsigned char input; /* the input source of ADC */ 113562306a36Sopenharmony_ci unsigned char mic20db; /* boost mic by 20db if input is microphone */ 113662306a36Sopenharmony_ci}; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistruct daio_conf { 113962306a36Sopenharmony_ci unsigned int msr; /* master sample rate in rsrs */ 114062306a36Sopenharmony_ci}; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_cistruct trn_conf { 114362306a36Sopenharmony_ci unsigned long vm_pgt_phys; 114462306a36Sopenharmony_ci}; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic int hw_daio_init(struct hw *hw, const struct daio_conf *info) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci u32 data; 114962306a36Sopenharmony_ci int i; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* Program I2S with proper sample rate and enable the correct I2S 115262306a36Sopenharmony_ci * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */ 115362306a36Sopenharmony_ci if (1 == info->msr) { 115462306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101); 115562306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); 115662306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); 115762306a36Sopenharmony_ci } else if (2 == info->msr) { 115862306a36Sopenharmony_ci if (hw->model != CTSB1270) { 115962306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); 116062306a36Sopenharmony_ci } else { 116162306a36Sopenharmony_ci /* PCM4220 on Titanium HD is different. */ 116262306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111); 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci /* Specify all playing 96khz 116562306a36Sopenharmony_ci * EA [0] - Enabled 116662306a36Sopenharmony_ci * RTA [4:5] - 96kHz 116762306a36Sopenharmony_ci * EB [8] - Enabled 116862306a36Sopenharmony_ci * RTB [12:13] - 96kHz 116962306a36Sopenharmony_ci * EC [16] - Enabled 117062306a36Sopenharmony_ci * RTC [20:21] - 96kHz 117162306a36Sopenharmony_ci * ED [24] - Enabled 117262306a36Sopenharmony_ci * RTD [28:29] - 96kHz */ 117362306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); 117462306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); 117562306a36Sopenharmony_ci } else if ((4 == info->msr) && (hw->model == CTSB1270)) { 117662306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111); 117762306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121); 117862306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); 117962306a36Sopenharmony_ci } else { 118062306a36Sopenharmony_ci dev_alert(hw->card->dev, 118162306a36Sopenharmony_ci "ERROR!!! Invalid sampling rate!!!\n"); 118262306a36Sopenharmony_ci return -EINVAL; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 118662306a36Sopenharmony_ci if (i <= 3) { 118762306a36Sopenharmony_ci /* This comment looks wrong since loop is over 4 */ 118862306a36Sopenharmony_ci /* channels and emu20k2 supports 4 spdif IOs. */ 118962306a36Sopenharmony_ci /* 1st 3 channels are SPDIFs (SB0960) */ 119062306a36Sopenharmony_ci if (i == 3) 119162306a36Sopenharmony_ci data = 0x1001001; 119262306a36Sopenharmony_ci else 119362306a36Sopenharmony_ci data = 0x1000001; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); 119662306a36Sopenharmony_ci hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci /* Initialize the SPDIF Out Channel status registers. 119962306a36Sopenharmony_ci * The value specified here is based on the typical 120062306a36Sopenharmony_ci * values provided in the specification, namely: Clock 120162306a36Sopenharmony_ci * Accuracy of 1000ppm, Sample Rate of 48KHz, 120262306a36Sopenharmony_ci * unspecified source number, Generation status = 1, 120362306a36Sopenharmony_ci * Category code = 0x12 (Digital Signal Mixer), 120462306a36Sopenharmony_ci * Mode = 0, Emph = 0, Copy Permitted, AN = 0 120562306a36Sopenharmony_ci * (indicating that we're transmitting digital audio, 120662306a36Sopenharmony_ci * and the Professional Use bit is 0. */ 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i), 120962306a36Sopenharmony_ci 0x02109204); /* Default to 48kHz */ 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); 121262306a36Sopenharmony_ci } else { 121362306a36Sopenharmony_ci /* Again, loop is over 4 channels not 5. */ 121462306a36Sopenharmony_ci /* Next 5 channels are I2S (SB0960) */ 121562306a36Sopenharmony_ci data = 0x11; 121662306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); 121762306a36Sopenharmony_ci if (2 == info->msr) { 121862306a36Sopenharmony_ci /* Four channels per sample period */ 121962306a36Sopenharmony_ci data |= 0x1000; 122062306a36Sopenharmony_ci } else if (4 == info->msr) { 122162306a36Sopenharmony_ci /* FIXME: check this against the chip spec */ 122262306a36Sopenharmony_ci data |= 0x2000; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/* TRANSPORT operations */ 123262306a36Sopenharmony_cistatic int hw_trn_init(struct hw *hw, const struct trn_conf *info) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci u32 vmctl, data; 123562306a36Sopenharmony_ci u32 ptp_phys_low, ptp_phys_high; 123662306a36Sopenharmony_ci int i; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci /* Set up device page table */ 123962306a36Sopenharmony_ci if ((~0UL) == info->vm_pgt_phys) { 124062306a36Sopenharmony_ci dev_alert(hw->card->dev, 124162306a36Sopenharmony_ci "Wrong device page table page address!!!\n"); 124262306a36Sopenharmony_ci return -1; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci vmctl = 0x80000C0F; /* 32-bit, 4k-size page */ 124662306a36Sopenharmony_ci ptp_phys_low = (u32)info->vm_pgt_phys; 124762306a36Sopenharmony_ci ptp_phys_high = upper_32_bits(info->vm_pgt_phys); 124862306a36Sopenharmony_ci if (sizeof(void *) == 8) /* 64bit address */ 124962306a36Sopenharmony_ci vmctl |= (3 << 8); 125062306a36Sopenharmony_ci /* Write page table physical address to all PTPAL registers */ 125162306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 125262306a36Sopenharmony_ci hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low); 125362306a36Sopenharmony_ci hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high); 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci /* Enable virtual memory transfer */ 125662306a36Sopenharmony_ci hw_write_20kx(hw, VMEM_CTL, vmctl); 125762306a36Sopenharmony_ci /* Enable transport bus master and queueing of request */ 125862306a36Sopenharmony_ci hw_write_20kx(hw, TRANSPORT_CTL, 0x03); 125962306a36Sopenharmony_ci hw_write_20kx(hw, TRANSPORT_INT, 0x200c01); 126062306a36Sopenharmony_ci /* Enable transport ring */ 126162306a36Sopenharmony_ci data = hw_read_20kx(hw, TRANSPORT_ENB); 126262306a36Sopenharmony_ci hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03)); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci return 0; 126562306a36Sopenharmony_ci} 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci/* Card initialization */ 126862306a36Sopenharmony_ci#define GCTL_AIE 0x00000001 126962306a36Sopenharmony_ci#define GCTL_UAA 0x00000002 127062306a36Sopenharmony_ci#define GCTL_DPC 0x00000004 127162306a36Sopenharmony_ci#define GCTL_DBP 0x00000008 127262306a36Sopenharmony_ci#define GCTL_ABP 0x00000010 127362306a36Sopenharmony_ci#define GCTL_TBP 0x00000020 127462306a36Sopenharmony_ci#define GCTL_SBP 0x00000040 127562306a36Sopenharmony_ci#define GCTL_FBP 0x00000080 127662306a36Sopenharmony_ci#define GCTL_ME 0x00000100 127762306a36Sopenharmony_ci#define GCTL_AID 0x00001000 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci#define PLLCTL_SRC 0x00000007 128062306a36Sopenharmony_ci#define PLLCTL_SPE 0x00000008 128162306a36Sopenharmony_ci#define PLLCTL_RD 0x000000F0 128262306a36Sopenharmony_ci#define PLLCTL_FD 0x0001FF00 128362306a36Sopenharmony_ci#define PLLCTL_OD 0x00060000 128462306a36Sopenharmony_ci#define PLLCTL_B 0x00080000 128562306a36Sopenharmony_ci#define PLLCTL_AS 0x00100000 128662306a36Sopenharmony_ci#define PLLCTL_LF 0x03E00000 128762306a36Sopenharmony_ci#define PLLCTL_SPS 0x1C000000 128862306a36Sopenharmony_ci#define PLLCTL_AD 0x60000000 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci#define PLLSTAT_CCS 0x00000007 129162306a36Sopenharmony_ci#define PLLSTAT_SPL 0x00000008 129262306a36Sopenharmony_ci#define PLLSTAT_CRD 0x000000F0 129362306a36Sopenharmony_ci#define PLLSTAT_CFD 0x0001FF00 129462306a36Sopenharmony_ci#define PLLSTAT_SL 0x00020000 129562306a36Sopenharmony_ci#define PLLSTAT_FAS 0x00040000 129662306a36Sopenharmony_ci#define PLLSTAT_B 0x00080000 129762306a36Sopenharmony_ci#define PLLSTAT_PD 0x00100000 129862306a36Sopenharmony_ci#define PLLSTAT_OCA 0x00200000 129962306a36Sopenharmony_ci#define PLLSTAT_NCA 0x00400000 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic int hw_pll_init(struct hw *hw, unsigned int rsr) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci unsigned int pllenb; 130462306a36Sopenharmony_ci unsigned int pllctl; 130562306a36Sopenharmony_ci unsigned int pllstat; 130662306a36Sopenharmony_ci int i; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci pllenb = 0xB; 130962306a36Sopenharmony_ci hw_write_20kx(hw, PLL_ENB, pllenb); 131062306a36Sopenharmony_ci pllctl = 0x20C00000; 131162306a36Sopenharmony_ci set_field(&pllctl, PLLCTL_B, 0); 131262306a36Sopenharmony_ci set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4); 131362306a36Sopenharmony_ci set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1); 131462306a36Sopenharmony_ci hw_write_20kx(hw, PLL_CTL, pllctl); 131562306a36Sopenharmony_ci msleep(40); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci pllctl = hw_read_20kx(hw, PLL_CTL); 131862306a36Sopenharmony_ci set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2); 131962306a36Sopenharmony_ci hw_write_20kx(hw, PLL_CTL, pllctl); 132062306a36Sopenharmony_ci msleep(40); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci for (i = 0; i < 1000; i++) { 132362306a36Sopenharmony_ci pllstat = hw_read_20kx(hw, PLL_STAT); 132462306a36Sopenharmony_ci if (get_field(pllstat, PLLSTAT_PD)) 132562306a36Sopenharmony_ci continue; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (get_field(pllstat, PLLSTAT_B) != 132862306a36Sopenharmony_ci get_field(pllctl, PLLCTL_B)) 132962306a36Sopenharmony_ci continue; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (get_field(pllstat, PLLSTAT_CCS) != 133262306a36Sopenharmony_ci get_field(pllctl, PLLCTL_SRC)) 133362306a36Sopenharmony_ci continue; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (get_field(pllstat, PLLSTAT_CRD) != 133662306a36Sopenharmony_ci get_field(pllctl, PLLCTL_RD)) 133762306a36Sopenharmony_ci continue; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci if (get_field(pllstat, PLLSTAT_CFD) != 134062306a36Sopenharmony_ci get_field(pllctl, PLLCTL_FD)) 134162306a36Sopenharmony_ci continue; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci break; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci if (i >= 1000) { 134662306a36Sopenharmony_ci dev_alert(hw->card->dev, 134762306a36Sopenharmony_ci "PLL initialization failed!!!\n"); 134862306a36Sopenharmony_ci return -EBUSY; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci return 0; 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic int hw_auto_init(struct hw *hw) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci unsigned int gctl; 135762306a36Sopenharmony_ci int i; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); 136062306a36Sopenharmony_ci set_field(&gctl, GCTL_AIE, 0); 136162306a36Sopenharmony_ci hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); 136262306a36Sopenharmony_ci set_field(&gctl, GCTL_AIE, 1); 136362306a36Sopenharmony_ci hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); 136462306a36Sopenharmony_ci mdelay(10); 136562306a36Sopenharmony_ci for (i = 0; i < 400000; i++) { 136662306a36Sopenharmony_ci gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); 136762306a36Sopenharmony_ci if (get_field(gctl, GCTL_AID)) 136862306a36Sopenharmony_ci break; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci if (!get_field(gctl, GCTL_AID)) { 137162306a36Sopenharmony_ci dev_alert(hw->card->dev, "Card Auto-init failed!!!\n"); 137262306a36Sopenharmony_ci return -EBUSY; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci return 0; 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci/* DAC operations */ 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci#define CS4382_MC1 0x1 138162306a36Sopenharmony_ci#define CS4382_MC2 0x2 138262306a36Sopenharmony_ci#define CS4382_MC3 0x3 138362306a36Sopenharmony_ci#define CS4382_FC 0x4 138462306a36Sopenharmony_ci#define CS4382_IC 0x5 138562306a36Sopenharmony_ci#define CS4382_XC1 0x6 138662306a36Sopenharmony_ci#define CS4382_VCA1 0x7 138762306a36Sopenharmony_ci#define CS4382_VCB1 0x8 138862306a36Sopenharmony_ci#define CS4382_XC2 0x9 138962306a36Sopenharmony_ci#define CS4382_VCA2 0xA 139062306a36Sopenharmony_ci#define CS4382_VCB2 0xB 139162306a36Sopenharmony_ci#define CS4382_XC3 0xC 139262306a36Sopenharmony_ci#define CS4382_VCA3 0xD 139362306a36Sopenharmony_ci#define CS4382_VCB3 0xE 139462306a36Sopenharmony_ci#define CS4382_XC4 0xF 139562306a36Sopenharmony_ci#define CS4382_VCA4 0x10 139662306a36Sopenharmony_ci#define CS4382_VCB4 0x11 139762306a36Sopenharmony_ci#define CS4382_CREV 0x12 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci/* I2C status */ 140062306a36Sopenharmony_ci#define STATE_LOCKED 0x00 140162306a36Sopenharmony_ci#define STATE_UNLOCKED 0xAA 140262306a36Sopenharmony_ci#define DATA_READY 0x800000 /* Used with I2C_IF_STATUS */ 140362306a36Sopenharmony_ci#define DATA_ABORT 0x10000 /* Used with I2C_IF_STATUS */ 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci#define I2C_STATUS_DCM 0x00000001 140662306a36Sopenharmony_ci#define I2C_STATUS_BC 0x00000006 140762306a36Sopenharmony_ci#define I2C_STATUS_APD 0x00000008 140862306a36Sopenharmony_ci#define I2C_STATUS_AB 0x00010000 140962306a36Sopenharmony_ci#define I2C_STATUS_DR 0x00800000 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci#define I2C_ADDRESS_PTAD 0x0000FFFF 141262306a36Sopenharmony_ci#define I2C_ADDRESS_SLAD 0x007F0000 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_cistruct regs_cs4382 { 141562306a36Sopenharmony_ci u32 mode_control_1; 141662306a36Sopenharmony_ci u32 mode_control_2; 141762306a36Sopenharmony_ci u32 mode_control_3; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci u32 filter_control; 142062306a36Sopenharmony_ci u32 invert_control; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci u32 mix_control_P1; 142362306a36Sopenharmony_ci u32 vol_control_A1; 142462306a36Sopenharmony_ci u32 vol_control_B1; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci u32 mix_control_P2; 142762306a36Sopenharmony_ci u32 vol_control_A2; 142862306a36Sopenharmony_ci u32 vol_control_B2; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci u32 mix_control_P3; 143162306a36Sopenharmony_ci u32 vol_control_A3; 143262306a36Sopenharmony_ci u32 vol_control_B3; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci u32 mix_control_P4; 143562306a36Sopenharmony_ci u32 vol_control_A4; 143662306a36Sopenharmony_ci u32 vol_control_B4; 143762306a36Sopenharmony_ci}; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic int hw20k2_i2c_unlock_full_access(struct hw *hw) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] = {0xB3, 0xD4}; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci /* Send keys for forced BIOS mode */ 144462306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_WLOCK, 144562306a36Sopenharmony_ci UnlockKeySequence_FLASH_FULLACCESS_MODE[0]); 144662306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_WLOCK, 144762306a36Sopenharmony_ci UnlockKeySequence_FLASH_FULLACCESS_MODE[1]); 144862306a36Sopenharmony_ci /* Check whether the chip is unlocked */ 144962306a36Sopenharmony_ci if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED) 145062306a36Sopenharmony_ci return 0; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci return -1; 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_cistatic int hw20k2_i2c_lock_chip(struct hw *hw) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci /* Write twice */ 145862306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); 145962306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); 146062306a36Sopenharmony_ci if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED) 146162306a36Sopenharmony_ci return 0; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci return -1; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; 146962306a36Sopenharmony_ci int err; 147062306a36Sopenharmony_ci unsigned int i2c_status; 147162306a36Sopenharmony_ci unsigned int i2c_addr; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci err = hw20k2_i2c_unlock_full_access(hw); 147462306a36Sopenharmony_ci if (err < 0) 147562306a36Sopenharmony_ci return err; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci hw20k2->addr_size = addr_size; 147862306a36Sopenharmony_ci hw20k2->data_size = data_size; 147962306a36Sopenharmony_ci hw20k2->dev_id = dev_id; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci i2c_addr = 0; 148262306a36Sopenharmony_ci set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */ 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci return 0; 149362306a36Sopenharmony_ci} 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_cistatic int hw20k2_i2c_uninit(struct hw *hw) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci unsigned int i2c_status; 149862306a36Sopenharmony_ci unsigned int i2c_addr; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci i2c_addr = 0; 150162306a36Sopenharmony_ci set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */ 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */ 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci return hw20k2_i2c_lock_chip(hw); 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_cistatic int hw20k2_i2c_wait_data_ready(struct hw *hw) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci int i = 0x400000; 151762306a36Sopenharmony_ci unsigned int ret; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci do { 152062306a36Sopenharmony_ci ret = hw_read_20kx(hw, I2C_IF_STATUS); 152162306a36Sopenharmony_ci } while ((!(ret & DATA_READY)) && --i); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci return i; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; 152962306a36Sopenharmony_ci unsigned int i2c_status; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); 153262306a36Sopenharmony_ci set_field(&i2c_status, I2C_STATUS_BC, 153362306a36Sopenharmony_ci (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size); 153462306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); 153562306a36Sopenharmony_ci if (!hw20k2_i2c_wait_data_ready(hw)) 153662306a36Sopenharmony_ci return -1; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_WDATA, addr); 153962306a36Sopenharmony_ci if (!hw20k2_i2c_wait_data_ready(hw)) 154062306a36Sopenharmony_ci return -1; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* Force a read operation */ 154362306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_RDATA, 0); 154462306a36Sopenharmony_ci if (!hw20k2_i2c_wait_data_ready(hw)) 154562306a36Sopenharmony_ci return -1; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci *datap = hw_read_20kx(hw, I2C_IF_RDATA); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci return 0; 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_cistatic int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) 155362306a36Sopenharmony_ci{ 155462306a36Sopenharmony_ci struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; 155562306a36Sopenharmony_ci unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr; 155662306a36Sopenharmony_ci unsigned int i2c_status; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci set_field(&i2c_status, I2C_STATUS_BC, 156162306a36Sopenharmony_ci (4 == (hw20k2->addr_size + hw20k2->data_size)) ? 156262306a36Sopenharmony_ci 0 : (hw20k2->addr_size + hw20k2->data_size)); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); 156562306a36Sopenharmony_ci hw20k2_i2c_wait_data_ready(hw); 156662306a36Sopenharmony_ci /* Dummy write to trigger the write operation */ 156762306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_WDATA, 0); 156862306a36Sopenharmony_ci hw20k2_i2c_wait_data_ready(hw); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci /* This is the real data */ 157162306a36Sopenharmony_ci hw_write_20kx(hw, I2C_IF_WDATA, i2c_data); 157262306a36Sopenharmony_ci hw20k2_i2c_wait_data_ready(hw); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci return 0; 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic void hw_dac_stop(struct hw *hw) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci u32 data; 158062306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 158162306a36Sopenharmony_ci data &= 0xFFFFFFFD; 158262306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 158362306a36Sopenharmony_ci usleep_range(10000, 11000); 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_cistatic void hw_dac_start(struct hw *hw) 158762306a36Sopenharmony_ci{ 158862306a36Sopenharmony_ci u32 data; 158962306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 159062306a36Sopenharmony_ci data |= 0x2; 159162306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 159262306a36Sopenharmony_ci msleep(50); 159362306a36Sopenharmony_ci} 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_cistatic void hw_dac_reset(struct hw *hw) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci hw_dac_stop(hw); 159862306a36Sopenharmony_ci hw_dac_start(hw); 159962306a36Sopenharmony_ci} 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic int hw_dac_init(struct hw *hw, const struct dac_conf *info) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci int err; 160462306a36Sopenharmony_ci u32 data; 160562306a36Sopenharmony_ci int i; 160662306a36Sopenharmony_ci struct regs_cs4382 cs_read = {0}; 160762306a36Sopenharmony_ci struct regs_cs4382 cs_def = { 160862306a36Sopenharmony_ci .mode_control_1 = 0x00000001, /* Mode Control 1 */ 160962306a36Sopenharmony_ci .mode_control_2 = 0x00000000, /* Mode Control 2 */ 161062306a36Sopenharmony_ci .mode_control_3 = 0x00000084, /* Mode Control 3 */ 161162306a36Sopenharmony_ci .filter_control = 0x00000000, /* Filter Control */ 161262306a36Sopenharmony_ci .invert_control = 0x00000000, /* Invert Control */ 161362306a36Sopenharmony_ci .mix_control_P1 = 0x00000024, /* Mixing Control Pair 1 */ 161462306a36Sopenharmony_ci .vol_control_A1 = 0x00000000, /* Vol Control A1 */ 161562306a36Sopenharmony_ci .vol_control_B1 = 0x00000000, /* Vol Control B1 */ 161662306a36Sopenharmony_ci .mix_control_P2 = 0x00000024, /* Mixing Control Pair 2 */ 161762306a36Sopenharmony_ci .vol_control_A2 = 0x00000000, /* Vol Control A2 */ 161862306a36Sopenharmony_ci .vol_control_B2 = 0x00000000, /* Vol Control B2 */ 161962306a36Sopenharmony_ci .mix_control_P3 = 0x00000024, /* Mixing Control Pair 3 */ 162062306a36Sopenharmony_ci .vol_control_A3 = 0x00000000, /* Vol Control A3 */ 162162306a36Sopenharmony_ci .vol_control_B3 = 0x00000000, /* Vol Control B3 */ 162262306a36Sopenharmony_ci .mix_control_P4 = 0x00000024, /* Mixing Control Pair 4 */ 162362306a36Sopenharmony_ci .vol_control_A4 = 0x00000000, /* Vol Control A4 */ 162462306a36Sopenharmony_ci .vol_control_B4 = 0x00000000 /* Vol Control B4 */ 162562306a36Sopenharmony_ci }; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (hw->model == CTSB1270) { 162862306a36Sopenharmony_ci hw_dac_stop(hw); 162962306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 163062306a36Sopenharmony_ci data &= ~0x0600; 163162306a36Sopenharmony_ci if (1 == info->msr) 163262306a36Sopenharmony_ci data |= 0x0000; /* Single Speed Mode 0-50kHz */ 163362306a36Sopenharmony_ci else if (2 == info->msr) 163462306a36Sopenharmony_ci data |= 0x0200; /* Double Speed Mode 50-100kHz */ 163562306a36Sopenharmony_ci else 163662306a36Sopenharmony_ci data |= 0x0600; /* Quad Speed Mode 100-200kHz */ 163762306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 163862306a36Sopenharmony_ci hw_dac_start(hw); 163962306a36Sopenharmony_ci return 0; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci /* Set DAC reset bit as output */ 164362306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_CTRL); 164462306a36Sopenharmony_ci data |= 0x02; 164562306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_CTRL, data); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci err = hw20k2_i2c_init(hw, 0x18, 1, 1); 164862306a36Sopenharmony_ci if (err < 0) 164962306a36Sopenharmony_ci goto End; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 165262306a36Sopenharmony_ci /* Reset DAC twice just in-case the chip 165362306a36Sopenharmony_ci * didn't initialized properly */ 165462306a36Sopenharmony_ci hw_dac_reset(hw); 165562306a36Sopenharmony_ci hw_dac_reset(hw); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) 165862306a36Sopenharmony_ci continue; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_MC2, &cs_read.mode_control_2)) 166162306a36Sopenharmony_ci continue; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_MC3, &cs_read.mode_control_3)) 166462306a36Sopenharmony_ci continue; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_FC, &cs_read.filter_control)) 166762306a36Sopenharmony_ci continue; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_IC, &cs_read.invert_control)) 167062306a36Sopenharmony_ci continue; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_XC1, &cs_read.mix_control_P1)) 167362306a36Sopenharmony_ci continue; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1)) 167662306a36Sopenharmony_ci continue; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1)) 167962306a36Sopenharmony_ci continue; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_XC2, &cs_read.mix_control_P2)) 168262306a36Sopenharmony_ci continue; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2)) 168562306a36Sopenharmony_ci continue; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2)) 168862306a36Sopenharmony_ci continue; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_XC3, &cs_read.mix_control_P3)) 169162306a36Sopenharmony_ci continue; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3)) 169462306a36Sopenharmony_ci continue; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3)) 169762306a36Sopenharmony_ci continue; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_XC4, &cs_read.mix_control_P4)) 170062306a36Sopenharmony_ci continue; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4)) 170362306a36Sopenharmony_ci continue; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4)) 170662306a36Sopenharmony_ci continue; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci if (memcmp(&cs_read, &cs_def, sizeof(cs_read))) 170962306a36Sopenharmony_ci continue; 171062306a36Sopenharmony_ci else 171162306a36Sopenharmony_ci break; 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci if (i >= 2) 171562306a36Sopenharmony_ci goto End; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci /* Note: Every I2C write must have some delay. 171862306a36Sopenharmony_ci * This is not a requirement but the delay works here... */ 171962306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_MC1, 0x80); 172062306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_MC2, 0x10); 172162306a36Sopenharmony_ci if (1 == info->msr) { 172262306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC1, 0x24); 172362306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC2, 0x24); 172462306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC3, 0x24); 172562306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC4, 0x24); 172662306a36Sopenharmony_ci } else if (2 == info->msr) { 172762306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC1, 0x25); 172862306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC2, 0x25); 172962306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC3, 0x25); 173062306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC4, 0x25); 173162306a36Sopenharmony_ci } else { 173262306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC1, 0x26); 173362306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC2, 0x26); 173462306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC3, 0x26); 173562306a36Sopenharmony_ci hw20k2_i2c_write(hw, CS4382_XC4, 0x26); 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci return 0; 173962306a36Sopenharmony_ciEnd: 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci hw20k2_i2c_uninit(hw); 174262306a36Sopenharmony_ci return -1; 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci/* ADC operations */ 174662306a36Sopenharmony_ci#define MAKE_WM8775_ADDR(addr, data) (u32)(((addr<<1)&0xFE)|((data>>8)&0x1)) 174762306a36Sopenharmony_ci#define MAKE_WM8775_DATA(data) (u32)(data&0xFF) 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci#define WM8775_IC 0x0B 175062306a36Sopenharmony_ci#define WM8775_MMC 0x0C 175162306a36Sopenharmony_ci#define WM8775_AADCL 0x0E 175262306a36Sopenharmony_ci#define WM8775_AADCR 0x0F 175362306a36Sopenharmony_ci#define WM8775_ADCMC 0x15 175462306a36Sopenharmony_ci#define WM8775_RESET 0x17 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci u32 data; 175962306a36Sopenharmony_ci if (hw->model == CTSB1270) { 176062306a36Sopenharmony_ci /* Titanium HD has two ADC chips, one for line in and one */ 176162306a36Sopenharmony_ci /* for MIC. We don't need to switch the ADC input. */ 176262306a36Sopenharmony_ci return 1; 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 176562306a36Sopenharmony_ci switch (type) { 176662306a36Sopenharmony_ci case ADC_MICIN: 176762306a36Sopenharmony_ci data = (data & (0x1 << 14)) ? 1 : 0; 176862306a36Sopenharmony_ci break; 176962306a36Sopenharmony_ci case ADC_LINEIN: 177062306a36Sopenharmony_ci data = (data & (0x1 << 14)) ? 0 : 1; 177162306a36Sopenharmony_ci break; 177262306a36Sopenharmony_ci default: 177362306a36Sopenharmony_ci data = 0; 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci return data; 177662306a36Sopenharmony_ci} 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci#define MIC_BOOST_0DB 0xCF 177962306a36Sopenharmony_ci#define MIC_BOOST_STEPS_PER_DB 2 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci u32 adcmc, gain; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci if (input > 3) 178662306a36Sopenharmony_ci input = 3; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */ 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc), 179162306a36Sopenharmony_ci MAKE_WM8775_DATA(adcmc)); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci if (gain_in_db < -103) 179462306a36Sopenharmony_ci gain_in_db = -103; 179562306a36Sopenharmony_ci if (gain_in_db > 24) 179662306a36Sopenharmony_ci gain_in_db = 24; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain), 180162306a36Sopenharmony_ci MAKE_WM8775_DATA(gain)); 180262306a36Sopenharmony_ci /* ...so there should be no need for the following. */ 180362306a36Sopenharmony_ci hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain), 180462306a36Sopenharmony_ci MAKE_WM8775_DATA(gain)); 180562306a36Sopenharmony_ci} 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_cistatic int hw_adc_input_select(struct hw *hw, enum ADCSRC type) 180862306a36Sopenharmony_ci{ 180962306a36Sopenharmony_ci u32 data; 181062306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 181162306a36Sopenharmony_ci switch (type) { 181262306a36Sopenharmony_ci case ADC_MICIN: 181362306a36Sopenharmony_ci data |= (0x1 << 14); 181462306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 181562306a36Sopenharmony_ci hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */ 181662306a36Sopenharmony_ci break; 181762306a36Sopenharmony_ci case ADC_LINEIN: 181862306a36Sopenharmony_ci data &= ~(0x1 << 14); 181962306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 182062306a36Sopenharmony_ci hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */ 182162306a36Sopenharmony_ci break; 182262306a36Sopenharmony_ci default: 182362306a36Sopenharmony_ci break; 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci return 0; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_cistatic int hw_adc_init(struct hw *hw, const struct adc_conf *info) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci int err; 183262306a36Sopenharmony_ci u32 data, ctl; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci /* Set ADC reset bit as output */ 183562306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_CTRL); 183662306a36Sopenharmony_ci data |= (0x1 << 15); 183762306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_CTRL, data); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci /* Initialize I2C */ 184062306a36Sopenharmony_ci err = hw20k2_i2c_init(hw, 0x1A, 1, 1); 184162306a36Sopenharmony_ci if (err < 0) { 184262306a36Sopenharmony_ci dev_alert(hw->card->dev, "Failure to acquire I2C!!!\n"); 184362306a36Sopenharmony_ci goto error; 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci /* Reset the ADC (reset is active low). */ 184762306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 184862306a36Sopenharmony_ci data &= ~(0x1 << 15); 184962306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci if (hw->model == CTSB1270) { 185262306a36Sopenharmony_ci /* Set up the PCM4220 ADC on Titanium HD */ 185362306a36Sopenharmony_ci data &= ~0x0C; 185462306a36Sopenharmony_ci if (1 == info->msr) 185562306a36Sopenharmony_ci data |= 0x00; /* Single Speed Mode 32-50kHz */ 185662306a36Sopenharmony_ci else if (2 == info->msr) 185762306a36Sopenharmony_ci data |= 0x08; /* Double Speed Mode 50-108kHz */ 185862306a36Sopenharmony_ci else 185962306a36Sopenharmony_ci data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */ 186062306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci usleep_range(10000, 11000); 186462306a36Sopenharmony_ci /* Return the ADC to normal operation. */ 186562306a36Sopenharmony_ci data |= (0x1 << 15); 186662306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 186762306a36Sopenharmony_ci msleep(50); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci /* I2C write to register offset 0x0B to set ADC LRCLK polarity */ 187062306a36Sopenharmony_ci /* invert bit, interface format to I2S, word length to 24-bit, */ 187162306a36Sopenharmony_ci /* enable ADC high pass filter. Fixes bug 5323? */ 187262306a36Sopenharmony_ci hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26), 187362306a36Sopenharmony_ci MAKE_WM8775_DATA(0x26)); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci /* Set the master mode (256fs) */ 187662306a36Sopenharmony_ci if (1 == info->msr) { 187762306a36Sopenharmony_ci /* slave mode, 128x oversampling 256fs */ 187862306a36Sopenharmony_ci hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), 187962306a36Sopenharmony_ci MAKE_WM8775_DATA(0x02)); 188062306a36Sopenharmony_ci } else if ((2 == info->msr) || (4 == info->msr)) { 188162306a36Sopenharmony_ci /* slave mode, 64x oversampling, 256fs */ 188262306a36Sopenharmony_ci hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), 188362306a36Sopenharmony_ci MAKE_WM8775_DATA(0x0A)); 188462306a36Sopenharmony_ci } else { 188562306a36Sopenharmony_ci dev_alert(hw->card->dev, 188662306a36Sopenharmony_ci "Invalid master sampling rate (msr %d)!!!\n", 188762306a36Sopenharmony_ci info->msr); 188862306a36Sopenharmony_ci err = -EINVAL; 188962306a36Sopenharmony_ci goto error; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (hw->model != CTSB1270) { 189362306a36Sopenharmony_ci /* Configure GPIO bit 14 change to line-in/mic-in */ 189462306a36Sopenharmony_ci ctl = hw_read_20kx(hw, GPIO_CTRL); 189562306a36Sopenharmony_ci ctl |= 0x1 << 14; 189662306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_CTRL, ctl); 189762306a36Sopenharmony_ci hw_adc_input_select(hw, ADC_LINEIN); 189862306a36Sopenharmony_ci } else { 189962306a36Sopenharmony_ci hw_wm8775_input_select(hw, 0, 0); 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci return 0; 190362306a36Sopenharmony_cierror: 190462306a36Sopenharmony_ci hw20k2_i2c_uninit(hw); 190562306a36Sopenharmony_ci return err; 190662306a36Sopenharmony_ci} 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_cistatic struct capabilities hw_capabilities(struct hw *hw) 190962306a36Sopenharmony_ci{ 191062306a36Sopenharmony_ci struct capabilities cap; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci cap.digit_io_switch = 0; 191362306a36Sopenharmony_ci cap.dedicated_mic = hw->model == CTSB1270; 191462306a36Sopenharmony_ci cap.output_switch = hw->model == CTSB1270; 191562306a36Sopenharmony_ci cap.mic_source_switch = hw->model == CTSB1270; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci return cap; 191862306a36Sopenharmony_ci} 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_cistatic int hw_output_switch_get(struct hw *hw) 192162306a36Sopenharmony_ci{ 192262306a36Sopenharmony_ci u32 data = hw_read_20kx(hw, GPIO_EXT_DATA); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci switch (data & 0x30) { 192562306a36Sopenharmony_ci case 0x00: 192662306a36Sopenharmony_ci return 0; 192762306a36Sopenharmony_ci case 0x10: 192862306a36Sopenharmony_ci return 1; 192962306a36Sopenharmony_ci case 0x20: 193062306a36Sopenharmony_ci return 2; 193162306a36Sopenharmony_ci default: 193262306a36Sopenharmony_ci return 3; 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci} 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_cistatic int hw_output_switch_put(struct hw *hw, int position) 193762306a36Sopenharmony_ci{ 193862306a36Sopenharmony_ci u32 data; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci if (position == hw_output_switch_get(hw)) 194162306a36Sopenharmony_ci return 0; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci /* Mute line and headphones (intended for anti-pop). */ 194462306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 194562306a36Sopenharmony_ci data |= (0x03 << 11); 194662306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30; 194962306a36Sopenharmony_ci switch (position) { 195062306a36Sopenharmony_ci case 0: 195162306a36Sopenharmony_ci break; 195262306a36Sopenharmony_ci case 1: 195362306a36Sopenharmony_ci data |= 0x10; 195462306a36Sopenharmony_ci break; 195562306a36Sopenharmony_ci default: 195662306a36Sopenharmony_ci data |= 0x20; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_EXT_DATA, data); 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci /* Unmute line and headphones. */ 196162306a36Sopenharmony_ci data = hw_read_20kx(hw, GPIO_DATA); 196262306a36Sopenharmony_ci data &= ~(0x03 << 11); 196362306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_DATA, data); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci return 1; 196662306a36Sopenharmony_ci} 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_cistatic int hw_mic_source_switch_get(struct hw *hw) 196962306a36Sopenharmony_ci{ 197062306a36Sopenharmony_ci struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci return hw20k2->mic_source; 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_cistatic int hw_mic_source_switch_put(struct hw *hw, int position) 197662306a36Sopenharmony_ci{ 197762306a36Sopenharmony_ci struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci if (position == hw20k2->mic_source) 198062306a36Sopenharmony_ci return 0; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci switch (position) { 198362306a36Sopenharmony_ci case 0: 198462306a36Sopenharmony_ci hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */ 198562306a36Sopenharmony_ci break; 198662306a36Sopenharmony_ci case 1: 198762306a36Sopenharmony_ci hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */ 198862306a36Sopenharmony_ci break; 198962306a36Sopenharmony_ci case 2: 199062306a36Sopenharmony_ci hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */ 199162306a36Sopenharmony_ci break; 199262306a36Sopenharmony_ci default: 199362306a36Sopenharmony_ci return 0; 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci hw20k2->mic_source = position; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci return 1; 199962306a36Sopenharmony_ci} 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_cistatic irqreturn_t ct_20k2_interrupt(int irq, void *dev_id) 200262306a36Sopenharmony_ci{ 200362306a36Sopenharmony_ci struct hw *hw = dev_id; 200462306a36Sopenharmony_ci unsigned int status; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci status = hw_read_20kx(hw, GIP); 200762306a36Sopenharmony_ci if (!status) 200862306a36Sopenharmony_ci return IRQ_NONE; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci if (hw->irq_callback) 201162306a36Sopenharmony_ci hw->irq_callback(hw->irq_callback_data, status); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci hw_write_20kx(hw, GIP, status); 201462306a36Sopenharmony_ci return IRQ_HANDLED; 201562306a36Sopenharmony_ci} 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_cistatic int hw_card_start(struct hw *hw) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci int err = 0; 202062306a36Sopenharmony_ci struct pci_dev *pci = hw->pci; 202162306a36Sopenharmony_ci unsigned int gctl; 202262306a36Sopenharmony_ci const unsigned int dma_bits = BITS_PER_LONG; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci err = pci_enable_device(pci); 202562306a36Sopenharmony_ci if (err < 0) 202662306a36Sopenharmony_ci return err; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci /* Set DMA transfer mask */ 202962306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(dma_bits))) 203062306a36Sopenharmony_ci dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32)); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if (!hw->io_base) { 203362306a36Sopenharmony_ci err = pci_request_regions(pci, "XFi"); 203462306a36Sopenharmony_ci if (err < 0) 203562306a36Sopenharmony_ci goto error1; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci hw->io_base = pci_resource_start(hw->pci, 2); 203862306a36Sopenharmony_ci hw->mem_base = ioremap(hw->io_base, 203962306a36Sopenharmony_ci pci_resource_len(hw->pci, 2)); 204062306a36Sopenharmony_ci if (!hw->mem_base) { 204162306a36Sopenharmony_ci err = -ENOENT; 204262306a36Sopenharmony_ci goto error2; 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci } 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* Switch to 20k2 mode from UAA mode. */ 204762306a36Sopenharmony_ci gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); 204862306a36Sopenharmony_ci set_field(&gctl, GCTL_UAA, 0); 204962306a36Sopenharmony_ci hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if (hw->irq < 0) { 205262306a36Sopenharmony_ci err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED, 205362306a36Sopenharmony_ci KBUILD_MODNAME, hw); 205462306a36Sopenharmony_ci if (err < 0) { 205562306a36Sopenharmony_ci dev_err(hw->card->dev, 205662306a36Sopenharmony_ci "XFi: Cannot get irq %d\n", pci->irq); 205762306a36Sopenharmony_ci goto error2; 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci hw->irq = pci->irq; 206062306a36Sopenharmony_ci hw->card->sync_irq = hw->irq; 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci pci_set_master(pci); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci return 0; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci/*error3: 206862306a36Sopenharmony_ci iounmap((void *)hw->mem_base); 206962306a36Sopenharmony_ci hw->mem_base = (unsigned long)NULL;*/ 207062306a36Sopenharmony_cierror2: 207162306a36Sopenharmony_ci pci_release_regions(pci); 207262306a36Sopenharmony_ci hw->io_base = 0; 207362306a36Sopenharmony_cierror1: 207462306a36Sopenharmony_ci pci_disable_device(pci); 207562306a36Sopenharmony_ci return err; 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic int hw_card_stop(struct hw *hw) 207962306a36Sopenharmony_ci{ 208062306a36Sopenharmony_ci unsigned int data; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci /* disable transport bus master and queueing of request */ 208362306a36Sopenharmony_ci hw_write_20kx(hw, TRANSPORT_CTL, 0x00); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci /* disable pll */ 208662306a36Sopenharmony_ci data = hw_read_20kx(hw, PLL_ENB); 208762306a36Sopenharmony_ci hw_write_20kx(hw, PLL_ENB, (data & (~0x07))); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci /* TODO: Disable interrupt and so on... */ 209062306a36Sopenharmony_ci return 0; 209162306a36Sopenharmony_ci} 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_cistatic int hw_card_shutdown(struct hw *hw) 209462306a36Sopenharmony_ci{ 209562306a36Sopenharmony_ci if (hw->irq >= 0) 209662306a36Sopenharmony_ci free_irq(hw->irq, hw); 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci hw->irq = -1; 209962306a36Sopenharmony_ci iounmap(hw->mem_base); 210062306a36Sopenharmony_ci hw->mem_base = NULL; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci if (hw->io_base) 210362306a36Sopenharmony_ci pci_release_regions(hw->pci); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci hw->io_base = 0; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci pci_disable_device(hw->pci); 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci return 0; 211062306a36Sopenharmony_ci} 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_cistatic int hw_card_init(struct hw *hw, struct card_conf *info) 211362306a36Sopenharmony_ci{ 211462306a36Sopenharmony_ci int err; 211562306a36Sopenharmony_ci unsigned int gctl; 211662306a36Sopenharmony_ci u32 data = 0; 211762306a36Sopenharmony_ci struct dac_conf dac_info = {0}; 211862306a36Sopenharmony_ci struct adc_conf adc_info = {0}; 211962306a36Sopenharmony_ci struct daio_conf daio_info = {0}; 212062306a36Sopenharmony_ci struct trn_conf trn_info = {0}; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci /* Get PCI io port/memory base address and 212362306a36Sopenharmony_ci * do 20kx core switch if needed. */ 212462306a36Sopenharmony_ci err = hw_card_start(hw); 212562306a36Sopenharmony_ci if (err) 212662306a36Sopenharmony_ci return err; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci /* PLL init */ 212962306a36Sopenharmony_ci err = hw_pll_init(hw, info->rsr); 213062306a36Sopenharmony_ci if (err < 0) 213162306a36Sopenharmony_ci return err; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci /* kick off auto-init */ 213462306a36Sopenharmony_ci err = hw_auto_init(hw); 213562306a36Sopenharmony_ci if (err < 0) 213662306a36Sopenharmony_ci return err; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); 213962306a36Sopenharmony_ci set_field(&gctl, GCTL_DBP, 1); 214062306a36Sopenharmony_ci set_field(&gctl, GCTL_TBP, 1); 214162306a36Sopenharmony_ci set_field(&gctl, GCTL_FBP, 1); 214262306a36Sopenharmony_ci set_field(&gctl, GCTL_DPC, 0); 214362306a36Sopenharmony_ci hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci /* Reset all global pending interrupts */ 214662306a36Sopenharmony_ci hw_write_20kx(hw, GIE, 0); 214762306a36Sopenharmony_ci /* Reset all SRC pending interrupts */ 214862306a36Sopenharmony_ci hw_write_20kx(hw, SRC_IP, 0); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci if (hw->model != CTSB1270) { 215162306a36Sopenharmony_ci /* TODO: detect the card ID and configure GPIO accordingly. */ 215262306a36Sopenharmony_ci /* Configures GPIO (0xD802 0x98028) */ 215362306a36Sopenharmony_ci /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ 215462306a36Sopenharmony_ci /* Configures GPIO (SB0880) */ 215562306a36Sopenharmony_ci /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ 215662306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_CTRL, 0xD802); 215762306a36Sopenharmony_ci } else { 215862306a36Sopenharmony_ci hw_write_20kx(hw, GPIO_CTRL, 0x9E5F); 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci /* Enable audio ring */ 216162306a36Sopenharmony_ci hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci trn_info.vm_pgt_phys = info->vm_pgt_phys; 216462306a36Sopenharmony_ci err = hw_trn_init(hw, &trn_info); 216562306a36Sopenharmony_ci if (err < 0) 216662306a36Sopenharmony_ci return err; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci daio_info.msr = info->msr; 216962306a36Sopenharmony_ci err = hw_daio_init(hw, &daio_info); 217062306a36Sopenharmony_ci if (err < 0) 217162306a36Sopenharmony_ci return err; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci dac_info.msr = info->msr; 217462306a36Sopenharmony_ci err = hw_dac_init(hw, &dac_info); 217562306a36Sopenharmony_ci if (err < 0) 217662306a36Sopenharmony_ci return err; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci adc_info.msr = info->msr; 217962306a36Sopenharmony_ci adc_info.input = ADC_LINEIN; 218062306a36Sopenharmony_ci adc_info.mic20db = 0; 218162306a36Sopenharmony_ci err = hw_adc_init(hw, &adc_info); 218262306a36Sopenharmony_ci if (err < 0) 218362306a36Sopenharmony_ci return err; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci data = hw_read_20kx(hw, SRC_MCTL); 218662306a36Sopenharmony_ci data |= 0x1; /* Enables input from the audio ring */ 218762306a36Sopenharmony_ci hw_write_20kx(hw, SRC_MCTL, data); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci return 0; 219062306a36Sopenharmony_ci} 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 219362306a36Sopenharmony_cistatic int hw_suspend(struct hw *hw) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci hw_card_stop(hw); 219662306a36Sopenharmony_ci return 0; 219762306a36Sopenharmony_ci} 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cistatic int hw_resume(struct hw *hw, struct card_conf *info) 220062306a36Sopenharmony_ci{ 220162306a36Sopenharmony_ci /* Re-initialize card hardware. */ 220262306a36Sopenharmony_ci return hw_card_init(hw, info); 220362306a36Sopenharmony_ci} 220462306a36Sopenharmony_ci#endif 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_cistatic u32 hw_read_20kx(struct hw *hw, u32 reg) 220762306a36Sopenharmony_ci{ 220862306a36Sopenharmony_ci return readl(hw->mem_base + reg); 220962306a36Sopenharmony_ci} 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic void hw_write_20kx(struct hw *hw, u32 reg, u32 data) 221262306a36Sopenharmony_ci{ 221362306a36Sopenharmony_ci writel(data, hw->mem_base + reg); 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_cistatic const struct hw ct20k2_preset = { 221762306a36Sopenharmony_ci .irq = -1, 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci .card_init = hw_card_init, 222062306a36Sopenharmony_ci .card_stop = hw_card_stop, 222162306a36Sopenharmony_ci .pll_init = hw_pll_init, 222262306a36Sopenharmony_ci .is_adc_source_selected = hw_is_adc_input_selected, 222362306a36Sopenharmony_ci .select_adc_source = hw_adc_input_select, 222462306a36Sopenharmony_ci .capabilities = hw_capabilities, 222562306a36Sopenharmony_ci .output_switch_get = hw_output_switch_get, 222662306a36Sopenharmony_ci .output_switch_put = hw_output_switch_put, 222762306a36Sopenharmony_ci .mic_source_switch_get = hw_mic_source_switch_get, 222862306a36Sopenharmony_ci .mic_source_switch_put = hw_mic_source_switch_put, 222962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 223062306a36Sopenharmony_ci .suspend = hw_suspend, 223162306a36Sopenharmony_ci .resume = hw_resume, 223262306a36Sopenharmony_ci#endif 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, 223562306a36Sopenharmony_ci .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, 223662306a36Sopenharmony_ci .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk, 223762306a36Sopenharmony_ci .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk, 223862306a36Sopenharmony_ci .src_set_state = src_set_state, 223962306a36Sopenharmony_ci .src_set_bm = src_set_bm, 224062306a36Sopenharmony_ci .src_set_rsr = src_set_rsr, 224162306a36Sopenharmony_ci .src_set_sf = src_set_sf, 224262306a36Sopenharmony_ci .src_set_wr = src_set_wr, 224362306a36Sopenharmony_ci .src_set_pm = src_set_pm, 224462306a36Sopenharmony_ci .src_set_rom = src_set_rom, 224562306a36Sopenharmony_ci .src_set_vo = src_set_vo, 224662306a36Sopenharmony_ci .src_set_st = src_set_st, 224762306a36Sopenharmony_ci .src_set_ie = src_set_ie, 224862306a36Sopenharmony_ci .src_set_ilsz = src_set_ilsz, 224962306a36Sopenharmony_ci .src_set_bp = src_set_bp, 225062306a36Sopenharmony_ci .src_set_cisz = src_set_cisz, 225162306a36Sopenharmony_ci .src_set_ca = src_set_ca, 225262306a36Sopenharmony_ci .src_set_sa = src_set_sa, 225362306a36Sopenharmony_ci .src_set_la = src_set_la, 225462306a36Sopenharmony_ci .src_set_pitch = src_set_pitch, 225562306a36Sopenharmony_ci .src_set_dirty = src_set_dirty, 225662306a36Sopenharmony_ci .src_set_clear_zbufs = src_set_clear_zbufs, 225762306a36Sopenharmony_ci .src_set_dirty_all = src_set_dirty_all, 225862306a36Sopenharmony_ci .src_commit_write = src_commit_write, 225962306a36Sopenharmony_ci .src_get_ca = src_get_ca, 226062306a36Sopenharmony_ci .src_get_dirty = src_get_dirty, 226162306a36Sopenharmony_ci .src_dirty_conj_mask = src_dirty_conj_mask, 226262306a36Sopenharmony_ci .src_mgr_enbs_src = src_mgr_enbs_src, 226362306a36Sopenharmony_ci .src_mgr_enb_src = src_mgr_enb_src, 226462306a36Sopenharmony_ci .src_mgr_dsb_src = src_mgr_dsb_src, 226562306a36Sopenharmony_ci .src_mgr_commit_write = src_mgr_commit_write, 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk, 226862306a36Sopenharmony_ci .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk, 226962306a36Sopenharmony_ci .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc, 227062306a36Sopenharmony_ci .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser, 227162306a36Sopenharmony_ci .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt, 227262306a36Sopenharmony_ci .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr, 227362306a36Sopenharmony_ci .srcimp_mgr_commit_write = srcimp_mgr_commit_write, 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk, 227662306a36Sopenharmony_ci .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk, 227762306a36Sopenharmony_ci .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk, 227862306a36Sopenharmony_ci .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk, 227962306a36Sopenharmony_ci .amixer_set_mode = amixer_set_mode, 228062306a36Sopenharmony_ci .amixer_set_iv = amixer_set_iv, 228162306a36Sopenharmony_ci .amixer_set_x = amixer_set_x, 228262306a36Sopenharmony_ci .amixer_set_y = amixer_set_y, 228362306a36Sopenharmony_ci .amixer_set_sadr = amixer_set_sadr, 228462306a36Sopenharmony_ci .amixer_set_se = amixer_set_se, 228562306a36Sopenharmony_ci .amixer_set_dirty = amixer_set_dirty, 228662306a36Sopenharmony_ci .amixer_set_dirty_all = amixer_set_dirty_all, 228762306a36Sopenharmony_ci .amixer_commit_write = amixer_commit_write, 228862306a36Sopenharmony_ci .amixer_get_y = amixer_get_y, 228962306a36Sopenharmony_ci .amixer_get_dirty = amixer_get_dirty, 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci .dai_get_ctrl_blk = dai_get_ctrl_blk, 229262306a36Sopenharmony_ci .dai_put_ctrl_blk = dai_put_ctrl_blk, 229362306a36Sopenharmony_ci .dai_srt_set_srco = dai_srt_set_srco, 229462306a36Sopenharmony_ci .dai_srt_set_srcm = dai_srt_set_srcm, 229562306a36Sopenharmony_ci .dai_srt_set_rsr = dai_srt_set_rsr, 229662306a36Sopenharmony_ci .dai_srt_set_drat = dai_srt_set_drat, 229762306a36Sopenharmony_ci .dai_srt_set_ec = dai_srt_set_ec, 229862306a36Sopenharmony_ci .dai_srt_set_et = dai_srt_set_et, 229962306a36Sopenharmony_ci .dai_commit_write = dai_commit_write, 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci .dao_get_ctrl_blk = dao_get_ctrl_blk, 230262306a36Sopenharmony_ci .dao_put_ctrl_blk = dao_put_ctrl_blk, 230362306a36Sopenharmony_ci .dao_set_spos = dao_set_spos, 230462306a36Sopenharmony_ci .dao_commit_write = dao_commit_write, 230562306a36Sopenharmony_ci .dao_get_spos = dao_get_spos, 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk, 230862306a36Sopenharmony_ci .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk, 230962306a36Sopenharmony_ci .daio_mgr_enb_dai = daio_mgr_enb_dai, 231062306a36Sopenharmony_ci .daio_mgr_dsb_dai = daio_mgr_dsb_dai, 231162306a36Sopenharmony_ci .daio_mgr_enb_dao = daio_mgr_enb_dao, 231262306a36Sopenharmony_ci .daio_mgr_dsb_dao = daio_mgr_dsb_dao, 231362306a36Sopenharmony_ci .daio_mgr_dao_init = daio_mgr_dao_init, 231462306a36Sopenharmony_ci .daio_mgr_set_imaparc = daio_mgr_set_imaparc, 231562306a36Sopenharmony_ci .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, 231662306a36Sopenharmony_ci .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, 231762306a36Sopenharmony_ci .daio_mgr_commit_write = daio_mgr_commit_write, 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci .set_timer_irq = set_timer_irq, 232062306a36Sopenharmony_ci .set_timer_tick = set_timer_tick, 232162306a36Sopenharmony_ci .get_wc = get_wc, 232262306a36Sopenharmony_ci}; 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ciint create_20k2_hw_obj(struct hw **rhw) 232562306a36Sopenharmony_ci{ 232662306a36Sopenharmony_ci struct hw20k2 *hw20k2; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci *rhw = NULL; 232962306a36Sopenharmony_ci hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL); 233062306a36Sopenharmony_ci if (!hw20k2) 233162306a36Sopenharmony_ci return -ENOMEM; 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci hw20k2->hw = ct20k2_preset; 233462306a36Sopenharmony_ci *rhw = &hw20k2->hw; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci return 0; 233762306a36Sopenharmony_ci} 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ciint destroy_20k2_hw_obj(struct hw *hw) 234062306a36Sopenharmony_ci{ 234162306a36Sopenharmony_ci if (hw->io_base) 234262306a36Sopenharmony_ci hw_card_shutdown(hw); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci kfree(hw); 234562306a36Sopenharmony_ci return 0; 234662306a36Sopenharmony_ci} 2347