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