xref: /minix3/minix/drivers/audio/es1371/SRC.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include "SRC.h"
2*433d6423SLionel Sambuc 
3*433d6423SLionel Sambuc #define SRC_RATE        48000U
4*433d6423SLionel Sambuc #define reg(n) DSP->base + n
5*433d6423SLionel Sambuc 
6*433d6423SLionel Sambuc 
SRCInit(DEV_STRUCT * DSP)7*433d6423SLionel Sambuc int SRCInit ( DEV_STRUCT * DSP )
8*433d6423SLionel Sambuc {
9*433d6423SLionel Sambuc     u32_t   i;
10*433d6423SLionel Sambuc     int     retVal;
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc     /* Clear all SRC RAM then init - keep SRC disabled until done */
13*433d6423SLionel Sambuc     if (WaitBitd (reg(CONC_dSRCIO_OFF), SRC_BUSY_BIT, 0, 1000))
14*433d6423SLionel Sambuc         return (SRC_ERR_NOT_BUSY_TIMEOUT);
15*433d6423SLionel Sambuc 
16*433d6423SLionel Sambuc     pci_outl(reg(CONC_dSRCIO_OFF), SRC_DISABLE);
17*433d6423SLionel Sambuc 
18*433d6423SLionel Sambuc     for( i = 0; i < 0x80; ++i )
19*433d6423SLionel Sambuc         if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, (u16_t)i, 0U)))
20*433d6423SLionel Sambuc             return (retVal);
21*433d6423SLionel Sambuc 
22*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_SYNTH_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
23*433d6423SLionel Sambuc         return (retVal);
24*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_SYNTH_BASE + SRC_INT_REGS_OFF, 16 << 10)))
25*433d6423SLionel Sambuc         return (retVal);
26*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_DAC_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
27*433d6423SLionel Sambuc         return (retVal);
28*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_DAC_BASE + SRC_INT_REGS_OFF, 16 << 10)))
29*433d6423SLionel Sambuc         return (retVal);
30*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_SYNTH_LVOL, 1 << 12)))
31*433d6423SLionel Sambuc         return (retVal);
32*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_SYNTH_RVOL, 1 << 12)))
33*433d6423SLionel Sambuc         return (retVal);
34*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_DAC_LVOL, 1 << 12)))
35*433d6423SLionel Sambuc         return (retVal);
36*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_DAC_RVOL, 1 << 12)))
37*433d6423SLionel Sambuc         return (retVal);
38*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_ADC_LVOL, 1 << 12)))
39*433d6423SLionel Sambuc         return (retVal);
40*433d6423SLionel Sambuc     if (SRC_SUCCESS != (retVal = SRCRegWrite(DSP, SRC_ADC_RVOL, 1 << 12)))
41*433d6423SLionel Sambuc         return (retVal);
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc     /* default some rates */
44*433d6423SLionel Sambuc     SRCSetRate(DSP, SRC_SYNTH_BASE, SRC_RATE);
45*433d6423SLionel Sambuc     SRCSetRate(DSP, SRC_DAC_BASE,   SRC_RATE);
46*433d6423SLionel Sambuc     SRCSetRate(DSP, SRC_ADC_BASE,   SRC_RATE);
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc     /* now enable the whole deal */
49*433d6423SLionel Sambuc     if (WaitBitd (reg(CONC_dSRCIO_OFF), SRC_BUSY_BIT, 0, 1000))
50*433d6423SLionel Sambuc         return (SRC_ERR_NOT_BUSY_TIMEOUT);
51*433d6423SLionel Sambuc 
52*433d6423SLionel Sambuc     pci_outl(reg(CONC_dSRCIO_OFF), 0UL);
53*433d6423SLionel Sambuc 
54*433d6423SLionel Sambuc     return 0;
55*433d6423SLionel Sambuc }
56*433d6423SLionel Sambuc 
57*433d6423SLionel Sambuc 
SRCRegRead(DEV_STRUCT * DSP,u16_t reg,u16_t * data)58*433d6423SLionel Sambuc int SRCRegRead(DEV_STRUCT * DSP, u16_t reg, u16_t *data)
59*433d6423SLionel Sambuc {
60*433d6423SLionel Sambuc     u32_t dtemp;
61*433d6423SLionel Sambuc 
62*433d6423SLionel Sambuc     /* wait for ready */
63*433d6423SLionel Sambuc     if (WaitBitd (reg(CONC_dSRCIO_OFF), SRC_BUSY_BIT, 0, 1000))
64*433d6423SLionel Sambuc         return (SRC_ERR_NOT_BUSY_TIMEOUT);
65*433d6423SLionel Sambuc 
66*433d6423SLionel Sambuc     dtemp = pci_inl(reg(CONC_dSRCIO_OFF));
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc     /* assert a read request */
69*433d6423SLionel Sambuc     pci_outl(reg(CONC_dSRCIO_OFF),
70*433d6423SLionel Sambuc             (dtemp & SRC_CTLMASK) | ((u32_t) reg << 25));
71*433d6423SLionel Sambuc 
72*433d6423SLionel Sambuc     /* now wait for the data */
73*433d6423SLionel Sambuc     if (WaitBitd (reg(CONC_dSRCIO_OFF), SRC_BUSY_BIT, 0, 1000))
74*433d6423SLionel Sambuc         return (SRC_ERR_NOT_BUSY_TIMEOUT);
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc     if (NULL != data)
77*433d6423SLionel Sambuc         *data = (u16_t) pci_inl(reg(CONC_dSRCIO_OFF));
78*433d6423SLionel Sambuc 
79*433d6423SLionel Sambuc     return 0;
80*433d6423SLionel Sambuc }
81*433d6423SLionel Sambuc 
82*433d6423SLionel Sambuc 
SRCRegWrite(DEV_STRUCT * DSP,u16_t reg,u16_t val)83*433d6423SLionel Sambuc int SRCRegWrite(DEV_STRUCT * DSP, u16_t reg, u16_t val)
84*433d6423SLionel Sambuc {
85*433d6423SLionel Sambuc     u32_t dtemp;
86*433d6423SLionel Sambuc 
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc     /* wait for ready */
89*433d6423SLionel Sambuc     if (WaitBitd (reg(CONC_dSRCIO_OFF), SRC_BUSY_BIT, 0, 1000))
90*433d6423SLionel Sambuc         return (SRC_ERR_NOT_BUSY_TIMEOUT);
91*433d6423SLionel Sambuc 
92*433d6423SLionel Sambuc     dtemp = pci_inl(reg(CONC_dSRCIO_OFF));
93*433d6423SLionel Sambuc 
94*433d6423SLionel Sambuc     /* assert the write request */
95*433d6423SLionel Sambuc     pci_outl(reg(CONC_dSRCIO_OFF),
96*433d6423SLionel Sambuc             (dtemp & SRC_CTLMASK) | SRC_WENABLE | ((u32_t) reg << 25) | val);
97*433d6423SLionel Sambuc 
98*433d6423SLionel Sambuc     return 0;
99*433d6423SLionel Sambuc }
100*433d6423SLionel Sambuc 
101*433d6423SLionel Sambuc 
SRCSetRate(DEV_STRUCT * DSP,char base,u16_t rate)102*433d6423SLionel Sambuc void SRCSetRate(DEV_STRUCT * DSP, char base, u16_t rate)
103*433d6423SLionel Sambuc {
104*433d6423SLionel Sambuc   u32_t    freq, dtemp, i;
105*433d6423SLionel Sambuc   u16_t     N, truncM, truncStart, wtemp;
106*433d6423SLionel Sambuc 
107*433d6423SLionel Sambuc 
108*433d6423SLionel Sambuc   if( base != SRC_ADC_BASE )
109*433d6423SLionel Sambuc   {
110*433d6423SLionel Sambuc       /* freeze the channel */
111*433d6423SLionel Sambuc       dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
112*433d6423SLionel Sambuc       for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
113*433d6423SLionel Sambuc           if( !(pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_BUSY) )
114*433d6423SLionel Sambuc               break;
115*433d6423SLionel Sambuc       pci_outl(reg(CONC_dSRCIO_OFF),
116*433d6423SLionel Sambuc               (pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_CTLMASK) |
117*433d6423SLionel Sambuc               dtemp);
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc       /* calculate new frequency and write it - preserve accum */
120*433d6423SLionel Sambuc       /* please don't try to understand. */
121*433d6423SLionel Sambuc       freq = ((u32_t) rate << 16) / 3000U;
122*433d6423SLionel Sambuc       SRCRegRead(DSP, base + SRC_INT_REGS_OFF, &wtemp);
123*433d6423SLionel Sambuc 
124*433d6423SLionel Sambuc       SRCRegWrite(DSP, base + SRC_INT_REGS_OFF,
125*433d6423SLionel Sambuc               (wtemp & 0x00ffU) |
126*433d6423SLionel Sambuc               (u16_t) (freq >> 6) & 0xfc00);
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc       SRCRegWrite(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
129*433d6423SLionel Sambuc 
130*433d6423SLionel Sambuc       /* un-freeze the channel */
131*433d6423SLionel Sambuc       dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
132*433d6423SLionel Sambuc       for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
133*433d6423SLionel Sambuc           if( !(pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_BUSY) )
134*433d6423SLionel Sambuc               break;
135*433d6423SLionel Sambuc       pci_outl(reg(CONC_dSRCIO_OFF),
136*433d6423SLionel Sambuc               (pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_CTLMASK) &
137*433d6423SLionel Sambuc               ~dtemp);
138*433d6423SLionel Sambuc   }
139*433d6423SLionel Sambuc   else /* setting ADC rate */
140*433d6423SLionel Sambuc   {
141*433d6423SLionel Sambuc     /* freeze the channel */
142*433d6423SLionel Sambuc     for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
143*433d6423SLionel Sambuc         if( !(pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_BUSY) )
144*433d6423SLionel Sambuc             break;
145*433d6423SLionel Sambuc     pci_outl(reg(CONC_dSRCIO_OFF),
146*433d6423SLionel Sambuc             (pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_CTLMASK) |
147*433d6423SLionel Sambuc             SRC_ADCFREEZE);
148*433d6423SLionel Sambuc 
149*433d6423SLionel Sambuc 
150*433d6423SLionel Sambuc 
151*433d6423SLionel Sambuc     /* derive oversample ratio */
152*433d6423SLionel Sambuc     N = rate/3000U;
153*433d6423SLionel Sambuc     if( N == 15 || N == 13 || N == 11 || N == 9 )
154*433d6423SLionel Sambuc         --N;
155*433d6423SLionel Sambuc     SRCRegWrite(DSP, SRC_ADC_LVOL, N << 8);
156*433d6423SLionel Sambuc     SRCRegWrite(DSP, SRC_ADC_RVOL, N << 8);
157*433d6423SLionel Sambuc 
158*433d6423SLionel Sambuc     /* truncate the filter and write n/trunc_start */
159*433d6423SLionel Sambuc     truncM = (21*N - 1) | 1;
160*433d6423SLionel Sambuc     if( rate >= 24000U )
161*433d6423SLionel Sambuc     {
162*433d6423SLionel Sambuc         if( truncM > 239 )
163*433d6423SLionel Sambuc             truncM = 239;
164*433d6423SLionel Sambuc         truncStart = (239 - truncM) >> 1;
165*433d6423SLionel Sambuc         SRCRegWrite(DSP, base + SRC_TRUNC_N_OFF,
166*433d6423SLionel Sambuc                 (truncStart << 9) | (N << 4));
167*433d6423SLionel Sambuc     }
168*433d6423SLionel Sambuc     else
169*433d6423SLionel Sambuc     {
170*433d6423SLionel Sambuc         if( truncM > 119 )
171*433d6423SLionel Sambuc             truncM = 119;
172*433d6423SLionel Sambuc         truncStart = (119 - truncM) >> 1;
173*433d6423SLionel Sambuc         SRCRegWrite(DSP, base + SRC_TRUNC_N_OFF,
174*433d6423SLionel Sambuc                 0x8000U | (truncStart << 9) | (N << 4));
175*433d6423SLionel Sambuc     }
176*433d6423SLionel Sambuc 
177*433d6423SLionel Sambuc     /* calculate new frequency and write it - preserve accum */
178*433d6423SLionel Sambuc     freq = ((48000UL << 16) / rate) * N;
179*433d6423SLionel Sambuc     SRCRegRead(DSP, base + SRC_INT_REGS_OFF, &wtemp);
180*433d6423SLionel Sambuc     SRCRegWrite(DSP, base + SRC_INT_REGS_OFF,
181*433d6423SLionel Sambuc             (wtemp & 0x00ffU) |
182*433d6423SLionel Sambuc             (u16_t) (freq >> 6) & 0xfc00);
183*433d6423SLionel Sambuc     SRCRegWrite(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
184*433d6423SLionel Sambuc 
185*433d6423SLionel Sambuc     /* un-freeze the channel */
186*433d6423SLionel Sambuc     for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
187*433d6423SLionel Sambuc         if( !(pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_BUSY) )
188*433d6423SLionel Sambuc             break;
189*433d6423SLionel Sambuc     pci_outl(reg(CONC_dSRCIO_OFF),
190*433d6423SLionel Sambuc             (pci_inl(reg(CONC_dSRCIO_OFF)) & SRC_CTLMASK) &
191*433d6423SLionel Sambuc             ~SRC_ADCFREEZE);
192*433d6423SLionel Sambuc   }
193*433d6423SLionel Sambuc   return;
194*433d6423SLionel Sambuc }
195*433d6423SLionel Sambuc 
196*433d6423SLionel Sambuc 
197