xref: /minix3/minix/drivers/audio/es1371/sample_rate_converter.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include "sample_rate_converter.h"
2*433d6423SLionel Sambuc 
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc 
5*433d6423SLionel Sambuc 
6*433d6423SLionel Sambuc #define SRC_RATE        48000U
7*433d6423SLionel Sambuc #define reg(n) DSP->base + n
8*433d6423SLionel Sambuc 
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc /* register/base and control equates for the SRC RAM */
11*433d6423SLionel Sambuc #define SRC_SYNTH_FIFO      0x00
12*433d6423SLionel Sambuc #define SRC_DAC_FIFO        0x20
13*433d6423SLionel Sambuc #define SRC_ADC_FIFO        0x40
14*433d6423SLionel Sambuc 
15*433d6423SLionel Sambuc #define SRC_SYNTH_LVOL      0x7c
16*433d6423SLionel Sambuc #define SRC_SYNTH_RVOL      0x7d
17*433d6423SLionel Sambuc #define SRC_DAC_LVOL        0x7e
18*433d6423SLionel Sambuc #define SRC_DAC_RVOL        0x7f
19*433d6423SLionel Sambuc #define SRC_ADC_LVOL        0x6c
20*433d6423SLionel Sambuc #define SRC_ADC_RVOL        0x6d
21*433d6423SLionel Sambuc 
22*433d6423SLionel Sambuc #define SRC_TRUNC_N_OFF     0x00
23*433d6423SLionel Sambuc #define SRC_INT_REGS_OFF    0x01
24*433d6423SLionel Sambuc #define SRC_ACCUM_FRAC_OFF  0x02
25*433d6423SLionel Sambuc #define SRC_VFREQ_FRAC_OFF  0x03
26*433d6423SLionel Sambuc 
27*433d6423SLionel Sambuc /* miscellaneous control defines */
28*433d6423SLionel Sambuc #define SRC_IOPOLL_COUNT    0x1000UL
29*433d6423SLionel Sambuc 
30*433d6423SLionel Sambuc #define SRC_SYNTHFREEZE     (1UL << 21)
31*433d6423SLionel Sambuc #define SRC_DACFREEZE       (1UL << 20)
32*433d6423SLionel Sambuc #define SRC_ADCFREEZE       (1UL << 19)
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc 
35*433d6423SLionel Sambuc 
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc static int src_reg_read(const DEV_STRUCT * DSP, u16_t reg, u16_t
38*433d6423SLionel Sambuc 	*data);
39*433d6423SLionel Sambuc static int src_reg_write(const DEV_STRUCT * DSP, u16_t reg, u16_t val);
40*433d6423SLionel Sambuc 
41*433d6423SLionel Sambuc 
src_init(DEV_STRUCT * DSP)42*433d6423SLionel Sambuc int src_init ( DEV_STRUCT * DSP ) {
43*433d6423SLionel Sambuc 	u32_t   i;
44*433d6423SLionel Sambuc 	int     retVal;
45*433d6423SLionel Sambuc 
46*433d6423SLionel Sambuc 	/* Clear all SRC RAM then init - keep SRC disabled until done */
47*433d6423SLionel Sambuc 	/* Wait till SRC_RAM_BUSY is 0 */
48*433d6423SLionel Sambuc 	if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
49*433d6423SLionel Sambuc 		return (SRC_ERR_NOT_BUSY_TIMEOUT);
50*433d6423SLionel Sambuc 
51*433d6423SLionel Sambuc 	pci_outl(reg(SAMPLE_RATE_CONV), SRC_DISABLE);
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc 	/* from the opensound system driver, no idea where the specification is */
54*433d6423SLionel Sambuc 	/* there are indeed 7 bits for the addresses of the SRC */
55*433d6423SLionel Sambuc 	for( i = 0; i < 0x80; ++i ) {
56*433d6423SLionel Sambuc 		if (SRC_SUCCESS != (retVal = src_reg_write(DSP, (u16_t)i, 0U)))
57*433d6423SLionel Sambuc 			return (retVal);
58*433d6423SLionel Sambuc 	}
59*433d6423SLionel Sambuc 
60*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
61*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_SYNTH_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
62*433d6423SLionel Sambuc 		return (retVal);
63*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal = src_reg_write(DSP,
64*433d6423SLionel Sambuc 					SRC_SYNTH_BASE + SRC_INT_REGS_OFF, 16 << 10)))
65*433d6423SLionel Sambuc 		return (retVal);
66*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
67*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_DAC_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
68*433d6423SLionel Sambuc 		return (retVal);
69*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
70*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_DAC_BASE + SRC_INT_REGS_OFF, 16 << 10)))
71*433d6423SLionel Sambuc 		return (retVal);
72*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
73*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_SYNTH_LVOL, 1 << 12)))
74*433d6423SLionel Sambuc 		return (retVal);
75*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
76*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_SYNTH_RVOL, 1 << 12)))
77*433d6423SLionel Sambuc 		return (retVal);
78*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
79*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_DAC_LVOL, 1 << 12)))
80*433d6423SLionel Sambuc 		return (retVal);
81*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
82*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_DAC_RVOL, 1 << 12)))
83*433d6423SLionel Sambuc 		return (retVal);
84*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
85*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_ADC_LVOL, 1 << 12)))
86*433d6423SLionel Sambuc 		return (retVal);
87*433d6423SLionel Sambuc 	if (SRC_SUCCESS != (retVal =
88*433d6423SLionel Sambuc 				src_reg_write(DSP, SRC_ADC_RVOL, 1 << 12)))
89*433d6423SLionel Sambuc 		return (retVal);
90*433d6423SLionel Sambuc 
91*433d6423SLionel Sambuc 	/* default some rates */
92*433d6423SLionel Sambuc 	src_set_rate(DSP, SRC_SYNTH_BASE, SRC_RATE);
93*433d6423SLionel Sambuc 	src_set_rate(DSP, SRC_DAC_BASE,   SRC_RATE);
94*433d6423SLionel Sambuc 	src_set_rate(DSP, SRC_ADC_BASE,   SRC_RATE);
95*433d6423SLionel Sambuc 
96*433d6423SLionel Sambuc 	/* now enable the whole deal */
97*433d6423SLionel Sambuc 	if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
98*433d6423SLionel Sambuc 		return (SRC_ERR_NOT_BUSY_TIMEOUT);
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc 	pci_outl(reg(SAMPLE_RATE_CONV), 0UL);
101*433d6423SLionel Sambuc 
102*433d6423SLionel Sambuc 	return 0;
103*433d6423SLionel Sambuc }
104*433d6423SLionel Sambuc 
105*433d6423SLionel Sambuc 
src_reg_read(const DEV_STRUCT * DSP,u16_t reg,u16_t * data)106*433d6423SLionel Sambuc static int src_reg_read(const DEV_STRUCT * DSP, u16_t reg, u16_t *data) {
107*433d6423SLionel Sambuc 	u32_t dtemp;
108*433d6423SLionel Sambuc 
109*433d6423SLionel Sambuc 	/* wait for ready */
110*433d6423SLionel Sambuc 	if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
111*433d6423SLionel Sambuc 		return (SRC_ERR_NOT_BUSY_TIMEOUT);
112*433d6423SLionel Sambuc 
113*433d6423SLionel Sambuc 	dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
114*433d6423SLionel Sambuc 
115*433d6423SLionel Sambuc 	/* assert a read request */
116*433d6423SLionel Sambuc 	/*pci_outl(reg(SAMPLE_RATE_CONV),
117*433d6423SLionel Sambuc 	  (dtemp & SRC_CTLMASK) | ((u32_t) reg << 25));*/
118*433d6423SLionel Sambuc 	pci_outl(reg(SAMPLE_RATE_CONV), (dtemp &
119*433d6423SLionel Sambuc 				(DIS_REC|DIS_P2|DIS_P1|SRC_DISABLE)) | ((u32_t) reg << 25));
120*433d6423SLionel Sambuc 
121*433d6423SLionel Sambuc 	/* now wait for the data */
122*433d6423SLionel Sambuc 	if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
123*433d6423SLionel Sambuc 		return (SRC_ERR_NOT_BUSY_TIMEOUT);
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc 	if (NULL != data)
126*433d6423SLionel Sambuc 		*data = (u16_t) pci_inl(reg(SAMPLE_RATE_CONV));
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc 	return 0;
129*433d6423SLionel Sambuc }
130*433d6423SLionel Sambuc 
131*433d6423SLionel Sambuc 
src_reg_write(const DEV_STRUCT * DSP,u16_t reg,u16_t val)132*433d6423SLionel Sambuc static int src_reg_write(const DEV_STRUCT * DSP, u16_t reg, u16_t val) {
133*433d6423SLionel Sambuc 	u32_t dtemp;
134*433d6423SLionel Sambuc 
135*433d6423SLionel Sambuc 	/* wait for ready */
136*433d6423SLionel Sambuc 	if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
137*433d6423SLionel Sambuc 		return (SRC_ERR_NOT_BUSY_TIMEOUT);
138*433d6423SLionel Sambuc 
139*433d6423SLionel Sambuc 	dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
140*433d6423SLionel Sambuc 
141*433d6423SLionel Sambuc 	/* assert the write request */
142*433d6423SLionel Sambuc 	pci_outl(reg(SAMPLE_RATE_CONV),
143*433d6423SLionel Sambuc 	  (dtemp & SRC_CTLMASK) | SRC_RAM_WE | ((u32_t) reg << 25) | val);
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc 	return 0;
146*433d6423SLionel Sambuc }
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc 
src_set_rate(const DEV_STRUCT * DSP,char base,u16_t rate)149*433d6423SLionel Sambuc void src_set_rate(const DEV_STRUCT * DSP, char base, u16_t rate) {
150*433d6423SLionel Sambuc 	u32_t    freq, dtemp, i;
151*433d6423SLionel Sambuc 	u16_t     N, truncM, truncStart, wtemp;
152*433d6423SLionel Sambuc 
153*433d6423SLionel Sambuc 
154*433d6423SLionel Sambuc 	if( base != SRC_ADC_BASE )
155*433d6423SLionel Sambuc 	{
156*433d6423SLionel Sambuc 		/* freeze the channel */
157*433d6423SLionel Sambuc 		dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
158*433d6423SLionel Sambuc 		for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
159*433d6423SLionel Sambuc 			if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
160*433d6423SLionel Sambuc 				break;
161*433d6423SLionel Sambuc 		pci_outl(reg(SAMPLE_RATE_CONV),
162*433d6423SLionel Sambuc 				(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
163*433d6423SLionel Sambuc 				dtemp);
164*433d6423SLionel Sambuc 
165*433d6423SLionel Sambuc 		/* calculate new frequency and write it - preserve accum */
166*433d6423SLionel Sambuc 		/* please don't try to understand. */
167*433d6423SLionel Sambuc 		freq = ((u32_t) rate << 16) / 3000U;
168*433d6423SLionel Sambuc 		src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
169*433d6423SLionel Sambuc 
170*433d6423SLionel Sambuc 		src_reg_write(DSP, base + SRC_INT_REGS_OFF,
171*433d6423SLionel Sambuc 				(wtemp & 0x00ffU) |
172*433d6423SLionel Sambuc 				((u16_t) (freq >> 6) & 0xfc00));
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc 		src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
175*433d6423SLionel Sambuc 
176*433d6423SLionel Sambuc 		/* un-freeze the channel */
177*433d6423SLionel Sambuc 		dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
178*433d6423SLionel Sambuc 		for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
179*433d6423SLionel Sambuc 			if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
180*433d6423SLionel Sambuc 				break;
181*433d6423SLionel Sambuc 		pci_outl(reg(SAMPLE_RATE_CONV),
182*433d6423SLionel Sambuc 				(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
183*433d6423SLionel Sambuc 				~dtemp);
184*433d6423SLionel Sambuc 	}
185*433d6423SLionel Sambuc 	else /* setting ADC rate */
186*433d6423SLionel Sambuc 	{
187*433d6423SLionel Sambuc 		/* freeze the channel */
188*433d6423SLionel Sambuc 		for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
189*433d6423SLionel Sambuc 			if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
190*433d6423SLionel Sambuc 				break;
191*433d6423SLionel Sambuc 		pci_outl(reg(SAMPLE_RATE_CONV),
192*433d6423SLionel Sambuc 				(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
193*433d6423SLionel Sambuc 				SRC_ADCFREEZE);
194*433d6423SLionel Sambuc 
195*433d6423SLionel Sambuc 
196*433d6423SLionel Sambuc 
197*433d6423SLionel Sambuc 		/* derive oversample ratio */
198*433d6423SLionel Sambuc 		N = rate/3000U;
199*433d6423SLionel Sambuc 		if( N == 15 || N == 13 || N == 11 || N == 9 )
200*433d6423SLionel Sambuc 			--N;
201*433d6423SLionel Sambuc 		src_reg_write(DSP, SRC_ADC_LVOL, N << 8);
202*433d6423SLionel Sambuc 		src_reg_write(DSP, SRC_ADC_RVOL, N << 8);
203*433d6423SLionel Sambuc 
204*433d6423SLionel Sambuc 		/* truncate the filter and write n/trunc_start */
205*433d6423SLionel Sambuc 		truncM = (21*N - 1) | 1;
206*433d6423SLionel Sambuc 		if( rate >= 24000U )
207*433d6423SLionel Sambuc 		{
208*433d6423SLionel Sambuc 			if( truncM > 239 )
209*433d6423SLionel Sambuc 				truncM = 239;
210*433d6423SLionel Sambuc 			truncStart = (239 - truncM) >> 1;
211*433d6423SLionel Sambuc 			src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
212*433d6423SLionel Sambuc 					(truncStart << 9) | (N << 4));
213*433d6423SLionel Sambuc 		}
214*433d6423SLionel Sambuc 		else
215*433d6423SLionel Sambuc 		{
216*433d6423SLionel Sambuc 			if( truncM > 119 )
217*433d6423SLionel Sambuc 				truncM = 119;
218*433d6423SLionel Sambuc 			truncStart = (119 - truncM) >> 1;
219*433d6423SLionel Sambuc 			src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
220*433d6423SLionel Sambuc 					0x8000U | (truncStart << 9) | (N << 4));
221*433d6423SLionel Sambuc 		}
222*433d6423SLionel Sambuc 
223*433d6423SLionel Sambuc 		/* calculate new frequency and write it - preserve accum */
224*433d6423SLionel Sambuc 		freq = ((48000UL << 16) / rate) * N;
225*433d6423SLionel Sambuc 		src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
226*433d6423SLionel Sambuc 		src_reg_write(DSP, base + SRC_INT_REGS_OFF,
227*433d6423SLionel Sambuc 				(wtemp & 0x00ffU) |
228*433d6423SLionel Sambuc 				((u16_t) (freq >> 6) & 0xfc00));
229*433d6423SLionel Sambuc 		src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
230*433d6423SLionel Sambuc 
231*433d6423SLionel Sambuc 		/* un-freeze the channel */
232*433d6423SLionel Sambuc 		for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
233*433d6423SLionel Sambuc 			if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
234*433d6423SLionel Sambuc 				break;
235*433d6423SLionel Sambuc 		pci_outl(reg(SAMPLE_RATE_CONV),
236*433d6423SLionel Sambuc 				(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
237*433d6423SLionel Sambuc 				~SRC_ADCFREEZE);
238*433d6423SLionel Sambuc 	}
239*433d6423SLionel Sambuc 	return;
240*433d6423SLionel Sambuc }
241