1*433d6423SLionel Sambuc #include "AC97.h"
2*433d6423SLionel Sambuc
3*433d6423SLionel Sambuc
4*433d6423SLionel Sambuc
5*433d6423SLionel Sambuc
6*433d6423SLionel Sambuc
7*433d6423SLionel Sambuc /* AC97 Mixer and Mode control function prototypes */
8*433d6423SLionel Sambuc
9*433d6423SLionel Sambuc static int AC97_write(const DEV_STRUCT * pCC, u16_t wAddr, u16_t
10*433d6423SLionel Sambuc wData);
11*433d6423SLionel Sambuc static int AC97_write_unsynced(const DEV_STRUCT * pCC, u16_t wAddr,
12*433d6423SLionel Sambuc u16_t wData);
13*433d6423SLionel Sambuc static int AC97_read_unsynced(const DEV_STRUCT * pCC, u16_t wAddr,
14*433d6423SLionel Sambuc u16_t *data);
15*433d6423SLionel Sambuc static void set_nice_volume(void);
16*433d6423SLionel Sambuc static int AC97_get_volume(struct volume_level *level);
17*433d6423SLionel Sambuc static int AC97_set_volume(const struct volume_level *level);
18*433d6423SLionel Sambuc
19*433d6423SLionel Sambuc
20*433d6423SLionel Sambuc
21*433d6423SLionel Sambuc #define AC97_0DB_GAIN 0x0008
22*433d6423SLionel Sambuc #define AC97_MAX_ATTN 0x003f
23*433d6423SLionel Sambuc #define AC97_MUTE 0x8000U
24*433d6423SLionel Sambuc
25*433d6423SLionel Sambuc
26*433d6423SLionel Sambuc /* Control function defines */
27*433d6423SLionel Sambuc #define AC97_CTL_4SPKR 0x00U /* 4-spkr output mode enable */
28*433d6423SLionel Sambuc #define AC97_CTL_MICBOOST 0x01U /* Mic boost (+30 dB) enable */
29*433d6423SLionel Sambuc #define AC97_CTL_PWRDOWN 0x02U /* power-down mode */
30*433d6423SLionel Sambuc #define AC97_CTL_DOSMODE 0x03U /* A/D sync to DAC1 */
31*433d6423SLionel Sambuc
32*433d6423SLionel Sambuc /* Timeout waiting for: */
33*433d6423SLionel Sambuc #define AC97_ERR_WIP_TIMEOUT -1 /* write in progress complete */
34*433d6423SLionel Sambuc #define AC97_ERR_DATA_TIMEOUT -2 /* data ready */
35*433d6423SLionel Sambuc #define AC97_ERR_SRC_NOT_BUSY_TIMEOUT -3 /* SRC not busy */
36*433d6423SLionel Sambuc #define AC97_ERR_SRC_SYNC_TIMEOUT -4 /* state #1 */
37*433d6423SLionel Sambuc
38*433d6423SLionel Sambuc
39*433d6423SLionel Sambuc
40*433d6423SLionel Sambuc
41*433d6423SLionel Sambuc
42*433d6423SLionel Sambuc
43*433d6423SLionel Sambuc /* Timeouts in milliseconds */
44*433d6423SLionel Sambuc #define WIP_TIMEOUT 250UL
45*433d6423SLionel Sambuc #define DRDY_TIMEOUT 250UL
46*433d6423SLionel Sambuc
47*433d6423SLionel Sambuc /* The default SRC syncronization state number is 1. This state occurs
48*433d6423SLionel Sambuc just after de-assertion of SYNC. This is supposed to be the safest
49*433d6423SLionel Sambuc state for accessing the codec with an ES1371 Rev 1. Later versions
50*433d6423SLionel Sambuc of the chip allegedly don't require syncronization. Be very careful
51*433d6423SLionel Sambuc if you change this ! */
52*433d6423SLionel Sambuc
53*433d6423SLionel Sambuc #define SRC_UNSYNCED 0xffffffffUL
54*433d6423SLionel Sambuc static u32_t SrcSyncState = 0x00010000UL;
55*433d6423SLionel Sambuc static DEV_STRUCT *dev;
56*433d6423SLionel Sambuc
57*433d6423SLionel Sambuc
58*433d6423SLionel Sambuc #if 0
59*433d6423SLionel Sambuc static void set_src_sync_state (int state)
60*433d6423SLionel Sambuc {
61*433d6423SLionel Sambuc if (state < 0)
62*433d6423SLionel Sambuc SrcSyncState = SRC_UNSYNCED;
63*433d6423SLionel Sambuc else {
64*433d6423SLionel Sambuc SrcSyncState = (u32_t)state << 16;
65*433d6423SLionel Sambuc SrcSyncState &= 0x00070000Ul;
66*433d6423SLionel Sambuc }
67*433d6423SLionel Sambuc }
68*433d6423SLionel Sambuc #endif
69*433d6423SLionel Sambuc
70*433d6423SLionel Sambuc
AC97_write(const DEV_STRUCT * pCC,u16_t wAddr,u16_t wData)71*433d6423SLionel Sambuc static int AC97_write (const DEV_STRUCT * pCC, u16_t wAddr, u16_t wData)
72*433d6423SLionel Sambuc {
73*433d6423SLionel Sambuc u32_t dtemp, i;
74*433d6423SLionel Sambuc u16_t wBaseAddr = pCC->base;
75*433d6423SLionel Sambuc
76*433d6423SLionel Sambuc /* wait for WIP bit (Write In Progress) to go away */
77*433d6423SLionel Sambuc /* remember, register CODEC_READ (0x14)
78*433d6423SLionel Sambuc is a pseudo read-write register */
79*433d6423SLionel Sambuc if (WaitBitd (wBaseAddr + CODEC_READ, 30, 0, WIP_TIMEOUT)){
80*433d6423SLionel Sambuc printf("AC97_ERR_WIP_TIMEOUT\n");
81*433d6423SLionel Sambuc return (AC97_ERR_WIP_TIMEOUT);
82*433d6423SLionel Sambuc }
83*433d6423SLionel Sambuc if (SRC_UNSYNCED != SrcSyncState)
84*433d6423SLionel Sambuc {
85*433d6423SLionel Sambuc /* enable SRC state data in SRC mux */
86*433d6423SLionel Sambuc if (WaitBitd (wBaseAddr + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
87*433d6423SLionel Sambuc return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
88*433d6423SLionel Sambuc
89*433d6423SLionel Sambuc /* todo: why are we writing an undefined register? */
90*433d6423SLionel Sambuc dtemp = pci_inl(wBaseAddr + SAMPLE_RATE_CONV);
91*433d6423SLionel Sambuc pci_outl(wBaseAddr + SAMPLE_RATE_CONV, (dtemp & SRC_CTLMASK) |
92*433d6423SLionel Sambuc 0x00010000UL);
93*433d6423SLionel Sambuc
94*433d6423SLionel Sambuc /* wait for a SAFE time to write addr/data and then do it */
95*433d6423SLionel Sambuc /*_disable(); */
96*433d6423SLionel Sambuc for( i = 0; i < 0x1000UL; ++i )
97*433d6423SLionel Sambuc if( (pci_inl(wBaseAddr + SAMPLE_RATE_CONV) & 0x00070000UL) ==
98*433d6423SLionel Sambuc SrcSyncState )
99*433d6423SLionel Sambuc break;
100*433d6423SLionel Sambuc
101*433d6423SLionel Sambuc if (i >= 0x1000UL) {
102*433d6423SLionel Sambuc /* _enable(); */
103*433d6423SLionel Sambuc return (AC97_ERR_SRC_SYNC_TIMEOUT);
104*433d6423SLionel Sambuc }
105*433d6423SLionel Sambuc }
106*433d6423SLionel Sambuc
107*433d6423SLionel Sambuc /* A test for 5880 - prime the PCI data bus */
108*433d6423SLionel Sambuc {
109*433d6423SLionel Sambuc u32_t dat = ((u32_t) wAddr << 16) | wData;
110*433d6423SLionel Sambuc char page = pci_inb(wBaseAddr + MEM_PAGE);
111*433d6423SLionel Sambuc
112*433d6423SLionel Sambuc pci_outl (wBaseAddr + MEM_PAGE, dat);
113*433d6423SLionel Sambuc
114*433d6423SLionel Sambuc /* write addr and data */
115*433d6423SLionel Sambuc pci_outl(wBaseAddr + CODEC_READ, dat);
116*433d6423SLionel Sambuc
117*433d6423SLionel Sambuc pci_outb(wBaseAddr + MEM_PAGE, page); /* restore page reg */
118*433d6423SLionel Sambuc }
119*433d6423SLionel Sambuc
120*433d6423SLionel Sambuc if (SRC_UNSYNCED != SrcSyncState)
121*433d6423SLionel Sambuc {
122*433d6423SLionel Sambuc /* _enable(); */
123*433d6423SLionel Sambuc
124*433d6423SLionel Sambuc /* restore SRC reg */
125*433d6423SLionel Sambuc if (WaitBitd (wBaseAddr + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
126*433d6423SLionel Sambuc return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
127*433d6423SLionel Sambuc
128*433d6423SLionel Sambuc pci_outl(wBaseAddr + SAMPLE_RATE_CONV, dtemp & 0xfff8ffffUL);
129*433d6423SLionel Sambuc }
130*433d6423SLionel Sambuc
131*433d6423SLionel Sambuc return 0;
132*433d6423SLionel Sambuc }
133*433d6423SLionel Sambuc
134*433d6423SLionel Sambuc
135*433d6423SLionel Sambuc #if 0
136*433d6423SLionel Sambuc static int AC97_read (const DEV_STRUCT * pCC, u16_t wAddr, u16_t *data)
137*433d6423SLionel Sambuc {
138*433d6423SLionel Sambuc u32_t dtemp, i;
139*433d6423SLionel Sambuc u16_t base = pCC->base;
140*433d6423SLionel Sambuc
141*433d6423SLionel Sambuc /* wait for WIP to go away */
142*433d6423SLionel Sambuc if (WaitBitd (base + CODEC_READ, 30, 0, WIP_TIMEOUT))
143*433d6423SLionel Sambuc return (AC97_ERR_WIP_TIMEOUT);
144*433d6423SLionel Sambuc
145*433d6423SLionel Sambuc if (SRC_UNSYNCED != SrcSyncState)
146*433d6423SLionel Sambuc {
147*433d6423SLionel Sambuc /* enable SRC state data in SRC mux */
148*433d6423SLionel Sambuc if (WaitBitd (base + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
149*433d6423SLionel Sambuc return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
150*433d6423SLionel Sambuc
151*433d6423SLionel Sambuc dtemp = pci_inl(base + SAMPLE_RATE_CONV);
152*433d6423SLionel Sambuc pci_outl(base + SAMPLE_RATE_CONV, (dtemp & SRC_CTLMASK) |
153*433d6423SLionel Sambuc 0x00010000UL);
154*433d6423SLionel Sambuc
155*433d6423SLionel Sambuc /* wait for a SAFE time to write a read request and then do it */
156*433d6423SLionel Sambuc /* todo: how do we solve the lock() problem? */
157*433d6423SLionel Sambuc /* _disable(); */
158*433d6423SLionel Sambuc for( i = 0; i < 0x1000UL; ++i )
159*433d6423SLionel Sambuc if( (pci_inl(base + SAMPLE_RATE_CONV) & 0x00070000UL) ==
160*433d6423SLionel Sambuc SrcSyncState )
161*433d6423SLionel Sambuc break;
162*433d6423SLionel Sambuc
163*433d6423SLionel Sambuc if (i >= 0x1000UL) {
164*433d6423SLionel Sambuc /*_enable();*/
165*433d6423SLionel Sambuc return (AC97_ERR_SRC_SYNC_TIMEOUT);
166*433d6423SLionel Sambuc }
167*433d6423SLionel Sambuc }
168*433d6423SLionel Sambuc
169*433d6423SLionel Sambuc /* A test for 5880 - prime the PCI data bus */
170*433d6423SLionel Sambuc {
171*433d6423SLionel Sambuc /* set bit 23, this means read in stead of write. */
172*433d6423SLionel Sambuc u32_t dat = ((u32_t) wAddr << 16) | (1UL << 23);
173*433d6423SLionel Sambuc char page = pci_inb(base + MEM_PAGE);
174*433d6423SLionel Sambuc
175*433d6423SLionel Sambuc /* todo: why are we putting data in the mem page register??? */
176*433d6423SLionel Sambuc pci_outl(base + MEM_PAGE, dat);
177*433d6423SLionel Sambuc
178*433d6423SLionel Sambuc /* write addr w/data=0 and assert read request */
179*433d6423SLionel Sambuc pci_outl(base + CODEC_READ, dat);
180*433d6423SLionel Sambuc
181*433d6423SLionel Sambuc pci_outb(base + MEM_PAGE, page); /* restore page reg */
182*433d6423SLionel Sambuc
183*433d6423SLionel Sambuc }
184*433d6423SLionel Sambuc if (SRC_UNSYNCED != SrcSyncState)
185*433d6423SLionel Sambuc {
186*433d6423SLionel Sambuc
187*433d6423SLionel Sambuc /*_enable();*/
188*433d6423SLionel Sambuc
189*433d6423SLionel Sambuc /* restore SRC reg */
190*433d6423SLionel Sambuc if (WaitBitd (base + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
191*433d6423SLionel Sambuc return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
192*433d6423SLionel Sambuc
193*433d6423SLionel Sambuc pci_outl(base + SAMPLE_RATE_CONV, dtemp & 0xfff8ffffUL);
194*433d6423SLionel Sambuc }
195*433d6423SLionel Sambuc
196*433d6423SLionel Sambuc /* now wait for the stinkin' data (DRDY = data ready) */
197*433d6423SLionel Sambuc if (WaitBitd (base + CODEC_READ, 31, 1, DRDY_TIMEOUT))
198*433d6423SLionel Sambuc return (AC97_ERR_DATA_TIMEOUT);
199*433d6423SLionel Sambuc
200*433d6423SLionel Sambuc dtemp = pci_inl(base + CODEC_READ);
201*433d6423SLionel Sambuc
202*433d6423SLionel Sambuc if (data)
203*433d6423SLionel Sambuc *data = (u16_t) dtemp;
204*433d6423SLionel Sambuc
205*433d6423SLionel Sambuc return 0;
206*433d6423SLionel Sambuc }
207*433d6423SLionel Sambuc #endif
208*433d6423SLionel Sambuc
209*433d6423SLionel Sambuc
AC97_write_unsynced(const DEV_STRUCT * pCC,u16_t wAddr,u16_t wData)210*433d6423SLionel Sambuc static int AC97_write_unsynced (const DEV_STRUCT * pCC, u16_t wAddr,
211*433d6423SLionel Sambuc u16_t wData)
212*433d6423SLionel Sambuc {
213*433d6423SLionel Sambuc /* wait for WIP to go away */
214*433d6423SLionel Sambuc if (WaitBitd (pCC->base + CODEC_READ, 30, 0, WIP_TIMEOUT))
215*433d6423SLionel Sambuc return (AC97_ERR_WIP_TIMEOUT);
216*433d6423SLionel Sambuc
217*433d6423SLionel Sambuc /* write addr and data */
218*433d6423SLionel Sambuc pci_outl(pCC->base + CODEC_READ, ((u32_t) wAddr << 16) | wData);
219*433d6423SLionel Sambuc return 0;
220*433d6423SLionel Sambuc }
221*433d6423SLionel Sambuc
222*433d6423SLionel Sambuc
AC97_read_unsynced(const DEV_STRUCT * pCC,u16_t wAddr,u16_t * data)223*433d6423SLionel Sambuc static int AC97_read_unsynced (const DEV_STRUCT * pCC, u16_t wAddr,
224*433d6423SLionel Sambuc u16_t *data)
225*433d6423SLionel Sambuc {
226*433d6423SLionel Sambuc u32_t dtemp;
227*433d6423SLionel Sambuc
228*433d6423SLionel Sambuc /* wait for WIP to go away */
229*433d6423SLionel Sambuc if (WaitBitd (pCC->base + CODEC_READ, 30, 0, WIP_TIMEOUT))
230*433d6423SLionel Sambuc return (AC97_ERR_WIP_TIMEOUT);
231*433d6423SLionel Sambuc
232*433d6423SLionel Sambuc /* write addr w/data=0 and assert read request */
233*433d6423SLionel Sambuc pci_outl(pCC->base + CODEC_READ, ((u32_t) wAddr << 16) | (1UL << 23));
234*433d6423SLionel Sambuc
235*433d6423SLionel Sambuc /* now wait for the stinkin' data (RDY) */
236*433d6423SLionel Sambuc if (WaitBitd (pCC->base + CODEC_READ, 31, 1, DRDY_TIMEOUT))
237*433d6423SLionel Sambuc return (AC97_ERR_DATA_TIMEOUT);
238*433d6423SLionel Sambuc
239*433d6423SLionel Sambuc dtemp = pci_inl(pCC->base + CODEC_READ);
240*433d6423SLionel Sambuc
241*433d6423SLionel Sambuc if (data)
242*433d6423SLionel Sambuc *data = (u16_t) dtemp;
243*433d6423SLionel Sambuc
244*433d6423SLionel Sambuc return 0;
245*433d6423SLionel Sambuc }
246*433d6423SLionel Sambuc
247*433d6423SLionel Sambuc
AC97_init(DEV_STRUCT * pCC)248*433d6423SLionel Sambuc int AC97_init( DEV_STRUCT * pCC ) {
249*433d6423SLionel Sambuc int retVal;
250*433d6423SLionel Sambuc /* All powerdown modes: off */
251*433d6423SLionel Sambuc
252*433d6423SLionel Sambuc dev = pCC;
253*433d6423SLionel Sambuc
254*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_POWERDOWN_CONTROL_STAT, 0x0000U);
255*433d6423SLionel Sambuc if (OK != retVal)
256*433d6423SLionel Sambuc return (retVal);
257*433d6423SLionel Sambuc
258*433d6423SLionel Sambuc /* Mute Line Out & set to 0dB attenuation */
259*433d6423SLionel Sambuc
260*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_MASTER_VOLUME, 0x0000U);
261*433d6423SLionel Sambuc if (OK != retVal)
262*433d6423SLionel Sambuc return (retVal);
263*433d6423SLionel Sambuc
264*433d6423SLionel Sambuc
265*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_MONO_VOLUME, 0x8000U);
266*433d6423SLionel Sambuc if (OK != retVal)
267*433d6423SLionel Sambuc return (retVal);
268*433d6423SLionel Sambuc
269*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_PHONE_VOLUME, 0x8008U);
270*433d6423SLionel Sambuc if (OK != retVal)
271*433d6423SLionel Sambuc return (retVal);
272*433d6423SLionel Sambuc
273*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_MIC_VOLUME, 0x0008U);
274*433d6423SLionel Sambuc if (OK != retVal)
275*433d6423SLionel Sambuc return (retVal);
276*433d6423SLionel Sambuc
277*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_LINE_IN_VOLUME, 0x0808U);
278*433d6423SLionel Sambuc if (OK != retVal)
279*433d6423SLionel Sambuc return (retVal);
280*433d6423SLionel Sambuc
281*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_CD_VOLUME, 0x0808U);
282*433d6423SLionel Sambuc if (OK != retVal)
283*433d6423SLionel Sambuc return (retVal);
284*433d6423SLionel Sambuc
285*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_AUX_IN_VOLUME, 0x0808U);
286*433d6423SLionel Sambuc if (OK != retVal)
287*433d6423SLionel Sambuc return (retVal);
288*433d6423SLionel Sambuc
289*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_PCM_OUT_VOLUME, 0x0808U);
290*433d6423SLionel Sambuc if (OK != retVal)
291*433d6423SLionel Sambuc return (retVal);
292*433d6423SLionel Sambuc
293*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_RECORD_GAIN_VOLUME, 0x0000U);
294*433d6423SLionel Sambuc if (OK != retVal)
295*433d6423SLionel Sambuc return (retVal);
296*433d6423SLionel Sambuc
297*433d6423SLionel Sambuc /* Connect Line In to ADC */
298*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_RECORD_SELECT, 0x0404U);
299*433d6423SLionel Sambuc if (OK != retVal)
300*433d6423SLionel Sambuc return (retVal);
301*433d6423SLionel Sambuc
302*433d6423SLionel Sambuc retVal = AC97_write (pCC, AC97_GENERAL_PURPOSE, 0x0000U);
303*433d6423SLionel Sambuc if (OK != retVal)
304*433d6423SLionel Sambuc return (retVal);
305*433d6423SLionel Sambuc
306*433d6423SLionel Sambuc set_nice_volume();
307*433d6423SLionel Sambuc
308*433d6423SLionel Sambuc return OK;
309*433d6423SLionel Sambuc }
310*433d6423SLionel Sambuc
311*433d6423SLionel Sambuc
set_nice_volume(void)312*433d6423SLionel Sambuc static void set_nice_volume(void) {
313*433d6423SLionel Sambuc /* goofy code to set the DAC1 channel to an audibe volume
314*433d6423SLionel Sambuc to be able to test it without using the mixer */
315*433d6423SLionel Sambuc
316*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_PCM_OUT_VOLUME, 0x0808);/* the higher,
317*433d6423SLionel Sambuc the softer */
318*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_MASTER_VOLUME, 0x0101);
319*433d6423SLionel Sambuc AC97_write_unsynced(dev, 0x38, 0); /* not crucial */
320*433d6423SLionel Sambuc
321*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_LINE_IN_VOLUME, 0x0303);
322*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_MIC_VOLUME, 0x005f);
323*433d6423SLionel Sambuc
324*433d6423SLionel Sambuc /* mute record gain */
325*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_RECORD_GAIN_VOLUME, 0xFFFF);
326*433d6423SLionel Sambuc /* mic record volume high */
327*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_RECORD_GAIN_MIC_VOL, 0x0000);
328*433d6423SLionel Sambuc
329*433d6423SLionel Sambuc /* Also, to be able test recording without mixer:
330*433d6423SLionel Sambuc select ONE channel as input below. */
331*433d6423SLionel Sambuc
332*433d6423SLionel Sambuc /* select LINE IN */
333*433d6423SLionel Sambuc /*AC97_write_unsynced(dev, AC97_RECORD_SELECT, 0x0404);*/
334*433d6423SLionel Sambuc
335*433d6423SLionel Sambuc /* select MIC */
336*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_RECORD_SELECT, 0x0000);
337*433d6423SLionel Sambuc
338*433d6423SLionel Sambuc /* unmute record gain */
339*433d6423SLionel Sambuc AC97_write_unsynced(dev, AC97_RECORD_GAIN_VOLUME, 0x0000);
340*433d6423SLionel Sambuc }
341*433d6423SLionel Sambuc
342*433d6423SLionel Sambuc
get_volume(u8_t * left,u8_t * right,int cmd)343*433d6423SLionel Sambuc static int get_volume(u8_t *left, u8_t *right, int cmd) {
344*433d6423SLionel Sambuc u16_t value = 0;
345*433d6423SLionel Sambuc
346*433d6423SLionel Sambuc AC97_read_unsynced(dev, (u16_t)cmd, &value);
347*433d6423SLionel Sambuc
348*433d6423SLionel Sambuc *left = value>>8;
349*433d6423SLionel Sambuc *right = value&0xff;
350*433d6423SLionel Sambuc
351*433d6423SLionel Sambuc return OK;
352*433d6423SLionel Sambuc }
353*433d6423SLionel Sambuc
354*433d6423SLionel Sambuc
set_volume(int left,int right,int cmd)355*433d6423SLionel Sambuc static int set_volume(int left, int right, int cmd) {
356*433d6423SLionel Sambuc u16_t waarde;
357*433d6423SLionel Sambuc
358*433d6423SLionel Sambuc waarde = (u16_t)((left<<8)|right);
359*433d6423SLionel Sambuc
360*433d6423SLionel Sambuc AC97_write_unsynced(dev, (u16_t)cmd, waarde);
361*433d6423SLionel Sambuc
362*433d6423SLionel Sambuc return OK;
363*433d6423SLionel Sambuc }
364*433d6423SLionel Sambuc
365*433d6423SLionel Sambuc
convert(int left_in,int right_in,int max_in,int * left_out,int * right_out,int max_out,int swaplr)366*433d6423SLionel Sambuc void convert(int left_in, int right_in, int max_in, int *left_out,
367*433d6423SLionel Sambuc int *right_out, int max_out, int swaplr) {
368*433d6423SLionel Sambuc int tmp;
369*433d6423SLionel Sambuc
370*433d6423SLionel Sambuc if(left_in < 0) left_in = 0;
371*433d6423SLionel Sambuc else if(left_in > max_in) left_in = max_in;
372*433d6423SLionel Sambuc if(right_in < 0) right_in = 0;
373*433d6423SLionel Sambuc else if(right_in > max_in) right_in = max_in;
374*433d6423SLionel Sambuc
375*433d6423SLionel Sambuc if (swaplr) {
376*433d6423SLionel Sambuc tmp = left_in;
377*433d6423SLionel Sambuc left_in = right_in;
378*433d6423SLionel Sambuc right_in = tmp;
379*433d6423SLionel Sambuc }
380*433d6423SLionel Sambuc
381*433d6423SLionel Sambuc *left_out = (-left_in) + max_out;
382*433d6423SLionel Sambuc *right_out = (-right_in) + max_out;
383*433d6423SLionel Sambuc }
384*433d6423SLionel Sambuc
385*433d6423SLionel Sambuc
AC97_get_set_volume(struct volume_level * level,int flag)386*433d6423SLionel Sambuc int AC97_get_set_volume(struct volume_level *level, int flag) {
387*433d6423SLionel Sambuc if (flag) {
388*433d6423SLionel Sambuc return AC97_set_volume(level);
389*433d6423SLionel Sambuc }
390*433d6423SLionel Sambuc else {
391*433d6423SLionel Sambuc return AC97_get_volume(level);
392*433d6423SLionel Sambuc }
393*433d6423SLionel Sambuc }
394*433d6423SLionel Sambuc
395*433d6423SLionel Sambuc
AC97_get_volume(struct volume_level * level)396*433d6423SLionel Sambuc static int AC97_get_volume(struct volume_level *level) {
397*433d6423SLionel Sambuc int cmd;
398*433d6423SLionel Sambuc u8_t left;
399*433d6423SLionel Sambuc u8_t right;
400*433d6423SLionel Sambuc
401*433d6423SLionel Sambuc switch(level->device) {
402*433d6423SLionel Sambuc case Master:
403*433d6423SLionel Sambuc cmd = AC97_MASTER_VOLUME;
404*433d6423SLionel Sambuc get_volume(&left, &right, cmd);
405*433d6423SLionel Sambuc convert(left, right, 0x1f,
406*433d6423SLionel Sambuc &(level->left), &(level->right), 0x1f, 0);
407*433d6423SLionel Sambuc break;
408*433d6423SLionel Sambuc case Dac:
409*433d6423SLionel Sambuc return EINVAL;
410*433d6423SLionel Sambuc break;
411*433d6423SLionel Sambuc case Fm:
412*433d6423SLionel Sambuc cmd = AC97_PCM_OUT_VOLUME;
413*433d6423SLionel Sambuc get_volume(&left, &right, cmd);
414*433d6423SLionel Sambuc convert(left, right, 0x1f,
415*433d6423SLionel Sambuc &(level->left), &(level->right), 0x1f, 0);
416*433d6423SLionel Sambuc break;
417*433d6423SLionel Sambuc case Cd:
418*433d6423SLionel Sambuc cmd = AC97_CD_VOLUME;
419*433d6423SLionel Sambuc get_volume(&left, &right, cmd);
420*433d6423SLionel Sambuc convert(left, right, 0x1f,
421*433d6423SLionel Sambuc &(level->left), &(level->right), 0x1f, 0);
422*433d6423SLionel Sambuc break;
423*433d6423SLionel Sambuc case Line:
424*433d6423SLionel Sambuc cmd = AC97_LINE_IN_VOLUME;
425*433d6423SLionel Sambuc get_volume(&left, &right, cmd);
426*433d6423SLionel Sambuc convert(left, right, 0x1f,
427*433d6423SLionel Sambuc &(level->left), &(level->right), 0x1f, 0);
428*433d6423SLionel Sambuc break;
429*433d6423SLionel Sambuc case Mic:
430*433d6423SLionel Sambuc cmd = AC97_MIC_VOLUME;
431*433d6423SLionel Sambuc get_volume(&left, &right, cmd);
432*433d6423SLionel Sambuc convert(left, right, 0x1f,
433*433d6423SLionel Sambuc &(level->left), &(level->right), 0x1f, 1);
434*433d6423SLionel Sambuc break;
435*433d6423SLionel Sambuc case Speaker:
436*433d6423SLionel Sambuc return EINVAL;
437*433d6423SLionel Sambuc case Treble:
438*433d6423SLionel Sambuc cmd = AC97_MASTER_TONE;
439*433d6423SLionel Sambuc get_volume(&left, &right, cmd);
440*433d6423SLionel Sambuc convert(left, right, 0xf,
441*433d6423SLionel Sambuc &(level->left), &(level->right), 0xf, 1);
442*433d6423SLionel Sambuc break;
443*433d6423SLionel Sambuc case Bass:
444*433d6423SLionel Sambuc cmd = AC97_MASTER_TONE;
445*433d6423SLionel Sambuc get_volume(&left, &right, cmd);
446*433d6423SLionel Sambuc convert(left, right, 0xf,
447*433d6423SLionel Sambuc &(level->left), &(level->right), 0xf, 1);
448*433d6423SLionel Sambuc break;
449*433d6423SLionel Sambuc default:
450*433d6423SLionel Sambuc return EINVAL;
451*433d6423SLionel Sambuc }
452*433d6423SLionel Sambuc return OK;
453*433d6423SLionel Sambuc }
454*433d6423SLionel Sambuc
455*433d6423SLionel Sambuc
AC97_set_volume(const struct volume_level * level)456*433d6423SLionel Sambuc static int AC97_set_volume(const struct volume_level *level) {
457*433d6423SLionel Sambuc int cmd;
458*433d6423SLionel Sambuc int left;
459*433d6423SLionel Sambuc int right;
460*433d6423SLionel Sambuc
461*433d6423SLionel Sambuc switch(level->device) {
462*433d6423SLionel Sambuc case Master:
463*433d6423SLionel Sambuc cmd = AC97_MASTER_VOLUME;
464*433d6423SLionel Sambuc convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
465*433d6423SLionel Sambuc break;
466*433d6423SLionel Sambuc case Dac:
467*433d6423SLionel Sambuc return EINVAL;
468*433d6423SLionel Sambuc case Fm:
469*433d6423SLionel Sambuc cmd = AC97_PCM_OUT_VOLUME;
470*433d6423SLionel Sambuc convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
471*433d6423SLionel Sambuc break;
472*433d6423SLionel Sambuc case Cd:
473*433d6423SLionel Sambuc cmd = AC97_CD_VOLUME;
474*433d6423SLionel Sambuc convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
475*433d6423SLionel Sambuc break;
476*433d6423SLionel Sambuc case Line:
477*433d6423SLionel Sambuc cmd = AC97_LINE_IN_VOLUME;
478*433d6423SLionel Sambuc convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
479*433d6423SLionel Sambuc break;
480*433d6423SLionel Sambuc case Mic:
481*433d6423SLionel Sambuc cmd = AC97_MIC_VOLUME;
482*433d6423SLionel Sambuc convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 1);
483*433d6423SLionel Sambuc break;
484*433d6423SLionel Sambuc case Speaker:
485*433d6423SLionel Sambuc return EINVAL;
486*433d6423SLionel Sambuc case Treble:
487*433d6423SLionel Sambuc return EINVAL;
488*433d6423SLionel Sambuc case Bass:
489*433d6423SLionel Sambuc return EINVAL;
490*433d6423SLionel Sambuc default:
491*433d6423SLionel Sambuc return EINVAL;
492*433d6423SLionel Sambuc }
493*433d6423SLionel Sambuc set_volume(left, right, cmd);
494*433d6423SLionel Sambuc
495*433d6423SLionel Sambuc return OK;
496*433d6423SLionel Sambuc }
497