]>
Commit | Line | Data |
---|---|---|
79fa88f3 WD |
1 | /* |
2 | * CODEC | |
3 | */ | |
4 | ||
5 | #include <common.h> | |
6 | #include <post.h> | |
7 | ||
8 | #include "mpc8xx.h" | |
9 | ||
10 | /***********************************************/ | |
11 | ||
12 | #define MAX_DUSLIC 4 | |
13 | ||
14 | #define NUM_CHANNELS 2 | |
15 | #define MAX_SLICS (MAX_DUSLIC * NUM_CHANNELS) | |
16 | ||
17 | /***********************************************/ | |
18 | ||
19 | #define SOP_READ_CH_0 0xC4 /* Read SOP Register for Channel A */ | |
20 | #define SOP_READ_CH_1 0xCC /* Read SOP Register for Channel B */ | |
21 | #define SOP_WRITE_CH_0 0x44 /* Write SOP Register for Channel A */ | |
22 | #define SOP_WRITE_CH_1 0x4C /* Write SOP Register for Channel B */ | |
23 | ||
24 | #define COP_READ_CH_0 0xC5 | |
25 | #define COP_READ_CH_1 0xCD | |
26 | #define COP_WRITE_CH_0 0x45 | |
27 | #define COP_WRITE_CH_1 0x4D | |
28 | ||
29 | #define POP_READ_CH_0 0xC6 | |
30 | #define POP_READ_CH_1 0xCE | |
31 | #define POP_WRITE_CH_0 0x46 | |
32 | #define POP_WRITE_CH_1 0x4E | |
33 | ||
34 | #define RST_CMD_DUSLIC_CHIP 0x40 /* OR 0x48 */ | |
35 | #define RST_CMD_DUSLIC_CH_A 0x41 | |
36 | #define RST_CMD_DUSLIC_CH_B 0x49 | |
37 | ||
38 | #define PCM_RESYNC_CMD_CH_A 0x42 | |
39 | #define PCM_RESYNC_CMD_CH_B 0x4A | |
40 | ||
1eaeb58e WD |
41 | #define ACTIVE_HOOK_LEV_4 0 |
42 | #define ACTIVE_HOOK_LEV_12 1 | |
79fa88f3 WD |
43 | |
44 | #define SLIC_P_NORMAL 0x01 | |
45 | ||
46 | /************************************************/ | |
47 | ||
48 | #define CODSP_WR 0x00 | |
49 | #define CODSP_RD 0x80 | |
50 | #define CODSP_OP 0x40 | |
51 | #define CODSP_ADR(x) (((unsigned char)(x) & 7) << 3) | |
52 | #define CODSP_M(x) ((unsigned char)(x) & 7) | |
53 | #define CODSP_CMD(x) ((unsigned char)(x) & 7) | |
54 | ||
55 | /************************************************/ | |
56 | ||
57 | /* command indication ops */ | |
58 | #define CODSP_M_SLEEP_PWRDN 7 | |
59 | #define CODSP_M_PWRDN_HIZ 0 | |
60 | #define CODSP_M_ANY_ACT 2 | |
61 | #define CODSP_M_RING 5 | |
62 | #define CODSP_M_ACT_MET 6 | |
63 | #define CODSP_M_GND_START 4 | |
64 | #define CODSP_M_RING_PAUSE 1 | |
65 | ||
66 | /* single byte commands */ | |
67 | #define CODSP_CMD_SOFT_RESET CODSP_CMD(0) | |
68 | #define CODSP_CMD_RESET_CH CODSP_CMD(1) | |
69 | #define CODSP_CMD_RESYNC CODSP_CMD(2) | |
70 | ||
71 | /* two byte commands */ | |
72 | #define CODSP_CMD_SOP CODSP_CMD(4) | |
73 | #define CODSP_CMD_COP CODSP_CMD(5) | |
74 | #define CODSP_CMD_POP CODSP_CMD(6) | |
75 | ||
76 | /************************************************/ | |
77 | ||
78 | /* read as 4-bytes */ | |
79 | #define CODSP_INTREG_INT_CH 0x80000000 | |
80 | #define CODSP_INTREG_HOOK 0x40000000 | |
81 | #define CODSP_INTREG_GNDK 0x20000000 | |
82 | #define CODSP_INTREG_GNDP 0x10000000 | |
83 | #define CODSP_INTREG_ICON 0x08000000 | |
84 | #define CODSP_INTREG_VRTLIM 0x04000000 | |
85 | #define CODSP_INTREG_OTEMP 0x02000000 | |
86 | #define CODSP_INTREG_SYNC_FAIL 0x01000000 | |
87 | #define CODSP_INTREG_LM_THRES 0x00800000 | |
88 | #define CODSP_INTREG_READY 0x00400000 | |
89 | #define CODSP_INTREG_RSTAT 0x00200000 | |
90 | #define CODSP_INTREG_LM_OK 0x00100000 | |
91 | #define CODSP_INTREG_IO4_DU 0x00080000 | |
92 | #define CODSP_INTREG_IO3_DU 0x00040000 | |
93 | #define CODSP_INTREG_IO2_DU 0x00020000 | |
94 | #define CODSP_INTREG_IO1_DU 0x00010000 | |
95 | #define CODSP_INTREG_DTMF_OK 0x00008000 | |
96 | #define CODSP_INTREG_DTMF_KEY4 0x00004000 | |
97 | #define CODSP_INTREG_DTMF_KEY3 0x00002000 | |
98 | #define CODSP_INTREG_DTMF_KEY2 0x00001000 | |
99 | #define CODSP_INTREG_DTMF_KEY1 0x00000800 | |
100 | #define CODSP_INTREG_DTMF_KEY0 0x00000400 | |
101 | #define CODSP_INTREG_UTDR_OK 0x00000200 | |
102 | #define CODSP_INTREG_UTDX_OK 0x00000100 | |
103 | #define CODSP_INTREG_EDSP_FAIL 0x00000080 | |
104 | #define CODSP_INTREG_CIS_BOF 0x00000008 | |
105 | #define CODSP_INTREG_CIS_BUF 0x00000004 | |
106 | #define CODSP_INTREG_CIS_REQ 0x00000002 | |
107 | #define CODSP_INTREG_CIS_ACT 0x00000001 | |
108 | ||
109 | /************************************************/ | |
110 | ||
111 | /* ======== SOP REG ADDRESSES =======*/ | |
112 | ||
113 | #define REVISION_ADDR 0x00 | |
114 | #define PCMC1_ADDR 0x05 | |
115 | #define XCR_ADDR 0x06 | |
116 | #define INTREG1_ADDR 0x07 | |
117 | #define INTREG2_ADDR 0x08 | |
118 | #define INTREG3_ADDR 0x09 | |
119 | #define INTREG4_ADDR 0x0A | |
120 | #define LMRES1_ADDR 0x0D | |
121 | #define MASK_ADDR 0x11 | |
122 | #define IOCTL3_ADDR 0x14 | |
123 | #define BCR1_ADDR 0x15 | |
124 | #define BCR2_ADDR 0x16 | |
125 | #define BCR3_ADDR 0x17 | |
126 | #define BCR4_ADDR 0x18 | |
127 | #define BCR5_ADDR 0x19 | |
128 | #define DSCR_ADDR 0x1A | |
129 | #define LMCR1_ADDR 0x1C | |
130 | #define LMCR2_ADDR 0x1D | |
131 | #define LMCR3_ADDR 0x1E | |
132 | #define OFR1_ADDR 0x1F | |
133 | #define PCMR1_ADDR 0x21 | |
134 | #define PCMX1_ADDR 0x25 | |
135 | #define TSTR3_ADDR 0x2B | |
136 | #define TSTR4_ADDR 0x2C | |
137 | #define TSTR5_ADDR 0x2D | |
138 | ||
139 | /* ========= POP REG ADDRESSES ========*/ | |
140 | ||
141 | #define CIS_DAT_ADDR 0x00 | |
142 | ||
1eaeb58e WD |
143 | #define LEC_LEN_ADDR 0x3A |
144 | #define LEC_POWR_ADDR 0x3B | |
145 | #define LEC_DELP_ADDR 0x3C | |
146 | #define LEC_DELQ_ADDR 0x3D | |
147 | #define LEC_GAIN_XI_ADDR 0x3E | |
148 | #define LEC_GAIN_RI_ADDR 0x3F | |
149 | #define LEC_GAIN_XO_ADDR 0x40 | |
150 | #define LEC_RES_1_ADDR 0x41 | |
79fa88f3 WD |
151 | #define LEC_RES_2_ADDR 0x42 |
152 | ||
1eaeb58e | 153 | #define NLP_POW_LPF_ADDR 0x30 |
79fa88f3 WD |
154 | #define NLP_POW_LPS_ADDR 0x31 |
155 | #define NLP_BN_LEV_X_ADDR 0x32 | |
156 | #define NLP_BN_LEV_R_ADDR 0x33 | |
157 | #define NLP_BN_INC_ADDR 0x34 | |
158 | #define NLP_BN_DEC_ADDR 0x35 | |
159 | #define NLP_BN_MAX_ADDR 0x36 | |
160 | #define NLP_BN_ADJ_ADDR 0x37 | |
161 | #define NLP_RE_MIN_ERLL_ADDR 0x38 | |
162 | #define NLP_RE_EST_ERLL_ADDR 0x39 | |
163 | #define NLP_SD_LEV_X_ADDR 0x3A | |
164 | #define NLP_SD_LEV_R_ADDR 0x3B | |
165 | #define NLP_SD_LEV_BN_ADDR 0x3C | |
166 | #define NLP_SD_LEV_RE_ADDR 0x3D | |
167 | #define NLP_SD_OT_DT_ADDR 0x3E | |
168 | #define NLP_ERL_LIN_LP_ADDR 0x3F | |
169 | #define NLP_ERL_LEC_LP_ADDR 0x40 | |
170 | #define NLP_CT_LEV_RE_ADDR 0x41 | |
171 | #define NLP_CTRL_ADDR 0x42 | |
172 | ||
1eaeb58e WD |
173 | #define UTD_CF_H_ADDR 0x4B |
174 | #define UTD_CF_L_ADDR 0x4C | |
175 | #define UTD_BW_H_ADDR 0x4D | |
176 | #define UTD_BW_L_ADDR 0x4E | |
177 | #define UTD_NLEV_ADDR 0x4F | |
178 | #define UTD_SLEV_H_ADDR 0x50 | |
179 | #define UTD_SLEV_L_ADDR 0x51 | |
180 | #define UTD_DELT_ADDR 0x52 | |
181 | #define UTD_RBRK_ADDR 0x53 | |
182 | #define UTD_RTIME_ADDR 0x54 | |
183 | #define UTD_EBRK_ADDR 0x55 | |
184 | #define UTD_ETIME_ADDR 0x56 | |
79fa88f3 WD |
185 | |
186 | #define DTMF_LEV_ADDR 0x30 | |
187 | #define DTMF_TWI_ADDR 0x31 | |
188 | #define DTMF_NCF_H_ADDR 0x32 | |
189 | #define DTMF_NCF_L_ADDR 0x33 | |
190 | #define DTMF_NBW_H_ADDR 0x34 | |
191 | #define DTMF_NBW_L_ADDR 0x35 | |
192 | #define DTMF_GAIN_ADDR 0x36 | |
193 | #define DTMF_RES1_ADDR 0x37 | |
194 | #define DTMF_RES2_ADDR 0x38 | |
195 | #define DTMF_RES3_ADDR 0x39 | |
196 | ||
197 | #define CIS_LEV_H_ADDR 0x43 | |
198 | #define CIS_LEV_L_ADDR 0x44 | |
199 | #define CIS_BRS_ADDR 0x45 | |
200 | #define CIS_SEIZ_H_ADDR 0x46 | |
201 | #define CIS_SEIZ_L_ADDR 0x47 | |
202 | #define CIS_MARK_H_ADDR 0x48 | |
203 | #define CIS_MARK_L_ADDR 0x49 | |
204 | #define CIS_LEC_MODE_ADDR 0x4A | |
205 | ||
206 | /*=====================================*/ | |
207 | ||
1eaeb58e | 208 | #define HOOK_LEV_ACT_START_ADDR 0x89 |
79fa88f3 WD |
209 | #define RO1_START_ADDR 0x70 |
210 | #define RO2_START_ADDR 0x95 | |
211 | #define RO3_START_ADDR 0x96 | |
212 | ||
213 | #define TG1_FREQ_START_ADDR 0x38 | |
214 | #define TG1_GAIN_START_ADDR 0x39 | |
1eaeb58e | 215 | #define TG1_BANDPASS_START_ADDR 0x3B |
79fa88f3 WD |
216 | #define TG1_BANDPASS_END_ADDR 0x3D |
217 | ||
218 | #define TG2_FREQ_START_ADDR 0x40 | |
219 | #define TG2_GAIN_START_ADDR 0x41 | |
1eaeb58e | 220 | #define TG2_BANDPASS_START_ADDR 0x43 |
79fa88f3 WD |
221 | #define TG2_BANDPASS_END_ADDR 0x45 |
222 | ||
223 | /*====================================*/ | |
224 | ||
1eaeb58e | 225 | #define PCM_HW_B 0x80 |
79fa88f3 | 226 | #define PCM_HW_A 0x00 |
1eaeb58e WD |
227 | #define PCM_TIME_SLOT_0 0x00 /* Byte 0 of PCM Frame (by default is assigned to channel A ) */ |
228 | #define PCM_TIME_SLOT_1 0x01 /* Byte 1 of PCM Frame (by default is assigned to channel B ) */ | |
229 | #define PCM_TIME_SLOT_4 0x04 /* Byte 4 of PCM Frame (Corresponds to B1 of the Second GCI ) */ | |
79fa88f3 WD |
230 | |
231 | #define RX_LEV_ADDR 0x28 | |
232 | #define TX_LEV_ADDR 0x30 | |
1eaeb58e | 233 | #define Ik1_ADDR 0x83 |
79fa88f3 | 234 | |
1eaeb58e WD |
235 | #define AR_ROW 3 /* Is the row (AR Params) of the ac_Coeff array in SMS_CODEC_Defaults struct */ |
236 | #define AX_ROW 6 /* Is the row (AX Params) of the ac_Coeff array in SMS_CODEC_Defaults struct */ | |
237 | #define DCF_ROW 0 /* Is the row (DCF Params) of the dc_Coeff array in SMS_CODEC_Defaults struct */ | |
79fa88f3 WD |
238 | |
239 | /* Mark the start byte of Duslic parameters that we use with configurator */ | |
1eaeb58e | 240 | #define Ik1_START_BYTE 3 |
79fa88f3 WD |
241 | #define RX_LEV_START_BYTE 0 |
242 | #define TX_LEV_START_BYTE 0 | |
243 | ||
244 | /************************************************/ | |
245 | ||
1eaeb58e | 246 | #define INTREG4_CIS_ACT (1 << 0) |
79fa88f3 WD |
247 | |
248 | #define BCR1_SLEEP 0x20 | |
249 | #define BCR1_REVPOL 0x10 | |
250 | #define BCR1_ACTR 0x08 | |
251 | #define BCR1_ACTL 0x04 | |
252 | #define BCR1_SLIC_MASK 0x03 | |
253 | ||
254 | #define BCR2_HARD_POL_REV 0x40 | |
255 | #define BCR2_TTX 0x20 | |
256 | #define BCR2_TTX_12K 0x10 | |
257 | #define BCR2_HIMAN 0x08 | |
258 | #define BCR2_PDOT 0x01 | |
259 | ||
1eaeb58e WD |
260 | #define BCR3_PCMX_EN (1 << 4) |
261 | ||
262 | #define BCR5_DTMF_EN (1 << 0) | |
263 | #define BCR5_DTMF_SRC (1 << 1) | |
264 | #define BCR5_LEC_EN (1 << 2) | |
265 | #define BCR5_LEC_OUT (1 << 3) | |
266 | #define BCR5_CIS_EN (1 << 4) | |
267 | #define BCR5_CIS_AUTO (1 << 5) | |
268 | #define BCR5_UTDX_EN (1 << 6) | |
269 | #define BCR5_UTDR_EN (1 << 7) | |
270 | ||
271 | #define DSCR_TG1_EN (1 << 0) | |
272 | #define DSCR_TG2_EN (1 << 1) | |
273 | #define DSCR_PTG (1 << 2) | |
274 | #define DSCR_COR8 (1 << 3) | |
275 | #define DSCR_DG_KEY(x) (((x) & 0x0F) << 4) | |
276 | ||
277 | #define CIS_LEC_MODE_CIS_V23 (1 << 0) | |
278 | #define CIS_LEC_MODE_CIS_FRM (1 << 1) | |
279 | #define CIS_LEC_MODE_NLP_EN (1 << 2) | |
280 | #define CIS_LEC_MODE_UTDR_SUM (1 << 4) | |
281 | #define CIS_LEC_MODE_UTDX_SUM (1 << 5) | |
79fa88f3 | 282 | #define CIS_LEC_MODE_LEC_FREEZE (1 << 6) |
1eaeb58e | 283 | #define CIS_LEC_MODE_LEC_ADAPT (1 << 7) |
79fa88f3 WD |
284 | |
285 | #define TSTR4_COR_64 (1 << 5) | |
286 | ||
287 | #define TSTR3_AC_DLB_8K (1 << 2) | |
288 | #define TSTR3_AC_DLB_32K (1 << 3) | |
289 | #define TSTR3_AC_DLB_4M (1 << 5) | |
290 | ||
291 | ||
292 | #define LMCR1_TEST_EN (1 << 7) | |
1eaeb58e | 293 | #define LMCR1_LM_EN (1 << 6) |
79fa88f3 | 294 | #define LMCR1_LM_THM (1 << 5) |
1eaeb58e | 295 | #define LMCR1_LM_ONCE (1 << 2) |
79fa88f3 WD |
296 | #define LMCR1_LM_MASK (1 << 1) |
297 | ||
1eaeb58e | 298 | #define LMCR2_LM_RECT (1 << 5) |
79fa88f3 WD |
299 | #define LMCR2_LM_SEL_VDD 0x0D |
300 | #define LMCR2_LM_SEL_IO3 0x0A | |
301 | #define LMCR2_LM_SEL_IO4 0x0B | |
302 | #define LMCR2_LM_SEL_IO4_MINUS_IO3 0x0F | |
303 | ||
304 | #define LMCR3_RTR_SEL (1 << 6) | |
305 | ||
306 | #define LMCR3_RNG_OFFSET_NONE 0x00 | |
307 | #define LMCR3_RNG_OFFSET_1 0x01 | |
308 | #define LMCR3_RNG_OFFSET_2 0x02 | |
309 | #define LMCR3_RNG_OFFSET_3 0x03 | |
310 | ||
311 | #define TSTR5_DC_HOLD (1 << 3) | |
312 | ||
313 | /************************************************/ | |
314 | ||
315 | #define TARGET_ONHOOK_BATH_x100 4600 /* 46.0 Volt */ | |
1eaeb58e | 316 | #define TARGET_ONHOOK_BATL_x100 2500 /* 25.0 Volt */ |
79fa88f3 WD |
317 | #define TARGET_V_DIVIDER_RATIO_x100 21376L /* (R1+R2)/R2 = 213.76 */ |
318 | #define DIVIDER_RATIO_ACCURx100 (22 * 100) | |
319 | #define V_AD_x10000 10834L /* VAD = 1.0834 */ | |
320 | #define TARGET_VDDx100 330 /* VDD = 3.3 * 10 */ | |
321 | #define VDD_MAX_DIFFx100 20 /* VDD Accur = 0.2*100 */ | |
322 | ||
1eaeb58e WD |
323 | #define RMS_MULTIPLIERx100 111 /* pi/(2xsqrt(2)) = 1.11*/ |
324 | #define K_INTDC_RECT_ON 4 /* When Rectifier is ON this value is necessary(2^4) */ | |
325 | #define K_INTDC_RECT_OFF 2 /* 2^2 */ | |
326 | #define RNG_FREQ 25 | |
327 | #define SAMPLING_FREQ (2000L) | |
328 | #define N_SAMPLES (SAMPLING_FREQ/RNG_FREQ) /* for Ring Freq =25Hz (40ms Integration Period)[Sampling rate 2KHz -->1 Sample every 500us] */ | |
329 | #define HOOK_THRESH_RING_START_ADDR 0x8B | |
330 | #define RING_PARAMS_START_ADDR 0x70 | |
79fa88f3 WD |
331 | |
332 | #define V_OUT_BATH_MAX_DIFFx100 300 /* 3.0 x100 */ | |
333 | #define V_OUT_BATL_MAX_DIFFx100 400 /* 4.0 x100 */ | |
1eaeb58e WD |
334 | #define MAX_V_RING_MEANx100 50 |
335 | #define TARGET_V_RING_RMSx100 2720 | |
336 | #define V_RMS_RING_MAX_DIFFx100 250 | |
79fa88f3 WD |
337 | |
338 | #define LM_OK_SRC_IRG_2 (1 << 4) | |
339 | ||
340 | /************************************************/ | |
341 | ||
6d0f6bcf JCPV |
342 | #define PORTB (((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat) |
343 | #define PORTC (((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat) | |
344 | #define PORTD (((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat) | |
79fa88f3 WD |
345 | |
346 | #define _PORTD_SET(mask, state) \ | |
347 | do { \ | |
348 | if (state) \ | |
349 | PORTD |= mask; \ | |
350 | else \ | |
351 | PORTD &= ~mask; \ | |
352 | } while (0) | |
353 | ||
354 | #define _PORTB_SET(mask, state) \ | |
355 | do { \ | |
356 | if (state) \ | |
357 | PORTB |= mask; \ | |
358 | else \ | |
359 | PORTB &= ~mask; \ | |
360 | } while (0) | |
361 | ||
362 | #define _PORTB_TGL(mask) do { PORTB ^= mask; } while (0) | |
363 | #define _PORTB_GET(mask) (!!(PORTB & mask)) | |
364 | ||
365 | #define _PORTC_GET(mask) (!!(PORTC & mask)) | |
366 | ||
367 | /* port B */ | |
368 | #define SPI_RXD (1 << (31 - 28)) | |
369 | #define SPI_TXD (1 << (31 - 29)) | |
370 | #define SPI_CLK (1 << (31 - 30)) | |
371 | ||
372 | /* port C */ | |
373 | #define COM_HOOK1 (1 << (15 - 9)) | |
374 | #define COM_HOOK2 (1 << (15 - 10)) | |
375 | ||
376 | #ifndef CONFIG_NETTA_SWAPHOOK | |
377 | ||
378 | #define COM_HOOK3 (1 << (15 - 11)) | |
379 | #define COM_HOOK4 (1 << (15 - 12)) | |
380 | ||
381 | #else | |
382 | ||
383 | #define COM_HOOK3 (1 << (15 - 12)) | |
384 | #define COM_HOOK4 (1 << (15 - 11)) | |
385 | ||
386 | #endif | |
387 | ||
388 | /* port D */ | |
389 | #define SPIENC1 (1 << (15 - 9)) | |
390 | #define SPIENC2 (1 << (15 - 10)) | |
391 | #define SPIENC3 (1 << (15 - 11)) | |
392 | #define SPIENC4 (1 << (15 - 14)) | |
393 | ||
394 | #define SPI_DELAY() udelay(1) | |
395 | ||
396 | static inline unsigned int __SPI_Transfer(unsigned int tx) | |
397 | { | |
398 | unsigned int rx; | |
399 | int b; | |
400 | ||
401 | rx = 0; b = 8; | |
402 | while (--b >= 0) { | |
403 | _PORTB_SET(SPI_TXD, tx & 0x80); | |
404 | tx <<= 1; | |
405 | _PORTB_TGL(SPI_CLK); | |
406 | SPI_DELAY(); | |
407 | rx <<= 1; | |
408 | rx |= _PORTB_GET(SPI_RXD); | |
409 | _PORTB_TGL(SPI_CLK); | |
410 | SPI_DELAY(); | |
411 | } | |
412 | ||
413 | return rx; | |
414 | } | |
415 | ||
416 | static const char *codsp_dtmf_map = "D1234567890*#ABC"; | |
417 | ||
418 | static const int spienc_mask_tab[4] = { SPIENC1, SPIENC2, SPIENC3, SPIENC4 }; | |
419 | static const int com_hook_mask_tab[4] = { COM_HOOK1, COM_HOOK2, COM_HOOK3, COM_HOOK4 }; | |
420 | ||
421 | static unsigned int codsp_send(int duslic_id, const unsigned char *cmd, int cmdlen, unsigned char *res, int reslen) | |
422 | { | |
423 | unsigned int rx; | |
424 | int i; | |
425 | ||
426 | /* just some sanity checks */ | |
427 | if (cmd == 0 || cmdlen < 0) | |
428 | return -1; | |
429 | ||
430 | _PORTD_SET(spienc_mask_tab[duslic_id], 0); | |
431 | ||
432 | /* first 2 bytes are without response */ | |
433 | i = 2; | |
434 | while (i-- > 0 && cmdlen-- > 0) | |
435 | __SPI_Transfer(*cmd++); | |
436 | ||
437 | while (cmdlen-- > 0) { | |
438 | rx = __SPI_Transfer(*cmd++); | |
439 | if (res != 0 && reslen-- > 0) | |
440 | *res++ = (unsigned char)rx; | |
441 | } | |
442 | if (res != 0) { | |
443 | while (reslen-- > 0) | |
444 | *res++ = __SPI_Transfer(0xFF); | |
445 | } | |
446 | ||
447 | _PORTD_SET(spienc_mask_tab[duslic_id], 1); | |
448 | ||
449 | return 0; | |
450 | } | |
451 | ||
452 | /****************************************************************************/ | |
453 | ||
454 | void codsp_set_ciop_m(int duslic_id, int channel, unsigned char m) | |
455 | { | |
456 | unsigned char cmd = CODSP_WR | CODSP_ADR(channel) | CODSP_M(m); | |
457 | codsp_send(duslic_id, &cmd, 1, 0, 0); | |
458 | } | |
459 | ||
460 | void codsp_reset_chip(int duslic_id) | |
461 | { | |
462 | static const unsigned char cmd = CODSP_WR | CODSP_OP | CODSP_CMD_SOFT_RESET; | |
463 | codsp_send(duslic_id, &cmd, 1, 0, 0); | |
464 | } | |
465 | ||
466 | void codsp_reset_channel(int duslic_id, int channel) | |
467 | { | |
468 | unsigned char cmd = CODSP_WR | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_RESET_CH; | |
469 | codsp_send(duslic_id, &cmd, 1, 0, 0); | |
470 | } | |
471 | ||
472 | void codsp_resync_channel(int duslic_id, int channel) | |
473 | { | |
474 | unsigned char cmd = CODSP_WR | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_RESYNC; | |
475 | codsp_send(duslic_id, &cmd, 1, 0, 0); | |
476 | } | |
477 | ||
478 | /****************************************************************************/ | |
479 | ||
480 | void codsp_write_sop_char(int duslic_id, int channel, unsigned char regno, unsigned char val) | |
481 | { | |
482 | unsigned char cmd[3]; | |
483 | ||
484 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_SOP; | |
485 | cmd[1] = regno; | |
486 | cmd[2] = val; | |
487 | ||
488 | codsp_send(duslic_id, cmd, 3, 0, 0); | |
489 | } | |
490 | ||
491 | void codsp_write_sop_short(int duslic_id, int channel, unsigned char regno, unsigned short val) | |
492 | { | |
493 | unsigned char cmd[4]; | |
494 | ||
495 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_SOP; | |
496 | cmd[1] = regno; | |
497 | cmd[2] = (unsigned char)(val >> 8); | |
498 | cmd[3] = (unsigned char)val; | |
499 | ||
500 | codsp_send(duslic_id, cmd, 4, 0, 0); | |
501 | } | |
502 | ||
503 | void codsp_write_sop_int(int duslic_id, int channel, unsigned char regno, unsigned int val) | |
504 | { | |
505 | unsigned char cmd[5]; | |
506 | ||
507 | cmd[0] = CODSP_WR | CODSP_ADR(channel) | CODSP_CMD_SOP; | |
508 | cmd[1] = regno; | |
509 | cmd[2] = (unsigned char)(val >> 24); | |
510 | cmd[3] = (unsigned char)(val >> 16); | |
511 | cmd[4] = (unsigned char)(val >> 8); | |
512 | cmd[5] = (unsigned char)val; | |
513 | ||
514 | codsp_send(duslic_id, cmd, 6, 0, 0); | |
515 | } | |
516 | ||
517 | unsigned char codsp_read_sop_char(int duslic_id, int channel, unsigned char regno) | |
518 | { | |
519 | unsigned char cmd[3]; | |
520 | unsigned char res[2]; | |
521 | ||
522 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_SOP; | |
523 | cmd[1] = regno; | |
524 | ||
525 | codsp_send(duslic_id, cmd, 2, res, 2); | |
526 | ||
527 | return res[1]; | |
528 | } | |
529 | ||
530 | unsigned short codsp_read_sop_short(int duslic_id, int channel, unsigned char regno) | |
531 | { | |
532 | unsigned char cmd[2]; | |
533 | unsigned char res[3]; | |
534 | ||
535 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_SOP; | |
536 | cmd[1] = regno; | |
537 | ||
538 | codsp_send(duslic_id, cmd, 2, res, 3); | |
539 | ||
540 | return ((unsigned short)res[1] << 8) | res[2]; | |
541 | } | |
542 | ||
543 | unsigned int codsp_read_sop_int(int duslic_id, int channel, unsigned char regno) | |
544 | { | |
545 | unsigned char cmd[2]; | |
546 | unsigned char res[5]; | |
547 | ||
548 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_SOP; | |
549 | cmd[1] = regno; | |
550 | ||
551 | codsp_send(duslic_id, cmd, 2, res, 5); | |
552 | ||
553 | return ((unsigned int)res[1] << 24) | ((unsigned int)res[2] << 16) | ((unsigned int)res[3] << 8) | res[4]; | |
554 | } | |
555 | ||
556 | /****************************************************************************/ | |
557 | ||
558 | void codsp_write_cop_block(int duslic_id, int channel, unsigned char addr, const unsigned char *block) | |
559 | { | |
560 | unsigned char cmd[10]; | |
561 | ||
562 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_COP; | |
563 | cmd[1] = addr; | |
564 | memcpy(cmd + 2, block, 8); | |
565 | codsp_send(duslic_id, cmd, 10, 0, 0); | |
566 | } | |
567 | ||
568 | void codsp_write_cop_char(int duslic_id, int channel, unsigned char addr, unsigned char val) | |
569 | { | |
570 | unsigned char cmd[3]; | |
571 | ||
572 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_COP; | |
573 | cmd[1] = addr; | |
574 | cmd[2] = val; | |
575 | codsp_send(duslic_id, cmd, 3, 0, 0); | |
576 | } | |
577 | ||
578 | void codsp_write_cop_short(int duslic_id, int channel, unsigned char addr, unsigned short val) | |
579 | { | |
580 | unsigned char cmd[3]; | |
581 | ||
582 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_COP; | |
583 | cmd[1] = addr; | |
584 | cmd[2] = (unsigned char)(val >> 8); | |
585 | cmd[3] = (unsigned char)val; | |
586 | ||
587 | codsp_send(duslic_id, cmd, 4, 0, 0); | |
588 | } | |
589 | ||
590 | void codsp_read_cop_block(int duslic_id, int channel, unsigned char addr, unsigned char *block) | |
591 | { | |
592 | unsigned char cmd[2]; | |
593 | unsigned char res[9]; | |
594 | ||
595 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_COP; | |
596 | cmd[1] = addr; | |
597 | codsp_send(duslic_id, cmd, 2, res, 9); | |
598 | memcpy(block, res + 1, 8); | |
599 | } | |
600 | ||
601 | unsigned char codsp_read_cop_char(int duslic_id, int channel, unsigned char addr) | |
602 | { | |
603 | unsigned char cmd[2]; | |
604 | unsigned char res[2]; | |
605 | ||
606 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_COP; | |
607 | cmd[1] = addr; | |
608 | codsp_send(duslic_id, cmd, 2, res, 2); | |
609 | return res[1]; | |
610 | } | |
611 | ||
612 | unsigned short codsp_read_cop_short(int duslic_id, int channel, unsigned char addr) | |
613 | { | |
614 | unsigned char cmd[2]; | |
615 | unsigned char res[3]; | |
616 | ||
617 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR(channel) | CODSP_CMD_COP; | |
618 | cmd[1] = addr; | |
619 | ||
620 | codsp_send(duslic_id, cmd, 2, res, 3); | |
621 | ||
622 | return ((unsigned short)res[1] << 8) | res[2]; | |
623 | } | |
624 | ||
625 | /****************************************************************************/ | |
626 | ||
1eaeb58e | 627 | #define MAX_POP_BLOCK 50 |
79fa88f3 | 628 | |
1eaeb58e WD |
629 | void codsp_write_pop_block (int duslic_id, int channel, unsigned char addr, |
630 | const unsigned char *block, int len) | |
79fa88f3 WD |
631 | { |
632 | unsigned char cmd[2 + MAX_POP_BLOCK]; | |
633 | ||
1eaeb58e WD |
634 | if (len > MAX_POP_BLOCK) /* truncate */ |
635 | len = MAX_POP_BLOCK; | |
79fa88f3 | 636 | |
1eaeb58e | 637 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR (channel) | CODSP_CMD_POP; |
79fa88f3 | 638 | cmd[1] = addr; |
1eaeb58e WD |
639 | memcpy (cmd + 2, block, len); |
640 | codsp_send (duslic_id, cmd, 2 + len, 0, 0); | |
79fa88f3 WD |
641 | } |
642 | ||
1eaeb58e WD |
643 | void codsp_write_pop_char (int duslic_id, int channel, unsigned char regno, |
644 | unsigned char val) | |
79fa88f3 WD |
645 | { |
646 | unsigned char cmd[3]; | |
647 | ||
1eaeb58e | 648 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR (channel) | CODSP_CMD_POP; |
79fa88f3 WD |
649 | cmd[1] = regno; |
650 | cmd[2] = val; | |
651 | ||
1eaeb58e | 652 | codsp_send (duslic_id, cmd, 3, 0, 0); |
79fa88f3 WD |
653 | } |
654 | ||
1eaeb58e WD |
655 | void codsp_write_pop_short (int duslic_id, int channel, unsigned char regno, |
656 | unsigned short val) | |
79fa88f3 WD |
657 | { |
658 | unsigned char cmd[4]; | |
659 | ||
1eaeb58e | 660 | cmd[0] = CODSP_WR | CODSP_OP | CODSP_ADR (channel) | CODSP_CMD_POP; |
79fa88f3 | 661 | cmd[1] = regno; |
1eaeb58e WD |
662 | cmd[2] = (unsigned char) (val >> 8); |
663 | cmd[3] = (unsigned char) val; | |
79fa88f3 | 664 | |
1eaeb58e | 665 | codsp_send (duslic_id, cmd, 4, 0, 0); |
79fa88f3 WD |
666 | } |
667 | ||
1eaeb58e WD |
668 | void codsp_write_pop_int (int duslic_id, int channel, unsigned char regno, |
669 | unsigned int val) | |
79fa88f3 WD |
670 | { |
671 | unsigned char cmd[5]; | |
672 | ||
1eaeb58e | 673 | cmd[0] = CODSP_WR | CODSP_ADR (channel) | CODSP_CMD_POP; |
79fa88f3 | 674 | cmd[1] = regno; |
1eaeb58e WD |
675 | cmd[2] = (unsigned char) (val >> 24); |
676 | cmd[3] = (unsigned char) (val >> 16); | |
677 | cmd[4] = (unsigned char) (val >> 8); | |
678 | cmd[5] = (unsigned char) val; | |
79fa88f3 | 679 | |
1eaeb58e | 680 | codsp_send (duslic_id, cmd, 6, 0, 0); |
79fa88f3 WD |
681 | } |
682 | ||
1eaeb58e WD |
683 | unsigned char codsp_read_pop_char (int duslic_id, int channel, |
684 | unsigned char regno) | |
79fa88f3 WD |
685 | { |
686 | unsigned char cmd[3]; | |
687 | unsigned char res[2]; | |
688 | ||
1eaeb58e | 689 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR (channel) | CODSP_CMD_POP; |
79fa88f3 WD |
690 | cmd[1] = regno; |
691 | ||
1eaeb58e | 692 | codsp_send (duslic_id, cmd, 2, res, 2); |
79fa88f3 WD |
693 | |
694 | return res[1]; | |
695 | } | |
696 | ||
1eaeb58e WD |
697 | unsigned short codsp_read_pop_short (int duslic_id, int channel, |
698 | unsigned char regno) | |
79fa88f3 WD |
699 | { |
700 | unsigned char cmd[2]; | |
701 | unsigned char res[3]; | |
702 | ||
1eaeb58e | 703 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR (channel) | CODSP_CMD_POP; |
79fa88f3 WD |
704 | cmd[1] = regno; |
705 | ||
1eaeb58e | 706 | codsp_send (duslic_id, cmd, 2, res, 3); |
79fa88f3 | 707 | |
1eaeb58e | 708 | return ((unsigned short) res[1] << 8) | res[2]; |
79fa88f3 WD |
709 | } |
710 | ||
1eaeb58e WD |
711 | unsigned int codsp_read_pop_int (int duslic_id, int channel, |
712 | unsigned char regno) | |
79fa88f3 WD |
713 | { |
714 | unsigned char cmd[2]; | |
715 | unsigned char res[5]; | |
716 | ||
1eaeb58e | 717 | cmd[0] = CODSP_RD | CODSP_OP | CODSP_ADR (channel) | CODSP_CMD_POP; |
79fa88f3 WD |
718 | cmd[1] = regno; |
719 | ||
1eaeb58e | 720 | codsp_send (duslic_id, cmd, 2, res, 5); |
79fa88f3 | 721 | |
1eaeb58e WD |
722 | return (((unsigned int) res[1] << 24) | |
723 | ((unsigned int) res[2] << 16) | | |
724 | ((unsigned int) res[3] << 8) | | |
725 | res[4] ); | |
79fa88f3 | 726 | } |
79fa88f3 WD |
727 | /****************************************************************************/ |
728 | ||
729 | struct _coeffs { | |
730 | unsigned char addr; | |
731 | unsigned char values[8]; | |
732 | }; | |
733 | ||
734 | struct _coeffs ac_coeffs[11] = { | |
735 | { 0x60, {0xAD,0xDA,0xB5,0x9B,0xC7,0x2A,0x9D,0x00} }, /* 0x60 IM-Filter part 1 */ | |
736 | { 0x68, {0x10,0x00,0xA9,0x82,0x0D,0x77,0x0A,0x00} }, /* 0x68 IM-Filter part 2 */ | |
1eaeb58e WD |
737 | { 0x18, {0x08,0xC0,0xD2,0xAB,0xA5,0xE2,0xAB,0x07} }, /* 0x18 FRR-Filter */ |
738 | { 0x28, {0x44,0x93,0xF5,0x92,0x88,0x00,0x00,0x00} }, /* 0x28 AR-Filter */ | |
739 | { 0x48, {0x96,0x38,0x29,0x96,0xC9,0x2B,0x8B,0x00} }, /* 0x48 LPR-Filter */ | |
740 | { 0x20, {0x08,0xB0,0xDA,0x9D,0xA7,0xFA,0x93,0x06} }, /* 0x20 FRX-Filter */ | |
741 | { 0x30, {0xBA,0xAC,0x00,0x01,0x85,0x50,0xC0,0x1A} }, /* 0x30 AX-Filter */ | |
742 | { 0x50, {0x96,0x38,0x29,0xF5,0xFA,0x2B,0x8B,0x00} }, /* 0x50 LPX-Filter */ | |
79fa88f3 WD |
743 | { 0x00, {0x00,0x08,0x08,0x81,0x00,0x80,0x00,0x08} }, /* 0x00 TH-Filter part 1 */ |
744 | { 0x08, {0x81,0x00,0x80,0x00,0xD7,0x33,0xBA,0x01} }, /* 0x08 TH-Filter part 2 */ | |
745 | { 0x10, {0xB3,0x6C,0xDC,0xA3,0xA4,0xE5,0x88,0x00} } /* 0x10 TH-Filter part 3 */ | |
746 | }; | |
747 | ||
748 | struct _coeffs ac_coeffs_0dB[11] = { | |
749 | { 0x60, {0xAC,0x2A,0xB5,0x9A,0xB7,0x2A,0x9D,0x00} }, | |
750 | { 0x68, {0x10,0x00,0xA9,0x82,0x0D,0x83,0x0A,0x00} }, | |
751 | { 0x18, {0x08,0x20,0xD4,0xA4,0x65,0xEE,0x92,0x07} }, | |
752 | { 0x28, {0x2B,0xAB,0x36,0xA5,0x88,0x00,0x00,0x00} }, | |
753 | { 0x48, {0xAB,0xE9,0x4E,0x32,0xAB,0x25,0xA5,0x03} }, | |
754 | { 0x20, {0x08,0x20,0xDB,0x9C,0xA7,0xFA,0xB4,0x07} }, | |
755 | { 0x30, {0xF3,0x10,0x07,0x60,0x85,0x40,0xC0,0x1A} }, | |
756 | { 0x50, {0x96,0x38,0x29,0x97,0x39,0x19,0x8B,0x00} }, | |
757 | { 0x00, {0x00,0x08,0x08,0x81,0x00,0x80,0x00,0x08} }, | |
758 | { 0x08, {0x81,0x00,0x80,0x00,0x47,0x3C,0xD2,0x01} }, | |
759 | { 0x10, {0x62,0xDB,0x4A,0x87,0x73,0x28,0x88,0x00} } | |
760 | }; | |
761 | ||
762 | struct _coeffs dc_coeffs[9] = { | |
763 | { 0x80, {0x25,0x59,0x9C,0x23,0x24,0x23,0x32,0x1C} }, /* 0x80 DC-Parameter */ | |
1eaeb58e WD |
764 | { 0x70, {0x90,0x30,0x1B,0xC0,0x33,0x43,0xAC,0x02} }, /* 0x70 Ringing */ |
765 | { 0x90, {0x3F,0xC3,0x2E,0x3A,0x80,0x90,0x00,0x09} }, /* 0x90 LP-Filters */ | |
79fa88f3 WD |
766 | { 0x88, {0xAF,0x80,0x27,0x7B,0x01,0x4C,0x7B,0x02} }, /* 0x88 Hook Levels */ |
767 | { 0x78, {0x00,0xC0,0x6D,0x7A,0xB3,0x78,0x89,0x00} }, /* 0x78 Ramp Generator */ | |
1eaeb58e WD |
768 | { 0x58, {0xA5,0x44,0x34,0xDB,0x0E,0xA2,0x2A,0x00} }, /* 0x58 TTX */ |
769 | { 0x38, {0x33,0x49,0x9A,0x65,0xBB,0x00,0x00,0x00} }, /* 0x38 TG1 */ | |
770 | { 0x40, {0x33,0x49,0x9A,0x65,0xBB,0x00,0x00,0x00} }, /* 0x40 TG2 */ | |
771 | { 0x98, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} } /* 0x98 Reserved */ | |
79fa88f3 WD |
772 | }; |
773 | ||
774 | void program_coeffs(int duslic_id, int channel, struct _coeffs *coeffs, int tab_size) | |
775 | { | |
776 | int i; | |
777 | ||
778 | for (i = 0; i < tab_size; i++) | |
1eaeb58e | 779 | codsp_write_cop_block(duslic_id, channel, coeffs[i].addr, coeffs[i].values); |
79fa88f3 WD |
780 | } |
781 | ||
782 | #define SS_OPEN_CIRCUIT 0 | |
783 | #define SS_RING_PAUSE 1 | |
784 | #define SS_ACTIVE 2 | |
785 | #define SS_ACTIVE_HIGH 3 | |
786 | #define SS_ACTIVE_RING 4 | |
787 | #define SS_RINGING 5 | |
788 | #define SS_ACTIVE_WITH_METERING 6 | |
789 | #define SS_ONHOOKTRNSM 7 | |
790 | #define SS_STANDBY 8 | |
791 | #define SS_MAX 8 | |
792 | ||
793 | static void codsp_set_slic(int duslic_id, int channel, int state) | |
794 | { | |
795 | unsigned char v; | |
796 | ||
797 | v = codsp_read_sop_char(duslic_id, channel, BCR1_ADDR); | |
798 | ||
799 | switch (state) { | |
800 | ||
801 | case SS_ACTIVE: | |
802 | codsp_write_sop_char(duslic_id, channel, BCR1_ADDR, (v & ~BCR1_ACTR) | BCR1_ACTL); | |
803 | codsp_set_ciop_m(duslic_id, channel, CODSP_M_ANY_ACT); | |
804 | break; | |
805 | ||
806 | case SS_ACTIVE_HIGH: | |
807 | codsp_write_sop_char(duslic_id, channel, BCR1_ADDR, v & ~(BCR1_ACTR | BCR1_ACTL)); | |
808 | codsp_set_ciop_m(duslic_id, channel, CODSP_M_ANY_ACT); | |
809 | break; | |
810 | ||
811 | case SS_ACTIVE_RING: | |
1eaeb58e | 812 | case SS_ONHOOKTRNSM: |
79fa88f3 WD |
813 | codsp_write_sop_char(duslic_id, channel, BCR1_ADDR, (v & ~BCR1_ACTL) | BCR1_ACTR); |
814 | codsp_set_ciop_m(duslic_id, channel, CODSP_M_ANY_ACT); | |
815 | break; | |
816 | ||
817 | case SS_STANDBY: | |
818 | codsp_write_sop_char(duslic_id, channel, BCR1_ADDR, v & ~(BCR1_ACTL | BCR1_ACTR)); | |
819 | codsp_set_ciop_m(duslic_id, channel, CODSP_M_SLEEP_PWRDN); | |
820 | break; | |
821 | ||
822 | case SS_OPEN_CIRCUIT: | |
823 | codsp_set_ciop_m(duslic_id, channel, CODSP_M_PWRDN_HIZ); | |
824 | break; | |
825 | ||
826 | case SS_RINGING: | |
827 | codsp_set_ciop_m(duslic_id, channel, CODSP_M_RING); | |
828 | break; | |
829 | ||
830 | case SS_RING_PAUSE: | |
831 | codsp_set_ciop_m(duslic_id, channel, CODSP_M_RING_PAUSE); | |
832 | break; | |
833 | } | |
834 | } | |
835 | ||
836 | const unsigned char Ring_Sin_28Vrms_25Hz[8] = { 0x90, 0x30, 0x1B, 0xC0, 0xC3, 0x9C, 0x88, 0x00 }; | |
837 | const unsigned char Max_HookRingTh[3] = { 0x7B, 0x41, 0x62 }; | |
838 | ||
839 | void retrieve_slic_state(int slic_id) | |
840 | { | |
841 | int duslic_id = slic_id >> 1; | |
842 | int channel = slic_id & 1; | |
843 | ||
844 | /* Retrieve the state of the SLICs */ | |
845 | codsp_write_sop_char(duslic_id, channel, LMCR2_ADDR, 0x00); | |
846 | ||
847 | /* wait at least 1000us to clear the LM_OK and 500us to set the LM_OK ==> for the LM to make the first Measurement */ | |
848 | udelay(10000); | |
849 | ||
850 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK); | |
851 | codsp_set_slic(duslic_id, channel, SS_ACTIVE_HIGH); | |
852 | codsp_write_sop_char(duslic_id, channel, LMCR3_ADDR, 0x40); | |
853 | ||
854 | /* Program Default Hook Ring thresholds */ | |
855 | codsp_write_cop_block(duslic_id, channel, dc_coeffs[1].addr, dc_coeffs[1].values); | |
856 | ||
857 | /* Now program Hook Threshold while Ring and ac RingTrip to max values */ | |
858 | codsp_write_cop_block(duslic_id, channel, dc_coeffs[3].addr, dc_coeffs[3].values); | |
859 | ||
860 | codsp_write_sop_short(duslic_id, channel, OFR1_ADDR, 0x0000); | |
861 | ||
862 | udelay(40000); | |
863 | } | |
864 | ||
865 | int wait_level_metering_finish(int duslic_id, int channel) | |
866 | { | |
867 | int cnt; | |
868 | ||
869 | for (cnt = 0; cnt < 1000 && | |
870 | (codsp_read_sop_char(duslic_id, channel, INTREG2_ADDR) & LM_OK_SRC_IRG_2) == 0; cnt++) { } | |
871 | ||
872 | return cnt != 1000; | |
873 | } | |
874 | ||
875 | int measure_on_hook_voltages(int slic_id, long *vdd, | |
1eaeb58e | 876 | long *v_oh_H, long *v_oh_L, long *ring_mean_v, long *ring_rms_v) |
79fa88f3 WD |
877 | { |
878 | short LM_Result, Offset_Compensation; /* Signed 16 bit */ | |
879 | long int VDD, VDD_diff, V_in, V_out, Divider_Ratio, Vout_diff ; | |
880 | unsigned char err_mask = 0; | |
881 | int duslic_id = slic_id >> 1; | |
882 | int channel = slic_id & 1; | |
883 | int i; | |
884 | ||
885 | /* measure VDD */ | |
886 | /* Now select the VDD level Measurement (but first of all Hold the DC characteristic) */ | |
887 | codsp_write_sop_char(duslic_id, channel, TSTR5_ADDR, TSTR5_DC_HOLD); | |
888 | ||
889 | /* Activate Test Mode ==> To Enable DC Hold !!! */ | |
890 | /* (else the LMRES is treated as Feeding Current and the Feeding voltage changes */ | |
891 | /* imediatelly (after 500us when the LMRES Registers is updated for the first time after selection of (IO4-IO3) measurement !!!!))*/ | |
892 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, LMCR1_TEST_EN | LMCR1_LM_THM | LMCR1_LM_MASK); | |
893 | ||
894 | udelay(40000); | |
895 | ||
896 | /* Now I Can select what to measure by DC Level Meter (select IO4-IO3) */ | |
897 | codsp_write_sop_char(duslic_id, channel, LMCR2_ADDR, LMCR2_LM_SEL_VDD); | |
898 | ||
899 | /* wait at least 1000us to clear the LM_OK and 500us to set the LM_OK ==> for the LM to make the first Measurement */ | |
900 | udelay(10000); | |
901 | ||
902 | /* Now Read the LM Result Registers */ | |
903 | LM_Result = codsp_read_sop_short(duslic_id, channel, LMRES1_ADDR); | |
904 | VDD = (-1)*((((long int)LM_Result) * 390L ) >> 15) ; /* VDDx100 */ | |
905 | ||
906 | *vdd = VDD; | |
907 | ||
908 | VDD_diff = VDD - TARGET_VDDx100; | |
909 | ||
910 | if (VDD_diff < 0) | |
911 | VDD_diff = -VDD_diff; | |
912 | ||
913 | if (VDD_diff > VDD_MAX_DIFFx100) | |
914 | err_mask |= 1; | |
915 | ||
916 | Divider_Ratio = TARGET_V_DIVIDER_RATIO_x100; | |
917 | ||
918 | codsp_write_sop_char(duslic_id, channel, LMCR2_ADDR, 0x00); | |
919 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK); | |
920 | ||
921 | codsp_set_slic(duslic_id, channel, SS_ACTIVE_HIGH); /* Go back to ONHOOK Voltage */ | |
922 | ||
923 | udelay(40000); | |
924 | ||
925 | codsp_write_sop_char(duslic_id, channel, | |
926 | LMCR1_ADDR, LMCR1_TEST_EN | LMCR1_LM_THM | LMCR1_LM_MASK); | |
927 | ||
928 | udelay(40000); | |
929 | ||
930 | /* Now I Can select what to measure by DC Level Meter (select IO4-IO3) */ | |
931 | codsp_write_sop_char(duslic_id, channel, LMCR2_ADDR, LMCR2_LM_SEL_IO4_MINUS_IO3); | |
932 | ||
933 | /* wait at least 1000us to clear the LM_OK and 500us to set the LM_OK ==> for the LM to make the first Measurement */ | |
934 | udelay(10000); | |
935 | ||
936 | /* Now Read the LM Result Registers */ | |
937 | LM_Result = codsp_read_sop_short(duslic_id, channel, LMRES1_ADDR); | |
938 | V_in = (-1)* ((((long int)LM_Result) * V_AD_x10000 ) >> 15) ; /* Vin x 10000*/ | |
939 | ||
940 | V_out = (V_in * Divider_Ratio) / 10000L ; /* Vout x100 */ | |
941 | ||
942 | *v_oh_H = V_out; | |
943 | ||
944 | Vout_diff = V_out - TARGET_ONHOOK_BATH_x100; | |
945 | ||
946 | if (Vout_diff < 0) | |
947 | Vout_diff = -Vout_diff; | |
948 | ||
949 | if (Vout_diff > V_OUT_BATH_MAX_DIFFx100) | |
950 | err_mask |= 2; | |
951 | ||
952 | codsp_set_slic(duslic_id, channel, SS_ACTIVE); /* Go back to ONHOOK Voltage */ | |
953 | ||
954 | udelay(40000); | |
955 | ||
956 | /* Now Read the LM Result Registers */ | |
957 | LM_Result = codsp_read_sop_short(duslic_id, channel, LMRES1_ADDR); | |
958 | ||
959 | V_in = (-1)* ((((long int)LM_Result) * V_AD_x10000 ) >> 15) ; /* Vin x 10000*/ | |
960 | ||
961 | V_out = (V_in * Divider_Ratio) / 10000L ; /* Vout x100 */ | |
962 | ||
963 | *v_oh_L = V_out; | |
964 | ||
965 | Vout_diff = V_out - TARGET_ONHOOK_BATL_x100; | |
966 | ||
967 | if (Vout_diff < 0) | |
968 | Vout_diff = -Vout_diff; | |
969 | ||
970 | if (Vout_diff > V_OUT_BATL_MAX_DIFFx100) | |
971 | err_mask |= 4; | |
972 | ||
973 | /* perform ring tests */ | |
974 | ||
975 | codsp_write_sop_char(duslic_id, channel, LMCR2_ADDR, 0x00); | |
976 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK); | |
977 | ||
978 | udelay(40000); | |
979 | ||
980 | codsp_write_sop_char(duslic_id, channel, LMCR3_ADDR, LMCR3_RTR_SEL | LMCR3_RNG_OFFSET_NONE); | |
981 | ||
982 | /* Now program RO1 =0V , Ring Amplitude and frequency and shift factor K = 1 (LMDC=0x0088)*/ | |
983 | codsp_write_cop_block(duslic_id, channel, RING_PARAMS_START_ADDR, Ring_Sin_28Vrms_25Hz); | |
984 | ||
985 | /* By Default RO1 is selected when ringing RNG-OFFSET = 00 */ | |
986 | ||
987 | /* Now program Hook Threshold while Ring and ac RingTrip to max values */ | |
988 | for(i = 0; i < sizeof(Max_HookRingTh); i++) | |
989 | codsp_write_cop_char(duslic_id, channel, HOOK_THRESH_RING_START_ADDR + i, Max_HookRingTh[i]); | |
990 | ||
991 | codsp_write_sop_short(duslic_id, channel, OFR1_ADDR, 0x0000); | |
992 | ||
993 | codsp_set_slic(duslic_id, channel, SS_RING_PAUSE); /* Start Ringing */ | |
994 | ||
995 | /* select source for the levelmeter to be IO4-IO3 */ | |
996 | codsp_write_sop_char(duslic_id, channel, LMCR2_ADDR, LMCR2_LM_SEL_IO4_MINUS_IO3); | |
997 | ||
998 | udelay(40000); | |
999 | ||
1000 | /* Before Enabling Level Meter Programm the apropriate shift factor K_INTDC=(4 if Rectifier Enabled and 2 if Rectifier Disabled) */ | |
1001 | codsp_write_cop_char(duslic_id, channel, RING_PARAMS_START_ADDR + 7, K_INTDC_RECT_OFF); | |
1002 | ||
1003 | udelay(10000); | |
1004 | ||
1005 | /* Enable LevelMeter to Integrate only once (Rectifier Disabled) */ | |
1006 | codsp_write_sop_char(duslic_id, channel, | |
1007 | LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK | LMCR1_LM_EN | LMCR1_LM_ONCE); | |
1008 | ||
1009 | udelay(40000); /* Integration Period == Ring Period = 40ms (for 25Hz Ring) */ | |
1010 | ||
1011 | if (wait_level_metering_finish(duslic_id, channel)) { | |
1012 | ||
1013 | udelay(10000); /* To be sure that Integration Results are Valid wait at least 500us !!! */ | |
1014 | ||
1015 | /* Now Read the LM Result Registers (Will be valid until LM_EN becomes zero again( after that the Result is updated every 500us) ) */ | |
1016 | Offset_Compensation = codsp_read_sop_short(duslic_id, channel, LMRES1_ADDR); | |
1017 | Offset_Compensation = (-1) * ((Offset_Compensation * (1 << K_INTDC_RECT_OFF)) / N_SAMPLES); | |
1018 | ||
1019 | /* Disable LevelMeter ==> In order to be able to restart Integrator again (for the next integration) */ | |
1020 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK | LMCR1_LM_ONCE); | |
1021 | ||
1022 | /* Now programm Integrator Offset Registers !!! */ | |
1023 | codsp_write_sop_short(duslic_id, channel, OFR1_ADDR, Offset_Compensation); | |
1024 | ||
1025 | codsp_set_slic(duslic_id, channel, SS_RINGING); /* Start Ringing */ | |
1026 | ||
1027 | udelay(40000); | |
1028 | ||
1029 | /* Reenable Level Meter Integrator (The Result will be valid after Integration Period=Ring Period and until LN_EN become zero again) */ | |
1030 | codsp_write_sop_char(duslic_id, channel, | |
1031 | LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK | LMCR1_LM_EN | LMCR1_LM_ONCE); | |
1032 | ||
1033 | udelay(40000); /* Integration Period == Ring Period = 40ms (for 25Hz Ring) */ | |
1034 | ||
1035 | /* Poll the LM_OK bit to see when Integration Result is Ready */ | |
1036 | if (wait_level_metering_finish(duslic_id, channel)) { | |
1037 | ||
1038 | udelay(10000); /* wait at least 500us to be sure that the Integration Result are valid !!! */ | |
1039 | ||
1040 | /* Now Read the LM Result Registers (They will hold their value until LM_EN become zero again */ | |
1eaeb58e | 1041 | /* ==>After that Result Regs will be updated every 500us !!!) */ |
79fa88f3 WD |
1042 | LM_Result = codsp_read_sop_short(duslic_id, channel, LMRES1_ADDR); |
1043 | V_in = (-1) * ( ( (((long int)LM_Result) * V_AD_x10000) / N_SAMPLES) >> (15 - K_INTDC_RECT_OFF)) ; /* Vin x 10000*/ | |
1044 | ||
1045 | V_out = (V_in * Divider_Ratio) / 10000L ; /* Vout x100 */ | |
1046 | ||
1047 | if (V_out < 0) | |
1048 | V_out= -V_out; | |
1049 | ||
1050 | if (V_out > MAX_V_RING_MEANx100) | |
1051 | err_mask |= 8; | |
1052 | ||
1053 | *ring_mean_v = V_out; | |
1054 | } else { | |
1055 | err_mask |= 8; | |
1056 | *ring_mean_v = 0; | |
1057 | } | |
1058 | } else { | |
1059 | err_mask |= 8; | |
1060 | *ring_mean_v = 0; | |
1061 | } | |
1062 | ||
1063 | /* Disable LevelMeter ==> In order to be able to restart Integrator again (for the next integration) */ | |
1064 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, | |
1065 | LMCR1_LM_THM | LMCR1_LM_MASK | LMCR1_LM_ONCE); | |
1066 | codsp_write_sop_short(duslic_id, channel, OFR1_ADDR, 0x0000); | |
1067 | ||
1068 | codsp_set_slic(duslic_id, channel, SS_RING_PAUSE); /* Start Ringing */ | |
1069 | ||
1070 | /* Now Enable Rectifier */ | |
1071 | /* select source for the levelmeter to be IO4-IO3 */ | |
1072 | codsp_write_sop_char(duslic_id, channel, LMCR2_ADDR, | |
1073 | LMCR2_LM_SEL_IO4_MINUS_IO3 | LMCR2_LM_RECT); | |
1074 | ||
1075 | /* Program the apropriate shift factor K_INTDC (in order to avoid Overflow at Integtation Result !!!) */ | |
1076 | codsp_write_cop_char(duslic_id, channel, RING_PARAMS_START_ADDR + 7, K_INTDC_RECT_ON); | |
1077 | ||
1078 | udelay(40000); | |
1079 | ||
1080 | /* Reenable Level Meter Integrator (The Result will be valid after Integration Period=Ring Period and until LN_EN become zero again) */ | |
1081 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, | |
1082 | LMCR1_LM_THM | LMCR1_LM_MASK | LMCR1_LM_EN | LMCR1_LM_ONCE); | |
1083 | ||
1084 | udelay(40000); | |
1085 | ||
1086 | /* Poll the LM_OK bit to see when Integration Result is Ready */ | |
1087 | if (wait_level_metering_finish(duslic_id, channel)) { | |
1088 | ||
1089 | udelay(10000); | |
1090 | ||
1091 | /* Now Read the LM Result Registers (They will hold their value until LM_EN become zero again */ | |
1eaeb58e | 1092 | /* ==>After that Result Regs will be updated every 500us !!!) */ |
79fa88f3 WD |
1093 | Offset_Compensation = codsp_read_sop_short(duslic_id, channel, LMRES1_ADDR); |
1094 | Offset_Compensation = (-1) * ((Offset_Compensation * (1 << K_INTDC_RECT_ON)) / N_SAMPLES); | |
1095 | ||
1096 | /* Disable LevelMeter ==> In order to be able to restart Integrator again (for the next integration) */ | |
1097 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK | LMCR1_LM_ONCE); | |
1098 | ||
1099 | /* Now programm Integrator Offset Registers !!! */ | |
1100 | codsp_write_sop_short(duslic_id, channel, OFR1_ADDR, Offset_Compensation); | |
1101 | ||
1102 | /* Be sure that a Ring is generated !!!! */ | |
1103 | codsp_set_slic(duslic_id, channel, SS_RINGING); /* Start Ringing again */ | |
1104 | ||
1105 | udelay(40000); | |
1106 | ||
1107 | /* Reenable Level Meter Integrator (The Result will be valid after Integration Period=Ring Period and until LN_EN become zero again) */ | |
1108 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, | |
1109 | LMCR1_LM_THM | LMCR1_LM_MASK | LMCR1_LM_EN | LMCR1_LM_ONCE); | |
1110 | ||
1111 | udelay(40000); | |
1112 | ||
1113 | /* Poll the LM_OK bit to see when Integration Result is Ready */ | |
1114 | if (wait_level_metering_finish(duslic_id, channel)) { | |
1115 | ||
1116 | udelay(10000); | |
1117 | ||
1118 | /* Now Read the LM Result Registers (They will hold their value until LM_EN become zero again */ | |
1eaeb58e | 1119 | /* ==>After that Result Regs will be updated every 500us !!!) */ |
79fa88f3 WD |
1120 | LM_Result = codsp_read_sop_short(duslic_id, channel, LMRES1_ADDR); |
1121 | V_in = (-1) * ( ( (((long int)LM_Result) * V_AD_x10000) / N_SAMPLES) >> (15 - K_INTDC_RECT_ON) ) ; /* Vin x 10000*/ | |
1122 | ||
1123 | V_out = (((V_in * Divider_Ratio) / 10000L) * RMS_MULTIPLIERx100) / 100 ; /* Vout_RMS x100 */ | |
1124 | if (V_out < 0) | |
1125 | V_out = -V_out; | |
1126 | ||
1127 | Vout_diff = (V_out - TARGET_V_RING_RMSx100); | |
1128 | ||
1129 | if (Vout_diff < 0) | |
1130 | Vout_diff = -Vout_diff; | |
1131 | ||
1132 | if (Vout_diff > V_RMS_RING_MAX_DIFFx100) | |
1133 | err_mask |= 16; | |
1134 | ||
1135 | *ring_rms_v = V_out; | |
1136 | } else { | |
1137 | err_mask |= 16; | |
1138 | *ring_rms_v = 0; | |
1139 | } | |
1140 | } else { | |
1141 | err_mask |= 16; | |
1142 | *ring_rms_v = 0; | |
1143 | } | |
1144 | /* Disable LevelMeter ==> In order to be able to restart Integrator again (for the next integration) */ | |
1145 | codsp_write_sop_char(duslic_id, channel, LMCR1_ADDR, LMCR1_LM_THM | LMCR1_LM_MASK); | |
1146 | ||
1147 | retrieve_slic_state(slic_id); | |
1148 | ||
1149 | return(err_mask); | |
1150 | } | |
1151 | ||
1152 | int test_dtmf(int slic_id) | |
1153 | { | |
1154 | unsigned char code; | |
1155 | unsigned char b; | |
1156 | unsigned int intreg; | |
1157 | int duslic_id = slic_id >> 1; | |
1158 | int channel = slic_id & 1; | |
1159 | ||
1160 | for (code = 0; code < 16; code++) { | |
1eaeb58e WD |
1161 | b = codsp_read_sop_char(duslic_id, channel, DSCR_ADDR); |
1162 | codsp_write_sop_char(duslic_id, channel, DSCR_ADDR, | |
1163 | (b & ~(DSCR_PTG | DSCR_DG_KEY(15))) | DSCR_DG_KEY(code) | DSCR_TG1_EN | DSCR_TG2_EN); | |
1164 | udelay(80000); | |
79fa88f3 WD |
1165 | |
1166 | intreg = codsp_read_sop_int(duslic_id, channel, INTREG1_ADDR); | |
1eaeb58e | 1167 | if ((intreg & CODSP_INTREG_INT_CH) == 0) |
79fa88f3 WD |
1168 | break; |
1169 | ||
1170 | if ((intreg & CODSP_INTREG_DTMF_OK) == 0 || | |
1171 | codsp_dtmf_map[(intreg >> 10) & 15] != codsp_dtmf_map[code]) | |
1172 | break; | |
1173 | ||
1eaeb58e WD |
1174 | b = codsp_read_sop_char(duslic_id, channel, DSCR_ADDR); |
1175 | codsp_write_sop_char(duslic_id, channel, DSCR_ADDR, | |
1176 | b & ~(DSCR_COR8 | DSCR_TG1_EN | DSCR_TG2_EN)); | |
79fa88f3 WD |
1177 | |
1178 | udelay(80000); | |
1179 | ||
1180 | intreg = codsp_read_sop_int(duslic_id, channel, INTREG1_ADDR); /* for dtmf_pause irq */ | |
1181 | } | |
1182 | ||
1183 | if (code != 16) { | |
1eaeb58e WD |
1184 | b = codsp_read_sop_char(duslic_id, channel, DSCR_ADDR); /* stop dtmf */ |
1185 | codsp_write_sop_char(duslic_id, channel, DSCR_ADDR, | |
1186 | b & ~(DSCR_COR8 | DSCR_TG1_EN | DSCR_TG2_EN)); | |
79fa88f3 WD |
1187 | return(1); |
1188 | } | |
1189 | ||
1190 | return(0); | |
1191 | } | |
1192 | ||
1193 | void data_up_persist_time(int duslic_id, int channel, int time_ms) | |
1194 | { | |
1195 | unsigned char b; | |
1196 | ||
1197 | b = codsp_read_sop_char(duslic_id, channel, IOCTL3_ADDR); | |
1198 | b = (b & 0x0F) | ((time_ms & 0x0F) << 4); | |
1199 | codsp_write_sop_char(duslic_id, channel, IOCTL3_ADDR, b); | |
1200 | } | |
1201 | ||
1202 | static void program_dtmf_params(int duslic_id, int channel) | |
1203 | { | |
1204 | unsigned char b; | |
1205 | ||
1206 | codsp_write_pop_char(duslic_id, channel, DTMF_LEV_ADDR, 0x10); | |
1207 | codsp_write_pop_char(duslic_id, channel, DTMF_TWI_ADDR, 0x0C); | |
1208 | codsp_write_pop_char(duslic_id, channel, DTMF_NCF_H_ADDR, 0x79); | |
1209 | codsp_write_pop_char(duslic_id, channel, DTMF_NCF_L_ADDR, 0x10); | |
1210 | codsp_write_pop_char(duslic_id, channel, DTMF_NBW_H_ADDR, 0x02); | |
1211 | codsp_write_pop_char(duslic_id, channel, DTMF_NBW_L_ADDR, 0xFB); | |
1212 | codsp_write_pop_char(duslic_id, channel, DTMF_GAIN_ADDR, 0x91); | |
1213 | codsp_write_pop_char(duslic_id, channel, DTMF_RES1_ADDR, 0x00); | |
1214 | codsp_write_pop_char(duslic_id, channel, DTMF_RES2_ADDR, 0x00); | |
1215 | codsp_write_pop_char(duslic_id, channel, DTMF_RES3_ADDR, 0x00); | |
1216 | ||
1217 | b = codsp_read_sop_char(duslic_id, channel, BCR5_ADDR); | |
1218 | codsp_write_sop_char(duslic_id, channel, BCR5_ADDR, b | BCR5_DTMF_EN); | |
1219 | } | |
1220 | ||
1221 | static void codsp_channel_full_reset(int duslic_id, int channel) | |
1222 | { | |
1223 | ||
1224 | program_coeffs(duslic_id, channel, ac_coeffs, sizeof(ac_coeffs) / sizeof(struct _coeffs)); | |
1225 | program_coeffs(duslic_id, channel, dc_coeffs, sizeof(dc_coeffs) / sizeof(struct _coeffs)); | |
1226 | ||
1227 | /* program basic configuration registers */ | |
1228 | codsp_write_sop_char(duslic_id, channel, BCR1_ADDR, 0x01); | |
1229 | codsp_write_sop_char(duslic_id, channel, BCR2_ADDR, 0x41); | |
1230 | codsp_write_sop_char(duslic_id, channel, BCR3_ADDR, 0x43); | |
1231 | codsp_write_sop_char(duslic_id, channel, BCR4_ADDR, 0x00); | |
1232 | codsp_write_sop_char(duslic_id, channel, BCR5_ADDR, 0x00); | |
1233 | ||
1234 | codsp_write_sop_char(duslic_id, channel, DSCR_ADDR, 0x04); /* PG */ | |
1235 | ||
1236 | program_dtmf_params(duslic_id, channel); | |
1237 | ||
1238 | codsp_write_sop_char(duslic_id, channel, LMCR3_ADDR, 0x40); /* RingTRip_SEL */ | |
1239 | ||
1240 | data_up_persist_time(duslic_id, channel, 4); | |
1241 | ||
1242 | codsp_write_sop_char(duslic_id, channel, MASK_ADDR, 0xFF); /* All interrupts masked */ | |
1243 | ||
1244 | codsp_set_slic(duslic_id, channel, SS_ACTIVE_HIGH); | |
1245 | } | |
1246 | ||
1247 | static int codsp_chip_full_reset(int duslic_id) | |
1248 | { | |
1249 | int i, cnt; | |
1250 | int intreg[NUM_CHANNELS]; | |
1251 | unsigned char pcm_resync; | |
1252 | unsigned char revision; | |
1253 | ||
1254 | codsp_reset_chip(duslic_id); | |
1255 | ||
1256 | udelay(2000); | |
1257 | ||
1258 | for (i = 0; i < NUM_CHANNELS; i++) | |
1259 | intreg[i] = codsp_read_sop_int(duslic_id, i, INTREG1_ADDR); | |
1260 | ||
1261 | udelay(1500); | |
1262 | ||
1263 | if (_PORTC_GET(com_hook_mask_tab[duslic_id]) == 0) { | |
1264 | printf("_HOOK(%d) stayed low\n", duslic_id); | |
1265 | return -1; | |
1266 | } | |
1267 | ||
1268 | for (pcm_resync = 0, i = 0; i < NUM_CHANNELS; i++) { | |
1269 | if (intreg[i] & CODSP_INTREG_SYNC_FAIL) | |
1270 | pcm_resync |= 1 << i; | |
1271 | } | |
1272 | ||
1273 | for (cnt = 0; cnt < 5 && pcm_resync; cnt++) { | |
1274 | for (i = 0; i < NUM_CHANNELS; i++) | |
1275 | codsp_resync_channel(duslic_id, i); | |
1276 | ||
1277 | udelay(2000); | |
1278 | ||
1279 | pcm_resync = 0; | |
1280 | ||
1281 | for (i = 0; i < NUM_CHANNELS; i++) { | |
1282 | if (codsp_read_sop_int(duslic_id, i, INTREG1_ADDR) & CODSP_INTREG_SYNC_FAIL) | |
1283 | pcm_resync |= 1 << i; | |
1284 | } | |
1285 | } | |
1286 | ||
1287 | if (cnt == 5) { | |
1eaeb58e | 1288 | printf("PCM_Resync(%u) not completed\n", duslic_id); |
79fa88f3 WD |
1289 | return -2; |
1290 | } | |
1291 | ||
1292 | revision = codsp_read_sop_char(duslic_id, 0, REVISION_ADDR); | |
1293 | printf("DuSLIC#%d hardware version %d.%d\r\n", duslic_id, (revision & 0xF0) >> 4, revision & 0x0F); | |
1294 | ||
1295 | codsp_write_sop_char(duslic_id, 0, XCR_ADDR, 0x80); /* EDSP_EN */ | |
1296 | ||
1297 | for (i = 0; i < NUM_CHANNELS; i++) { | |
1298 | codsp_write_sop_char(duslic_id, i, PCMC1_ADDR, 0x01); | |
1299 | codsp_channel_full_reset(duslic_id, i); | |
1300 | } | |
1301 | ||
1302 | return 0; | |
1303 | } | |
1304 | ||
1305 | int slic_self_test(int duslic_mask) | |
1306 | { | |
1307 | int slic; | |
1308 | int i; | |
1309 | int r; | |
1310 | long vdd, v_oh_H, v_oh_L, ring_mean_v, ring_rms_v; | |
1311 | const char *err_txt[] = { "VDD", "V_OH_H", "V_OH_L", "V_RING_MEAN", "V_RING_RMS" }; | |
1312 | int error = 0; | |
1313 | ||
1314 | for (slic = 0; slic < MAX_SLICS; slic++) { /* voltages self test */ | |
1315 | if (duslic_mask & (1 << (slic >> 1))) { | |
1316 | r = measure_on_hook_voltages(slic, &vdd, | |
1eaeb58e | 1317 | &v_oh_H, &v_oh_L, &ring_mean_v, &ring_rms_v); |
79fa88f3 WD |
1318 | |
1319 | printf("SLIC %u measured voltages (x100):\n\t" | |
1eaeb58e WD |
1320 | "VDD = %ld\tV_OH_H = %ld\tV_OH_L = %ld\tV_RING_MEAN = %ld\tV_RING_RMS = %ld\n", |
1321 | slic, vdd, v_oh_H, v_oh_L, ring_mean_v, ring_rms_v); | |
79fa88f3 WD |
1322 | |
1323 | if (r != 0) | |
1324 | error |= 1 << slic; | |
1325 | ||
1326 | for (i = 0; i < 5; i++) | |
1327 | if (r & (1 << i)) | |
1328 | printf("\t%s out of range\n", err_txt[i]); | |
1329 | } | |
1330 | } | |
1331 | ||
1332 | for (slic = 0; slic < MAX_SLICS; slic++) { /* voice path self test */ | |
1333 | if (duslic_mask & (1 << (slic >> 1))) { | |
1334 | printf("SLIC %u VOICE PATH...CHECKING", slic); | |
1335 | printf("\rSLIC %u VOICE PATH...%s\n", slic, | |
1336 | (r = test_dtmf(slic)) != 0 ? "FAILED " : "PASSED "); | |
1337 | ||
1338 | if (r != 0) | |
1339 | error |= 1 << slic; | |
1340 | } | |
1341 | } | |
1342 | ||
1343 | return(error); | |
1344 | } | |
1345 | ||
1346 | #if defined(CONFIG_NETTA_ISDN) | |
1347 | ||
1348 | #define SPIENS1 (1 << (31 - 15)) | |
1349 | #define SPIENS2 (1 << (31 - 19)) | |
1350 | ||
1351 | static const int spiens_mask_tab[2] = { SPIENS1, SPIENS2 }; | |
1352 | int s_initialized = 0; | |
1353 | ||
1354 | static inline unsigned int s_transfer_internal(int s_id, unsigned int address, unsigned int value) | |
1355 | { | |
1356 | unsigned int rx, v; | |
1357 | ||
1358 | _PORTB_SET(spiens_mask_tab[s_id], 0); | |
1359 | ||
1360 | rx = __SPI_Transfer(address); | |
1361 | ||
1362 | switch (address & 0xF0) { | |
1363 | case 0x60: /* write byte register */ | |
1364 | case 0x70: | |
1365 | rx = __SPI_Transfer(value); | |
1366 | break; | |
1367 | ||
1368 | case 0xE0: /* read R6 register */ | |
1369 | v = __SPI_Transfer(0); | |
1370 | ||
1371 | rx = (rx << 8) | v; | |
1372 | ||
1373 | break; | |
1374 | ||
1375 | case 0xF0: /* read byte register */ | |
1376 | rx = __SPI_Transfer(0); | |
1377 | ||
1378 | break; | |
1379 | } | |
1380 | ||
1381 | _PORTB_SET(spiens_mask_tab[s_id], 1); | |
1382 | ||
1383 | return rx; | |
1384 | } | |
1385 | ||
1386 | static void s_write_BR(int s_id, unsigned int regno, unsigned int val) | |
1387 | { | |
1388 | unsigned int address; | |
1389 | unsigned int v; | |
1390 | ||
1391 | address = 0x70 | (regno & 15); | |
1392 | val &= 0xff; | |
1393 | ||
1394 | v = s_transfer_internal(s_id, address, val); | |
1395 | } | |
1396 | ||
1397 | static void s_write_OR(int s_id, unsigned int regno, unsigned int val) | |
1398 | { | |
1399 | unsigned int address; | |
1400 | unsigned int v; | |
1401 | ||
1402 | address = 0x70 | (regno & 15); | |
1403 | val &= 0xff; | |
1404 | ||
1405 | v = s_transfer_internal(s_id, address, val); | |
1406 | } | |
1407 | ||
1408 | static void s_write_NR(int s_id, unsigned int regno, unsigned int val) | |
1409 | { | |
1410 | unsigned int address; | |
1411 | unsigned int v; | |
1412 | ||
1413 | address = (regno & 7) << 4; | |
1414 | val &= 0xf; | |
1415 | ||
1416 | v = s_transfer_internal(s_id, address | val, 0x00); | |
1417 | } | |
1418 | ||
1419 | #define BR7_IFR 0x08 /* IDL2 free run */ | |
1420 | #define BR7_ICSLSB 0x04 /* IDL2 clock speed LSB */ | |
1421 | ||
1422 | #define BR15_OVRL_REG_EN 0x80 | |
1423 | #define OR7_D3VR 0x80 /* disable 3V regulator */ | |
1424 | ||
1425 | #define OR8_TEME 0x10 /* TE mode enable */ | |
1426 | #define OR8_MME 0x08 /* master mode enable */ | |
1427 | ||
1428 | void s_initialize(void) | |
1429 | { | |
1430 | int s_id; | |
1431 | ||
1432 | for (s_id = 0; s_id < 2; s_id++) { | |
1433 | s_write_BR(s_id, 7, BR7_IFR | BR7_ICSLSB); | |
1434 | s_write_BR(s_id, 15, BR15_OVRL_REG_EN); | |
1435 | s_write_OR(s_id, 8, OR8_TEME | OR8_MME); | |
1436 | s_write_OR(s_id, 7, OR7_D3VR); | |
1437 | s_write_OR(s_id, 6, 0); | |
1438 | s_write_BR(s_id, 15, 0); | |
1439 | s_write_NR(s_id, 3, 0); | |
1440 | } | |
1441 | } | |
1442 | ||
1443 | #endif | |
1444 | ||
1445 | int board_post_codec(int flags) | |
1446 | { | |
1447 | int j; | |
1448 | int r; | |
1449 | int duslic_mask; | |
1450 | ||
1451 | printf("board_post_dsp\n"); | |
1452 | ||
1453 | #if defined(CONFIG_NETTA_ISDN) | |
1454 | if (s_initialized == 0) { | |
1455 | s_initialize(); | |
1456 | s_initialized = 1; | |
1457 | ||
1458 | printf("s_initialized\n"); | |
1459 | ||
1460 | udelay(20000); | |
1461 | } | |
1462 | #endif | |
1463 | duslic_mask = 0; | |
1464 | ||
1465 | for (j = 0; j < MAX_DUSLIC; j++) { | |
1466 | if (codsp_chip_full_reset(j) < 0) | |
1467 | printf("Error initializing DuSLIC#%d\n", j); | |
1468 | else | |
1469 | duslic_mask |= 1 << j; | |
1470 | } | |
1471 | ||
1472 | if (duslic_mask != 0) { | |
1473 | printf("Testing SLICs...\n"); | |
1474 | ||
1475 | r = slic_self_test(duslic_mask); | |
1476 | for (j = 0; j < MAX_SLICS; j++) { | |
1477 | if (duslic_mask & (1 << (j >> 1))) | |
1478 | printf("SLIC %u...%s\n", j, r & (1 << j) ? "FAULTY" : "OK"); | |
1479 | } | |
1480 | } | |
1481 | printf("DuSLIC self test finished\n"); | |
1482 | ||
1483 | return 0; /* return -1 on error */ | |
1484 | } |