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 cthw20k1.c 98cc72361SWai Yew CHAY * 108cc72361SWai Yew CHAY * @Brief 118cc72361SWai Yew CHAY * This file contains the implementation of hardware access methord for 20k1. 128cc72361SWai Yew CHAY * 138cc72361SWai Yew CHAY * @Author Liu Chun 148cc72361SWai Yew CHAY * @Date Jun 24 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/spinlock.h> 248cc72361SWai Yew CHAY #include <linux/kernel.h> 258cc72361SWai Yew CHAY #include <linux/interrupt.h> 26d0da727eSTakashi Iwai #include <linux/delay.h> 276d74b86dSTakashi Iwai #include "cthw20k1.h" 286d74b86dSTakashi Iwai #include "ct20k1reg.h" 298cc72361SWai Yew CHAY 306d74b86dSTakashi Iwai #if BITS_PER_LONG == 32 316d74b86dSTakashi Iwai #define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ 326d74b86dSTakashi Iwai #else 336d74b86dSTakashi Iwai #define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ 346d74b86dSTakashi Iwai #endif 358cc72361SWai Yew CHAY 368cc72361SWai Yew CHAY struct hw20k1 { 378cc72361SWai Yew CHAY struct hw hw; 388cc72361SWai Yew CHAY spinlock_t reg_20k1_lock; 398cc72361SWai Yew CHAY spinlock_t reg_pci_lock; 408cc72361SWai Yew CHAY }; 418cc72361SWai Yew CHAY 428cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg); 438cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data); 448cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg); 458cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data); 468cc72361SWai Yew CHAY 478cc72361SWai Yew CHAY /* 488cc72361SWai Yew CHAY * Type definition block. 498cc72361SWai Yew CHAY * The layout of control structures can be directly applied on 20k2 chip. 508cc72361SWai Yew CHAY */ 518cc72361SWai Yew CHAY 528cc72361SWai Yew CHAY /* 538cc72361SWai Yew CHAY * SRC control block definitions. 548cc72361SWai Yew CHAY */ 558cc72361SWai Yew CHAY 568cc72361SWai Yew CHAY /* SRC resource control block */ 578cc72361SWai Yew CHAY #define SRCCTL_STATE 0x00000007 588cc72361SWai Yew CHAY #define SRCCTL_BM 0x00000008 598cc72361SWai Yew CHAY #define SRCCTL_RSR 0x00000030 608cc72361SWai Yew CHAY #define SRCCTL_SF 0x000001C0 618cc72361SWai Yew CHAY #define SRCCTL_WR 0x00000200 628cc72361SWai Yew CHAY #define SRCCTL_PM 0x00000400 638cc72361SWai Yew CHAY #define SRCCTL_ROM 0x00001800 648cc72361SWai Yew CHAY #define SRCCTL_VO 0x00002000 658cc72361SWai Yew CHAY #define SRCCTL_ST 0x00004000 668cc72361SWai Yew CHAY #define SRCCTL_IE 0x00008000 678cc72361SWai Yew CHAY #define SRCCTL_ILSZ 0x000F0000 688cc72361SWai Yew CHAY #define SRCCTL_BP 0x00100000 698cc72361SWai Yew CHAY 708cc72361SWai Yew CHAY #define SRCCCR_CISZ 0x000007FF 718cc72361SWai Yew CHAY #define SRCCCR_CWA 0x001FF800 728cc72361SWai Yew CHAY #define SRCCCR_D 0x00200000 738cc72361SWai Yew CHAY #define SRCCCR_RS 0x01C00000 748cc72361SWai Yew CHAY #define SRCCCR_NAL 0x3E000000 758cc72361SWai Yew CHAY #define SRCCCR_RA 0xC0000000 768cc72361SWai Yew CHAY 778cc72361SWai Yew CHAY #define SRCCA_CA 0x03FFFFFF 788cc72361SWai Yew CHAY #define SRCCA_RS 0x1C000000 798cc72361SWai Yew CHAY #define SRCCA_NAL 0xE0000000 808cc72361SWai Yew CHAY 818cc72361SWai Yew CHAY #define SRCSA_SA 0x03FFFFFF 828cc72361SWai Yew CHAY 838cc72361SWai Yew CHAY #define SRCLA_LA 0x03FFFFFF 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); 1718cc72361SWai Yew CHAY if (NULL == 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 { 1818cc72361SWai Yew CHAY kfree((struct src_rsc_ctrl_blk *)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; 3728cc72361SWai Yew CHAY int i = 0; 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, SRCUPZ+idx*0x100+i*0x4, 0); 3788cc72361SWai Yew CHAY 3798cc72361SWai Yew CHAY for (i = 0; i < 4; i++) 3808cc72361SWai Yew CHAY hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0); 3818cc72361SWai Yew CHAY 3828cc72361SWai Yew CHAY for (i = 0; i < 8; i++) 3838cc72361SWai Yew CHAY hw_write_20kx(hw, SRCDN1Z+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, PRING_LO_HI+4*pm_idx, ctl->mpr); 3948cc72361SWai Yew CHAY hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3); 3958cc72361SWai Yew CHAY hw_write_20kx(hw, 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, SRCSA+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, SRCLA+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, SRCCA+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, SRCCF+idx*0x100, 0x0); 4138cc72361SWai Yew CHAY 4148cc72361SWai Yew CHAY if (ctl->dirty.bf.ccr) { 4158cc72361SWai Yew CHAY hw_write_20kx(hw, SRCCCR+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, SRCCTL+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, SRCCA+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 = ~(0x0); 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; 4718cc72361SWai Yew CHAY int i = 0; 4728cc72361SWai Yew CHAY unsigned int ret = 0; 4738cc72361SWai Yew CHAY 4748cc72361SWai Yew CHAY if (ctl->dirty.bf.enbsa) { 4758cc72361SWai Yew CHAY do { 4768cc72361SWai Yew CHAY ret = hw_read_20kx(hw, SRCENBSTAT); 4778cc72361SWai Yew CHAY } while (ret & 0x1); 4788cc72361SWai Yew CHAY hw_write_20kx(hw, SRCENBS, 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, SRCENB+(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); 4978cc72361SWai Yew CHAY if (NULL == 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 { 5078cc72361SWai Yew CHAY kfree((struct src_mgr_ctrl_blk *)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); 5188cc72361SWai Yew CHAY if (NULL == 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 { 5288cc72361SWai Yew CHAY kfree((struct srcimp_mgr_ctrl_blk *)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 *ctl = blk; 5638cc72361SWai Yew CHAY 5648cc72361SWai Yew CHAY ctl->srcimap.idx = addr; 5658cc72361SWai Yew CHAY ctl->dirty.bf.srcimap = 1; 5668cc72361SWai Yew CHAY return 0; 5678cc72361SWai Yew CHAY } 5688cc72361SWai Yew CHAY 5698cc72361SWai Yew CHAY static int srcimp_mgr_commit_write(struct hw *hw, void *blk) 5708cc72361SWai Yew CHAY { 5718cc72361SWai Yew CHAY struct srcimp_mgr_ctrl_blk *ctl = blk; 5728cc72361SWai Yew CHAY 5738cc72361SWai Yew CHAY if (ctl->dirty.bf.srcimap) { 5748cc72361SWai Yew CHAY hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100, 5758cc72361SWai Yew CHAY ctl->srcimap.srcaim); 5768cc72361SWai Yew CHAY ctl->dirty.bf.srcimap = 0; 5778cc72361SWai Yew CHAY } 5788cc72361SWai Yew CHAY 5798cc72361SWai Yew CHAY return 0; 5808cc72361SWai Yew CHAY } 5818cc72361SWai Yew CHAY 5828cc72361SWai Yew CHAY /* 5838cc72361SWai Yew CHAY * AMIXER control block definitions. 5848cc72361SWai Yew CHAY */ 5858cc72361SWai Yew CHAY 5868cc72361SWai Yew CHAY #define AMOPLO_M 0x00000003 5878cc72361SWai Yew CHAY #define AMOPLO_X 0x0003FFF0 5888cc72361SWai Yew CHAY #define AMOPLO_Y 0xFFFC0000 5898cc72361SWai Yew CHAY 5908cc72361SWai Yew CHAY #define AMOPHI_SADR 0x000000FF 5918cc72361SWai Yew CHAY #define AMOPHI_SE 0x80000000 5928cc72361SWai Yew CHAY 5938cc72361SWai Yew CHAY /* AMIXER resource register dirty flags */ 5948cc72361SWai Yew CHAY union amixer_dirty { 5958cc72361SWai Yew CHAY struct { 5968cc72361SWai Yew CHAY u16 amoplo:1; 5978cc72361SWai Yew CHAY u16 amophi:1; 5988cc72361SWai Yew CHAY u16 rsv:14; 5998cc72361SWai Yew CHAY } bf; 6008cc72361SWai Yew CHAY u16 data; 6018cc72361SWai Yew CHAY }; 6028cc72361SWai Yew CHAY 6038cc72361SWai Yew CHAY /* AMIXER resource control block */ 6048cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk { 6058cc72361SWai Yew CHAY unsigned int amoplo; 6068cc72361SWai Yew CHAY unsigned int amophi; 6078cc72361SWai Yew CHAY union amixer_dirty dirty; 6088cc72361SWai Yew CHAY }; 6098cc72361SWai Yew CHAY 6108cc72361SWai Yew CHAY static int amixer_set_mode(void *blk, unsigned int mode) 6118cc72361SWai Yew CHAY { 6128cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *ctl = blk; 6138cc72361SWai Yew CHAY 6148cc72361SWai Yew CHAY set_field(&ctl->amoplo, AMOPLO_M, mode); 6158cc72361SWai Yew CHAY ctl->dirty.bf.amoplo = 1; 6168cc72361SWai Yew CHAY return 0; 6178cc72361SWai Yew CHAY } 6188cc72361SWai Yew CHAY 6198cc72361SWai Yew CHAY static int amixer_set_iv(void *blk, unsigned int iv) 6208cc72361SWai Yew CHAY { 6218cc72361SWai Yew CHAY /* 20k1 amixer does not have this field */ 6228cc72361SWai Yew CHAY return 0; 6238cc72361SWai Yew CHAY } 6248cc72361SWai Yew CHAY 6258cc72361SWai Yew CHAY static int amixer_set_x(void *blk, unsigned int x) 6268cc72361SWai Yew CHAY { 6278cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *ctl = blk; 6288cc72361SWai Yew CHAY 6298cc72361SWai Yew CHAY set_field(&ctl->amoplo, AMOPLO_X, x); 6308cc72361SWai Yew CHAY ctl->dirty.bf.amoplo = 1; 6318cc72361SWai Yew CHAY return 0; 6328cc72361SWai Yew CHAY } 6338cc72361SWai Yew CHAY 6348cc72361SWai Yew CHAY static int amixer_set_y(void *blk, unsigned int y) 6358cc72361SWai Yew CHAY { 6368cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *ctl = blk; 6378cc72361SWai Yew CHAY 6388cc72361SWai Yew CHAY set_field(&ctl->amoplo, AMOPLO_Y, y); 6398cc72361SWai Yew CHAY ctl->dirty.bf.amoplo = 1; 6408cc72361SWai Yew CHAY return 0; 6418cc72361SWai Yew CHAY } 6428cc72361SWai Yew CHAY 6438cc72361SWai Yew CHAY static int amixer_set_sadr(void *blk, unsigned int sadr) 6448cc72361SWai Yew CHAY { 6458cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *ctl = blk; 6468cc72361SWai Yew CHAY 6478cc72361SWai Yew CHAY set_field(&ctl->amophi, AMOPHI_SADR, sadr); 6488cc72361SWai Yew CHAY ctl->dirty.bf.amophi = 1; 6498cc72361SWai Yew CHAY return 0; 6508cc72361SWai Yew CHAY } 6518cc72361SWai Yew CHAY 6528cc72361SWai Yew CHAY static int amixer_set_se(void *blk, unsigned int se) 6538cc72361SWai Yew CHAY { 6548cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *ctl = blk; 6558cc72361SWai Yew CHAY 6568cc72361SWai Yew CHAY set_field(&ctl->amophi, AMOPHI_SE, se); 6578cc72361SWai Yew CHAY ctl->dirty.bf.amophi = 1; 6588cc72361SWai Yew CHAY return 0; 6598cc72361SWai Yew CHAY } 6608cc72361SWai Yew CHAY 6618cc72361SWai Yew CHAY static int amixer_set_dirty(void *blk, unsigned int flags) 6628cc72361SWai Yew CHAY { 6638cc72361SWai Yew CHAY ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); 6648cc72361SWai Yew CHAY return 0; 6658cc72361SWai Yew CHAY } 6668cc72361SWai Yew CHAY 6678cc72361SWai Yew CHAY static int amixer_set_dirty_all(void *blk) 6688cc72361SWai Yew CHAY { 6698cc72361SWai Yew CHAY ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); 6708cc72361SWai Yew CHAY return 0; 6718cc72361SWai Yew CHAY } 6728cc72361SWai Yew CHAY 6738cc72361SWai Yew CHAY static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) 6748cc72361SWai Yew CHAY { 6758cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *ctl = blk; 6768cc72361SWai Yew CHAY 6778cc72361SWai Yew CHAY if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { 6788cc72361SWai Yew CHAY hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo); 6798cc72361SWai Yew CHAY ctl->dirty.bf.amoplo = 0; 6808cc72361SWai Yew CHAY hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi); 6818cc72361SWai Yew CHAY ctl->dirty.bf.amophi = 0; 6828cc72361SWai Yew CHAY } 6838cc72361SWai Yew CHAY 6848cc72361SWai Yew CHAY return 0; 6858cc72361SWai Yew CHAY } 6868cc72361SWai Yew CHAY 6878cc72361SWai Yew CHAY static int amixer_get_y(void *blk) 6888cc72361SWai Yew CHAY { 6898cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *ctl = blk; 6908cc72361SWai Yew CHAY 6918cc72361SWai Yew CHAY return get_field(ctl->amoplo, AMOPLO_Y); 6928cc72361SWai Yew CHAY } 6938cc72361SWai Yew CHAY 6948cc72361SWai Yew CHAY static unsigned int amixer_get_dirty(void *blk) 6958cc72361SWai Yew CHAY { 6968cc72361SWai Yew CHAY return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; 6978cc72361SWai Yew CHAY } 6988cc72361SWai Yew CHAY 6998cc72361SWai Yew CHAY static int amixer_rsc_get_ctrl_blk(void **rblk) 7008cc72361SWai Yew CHAY { 7018cc72361SWai Yew CHAY struct amixer_rsc_ctrl_blk *blk; 7028cc72361SWai Yew CHAY 7038cc72361SWai Yew CHAY *rblk = NULL; 7048cc72361SWai Yew CHAY blk = kzalloc(sizeof(*blk), GFP_KERNEL); 7058cc72361SWai Yew CHAY if (NULL == blk) 7068cc72361SWai Yew CHAY return -ENOMEM; 7078cc72361SWai Yew CHAY 7088cc72361SWai Yew CHAY *rblk = blk; 7098cc72361SWai Yew CHAY 7108cc72361SWai Yew CHAY return 0; 7118cc72361SWai Yew CHAY } 7128cc72361SWai Yew CHAY 7138cc72361SWai Yew CHAY static int amixer_rsc_put_ctrl_blk(void *blk) 7148cc72361SWai Yew CHAY { 7158cc72361SWai Yew CHAY kfree((struct amixer_rsc_ctrl_blk *)blk); 7168cc72361SWai Yew CHAY 7178cc72361SWai Yew CHAY return 0; 7188cc72361SWai Yew CHAY } 7198cc72361SWai Yew CHAY 7208cc72361SWai Yew CHAY static int amixer_mgr_get_ctrl_blk(void **rblk) 7218cc72361SWai Yew CHAY { 7228cc72361SWai Yew CHAY /*amixer_mgr_ctrl_blk_t *blk;*/ 7238cc72361SWai Yew CHAY 7248cc72361SWai Yew CHAY *rblk = NULL; 7258cc72361SWai Yew CHAY /*blk = kzalloc(sizeof(*blk), GFP_KERNEL); 7268cc72361SWai Yew CHAY if (NULL == blk) 7278cc72361SWai Yew CHAY return -ENOMEM; 7288cc72361SWai Yew CHAY 7298cc72361SWai Yew CHAY *rblk = blk;*/ 7308cc72361SWai Yew CHAY 7318cc72361SWai Yew CHAY return 0; 7328cc72361SWai Yew CHAY } 7338cc72361SWai Yew CHAY 7348cc72361SWai Yew CHAY static int amixer_mgr_put_ctrl_blk(void *blk) 7358cc72361SWai Yew CHAY { 7368cc72361SWai Yew CHAY /*kfree((amixer_mgr_ctrl_blk_t *)blk);*/ 7378cc72361SWai Yew CHAY 7388cc72361SWai Yew CHAY return 0; 7398cc72361SWai Yew CHAY } 7408cc72361SWai Yew CHAY 7418cc72361SWai Yew CHAY /* 7428cc72361SWai Yew CHAY * DAIO control block definitions. 7438cc72361SWai Yew CHAY */ 7448cc72361SWai Yew CHAY 7458cc72361SWai Yew CHAY /* Receiver Sample Rate Tracker Control register */ 7468cc72361SWai Yew CHAY #define SRTCTL_SRCR 0x000000FF 7478cc72361SWai Yew CHAY #define SRTCTL_SRCL 0x0000FF00 7488cc72361SWai Yew CHAY #define SRTCTL_RSR 0x00030000 7498cc72361SWai Yew CHAY #define SRTCTL_DRAT 0x000C0000 7508cc72361SWai Yew CHAY #define SRTCTL_RLE 0x10000000 7518cc72361SWai Yew CHAY #define SRTCTL_RLP 0x20000000 7528cc72361SWai Yew CHAY #define SRTCTL_EC 0x40000000 7538cc72361SWai Yew CHAY #define SRTCTL_ET 0x80000000 7548cc72361SWai Yew CHAY 7558cc72361SWai Yew CHAY /* DAIO Receiver register dirty flags */ 7568cc72361SWai Yew CHAY union dai_dirty { 7578cc72361SWai Yew CHAY struct { 7588cc72361SWai Yew CHAY u16 srtctl:1; 7598cc72361SWai Yew CHAY u16 rsv:15; 7608cc72361SWai Yew CHAY } bf; 7618cc72361SWai Yew CHAY u16 data; 7628cc72361SWai Yew CHAY }; 7638cc72361SWai Yew CHAY 7648cc72361SWai Yew CHAY /* DAIO Receiver control block */ 7658cc72361SWai Yew CHAY struct dai_ctrl_blk { 7668cc72361SWai Yew CHAY unsigned int srtctl; 7678cc72361SWai Yew CHAY union dai_dirty dirty; 7688cc72361SWai Yew CHAY }; 7698cc72361SWai Yew CHAY 7708cc72361SWai Yew CHAY /* S/PDIF Transmitter register dirty flags */ 7718cc72361SWai Yew CHAY union dao_dirty { 7728cc72361SWai Yew CHAY struct { 7738cc72361SWai Yew CHAY u16 spos:1; 7748cc72361SWai Yew CHAY u16 rsv:15; 7758cc72361SWai Yew CHAY } bf; 7768cc72361SWai Yew CHAY u16 data; 7778cc72361SWai Yew CHAY }; 7788cc72361SWai Yew CHAY 7798cc72361SWai Yew CHAY /* S/PDIF Transmitter control block */ 7808cc72361SWai Yew CHAY struct dao_ctrl_blk { 7818cc72361SWai Yew CHAY unsigned int spos; /* S/PDIF Output Channel Status Register */ 7828cc72361SWai Yew CHAY union dao_dirty dirty; 7838cc72361SWai Yew CHAY }; 7848cc72361SWai Yew CHAY 7858cc72361SWai Yew CHAY /* Audio Input Mapper RAM */ 7868cc72361SWai Yew CHAY #define AIM_ARC 0x00000FFF 7878cc72361SWai Yew CHAY #define AIM_NXT 0x007F0000 7888cc72361SWai Yew CHAY 7898cc72361SWai Yew CHAY struct daoimap { 7908cc72361SWai Yew CHAY unsigned int aim; 7918cc72361SWai Yew CHAY unsigned int idx; 7928cc72361SWai Yew CHAY }; 7938cc72361SWai Yew CHAY 7948cc72361SWai Yew CHAY /* I2S Transmitter/Receiver Control register */ 7958cc72361SWai Yew CHAY #define I2SCTL_EA 0x00000004 7968cc72361SWai Yew CHAY #define I2SCTL_EI 0x00000010 7978cc72361SWai Yew CHAY 7988cc72361SWai Yew CHAY /* S/PDIF Transmitter Control register */ 7998cc72361SWai Yew CHAY #define SPOCTL_OE 0x00000001 8008cc72361SWai Yew CHAY #define SPOCTL_OS 0x0000000E 8018cc72361SWai Yew CHAY #define SPOCTL_RIV 0x00000010 8028cc72361SWai Yew CHAY #define SPOCTL_LIV 0x00000020 8038cc72361SWai Yew CHAY #define SPOCTL_SR 0x000000C0 8048cc72361SWai Yew CHAY 8058cc72361SWai Yew CHAY /* S/PDIF Receiver Control register */ 8068cc72361SWai Yew CHAY #define SPICTL_EN 0x00000001 8078cc72361SWai Yew CHAY #define SPICTL_I24 0x00000002 8088cc72361SWai Yew CHAY #define SPICTL_IB 0x00000004 8098cc72361SWai Yew CHAY #define SPICTL_SM 0x00000008 8108cc72361SWai Yew CHAY #define SPICTL_VM 0x00000010 8118cc72361SWai Yew CHAY 8128cc72361SWai Yew CHAY /* DAIO manager register dirty flags */ 8138cc72361SWai Yew CHAY union daio_mgr_dirty { 8148cc72361SWai Yew CHAY struct { 8158cc72361SWai Yew CHAY u32 i2soctl:4; 8168cc72361SWai Yew CHAY u32 i2sictl:4; 8178cc72361SWai Yew CHAY u32 spoctl:4; 8188cc72361SWai Yew CHAY u32 spictl:4; 8198cc72361SWai Yew CHAY u32 daoimap:1; 8208cc72361SWai Yew CHAY u32 rsv:15; 8218cc72361SWai Yew CHAY } bf; 8228cc72361SWai Yew CHAY u32 data; 8238cc72361SWai Yew CHAY }; 8248cc72361SWai Yew CHAY 8258cc72361SWai Yew CHAY /* DAIO manager control block */ 8268cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk { 8278cc72361SWai Yew CHAY unsigned int i2sctl; 8288cc72361SWai Yew CHAY unsigned int spoctl; 8298cc72361SWai Yew CHAY unsigned int spictl; 8308cc72361SWai Yew CHAY struct daoimap daoimap; 8318cc72361SWai Yew CHAY union daio_mgr_dirty dirty; 8328cc72361SWai Yew CHAY }; 8338cc72361SWai Yew CHAY 8348cc72361SWai Yew CHAY static int dai_srt_set_srcr(void *blk, unsigned int src) 8358cc72361SWai Yew CHAY { 8368cc72361SWai Yew CHAY struct dai_ctrl_blk *ctl = blk; 8378cc72361SWai Yew CHAY 8388cc72361SWai Yew CHAY set_field(&ctl->srtctl, SRTCTL_SRCR, src); 8398cc72361SWai Yew CHAY ctl->dirty.bf.srtctl = 1; 8408cc72361SWai Yew CHAY return 0; 8418cc72361SWai Yew CHAY } 8428cc72361SWai Yew CHAY 8438cc72361SWai Yew CHAY static int dai_srt_set_srcl(void *blk, unsigned int src) 8448cc72361SWai Yew CHAY { 8458cc72361SWai Yew CHAY struct dai_ctrl_blk *ctl = blk; 8468cc72361SWai Yew CHAY 8478cc72361SWai Yew CHAY set_field(&ctl->srtctl, SRTCTL_SRCL, src); 8488cc72361SWai Yew CHAY ctl->dirty.bf.srtctl = 1; 8498cc72361SWai Yew CHAY return 0; 8508cc72361SWai Yew CHAY } 8518cc72361SWai Yew CHAY 8528cc72361SWai Yew CHAY static int dai_srt_set_rsr(void *blk, unsigned int rsr) 8538cc72361SWai Yew CHAY { 8548cc72361SWai Yew CHAY struct dai_ctrl_blk *ctl = blk; 8558cc72361SWai Yew CHAY 8568cc72361SWai Yew CHAY set_field(&ctl->srtctl, SRTCTL_RSR, rsr); 8578cc72361SWai Yew CHAY ctl->dirty.bf.srtctl = 1; 8588cc72361SWai Yew CHAY return 0; 8598cc72361SWai Yew CHAY } 8608cc72361SWai Yew CHAY 8618cc72361SWai Yew CHAY static int dai_srt_set_drat(void *blk, unsigned int drat) 8628cc72361SWai Yew CHAY { 8638cc72361SWai Yew CHAY struct dai_ctrl_blk *ctl = blk; 8648cc72361SWai Yew CHAY 8658cc72361SWai Yew CHAY set_field(&ctl->srtctl, SRTCTL_DRAT, drat); 8668cc72361SWai Yew CHAY ctl->dirty.bf.srtctl = 1; 8678cc72361SWai Yew CHAY return 0; 8688cc72361SWai Yew CHAY } 8698cc72361SWai Yew CHAY 8708cc72361SWai Yew CHAY static int dai_srt_set_ec(void *blk, unsigned int ec) 8718cc72361SWai Yew CHAY { 8728cc72361SWai Yew CHAY struct dai_ctrl_blk *ctl = blk; 8738cc72361SWai Yew CHAY 8748cc72361SWai Yew CHAY set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0); 8758cc72361SWai Yew CHAY ctl->dirty.bf.srtctl = 1; 8768cc72361SWai Yew CHAY return 0; 8778cc72361SWai Yew CHAY } 8788cc72361SWai Yew CHAY 8798cc72361SWai Yew CHAY static int dai_srt_set_et(void *blk, unsigned int et) 8808cc72361SWai Yew CHAY { 8818cc72361SWai Yew CHAY struct dai_ctrl_blk *ctl = blk; 8828cc72361SWai Yew CHAY 8838cc72361SWai Yew CHAY set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0); 8848cc72361SWai Yew CHAY ctl->dirty.bf.srtctl = 1; 8858cc72361SWai Yew CHAY return 0; 8868cc72361SWai Yew CHAY } 8878cc72361SWai Yew CHAY 8888cc72361SWai Yew CHAY static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) 8898cc72361SWai Yew CHAY { 8908cc72361SWai Yew CHAY struct dai_ctrl_blk *ctl = blk; 8918cc72361SWai Yew CHAY 8928cc72361SWai Yew CHAY if (ctl->dirty.bf.srtctl) { 8938cc72361SWai Yew CHAY if (idx < 4) { 8948cc72361SWai Yew CHAY /* S/PDIF SRTs */ 8958cc72361SWai Yew CHAY hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl); 8968cc72361SWai Yew CHAY } else { 8978cc72361SWai Yew CHAY /* I2S SRT */ 8988cc72361SWai Yew CHAY hw_write_20kx(hw, SRTICTL, ctl->srtctl); 8998cc72361SWai Yew CHAY } 9008cc72361SWai Yew CHAY ctl->dirty.bf.srtctl = 0; 9018cc72361SWai Yew CHAY } 9028cc72361SWai Yew CHAY 9038cc72361SWai Yew CHAY return 0; 9048cc72361SWai Yew CHAY } 9058cc72361SWai Yew CHAY 9068cc72361SWai Yew CHAY static int dai_get_ctrl_blk(void **rblk) 9078cc72361SWai Yew CHAY { 9088cc72361SWai Yew CHAY struct dai_ctrl_blk *blk; 9098cc72361SWai Yew CHAY 9108cc72361SWai Yew CHAY *rblk = NULL; 9118cc72361SWai Yew CHAY blk = kzalloc(sizeof(*blk), GFP_KERNEL); 9128cc72361SWai Yew CHAY if (NULL == blk) 9138cc72361SWai Yew CHAY return -ENOMEM; 9148cc72361SWai Yew CHAY 9158cc72361SWai Yew CHAY *rblk = blk; 9168cc72361SWai Yew CHAY 9178cc72361SWai Yew CHAY return 0; 9188cc72361SWai Yew CHAY } 9198cc72361SWai Yew CHAY 9208cc72361SWai Yew CHAY static int dai_put_ctrl_blk(void *blk) 9218cc72361SWai Yew CHAY { 9228cc72361SWai Yew CHAY kfree((struct dai_ctrl_blk *)blk); 9238cc72361SWai Yew CHAY 9248cc72361SWai Yew CHAY return 0; 9258cc72361SWai Yew CHAY } 9268cc72361SWai Yew CHAY 9278cc72361SWai Yew CHAY static int dao_set_spos(void *blk, unsigned int spos) 9288cc72361SWai Yew CHAY { 9298cc72361SWai Yew CHAY ((struct dao_ctrl_blk *)blk)->spos = spos; 9308cc72361SWai Yew CHAY ((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1; 9318cc72361SWai Yew CHAY return 0; 9328cc72361SWai Yew CHAY } 9338cc72361SWai Yew CHAY 9348cc72361SWai Yew CHAY static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) 9358cc72361SWai Yew CHAY { 9368cc72361SWai Yew CHAY struct dao_ctrl_blk *ctl = blk; 9378cc72361SWai Yew CHAY 9388cc72361SWai Yew CHAY if (ctl->dirty.bf.spos) { 9398cc72361SWai Yew CHAY if (idx < 4) { 9408cc72361SWai Yew CHAY /* S/PDIF SPOSx */ 9418cc72361SWai Yew CHAY hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos); 9428cc72361SWai Yew CHAY } 9438cc72361SWai Yew CHAY ctl->dirty.bf.spos = 0; 9448cc72361SWai Yew CHAY } 9458cc72361SWai Yew CHAY 9468cc72361SWai Yew CHAY return 0; 9478cc72361SWai Yew CHAY } 9488cc72361SWai Yew CHAY 9498cc72361SWai Yew CHAY static int dao_get_spos(void *blk, unsigned int *spos) 9508cc72361SWai Yew CHAY { 9518cc72361SWai Yew CHAY *spos = ((struct dao_ctrl_blk *)blk)->spos; 9528cc72361SWai Yew CHAY return 0; 9538cc72361SWai Yew CHAY } 9548cc72361SWai Yew CHAY 9558cc72361SWai Yew CHAY static int dao_get_ctrl_blk(void **rblk) 9568cc72361SWai Yew CHAY { 9578cc72361SWai Yew CHAY struct dao_ctrl_blk *blk; 9588cc72361SWai Yew CHAY 9598cc72361SWai Yew CHAY *rblk = NULL; 9608cc72361SWai Yew CHAY blk = kzalloc(sizeof(*blk), GFP_KERNEL); 9618cc72361SWai Yew CHAY if (NULL == blk) 9628cc72361SWai Yew CHAY return -ENOMEM; 9638cc72361SWai Yew CHAY 9648cc72361SWai Yew CHAY *rblk = blk; 9658cc72361SWai Yew CHAY 9668cc72361SWai Yew CHAY return 0; 9678cc72361SWai Yew CHAY } 9688cc72361SWai Yew CHAY 9698cc72361SWai Yew CHAY static int dao_put_ctrl_blk(void *blk) 9708cc72361SWai Yew CHAY { 9718cc72361SWai Yew CHAY kfree((struct dao_ctrl_blk *)blk); 9728cc72361SWai Yew CHAY 9738cc72361SWai Yew CHAY return 0; 9748cc72361SWai Yew CHAY } 9758cc72361SWai Yew CHAY 9768cc72361SWai Yew CHAY static int daio_mgr_enb_dai(void *blk, unsigned int idx) 9778cc72361SWai Yew CHAY { 9788cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 9798cc72361SWai Yew CHAY 9808cc72361SWai Yew CHAY if (idx < 4) { 9818cc72361SWai Yew CHAY /* S/PDIF input */ 9828cc72361SWai Yew CHAY set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1); 9838cc72361SWai Yew CHAY ctl->dirty.bf.spictl |= (0x1 << idx); 9848cc72361SWai Yew CHAY } else { 9858cc72361SWai Yew CHAY /* I2S input */ 9868cc72361SWai Yew CHAY idx %= 4; 9878cc72361SWai Yew CHAY set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1); 9888cc72361SWai Yew CHAY ctl->dirty.bf.i2sictl |= (0x1 << idx); 9898cc72361SWai Yew CHAY } 9908cc72361SWai Yew CHAY return 0; 9918cc72361SWai Yew CHAY } 9928cc72361SWai Yew CHAY 9938cc72361SWai Yew CHAY static int daio_mgr_dsb_dai(void *blk, unsigned int idx) 9948cc72361SWai Yew CHAY { 9958cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 9968cc72361SWai Yew CHAY 9978cc72361SWai Yew CHAY if (idx < 4) { 9988cc72361SWai Yew CHAY /* S/PDIF input */ 9998cc72361SWai Yew CHAY set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0); 10008cc72361SWai Yew CHAY ctl->dirty.bf.spictl |= (0x1 << idx); 10018cc72361SWai Yew CHAY } else { 10028cc72361SWai Yew CHAY /* I2S input */ 10038cc72361SWai Yew CHAY idx %= 4; 10048cc72361SWai Yew CHAY set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0); 10058cc72361SWai Yew CHAY ctl->dirty.bf.i2sictl |= (0x1 << idx); 10068cc72361SWai Yew CHAY } 10078cc72361SWai Yew CHAY return 0; 10088cc72361SWai Yew CHAY } 10098cc72361SWai Yew CHAY 10108cc72361SWai Yew CHAY static int daio_mgr_enb_dao(void *blk, unsigned int idx) 10118cc72361SWai Yew CHAY { 10128cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 10138cc72361SWai Yew CHAY 10148cc72361SWai Yew CHAY if (idx < 4) { 10158cc72361SWai Yew CHAY /* S/PDIF output */ 10168cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1); 10178cc72361SWai Yew CHAY ctl->dirty.bf.spoctl |= (0x1 << idx); 10188cc72361SWai Yew CHAY } else { 10198cc72361SWai Yew CHAY /* I2S output */ 10208cc72361SWai Yew CHAY idx %= 4; 10218cc72361SWai Yew CHAY set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1); 10228cc72361SWai Yew CHAY ctl->dirty.bf.i2soctl |= (0x1 << idx); 10238cc72361SWai Yew CHAY } 10248cc72361SWai Yew CHAY return 0; 10258cc72361SWai Yew CHAY } 10268cc72361SWai Yew CHAY 10278cc72361SWai Yew CHAY static int daio_mgr_dsb_dao(void *blk, unsigned int idx) 10288cc72361SWai Yew CHAY { 10298cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 10308cc72361SWai Yew CHAY 10318cc72361SWai Yew CHAY if (idx < 4) { 10328cc72361SWai Yew CHAY /* S/PDIF output */ 10338cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0); 10348cc72361SWai Yew CHAY ctl->dirty.bf.spoctl |= (0x1 << idx); 10358cc72361SWai Yew CHAY } else { 10368cc72361SWai Yew CHAY /* I2S output */ 10378cc72361SWai Yew CHAY idx %= 4; 10388cc72361SWai Yew CHAY set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0); 10398cc72361SWai Yew CHAY ctl->dirty.bf.i2soctl |= (0x1 << idx); 10408cc72361SWai Yew CHAY } 10418cc72361SWai Yew CHAY return 0; 10428cc72361SWai Yew CHAY } 10438cc72361SWai Yew CHAY 10448cc72361SWai Yew CHAY static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) 10458cc72361SWai Yew CHAY { 10468cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 10478cc72361SWai Yew CHAY 10488cc72361SWai Yew CHAY if (idx < 4) { 10498cc72361SWai Yew CHAY /* S/PDIF output */ 10508cc72361SWai Yew CHAY switch ((conf & 0x7)) { 10518cc72361SWai Yew CHAY case 0: 10528cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3); 10538cc72361SWai Yew CHAY break; /* CDIF */ 10548cc72361SWai Yew CHAY case 1: 10558cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0); 10568cc72361SWai Yew CHAY break; 10578cc72361SWai Yew CHAY case 2: 10588cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1); 10598cc72361SWai Yew CHAY break; 10608cc72361SWai Yew CHAY case 4: 10618cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2); 10628cc72361SWai Yew CHAY break; 10638cc72361SWai Yew CHAY default: 10648cc72361SWai Yew CHAY break; 10658cc72361SWai Yew CHAY } 10668cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8), 10678cc72361SWai Yew CHAY (conf >> 4) & 0x1); /* Non-audio */ 10688cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8), 10698cc72361SWai Yew CHAY (conf >> 4) & 0x1); /* Non-audio */ 10708cc72361SWai Yew CHAY set_field(&ctl->spoctl, SPOCTL_OS << (idx*8), 10718cc72361SWai Yew CHAY ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */ 10728cc72361SWai Yew CHAY 10738cc72361SWai Yew CHAY ctl->dirty.bf.spoctl |= (0x1 << idx); 10748cc72361SWai Yew CHAY } else { 10758cc72361SWai Yew CHAY /* I2S output */ 10768cc72361SWai Yew CHAY /*idx %= 4; */ 10778cc72361SWai Yew CHAY } 10788cc72361SWai Yew CHAY return 0; 10798cc72361SWai Yew CHAY } 10808cc72361SWai Yew CHAY 10818cc72361SWai Yew CHAY static int daio_mgr_set_imaparc(void *blk, unsigned int slot) 10828cc72361SWai Yew CHAY { 10838cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 10848cc72361SWai Yew CHAY 10858cc72361SWai Yew CHAY set_field(&ctl->daoimap.aim, AIM_ARC, slot); 10868cc72361SWai Yew CHAY ctl->dirty.bf.daoimap = 1; 10878cc72361SWai Yew CHAY return 0; 10888cc72361SWai Yew CHAY } 10898cc72361SWai Yew CHAY 10908cc72361SWai Yew CHAY static int daio_mgr_set_imapnxt(void *blk, unsigned int next) 10918cc72361SWai Yew CHAY { 10928cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 10938cc72361SWai Yew CHAY 10948cc72361SWai Yew CHAY set_field(&ctl->daoimap.aim, AIM_NXT, next); 10958cc72361SWai Yew CHAY ctl->dirty.bf.daoimap = 1; 10968cc72361SWai Yew CHAY return 0; 10978cc72361SWai Yew CHAY } 10988cc72361SWai Yew CHAY 10998cc72361SWai Yew CHAY static int daio_mgr_set_imapaddr(void *blk, unsigned int addr) 11008cc72361SWai Yew CHAY { 11018cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 11028cc72361SWai Yew CHAY 11038cc72361SWai Yew CHAY ctl->daoimap.idx = addr; 11048cc72361SWai Yew CHAY ctl->dirty.bf.daoimap = 1; 11058cc72361SWai Yew CHAY return 0; 11068cc72361SWai Yew CHAY } 11078cc72361SWai Yew CHAY 11088cc72361SWai Yew CHAY static int daio_mgr_commit_write(struct hw *hw, void *blk) 11098cc72361SWai Yew CHAY { 11108cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *ctl = blk; 11118cc72361SWai Yew CHAY int i = 0; 11128cc72361SWai Yew CHAY 11138cc72361SWai Yew CHAY if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) { 11148cc72361SWai Yew CHAY for (i = 0; i < 4; i++) { 11158cc72361SWai Yew CHAY if ((ctl->dirty.bf.i2sictl & (0x1 << i))) 11168cc72361SWai Yew CHAY ctl->dirty.bf.i2sictl &= ~(0x1 << i); 11178cc72361SWai Yew CHAY 11188cc72361SWai Yew CHAY if ((ctl->dirty.bf.i2soctl & (0x1 << i))) 11198cc72361SWai Yew CHAY ctl->dirty.bf.i2soctl &= ~(0x1 << i); 11208cc72361SWai Yew CHAY } 11218cc72361SWai Yew CHAY hw_write_20kx(hw, I2SCTL, ctl->i2sctl); 11228cc72361SWai Yew CHAY mdelay(1); 11238cc72361SWai Yew CHAY } 11248cc72361SWai Yew CHAY if (ctl->dirty.bf.spoctl) { 11258cc72361SWai Yew CHAY for (i = 0; i < 4; i++) { 11268cc72361SWai Yew CHAY if ((ctl->dirty.bf.spoctl & (0x1 << i))) 11278cc72361SWai Yew CHAY ctl->dirty.bf.spoctl &= ~(0x1 << i); 11288cc72361SWai Yew CHAY } 11298cc72361SWai Yew CHAY hw_write_20kx(hw, SPOCTL, ctl->spoctl); 11308cc72361SWai Yew CHAY mdelay(1); 11318cc72361SWai Yew CHAY } 11328cc72361SWai Yew CHAY if (ctl->dirty.bf.spictl) { 11338cc72361SWai Yew CHAY for (i = 0; i < 4; i++) { 11348cc72361SWai Yew CHAY if ((ctl->dirty.bf.spictl & (0x1 << i))) 11358cc72361SWai Yew CHAY ctl->dirty.bf.spictl &= ~(0x1 << i); 11368cc72361SWai Yew CHAY } 11378cc72361SWai Yew CHAY hw_write_20kx(hw, SPICTL, ctl->spictl); 11388cc72361SWai Yew CHAY mdelay(1); 11398cc72361SWai Yew CHAY } 11408cc72361SWai Yew CHAY if (ctl->dirty.bf.daoimap) { 11418cc72361SWai Yew CHAY hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4, 11428cc72361SWai Yew CHAY ctl->daoimap.aim); 11438cc72361SWai Yew CHAY ctl->dirty.bf.daoimap = 0; 11448cc72361SWai Yew CHAY } 11458cc72361SWai Yew CHAY 11468cc72361SWai Yew CHAY return 0; 11478cc72361SWai Yew CHAY } 11488cc72361SWai Yew CHAY 11498cc72361SWai Yew CHAY static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) 11508cc72361SWai Yew CHAY { 11518cc72361SWai Yew CHAY struct daio_mgr_ctrl_blk *blk; 11528cc72361SWai Yew CHAY 11538cc72361SWai Yew CHAY *rblk = NULL; 11548cc72361SWai Yew CHAY blk = kzalloc(sizeof(*blk), GFP_KERNEL); 11558cc72361SWai Yew CHAY if (NULL == blk) 11568cc72361SWai Yew CHAY return -ENOMEM; 11578cc72361SWai Yew CHAY 11588cc72361SWai Yew CHAY blk->i2sctl = hw_read_20kx(hw, I2SCTL); 11598cc72361SWai Yew CHAY blk->spoctl = hw_read_20kx(hw, SPOCTL); 11608cc72361SWai Yew CHAY blk->spictl = hw_read_20kx(hw, SPICTL); 11618cc72361SWai Yew CHAY 11628cc72361SWai Yew CHAY *rblk = blk; 11638cc72361SWai Yew CHAY 11648cc72361SWai Yew CHAY return 0; 11658cc72361SWai Yew CHAY } 11668cc72361SWai Yew CHAY 11678cc72361SWai Yew CHAY static int daio_mgr_put_ctrl_blk(void *blk) 11688cc72361SWai Yew CHAY { 11698cc72361SWai Yew CHAY kfree((struct daio_mgr_ctrl_blk *)blk); 11708cc72361SWai Yew CHAY 11718cc72361SWai Yew CHAY return 0; 11728cc72361SWai Yew CHAY } 11738cc72361SWai Yew CHAY 1174*b7bbf876STakashi Iwai /* Timer interrupt */ 1175*b7bbf876STakashi Iwai static int set_timer_irq(struct hw *hw, int enable) 1176*b7bbf876STakashi Iwai { 1177*b7bbf876STakashi Iwai hw_write_20kx(hw, GIE, enable ? IT_INT : 0); 1178*b7bbf876STakashi Iwai return 0; 1179*b7bbf876STakashi Iwai } 1180*b7bbf876STakashi Iwai 1181*b7bbf876STakashi Iwai static int set_timer_tick(struct hw *hw, unsigned int ticks) 1182*b7bbf876STakashi Iwai { 1183*b7bbf876STakashi Iwai if (ticks) 1184*b7bbf876STakashi Iwai ticks |= TIMR_IE | TIMR_IP; 1185*b7bbf876STakashi Iwai hw_write_20kx(hw, TIMR, ticks); 1186*b7bbf876STakashi Iwai return 0; 1187*b7bbf876STakashi Iwai } 1188*b7bbf876STakashi Iwai 11898cc72361SWai Yew CHAY /* Card hardware initialization block */ 11908cc72361SWai Yew CHAY struct dac_conf { 11918cc72361SWai Yew CHAY unsigned int msr; /* master sample rate in rsrs */ 11928cc72361SWai Yew CHAY }; 11938cc72361SWai Yew CHAY 11948cc72361SWai Yew CHAY struct adc_conf { 11958cc72361SWai Yew CHAY unsigned int msr; /* master sample rate in rsrs */ 11968cc72361SWai Yew CHAY unsigned char input; /* the input source of ADC */ 11978cc72361SWai Yew CHAY unsigned char mic20db; /* boost mic by 20db if input is microphone */ 11988cc72361SWai Yew CHAY }; 11998cc72361SWai Yew CHAY 12008cc72361SWai Yew CHAY struct daio_conf { 12018cc72361SWai Yew CHAY unsigned int msr; /* master sample rate in rsrs */ 12028cc72361SWai Yew CHAY }; 12038cc72361SWai Yew CHAY 12048cc72361SWai Yew CHAY struct trn_conf { 12058cc72361SWai Yew CHAY unsigned long vm_pgt_phys; 12068cc72361SWai Yew CHAY }; 12078cc72361SWai Yew CHAY 12088cc72361SWai Yew CHAY static int hw_daio_init(struct hw *hw, const struct daio_conf *info) 12098cc72361SWai Yew CHAY { 12108cc72361SWai Yew CHAY u32 i2sorg = 0; 12118cc72361SWai Yew CHAY u32 spdorg = 0; 12128cc72361SWai Yew CHAY 12138cc72361SWai Yew CHAY /* Read I2S CTL. Keep original value. */ 12148cc72361SWai Yew CHAY /*i2sorg = hw_read_20kx(hw, I2SCTL);*/ 12158cc72361SWai Yew CHAY i2sorg = 0x94040404; /* enable all audio out and I2S-D input */ 12168cc72361SWai Yew CHAY /* Program I2S with proper master sample rate and enable 12178cc72361SWai Yew CHAY * the correct I2S channel. */ 12188cc72361SWai Yew CHAY i2sorg &= 0xfffffffc; 12198cc72361SWai Yew CHAY 12208cc72361SWai Yew CHAY /* Enable S/PDIF-out-A in fixed 24-bit data 12218cc72361SWai Yew CHAY * format and default to 48kHz. */ 12228cc72361SWai Yew CHAY /* Disable all before doing any changes. */ 12238cc72361SWai Yew CHAY hw_write_20kx(hw, SPOCTL, 0x0); 12248cc72361SWai Yew CHAY spdorg = 0x05; 12258cc72361SWai Yew CHAY 12268cc72361SWai Yew CHAY switch (info->msr) { 12278cc72361SWai Yew CHAY case 1: 12288cc72361SWai Yew CHAY i2sorg |= 1; 12298cc72361SWai Yew CHAY spdorg |= (0x0 << 6); 12308cc72361SWai Yew CHAY break; 12318cc72361SWai Yew CHAY case 2: 12328cc72361SWai Yew CHAY i2sorg |= 2; 12338cc72361SWai Yew CHAY spdorg |= (0x1 << 6); 12348cc72361SWai Yew CHAY break; 12358cc72361SWai Yew CHAY case 4: 12368cc72361SWai Yew CHAY i2sorg |= 3; 12378cc72361SWai Yew CHAY spdorg |= (0x2 << 6); 12388cc72361SWai Yew CHAY break; 12398cc72361SWai Yew CHAY default: 12408cc72361SWai Yew CHAY i2sorg |= 1; 12418cc72361SWai Yew CHAY break; 12428cc72361SWai Yew CHAY } 12438cc72361SWai Yew CHAY 12448cc72361SWai Yew CHAY hw_write_20kx(hw, I2SCTL, i2sorg); 12458cc72361SWai Yew CHAY hw_write_20kx(hw, SPOCTL, spdorg); 12468cc72361SWai Yew CHAY 12478cc72361SWai Yew CHAY /* Enable S/PDIF-in-A in fixed 24-bit data format. */ 12488cc72361SWai Yew CHAY /* Disable all before doing any changes. */ 12498cc72361SWai Yew CHAY hw_write_20kx(hw, SPICTL, 0x0); 12508cc72361SWai Yew CHAY mdelay(1); 12518cc72361SWai Yew CHAY spdorg = 0x0a0a0a0a; 12528cc72361SWai Yew CHAY hw_write_20kx(hw, SPICTL, spdorg); 12538cc72361SWai Yew CHAY mdelay(1); 12548cc72361SWai Yew CHAY 12558cc72361SWai Yew CHAY return 0; 12568cc72361SWai Yew CHAY } 12578cc72361SWai Yew CHAY 12588cc72361SWai Yew CHAY /* TRANSPORT operations */ 12598cc72361SWai Yew CHAY static int hw_trn_init(struct hw *hw, const struct trn_conf *info) 12608cc72361SWai Yew CHAY { 12618cc72361SWai Yew CHAY u32 trnctl = 0; 12628cc72361SWai Yew CHAY unsigned long ptp_phys_low = 0, ptp_phys_high = 0; 12638cc72361SWai Yew CHAY 12648cc72361SWai Yew CHAY /* Set up device page table */ 12658cc72361SWai Yew CHAY if ((~0UL) == info->vm_pgt_phys) { 12668cc72361SWai Yew CHAY printk(KERN_ERR "Wrong device page table page address!\n"); 12678cc72361SWai Yew CHAY return -1; 12688cc72361SWai Yew CHAY } 12698cc72361SWai Yew CHAY 12708cc72361SWai Yew CHAY trnctl = 0x13; /* 32-bit, 4k-size page */ 1271cd391e20STakashi Iwai ptp_phys_low = (u32)info->vm_pgt_phys; 1272cd391e20STakashi Iwai ptp_phys_high = upper_32_bits(info->vm_pgt_phys); 1273cd391e20STakashi Iwai if (sizeof(void *) == 8) /* 64bit address */ 12748cc72361SWai Yew CHAY trnctl |= (1 << 2); 1275cd391e20STakashi Iwai #if 0 /* Only 4k h/w pages for simplicitiy */ 12768cc72361SWai Yew CHAY #if PAGE_SIZE == 8192 12778cc72361SWai Yew CHAY trnctl |= (1<<5); 12788cc72361SWai Yew CHAY #endif 1279cd391e20STakashi Iwai #endif 12808cc72361SWai Yew CHAY hw_write_20kx(hw, PTPALX, ptp_phys_low); 12818cc72361SWai Yew CHAY hw_write_20kx(hw, PTPAHX, ptp_phys_high); 12828cc72361SWai Yew CHAY hw_write_20kx(hw, TRNCTL, trnctl); 12838cc72361SWai Yew CHAY hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */ 12848cc72361SWai Yew CHAY 12858cc72361SWai Yew CHAY return 0; 12868cc72361SWai Yew CHAY } 12878cc72361SWai Yew CHAY 12888cc72361SWai Yew CHAY /* Card initialization */ 12898cc72361SWai Yew CHAY #define GCTL_EAC 0x00000001 12908cc72361SWai Yew CHAY #define GCTL_EAI 0x00000002 12918cc72361SWai Yew CHAY #define GCTL_BEP 0x00000004 12928cc72361SWai Yew CHAY #define GCTL_BES 0x00000008 12938cc72361SWai Yew CHAY #define GCTL_DSP 0x00000010 12948cc72361SWai Yew CHAY #define GCTL_DBP 0x00000020 12958cc72361SWai Yew CHAY #define GCTL_ABP 0x00000040 12968cc72361SWai Yew CHAY #define GCTL_TBP 0x00000080 12978cc72361SWai Yew CHAY #define GCTL_SBP 0x00000100 12988cc72361SWai Yew CHAY #define GCTL_FBP 0x00000200 12998cc72361SWai Yew CHAY #define GCTL_XA 0x00000400 13008cc72361SWai Yew CHAY #define GCTL_ET 0x00000800 13018cc72361SWai Yew CHAY #define GCTL_PR 0x00001000 13028cc72361SWai Yew CHAY #define GCTL_MRL 0x00002000 13038cc72361SWai Yew CHAY #define GCTL_SDE 0x00004000 13048cc72361SWai Yew CHAY #define GCTL_SDI 0x00008000 13058cc72361SWai Yew CHAY #define GCTL_SM 0x00010000 13068cc72361SWai Yew CHAY #define GCTL_SR 0x00020000 13078cc72361SWai Yew CHAY #define GCTL_SD 0x00040000 13088cc72361SWai Yew CHAY #define GCTL_SE 0x00080000 13098cc72361SWai Yew CHAY #define GCTL_AID 0x00100000 13108cc72361SWai Yew CHAY 13118cc72361SWai Yew CHAY static int hw_pll_init(struct hw *hw, unsigned int rsr) 13128cc72361SWai Yew CHAY { 13138cc72361SWai Yew CHAY unsigned int pllctl; 13148cc72361SWai Yew CHAY int i = 0; 13158cc72361SWai Yew CHAY 13168cc72361SWai Yew CHAY pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731; 13178cc72361SWai Yew CHAY for (i = 0; i < 3; i++) { 13188cc72361SWai Yew CHAY if (hw_read_20kx(hw, PLLCTL) == pllctl) 13198cc72361SWai Yew CHAY break; 13208cc72361SWai Yew CHAY 13218cc72361SWai Yew CHAY hw_write_20kx(hw, PLLCTL, pllctl); 13228cc72361SWai Yew CHAY mdelay(40); 13238cc72361SWai Yew CHAY } 13248cc72361SWai Yew CHAY if (i >= 3) { 13258cc72361SWai Yew CHAY printk(KERN_ALERT "PLL initialization failed!!!\n"); 13268cc72361SWai Yew CHAY return -EBUSY; 13278cc72361SWai Yew CHAY } 13288cc72361SWai Yew CHAY 13298cc72361SWai Yew CHAY return 0; 13308cc72361SWai Yew CHAY } 13318cc72361SWai Yew CHAY 13328cc72361SWai Yew CHAY static int hw_auto_init(struct hw *hw) 13338cc72361SWai Yew CHAY { 13348cc72361SWai Yew CHAY unsigned int gctl; 13358cc72361SWai Yew CHAY int i; 13368cc72361SWai Yew CHAY 13378cc72361SWai Yew CHAY gctl = hw_read_20kx(hw, GCTL); 13388cc72361SWai Yew CHAY set_field(&gctl, GCTL_EAI, 0); 13398cc72361SWai Yew CHAY hw_write_20kx(hw, GCTL, gctl); 13408cc72361SWai Yew CHAY set_field(&gctl, GCTL_EAI, 1); 13418cc72361SWai Yew CHAY hw_write_20kx(hw, GCTL, gctl); 13428cc72361SWai Yew CHAY mdelay(10); 13438cc72361SWai Yew CHAY for (i = 0; i < 400000; i++) { 13448cc72361SWai Yew CHAY gctl = hw_read_20kx(hw, GCTL); 13458cc72361SWai Yew CHAY if (get_field(gctl, GCTL_AID)) 13468cc72361SWai Yew CHAY break; 13478cc72361SWai Yew CHAY } 13488cc72361SWai Yew CHAY if (!get_field(gctl, GCTL_AID)) { 13498cc72361SWai Yew CHAY printk(KERN_ALERT "Card Auto-init failed!!!\n"); 13508cc72361SWai Yew CHAY return -EBUSY; 13518cc72361SWai Yew CHAY } 13528cc72361SWai Yew CHAY 13538cc72361SWai Yew CHAY return 0; 13548cc72361SWai Yew CHAY } 13558cc72361SWai Yew CHAY 13568cc72361SWai Yew CHAY static int i2c_unlock(struct hw *hw) 13578cc72361SWai Yew CHAY { 13588cc72361SWai Yew CHAY if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) 13598cc72361SWai Yew CHAY return 0; 13608cc72361SWai Yew CHAY 13618cc72361SWai Yew CHAY hw_write_pci(hw, 0xcc, 0x8c); 13628cc72361SWai Yew CHAY hw_write_pci(hw, 0xcc, 0x0e); 13638cc72361SWai Yew CHAY if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) 13648cc72361SWai Yew CHAY return 0; 13658cc72361SWai Yew CHAY 13668cc72361SWai Yew CHAY hw_write_pci(hw, 0xcc, 0xee); 13678cc72361SWai Yew CHAY hw_write_pci(hw, 0xcc, 0xaa); 13688cc72361SWai Yew CHAY if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) 13698cc72361SWai Yew CHAY return 0; 13708cc72361SWai Yew CHAY 13718cc72361SWai Yew CHAY return -1; 13728cc72361SWai Yew CHAY } 13738cc72361SWai Yew CHAY 13748cc72361SWai Yew CHAY static void i2c_lock(struct hw *hw) 13758cc72361SWai Yew CHAY { 13768cc72361SWai Yew CHAY if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) 13778cc72361SWai Yew CHAY hw_write_pci(hw, 0xcc, 0x00); 13788cc72361SWai Yew CHAY } 13798cc72361SWai Yew CHAY 13808cc72361SWai Yew CHAY static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data) 13818cc72361SWai Yew CHAY { 13828cc72361SWai Yew CHAY unsigned int ret = 0; 13838cc72361SWai Yew CHAY 13848cc72361SWai Yew CHAY do { 13858cc72361SWai Yew CHAY ret = hw_read_pci(hw, 0xEC); 13868cc72361SWai Yew CHAY } while (!(ret & 0x800000)); 13878cc72361SWai Yew CHAY hw_write_pci(hw, 0xE0, device); 13888cc72361SWai Yew CHAY hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff)); 13898cc72361SWai Yew CHAY } 13908cc72361SWai Yew CHAY 13918cc72361SWai Yew CHAY /* DAC operations */ 13928cc72361SWai Yew CHAY 13938cc72361SWai Yew CHAY static int hw_reset_dac(struct hw *hw) 13948cc72361SWai Yew CHAY { 13958cc72361SWai Yew CHAY u32 i = 0; 13968cc72361SWai Yew CHAY u16 gpioorg = 0; 13978cc72361SWai Yew CHAY unsigned int ret = 0; 13988cc72361SWai Yew CHAY 13998cc72361SWai Yew CHAY if (i2c_unlock(hw)) 14008cc72361SWai Yew CHAY return -1; 14018cc72361SWai Yew CHAY 14028cc72361SWai Yew CHAY do { 14038cc72361SWai Yew CHAY ret = hw_read_pci(hw, 0xEC); 14048cc72361SWai Yew CHAY } while (!(ret & 0x800000)); 14058cc72361SWai Yew CHAY hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ 14068cc72361SWai Yew CHAY 14078cc72361SWai Yew CHAY /* To be effective, need to reset the DAC twice. */ 14088cc72361SWai Yew CHAY for (i = 0; i < 2; i++) { 14098cc72361SWai Yew CHAY /* set gpio */ 14108cc72361SWai Yew CHAY mdelay(100); 14118cc72361SWai Yew CHAY gpioorg = (u16)hw_read_20kx(hw, GPIO); 14128cc72361SWai Yew CHAY gpioorg &= 0xfffd; 14138cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, gpioorg); 14148cc72361SWai Yew CHAY mdelay(1); 14158cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, gpioorg | 0x2); 14168cc72361SWai Yew CHAY } 14178cc72361SWai Yew CHAY 14188cc72361SWai Yew CHAY i2c_write(hw, 0x00180080, 0x01, 0x80); 14198cc72361SWai Yew CHAY i2c_write(hw, 0x00180080, 0x02, 0x10); 14208cc72361SWai Yew CHAY 14218cc72361SWai Yew CHAY i2c_lock(hw); 14228cc72361SWai Yew CHAY 14238cc72361SWai Yew CHAY return 0; 14248cc72361SWai Yew CHAY } 14258cc72361SWai Yew CHAY 14268cc72361SWai Yew CHAY static int hw_dac_init(struct hw *hw, const struct dac_conf *info) 14278cc72361SWai Yew CHAY { 14288cc72361SWai Yew CHAY u32 data = 0; 14298cc72361SWai Yew CHAY u16 gpioorg = 0; 14308cc72361SWai Yew CHAY u16 subsys_id = 0; 14318cc72361SWai Yew CHAY unsigned int ret = 0; 14328cc72361SWai Yew CHAY 14338cc72361SWai Yew CHAY pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id); 14348cc72361SWai Yew CHAY if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) { 14358cc72361SWai Yew CHAY /* SB055x, unmute outputs */ 14368cc72361SWai Yew CHAY gpioorg = (u16)hw_read_20kx(hw, GPIO); 14378cc72361SWai Yew CHAY gpioorg &= 0xffbf; /* set GPIO6 to low */ 14388cc72361SWai Yew CHAY gpioorg |= 2; /* set GPIO1 to high */ 14398cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, gpioorg); 14408cc72361SWai Yew CHAY return 0; 14418cc72361SWai Yew CHAY } 14428cc72361SWai Yew CHAY 14438cc72361SWai Yew CHAY /* mute outputs */ 14448cc72361SWai Yew CHAY gpioorg = (u16)hw_read_20kx(hw, GPIO); 14458cc72361SWai Yew CHAY gpioorg &= 0xffbf; 14468cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, gpioorg); 14478cc72361SWai Yew CHAY 14488cc72361SWai Yew CHAY hw_reset_dac(hw); 14498cc72361SWai Yew CHAY 14508cc72361SWai Yew CHAY if (i2c_unlock(hw)) 14518cc72361SWai Yew CHAY return -1; 14528cc72361SWai Yew CHAY 14538cc72361SWai Yew CHAY hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ 14548cc72361SWai Yew CHAY do { 14558cc72361SWai Yew CHAY ret = hw_read_pci(hw, 0xEC); 14568cc72361SWai Yew CHAY } while (!(ret & 0x800000)); 14578cc72361SWai Yew CHAY 14588cc72361SWai Yew CHAY switch (info->msr) { 14598cc72361SWai Yew CHAY case 1: 14608cc72361SWai Yew CHAY data = 0x24; 14618cc72361SWai Yew CHAY break; 14628cc72361SWai Yew CHAY case 2: 14638cc72361SWai Yew CHAY data = 0x25; 14648cc72361SWai Yew CHAY break; 14658cc72361SWai Yew CHAY case 4: 14668cc72361SWai Yew CHAY data = 0x26; 14678cc72361SWai Yew CHAY break; 14688cc72361SWai Yew CHAY default: 14698cc72361SWai Yew CHAY data = 0x24; 14708cc72361SWai Yew CHAY break; 14718cc72361SWai Yew CHAY } 14728cc72361SWai Yew CHAY 14738cc72361SWai Yew CHAY i2c_write(hw, 0x00180080, 0x06, data); 14748cc72361SWai Yew CHAY i2c_write(hw, 0x00180080, 0x09, data); 14758cc72361SWai Yew CHAY i2c_write(hw, 0x00180080, 0x0c, data); 14768cc72361SWai Yew CHAY i2c_write(hw, 0x00180080, 0x0f, data); 14778cc72361SWai Yew CHAY 14788cc72361SWai Yew CHAY i2c_lock(hw); 14798cc72361SWai Yew CHAY 14808cc72361SWai Yew CHAY /* unmute outputs */ 14818cc72361SWai Yew CHAY gpioorg = (u16)hw_read_20kx(hw, GPIO); 14828cc72361SWai Yew CHAY gpioorg = gpioorg | 0x40; 14838cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, gpioorg); 14848cc72361SWai Yew CHAY 14858cc72361SWai Yew CHAY return 0; 14868cc72361SWai Yew CHAY } 14878cc72361SWai Yew CHAY 14888cc72361SWai Yew CHAY /* ADC operations */ 14898cc72361SWai Yew CHAY 14908cc72361SWai Yew CHAY static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type) 14918cc72361SWai Yew CHAY { 14928cc72361SWai Yew CHAY u32 data = 0; 14938cc72361SWai Yew CHAY return data; 14948cc72361SWai Yew CHAY } 14958cc72361SWai Yew CHAY 14968cc72361SWai Yew CHAY static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type) 14978cc72361SWai Yew CHAY { 14988cc72361SWai Yew CHAY u32 data = 0; 14998cc72361SWai Yew CHAY 15008cc72361SWai Yew CHAY data = hw_read_20kx(hw, GPIO); 15018cc72361SWai Yew CHAY switch (type) { 15028cc72361SWai Yew CHAY case ADC_MICIN: 15038cc72361SWai Yew CHAY data = ((data & (0x1<<7)) && (data & (0x1<<8))); 15048cc72361SWai Yew CHAY break; 15058cc72361SWai Yew CHAY case ADC_LINEIN: 15068cc72361SWai Yew CHAY data = (!(data & (0x1<<7)) && (data & (0x1<<8))); 15078cc72361SWai Yew CHAY break; 15088cc72361SWai Yew CHAY case ADC_NONE: /* Digital I/O */ 15098cc72361SWai Yew CHAY data = (!(data & (0x1<<8))); 15108cc72361SWai Yew CHAY break; 15118cc72361SWai Yew CHAY default: 15128cc72361SWai Yew CHAY data = 0; 15138cc72361SWai Yew CHAY } 15148cc72361SWai Yew CHAY return data; 15158cc72361SWai Yew CHAY } 15168cc72361SWai Yew CHAY 15178cc72361SWai Yew CHAY static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type) 15188cc72361SWai Yew CHAY { 15198cc72361SWai Yew CHAY u32 data = 0; 15208cc72361SWai Yew CHAY 15218cc72361SWai Yew CHAY data = hw_read_20kx(hw, GPIO); 15228cc72361SWai Yew CHAY switch (type) { 15238cc72361SWai Yew CHAY case ADC_MICIN: 15248cc72361SWai Yew CHAY data = (data & (0x1 << 7)) ? 1 : 0; 15258cc72361SWai Yew CHAY break; 15268cc72361SWai Yew CHAY case ADC_LINEIN: 15278cc72361SWai Yew CHAY data = (data & (0x1 << 7)) ? 0 : 1; 15288cc72361SWai Yew CHAY break; 15298cc72361SWai Yew CHAY default: 15308cc72361SWai Yew CHAY data = 0; 15318cc72361SWai Yew CHAY } 15328cc72361SWai Yew CHAY return data; 15338cc72361SWai Yew CHAY } 15348cc72361SWai Yew CHAY 15358cc72361SWai Yew CHAY static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) 15368cc72361SWai Yew CHAY { 15378cc72361SWai Yew CHAY u16 subsys_id = 0; 15388cc72361SWai Yew CHAY 15398cc72361SWai Yew CHAY pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id); 15408cc72361SWai Yew CHAY if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) { 15418cc72361SWai Yew CHAY /* SB055x cards */ 15428cc72361SWai Yew CHAY return is_adc_input_selected_SB055x(hw, type); 15438cc72361SWai Yew CHAY } else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) { 15448cc72361SWai Yew CHAY /* SB073x cards */ 15458cc72361SWai Yew CHAY return is_adc_input_selected_hendrix(hw, type); 15468cc72361SWai Yew CHAY } else if ((subsys_id & 0xf000) == 0x6000) { 15478cc72361SWai Yew CHAY /* Vista compatible cards */ 15488cc72361SWai Yew CHAY return is_adc_input_selected_hendrix(hw, type); 15498cc72361SWai Yew CHAY } else { 15508cc72361SWai Yew CHAY return is_adc_input_selected_SBx(hw, type); 15518cc72361SWai Yew CHAY } 15528cc72361SWai Yew CHAY } 15538cc72361SWai Yew CHAY 15548cc72361SWai Yew CHAY static int 15558cc72361SWai Yew CHAY adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost) 15568cc72361SWai Yew CHAY { 15578cc72361SWai Yew CHAY u32 data = 0; 15588cc72361SWai Yew CHAY 15598cc72361SWai Yew CHAY /* 15608cc72361SWai Yew CHAY * check and set the following GPIO bits accordingly 15618cc72361SWai Yew CHAY * ADC_Gain = GPIO2 15628cc72361SWai Yew CHAY * DRM_off = GPIO3 15638cc72361SWai Yew CHAY * Mic_Pwr_on = GPIO7 15648cc72361SWai Yew CHAY * Digital_IO_Sel = GPIO8 15658cc72361SWai Yew CHAY * Mic_Sw = GPIO9 15668cc72361SWai Yew CHAY * Aux/MicLine_Sw = GPIO12 15678cc72361SWai Yew CHAY */ 15688cc72361SWai Yew CHAY data = hw_read_20kx(hw, GPIO); 15698cc72361SWai Yew CHAY data &= 0xec73; 15708cc72361SWai Yew CHAY switch (type) { 15718cc72361SWai Yew CHAY case ADC_MICIN: 15728cc72361SWai Yew CHAY data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ; 15738cc72361SWai Yew CHAY data |= boost ? (0x1<<2) : 0; 15748cc72361SWai Yew CHAY break; 15758cc72361SWai Yew CHAY case ADC_LINEIN: 15768cc72361SWai Yew CHAY data |= (0x1<<8); 15778cc72361SWai Yew CHAY break; 15788cc72361SWai Yew CHAY case ADC_AUX: 15798cc72361SWai Yew CHAY data |= (0x1<<8) | (0x1<<12); 15808cc72361SWai Yew CHAY break; 15818cc72361SWai Yew CHAY case ADC_NONE: 15828cc72361SWai Yew CHAY data |= (0x1<<12); /* set to digital */ 15838cc72361SWai Yew CHAY break; 15848cc72361SWai Yew CHAY default: 15858cc72361SWai Yew CHAY return -1; 15868cc72361SWai Yew CHAY } 15878cc72361SWai Yew CHAY 15888cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, data); 15898cc72361SWai Yew CHAY 15908cc72361SWai Yew CHAY return 0; 15918cc72361SWai Yew CHAY } 15928cc72361SWai Yew CHAY 15938cc72361SWai Yew CHAY 15948cc72361SWai Yew CHAY static int 15958cc72361SWai Yew CHAY adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost) 15968cc72361SWai Yew CHAY { 15978cc72361SWai Yew CHAY u32 data = 0; 15988cc72361SWai Yew CHAY u32 i2c_data = 0; 15998cc72361SWai Yew CHAY unsigned int ret = 0; 16008cc72361SWai Yew CHAY 16018cc72361SWai Yew CHAY if (i2c_unlock(hw)) 16028cc72361SWai Yew CHAY return -1; 16038cc72361SWai Yew CHAY 16048cc72361SWai Yew CHAY do { 16058cc72361SWai Yew CHAY ret = hw_read_pci(hw, 0xEC); 16068cc72361SWai Yew CHAY } while (!(ret & 0x800000)); /* i2c ready poll */ 16078cc72361SWai Yew CHAY /* set i2c access mode as Direct Control */ 16088cc72361SWai Yew CHAY hw_write_pci(hw, 0xEC, 0x05); 16098cc72361SWai Yew CHAY 16108cc72361SWai Yew CHAY data = hw_read_20kx(hw, GPIO); 16118cc72361SWai Yew CHAY switch (type) { 16128cc72361SWai Yew CHAY case ADC_MICIN: 16138cc72361SWai Yew CHAY data |= ((0x1 << 7) | (0x1 << 8)); 16148cc72361SWai Yew CHAY i2c_data = 0x1; /* Mic-in */ 16158cc72361SWai Yew CHAY break; 16168cc72361SWai Yew CHAY case ADC_LINEIN: 16178cc72361SWai Yew CHAY data &= ~(0x1 << 7); 16188cc72361SWai Yew CHAY data |= (0x1 << 8); 16198cc72361SWai Yew CHAY i2c_data = 0x2; /* Line-in */ 16208cc72361SWai Yew CHAY break; 16218cc72361SWai Yew CHAY case ADC_NONE: 16228cc72361SWai Yew CHAY data &= ~(0x1 << 8); 16238cc72361SWai Yew CHAY i2c_data = 0x0; /* set to Digital */ 16248cc72361SWai Yew CHAY break; 16258cc72361SWai Yew CHAY default: 16268cc72361SWai Yew CHAY i2c_lock(hw); 16278cc72361SWai Yew CHAY return -1; 16288cc72361SWai Yew CHAY } 16298cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, data); 16308cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x2a, i2c_data); 16318cc72361SWai Yew CHAY if (boost) { 16328cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ 16338cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ 16348cc72361SWai Yew CHAY } else { 16358cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ 16368cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ 16378cc72361SWai Yew CHAY } 16388cc72361SWai Yew CHAY 16398cc72361SWai Yew CHAY i2c_lock(hw); 16408cc72361SWai Yew CHAY 16418cc72361SWai Yew CHAY return 0; 16428cc72361SWai Yew CHAY } 16438cc72361SWai Yew CHAY 16448cc72361SWai Yew CHAY static int 16458cc72361SWai Yew CHAY adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost) 16468cc72361SWai Yew CHAY { 16478cc72361SWai Yew CHAY u32 data = 0; 16488cc72361SWai Yew CHAY u32 i2c_data = 0; 16498cc72361SWai Yew CHAY unsigned int ret = 0; 16508cc72361SWai Yew CHAY 16518cc72361SWai Yew CHAY if (i2c_unlock(hw)) 16528cc72361SWai Yew CHAY return -1; 16538cc72361SWai Yew CHAY 16548cc72361SWai Yew CHAY do { 16558cc72361SWai Yew CHAY ret = hw_read_pci(hw, 0xEC); 16568cc72361SWai Yew CHAY } while (!(ret & 0x800000)); /* i2c ready poll */ 16578cc72361SWai Yew CHAY /* set i2c access mode as Direct Control */ 16588cc72361SWai Yew CHAY hw_write_pci(hw, 0xEC, 0x05); 16598cc72361SWai Yew CHAY 16608cc72361SWai Yew CHAY data = hw_read_20kx(hw, GPIO); 16618cc72361SWai Yew CHAY switch (type) { 16628cc72361SWai Yew CHAY case ADC_MICIN: 16638cc72361SWai Yew CHAY data |= (0x1 << 7); 16648cc72361SWai Yew CHAY i2c_data = 0x1; /* Mic-in */ 16658cc72361SWai Yew CHAY break; 16668cc72361SWai Yew CHAY case ADC_LINEIN: 16678cc72361SWai Yew CHAY data &= ~(0x1 << 7); 16688cc72361SWai Yew CHAY i2c_data = 0x2; /* Line-in */ 16698cc72361SWai Yew CHAY break; 16708cc72361SWai Yew CHAY default: 16718cc72361SWai Yew CHAY i2c_lock(hw); 16728cc72361SWai Yew CHAY return -1; 16738cc72361SWai Yew CHAY } 16748cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, data); 16758cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x2a, i2c_data); 16768cc72361SWai Yew CHAY if (boost) { 16778cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ 16788cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ 16798cc72361SWai Yew CHAY } else { 16808cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ 16818cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ 16828cc72361SWai Yew CHAY } 16838cc72361SWai Yew CHAY 16848cc72361SWai Yew CHAY i2c_lock(hw); 16858cc72361SWai Yew CHAY 16868cc72361SWai Yew CHAY return 0; 16878cc72361SWai Yew CHAY } 16888cc72361SWai Yew CHAY 16898cc72361SWai Yew CHAY static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) 16908cc72361SWai Yew CHAY { 16918cc72361SWai Yew CHAY u16 subsys_id = 0; 16928cc72361SWai Yew CHAY 16938cc72361SWai Yew CHAY pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id); 16948cc72361SWai Yew CHAY if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) { 16958cc72361SWai Yew CHAY /* SB055x cards */ 16968cc72361SWai Yew CHAY return adc_input_select_SB055x(hw, type, (ADC_MICIN == type)); 16978cc72361SWai Yew CHAY } else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) { 16988cc72361SWai Yew CHAY /* SB073x cards */ 16998cc72361SWai Yew CHAY return adc_input_select_hendrix(hw, type, (ADC_MICIN == type)); 17008cc72361SWai Yew CHAY } else if ((subsys_id & 0xf000) == 0x6000) { 17018cc72361SWai Yew CHAY /* Vista compatible cards */ 17028cc72361SWai Yew CHAY return adc_input_select_hendrix(hw, type, (ADC_MICIN == type)); 17038cc72361SWai Yew CHAY } else { 17048cc72361SWai Yew CHAY return adc_input_select_SBx(hw, type, (ADC_MICIN == type)); 17058cc72361SWai Yew CHAY } 17068cc72361SWai Yew CHAY } 17078cc72361SWai Yew CHAY 17088cc72361SWai Yew CHAY static int adc_init_SB055x(struct hw *hw, int input, int mic20db) 17098cc72361SWai Yew CHAY { 17108cc72361SWai Yew CHAY return adc_input_select_SB055x(hw, input, mic20db); 17118cc72361SWai Yew CHAY } 17128cc72361SWai Yew CHAY 17138cc72361SWai Yew CHAY static int adc_init_SBx(struct hw *hw, int input, int mic20db) 17148cc72361SWai Yew CHAY { 17158cc72361SWai Yew CHAY u16 gpioorg; 17168cc72361SWai Yew CHAY u16 input_source; 17178cc72361SWai Yew CHAY u32 adcdata = 0; 17188cc72361SWai Yew CHAY unsigned int ret = 0; 17198cc72361SWai Yew CHAY 17208cc72361SWai Yew CHAY input_source = 0x100; /* default to analog */ 17218cc72361SWai Yew CHAY switch (input) { 17228cc72361SWai Yew CHAY case ADC_MICIN: 17238cc72361SWai Yew CHAY adcdata = 0x1; 17248cc72361SWai Yew CHAY input_source = 0x180; /* set GPIO7 to select Mic */ 17258cc72361SWai Yew CHAY break; 17268cc72361SWai Yew CHAY case ADC_LINEIN: 17278cc72361SWai Yew CHAY adcdata = 0x2; 17288cc72361SWai Yew CHAY break; 17298cc72361SWai Yew CHAY case ADC_VIDEO: 17308cc72361SWai Yew CHAY adcdata = 0x4; 17318cc72361SWai Yew CHAY break; 17328cc72361SWai Yew CHAY case ADC_AUX: 17338cc72361SWai Yew CHAY adcdata = 0x8; 17348cc72361SWai Yew CHAY break; 17358cc72361SWai Yew CHAY case ADC_NONE: 17368cc72361SWai Yew CHAY adcdata = 0x0; 17378cc72361SWai Yew CHAY input_source = 0x0; /* set to Digital */ 17388cc72361SWai Yew CHAY break; 17398cc72361SWai Yew CHAY default: 17408cc72361SWai Yew CHAY break; 17418cc72361SWai Yew CHAY } 17428cc72361SWai Yew CHAY 17438cc72361SWai Yew CHAY if (i2c_unlock(hw)) 17448cc72361SWai Yew CHAY return -1; 17458cc72361SWai Yew CHAY 17468cc72361SWai Yew CHAY do { 17478cc72361SWai Yew CHAY ret = hw_read_pci(hw, 0xEC); 17488cc72361SWai Yew CHAY } while (!(ret & 0x800000)); /* i2c ready poll */ 17498cc72361SWai Yew CHAY hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ 17508cc72361SWai Yew CHAY 17518cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x0e, 0x08); 17528cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x18, 0x0a); 17538cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x28, 0x86); 17548cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x2a, adcdata); 17558cc72361SWai Yew CHAY 17568cc72361SWai Yew CHAY if (mic20db) { 17578cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1c, 0xf7); 17588cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1e, 0xf7); 17598cc72361SWai Yew CHAY } else { 17608cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1c, 0xcf); 17618cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x1e, 0xcf); 17628cc72361SWai Yew CHAY } 17638cc72361SWai Yew CHAY 17648cc72361SWai Yew CHAY if (!(hw_read_20kx(hw, ID0) & 0x100)) 17658cc72361SWai Yew CHAY i2c_write(hw, 0x001a0080, 0x16, 0x26); 17668cc72361SWai Yew CHAY 17678cc72361SWai Yew CHAY i2c_lock(hw); 17688cc72361SWai Yew CHAY 17698cc72361SWai Yew CHAY gpioorg = (u16)hw_read_20kx(hw, GPIO); 17708cc72361SWai Yew CHAY gpioorg &= 0xfe7f; 17718cc72361SWai Yew CHAY gpioorg |= input_source; 17728cc72361SWai Yew CHAY hw_write_20kx(hw, GPIO, gpioorg); 17738cc72361SWai Yew CHAY 17748cc72361SWai Yew CHAY return 0; 17758cc72361SWai Yew CHAY } 17768cc72361SWai Yew CHAY 17778cc72361SWai Yew CHAY static int hw_adc_init(struct hw *hw, const struct adc_conf *info) 17788cc72361SWai Yew CHAY { 17798cc72361SWai Yew CHAY int err = 0; 17808cc72361SWai Yew CHAY u16 subsys_id = 0; 17818cc72361SWai Yew CHAY 17828cc72361SWai Yew CHAY pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id); 17838cc72361SWai Yew CHAY if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) { 17848cc72361SWai Yew CHAY /* Sb055x card */ 17858cc72361SWai Yew CHAY err = adc_init_SB055x(hw, info->input, info->mic20db); 17868cc72361SWai Yew CHAY } else { 17878cc72361SWai Yew CHAY err = adc_init_SBx(hw, info->input, info->mic20db); 17888cc72361SWai Yew CHAY } 17898cc72361SWai Yew CHAY 17908cc72361SWai Yew CHAY return err; 17918cc72361SWai Yew CHAY } 17928cc72361SWai Yew CHAY 17938cc72361SWai Yew CHAY static int hw_have_digit_io_switch(struct hw *hw) 17948cc72361SWai Yew CHAY { 17958cc72361SWai Yew CHAY u16 subsys_id = 0; 17968cc72361SWai Yew CHAY 17978cc72361SWai Yew CHAY pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id); 17988cc72361SWai Yew CHAY /* SB073x and Vista compatible cards have no digit IO switch */ 17998cc72361SWai Yew CHAY return !((subsys_id == 0x0029) || (subsys_id == 0x0031) 18008cc72361SWai Yew CHAY || ((subsys_id & 0xf000) == 0x6000)); 18018cc72361SWai Yew CHAY } 18028cc72361SWai Yew CHAY 180342a0b318STakashi Iwai #define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) 180442a0b318STakashi Iwai 18058cc72361SWai Yew CHAY #define UAA_CFG_PWRSTATUS 0x44 18068cc72361SWai Yew CHAY #define UAA_CFG_SPACE_FLAG 0xA0 18078cc72361SWai Yew CHAY #define UAA_CORE_CHANGE 0x3FFC 18088cc72361SWai Yew CHAY static int uaa_to_xfi(struct pci_dev *pci) 18098cc72361SWai Yew CHAY { 18108cc72361SWai Yew CHAY unsigned int bar0, bar1, bar2, bar3, bar4, bar5; 18118cc72361SWai Yew CHAY unsigned int cmd, irq, cl_size, l_timer, pwr; 18128cc72361SWai Yew CHAY unsigned int is_uaa = 0; 18138cc72361SWai Yew CHAY unsigned int data[4] = {0}; 18148cc72361SWai Yew CHAY unsigned int io_base; 18158cc72361SWai Yew CHAY void *mem_base; 18168cc72361SWai Yew CHAY int i = 0; 181742a0b318STakashi Iwai const u32 CTLX = CTLBITS('C', 'T', 'L', 'X'); 181842a0b318STakashi Iwai const u32 CTL_ = CTLBITS('C', 'T', 'L', '-'); 181942a0b318STakashi Iwai const u32 CTLF = CTLBITS('C', 'T', 'L', 'F'); 182042a0b318STakashi Iwai const u32 CTLi = CTLBITS('C', 'T', 'L', 'i'); 182142a0b318STakashi Iwai const u32 CTLA = CTLBITS('C', 'T', 'L', 'A'); 182242a0b318STakashi Iwai const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z'); 182342a0b318STakashi Iwai const u32 CTLL = CTLBITS('C', 'T', 'L', 'L'); 18248cc72361SWai Yew CHAY 18258cc72361SWai Yew CHAY /* By default, Hendrix card UAA Bar0 should be using memory... */ 18268cc72361SWai Yew CHAY io_base = pci_resource_start(pci, 0); 18278cc72361SWai Yew CHAY mem_base = ioremap(io_base, pci_resource_len(pci, 0)); 18288cc72361SWai Yew CHAY if (NULL == mem_base) 18298cc72361SWai Yew CHAY return -ENOENT; 18308cc72361SWai Yew CHAY 18318cc72361SWai Yew CHAY /* Read current mode from Mode Change Register */ 18328cc72361SWai Yew CHAY for (i = 0; i < 4; i++) 18338cc72361SWai Yew CHAY data[i] = readl(mem_base + UAA_CORE_CHANGE); 18348cc72361SWai Yew CHAY 18358cc72361SWai Yew CHAY /* Determine current mode... */ 18368cc72361SWai Yew CHAY if (data[0] == CTLA) { 18378cc72361SWai Yew CHAY is_uaa = ((data[1] == CTLZ && data[2] == CTLL 18388cc72361SWai Yew CHAY && data[3] == CTLA) || (data[1] == CTLA 18398cc72361SWai Yew CHAY && data[2] == CTLZ && data[3] == CTLL)); 18408cc72361SWai Yew CHAY } else if (data[0] == CTLZ) { 18418cc72361SWai Yew CHAY is_uaa = (data[1] == CTLL 18428cc72361SWai Yew CHAY && data[2] == CTLA && data[3] == CTLA); 18438cc72361SWai Yew CHAY } else if (data[0] == CTLL) { 18448cc72361SWai Yew CHAY is_uaa = (data[1] == CTLA 18458cc72361SWai Yew CHAY && data[2] == CTLA && data[3] == CTLZ); 18468cc72361SWai Yew CHAY } else { 18478cc72361SWai Yew CHAY is_uaa = 0; 18488cc72361SWai Yew CHAY } 18498cc72361SWai Yew CHAY 18508cc72361SWai Yew CHAY if (!is_uaa) { 18518cc72361SWai Yew CHAY /* Not in UAA mode currently. Return directly. */ 18528cc72361SWai Yew CHAY iounmap(mem_base); 18538cc72361SWai Yew CHAY return 0; 18548cc72361SWai Yew CHAY } 18558cc72361SWai Yew CHAY 18568cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0); 18578cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1); 18588cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2); 18598cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3); 18608cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4); 18618cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5); 18628cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq); 18638cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size); 18648cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer); 18658cc72361SWai Yew CHAY pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr); 18668cc72361SWai Yew CHAY pci_read_config_dword(pci, PCI_COMMAND, &cmd); 18678cc72361SWai Yew CHAY 18688cc72361SWai Yew CHAY /* Set up X-Fi core PCI configuration space. */ 18698cc72361SWai Yew CHAY /* Switch to X-Fi config space with BAR0 exposed. */ 18708cc72361SWai Yew CHAY pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321); 18718cc72361SWai Yew CHAY /* Copy UAA's BAR5 into X-Fi BAR0 */ 18728cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5); 18738cc72361SWai Yew CHAY /* Switch to X-Fi config space without BAR0 exposed. */ 18748cc72361SWai Yew CHAY pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678); 18758cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1); 18768cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2); 18778cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3); 18788cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4); 18798cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq); 18808cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size); 18818cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer); 18828cc72361SWai Yew CHAY pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr); 18838cc72361SWai Yew CHAY pci_write_config_dword(pci, PCI_COMMAND, cmd); 18848cc72361SWai Yew CHAY 18858cc72361SWai Yew CHAY /* Switch to X-Fi mode */ 18868cc72361SWai Yew CHAY writel(CTLX, (mem_base + UAA_CORE_CHANGE)); 18878cc72361SWai Yew CHAY writel(CTL_, (mem_base + UAA_CORE_CHANGE)); 18888cc72361SWai Yew CHAY writel(CTLF, (mem_base + UAA_CORE_CHANGE)); 18898cc72361SWai Yew CHAY writel(CTLi, (mem_base + UAA_CORE_CHANGE)); 18908cc72361SWai Yew CHAY 18918cc72361SWai Yew CHAY iounmap(mem_base); 18928cc72361SWai Yew CHAY 18938cc72361SWai Yew CHAY return 0; 18948cc72361SWai Yew CHAY } 18958cc72361SWai Yew CHAY 1896*b7bbf876STakashi Iwai static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id) 1897*b7bbf876STakashi Iwai { 1898*b7bbf876STakashi Iwai struct hw *hw = dev_id; 1899*b7bbf876STakashi Iwai unsigned int status; 1900*b7bbf876STakashi Iwai 1901*b7bbf876STakashi Iwai status = hw_read_20kx(hw, GIP); 1902*b7bbf876STakashi Iwai if (!status) 1903*b7bbf876STakashi Iwai return IRQ_NONE; 1904*b7bbf876STakashi Iwai 1905*b7bbf876STakashi Iwai if (hw->irq_callback) 1906*b7bbf876STakashi Iwai hw->irq_callback(hw->irq_callback_data, status); 1907*b7bbf876STakashi Iwai 1908*b7bbf876STakashi Iwai hw_write_20kx(hw, GIP, status); 1909*b7bbf876STakashi Iwai return IRQ_HANDLED; 1910*b7bbf876STakashi Iwai } 1911*b7bbf876STakashi Iwai 19128cc72361SWai Yew CHAY static int hw_card_start(struct hw *hw) 19138cc72361SWai Yew CHAY { 19148cc72361SWai Yew CHAY int err = 0; 19158cc72361SWai Yew CHAY struct pci_dev *pci = hw->pci; 19168cc72361SWai Yew CHAY u16 subsys_id = 0; 19178cc72361SWai Yew CHAY 19188cc72361SWai Yew CHAY err = pci_enable_device(pci); 19198cc72361SWai Yew CHAY if (err < 0) 19208cc72361SWai Yew CHAY return err; 19218cc72361SWai Yew CHAY 19228cc72361SWai Yew CHAY /* Set DMA transfer mask */ 19236bc5874aSTakashi Iwai if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || 19246bc5874aSTakashi Iwai pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { 19258cc72361SWai Yew CHAY printk(KERN_ERR "architecture does not support PCI " 19266bc5874aSTakashi Iwai "busmaster DMA with mask 0x%llx\n", 19276bc5874aSTakashi Iwai CT_XFI_DMA_MASK); 19288cc72361SWai Yew CHAY err = -ENXIO; 19298cc72361SWai Yew CHAY goto error1; 19308cc72361SWai Yew CHAY } 19318cc72361SWai Yew CHAY 19328cc72361SWai Yew CHAY err = pci_request_regions(pci, "XFi"); 19338cc72361SWai Yew CHAY if (err < 0) 19348cc72361SWai Yew CHAY goto error1; 19358cc72361SWai Yew CHAY 19368cc72361SWai Yew CHAY /* Switch to X-Fi mode from UAA mode if neeeded */ 19378cc72361SWai Yew CHAY pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsys_id); 19388cc72361SWai Yew CHAY if ((0x5 == pci->device) && (0x6000 == (subsys_id & 0x6000))) { 19398cc72361SWai Yew CHAY err = uaa_to_xfi(pci); 19408cc72361SWai Yew CHAY if (err) 19418cc72361SWai Yew CHAY goto error2; 19428cc72361SWai Yew CHAY 19438cc72361SWai Yew CHAY hw->io_base = pci_resource_start(pci, 5); 19448cc72361SWai Yew CHAY } else { 19458cc72361SWai Yew CHAY hw->io_base = pci_resource_start(pci, 0); 19468cc72361SWai Yew CHAY } 19478cc72361SWai Yew CHAY 1948*b7bbf876STakashi Iwai err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, 1949*b7bbf876STakashi Iwai "ctxfi", hw); 1950*b7bbf876STakashi Iwai if (err < 0) { 1951*b7bbf876STakashi Iwai printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); 19528cc72361SWai Yew CHAY goto error2; 19538cc72361SWai Yew CHAY } 19548cc72361SWai Yew CHAY hw->irq = pci->irq; 19558cc72361SWai Yew CHAY 19568cc72361SWai Yew CHAY pci_set_master(pci); 19578cc72361SWai Yew CHAY 19588cc72361SWai Yew CHAY return 0; 19598cc72361SWai Yew CHAY 19608cc72361SWai Yew CHAY error2: 19618cc72361SWai Yew CHAY pci_release_regions(pci); 19628cc72361SWai Yew CHAY hw->io_base = 0; 19638cc72361SWai Yew CHAY error1: 19648cc72361SWai Yew CHAY pci_disable_device(pci); 19658cc72361SWai Yew CHAY return err; 19668cc72361SWai Yew CHAY } 19678cc72361SWai Yew CHAY 19688cc72361SWai Yew CHAY static int hw_card_stop(struct hw *hw) 19698cc72361SWai Yew CHAY { 19708cc72361SWai Yew CHAY /* TODO: Disable interrupt and so on... */ 1971*b7bbf876STakashi Iwai if (hw->irq >= 0) 1972*b7bbf876STakashi Iwai synchronize_irq(hw->irq); 19738cc72361SWai Yew CHAY return 0; 19748cc72361SWai Yew CHAY } 19758cc72361SWai Yew CHAY 19768cc72361SWai Yew CHAY static int hw_card_shutdown(struct hw *hw) 19778cc72361SWai Yew CHAY { 19788cc72361SWai Yew CHAY if (hw->irq >= 0) 19798cc72361SWai Yew CHAY free_irq(hw->irq, hw); 19808cc72361SWai Yew CHAY 19818cc72361SWai Yew CHAY hw->irq = -1; 19828cc72361SWai Yew CHAY 19838cc72361SWai Yew CHAY if (NULL != ((void *)hw->mem_base)) 19848cc72361SWai Yew CHAY iounmap((void *)hw->mem_base); 19858cc72361SWai Yew CHAY 19868cc72361SWai Yew CHAY hw->mem_base = (unsigned long)NULL; 19878cc72361SWai Yew CHAY 19888cc72361SWai Yew CHAY if (hw->io_base) 19898cc72361SWai Yew CHAY pci_release_regions(hw->pci); 19908cc72361SWai Yew CHAY 19918cc72361SWai Yew CHAY hw->io_base = 0; 19928cc72361SWai Yew CHAY 19938cc72361SWai Yew CHAY pci_disable_device(hw->pci); 19948cc72361SWai Yew CHAY 19958cc72361SWai Yew CHAY return 0; 19968cc72361SWai Yew CHAY } 19978cc72361SWai Yew CHAY 19988cc72361SWai Yew CHAY static int hw_card_init(struct hw *hw, struct card_conf *info) 19998cc72361SWai Yew CHAY { 20008cc72361SWai Yew CHAY int err; 20018cc72361SWai Yew CHAY unsigned int gctl; 20028cc72361SWai Yew CHAY u16 subsys_id = 0; 20038cc72361SWai Yew CHAY u32 data = 0; 20048cc72361SWai Yew CHAY struct dac_conf dac_info = {0}; 20058cc72361SWai Yew CHAY struct adc_conf adc_info = {0}; 20068cc72361SWai Yew CHAY struct daio_conf daio_info = {0}; 20078cc72361SWai Yew CHAY struct trn_conf trn_info = {0}; 20088cc72361SWai Yew CHAY 20098cc72361SWai Yew CHAY /* Get PCI io port base address and do Hendrix switch if needed. */ 20108cc72361SWai Yew CHAY if (!hw->io_base) { 20118cc72361SWai Yew CHAY err = hw_card_start(hw); 20128cc72361SWai Yew CHAY if (err) 20138cc72361SWai Yew CHAY return err; 20148cc72361SWai Yew CHAY } 20158cc72361SWai Yew CHAY 20168cc72361SWai Yew CHAY /* PLL init */ 20178cc72361SWai Yew CHAY err = hw_pll_init(hw, info->rsr); 20188cc72361SWai Yew CHAY if (err < 0) 20198cc72361SWai Yew CHAY return err; 20208cc72361SWai Yew CHAY 20218cc72361SWai Yew CHAY /* kick off auto-init */ 20228cc72361SWai Yew CHAY err = hw_auto_init(hw); 20238cc72361SWai Yew CHAY if (err < 0) 20248cc72361SWai Yew CHAY return err; 20258cc72361SWai Yew CHAY 20268cc72361SWai Yew CHAY /* Enable audio ring */ 20278cc72361SWai Yew CHAY gctl = hw_read_20kx(hw, GCTL); 20288cc72361SWai Yew CHAY set_field(&gctl, GCTL_EAC, 1); 20298cc72361SWai Yew CHAY set_field(&gctl, GCTL_DBP, 1); 20308cc72361SWai Yew CHAY set_field(&gctl, GCTL_TBP, 1); 20318cc72361SWai Yew CHAY set_field(&gctl, GCTL_FBP, 1); 20328cc72361SWai Yew CHAY set_field(&gctl, GCTL_ET, 1); 20338cc72361SWai Yew CHAY hw_write_20kx(hw, GCTL, gctl); 20348cc72361SWai Yew CHAY mdelay(10); 20358cc72361SWai Yew CHAY 20368cc72361SWai Yew CHAY /* Reset all global pending interrupts */ 20378cc72361SWai Yew CHAY hw_write_20kx(hw, GIE, 0); 20388cc72361SWai Yew CHAY /* Reset all SRC pending interrupts */ 20398cc72361SWai Yew CHAY hw_write_20kx(hw, SRCIP, 0); 20408cc72361SWai Yew CHAY mdelay(30); 20418cc72361SWai Yew CHAY 20428cc72361SWai Yew CHAY pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id); 20438cc72361SWai Yew CHAY /* Detect the card ID and configure GPIO accordingly. */ 20448cc72361SWai Yew CHAY if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) { 20458cc72361SWai Yew CHAY /* SB055x cards */ 20468cc72361SWai Yew CHAY hw_write_20kx(hw, GPIOCTL, 0x13fe); 20478cc72361SWai Yew CHAY } else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) { 20488cc72361SWai Yew CHAY /* SB073x cards */ 20498cc72361SWai Yew CHAY hw_write_20kx(hw, GPIOCTL, 0x00e6); 20508cc72361SWai Yew CHAY } else if ((subsys_id & 0xf000) == 0x6000) { 20518cc72361SWai Yew CHAY /* Vista compatible cards */ 20528cc72361SWai Yew CHAY hw_write_20kx(hw, GPIOCTL, 0x00c2); 20538cc72361SWai Yew CHAY } else { 20548cc72361SWai Yew CHAY hw_write_20kx(hw, GPIOCTL, 0x01e6); 20558cc72361SWai Yew CHAY } 20568cc72361SWai Yew CHAY 20578cc72361SWai Yew CHAY trn_info.vm_pgt_phys = info->vm_pgt_phys; 20588cc72361SWai Yew CHAY err = hw_trn_init(hw, &trn_info); 20598cc72361SWai Yew CHAY if (err < 0) 20608cc72361SWai Yew CHAY return err; 20618cc72361SWai Yew CHAY 20628cc72361SWai Yew CHAY daio_info.msr = info->msr; 20638cc72361SWai Yew CHAY err = hw_daio_init(hw, &daio_info); 20648cc72361SWai Yew CHAY if (err < 0) 20658cc72361SWai Yew CHAY return err; 20668cc72361SWai Yew CHAY 20678cc72361SWai Yew CHAY dac_info.msr = info->msr; 20688cc72361SWai Yew CHAY err = hw_dac_init(hw, &dac_info); 20698cc72361SWai Yew CHAY if (err < 0) 20708cc72361SWai Yew CHAY return err; 20718cc72361SWai Yew CHAY 20728cc72361SWai Yew CHAY adc_info.msr = info->msr; 20738cc72361SWai Yew CHAY adc_info.input = ADC_LINEIN; 20748cc72361SWai Yew CHAY adc_info.mic20db = 0; 20758cc72361SWai Yew CHAY err = hw_adc_init(hw, &adc_info); 20768cc72361SWai Yew CHAY if (err < 0) 20778cc72361SWai Yew CHAY return err; 20788cc72361SWai Yew CHAY 20798cc72361SWai Yew CHAY data = hw_read_20kx(hw, SRCMCTL); 20808cc72361SWai Yew CHAY data |= 0x1; /* Enables input from the audio ring */ 20818cc72361SWai Yew CHAY hw_write_20kx(hw, SRCMCTL, data); 20828cc72361SWai Yew CHAY 20838cc72361SWai Yew CHAY return 0; 20848cc72361SWai Yew CHAY } 20858cc72361SWai Yew CHAY 20868cc72361SWai Yew CHAY static u32 hw_read_20kx(struct hw *hw, u32 reg) 20878cc72361SWai Yew CHAY { 20888cc72361SWai Yew CHAY u32 value; 20898cc72361SWai Yew CHAY unsigned long flags; 20908cc72361SWai Yew CHAY 20918cc72361SWai Yew CHAY spin_lock_irqsave( 20928cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); 20938cc72361SWai Yew CHAY outl(reg, hw->io_base + 0x0); 20948cc72361SWai Yew CHAY value = inl(hw->io_base + 0x4); 20958cc72361SWai Yew CHAY spin_unlock_irqrestore( 20968cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); 20978cc72361SWai Yew CHAY 20988cc72361SWai Yew CHAY return value; 20998cc72361SWai Yew CHAY } 21008cc72361SWai Yew CHAY 21018cc72361SWai Yew CHAY static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) 21028cc72361SWai Yew CHAY { 21038cc72361SWai Yew CHAY unsigned long flags; 21048cc72361SWai Yew CHAY 21058cc72361SWai Yew CHAY spin_lock_irqsave( 21068cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); 21078cc72361SWai Yew CHAY outl(reg, hw->io_base + 0x0); 21088cc72361SWai Yew CHAY outl(data, hw->io_base + 0x4); 21098cc72361SWai Yew CHAY spin_unlock_irqrestore( 21108cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); 21118cc72361SWai Yew CHAY 21128cc72361SWai Yew CHAY } 21138cc72361SWai Yew CHAY 21148cc72361SWai Yew CHAY static u32 hw_read_pci(struct hw *hw, u32 reg) 21158cc72361SWai Yew CHAY { 21168cc72361SWai Yew CHAY u32 value; 21178cc72361SWai Yew CHAY unsigned long flags; 21188cc72361SWai Yew CHAY 21198cc72361SWai Yew CHAY spin_lock_irqsave( 21208cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); 21218cc72361SWai Yew CHAY outl(reg, hw->io_base + 0x10); 21228cc72361SWai Yew CHAY value = inl(hw->io_base + 0x14); 21238cc72361SWai Yew CHAY spin_unlock_irqrestore( 21248cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); 21258cc72361SWai Yew CHAY 21268cc72361SWai Yew CHAY return value; 21278cc72361SWai Yew CHAY } 21288cc72361SWai Yew CHAY 21298cc72361SWai Yew CHAY static void hw_write_pci(struct hw *hw, u32 reg, u32 data) 21308cc72361SWai Yew CHAY { 21318cc72361SWai Yew CHAY unsigned long flags; 21328cc72361SWai Yew CHAY 21338cc72361SWai Yew CHAY spin_lock_irqsave( 21348cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); 21358cc72361SWai Yew CHAY outl(reg, hw->io_base + 0x10); 21368cc72361SWai Yew CHAY outl(data, hw->io_base + 0x14); 21378cc72361SWai Yew CHAY spin_unlock_irqrestore( 21388cc72361SWai Yew CHAY &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); 21398cc72361SWai Yew CHAY } 21408cc72361SWai Yew CHAY 21418cc72361SWai Yew CHAY int create_20k1_hw_obj(struct hw **rhw) 21428cc72361SWai Yew CHAY { 21438cc72361SWai Yew CHAY struct hw *hw; 21448cc72361SWai Yew CHAY struct hw20k1 *hw20k1; 21458cc72361SWai Yew CHAY 21468cc72361SWai Yew CHAY *rhw = NULL; 21478cc72361SWai Yew CHAY hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL); 21488cc72361SWai Yew CHAY if (NULL == hw20k1) 21498cc72361SWai Yew CHAY return -ENOMEM; 21508cc72361SWai Yew CHAY 21518cc72361SWai Yew CHAY spin_lock_init(&hw20k1->reg_20k1_lock); 21528cc72361SWai Yew CHAY spin_lock_init(&hw20k1->reg_pci_lock); 21538cc72361SWai Yew CHAY 21548cc72361SWai Yew CHAY hw = &hw20k1->hw; 21558cc72361SWai Yew CHAY 21568cc72361SWai Yew CHAY hw->io_base = 0; 21578cc72361SWai Yew CHAY hw->mem_base = (unsigned long)NULL; 21588cc72361SWai Yew CHAY hw->irq = -1; 21598cc72361SWai Yew CHAY 21608cc72361SWai Yew CHAY hw->card_init = hw_card_init; 21618cc72361SWai Yew CHAY hw->card_stop = hw_card_stop; 21628cc72361SWai Yew CHAY hw->pll_init = hw_pll_init; 21638cc72361SWai Yew CHAY hw->is_adc_source_selected = hw_is_adc_input_selected; 21648cc72361SWai Yew CHAY hw->select_adc_source = hw_adc_input_select; 21658cc72361SWai Yew CHAY hw->have_digit_io_switch = hw_have_digit_io_switch; 21668cc72361SWai Yew CHAY 21678cc72361SWai Yew CHAY hw->src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk; 21688cc72361SWai Yew CHAY hw->src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk; 21698cc72361SWai Yew CHAY hw->src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk; 21708cc72361SWai Yew CHAY hw->src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk; 21718cc72361SWai Yew CHAY hw->src_set_state = src_set_state; 21728cc72361SWai Yew CHAY hw->src_set_bm = src_set_bm; 21738cc72361SWai Yew CHAY hw->src_set_rsr = src_set_rsr; 21748cc72361SWai Yew CHAY hw->src_set_sf = src_set_sf; 21758cc72361SWai Yew CHAY hw->src_set_wr = src_set_wr; 21768cc72361SWai Yew CHAY hw->src_set_pm = src_set_pm; 21778cc72361SWai Yew CHAY hw->src_set_rom = src_set_rom; 21788cc72361SWai Yew CHAY hw->src_set_vo = src_set_vo; 21798cc72361SWai Yew CHAY hw->src_set_st = src_set_st; 21808cc72361SWai Yew CHAY hw->src_set_ie = src_set_ie; 21818cc72361SWai Yew CHAY hw->src_set_ilsz = src_set_ilsz; 21828cc72361SWai Yew CHAY hw->src_set_bp = src_set_bp; 21838cc72361SWai Yew CHAY hw->src_set_cisz = src_set_cisz; 21848cc72361SWai Yew CHAY hw->src_set_ca = src_set_ca; 21858cc72361SWai Yew CHAY hw->src_set_sa = src_set_sa; 21868cc72361SWai Yew CHAY hw->src_set_la = src_set_la; 21878cc72361SWai Yew CHAY hw->src_set_pitch = src_set_pitch; 21888cc72361SWai Yew CHAY hw->src_set_dirty = src_set_dirty; 21898cc72361SWai Yew CHAY hw->src_set_clear_zbufs = src_set_clear_zbufs; 21908cc72361SWai Yew CHAY hw->src_set_dirty_all = src_set_dirty_all; 21918cc72361SWai Yew CHAY hw->src_commit_write = src_commit_write; 21928cc72361SWai Yew CHAY hw->src_get_ca = src_get_ca; 21938cc72361SWai Yew CHAY hw->src_get_dirty = src_get_dirty; 21948cc72361SWai Yew CHAY hw->src_dirty_conj_mask = src_dirty_conj_mask; 21958cc72361SWai Yew CHAY hw->src_mgr_enbs_src = src_mgr_enbs_src; 21968cc72361SWai Yew CHAY hw->src_mgr_enb_src = src_mgr_enb_src; 21978cc72361SWai Yew CHAY hw->src_mgr_dsb_src = src_mgr_dsb_src; 21988cc72361SWai Yew CHAY hw->src_mgr_commit_write = src_mgr_commit_write; 21998cc72361SWai Yew CHAY 22008cc72361SWai Yew CHAY hw->srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk; 22018cc72361SWai Yew CHAY hw->srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk; 22028cc72361SWai Yew CHAY hw->srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc; 22038cc72361SWai Yew CHAY hw->srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser; 22048cc72361SWai Yew CHAY hw->srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt; 22058cc72361SWai Yew CHAY hw->srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr; 22068cc72361SWai Yew CHAY hw->srcimp_mgr_commit_write = srcimp_mgr_commit_write; 22078cc72361SWai Yew CHAY 22088cc72361SWai Yew CHAY hw->amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk; 22098cc72361SWai Yew CHAY hw->amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk; 22108cc72361SWai Yew CHAY hw->amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk; 22118cc72361SWai Yew CHAY hw->amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk; 22128cc72361SWai Yew CHAY hw->amixer_set_mode = amixer_set_mode; 22138cc72361SWai Yew CHAY hw->amixer_set_iv = amixer_set_iv; 22148cc72361SWai Yew CHAY hw->amixer_set_x = amixer_set_x; 22158cc72361SWai Yew CHAY hw->amixer_set_y = amixer_set_y; 22168cc72361SWai Yew CHAY hw->amixer_set_sadr = amixer_set_sadr; 22178cc72361SWai Yew CHAY hw->amixer_set_se = amixer_set_se; 22188cc72361SWai Yew CHAY hw->amixer_set_dirty = amixer_set_dirty; 22198cc72361SWai Yew CHAY hw->amixer_set_dirty_all = amixer_set_dirty_all; 22208cc72361SWai Yew CHAY hw->amixer_commit_write = amixer_commit_write; 22218cc72361SWai Yew CHAY hw->amixer_get_y = amixer_get_y; 22228cc72361SWai Yew CHAY hw->amixer_get_dirty = amixer_get_dirty; 22238cc72361SWai Yew CHAY 22248cc72361SWai Yew CHAY hw->dai_get_ctrl_blk = dai_get_ctrl_blk; 22258cc72361SWai Yew CHAY hw->dai_put_ctrl_blk = dai_put_ctrl_blk; 22268cc72361SWai Yew CHAY hw->dai_srt_set_srco = dai_srt_set_srcr; 22278cc72361SWai Yew CHAY hw->dai_srt_set_srcm = dai_srt_set_srcl; 22288cc72361SWai Yew CHAY hw->dai_srt_set_rsr = dai_srt_set_rsr; 22298cc72361SWai Yew CHAY hw->dai_srt_set_drat = dai_srt_set_drat; 22308cc72361SWai Yew CHAY hw->dai_srt_set_ec = dai_srt_set_ec; 22318cc72361SWai Yew CHAY hw->dai_srt_set_et = dai_srt_set_et; 22328cc72361SWai Yew CHAY hw->dai_commit_write = dai_commit_write; 22338cc72361SWai Yew CHAY 22348cc72361SWai Yew CHAY hw->dao_get_ctrl_blk = dao_get_ctrl_blk; 22358cc72361SWai Yew CHAY hw->dao_put_ctrl_blk = dao_put_ctrl_blk; 22368cc72361SWai Yew CHAY hw->dao_set_spos = dao_set_spos; 22378cc72361SWai Yew CHAY hw->dao_commit_write = dao_commit_write; 22388cc72361SWai Yew CHAY hw->dao_get_spos = dao_get_spos; 22398cc72361SWai Yew CHAY 22408cc72361SWai Yew CHAY hw->daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk; 22418cc72361SWai Yew CHAY hw->daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk; 22428cc72361SWai Yew CHAY hw->daio_mgr_enb_dai = daio_mgr_enb_dai; 22438cc72361SWai Yew CHAY hw->daio_mgr_dsb_dai = daio_mgr_dsb_dai; 22448cc72361SWai Yew CHAY hw->daio_mgr_enb_dao = daio_mgr_enb_dao; 22458cc72361SWai Yew CHAY hw->daio_mgr_dsb_dao = daio_mgr_dsb_dao; 22468cc72361SWai Yew CHAY hw->daio_mgr_dao_init = daio_mgr_dao_init; 22478cc72361SWai Yew CHAY hw->daio_mgr_set_imaparc = daio_mgr_set_imaparc; 22488cc72361SWai Yew CHAY hw->daio_mgr_set_imapnxt = daio_mgr_set_imapnxt; 22498cc72361SWai Yew CHAY hw->daio_mgr_set_imapaddr = daio_mgr_set_imapaddr; 22508cc72361SWai Yew CHAY hw->daio_mgr_commit_write = daio_mgr_commit_write; 22518cc72361SWai Yew CHAY 2252*b7bbf876STakashi Iwai hw->set_timer_irq = set_timer_irq; 2253*b7bbf876STakashi Iwai hw->set_timer_tick = set_timer_tick; 2254*b7bbf876STakashi Iwai 22558cc72361SWai Yew CHAY *rhw = hw; 22568cc72361SWai Yew CHAY 22578cc72361SWai Yew CHAY return 0; 22588cc72361SWai Yew CHAY } 22598cc72361SWai Yew CHAY 22608cc72361SWai Yew CHAY int destroy_20k1_hw_obj(struct hw *hw) 22618cc72361SWai Yew CHAY { 22628cc72361SWai Yew CHAY if (hw->io_base) 22638cc72361SWai Yew CHAY hw_card_shutdown(hw); 22648cc72361SWai Yew CHAY 22658cc72361SWai Yew CHAY kfree(container_of(hw, struct hw20k1, hw)); 22668cc72361SWai Yew CHAY return 0; 22678cc72361SWai Yew CHAY } 2268