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