xref: /minix3/minix/drivers/audio/es1371/codec.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include "codec.h"
2*433d6423SLionel Sambuc 
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc /* Timeouts in milliseconds */
5*433d6423SLionel Sambuc #define WIP_TIMEOUT     250UL
6*433d6423SLionel Sambuc #define DRDY_TIMEOUT    250UL
7*433d6423SLionel Sambuc 
8*433d6423SLionel Sambuc /* The default SRC syncronization state number is 1.  This state occurs
9*433d6423SLionel Sambuc    just after de-assertion of SYNC.  This is supposed to be the safest
10*433d6423SLionel Sambuc    state for accessing the codec with an ES1371 Rev 1.  Later versions
11*433d6423SLionel Sambuc    of the chip allegedly don't require syncronization.  Be very careful
12*433d6423SLionel Sambuc    if you change this ! */
13*433d6423SLionel Sambuc 
14*433d6423SLionel Sambuc #define SRC_UNSYNCED 0xffffffffUL
15*433d6423SLionel Sambuc static u32_t SrcSyncState = 0x00010000UL;
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc 
CodecSetSrcSyncState(int state)18*433d6423SLionel Sambuc void CodecSetSrcSyncState (int state)
19*433d6423SLionel Sambuc {
20*433d6423SLionel Sambuc     if (state < 0)
21*433d6423SLionel Sambuc         SrcSyncState = SRC_UNSYNCED;
22*433d6423SLionel Sambuc     else {
23*433d6423SLionel Sambuc         SrcSyncState = (u32_t)state << 16;
24*433d6423SLionel Sambuc         SrcSyncState &= 0x00070000Ul;
25*433d6423SLionel Sambuc     }
26*433d6423SLionel Sambuc }
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc 
CodecWrite(DEV_STRUCT * pCC,u16_t wAddr,u16_t wData)29*433d6423SLionel Sambuc int CodecWrite (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData)
30*433d6423SLionel Sambuc {
31*433d6423SLionel Sambuc u32_t dtemp, i;
32*433d6423SLionel Sambuc u16_t  wBaseAddr = pCC->base;
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc     /* wait for WIP bit (Write In Progress) to go away */
35*433d6423SLionel Sambuc     /* remember, register CONC_dCODECCTL_OFF (0x14)
36*433d6423SLionel Sambuc        is a pseudo read-write register */
37*433d6423SLionel Sambuc     if (WaitBitd (wBaseAddr + CONC_dCODECCTL_OFF, 30, 0, WIP_TIMEOUT)){
38*433d6423SLionel Sambuc         printf("CODEC_ERR_WIP_TIMEOUT\n");
39*433d6423SLionel Sambuc         return (CODEC_ERR_WIP_TIMEOUT);
40*433d6423SLionel Sambuc     }
41*433d6423SLionel Sambuc     if (SRC_UNSYNCED != SrcSyncState)
42*433d6423SLionel Sambuc     {
43*433d6423SLionel Sambuc         /* enable SRC state data in SRC mux */
44*433d6423SLionel Sambuc         if (WaitBitd (wBaseAddr + CONC_dSRCIO_OFF, SRC_BUSY_BIT, 0, 1000))
45*433d6423SLionel Sambuc             return (CODEC_ERR_SRC_NOT_BUSY_TIMEOUT);
46*433d6423SLionel Sambuc 
47*433d6423SLionel Sambuc         /* todo: why are we writing an undefined register? */
48*433d6423SLionel Sambuc         dtemp = pci_inl(wBaseAddr + CONC_dSRCIO_OFF);
49*433d6423SLionel Sambuc         pci_outl(wBaseAddr + CONC_dSRCIO_OFF, (dtemp & SRC_CTLMASK) |
50*433d6423SLionel Sambuc                 0x00010000UL);
51*433d6423SLionel Sambuc 
52*433d6423SLionel Sambuc         /* wait for a SAFE time to write addr/data and then do it */
53*433d6423SLionel Sambuc         /*_disable(); */
54*433d6423SLionel Sambuc         for( i = 0; i < 0x1000UL; ++i )
55*433d6423SLionel Sambuc             if( (pci_inl(wBaseAddr + CONC_dSRCIO_OFF) & 0x00070000UL) ==
56*433d6423SLionel Sambuc                     SrcSyncState )
57*433d6423SLionel Sambuc             break;
58*433d6423SLionel Sambuc 
59*433d6423SLionel Sambuc         if (i >= 0x1000UL) {
60*433d6423SLionel Sambuc             /* _enable(); */
61*433d6423SLionel Sambuc             return (CODEC_ERR_SRC_SYNC_TIMEOUT);
62*433d6423SLionel Sambuc         }
63*433d6423SLionel Sambuc     }
64*433d6423SLionel Sambuc 
65*433d6423SLionel Sambuc     /* A test for 5880 - prime the PCI data bus */
66*433d6423SLionel Sambuc     {
67*433d6423SLionel Sambuc         u32_t dat = ((u32_t) wAddr << 16) | wData;
68*433d6423SLionel Sambuc         char page = pci_inb(wBaseAddr + CONC_bMEMPAGE_OFF);
69*433d6423SLionel Sambuc 
70*433d6423SLionel Sambuc         pci_outl (wBaseAddr + CONC_bMEMPAGE_OFF, dat);
71*433d6423SLionel Sambuc 
72*433d6423SLionel Sambuc         /* write addr and data */
73*433d6423SLionel Sambuc         pci_outl(wBaseAddr + CONC_dCODECCTL_OFF, dat);
74*433d6423SLionel Sambuc 
75*433d6423SLionel Sambuc         pci_outb(wBaseAddr + CONC_bMEMPAGE_OFF, page);  /* restore page reg */
76*433d6423SLionel Sambuc     }
77*433d6423SLionel Sambuc 
78*433d6423SLionel Sambuc     if (SRC_UNSYNCED != SrcSyncState)
79*433d6423SLionel Sambuc     {
80*433d6423SLionel Sambuc          /* _enable(); */
81*433d6423SLionel Sambuc 
82*433d6423SLionel Sambuc         /* restore SRC reg */
83*433d6423SLionel Sambuc         if (WaitBitd (wBaseAddr + CONC_dSRCIO_OFF, SRC_BUSY_BIT, 0, 1000))
84*433d6423SLionel Sambuc             return (CODEC_ERR_SRC_NOT_BUSY_TIMEOUT);
85*433d6423SLionel Sambuc 
86*433d6423SLionel Sambuc         pci_outl(wBaseAddr + CONC_dSRCIO_OFF, dtemp & 0xfff8ffffUL);
87*433d6423SLionel Sambuc     }
88*433d6423SLionel Sambuc 
89*433d6423SLionel Sambuc     return 0;
90*433d6423SLionel Sambuc }
91*433d6423SLionel Sambuc 
CodecRead(DEV_STRUCT * pCC,u16_t wAddr,u16_t * data)92*433d6423SLionel Sambuc int CodecRead (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data)
93*433d6423SLionel Sambuc {
94*433d6423SLionel Sambuc u32_t dtemp, i;
95*433d6423SLionel Sambuc u16_t  base = pCC->base;
96*433d6423SLionel Sambuc 
97*433d6423SLionel Sambuc     /* wait for WIP to go away */
98*433d6423SLionel Sambuc     if (WaitBitd (base + CONC_dCODECCTL_OFF, 30, 0, WIP_TIMEOUT))
99*433d6423SLionel Sambuc         return (CODEC_ERR_WIP_TIMEOUT);
100*433d6423SLionel Sambuc 
101*433d6423SLionel Sambuc     if (SRC_UNSYNCED != SrcSyncState)
102*433d6423SLionel Sambuc     {
103*433d6423SLionel Sambuc         /* enable SRC state data in SRC mux */
104*433d6423SLionel Sambuc         if (WaitBitd (base + CONC_dSRCIO_OFF, SRC_BUSY_BIT, 0, 1000))
105*433d6423SLionel Sambuc             return (CODEC_ERR_SRC_NOT_BUSY_TIMEOUT);
106*433d6423SLionel Sambuc 
107*433d6423SLionel Sambuc         dtemp = pci_inl(base + CONC_dSRCIO_OFF);
108*433d6423SLionel Sambuc         pci_outl(base + CONC_dSRCIO_OFF, (dtemp & SRC_CTLMASK) |
109*433d6423SLionel Sambuc                 0x00010000UL);
110*433d6423SLionel Sambuc 
111*433d6423SLionel Sambuc         /* wait for a SAFE time to write a read request and then do it */
112*433d6423SLionel Sambuc         /* todo: how do we solve the lock() problem? */
113*433d6423SLionel Sambuc         /* _disable(); */
114*433d6423SLionel Sambuc         for( i = 0; i < 0x1000UL; ++i )
115*433d6423SLionel Sambuc             if( (pci_inl(base + CONC_dSRCIO_OFF) & 0x00070000UL) ==
116*433d6423SLionel Sambuc                     SrcSyncState )
117*433d6423SLionel Sambuc             break;
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc         if (i >= 0x1000UL) {
120*433d6423SLionel Sambuc             /*_enable();*/
121*433d6423SLionel Sambuc             return (CODEC_ERR_SRC_SYNC_TIMEOUT);
122*433d6423SLionel Sambuc         }
123*433d6423SLionel Sambuc     }
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc     /* A test for 5880 - prime the PCI data bus */
126*433d6423SLionel Sambuc     {
127*433d6423SLionel Sambuc         /* set bit 23, this means read in stead of write. */
128*433d6423SLionel Sambuc         u32_t dat = ((u32_t) wAddr << 16) | (1UL << 23);
129*433d6423SLionel Sambuc         char page = pci_inb(base + CONC_bMEMPAGE_OFF);
130*433d6423SLionel Sambuc 
131*433d6423SLionel Sambuc         /* todo: why are we putting data in the mem page register??? */
132*433d6423SLionel Sambuc         pci_outl(base + CONC_bMEMPAGE_OFF, dat);
133*433d6423SLionel Sambuc 
134*433d6423SLionel Sambuc         /* write addr w/data=0 and assert read request */
135*433d6423SLionel Sambuc         pci_outl(base + CONC_dCODECCTL_OFF, dat);
136*433d6423SLionel Sambuc 
137*433d6423SLionel Sambuc         pci_outb(base + CONC_bMEMPAGE_OFF, page);  /* restore page reg */
138*433d6423SLionel Sambuc 
139*433d6423SLionel Sambuc     }
140*433d6423SLionel Sambuc     if (SRC_UNSYNCED != SrcSyncState)
141*433d6423SLionel Sambuc     {
142*433d6423SLionel Sambuc 
143*433d6423SLionel Sambuc         /*_enable();*/
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc         /* restore SRC reg */
146*433d6423SLionel Sambuc         if (WaitBitd (base + CONC_dSRCIO_OFF, SRC_BUSY_BIT, 0, 1000))
147*433d6423SLionel Sambuc             return (CODEC_ERR_SRC_NOT_BUSY_TIMEOUT);
148*433d6423SLionel Sambuc 
149*433d6423SLionel Sambuc         pci_outl(base + CONC_dSRCIO_OFF, dtemp & 0xfff8ffffUL);
150*433d6423SLionel Sambuc     }
151*433d6423SLionel Sambuc 
152*433d6423SLionel Sambuc     /* now wait for the stinkin' data (DRDY = data ready) */
153*433d6423SLionel Sambuc     if (WaitBitd (base + CONC_dCODECCTL_OFF, 31, 1, DRDY_TIMEOUT))
154*433d6423SLionel Sambuc         return (CODEC_ERR_DATA_TIMEOUT);
155*433d6423SLionel Sambuc 
156*433d6423SLionel Sambuc     dtemp = pci_inl(base + CONC_dCODECCTL_OFF);
157*433d6423SLionel Sambuc 
158*433d6423SLionel Sambuc     if (data)
159*433d6423SLionel Sambuc         *data = (u16_t) dtemp;
160*433d6423SLionel Sambuc 
161*433d6423SLionel Sambuc     return 0;
162*433d6423SLionel Sambuc }
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc 
CodecWriteUnsynced(DEV_STRUCT * pCC,u16_t wAddr,u16_t wData)165*433d6423SLionel Sambuc int CodecWriteUnsynced (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData)
166*433d6423SLionel Sambuc {
167*433d6423SLionel Sambuc     /* wait for WIP to go away */
168*433d6423SLionel Sambuc     if (WaitBitd (pCC->base + CONC_dCODECCTL_OFF, 30, 0, WIP_TIMEOUT))
169*433d6423SLionel Sambuc         return (CODEC_ERR_WIP_TIMEOUT);
170*433d6423SLionel Sambuc 
171*433d6423SLionel Sambuc     /* write addr and data */
172*433d6423SLionel Sambuc     pci_outl(pCC->base + CONC_dCODECCTL_OFF, ((u32_t) wAddr << 16) | wData);
173*433d6423SLionel Sambuc     return 0;
174*433d6423SLionel Sambuc }
175*433d6423SLionel Sambuc 
176*433d6423SLionel Sambuc 
CodecReadUnsynced(DEV_STRUCT * pCC,u16_t wAddr,u16_t * data)177*433d6423SLionel Sambuc int CodecReadUnsynced (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data)
178*433d6423SLionel Sambuc {
179*433d6423SLionel Sambuc u32_t dtemp;
180*433d6423SLionel Sambuc 
181*433d6423SLionel Sambuc     /* wait for WIP to go away */
182*433d6423SLionel Sambuc     if (WaitBitd (pCC->base + CONC_dCODECCTL_OFF, 30, 0, WIP_TIMEOUT))
183*433d6423SLionel Sambuc         return (CODEC_ERR_WIP_TIMEOUT);
184*433d6423SLionel Sambuc 
185*433d6423SLionel Sambuc     /* write addr w/data=0 and assert read request */
186*433d6423SLionel Sambuc     pci_outl(pCC->base + CONC_dCODECCTL_OFF, ((u32_t) wAddr << 16) | (1UL << 23));
187*433d6423SLionel Sambuc 
188*433d6423SLionel Sambuc     /* now wait for the stinkin' data (RDY) */
189*433d6423SLionel Sambuc     if (WaitBitd (pCC->base + CONC_dCODECCTL_OFF, 31, 1, DRDY_TIMEOUT))
190*433d6423SLionel Sambuc         return (CODEC_ERR_DATA_TIMEOUT);
191*433d6423SLionel Sambuc 
192*433d6423SLionel Sambuc     dtemp = pci_inl(pCC->base + CONC_dCODECCTL_OFF);
193*433d6423SLionel Sambuc 
194*433d6423SLionel Sambuc     if (data)
195*433d6423SLionel Sambuc         *data = (u16_t) dtemp;
196*433d6423SLionel Sambuc 
197*433d6423SLionel Sambuc     return 0;
198*433d6423SLionel Sambuc }
199*433d6423SLionel Sambuc 
CODECInit(DEV_STRUCT * pCC)200*433d6423SLionel Sambuc int CODECInit( DEV_STRUCT * pCC )
201*433d6423SLionel Sambuc {
202*433d6423SLionel Sambuc int retVal;
203*433d6423SLionel Sambuc     /* All powerdown modes: off */
204*433d6423SLionel Sambuc 
205*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_POWERDOWN_CONTROL_STAT,  0x0000U);
206*433d6423SLionel Sambuc     if (OK != retVal)
207*433d6423SLionel Sambuc         return (retVal);
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc     /* Mute Line Out & set to 0dB attenuation */
210*433d6423SLionel Sambuc 
211*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_MASTER_VOLUME, 0x0000U);
212*433d6423SLionel Sambuc     if (OK != retVal)
213*433d6423SLionel Sambuc         return (retVal);
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc 
216*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_MONO_VOLUME,   0x8000U);
217*433d6423SLionel Sambuc     if (OK != retVal)
218*433d6423SLionel Sambuc         return (retVal);
219*433d6423SLionel Sambuc 
220*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_PHONE_VOLUME,  0x8008U);
221*433d6423SLionel Sambuc     if (OK != retVal)
222*433d6423SLionel Sambuc         return (retVal);
223*433d6423SLionel Sambuc 
224*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_MIC_VOLUME,    0x0008U);
225*433d6423SLionel Sambuc     if (OK != retVal)
226*433d6423SLionel Sambuc         return (retVal);
227*433d6423SLionel Sambuc 
228*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_LINE_IN_VOLUME,   0x0808U);
229*433d6423SLionel Sambuc     if (OK != retVal)
230*433d6423SLionel Sambuc         return (retVal);
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_CD_VOLUME,     0x0808U);
233*433d6423SLionel Sambuc     if (OK != retVal)
234*433d6423SLionel Sambuc         return (retVal);
235*433d6423SLionel Sambuc 
236*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_AUX_IN_VOLUME,    0x0808U);
237*433d6423SLionel Sambuc     if (OK != retVal)
238*433d6423SLionel Sambuc         return (retVal);
239*433d6423SLionel Sambuc 
240*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_PCM_OUT_VOLUME,    0x0808U);
241*433d6423SLionel Sambuc     if (OK != retVal)
242*433d6423SLionel Sambuc         return (retVal);
243*433d6423SLionel Sambuc 
244*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_RECORD_GAIN_VOLUME, 0x0000U);
245*433d6423SLionel Sambuc     if (OK != retVal)
246*433d6423SLionel Sambuc         return (retVal);
247*433d6423SLionel Sambuc 
248*433d6423SLionel Sambuc     /* Connect Line In to ADC */
249*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_RECORD_SELECT, 0x0404U);
250*433d6423SLionel Sambuc     if (OK != retVal)
251*433d6423SLionel Sambuc         return (retVal);
252*433d6423SLionel Sambuc 
253*433d6423SLionel Sambuc     retVal = CodecWrite (pCC, AC97_GENERAL_PURPOSE, 0x0000U);
254*433d6423SLionel Sambuc     if (OK != retVal)
255*433d6423SLionel Sambuc         return (retVal);
256*433d6423SLionel Sambuc 
257*433d6423SLionel Sambuc     return OK;
258*433d6423SLionel Sambuc }
259*433d6423SLionel Sambuc 
260*433d6423SLionel Sambuc 
261*433d6423SLionel Sambuc 
262*433d6423SLionel Sambuc 
263*433d6423SLionel Sambuc 
264*433d6423SLionel Sambuc 
265