diff options
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r-- | drivers/media/video/cx25840/Kconfig | 8 | ||||
-rw-r--r-- | drivers/media/video/cx25840/Makefile | 6 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-audio.c | 571 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 2071 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.h | 137 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-firmware.c | 166 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-ir.c | 1280 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-vbi.c | 256 |
8 files changed, 4495 insertions, 0 deletions
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig new file mode 100644 index 00000000000..451133ad41f --- /dev/null +++ b/drivers/media/video/cx25840/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | config VIDEO_CX25840 | ||
2 | tristate "Conexant CX2584x audio/video decoders" | ||
3 | depends on VIDEO_V4L2 && I2C | ||
4 | ---help--- | ||
5 | Support for the Conexant CX2584x audio/video decoders. | ||
6 | |||
7 | To compile this driver as a module, choose M here: the | ||
8 | module will be called cx25840 | ||
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile new file mode 100644 index 00000000000..2ee96d3973b --- /dev/null +++ b/drivers/media/video/cx25840/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ | ||
2 | cx25840-vbi.o cx25840-ir.o | ||
3 | |||
4 | obj-$(CONFIG_VIDEO_CX25840) += cx25840.o | ||
5 | |||
6 | EXTRA_CFLAGS += -Idrivers/media/video | ||
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c new file mode 100644 index 00000000000..34b96c7cfd6 --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-audio.c | |||
@@ -0,0 +1,571 @@ | |||
1 | /* cx25840 audio functions | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of the GNU General Public License | ||
5 | * as published by the Free Software Foundation; either version 2 | ||
6 | * of the License, or (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/videodev2.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <media/v4l2-common.h> | ||
22 | #include <media/cx25840.h> | ||
23 | |||
24 | #include "cx25840-core.h" | ||
25 | |||
26 | /* | ||
27 | * Note: The PLL and SRC parameters are based on a reference frequency that | ||
28 | * would ideally be: | ||
29 | * | ||
30 | * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz | ||
31 | * | ||
32 | * However, it's not the exact reference frequency that matters, only that the | ||
33 | * firmware and modules that comprise the driver for a particular board all | ||
34 | * use the same value (close to the ideal value). | ||
35 | * | ||
36 | * Comments below will note which reference frequency is assumed for various | ||
37 | * parameters. They will usually be one of | ||
38 | * | ||
39 | * ref_freq = 28.636360 MHz | ||
40 | * or | ||
41 | * ref_freq = 28.636363 MHz | ||
42 | */ | ||
43 | |||
44 | static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
45 | { | ||
46 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
47 | |||
48 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | ||
49 | switch (freq) { | ||
50 | case 32000: | ||
51 | /* | ||
52 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 | ||
53 | * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10 | ||
54 | */ | ||
55 | cx25840_write4(client, 0x108, 0x1006040f); | ||
56 | |||
57 | /* | ||
58 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
59 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
60 | * 432 MHz pre-postdivide | ||
61 | */ | ||
62 | |||
63 | /* | ||
64 | * AUX_PLL Fraction = 0x1bb39ee | ||
65 | * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384 | ||
66 | * 196.6 MHz pre-postdivide | ||
67 | * FIXME < 200 MHz is out of specified valid range | ||
68 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
69 | */ | ||
70 | cx25840_write4(client, 0x110, 0x01bb39ee); | ||
71 | |||
72 | /* | ||
73 | * SA_MCLK_SEL = 1 | ||
74 | * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider | ||
75 | */ | ||
76 | cx25840_write(client, 0x127, 0x50); | ||
77 | |||
78 | if (is_cx2583x(state)) | ||
79 | break; | ||
80 | |||
81 | /* src3/4/6_ctl */ | ||
82 | /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ | ||
83 | cx25840_write4(client, 0x900, 0x0801f77f); | ||
84 | cx25840_write4(client, 0x904, 0x0801f77f); | ||
85 | cx25840_write4(client, 0x90c, 0x0801f77f); | ||
86 | break; | ||
87 | |||
88 | case 44100: | ||
89 | /* | ||
90 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 | ||
91 | * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10 | ||
92 | */ | ||
93 | cx25840_write4(client, 0x108, 0x1009040f); | ||
94 | |||
95 | /* | ||
96 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
97 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
98 | * 432 MHz pre-postdivide | ||
99 | */ | ||
100 | |||
101 | /* | ||
102 | * AUX_PLL Fraction = 0x0ec6bd6 | ||
103 | * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384 | ||
104 | * 271 MHz pre-postdivide | ||
105 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
106 | */ | ||
107 | cx25840_write4(client, 0x110, 0x00ec6bd6); | ||
108 | |||
109 | /* | ||
110 | * SA_MCLK_SEL = 1 | ||
111 | * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider | ||
112 | */ | ||
113 | cx25840_write(client, 0x127, 0x50); | ||
114 | |||
115 | if (is_cx2583x(state)) | ||
116 | break; | ||
117 | |||
118 | /* src3/4/6_ctl */ | ||
119 | /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ | ||
120 | cx25840_write4(client, 0x900, 0x08016d59); | ||
121 | cx25840_write4(client, 0x904, 0x08016d59); | ||
122 | cx25840_write4(client, 0x90c, 0x08016d59); | ||
123 | break; | ||
124 | |||
125 | case 48000: | ||
126 | /* | ||
127 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 | ||
128 | * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10 | ||
129 | */ | ||
130 | cx25840_write4(client, 0x108, 0x100a040f); | ||
131 | |||
132 | /* | ||
133 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
134 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
135 | * 432 MHz pre-postdivide | ||
136 | */ | ||
137 | |||
138 | /* | ||
139 | * AUX_PLL Fraction = 0x098d6e5 | ||
140 | * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384 | ||
141 | * 295 MHz pre-postdivide | ||
142 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
143 | */ | ||
144 | cx25840_write4(client, 0x110, 0x0098d6e5); | ||
145 | |||
146 | /* | ||
147 | * SA_MCLK_SEL = 1 | ||
148 | * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider | ||
149 | */ | ||
150 | cx25840_write(client, 0x127, 0x50); | ||
151 | |||
152 | if (is_cx2583x(state)) | ||
153 | break; | ||
154 | |||
155 | /* src3/4/6_ctl */ | ||
156 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
157 | cx25840_write4(client, 0x900, 0x08014faa); | ||
158 | cx25840_write4(client, 0x904, 0x08014faa); | ||
159 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
160 | break; | ||
161 | } | ||
162 | } else { | ||
163 | switch (freq) { | ||
164 | case 32000: | ||
165 | /* | ||
166 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 | ||
167 | * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e | ||
168 | */ | ||
169 | cx25840_write4(client, 0x108, 0x1e08040f); | ||
170 | |||
171 | /* | ||
172 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
173 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
174 | * 432 MHz pre-postdivide | ||
175 | */ | ||
176 | |||
177 | /* | ||
178 | * AUX_PLL Fraction = 0x12a0869 | ||
179 | * 28636363 * 0x8.9504348/0x1e = 32000 * 256 | ||
180 | * 246 MHz pre-postdivide | ||
181 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
182 | */ | ||
183 | cx25840_write4(client, 0x110, 0x012a0869); | ||
184 | |||
185 | /* | ||
186 | * SA_MCLK_SEL = 1 | ||
187 | * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider | ||
188 | */ | ||
189 | cx25840_write(client, 0x127, 0x54); | ||
190 | |||
191 | if (is_cx2583x(state)) | ||
192 | break; | ||
193 | |||
194 | /* src1_ctl */ | ||
195 | /* 0x1.0000 = 32000/32000 */ | ||
196 | cx25840_write4(client, 0x8f8, 0x08010000); | ||
197 | |||
198 | /* src3/4/6_ctl */ | ||
199 | /* 0x2.0000 = 2 * (32000/32000) */ | ||
200 | cx25840_write4(client, 0x900, 0x08020000); | ||
201 | cx25840_write4(client, 0x904, 0x08020000); | ||
202 | cx25840_write4(client, 0x90c, 0x08020000); | ||
203 | break; | ||
204 | |||
205 | case 44100: | ||
206 | /* | ||
207 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 | ||
208 | * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18 | ||
209 | */ | ||
210 | cx25840_write4(client, 0x108, 0x1809040f); | ||
211 | |||
212 | /* | ||
213 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
214 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
215 | * 432 MHz pre-postdivide | ||
216 | */ | ||
217 | |||
218 | /* | ||
219 | * AUX_PLL Fraction = 0x0ec6bd6 | ||
220 | * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256 | ||
221 | * 271 MHz pre-postdivide | ||
222 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
223 | */ | ||
224 | cx25840_write4(client, 0x110, 0x00ec6bd6); | ||
225 | |||
226 | /* | ||
227 | * SA_MCLK_SEL = 1 | ||
228 | * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider | ||
229 | */ | ||
230 | cx25840_write(client, 0x127, 0x50); | ||
231 | |||
232 | if (is_cx2583x(state)) | ||
233 | break; | ||
234 | |||
235 | /* src1_ctl */ | ||
236 | /* 0x1.60cd = 44100/32000 */ | ||
237 | cx25840_write4(client, 0x8f8, 0x080160cd); | ||
238 | |||
239 | /* src3/4/6_ctl */ | ||
240 | /* 0x1.7385 = 2 * (32000/44100) */ | ||
241 | cx25840_write4(client, 0x900, 0x08017385); | ||
242 | cx25840_write4(client, 0x904, 0x08017385); | ||
243 | cx25840_write4(client, 0x90c, 0x08017385); | ||
244 | break; | ||
245 | |||
246 | case 48000: | ||
247 | /* | ||
248 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 | ||
249 | * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18 | ||
250 | */ | ||
251 | cx25840_write4(client, 0x108, 0x180a040f); | ||
252 | |||
253 | /* | ||
254 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
255 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
256 | * 432 MHz pre-postdivide | ||
257 | */ | ||
258 | |||
259 | /* | ||
260 | * AUX_PLL Fraction = 0x098d6e5 | ||
261 | * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256 | ||
262 | * 295 MHz pre-postdivide | ||
263 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
264 | */ | ||
265 | cx25840_write4(client, 0x110, 0x0098d6e5); | ||
266 | |||
267 | /* | ||
268 | * SA_MCLK_SEL = 1 | ||
269 | * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider | ||
270 | */ | ||
271 | cx25840_write(client, 0x127, 0x50); | ||
272 | |||
273 | if (is_cx2583x(state)) | ||
274 | break; | ||
275 | |||
276 | /* src1_ctl */ | ||
277 | /* 0x1.8000 = 48000/32000 */ | ||
278 | cx25840_write4(client, 0x8f8, 0x08018000); | ||
279 | |||
280 | /* src3/4/6_ctl */ | ||
281 | /* 0x1.5555 = 2 * (32000/48000) */ | ||
282 | cx25840_write4(client, 0x900, 0x08015555); | ||
283 | cx25840_write4(client, 0x904, 0x08015555); | ||
284 | cx25840_write4(client, 0x90c, 0x08015555); | ||
285 | break; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | state->audclk_freq = freq; | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
295 | { | ||
296 | return cx25840_set_audclk_freq(client, freq); | ||
297 | } | ||
298 | |||
299 | static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
300 | { | ||
301 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
302 | |||
303 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | ||
304 | switch (freq) { | ||
305 | case 32000: | ||
306 | case 44100: | ||
307 | case 48000: | ||
308 | /* We don't have register values | ||
309 | * so avoid destroying registers. */ | ||
310 | /* FIXME return -EINVAL; */ | ||
311 | break; | ||
312 | } | ||
313 | } else { | ||
314 | switch (freq) { | ||
315 | case 32000: | ||
316 | case 44100: | ||
317 | /* We don't have register values | ||
318 | * so avoid destroying registers. */ | ||
319 | /* FIXME return -EINVAL; */ | ||
320 | break; | ||
321 | |||
322 | case 48000: | ||
323 | /* src1_ctl */ | ||
324 | /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ | ||
325 | cx25840_write4(client, 0x8f8, 0x0801867c); | ||
326 | |||
327 | /* src3/4/6_ctl */ | ||
328 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
329 | cx25840_write4(client, 0x900, 0x08014faa); | ||
330 | cx25840_write4(client, 0x904, 0x08014faa); | ||
331 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | state->audclk_freq = freq; | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
342 | { | ||
343 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
344 | |||
345 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | ||
346 | switch (freq) { | ||
347 | case 32000: | ||
348 | /* src3/4/6_ctl */ | ||
349 | /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ | ||
350 | cx25840_write4(client, 0x900, 0x0801f77f); | ||
351 | cx25840_write4(client, 0x904, 0x0801f77f); | ||
352 | cx25840_write4(client, 0x90c, 0x0801f77f); | ||
353 | break; | ||
354 | |||
355 | case 44100: | ||
356 | /* src3/4/6_ctl */ | ||
357 | /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ | ||
358 | cx25840_write4(client, 0x900, 0x08016d59); | ||
359 | cx25840_write4(client, 0x904, 0x08016d59); | ||
360 | cx25840_write4(client, 0x90c, 0x08016d59); | ||
361 | break; | ||
362 | |||
363 | case 48000: | ||
364 | /* src3/4/6_ctl */ | ||
365 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
366 | cx25840_write4(client, 0x900, 0x08014faa); | ||
367 | cx25840_write4(client, 0x904, 0x08014faa); | ||
368 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
369 | break; | ||
370 | } | ||
371 | } else { | ||
372 | switch (freq) { | ||
373 | /* FIXME These cases make different assumptions about audclk */ | ||
374 | case 32000: | ||
375 | /* src1_ctl */ | ||
376 | /* 0x1.0000 = 32000/32000 */ | ||
377 | cx25840_write4(client, 0x8f8, 0x08010000); | ||
378 | |||
379 | /* src3/4/6_ctl */ | ||
380 | /* 0x2.0000 = 2 * (32000/32000) */ | ||
381 | cx25840_write4(client, 0x900, 0x08020000); | ||
382 | cx25840_write4(client, 0x904, 0x08020000); | ||
383 | cx25840_write4(client, 0x90c, 0x08020000); | ||
384 | break; | ||
385 | |||
386 | case 44100: | ||
387 | /* src1_ctl */ | ||
388 | /* 0x1.60cd = 44100/32000 */ | ||
389 | cx25840_write4(client, 0x8f8, 0x080160cd); | ||
390 | |||
391 | /* src3/4/6_ctl */ | ||
392 | /* 0x1.7385 = 2 * (32000/44100) */ | ||
393 | cx25840_write4(client, 0x900, 0x08017385); | ||
394 | cx25840_write4(client, 0x904, 0x08017385); | ||
395 | cx25840_write4(client, 0x90c, 0x08017385); | ||
396 | break; | ||
397 | |||
398 | case 48000: | ||
399 | /* src1_ctl */ | ||
400 | /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ | ||
401 | cx25840_write4(client, 0x8f8, 0x0801867c); | ||
402 | |||
403 | /* src3/4/6_ctl */ | ||
404 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
405 | cx25840_write4(client, 0x900, 0x08014faa); | ||
406 | cx25840_write4(client, 0x904, 0x08014faa); | ||
407 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | state->audclk_freq = freq; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int set_audclk_freq(struct i2c_client *client, u32 freq) | ||
418 | { | ||
419 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
420 | |||
421 | if (freq != 32000 && freq != 44100 && freq != 48000) | ||
422 | return -EINVAL; | ||
423 | |||
424 | if (is_cx231xx(state)) | ||
425 | return cx231xx_set_audclk_freq(client, freq); | ||
426 | |||
427 | if (is_cx2388x(state)) | ||
428 | return cx23885_set_audclk_freq(client, freq); | ||
429 | |||
430 | if (is_cx2583x(state)) | ||
431 | return cx25836_set_audclk_freq(client, freq); | ||
432 | |||
433 | return cx25840_set_audclk_freq(client, freq); | ||
434 | } | ||
435 | |||
436 | void cx25840_audio_set_path(struct i2c_client *client) | ||
437 | { | ||
438 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
439 | |||
440 | if (!is_cx2583x(state)) { | ||
441 | /* assert soft reset */ | ||
442 | cx25840_and_or(client, 0x810, ~0x1, 0x01); | ||
443 | |||
444 | /* stop microcontroller */ | ||
445 | cx25840_and_or(client, 0x803, ~0x10, 0); | ||
446 | |||
447 | /* Mute everything to prevent the PFFT! */ | ||
448 | cx25840_write(client, 0x8d3, 0x1f); | ||
449 | |||
450 | if (state->aud_input == CX25840_AUDIO_SERIAL) { | ||
451 | /* Set Path1 to Serial Audio Input */ | ||
452 | cx25840_write4(client, 0x8d0, 0x01011012); | ||
453 | |||
454 | /* The microcontroller should not be started for the | ||
455 | * non-tuner inputs: autodetection is specific for | ||
456 | * TV audio. */ | ||
457 | } else { | ||
458 | /* Set Path1 to Analog Demod Main Channel */ | ||
459 | cx25840_write4(client, 0x8d0, 0x1f063870); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | set_audclk_freq(client, state->audclk_freq); | ||
464 | |||
465 | if (!is_cx2583x(state)) { | ||
466 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | ||
467 | /* When the microcontroller detects the | ||
468 | * audio format, it will unmute the lines */ | ||
469 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
470 | } | ||
471 | |||
472 | /* deassert soft reset */ | ||
473 | cx25840_and_or(client, 0x810, ~0x1, 0x00); | ||
474 | |||
475 | /* Ensure the controller is running when we exit */ | ||
476 | if (is_cx2388x(state) || is_cx231xx(state)) | ||
477 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
478 | } | ||
479 | } | ||
480 | |||
481 | static void set_volume(struct i2c_client *client, int volume) | ||
482 | { | ||
483 | int vol; | ||
484 | |||
485 | /* Convert the volume to msp3400 values (0-127) */ | ||
486 | vol = volume >> 9; | ||
487 | |||
488 | /* now scale it up to cx25840 values | ||
489 | * -114dB to -96dB maps to 0 | ||
490 | * this should be 19, but in my testing that was 4dB too loud */ | ||
491 | if (vol <= 23) { | ||
492 | vol = 0; | ||
493 | } else { | ||
494 | vol -= 23; | ||
495 | } | ||
496 | |||
497 | /* PATH1_VOLUME */ | ||
498 | cx25840_write(client, 0x8d4, 228 - (vol * 2)); | ||
499 | } | ||
500 | |||
501 | static void set_balance(struct i2c_client *client, int balance) | ||
502 | { | ||
503 | int bal = balance >> 8; | ||
504 | if (bal > 0x80) { | ||
505 | /* PATH1_BAL_LEFT */ | ||
506 | cx25840_and_or(client, 0x8d5, 0x7f, 0x80); | ||
507 | /* PATH1_BAL_LEVEL */ | ||
508 | cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f); | ||
509 | } else { | ||
510 | /* PATH1_BAL_LEFT */ | ||
511 | cx25840_and_or(client, 0x8d5, 0x7f, 0x00); | ||
512 | /* PATH1_BAL_LEVEL */ | ||
513 | cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal); | ||
514 | } | ||
515 | } | ||
516 | |||
517 | int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq) | ||
518 | { | ||
519 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
520 | struct cx25840_state *state = to_state(sd); | ||
521 | int retval; | ||
522 | |||
523 | if (!is_cx2583x(state)) | ||
524 | cx25840_and_or(client, 0x810, ~0x1, 1); | ||
525 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | ||
526 | cx25840_and_or(client, 0x803, ~0x10, 0); | ||
527 | cx25840_write(client, 0x8d3, 0x1f); | ||
528 | } | ||
529 | retval = set_audclk_freq(client, freq); | ||
530 | if (state->aud_input != CX25840_AUDIO_SERIAL) | ||
531 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
532 | if (!is_cx2583x(state)) | ||
533 | cx25840_and_or(client, 0x810, ~0x1, 0); | ||
534 | return retval; | ||
535 | } | ||
536 | |||
537 | static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl) | ||
538 | { | ||
539 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
540 | struct cx25840_state *state = to_state(sd); | ||
541 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
542 | |||
543 | switch (ctrl->id) { | ||
544 | case V4L2_CID_AUDIO_VOLUME: | ||
545 | if (state->mute->val) | ||
546 | set_volume(client, 0); | ||
547 | else | ||
548 | set_volume(client, state->volume->val); | ||
549 | break; | ||
550 | case V4L2_CID_AUDIO_BASS: | ||
551 | /* PATH1_EQ_BASS_VOL */ | ||
552 | cx25840_and_or(client, 0x8d9, ~0x3f, | ||
553 | 48 - (ctrl->val * 48 / 0xffff)); | ||
554 | break; | ||
555 | case V4L2_CID_AUDIO_TREBLE: | ||
556 | /* PATH1_EQ_TREBLE_VOL */ | ||
557 | cx25840_and_or(client, 0x8db, ~0x3f, | ||
558 | 48 - (ctrl->val * 48 / 0xffff)); | ||
559 | break; | ||
560 | case V4L2_CID_AUDIO_BALANCE: | ||
561 | set_balance(client, ctrl->val); | ||
562 | break; | ||
563 | default: | ||
564 | return -EINVAL; | ||
565 | } | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = { | ||
570 | .s_ctrl = cx25840_audio_s_ctrl, | ||
571 | }; | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c new file mode 100644 index 00000000000..b7ee2ae7058 --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -0,0 +1,2071 @@ | |||
1 | /* cx25840 - Conexant CX25840 audio/video decoder driver | ||
2 | * | ||
3 | * Copyright (C) 2004 Ulf Eklund | ||
4 | * | ||
5 | * Based on the saa7115 driver and on the first version of Chris Kennedy's | ||
6 | * cx25840 driver. | ||
7 | * | ||
8 | * Changes by Tyler Trafford <tatrafford@comcast.net> | ||
9 | * - cleanup/rewrite for V4L2 API (2005) | ||
10 | * | ||
11 | * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. | ||
12 | * | ||
13 | * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> | ||
14 | * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. | ||
15 | * | ||
16 | * CX23885 support by Steven Toth <stoth@linuxtv.org>. | ||
17 | * | ||
18 | * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are | ||
19 | * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> | ||
20 | * | ||
21 | * This program is free software; you can redistribute it and/or | ||
22 | * modify it under the terms of the GNU General Public License | ||
23 | * as published by the Free Software Foundation; either version 2 | ||
24 | * of the License, or (at your option) any later version. | ||
25 | * | ||
26 | * This program is distributed in the hope that it will be useful, | ||
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | * GNU General Public License for more details. | ||
30 | * | ||
31 | * You should have received a copy of the GNU General Public License | ||
32 | * along with this program; if not, write to the Free Software | ||
33 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
34 | */ | ||
35 | |||
36 | |||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/videodev2.h> | ||
41 | #include <linux/i2c.h> | ||
42 | #include <linux/delay.h> | ||
43 | #include <media/v4l2-common.h> | ||
44 | #include <media/v4l2-chip-ident.h> | ||
45 | #include <media/cx25840.h> | ||
46 | |||
47 | #include "cx25840-core.h" | ||
48 | |||
49 | MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver"); | ||
50 | MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); | ||
51 | MODULE_LICENSE("GPL"); | ||
52 | |||
53 | #define CX25840_VID_INT_STAT_REG 0x410 | ||
54 | #define CX25840_VID_INT_STAT_BITS 0x0000ffff | ||
55 | #define CX25840_VID_INT_MASK_BITS 0xffff0000 | ||
56 | #define CX25840_VID_INT_MASK_SHFT 16 | ||
57 | #define CX25840_VID_INT_MASK_REG 0x412 | ||
58 | |||
59 | #define CX23885_AUD_MC_INT_MASK_REG 0x80c | ||
60 | #define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000 | ||
61 | #define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff | ||
62 | #define CX23885_AUD_MC_INT_STAT_SHFT 16 | ||
63 | |||
64 | #define CX25840_AUD_INT_CTRL_REG 0x812 | ||
65 | #define CX25840_AUD_INT_STAT_REG 0x813 | ||
66 | |||
67 | #define CX23885_PIN_CTRL_IRQ_REG 0x123 | ||
68 | #define CX23885_PIN_CTRL_IRQ_IR_STAT 0x40 | ||
69 | #define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20 | ||
70 | #define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10 | ||
71 | |||
72 | #define CX25840_IR_STATS_REG 0x210 | ||
73 | #define CX25840_IR_IRQEN_REG 0x214 | ||
74 | |||
75 | static int cx25840_debug; | ||
76 | |||
77 | module_param_named(debug,cx25840_debug, int, 0644); | ||
78 | |||
79 | MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); | ||
80 | |||
81 | |||
82 | /* ----------------------------------------------------------------------- */ | ||
83 | |||
84 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value) | ||
85 | { | ||
86 | u8 buffer[3]; | ||
87 | buffer[0] = addr >> 8; | ||
88 | buffer[1] = addr & 0xff; | ||
89 | buffer[2] = value; | ||
90 | return i2c_master_send(client, buffer, 3); | ||
91 | } | ||
92 | |||
93 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) | ||
94 | { | ||
95 | u8 buffer[6]; | ||
96 | buffer[0] = addr >> 8; | ||
97 | buffer[1] = addr & 0xff; | ||
98 | buffer[2] = value & 0xff; | ||
99 | buffer[3] = (value >> 8) & 0xff; | ||
100 | buffer[4] = (value >> 16) & 0xff; | ||
101 | buffer[5] = value >> 24; | ||
102 | return i2c_master_send(client, buffer, 6); | ||
103 | } | ||
104 | |||
105 | u8 cx25840_read(struct i2c_client * client, u16 addr) | ||
106 | { | ||
107 | struct i2c_msg msgs[2]; | ||
108 | u8 tx_buf[2], rx_buf[1]; | ||
109 | |||
110 | /* Write register address */ | ||
111 | tx_buf[0] = addr >> 8; | ||
112 | tx_buf[1] = addr & 0xff; | ||
113 | msgs[0].addr = client->addr; | ||
114 | msgs[0].flags = 0; | ||
115 | msgs[0].len = 2; | ||
116 | msgs[0].buf = (char *) tx_buf; | ||
117 | |||
118 | /* Read data from register */ | ||
119 | msgs[1].addr = client->addr; | ||
120 | msgs[1].flags = I2C_M_RD; | ||
121 | msgs[1].len = 1; | ||
122 | msgs[1].buf = (char *) rx_buf; | ||
123 | |||
124 | if (i2c_transfer(client->adapter, msgs, 2) < 2) | ||
125 | return 0; | ||
126 | |||
127 | return rx_buf[0]; | ||
128 | } | ||
129 | |||
130 | u32 cx25840_read4(struct i2c_client * client, u16 addr) | ||
131 | { | ||
132 | struct i2c_msg msgs[2]; | ||
133 | u8 tx_buf[2], rx_buf[4]; | ||
134 | |||
135 | /* Write register address */ | ||
136 | tx_buf[0] = addr >> 8; | ||
137 | tx_buf[1] = addr & 0xff; | ||
138 | msgs[0].addr = client->addr; | ||
139 | msgs[0].flags = 0; | ||
140 | msgs[0].len = 2; | ||
141 | msgs[0].buf = (char *) tx_buf; | ||
142 | |||
143 | /* Read data from registers */ | ||
144 | msgs[1].addr = client->addr; | ||
145 | msgs[1].flags = I2C_M_RD; | ||
146 | msgs[1].len = 4; | ||
147 | msgs[1].buf = (char *) rx_buf; | ||
148 | |||
149 | if (i2c_transfer(client->adapter, msgs, 2) < 2) | ||
150 | return 0; | ||
151 | |||
152 | return (rx_buf[3] << 24) | (rx_buf[2] << 16) | (rx_buf[1] << 8) | | ||
153 | rx_buf[0]; | ||
154 | } | ||
155 | |||
156 | int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, | ||
157 | u8 or_value) | ||
158 | { | ||
159 | return cx25840_write(client, addr, | ||
160 | (cx25840_read(client, addr) & and_mask) | | ||
161 | or_value); | ||
162 | } | ||
163 | |||
164 | int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, | ||
165 | u32 or_value) | ||
166 | { | ||
167 | return cx25840_write4(client, addr, | ||
168 | (cx25840_read4(client, addr) & and_mask) | | ||
169 | or_value); | ||
170 | } | ||
171 | |||
172 | /* ----------------------------------------------------------------------- */ | ||
173 | |||
174 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, | ||
175 | enum cx25840_audio_input aud_input); | ||
176 | |||
177 | /* ----------------------------------------------------------------------- */ | ||
178 | |||
179 | static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, | ||
180 | struct v4l2_subdev_io_pin_config *p) | ||
181 | { | ||
182 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
183 | int i; | ||
184 | u32 pin_ctrl; | ||
185 | u8 gpio_oe, gpio_data, strength; | ||
186 | |||
187 | pin_ctrl = cx25840_read4(client, 0x120); | ||
188 | gpio_oe = cx25840_read(client, 0x160); | ||
189 | gpio_data = cx25840_read(client, 0x164); | ||
190 | |||
191 | for (i = 0; i < n; i++) { | ||
192 | strength = p[i].strength; | ||
193 | if (strength > CX25840_PIN_DRIVE_FAST) | ||
194 | strength = CX25840_PIN_DRIVE_FAST; | ||
195 | |||
196 | switch (p[i].pin) { | ||
197 | case CX23885_PIN_IRQ_N_GPIO16: | ||
198 | if (p[i].function != CX23885_PAD_IRQ_N) { | ||
199 | /* GPIO16 */ | ||
200 | pin_ctrl &= ~(0x1 << 25); | ||
201 | } else { | ||
202 | /* IRQ_N */ | ||
203 | if (p[i].flags & | ||
204 | (V4L2_SUBDEV_IO_PIN_DISABLE | | ||
205 | V4L2_SUBDEV_IO_PIN_INPUT)) { | ||
206 | pin_ctrl &= ~(0x1 << 25); | ||
207 | } else { | ||
208 | pin_ctrl |= (0x1 << 25); | ||
209 | } | ||
210 | if (p[i].flags & | ||
211 | V4L2_SUBDEV_IO_PIN_ACTIVE_LOW) { | ||
212 | pin_ctrl &= ~(0x1 << 24); | ||
213 | } else { | ||
214 | pin_ctrl |= (0x1 << 24); | ||
215 | } | ||
216 | } | ||
217 | break; | ||
218 | case CX23885_PIN_IR_RX_GPIO19: | ||
219 | if (p[i].function != CX23885_PAD_GPIO19) { | ||
220 | /* IR_RX */ | ||
221 | gpio_oe |= (0x1 << 0); | ||
222 | pin_ctrl &= ~(0x3 << 18); | ||
223 | pin_ctrl |= (strength << 18); | ||
224 | } else { | ||
225 | /* GPIO19 */ | ||
226 | gpio_oe &= ~(0x1 << 0); | ||
227 | if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { | ||
228 | gpio_data &= ~(0x1 << 0); | ||
229 | gpio_data |= ((p[i].value & 0x1) << 0); | ||
230 | } | ||
231 | pin_ctrl &= ~(0x3 << 12); | ||
232 | pin_ctrl |= (strength << 12); | ||
233 | } | ||
234 | break; | ||
235 | case CX23885_PIN_IR_TX_GPIO20: | ||
236 | if (p[i].function != CX23885_PAD_GPIO20) { | ||
237 | /* IR_TX */ | ||
238 | gpio_oe |= (0x1 << 1); | ||
239 | if (p[i].flags & V4L2_SUBDEV_IO_PIN_DISABLE) | ||
240 | pin_ctrl &= ~(0x1 << 10); | ||
241 | else | ||
242 | pin_ctrl |= (0x1 << 10); | ||
243 | pin_ctrl &= ~(0x3 << 18); | ||
244 | pin_ctrl |= (strength << 18); | ||
245 | } else { | ||
246 | /* GPIO20 */ | ||
247 | gpio_oe &= ~(0x1 << 1); | ||
248 | if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { | ||
249 | gpio_data &= ~(0x1 << 1); | ||
250 | gpio_data |= ((p[i].value & 0x1) << 1); | ||
251 | } | ||
252 | pin_ctrl &= ~(0x3 << 12); | ||
253 | pin_ctrl |= (strength << 12); | ||
254 | } | ||
255 | break; | ||
256 | case CX23885_PIN_I2S_SDAT_GPIO21: | ||
257 | if (p[i].function != CX23885_PAD_GPIO21) { | ||
258 | /* I2S_SDAT */ | ||
259 | /* TODO: Input or Output config */ | ||
260 | gpio_oe |= (0x1 << 2); | ||
261 | pin_ctrl &= ~(0x3 << 22); | ||
262 | pin_ctrl |= (strength << 22); | ||
263 | } else { | ||
264 | /* GPIO21 */ | ||
265 | gpio_oe &= ~(0x1 << 2); | ||
266 | if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { | ||
267 | gpio_data &= ~(0x1 << 2); | ||
268 | gpio_data |= ((p[i].value & 0x1) << 2); | ||
269 | } | ||
270 | pin_ctrl &= ~(0x3 << 12); | ||
271 | pin_ctrl |= (strength << 12); | ||
272 | } | ||
273 | break; | ||
274 | case CX23885_PIN_I2S_WCLK_GPIO22: | ||
275 | if (p[i].function != CX23885_PAD_GPIO22) { | ||
276 | /* I2S_WCLK */ | ||
277 | /* TODO: Input or Output config */ | ||
278 | gpio_oe |= (0x1 << 3); | ||
279 | pin_ctrl &= ~(0x3 << 22); | ||
280 | pin_ctrl |= (strength << 22); | ||
281 | } else { | ||
282 | /* GPIO22 */ | ||
283 | gpio_oe &= ~(0x1 << 3); | ||
284 | if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { | ||
285 | gpio_data &= ~(0x1 << 3); | ||
286 | gpio_data |= ((p[i].value & 0x1) << 3); | ||
287 | } | ||
288 | pin_ctrl &= ~(0x3 << 12); | ||
289 | pin_ctrl |= (strength << 12); | ||
290 | } | ||
291 | break; | ||
292 | case CX23885_PIN_I2S_BCLK_GPIO23: | ||
293 | if (p[i].function != CX23885_PAD_GPIO23) { | ||
294 | /* I2S_BCLK */ | ||
295 | /* TODO: Input or Output config */ | ||
296 | gpio_oe |= (0x1 << 4); | ||
297 | pin_ctrl &= ~(0x3 << 22); | ||
298 | pin_ctrl |= (strength << 22); | ||
299 | } else { | ||
300 | /* GPIO23 */ | ||
301 | gpio_oe &= ~(0x1 << 4); | ||
302 | if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { | ||
303 | gpio_data &= ~(0x1 << 4); | ||
304 | gpio_data |= ((p[i].value & 0x1) << 4); | ||
305 | } | ||
306 | pin_ctrl &= ~(0x3 << 12); | ||
307 | pin_ctrl |= (strength << 12); | ||
308 | } | ||
309 | break; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | cx25840_write(client, 0x164, gpio_data); | ||
314 | cx25840_write(client, 0x160, gpio_oe); | ||
315 | cx25840_write4(client, 0x120, pin_ctrl); | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, | ||
320 | struct v4l2_subdev_io_pin_config *pincfg) | ||
321 | { | ||
322 | struct cx25840_state *state = to_state(sd); | ||
323 | |||
324 | if (is_cx2388x(state)) | ||
325 | return cx23885_s_io_pin_config(sd, n, pincfg); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* ----------------------------------------------------------------------- */ | ||
330 | |||
331 | static void init_dll1(struct i2c_client *client) | ||
332 | { | ||
333 | /* This is the Hauppauge sequence used to | ||
334 | * initialize the Delay Lock Loop 1 (ADC DLL). */ | ||
335 | cx25840_write(client, 0x159, 0x23); | ||
336 | cx25840_write(client, 0x15a, 0x87); | ||
337 | cx25840_write(client, 0x15b, 0x06); | ||
338 | udelay(10); | ||
339 | cx25840_write(client, 0x159, 0xe1); | ||
340 | udelay(10); | ||
341 | cx25840_write(client, 0x15a, 0x86); | ||
342 | cx25840_write(client, 0x159, 0xe0); | ||
343 | cx25840_write(client, 0x159, 0xe1); | ||
344 | cx25840_write(client, 0x15b, 0x10); | ||
345 | } | ||
346 | |||
347 | static void init_dll2(struct i2c_client *client) | ||
348 | { | ||
349 | /* This is the Hauppauge sequence used to | ||
350 | * initialize the Delay Lock Loop 2 (ADC DLL). */ | ||
351 | cx25840_write(client, 0x15d, 0xe3); | ||
352 | cx25840_write(client, 0x15e, 0x86); | ||
353 | cx25840_write(client, 0x15f, 0x06); | ||
354 | udelay(10); | ||
355 | cx25840_write(client, 0x15d, 0xe1); | ||
356 | cx25840_write(client, 0x15d, 0xe0); | ||
357 | cx25840_write(client, 0x15d, 0xe1); | ||
358 | } | ||
359 | |||
360 | static void cx25836_initialize(struct i2c_client *client) | ||
361 | { | ||
362 | /* reset configuration is described on page 3-77 of the CX25836 datasheet */ | ||
363 | /* 2. */ | ||
364 | cx25840_and_or(client, 0x000, ~0x01, 0x01); | ||
365 | cx25840_and_or(client, 0x000, ~0x01, 0x00); | ||
366 | /* 3a. */ | ||
367 | cx25840_and_or(client, 0x15a, ~0x70, 0x00); | ||
368 | /* 3b. */ | ||
369 | cx25840_and_or(client, 0x15b, ~0x1e, 0x06); | ||
370 | /* 3c. */ | ||
371 | cx25840_and_or(client, 0x159, ~0x02, 0x02); | ||
372 | /* 3d. */ | ||
373 | udelay(10); | ||
374 | /* 3e. */ | ||
375 | cx25840_and_or(client, 0x159, ~0x02, 0x00); | ||
376 | /* 3f. */ | ||
377 | cx25840_and_or(client, 0x159, ~0xc0, 0xc0); | ||
378 | /* 3g. */ | ||
379 | cx25840_and_or(client, 0x159, ~0x01, 0x00); | ||
380 | cx25840_and_or(client, 0x159, ~0x01, 0x01); | ||
381 | /* 3h. */ | ||
382 | cx25840_and_or(client, 0x15b, ~0x1e, 0x10); | ||
383 | } | ||
384 | |||
385 | static void cx25840_work_handler(struct work_struct *work) | ||
386 | { | ||
387 | struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); | ||
388 | cx25840_loadfw(state->c); | ||
389 | wake_up(&state->fw_wait); | ||
390 | } | ||
391 | |||
392 | static void cx25840_initialize(struct i2c_client *client) | ||
393 | { | ||
394 | DEFINE_WAIT(wait); | ||
395 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
396 | struct workqueue_struct *q; | ||
397 | |||
398 | /* datasheet startup in numbered steps, refer to page 3-77 */ | ||
399 | /* 2. */ | ||
400 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | ||
401 | /* The default of this register should be 4, but I get 0 instead. | ||
402 | * Set this register to 4 manually. */ | ||
403 | cx25840_write(client, 0x000, 0x04); | ||
404 | /* 3. */ | ||
405 | init_dll1(client); | ||
406 | init_dll2(client); | ||
407 | cx25840_write(client, 0x136, 0x0a); | ||
408 | /* 4. */ | ||
409 | cx25840_write(client, 0x13c, 0x01); | ||
410 | cx25840_write(client, 0x13c, 0x00); | ||
411 | /* 5. */ | ||
412 | /* Do the firmware load in a work handler to prevent. | ||
413 | Otherwise the kernel is blocked waiting for the | ||
414 | bit-banging i2c interface to finish uploading the | ||
415 | firmware. */ | ||
416 | INIT_WORK(&state->fw_work, cx25840_work_handler); | ||
417 | init_waitqueue_head(&state->fw_wait); | ||
418 | q = create_singlethread_workqueue("cx25840_fw"); | ||
419 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | ||
420 | queue_work(q, &state->fw_work); | ||
421 | schedule(); | ||
422 | finish_wait(&state->fw_wait, &wait); | ||
423 | destroy_workqueue(q); | ||
424 | |||
425 | /* 6. */ | ||
426 | cx25840_write(client, 0x115, 0x8c); | ||
427 | cx25840_write(client, 0x116, 0x07); | ||
428 | cx25840_write(client, 0x118, 0x02); | ||
429 | /* 7. */ | ||
430 | cx25840_write(client, 0x4a5, 0x80); | ||
431 | cx25840_write(client, 0x4a5, 0x00); | ||
432 | cx25840_write(client, 0x402, 0x00); | ||
433 | /* 8. */ | ||
434 | cx25840_and_or(client, 0x401, ~0x18, 0); | ||
435 | cx25840_and_or(client, 0x4a2, ~0x10, 0x10); | ||
436 | /* steps 8c and 8d are done in change_input() */ | ||
437 | /* 10. */ | ||
438 | cx25840_write(client, 0x8d3, 0x1f); | ||
439 | cx25840_write(client, 0x8e3, 0x03); | ||
440 | |||
441 | cx25840_std_setup(client); | ||
442 | |||
443 | /* trial and error says these are needed to get audio */ | ||
444 | cx25840_write(client, 0x914, 0xa0); | ||
445 | cx25840_write(client, 0x918, 0xa0); | ||
446 | cx25840_write(client, 0x919, 0x01); | ||
447 | |||
448 | /* stereo preferred */ | ||
449 | cx25840_write(client, 0x809, 0x04); | ||
450 | /* AC97 shift */ | ||
451 | cx25840_write(client, 0x8cf, 0x0f); | ||
452 | |||
453 | /* (re)set input */ | ||
454 | set_input(client, state->vid_input, state->aud_input); | ||
455 | |||
456 | /* start microcontroller */ | ||
457 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
458 | } | ||
459 | |||
460 | static void cx23885_initialize(struct i2c_client *client) | ||
461 | { | ||
462 | DEFINE_WAIT(wait); | ||
463 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
464 | struct workqueue_struct *q; | ||
465 | |||
466 | /* | ||
467 | * Come out of digital power down | ||
468 | * The CX23888, at least, needs this, otherwise registers aside from | ||
469 | * 0x0-0x2 can't be read or written. | ||
470 | */ | ||
471 | cx25840_write(client, 0x000, 0); | ||
472 | |||
473 | /* Internal Reset */ | ||
474 | cx25840_and_or(client, 0x102, ~0x01, 0x01); | ||
475 | cx25840_and_or(client, 0x102, ~0x01, 0x00); | ||
476 | |||
477 | /* Stop microcontroller */ | ||
478 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | ||
479 | |||
480 | /* DIF in reset? */ | ||
481 | cx25840_write(client, 0x398, 0); | ||
482 | |||
483 | /* | ||
484 | * Trust the default xtal, no division | ||
485 | * '885: 28.636363... MHz | ||
486 | * '887: 25.000000 MHz | ||
487 | * '888: 50.000000 MHz | ||
488 | */ | ||
489 | cx25840_write(client, 0x2, 0x76); | ||
490 | |||
491 | /* Power up all the PLL's and DLL */ | ||
492 | cx25840_write(client, 0x1, 0x40); | ||
493 | |||
494 | /* Sys PLL */ | ||
495 | switch (state->id) { | ||
496 | case V4L2_IDENT_CX23888_AV: | ||
497 | /* | ||
498 | * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz | ||
499 | * 572.73 MHz before post divide | ||
500 | */ | ||
501 | cx25840_write4(client, 0x11c, 0x00e8ba26); | ||
502 | cx25840_write4(client, 0x118, 0x0000040b); | ||
503 | break; | ||
504 | case V4L2_IDENT_CX23887_AV: | ||
505 | /* | ||
506 | * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz | ||
507 | * 572.73 MHz before post divide | ||
508 | */ | ||
509 | cx25840_write4(client, 0x11c, 0x01d1744c); | ||
510 | cx25840_write4(client, 0x118, 0x00000416); | ||
511 | break; | ||
512 | case V4L2_IDENT_CX23885_AV: | ||
513 | default: | ||
514 | /* | ||
515 | * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz | ||
516 | * 572.73 MHz before post divide | ||
517 | */ | ||
518 | cx25840_write4(client, 0x11c, 0x00000000); | ||
519 | cx25840_write4(client, 0x118, 0x00000414); | ||
520 | break; | ||
521 | } | ||
522 | |||
523 | /* Disable DIF bypass */ | ||
524 | cx25840_write4(client, 0x33c, 0x00000001); | ||
525 | |||
526 | /* DIF Src phase inc */ | ||
527 | cx25840_write4(client, 0x340, 0x0df7df83); | ||
528 | |||
529 | /* | ||
530 | * Vid PLL | ||
531 | * Setup for a BT.656 pixel clock of 13.5 Mpixels/second | ||
532 | * | ||
533 | * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz | ||
534 | * 432.0 MHz before post divide | ||
535 | */ | ||
536 | cx25840_write4(client, 0x10c, 0x002be2c9); | ||
537 | cx25840_write4(client, 0x108, 0x0000040f); | ||
538 | |||
539 | /* Luma */ | ||
540 | cx25840_write4(client, 0x414, 0x00107d12); | ||
541 | |||
542 | /* Chroma */ | ||
543 | cx25840_write4(client, 0x420, 0x3d008282); | ||
544 | |||
545 | /* | ||
546 | * Aux PLL | ||
547 | * Initial setup for audio sample clock: | ||
548 | * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz | ||
549 | * Initial I2S output/master clock(?): | ||
550 | * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz | ||
551 | */ | ||
552 | switch (state->id) { | ||
553 | case V4L2_IDENT_CX23888_AV: | ||
554 | /* | ||
555 | * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz | ||
556 | * 368.64 MHz before post divide | ||
557 | * 122.88 MHz / 0xa = 12.288 MHz | ||
558 | */ | ||
559 | cx25840_write4(client, 0x114, 0x00bedfa4); | ||
560 | cx25840_write4(client, 0x110, 0x000a0307); | ||
561 | break; | ||
562 | case V4L2_IDENT_CX23887_AV: | ||
563 | /* | ||
564 | * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz | ||
565 | * 368.64 MHz before post divide | ||
566 | * 122.88 MHz / 0xa = 12.288 MHz | ||
567 | */ | ||
568 | cx25840_write4(client, 0x114, 0x017dbf48); | ||
569 | cx25840_write4(client, 0x110, 0x000a030e); | ||
570 | break; | ||
571 | case V4L2_IDENT_CX23885_AV: | ||
572 | default: | ||
573 | /* | ||
574 | * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz | ||
575 | * 368.64 MHz before post divide | ||
576 | * 122.88 MHz / 0xa = 12.288 MHz | ||
577 | */ | ||
578 | cx25840_write4(client, 0x114, 0x01bf0c9e); | ||
579 | cx25840_write4(client, 0x110, 0x000a030c); | ||
580 | break; | ||
581 | }; | ||
582 | |||
583 | /* ADC2 input select */ | ||
584 | cx25840_write(client, 0x102, 0x10); | ||
585 | |||
586 | /* VIN1 & VIN5 */ | ||
587 | cx25840_write(client, 0x103, 0x11); | ||
588 | |||
589 | /* Enable format auto detect */ | ||
590 | cx25840_write(client, 0x400, 0); | ||
591 | /* Fast subchroma lock */ | ||
592 | /* White crush, Chroma AGC & Chroma Killer enabled */ | ||
593 | cx25840_write(client, 0x401, 0xe8); | ||
594 | |||
595 | /* Select AFE clock pad output source */ | ||
596 | cx25840_write(client, 0x144, 0x05); | ||
597 | |||
598 | /* Drive GPIO2 direction and values for HVR1700 | ||
599 | * where an onboard mux selects the output of demodulator | ||
600 | * vs the 417. Failure to set this results in no DTV. | ||
601 | * It's safe to set this across all Hauppauge boards | ||
602 | * currently, regardless of the board type. | ||
603 | */ | ||
604 | cx25840_write(client, 0x160, 0x1d); | ||
605 | cx25840_write(client, 0x164, 0x00); | ||
606 | |||
607 | /* Do the firmware load in a work handler to prevent. | ||
608 | Otherwise the kernel is blocked waiting for the | ||
609 | bit-banging i2c interface to finish uploading the | ||
610 | firmware. */ | ||
611 | INIT_WORK(&state->fw_work, cx25840_work_handler); | ||
612 | init_waitqueue_head(&state->fw_wait); | ||
613 | q = create_singlethread_workqueue("cx25840_fw"); | ||
614 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | ||
615 | queue_work(q, &state->fw_work); | ||
616 | schedule(); | ||
617 | finish_wait(&state->fw_wait, &wait); | ||
618 | destroy_workqueue(q); | ||
619 | |||
620 | cx25840_std_setup(client); | ||
621 | |||
622 | /* (re)set input */ | ||
623 | set_input(client, state->vid_input, state->aud_input); | ||
624 | |||
625 | /* start microcontroller */ | ||
626 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
627 | |||
628 | /* Disable and clear video interrupts - we don't use them */ | ||
629 | cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff); | ||
630 | |||
631 | /* Disable and clear audio interrupts - we don't use them */ | ||
632 | cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff); | ||
633 | cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff); | ||
634 | } | ||
635 | |||
636 | /* ----------------------------------------------------------------------- */ | ||
637 | |||
638 | static void cx231xx_initialize(struct i2c_client *client) | ||
639 | { | ||
640 | DEFINE_WAIT(wait); | ||
641 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
642 | struct workqueue_struct *q; | ||
643 | |||
644 | /* Internal Reset */ | ||
645 | cx25840_and_or(client, 0x102, ~0x01, 0x01); | ||
646 | cx25840_and_or(client, 0x102, ~0x01, 0x00); | ||
647 | |||
648 | /* Stop microcontroller */ | ||
649 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | ||
650 | |||
651 | /* DIF in reset? */ | ||
652 | cx25840_write(client, 0x398, 0); | ||
653 | |||
654 | /* Trust the default xtal, no division */ | ||
655 | /* This changes for the cx23888 products */ | ||
656 | cx25840_write(client, 0x2, 0x76); | ||
657 | |||
658 | /* Bring down the regulator for AUX clk */ | ||
659 | cx25840_write(client, 0x1, 0x40); | ||
660 | |||
661 | /* Disable DIF bypass */ | ||
662 | cx25840_write4(client, 0x33c, 0x00000001); | ||
663 | |||
664 | /* DIF Src phase inc */ | ||
665 | cx25840_write4(client, 0x340, 0x0df7df83); | ||
666 | |||
667 | /* Luma */ | ||
668 | cx25840_write4(client, 0x414, 0x00107d12); | ||
669 | |||
670 | /* Chroma */ | ||
671 | cx25840_write4(client, 0x420, 0x3d008282); | ||
672 | |||
673 | /* ADC2 input select */ | ||
674 | cx25840_write(client, 0x102, 0x10); | ||
675 | |||
676 | /* VIN1 & VIN5 */ | ||
677 | cx25840_write(client, 0x103, 0x11); | ||
678 | |||
679 | /* Enable format auto detect */ | ||
680 | cx25840_write(client, 0x400, 0); | ||
681 | /* Fast subchroma lock */ | ||
682 | /* White crush, Chroma AGC & Chroma Killer enabled */ | ||
683 | cx25840_write(client, 0x401, 0xe8); | ||
684 | |||
685 | /* Do the firmware load in a work handler to prevent. | ||
686 | Otherwise the kernel is blocked waiting for the | ||
687 | bit-banging i2c interface to finish uploading the | ||
688 | firmware. */ | ||
689 | INIT_WORK(&state->fw_work, cx25840_work_handler); | ||
690 | init_waitqueue_head(&state->fw_wait); | ||
691 | q = create_singlethread_workqueue("cx25840_fw"); | ||
692 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | ||
693 | queue_work(q, &state->fw_work); | ||
694 | schedule(); | ||
695 | finish_wait(&state->fw_wait, &wait); | ||
696 | destroy_workqueue(q); | ||
697 | |||
698 | cx25840_std_setup(client); | ||
699 | |||
700 | /* (re)set input */ | ||
701 | set_input(client, state->vid_input, state->aud_input); | ||
702 | |||
703 | /* start microcontroller */ | ||
704 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
705 | } | ||
706 | |||
707 | /* ----------------------------------------------------------------------- */ | ||
708 | |||
709 | void cx25840_std_setup(struct i2c_client *client) | ||
710 | { | ||
711 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
712 | v4l2_std_id std = state->std; | ||
713 | int hblank, hactive, burst, vblank, vactive, sc; | ||
714 | int vblank656, src_decimation; | ||
715 | int luma_lpf, uv_lpf, comb; | ||
716 | u32 pll_int, pll_frac, pll_post; | ||
717 | |||
718 | /* datasheet startup, step 8d */ | ||
719 | if (std & ~V4L2_STD_NTSC) | ||
720 | cx25840_write(client, 0x49f, 0x11); | ||
721 | else | ||
722 | cx25840_write(client, 0x49f, 0x14); | ||
723 | |||
724 | if (std & V4L2_STD_625_50) { | ||
725 | hblank = 132; | ||
726 | hactive = 720; | ||
727 | burst = 93; | ||
728 | vblank = 36; | ||
729 | vactive = 580; | ||
730 | vblank656 = 40; | ||
731 | src_decimation = 0x21f; | ||
732 | luma_lpf = 2; | ||
733 | |||
734 | if (std & V4L2_STD_SECAM) { | ||
735 | uv_lpf = 0; | ||
736 | comb = 0; | ||
737 | sc = 0x0a425f; | ||
738 | } else if (std == V4L2_STD_PAL_Nc) { | ||
739 | uv_lpf = 1; | ||
740 | comb = 0x20; | ||
741 | sc = 556453; | ||
742 | } else { | ||
743 | uv_lpf = 1; | ||
744 | comb = 0x20; | ||
745 | sc = 688739; | ||
746 | } | ||
747 | } else { | ||
748 | hactive = 720; | ||
749 | hblank = 122; | ||
750 | vactive = 487; | ||
751 | luma_lpf = 1; | ||
752 | uv_lpf = 1; | ||
753 | |||
754 | src_decimation = 0x21f; | ||
755 | if (std == V4L2_STD_PAL_60) { | ||
756 | vblank = 26; | ||
757 | vblank656 = 26; | ||
758 | burst = 0x5b; | ||
759 | luma_lpf = 2; | ||
760 | comb = 0x20; | ||
761 | sc = 688739; | ||
762 | } else if (std == V4L2_STD_PAL_M) { | ||
763 | vblank = 20; | ||
764 | vblank656 = 24; | ||
765 | burst = 0x61; | ||
766 | comb = 0x20; | ||
767 | sc = 555452; | ||
768 | } else { | ||
769 | vblank = 26; | ||
770 | vblank656 = 26; | ||
771 | burst = 0x5b; | ||
772 | comb = 0x66; | ||
773 | sc = 556063; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | /* DEBUG: Displays configured PLL frequency */ | ||
778 | if (!is_cx231xx(state)) { | ||
779 | pll_int = cx25840_read(client, 0x108); | ||
780 | pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; | ||
781 | pll_post = cx25840_read(client, 0x109); | ||
782 | v4l_dbg(1, cx25840_debug, client, | ||
783 | "PLL regs = int: %u, frac: %u, post: %u\n", | ||
784 | pll_int, pll_frac, pll_post); | ||
785 | |||
786 | if (pll_post) { | ||
787 | int fin, fsc; | ||
788 | int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; | ||
789 | |||
790 | pll /= pll_post; | ||
791 | v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", | ||
792 | pll / 1000000, pll % 1000000); | ||
793 | v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", | ||
794 | pll / 8000000, (pll / 8) % 1000000); | ||
795 | |||
796 | fin = ((u64)src_decimation * pll) >> 12; | ||
797 | v4l_dbg(1, cx25840_debug, client, | ||
798 | "ADC Sampling freq = %d.%06d MHz\n", | ||
799 | fin / 1000000, fin % 1000000); | ||
800 | |||
801 | fsc = (((u64)sc) * pll) >> 24L; | ||
802 | v4l_dbg(1, cx25840_debug, client, | ||
803 | "Chroma sub-carrier freq = %d.%06d MHz\n", | ||
804 | fsc / 1000000, fsc % 1000000); | ||
805 | |||
806 | v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " | ||
807 | "vblank %i, vactive %i, vblank656 %i, src_dec %i, " | ||
808 | "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " | ||
809 | "sc 0x%06x\n", | ||
810 | hblank, hactive, vblank, vactive, vblank656, | ||
811 | src_decimation, burst, luma_lpf, uv_lpf, comb, sc); | ||
812 | } | ||
813 | } | ||
814 | |||
815 | /* Sets horizontal blanking delay and active lines */ | ||
816 | cx25840_write(client, 0x470, hblank); | ||
817 | cx25840_write(client, 0x471, | ||
818 | 0xff & (((hblank >> 8) & 0x3) | (hactive << 4))); | ||
819 | cx25840_write(client, 0x472, hactive >> 4); | ||
820 | |||
821 | /* Sets burst gate delay */ | ||
822 | cx25840_write(client, 0x473, burst); | ||
823 | |||
824 | /* Sets vertical blanking delay and active duration */ | ||
825 | cx25840_write(client, 0x474, vblank); | ||
826 | cx25840_write(client, 0x475, | ||
827 | 0xff & (((vblank >> 8) & 0x3) | (vactive << 4))); | ||
828 | cx25840_write(client, 0x476, vactive >> 4); | ||
829 | cx25840_write(client, 0x477, vblank656); | ||
830 | |||
831 | /* Sets src decimation rate */ | ||
832 | cx25840_write(client, 0x478, 0xff & src_decimation); | ||
833 | cx25840_write(client, 0x479, 0xff & (src_decimation >> 8)); | ||
834 | |||
835 | /* Sets Luma and UV Low pass filters */ | ||
836 | cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); | ||
837 | |||
838 | /* Enables comb filters */ | ||
839 | cx25840_write(client, 0x47b, comb); | ||
840 | |||
841 | /* Sets SC Step*/ | ||
842 | cx25840_write(client, 0x47c, sc); | ||
843 | cx25840_write(client, 0x47d, 0xff & sc >> 8); | ||
844 | cx25840_write(client, 0x47e, 0xff & sc >> 16); | ||
845 | |||
846 | /* Sets VBI parameters */ | ||
847 | if (std & V4L2_STD_625_50) { | ||
848 | cx25840_write(client, 0x47f, 0x01); | ||
849 | state->vbi_line_offset = 5; | ||
850 | } else { | ||
851 | cx25840_write(client, 0x47f, 0x00); | ||
852 | state->vbi_line_offset = 8; | ||
853 | } | ||
854 | } | ||
855 | |||
856 | /* ----------------------------------------------------------------------- */ | ||
857 | |||
858 | static void input_change(struct i2c_client *client) | ||
859 | { | ||
860 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
861 | v4l2_std_id std = state->std; | ||
862 | |||
863 | /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ | ||
864 | if (std & V4L2_STD_SECAM) { | ||
865 | cx25840_write(client, 0x402, 0); | ||
866 | } | ||
867 | else { | ||
868 | cx25840_write(client, 0x402, 0x04); | ||
869 | cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); | ||
870 | } | ||
871 | cx25840_and_or(client, 0x401, ~0x60, 0); | ||
872 | cx25840_and_or(client, 0x401, ~0x60, 0x60); | ||
873 | |||
874 | /* Don't write into audio registers on cx2583x chips */ | ||
875 | if (is_cx2583x(state)) | ||
876 | return; | ||
877 | |||
878 | cx25840_and_or(client, 0x810, ~0x01, 1); | ||
879 | |||
880 | if (state->radio) { | ||
881 | cx25840_write(client, 0x808, 0xf9); | ||
882 | cx25840_write(client, 0x80b, 0x00); | ||
883 | } | ||
884 | else if (std & V4L2_STD_525_60) { | ||
885 | /* Certain Hauppauge PVR150 models have a hardware bug | ||
886 | that causes audio to drop out. For these models the | ||
887 | audio standard must be set explicitly. | ||
888 | To be precise: it affects cards with tuner models | ||
889 | 85, 99 and 112 (model numbers from tveeprom). */ | ||
890 | int hw_fix = state->pvr150_workaround; | ||
891 | |||
892 | if (std == V4L2_STD_NTSC_M_JP) { | ||
893 | /* Japan uses EIAJ audio standard */ | ||
894 | cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7); | ||
895 | } else if (std == V4L2_STD_NTSC_M_KR) { | ||
896 | /* South Korea uses A2 audio standard */ | ||
897 | cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8); | ||
898 | } else { | ||
899 | /* Others use the BTSC audio standard */ | ||
900 | cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6); | ||
901 | } | ||
902 | cx25840_write(client, 0x80b, 0x00); | ||
903 | } else if (std & V4L2_STD_PAL) { | ||
904 | /* Autodetect audio standard and audio system */ | ||
905 | cx25840_write(client, 0x808, 0xff); | ||
906 | /* Since system PAL-L is pretty much non-existent and | ||
907 | not used by any public broadcast network, force | ||
908 | 6.5 MHz carrier to be interpreted as System DK, | ||
909 | this avoids DK audio detection instability */ | ||
910 | cx25840_write(client, 0x80b, 0x00); | ||
911 | } else if (std & V4L2_STD_SECAM) { | ||
912 | /* Autodetect audio standard and audio system */ | ||
913 | cx25840_write(client, 0x808, 0xff); | ||
914 | /* If only one of SECAM-DK / SECAM-L is required, then force | ||
915 | 6.5MHz carrier, else autodetect it */ | ||
916 | if ((std & V4L2_STD_SECAM_DK) && | ||
917 | !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { | ||
918 | /* 6.5 MHz carrier to be interpreted as System DK */ | ||
919 | cx25840_write(client, 0x80b, 0x00); | ||
920 | } else if (!(std & V4L2_STD_SECAM_DK) && | ||
921 | (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { | ||
922 | /* 6.5 MHz carrier to be interpreted as System L */ | ||
923 | cx25840_write(client, 0x80b, 0x08); | ||
924 | } else { | ||
925 | /* 6.5 MHz carrier to be autodetected */ | ||
926 | cx25840_write(client, 0x80b, 0x10); | ||
927 | } | ||
928 | } | ||
929 | |||
930 | cx25840_and_or(client, 0x810, ~0x01, 0); | ||
931 | } | ||
932 | |||
933 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, | ||
934 | enum cx25840_audio_input aud_input) | ||
935 | { | ||
936 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
937 | u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && | ||
938 | vid_input <= CX25840_COMPOSITE8); | ||
939 | u8 is_component = (vid_input & CX25840_COMPONENT_ON) == | ||
940 | CX25840_COMPONENT_ON; | ||
941 | int luma = vid_input & 0xf0; | ||
942 | int chroma = vid_input & 0xf00; | ||
943 | u8 reg; | ||
944 | |||
945 | v4l_dbg(1, cx25840_debug, client, | ||
946 | "decoder set video input %d, audio input %d\n", | ||
947 | vid_input, aud_input); | ||
948 | |||
949 | if (vid_input >= CX25840_VIN1_CH1) { | ||
950 | v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", | ||
951 | vid_input); | ||
952 | reg = vid_input & 0xff; | ||
953 | is_composite = !is_component && | ||
954 | ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); | ||
955 | |||
956 | v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", | ||
957 | reg, is_composite); | ||
958 | } else if (is_composite) { | ||
959 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); | ||
960 | } else { | ||
961 | if ((vid_input & ~0xff0) || | ||
962 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || | ||
963 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { | ||
964 | v4l_err(client, "0x%04x is not a valid video input!\n", | ||
965 | vid_input); | ||
966 | return -EINVAL; | ||
967 | } | ||
968 | reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); | ||
969 | if (chroma >= CX25840_SVIDEO_CHROMA7) { | ||
970 | reg &= 0x3f; | ||
971 | reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2; | ||
972 | } else { | ||
973 | reg &= 0xcf; | ||
974 | reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4; | ||
975 | } | ||
976 | } | ||
977 | |||
978 | /* The caller has previously prepared the correct routing | ||
979 | * configuration in reg (for the cx23885) so we have no | ||
980 | * need to attempt to flip bits for earlier av decoders. | ||
981 | */ | ||
982 | if (!is_cx2388x(state) && !is_cx231xx(state)) { | ||
983 | switch (aud_input) { | ||
984 | case CX25840_AUDIO_SERIAL: | ||
985 | /* do nothing, use serial audio input */ | ||
986 | break; | ||
987 | case CX25840_AUDIO4: reg &= ~0x30; break; | ||
988 | case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; | ||
989 | case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; | ||
990 | case CX25840_AUDIO7: reg &= ~0xc0; break; | ||
991 | case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; | ||
992 | |||
993 | default: | ||
994 | v4l_err(client, "0x%04x is not a valid audio input!\n", | ||
995 | aud_input); | ||
996 | return -EINVAL; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | cx25840_write(client, 0x103, reg); | ||
1001 | |||
1002 | /* Set INPUT_MODE to Composite, S-Video or Component */ | ||
1003 | if (is_component) | ||
1004 | cx25840_and_or(client, 0x401, ~0x6, 0x6); | ||
1005 | else | ||
1006 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | ||
1007 | |||
1008 | if (!is_cx2388x(state) && !is_cx231xx(state)) { | ||
1009 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ | ||
1010 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); | ||
1011 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ | ||
1012 | if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) | ||
1013 | cx25840_and_or(client, 0x102, ~0x4, 4); | ||
1014 | else | ||
1015 | cx25840_and_or(client, 0x102, ~0x4, 0); | ||
1016 | } else { | ||
1017 | /* Set DUAL_MODE_ADC2 to 1 if component*/ | ||
1018 | cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0); | ||
1019 | if (is_composite) { | ||
1020 | /* ADC2 input select channel 2 */ | ||
1021 | cx25840_and_or(client, 0x102, ~0x2, 0); | ||
1022 | } else if (!is_component) { | ||
1023 | /* S-Video */ | ||
1024 | if (chroma >= CX25840_SVIDEO_CHROMA7) { | ||
1025 | /* ADC2 input select channel 3 */ | ||
1026 | cx25840_and_or(client, 0x102, ~0x2, 2); | ||
1027 | } else { | ||
1028 | /* ADC2 input select channel 2 */ | ||
1029 | cx25840_and_or(client, 0x102, ~0x2, 0); | ||
1030 | } | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | state->vid_input = vid_input; | ||
1035 | state->aud_input = aud_input; | ||
1036 | cx25840_audio_set_path(client); | ||
1037 | input_change(client); | ||
1038 | |||
1039 | if (is_cx2388x(state)) { | ||
1040 | /* Audio channel 1 src : Parallel 1 */ | ||
1041 | cx25840_write(client, 0x124, 0x03); | ||
1042 | |||
1043 | /* Select AFE clock pad output source */ | ||
1044 | cx25840_write(client, 0x144, 0x05); | ||
1045 | |||
1046 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ | ||
1047 | cx25840_write(client, 0x914, 0xa0); | ||
1048 | |||
1049 | /* I2S_OUT_CTL: | ||
1050 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 | ||
1051 | * I2S_OUT_MASTER_MODE = Master | ||
1052 | */ | ||
1053 | cx25840_write(client, 0x918, 0xa0); | ||
1054 | cx25840_write(client, 0x919, 0x01); | ||
1055 | } else if (is_cx231xx(state)) { | ||
1056 | /* Audio channel 1 src : Parallel 1 */ | ||
1057 | cx25840_write(client, 0x124, 0x03); | ||
1058 | |||
1059 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ | ||
1060 | cx25840_write(client, 0x914, 0xa0); | ||
1061 | |||
1062 | /* I2S_OUT_CTL: | ||
1063 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 | ||
1064 | * I2S_OUT_MASTER_MODE = Master | ||
1065 | */ | ||
1066 | cx25840_write(client, 0x918, 0xa0); | ||
1067 | cx25840_write(client, 0x919, 0x01); | ||
1068 | } | ||
1069 | |||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | /* ----------------------------------------------------------------------- */ | ||
1074 | |||
1075 | static int set_v4lstd(struct i2c_client *client) | ||
1076 | { | ||
1077 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
1078 | u8 fmt = 0; /* zero is autodetect */ | ||
1079 | u8 pal_m = 0; | ||
1080 | |||
1081 | /* First tests should be against specific std */ | ||
1082 | if (state->std == V4L2_STD_NTSC_M_JP) { | ||
1083 | fmt = 0x2; | ||
1084 | } else if (state->std == V4L2_STD_NTSC_443) { | ||
1085 | fmt = 0x3; | ||
1086 | } else if (state->std == V4L2_STD_PAL_M) { | ||
1087 | pal_m = 1; | ||
1088 | fmt = 0x5; | ||
1089 | } else if (state->std == V4L2_STD_PAL_N) { | ||
1090 | fmt = 0x6; | ||
1091 | } else if (state->std == V4L2_STD_PAL_Nc) { | ||
1092 | fmt = 0x7; | ||
1093 | } else if (state->std == V4L2_STD_PAL_60) { | ||
1094 | fmt = 0x8; | ||
1095 | } else { | ||
1096 | /* Then, test against generic ones */ | ||
1097 | if (state->std & V4L2_STD_NTSC) | ||
1098 | fmt = 0x1; | ||
1099 | else if (state->std & V4L2_STD_PAL) | ||
1100 | fmt = 0x4; | ||
1101 | else if (state->std & V4L2_STD_SECAM) | ||
1102 | fmt = 0xc; | ||
1103 | } | ||
1104 | |||
1105 | v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt); | ||
1106 | |||
1107 | /* Follow step 9 of section 3.16 in the cx25840 datasheet. | ||
1108 | Without this PAL may display a vertical ghosting effect. | ||
1109 | This happens for example with the Yuan MPC622. */ | ||
1110 | if (fmt >= 4 && fmt < 8) { | ||
1111 | /* Set format to NTSC-M */ | ||
1112 | cx25840_and_or(client, 0x400, ~0xf, 1); | ||
1113 | /* Turn off LCOMB */ | ||
1114 | cx25840_and_or(client, 0x47b, ~6, 0); | ||
1115 | } | ||
1116 | cx25840_and_or(client, 0x400, ~0xf, fmt); | ||
1117 | cx25840_and_or(client, 0x403, ~0x3, pal_m); | ||
1118 | cx25840_std_setup(client); | ||
1119 | if (!is_cx2583x(state)) | ||
1120 | input_change(client); | ||
1121 | return 0; | ||
1122 | } | ||
1123 | |||
1124 | /* ----------------------------------------------------------------------- */ | ||
1125 | |||
1126 | static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1127 | { | ||
1128 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
1129 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1130 | |||
1131 | switch (ctrl->id) { | ||
1132 | case V4L2_CID_BRIGHTNESS: | ||
1133 | cx25840_write(client, 0x414, ctrl->val - 128); | ||
1134 | break; | ||
1135 | |||
1136 | case V4L2_CID_CONTRAST: | ||
1137 | cx25840_write(client, 0x415, ctrl->val << 1); | ||
1138 | break; | ||
1139 | |||
1140 | case V4L2_CID_SATURATION: | ||
1141 | cx25840_write(client, 0x420, ctrl->val << 1); | ||
1142 | cx25840_write(client, 0x421, ctrl->val << 1); | ||
1143 | break; | ||
1144 | |||
1145 | case V4L2_CID_HUE: | ||
1146 | cx25840_write(client, 0x422, ctrl->val); | ||
1147 | break; | ||
1148 | |||
1149 | default: | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | |||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | /* ----------------------------------------------------------------------- */ | ||
1157 | |||
1158 | static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) | ||
1159 | { | ||
1160 | struct cx25840_state *state = to_state(sd); | ||
1161 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1162 | int HSC, VSC, Vsrc, Hsrc, filter, Vlines; | ||
1163 | int is_50Hz = !(state->std & V4L2_STD_525_60); | ||
1164 | |||
1165 | if (fmt->code != V4L2_MBUS_FMT_FIXED) | ||
1166 | return -EINVAL; | ||
1167 | |||
1168 | fmt->field = V4L2_FIELD_INTERLACED; | ||
1169 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
1170 | |||
1171 | Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; | ||
1172 | Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; | ||
1173 | |||
1174 | Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; | ||
1175 | Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; | ||
1176 | |||
1177 | Vlines = fmt->height + (is_50Hz ? 4 : 7); | ||
1178 | |||
1179 | if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || | ||
1180 | (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { | ||
1181 | v4l_err(client, "%dx%d is not a valid size!\n", | ||
1182 | fmt->width, fmt->height); | ||
1183 | return -ERANGE; | ||
1184 | } | ||
1185 | |||
1186 | HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); | ||
1187 | VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); | ||
1188 | VSC &= 0x1fff; | ||
1189 | |||
1190 | if (fmt->width >= 385) | ||
1191 | filter = 0; | ||
1192 | else if (fmt->width > 192) | ||
1193 | filter = 1; | ||
1194 | else if (fmt->width > 96) | ||
1195 | filter = 2; | ||
1196 | else | ||
1197 | filter = 3; | ||
1198 | |||
1199 | v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", | ||
1200 | fmt->width, fmt->height, HSC, VSC); | ||
1201 | |||
1202 | /* HSCALE=HSC */ | ||
1203 | cx25840_write(client, 0x418, HSC & 0xff); | ||
1204 | cx25840_write(client, 0x419, (HSC >> 8) & 0xff); | ||
1205 | cx25840_write(client, 0x41a, HSC >> 16); | ||
1206 | /* VSCALE=VSC */ | ||
1207 | cx25840_write(client, 0x41c, VSC & 0xff); | ||
1208 | cx25840_write(client, 0x41d, VSC >> 8); | ||
1209 | /* VS_INTRLACE=1 VFILT=filter */ | ||
1210 | cx25840_write(client, 0x41e, 0x8 | filter); | ||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | /* ----------------------------------------------------------------------- */ | ||
1215 | |||
1216 | static void log_video_status(struct i2c_client *client) | ||
1217 | { | ||
1218 | static const char *const fmt_strs[] = { | ||
1219 | "0x0", | ||
1220 | "NTSC-M", "NTSC-J", "NTSC-4.43", | ||
1221 | "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", | ||
1222 | "0x9", "0xA", "0xB", | ||
1223 | "SECAM", | ||
1224 | "0xD", "0xE", "0xF" | ||
1225 | }; | ||
1226 | |||
1227 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
1228 | u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; | ||
1229 | u8 gen_stat1 = cx25840_read(client, 0x40d); | ||
1230 | u8 gen_stat2 = cx25840_read(client, 0x40e); | ||
1231 | int vid_input = state->vid_input; | ||
1232 | |||
1233 | v4l_info(client, "Video signal: %spresent\n", | ||
1234 | (gen_stat2 & 0x20) ? "" : "not "); | ||
1235 | v4l_info(client, "Detected format: %s\n", | ||
1236 | fmt_strs[gen_stat1 & 0xf]); | ||
1237 | |||
1238 | v4l_info(client, "Specified standard: %s\n", | ||
1239 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); | ||
1240 | |||
1241 | if (vid_input >= CX25840_COMPOSITE1 && | ||
1242 | vid_input <= CX25840_COMPOSITE8) { | ||
1243 | v4l_info(client, "Specified video input: Composite %d\n", | ||
1244 | vid_input - CX25840_COMPOSITE1 + 1); | ||
1245 | } else { | ||
1246 | v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", | ||
1247 | (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); | ||
1248 | } | ||
1249 | |||
1250 | v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); | ||
1251 | } | ||
1252 | |||
1253 | /* ----------------------------------------------------------------------- */ | ||
1254 | |||
1255 | static void log_audio_status(struct i2c_client *client) | ||
1256 | { | ||
1257 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
1258 | u8 download_ctl = cx25840_read(client, 0x803); | ||
1259 | u8 mod_det_stat0 = cx25840_read(client, 0x804); | ||
1260 | u8 mod_det_stat1 = cx25840_read(client, 0x805); | ||
1261 | u8 audio_config = cx25840_read(client, 0x808); | ||
1262 | u8 pref_mode = cx25840_read(client, 0x809); | ||
1263 | u8 afc0 = cx25840_read(client, 0x80b); | ||
1264 | u8 mute_ctl = cx25840_read(client, 0x8d3); | ||
1265 | int aud_input = state->aud_input; | ||
1266 | char *p; | ||
1267 | |||
1268 | switch (mod_det_stat0) { | ||
1269 | case 0x00: p = "mono"; break; | ||
1270 | case 0x01: p = "stereo"; break; | ||
1271 | case 0x02: p = "dual"; break; | ||
1272 | case 0x04: p = "tri"; break; | ||
1273 | case 0x10: p = "mono with SAP"; break; | ||
1274 | case 0x11: p = "stereo with SAP"; break; | ||
1275 | case 0x12: p = "dual with SAP"; break; | ||
1276 | case 0x14: p = "tri with SAP"; break; | ||
1277 | case 0xfe: p = "forced mode"; break; | ||
1278 | default: p = "not defined"; | ||
1279 | } | ||
1280 | v4l_info(client, "Detected audio mode: %s\n", p); | ||
1281 | |||
1282 | switch (mod_det_stat1) { | ||
1283 | case 0x00: p = "not defined"; break; | ||
1284 | case 0x01: p = "EIAJ"; break; | ||
1285 | case 0x02: p = "A2-M"; break; | ||
1286 | case 0x03: p = "A2-BG"; break; | ||
1287 | case 0x04: p = "A2-DK1"; break; | ||
1288 | case 0x05: p = "A2-DK2"; break; | ||
1289 | case 0x06: p = "A2-DK3"; break; | ||
1290 | case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; | ||
1291 | case 0x08: p = "AM-L"; break; | ||
1292 | case 0x09: p = "NICAM-BG"; break; | ||
1293 | case 0x0a: p = "NICAM-DK"; break; | ||
1294 | case 0x0b: p = "NICAM-I"; break; | ||
1295 | case 0x0c: p = "NICAM-L"; break; | ||
1296 | case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; | ||
1297 | case 0x0e: p = "IF FM Radio"; break; | ||
1298 | case 0x0f: p = "BTSC"; break; | ||
1299 | case 0x10: p = "high-deviation FM"; break; | ||
1300 | case 0x11: p = "very high-deviation FM"; break; | ||
1301 | case 0xfd: p = "unknown audio standard"; break; | ||
1302 | case 0xfe: p = "forced audio standard"; break; | ||
1303 | case 0xff: p = "no detected audio standard"; break; | ||
1304 | default: p = "not defined"; | ||
1305 | } | ||
1306 | v4l_info(client, "Detected audio standard: %s\n", p); | ||
1307 | v4l_info(client, "Audio microcontroller: %s\n", | ||
1308 | (download_ctl & 0x10) ? | ||
1309 | ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); | ||
1310 | |||
1311 | switch (audio_config >> 4) { | ||
1312 | case 0x00: p = "undefined"; break; | ||
1313 | case 0x01: p = "BTSC"; break; | ||
1314 | case 0x02: p = "EIAJ"; break; | ||
1315 | case 0x03: p = "A2-M"; break; | ||
1316 | case 0x04: p = "A2-BG"; break; | ||
1317 | case 0x05: p = "A2-DK1"; break; | ||
1318 | case 0x06: p = "A2-DK2"; break; | ||
1319 | case 0x07: p = "A2-DK3"; break; | ||
1320 | case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; | ||
1321 | case 0x09: p = "AM-L"; break; | ||
1322 | case 0x0a: p = "NICAM-BG"; break; | ||
1323 | case 0x0b: p = "NICAM-DK"; break; | ||
1324 | case 0x0c: p = "NICAM-I"; break; | ||
1325 | case 0x0d: p = "NICAM-L"; break; | ||
1326 | case 0x0e: p = "FM radio"; break; | ||
1327 | case 0x0f: p = "automatic detection"; break; | ||
1328 | default: p = "undefined"; | ||
1329 | } | ||
1330 | v4l_info(client, "Configured audio standard: %s\n", p); | ||
1331 | |||
1332 | if ((audio_config >> 4) < 0xF) { | ||
1333 | switch (audio_config & 0xF) { | ||
1334 | case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; | ||
1335 | case 0x01: p = "MONO2 (LANGUAGE B)"; break; | ||
1336 | case 0x02: p = "MONO3 (STEREO forced MONO)"; break; | ||
1337 | case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; | ||
1338 | case 0x04: p = "STEREO"; break; | ||
1339 | case 0x05: p = "DUAL1 (AB)"; break; | ||
1340 | case 0x06: p = "DUAL2 (AC) (FM)"; break; | ||
1341 | case 0x07: p = "DUAL3 (BC) (FM)"; break; | ||
1342 | case 0x08: p = "DUAL4 (AC) (AM)"; break; | ||
1343 | case 0x09: p = "DUAL5 (BC) (AM)"; break; | ||
1344 | case 0x0a: p = "SAP"; break; | ||
1345 | default: p = "undefined"; | ||
1346 | } | ||
1347 | v4l_info(client, "Configured audio mode: %s\n", p); | ||
1348 | } else { | ||
1349 | switch (audio_config & 0xF) { | ||
1350 | case 0x00: p = "BG"; break; | ||
1351 | case 0x01: p = "DK1"; break; | ||
1352 | case 0x02: p = "DK2"; break; | ||
1353 | case 0x03: p = "DK3"; break; | ||
1354 | case 0x04: p = "I"; break; | ||
1355 | case 0x05: p = "L"; break; | ||
1356 | case 0x06: p = "BTSC"; break; | ||
1357 | case 0x07: p = "EIAJ"; break; | ||
1358 | case 0x08: p = "A2-M"; break; | ||
1359 | case 0x09: p = "FM Radio"; break; | ||
1360 | case 0x0f: p = "automatic standard and mode detection"; break; | ||
1361 | default: p = "undefined"; | ||
1362 | } | ||
1363 | v4l_info(client, "Configured audio system: %s\n", p); | ||
1364 | } | ||
1365 | |||
1366 | if (aud_input) { | ||
1367 | v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); | ||
1368 | } else { | ||
1369 | v4l_info(client, "Specified audio input: External\n"); | ||
1370 | } | ||
1371 | |||
1372 | switch (pref_mode & 0xf) { | ||
1373 | case 0: p = "mono/language A"; break; | ||
1374 | case 1: p = "language B"; break; | ||
1375 | case 2: p = "language C"; break; | ||
1376 | case 3: p = "analog fallback"; break; | ||
1377 | case 4: p = "stereo"; break; | ||
1378 | case 5: p = "language AC"; break; | ||
1379 | case 6: p = "language BC"; break; | ||
1380 | case 7: p = "language AB"; break; | ||
1381 | default: p = "undefined"; | ||
1382 | } | ||
1383 | v4l_info(client, "Preferred audio mode: %s\n", p); | ||
1384 | |||
1385 | if ((audio_config & 0xf) == 0xf) { | ||
1386 | switch ((afc0 >> 3) & 0x3) { | ||
1387 | case 0: p = "system DK"; break; | ||
1388 | case 1: p = "system L"; break; | ||
1389 | case 2: p = "autodetect"; break; | ||
1390 | default: p = "undefined"; | ||
1391 | } | ||
1392 | v4l_info(client, "Selected 65 MHz format: %s\n", p); | ||
1393 | |||
1394 | switch (afc0 & 0x7) { | ||
1395 | case 0: p = "chroma"; break; | ||
1396 | case 1: p = "BTSC"; break; | ||
1397 | case 2: p = "EIAJ"; break; | ||
1398 | case 3: p = "A2-M"; break; | ||
1399 | case 4: p = "autodetect"; break; | ||
1400 | default: p = "undefined"; | ||
1401 | } | ||
1402 | v4l_info(client, "Selected 45 MHz format: %s\n", p); | ||
1403 | } | ||
1404 | } | ||
1405 | |||
1406 | /* ----------------------------------------------------------------------- */ | ||
1407 | |||
1408 | /* This load_fw operation must be called to load the driver's firmware. | ||
1409 | Without this the audio standard detection will fail and you will | ||
1410 | only get mono. | ||
1411 | |||
1412 | Since loading the firmware is often problematic when the driver is | ||
1413 | compiled into the kernel I recommend postponing calling this function | ||
1414 | until the first open of the video device. Another reason for | ||
1415 | postponing it is that loading this firmware takes a long time (seconds) | ||
1416 | due to the slow i2c bus speed. So it will speed up the boot process if | ||
1417 | you can avoid loading the fw as long as the video device isn't used. */ | ||
1418 | static int cx25840_load_fw(struct v4l2_subdev *sd) | ||
1419 | { | ||
1420 | struct cx25840_state *state = to_state(sd); | ||
1421 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1422 | |||
1423 | if (!state->is_initialized) { | ||
1424 | /* initialize and load firmware */ | ||
1425 | state->is_initialized = 1; | ||
1426 | if (is_cx2583x(state)) | ||
1427 | cx25836_initialize(client); | ||
1428 | else if (is_cx2388x(state)) | ||
1429 | cx23885_initialize(client); | ||
1430 | else if (is_cx231xx(state)) | ||
1431 | cx231xx_initialize(client); | ||
1432 | else | ||
1433 | cx25840_initialize(client); | ||
1434 | } | ||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1439 | static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | ||
1440 | { | ||
1441 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1442 | |||
1443 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
1444 | return -EINVAL; | ||
1445 | if (!capable(CAP_SYS_ADMIN)) | ||
1446 | return -EPERM; | ||
1447 | reg->size = 1; | ||
1448 | reg->val = cx25840_read(client, reg->reg & 0x0fff); | ||
1449 | return 0; | ||
1450 | } | ||
1451 | |||
1452 | static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | ||
1453 | { | ||
1454 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1455 | |||
1456 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
1457 | return -EINVAL; | ||
1458 | if (!capable(CAP_SYS_ADMIN)) | ||
1459 | return -EPERM; | ||
1460 | cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff); | ||
1461 | return 0; | ||
1462 | } | ||
1463 | #endif | ||
1464 | |||
1465 | static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable) | ||
1466 | { | ||
1467 | struct cx25840_state *state = to_state(sd); | ||
1468 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1469 | u8 v; | ||
1470 | |||
1471 | if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state)) | ||
1472 | return 0; | ||
1473 | |||
1474 | v4l_dbg(1, cx25840_debug, client, "%s audio output\n", | ||
1475 | enable ? "enable" : "disable"); | ||
1476 | |||
1477 | if (enable) { | ||
1478 | v = cx25840_read(client, 0x115) | 0x80; | ||
1479 | cx25840_write(client, 0x115, v); | ||
1480 | v = cx25840_read(client, 0x116) | 0x03; | ||
1481 | cx25840_write(client, 0x116, v); | ||
1482 | } else { | ||
1483 | v = cx25840_read(client, 0x115) & ~(0x80); | ||
1484 | cx25840_write(client, 0x115, v); | ||
1485 | v = cx25840_read(client, 0x116) & ~(0x03); | ||
1486 | cx25840_write(client, 0x116, v); | ||
1487 | } | ||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) | ||
1492 | { | ||
1493 | struct cx25840_state *state = to_state(sd); | ||
1494 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1495 | u8 v; | ||
1496 | |||
1497 | v4l_dbg(1, cx25840_debug, client, "%s video output\n", | ||
1498 | enable ? "enable" : "disable"); | ||
1499 | if (enable) { | ||
1500 | if (is_cx2388x(state) || is_cx231xx(state)) { | ||
1501 | v = cx25840_read(client, 0x421) | 0x0b; | ||
1502 | cx25840_write(client, 0x421, v); | ||
1503 | } else { | ||
1504 | v = cx25840_read(client, 0x115) | 0x0c; | ||
1505 | cx25840_write(client, 0x115, v); | ||
1506 | v = cx25840_read(client, 0x116) | 0x04; | ||
1507 | cx25840_write(client, 0x116, v); | ||
1508 | } | ||
1509 | } else { | ||
1510 | if (is_cx2388x(state) || is_cx231xx(state)) { | ||
1511 | v = cx25840_read(client, 0x421) & ~(0x0b); | ||
1512 | cx25840_write(client, 0x421, v); | ||
1513 | } else { | ||
1514 | v = cx25840_read(client, 0x115) & ~(0x0c); | ||
1515 | cx25840_write(client, 0x115, v); | ||
1516 | v = cx25840_read(client, 0x116) & ~(0x04); | ||
1517 | cx25840_write(client, 0x116, v); | ||
1518 | } | ||
1519 | } | ||
1520 | return 0; | ||
1521 | } | ||
1522 | |||
1523 | static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) | ||
1524 | { | ||
1525 | struct cx25840_state *state = to_state(sd); | ||
1526 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1527 | |||
1528 | if (state->radio == 0 && state->std == std) | ||
1529 | return 0; | ||
1530 | state->radio = 0; | ||
1531 | state->std = std; | ||
1532 | return set_v4lstd(client); | ||
1533 | } | ||
1534 | |||
1535 | static int cx25840_s_radio(struct v4l2_subdev *sd) | ||
1536 | { | ||
1537 | struct cx25840_state *state = to_state(sd); | ||
1538 | |||
1539 | state->radio = 1; | ||
1540 | return 0; | ||
1541 | } | ||
1542 | |||
1543 | static int cx25840_s_video_routing(struct v4l2_subdev *sd, | ||
1544 | u32 input, u32 output, u32 config) | ||
1545 | { | ||
1546 | struct cx25840_state *state = to_state(sd); | ||
1547 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1548 | |||
1549 | return set_input(client, input, state->aud_input); | ||
1550 | } | ||
1551 | |||
1552 | static int cx25840_s_audio_routing(struct v4l2_subdev *sd, | ||
1553 | u32 input, u32 output, u32 config) | ||
1554 | { | ||
1555 | struct cx25840_state *state = to_state(sd); | ||
1556 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1557 | |||
1558 | return set_input(client, state->vid_input, input); | ||
1559 | } | ||
1560 | |||
1561 | static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) | ||
1562 | { | ||
1563 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1564 | |||
1565 | input_change(client); | ||
1566 | return 0; | ||
1567 | } | ||
1568 | |||
1569 | static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | ||
1570 | { | ||
1571 | struct cx25840_state *state = to_state(sd); | ||
1572 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1573 | u8 vpres = cx25840_read(client, 0x40e) & 0x20; | ||
1574 | u8 mode; | ||
1575 | int val = 0; | ||
1576 | |||
1577 | if (state->radio) | ||
1578 | return 0; | ||
1579 | |||
1580 | vt->signal = vpres ? 0xffff : 0x0; | ||
1581 | if (is_cx2583x(state)) | ||
1582 | return 0; | ||
1583 | |||
1584 | vt->capability |= | ||
1585 | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | | ||
1586 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; | ||
1587 | |||
1588 | mode = cx25840_read(client, 0x804); | ||
1589 | |||
1590 | /* get rxsubchans and audmode */ | ||
1591 | if ((mode & 0xf) == 1) | ||
1592 | val |= V4L2_TUNER_SUB_STEREO; | ||
1593 | else | ||
1594 | val |= V4L2_TUNER_SUB_MONO; | ||
1595 | |||
1596 | if (mode == 2 || mode == 4) | ||
1597 | val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
1598 | |||
1599 | if (mode & 0x10) | ||
1600 | val |= V4L2_TUNER_SUB_SAP; | ||
1601 | |||
1602 | vt->rxsubchans = val; | ||
1603 | vt->audmode = state->audmode; | ||
1604 | return 0; | ||
1605 | } | ||
1606 | |||
1607 | static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | ||
1608 | { | ||
1609 | struct cx25840_state *state = to_state(sd); | ||
1610 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1611 | |||
1612 | if (state->radio || is_cx2583x(state)) | ||
1613 | return 0; | ||
1614 | |||
1615 | switch (vt->audmode) { | ||
1616 | case V4L2_TUNER_MODE_MONO: | ||
1617 | /* mono -> mono | ||
1618 | stereo -> mono | ||
1619 | bilingual -> lang1 */ | ||
1620 | cx25840_and_or(client, 0x809, ~0xf, 0x00); | ||
1621 | break; | ||
1622 | case V4L2_TUNER_MODE_STEREO: | ||
1623 | case V4L2_TUNER_MODE_LANG1: | ||
1624 | /* mono -> mono | ||
1625 | stereo -> stereo | ||
1626 | bilingual -> lang1 */ | ||
1627 | cx25840_and_or(client, 0x809, ~0xf, 0x04); | ||
1628 | break; | ||
1629 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
1630 | /* mono -> mono | ||
1631 | stereo -> stereo | ||
1632 | bilingual -> lang1/lang2 */ | ||
1633 | cx25840_and_or(client, 0x809, ~0xf, 0x07); | ||
1634 | break; | ||
1635 | case V4L2_TUNER_MODE_LANG2: | ||
1636 | /* mono -> mono | ||
1637 | stereo -> stereo | ||
1638 | bilingual -> lang2 */ | ||
1639 | cx25840_and_or(client, 0x809, ~0xf, 0x01); | ||
1640 | break; | ||
1641 | default: | ||
1642 | return -EINVAL; | ||
1643 | } | ||
1644 | state->audmode = vt->audmode; | ||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | static int cx25840_reset(struct v4l2_subdev *sd, u32 val) | ||
1649 | { | ||
1650 | struct cx25840_state *state = to_state(sd); | ||
1651 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1652 | |||
1653 | if (is_cx2583x(state)) | ||
1654 | cx25836_initialize(client); | ||
1655 | else if (is_cx2388x(state)) | ||
1656 | cx23885_initialize(client); | ||
1657 | else if (is_cx231xx(state)) | ||
1658 | cx231xx_initialize(client); | ||
1659 | else | ||
1660 | cx25840_initialize(client); | ||
1661 | return 0; | ||
1662 | } | ||
1663 | |||
1664 | static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | ||
1665 | { | ||
1666 | struct cx25840_state *state = to_state(sd); | ||
1667 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1668 | |||
1669 | return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); | ||
1670 | } | ||
1671 | |||
1672 | static int cx25840_log_status(struct v4l2_subdev *sd) | ||
1673 | { | ||
1674 | struct cx25840_state *state = to_state(sd); | ||
1675 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1676 | |||
1677 | log_video_status(client); | ||
1678 | if (!is_cx2583x(state)) | ||
1679 | log_audio_status(client); | ||
1680 | cx25840_ir_log_status(sd); | ||
1681 | v4l2_ctrl_handler_log_status(&state->hdl, sd->name); | ||
1682 | return 0; | ||
1683 | } | ||
1684 | |||
1685 | static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status, | ||
1686 | bool *handled) | ||
1687 | { | ||
1688 | struct cx25840_state *state = to_state(sd); | ||
1689 | struct i2c_client *c = v4l2_get_subdevdata(sd); | ||
1690 | u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en; | ||
1691 | u32 vid_stat, aud_mc_stat; | ||
1692 | bool block_handled; | ||
1693 | int ret = 0; | ||
1694 | |||
1695 | irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG); | ||
1696 | v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n", | ||
1697 | irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ", | ||
1698 | irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ", | ||
1699 | irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " "); | ||
1700 | |||
1701 | if ((is_cx23885(state) || is_cx23887(state))) { | ||
1702 | ir_stat = cx25840_read(c, CX25840_IR_STATS_REG); | ||
1703 | ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG); | ||
1704 | v4l_dbg(2, cx25840_debug, c, | ||
1705 | "AV Core ir IRQ status: %#04x disables: %#04x\n", | ||
1706 | ir_stat, ir_en); | ||
1707 | if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) { | ||
1708 | block_handled = false; | ||
1709 | ret = cx25840_ir_irq_handler(sd, | ||
1710 | status, &block_handled); | ||
1711 | if (block_handled) | ||
1712 | *handled = true; | ||
1713 | } | ||
1714 | } | ||
1715 | |||
1716 | aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG); | ||
1717 | aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG); | ||
1718 | v4l_dbg(2, cx25840_debug, c, | ||
1719 | "AV Core audio IRQ status: %#04x disables: %#04x\n", | ||
1720 | aud_stat, aud_en); | ||
1721 | aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG); | ||
1722 | v4l_dbg(2, cx25840_debug, c, | ||
1723 | "AV Core audio MC IRQ status: %#06x enables: %#06x\n", | ||
1724 | aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT, | ||
1725 | aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS); | ||
1726 | if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) { | ||
1727 | if (aud_stat) { | ||
1728 | cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat); | ||
1729 | *handled = true; | ||
1730 | } | ||
1731 | } | ||
1732 | |||
1733 | vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG); | ||
1734 | v4l_dbg(2, cx25840_debug, c, | ||
1735 | "AV Core video IRQ status: %#06x disables: %#06x\n", | ||
1736 | vid_stat & CX25840_VID_INT_STAT_BITS, | ||
1737 | vid_stat >> CX25840_VID_INT_MASK_SHFT); | ||
1738 | if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) { | ||
1739 | if (vid_stat & CX25840_VID_INT_STAT_BITS) { | ||
1740 | cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat); | ||
1741 | *handled = true; | ||
1742 | } | ||
1743 | } | ||
1744 | |||
1745 | irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG); | ||
1746 | v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n", | ||
1747 | irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ", | ||
1748 | irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ", | ||
1749 | irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " "); | ||
1750 | |||
1751 | return ret; | ||
1752 | } | ||
1753 | |||
1754 | static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, | ||
1755 | bool *handled) | ||
1756 | { | ||
1757 | struct cx25840_state *state = to_state(sd); | ||
1758 | |||
1759 | *handled = false; | ||
1760 | |||
1761 | /* Only support the CX2388[578] AV Core for now */ | ||
1762 | if (is_cx2388x(state)) | ||
1763 | return cx23885_irq_handler(sd, status, handled); | ||
1764 | |||
1765 | return -ENODEV; | ||
1766 | } | ||
1767 | |||
1768 | /* ----------------------------------------------------------------------- */ | ||
1769 | |||
1770 | static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { | ||
1771 | .s_ctrl = cx25840_s_ctrl, | ||
1772 | }; | ||
1773 | |||
1774 | static const struct v4l2_subdev_core_ops cx25840_core_ops = { | ||
1775 | .log_status = cx25840_log_status, | ||
1776 | .g_chip_ident = cx25840_g_chip_ident, | ||
1777 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
1778 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
1779 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
1780 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
1781 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
1782 | .queryctrl = v4l2_subdev_queryctrl, | ||
1783 | .querymenu = v4l2_subdev_querymenu, | ||
1784 | .s_std = cx25840_s_std, | ||
1785 | .reset = cx25840_reset, | ||
1786 | .load_fw = cx25840_load_fw, | ||
1787 | .s_io_pin_config = common_s_io_pin_config, | ||
1788 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1789 | .g_register = cx25840_g_register, | ||
1790 | .s_register = cx25840_s_register, | ||
1791 | #endif | ||
1792 | .interrupt_service_routine = cx25840_irq_handler, | ||
1793 | }; | ||
1794 | |||
1795 | static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { | ||
1796 | .s_frequency = cx25840_s_frequency, | ||
1797 | .s_radio = cx25840_s_radio, | ||
1798 | .g_tuner = cx25840_g_tuner, | ||
1799 | .s_tuner = cx25840_s_tuner, | ||
1800 | }; | ||
1801 | |||
1802 | static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { | ||
1803 | .s_clock_freq = cx25840_s_clock_freq, | ||
1804 | .s_routing = cx25840_s_audio_routing, | ||
1805 | .s_stream = cx25840_s_audio_stream, | ||
1806 | }; | ||
1807 | |||
1808 | static const struct v4l2_subdev_video_ops cx25840_video_ops = { | ||
1809 | .s_routing = cx25840_s_video_routing, | ||
1810 | .s_mbus_fmt = cx25840_s_mbus_fmt, | ||
1811 | .s_stream = cx25840_s_stream, | ||
1812 | }; | ||
1813 | |||
1814 | static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = { | ||
1815 | .decode_vbi_line = cx25840_decode_vbi_line, | ||
1816 | .s_raw_fmt = cx25840_s_raw_fmt, | ||
1817 | .s_sliced_fmt = cx25840_s_sliced_fmt, | ||
1818 | .g_sliced_fmt = cx25840_g_sliced_fmt, | ||
1819 | }; | ||
1820 | |||
1821 | static const struct v4l2_subdev_ops cx25840_ops = { | ||
1822 | .core = &cx25840_core_ops, | ||
1823 | .tuner = &cx25840_tuner_ops, | ||
1824 | .audio = &cx25840_audio_ops, | ||
1825 | .video = &cx25840_video_ops, | ||
1826 | .vbi = &cx25840_vbi_ops, | ||
1827 | .ir = &cx25840_ir_ops, | ||
1828 | }; | ||
1829 | |||
1830 | /* ----------------------------------------------------------------------- */ | ||
1831 | |||
1832 | static u32 get_cx2388x_ident(struct i2c_client *client) | ||
1833 | { | ||
1834 | u32 ret; | ||
1835 | |||
1836 | /* Come out of digital power down */ | ||
1837 | cx25840_write(client, 0x000, 0); | ||
1838 | |||
1839 | /* Detecting whether the part is cx23885/7/8 is more | ||
1840 | * difficult than it needs to be. No ID register. Instead we | ||
1841 | * probe certain registers indicated in the datasheets to look | ||
1842 | * for specific defaults that differ between the silicon designs. */ | ||
1843 | |||
1844 | /* It's either 885/7 if the IR Tx Clk Divider register exists */ | ||
1845 | if (cx25840_read4(client, 0x204) & 0xffff) { | ||
1846 | /* CX23885 returns bogus repetitive byte values for the DIF, | ||
1847 | * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ | ||
1848 | ret = cx25840_read4(client, 0x300); | ||
1849 | if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { | ||
1850 | /* No DIF */ | ||
1851 | ret = V4L2_IDENT_CX23885_AV; | ||
1852 | } else { | ||
1853 | /* CX23887 has a broken DIF, but the registers | ||
1854 | * appear valid (but unused), good enough to detect. */ | ||
1855 | ret = V4L2_IDENT_CX23887_AV; | ||
1856 | } | ||
1857 | } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { | ||
1858 | /* DIF PLL Freq Word reg exists; chip must be a CX23888 */ | ||
1859 | ret = V4L2_IDENT_CX23888_AV; | ||
1860 | } else { | ||
1861 | v4l_err(client, "Unable to detect h/w, assuming cx23887\n"); | ||
1862 | ret = V4L2_IDENT_CX23887_AV; | ||
1863 | } | ||
1864 | |||
1865 | /* Back into digital power down */ | ||
1866 | cx25840_write(client, 0x000, 2); | ||
1867 | return ret; | ||
1868 | } | ||
1869 | |||
1870 | static int cx25840_probe(struct i2c_client *client, | ||
1871 | const struct i2c_device_id *did) | ||
1872 | { | ||
1873 | struct cx25840_state *state; | ||
1874 | struct v4l2_subdev *sd; | ||
1875 | int default_volume; | ||
1876 | u32 id = V4L2_IDENT_NONE; | ||
1877 | u16 device_id; | ||
1878 | |||
1879 | /* Check if the adapter supports the needed features */ | ||
1880 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
1881 | return -EIO; | ||
1882 | |||
1883 | v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); | ||
1884 | |||
1885 | device_id = cx25840_read(client, 0x101) << 8; | ||
1886 | device_id |= cx25840_read(client, 0x100); | ||
1887 | v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); | ||
1888 | |||
1889 | /* The high byte of the device ID should be | ||
1890 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ | ||
1891 | if ((device_id & 0xff00) == 0x8300) { | ||
1892 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | ||
1893 | } else if ((device_id & 0xff00) == 0x8400) { | ||
1894 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | ||
1895 | } else if (device_id == 0x0000) { | ||
1896 | id = get_cx2388x_ident(client); | ||
1897 | } else if ((device_id & 0xfff0) == 0x5A30) { | ||
1898 | /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */ | ||
1899 | id = V4L2_IDENT_CX2310X_AV; | ||
1900 | } else if ((device_id & 0xff) == (device_id >> 8)) { | ||
1901 | v4l_err(client, | ||
1902 | "likely a confused/unresponsive cx2388[578] A/V decoder" | ||
1903 | " found @ 0x%x (%s)\n", | ||
1904 | client->addr << 1, client->adapter->name); | ||
1905 | v4l_err(client, "A method to reset it from the cx25840 driver" | ||
1906 | " software is not known at this time\n"); | ||
1907 | return -ENODEV; | ||
1908 | } else { | ||
1909 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); | ||
1910 | return -ENODEV; | ||
1911 | } | ||
1912 | |||
1913 | state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); | ||
1914 | if (state == NULL) | ||
1915 | return -ENOMEM; | ||
1916 | |||
1917 | sd = &state->sd; | ||
1918 | v4l2_i2c_subdev_init(sd, client, &cx25840_ops); | ||
1919 | |||
1920 | switch (id) { | ||
1921 | case V4L2_IDENT_CX23885_AV: | ||
1922 | v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n", | ||
1923 | client->addr << 1, client->adapter->name); | ||
1924 | break; | ||
1925 | case V4L2_IDENT_CX23887_AV: | ||
1926 | v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n", | ||
1927 | client->addr << 1, client->adapter->name); | ||
1928 | break; | ||
1929 | case V4L2_IDENT_CX23888_AV: | ||
1930 | v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n", | ||
1931 | client->addr << 1, client->adapter->name); | ||
1932 | break; | ||
1933 | case V4L2_IDENT_CX2310X_AV: | ||
1934 | v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n", | ||
1935 | device_id, client->addr << 1, client->adapter->name); | ||
1936 | break; | ||
1937 | case V4L2_IDENT_CX25840: | ||
1938 | case V4L2_IDENT_CX25841: | ||
1939 | case V4L2_IDENT_CX25842: | ||
1940 | case V4L2_IDENT_CX25843: | ||
1941 | /* Note: revision '(device_id & 0x0f) == 2' was never built. The | ||
1942 | marking skips from 0x1 == 22 to 0x3 == 23. */ | ||
1943 | v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", | ||
1944 | (device_id & 0xfff0) >> 4, | ||
1945 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 | ||
1946 | : (device_id & 0x0f), | ||
1947 | client->addr << 1, client->adapter->name); | ||
1948 | break; | ||
1949 | case V4L2_IDENT_CX25836: | ||
1950 | case V4L2_IDENT_CX25837: | ||
1951 | default: | ||
1952 | v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n", | ||
1953 | (device_id & 0xfff0) >> 4, device_id & 0x0f, | ||
1954 | client->addr << 1, client->adapter->name); | ||
1955 | break; | ||
1956 | } | ||
1957 | |||
1958 | state->c = client; | ||
1959 | state->vid_input = CX25840_COMPOSITE7; | ||
1960 | state->aud_input = CX25840_AUDIO8; | ||
1961 | state->audclk_freq = 48000; | ||
1962 | state->audmode = V4L2_TUNER_MODE_LANG1; | ||
1963 | state->vbi_line_offset = 8; | ||
1964 | state->id = id; | ||
1965 | state->rev = device_id; | ||
1966 | v4l2_ctrl_handler_init(&state->hdl, 9); | ||
1967 | v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, | ||
1968 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
1969 | v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, | ||
1970 | V4L2_CID_CONTRAST, 0, 127, 1, 64); | ||
1971 | v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, | ||
1972 | V4L2_CID_SATURATION, 0, 127, 1, 64); | ||
1973 | v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, | ||
1974 | V4L2_CID_HUE, -128, 127, 1, 0); | ||
1975 | if (!is_cx2583x(state)) { | ||
1976 | default_volume = cx25840_read(client, 0x8d4); | ||
1977 | /* | ||
1978 | * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume | ||
1979 | * scale mapping limits to avoid -ERANGE errors when | ||
1980 | * initializing the volume control | ||
1981 | */ | ||
1982 | if (default_volume > 228) { | ||
1983 | /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ | ||
1984 | default_volume = 228; | ||
1985 | cx25840_write(client, 0x8d4, 228); | ||
1986 | } | ||
1987 | else if (default_volume < 20) { | ||
1988 | /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ | ||
1989 | default_volume = 20; | ||
1990 | cx25840_write(client, 0x8d4, 20); | ||
1991 | } | ||
1992 | default_volume = (((228 - default_volume) >> 1) + 23) << 9; | ||
1993 | |||
1994 | state->volume = v4l2_ctrl_new_std(&state->hdl, | ||
1995 | &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, | ||
1996 | 0, 65535, 65535 / 100, default_volume); | ||
1997 | state->mute = v4l2_ctrl_new_std(&state->hdl, | ||
1998 | &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, | ||
1999 | 0, 1, 1, 0); | ||
2000 | v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, | ||
2001 | V4L2_CID_AUDIO_BALANCE, | ||
2002 | 0, 65535, 65535 / 100, 32768); | ||
2003 | v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, | ||
2004 | V4L2_CID_AUDIO_BASS, | ||
2005 | 0, 65535, 65535 / 100, 32768); | ||
2006 | v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, | ||
2007 | V4L2_CID_AUDIO_TREBLE, | ||
2008 | 0, 65535, 65535 / 100, 32768); | ||
2009 | } | ||
2010 | sd->ctrl_handler = &state->hdl; | ||
2011 | if (state->hdl.error) { | ||
2012 | int err = state->hdl.error; | ||
2013 | |||
2014 | v4l2_ctrl_handler_free(&state->hdl); | ||
2015 | kfree(state); | ||
2016 | return err; | ||
2017 | } | ||
2018 | if (!is_cx2583x(state)) | ||
2019 | v4l2_ctrl_cluster(2, &state->volume); | ||
2020 | v4l2_ctrl_handler_setup(&state->hdl); | ||
2021 | |||
2022 | if (client->dev.platform_data) { | ||
2023 | struct cx25840_platform_data *pdata = client->dev.platform_data; | ||
2024 | |||
2025 | state->pvr150_workaround = pdata->pvr150_workaround; | ||
2026 | } | ||
2027 | |||
2028 | cx25840_ir_probe(sd); | ||
2029 | return 0; | ||
2030 | } | ||
2031 | |||
2032 | static int cx25840_remove(struct i2c_client *client) | ||
2033 | { | ||
2034 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
2035 | struct cx25840_state *state = to_state(sd); | ||
2036 | |||
2037 | cx25840_ir_remove(sd); | ||
2038 | v4l2_device_unregister_subdev(sd); | ||
2039 | v4l2_ctrl_handler_free(&state->hdl); | ||
2040 | kfree(state); | ||
2041 | return 0; | ||
2042 | } | ||
2043 | |||
2044 | static const struct i2c_device_id cx25840_id[] = { | ||
2045 | { "cx25840", 0 }, | ||
2046 | { } | ||
2047 | }; | ||
2048 | MODULE_DEVICE_TABLE(i2c, cx25840_id); | ||
2049 | |||
2050 | static struct i2c_driver cx25840_driver = { | ||
2051 | .driver = { | ||
2052 | .owner = THIS_MODULE, | ||
2053 | .name = "cx25840", | ||
2054 | }, | ||
2055 | .probe = cx25840_probe, | ||
2056 | .remove = cx25840_remove, | ||
2057 | .id_table = cx25840_id, | ||
2058 | }; | ||
2059 | |||
2060 | static __init int init_cx25840(void) | ||
2061 | { | ||
2062 | return i2c_add_driver(&cx25840_driver); | ||
2063 | } | ||
2064 | |||
2065 | static __exit void exit_cx25840(void) | ||
2066 | { | ||
2067 | i2c_del_driver(&cx25840_driver); | ||
2068 | } | ||
2069 | |||
2070 | module_init(init_cx25840); | ||
2071 | module_exit(exit_cx25840); | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h new file mode 100644 index 00000000000..bd4ada28b49 --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-core.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* cx25840 internal API header | ||
2 | * | ||
3 | * Copyright (C) 2003-2004 Chris Kennedy | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef _CX25840_CORE_H_ | ||
21 | #define _CX25840_CORE_H_ | ||
22 | |||
23 | |||
24 | #include <linux/videodev2.h> | ||
25 | #include <media/v4l2-device.h> | ||
26 | #include <media/v4l2-chip-ident.h> | ||
27 | #include <media/v4l2-ctrls.h> | ||
28 | #include <linux/i2c.h> | ||
29 | |||
30 | struct cx25840_ir_state; | ||
31 | |||
32 | struct cx25840_state { | ||
33 | struct i2c_client *c; | ||
34 | struct v4l2_subdev sd; | ||
35 | struct v4l2_ctrl_handler hdl; | ||
36 | struct { | ||
37 | /* volume cluster */ | ||
38 | struct v4l2_ctrl *volume; | ||
39 | struct v4l2_ctrl *mute; | ||
40 | }; | ||
41 | int pvr150_workaround; | ||
42 | int radio; | ||
43 | v4l2_std_id std; | ||
44 | enum cx25840_video_input vid_input; | ||
45 | enum cx25840_audio_input aud_input; | ||
46 | u32 audclk_freq; | ||
47 | int audmode; | ||
48 | int vbi_line_offset; | ||
49 | u32 id; | ||
50 | u32 rev; | ||
51 | int is_initialized; | ||
52 | wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ | ||
53 | struct work_struct fw_work; /* work entry for fw load */ | ||
54 | struct cx25840_ir_state *ir_state; | ||
55 | }; | ||
56 | |||
57 | static inline struct cx25840_state *to_state(struct v4l2_subdev *sd) | ||
58 | { | ||
59 | return container_of(sd, struct cx25840_state, sd); | ||
60 | } | ||
61 | |||
62 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
63 | { | ||
64 | return &container_of(ctrl->handler, struct cx25840_state, hdl)->sd; | ||
65 | } | ||
66 | |||
67 | static inline bool is_cx2583x(struct cx25840_state *state) | ||
68 | { | ||
69 | return state->id == V4L2_IDENT_CX25836 || | ||
70 | state->id == V4L2_IDENT_CX25837; | ||
71 | } | ||
72 | |||
73 | static inline bool is_cx231xx(struct cx25840_state *state) | ||
74 | { | ||
75 | return state->id == V4L2_IDENT_CX2310X_AV; | ||
76 | } | ||
77 | |||
78 | static inline bool is_cx2388x(struct cx25840_state *state) | ||
79 | { | ||
80 | return state->id == V4L2_IDENT_CX23885_AV || | ||
81 | state->id == V4L2_IDENT_CX23887_AV || | ||
82 | state->id == V4L2_IDENT_CX23888_AV; | ||
83 | } | ||
84 | |||
85 | static inline bool is_cx23885(struct cx25840_state *state) | ||
86 | { | ||
87 | return state->id == V4L2_IDENT_CX23885_AV; | ||
88 | } | ||
89 | |||
90 | static inline bool is_cx23887(struct cx25840_state *state) | ||
91 | { | ||
92 | return state->id == V4L2_IDENT_CX23887_AV; | ||
93 | } | ||
94 | |||
95 | static inline bool is_cx23888(struct cx25840_state *state) | ||
96 | { | ||
97 | return state->id == V4L2_IDENT_CX23888_AV; | ||
98 | } | ||
99 | |||
100 | /* ----------------------------------------------------------------------- */ | ||
101 | /* cx25850-core.c */ | ||
102 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value); | ||
103 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); | ||
104 | u8 cx25840_read(struct i2c_client *client, u16 addr); | ||
105 | u32 cx25840_read4(struct i2c_client *client, u16 addr); | ||
106 | int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); | ||
107 | int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, | ||
108 | u32 or_value); | ||
109 | void cx25840_std_setup(struct i2c_client *client); | ||
110 | |||
111 | /* ----------------------------------------------------------------------- */ | ||
112 | /* cx25850-firmware.c */ | ||
113 | int cx25840_loadfw(struct i2c_client *client); | ||
114 | |||
115 | /* ----------------------------------------------------------------------- */ | ||
116 | /* cx25850-audio.c */ | ||
117 | void cx25840_audio_set_path(struct i2c_client *client); | ||
118 | int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq); | ||
119 | |||
120 | extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops; | ||
121 | |||
122 | /* ----------------------------------------------------------------------- */ | ||
123 | /* cx25850-vbi.c */ | ||
124 | int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); | ||
125 | int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); | ||
126 | int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); | ||
127 | int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi); | ||
128 | |||
129 | /* ----------------------------------------------------------------------- */ | ||
130 | /* cx25850-ir.c */ | ||
131 | extern const struct v4l2_subdev_ir_ops cx25840_ir_ops; | ||
132 | int cx25840_ir_log_status(struct v4l2_subdev *sd); | ||
133 | int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled); | ||
134 | int cx25840_ir_probe(struct v4l2_subdev *sd); | ||
135 | int cx25840_ir_remove(struct v4l2_subdev *sd); | ||
136 | |||
137 | #endif | ||
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c new file mode 100644 index 00000000000..8150200511d --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-firmware.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* cx25840 firmware functions | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of the GNU General Public License | ||
5 | * as published by the Free Software Foundation; either version 2 | ||
6 | * of the License, or (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/firmware.h> | ||
21 | #include <media/v4l2-common.h> | ||
22 | #include <media/cx25840.h> | ||
23 | |||
24 | #include "cx25840-core.h" | ||
25 | |||
26 | /* | ||
27 | * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the | ||
28 | * size of the firmware chunks sent down the I2C bus to the chip. | ||
29 | * Previously this had been set to 1024 but unfortunately some I2C | ||
30 | * implementations can't transfer data in such big gulps. | ||
31 | * Specifically, the pvrusb2 driver has a hard limit of around 60 | ||
32 | * bytes, due to the encapsulation there of I2C traffic into USB | ||
33 | * messages. So we have to significantly reduce this parameter. | ||
34 | */ | ||
35 | #define FWSEND 48 | ||
36 | |||
37 | #define FWDEV(x) &((x)->dev) | ||
38 | |||
39 | static char *firmware = ""; | ||
40 | |||
41 | module_param(firmware, charp, 0444); | ||
42 | |||
43 | MODULE_PARM_DESC(firmware, "Firmware image to load"); | ||
44 | |||
45 | static void start_fw_load(struct i2c_client *client) | ||
46 | { | ||
47 | /* DL_ADDR_LB=0 DL_ADDR_HB=0 */ | ||
48 | cx25840_write(client, 0x800, 0x00); | ||
49 | cx25840_write(client, 0x801, 0x00); | ||
50 | // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1 | ||
51 | cx25840_write(client, 0x803, 0x0b); | ||
52 | /* AUTO_INC_DIS=1 */ | ||
53 | cx25840_write(client, 0x000, 0x20); | ||
54 | } | ||
55 | |||
56 | static void end_fw_load(struct i2c_client *client) | ||
57 | { | ||
58 | /* AUTO_INC_DIS=0 */ | ||
59 | cx25840_write(client, 0x000, 0x00); | ||
60 | /* DL_ENABLE=0 */ | ||
61 | cx25840_write(client, 0x803, 0x03); | ||
62 | } | ||
63 | |||
64 | static const char *get_fw_name(struct i2c_client *client) | ||
65 | { | ||
66 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
67 | |||
68 | if (firmware[0]) | ||
69 | return firmware; | ||
70 | if (is_cx2388x(state)) | ||
71 | return "v4l-cx23885-avcore-01.fw"; | ||
72 | if (is_cx231xx(state)) | ||
73 | return "v4l-cx231xx-avcore-01.fw"; | ||
74 | return "v4l-cx25840.fw"; | ||
75 | } | ||
76 | |||
77 | static int check_fw_load(struct i2c_client *client, int size) | ||
78 | { | ||
79 | /* DL_ADDR_HB DL_ADDR_LB */ | ||
80 | int s = cx25840_read(client, 0x801) << 8; | ||
81 | s |= cx25840_read(client, 0x800); | ||
82 | |||
83 | if (size != s) { | ||
84 | v4l_err(client, "firmware %s load failed\n", | ||
85 | get_fw_name(client)); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | v4l_info(client, "loaded %s firmware (%d bytes)\n", | ||
90 | get_fw_name(client), size); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int fw_write(struct i2c_client *client, const u8 *data, int size) | ||
95 | { | ||
96 | if (i2c_master_send(client, data, size) < size) { | ||
97 | v4l_err(client, "firmware load i2c failure\n"); | ||
98 | return -ENOSYS; | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | int cx25840_loadfw(struct i2c_client *client) | ||
105 | { | ||
106 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
107 | const struct firmware *fw = NULL; | ||
108 | u8 buffer[FWSEND]; | ||
109 | const u8 *ptr; | ||
110 | const char *fwname = get_fw_name(client); | ||
111 | int size, retval; | ||
112 | int MAX_BUF_SIZE = FWSEND; | ||
113 | u32 gpio_oe = 0, gpio_da = 0; | ||
114 | |||
115 | if (is_cx2388x(state)) { | ||
116 | /* Preserve the GPIO OE and output bits */ | ||
117 | gpio_oe = cx25840_read(client, 0x160); | ||
118 | gpio_da = cx25840_read(client, 0x164); | ||
119 | } | ||
120 | |||
121 | if (is_cx231xx(state) && MAX_BUF_SIZE > 16) { | ||
122 | v4l_err(client, " Firmware download size changed to 16 bytes max length\n"); | ||
123 | MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */ | ||
124 | } | ||
125 | |||
126 | if (request_firmware(&fw, fwname, FWDEV(client)) != 0) { | ||
127 | v4l_err(client, "unable to open firmware %s\n", fwname); | ||
128 | return -EINVAL; | ||
129 | } | ||
130 | |||
131 | start_fw_load(client); | ||
132 | |||
133 | buffer[0] = 0x08; | ||
134 | buffer[1] = 0x02; | ||
135 | |||
136 | size = fw->size; | ||
137 | ptr = fw->data; | ||
138 | while (size > 0) { | ||
139 | int len = min(MAX_BUF_SIZE - 2, size); | ||
140 | |||
141 | memcpy(buffer + 2, ptr, len); | ||
142 | |||
143 | retval = fw_write(client, buffer, len + 2); | ||
144 | |||
145 | if (retval < 0) { | ||
146 | release_firmware(fw); | ||
147 | return retval; | ||
148 | } | ||
149 | |||
150 | size -= len; | ||
151 | ptr += len; | ||
152 | } | ||
153 | |||
154 | end_fw_load(client); | ||
155 | |||
156 | size = fw->size; | ||
157 | release_firmware(fw); | ||
158 | |||
159 | if (is_cx2388x(state)) { | ||
160 | /* Restore GPIO configuration after f/w load */ | ||
161 | cx25840_write(client, 0x160, gpio_oe); | ||
162 | cx25840_write(client, 0x164, gpio_da); | ||
163 | } | ||
164 | |||
165 | return check_fw_load(client, size); | ||
166 | } | ||
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c new file mode 100644 index 00000000000..7eb79af28aa --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-ir.c | |||
@@ -0,0 +1,1280 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX2584x Audio/Video decoder chip and related cores | ||
3 | * | ||
4 | * Integrated Consumer Infrared Controller | ||
5 | * | ||
6 | * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/kfifo.h> | ||
26 | #include <media/cx25840.h> | ||
27 | #include <media/rc-core.h> | ||
28 | |||
29 | #include "cx25840-core.h" | ||
30 | |||
31 | static unsigned int ir_debug; | ||
32 | module_param(ir_debug, int, 0644); | ||
33 | MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages"); | ||
34 | |||
35 | #define CX25840_IR_REG_BASE 0x200 | ||
36 | |||
37 | #define CX25840_IR_CNTRL_REG 0x200 | ||
38 | #define CNTRL_WIN_3_3 0x00000000 | ||
39 | #define CNTRL_WIN_4_3 0x00000001 | ||
40 | #define CNTRL_WIN_3_4 0x00000002 | ||
41 | #define CNTRL_WIN_4_4 0x00000003 | ||
42 | #define CNTRL_WIN 0x00000003 | ||
43 | #define CNTRL_EDG_NONE 0x00000000 | ||
44 | #define CNTRL_EDG_FALL 0x00000004 | ||
45 | #define CNTRL_EDG_RISE 0x00000008 | ||
46 | #define CNTRL_EDG_BOTH 0x0000000C | ||
47 | #define CNTRL_EDG 0x0000000C | ||
48 | #define CNTRL_DMD 0x00000010 | ||
49 | #define CNTRL_MOD 0x00000020 | ||
50 | #define CNTRL_RFE 0x00000040 | ||
51 | #define CNTRL_TFE 0x00000080 | ||
52 | #define CNTRL_RXE 0x00000100 | ||
53 | #define CNTRL_TXE 0x00000200 | ||
54 | #define CNTRL_RIC 0x00000400 | ||
55 | #define CNTRL_TIC 0x00000800 | ||
56 | #define CNTRL_CPL 0x00001000 | ||
57 | #define CNTRL_LBM 0x00002000 | ||
58 | #define CNTRL_R 0x00004000 | ||
59 | |||
60 | #define CX25840_IR_TXCLK_REG 0x204 | ||
61 | #define TXCLK_TCD 0x0000FFFF | ||
62 | |||
63 | #define CX25840_IR_RXCLK_REG 0x208 | ||
64 | #define RXCLK_RCD 0x0000FFFF | ||
65 | |||
66 | #define CX25840_IR_CDUTY_REG 0x20C | ||
67 | #define CDUTY_CDC 0x0000000F | ||
68 | |||
69 | #define CX25840_IR_STATS_REG 0x210 | ||
70 | #define STATS_RTO 0x00000001 | ||
71 | #define STATS_ROR 0x00000002 | ||
72 | #define STATS_RBY 0x00000004 | ||
73 | #define STATS_TBY 0x00000008 | ||
74 | #define STATS_RSR 0x00000010 | ||
75 | #define STATS_TSR 0x00000020 | ||
76 | |||
77 | #define CX25840_IR_IRQEN_REG 0x214 | ||
78 | #define IRQEN_RTE 0x00000001 | ||
79 | #define IRQEN_ROE 0x00000002 | ||
80 | #define IRQEN_RSE 0x00000010 | ||
81 | #define IRQEN_TSE 0x00000020 | ||
82 | #define IRQEN_MSK 0x00000033 | ||
83 | |||
84 | #define CX25840_IR_FILTR_REG 0x218 | ||
85 | #define FILTR_LPF 0x0000FFFF | ||
86 | |||
87 | #define CX25840_IR_FIFO_REG 0x23C | ||
88 | #define FIFO_RXTX 0x0000FFFF | ||
89 | #define FIFO_RXTX_LVL 0x00010000 | ||
90 | #define FIFO_RXTX_RTO 0x0001FFFF | ||
91 | #define FIFO_RX_NDV 0x00020000 | ||
92 | #define FIFO_RX_DEPTH 8 | ||
93 | #define FIFO_TX_DEPTH 8 | ||
94 | |||
95 | #define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ | ||
96 | #define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2) | ||
97 | |||
98 | /* | ||
99 | * We use this union internally for convenience, but callers to tx_write | ||
100 | * and rx_read will be expecting records of type struct ir_raw_event. | ||
101 | * Always ensure the size of this union is dictated by struct ir_raw_event. | ||
102 | */ | ||
103 | union cx25840_ir_fifo_rec { | ||
104 | u32 hw_fifo_data; | ||
105 | struct ir_raw_event ir_core_data; | ||
106 | }; | ||
107 | |||
108 | #define CX25840_IR_RX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec)) | ||
109 | #define CX25840_IR_TX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec)) | ||
110 | |||
111 | struct cx25840_ir_state { | ||
112 | struct i2c_client *c; | ||
113 | |||
114 | struct v4l2_subdev_ir_parameters rx_params; | ||
115 | struct mutex rx_params_lock; /* protects Rx parameter settings cache */ | ||
116 | atomic_t rxclk_divider; | ||
117 | atomic_t rx_invert; | ||
118 | |||
119 | struct kfifo rx_kfifo; | ||
120 | spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */ | ||
121 | |||
122 | struct v4l2_subdev_ir_parameters tx_params; | ||
123 | struct mutex tx_params_lock; /* protects Tx parameter settings cache */ | ||
124 | atomic_t txclk_divider; | ||
125 | }; | ||
126 | |||
127 | static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd) | ||
128 | { | ||
129 | struct cx25840_state *state = to_state(sd); | ||
130 | return state ? state->ir_state : NULL; | ||
131 | } | ||
132 | |||
133 | |||
134 | /* | ||
135 | * Rx and Tx Clock Divider register computations | ||
136 | * | ||
137 | * Note the largest clock divider value of 0xffff corresponds to: | ||
138 | * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns | ||
139 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
140 | */ | ||
141 | static inline u16 count_to_clock_divider(unsigned int d) | ||
142 | { | ||
143 | if (d > RXCLK_RCD + 1) | ||
144 | d = RXCLK_RCD; | ||
145 | else if (d < 2) | ||
146 | d = 1; | ||
147 | else | ||
148 | d--; | ||
149 | return (u16) d; | ||
150 | } | ||
151 | |||
152 | static inline u16 ns_to_clock_divider(unsigned int ns) | ||
153 | { | ||
154 | return count_to_clock_divider( | ||
155 | DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); | ||
156 | } | ||
157 | |||
158 | static inline unsigned int clock_divider_to_ns(unsigned int divider) | ||
159 | { | ||
160 | /* Period of the Rx or Tx clock in ns */ | ||
161 | return DIV_ROUND_CLOSEST((divider + 1) * 1000, | ||
162 | CX25840_IR_REFCLK_FREQ / 1000000); | ||
163 | } | ||
164 | |||
165 | static inline u16 carrier_freq_to_clock_divider(unsigned int freq) | ||
166 | { | ||
167 | return count_to_clock_divider( | ||
168 | DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16)); | ||
169 | } | ||
170 | |||
171 | static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) | ||
172 | { | ||
173 | return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16); | ||
174 | } | ||
175 | |||
176 | static inline u16 freq_to_clock_divider(unsigned int freq, | ||
177 | unsigned int rollovers) | ||
178 | { | ||
179 | return count_to_clock_divider( | ||
180 | DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers)); | ||
181 | } | ||
182 | |||
183 | static inline unsigned int clock_divider_to_freq(unsigned int divider, | ||
184 | unsigned int rollovers) | ||
185 | { | ||
186 | return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, | ||
187 | (divider + 1) * rollovers); | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Low Pass Filter register calculations | ||
192 | * | ||
193 | * Note the largest count value of 0xffff corresponds to: | ||
194 | * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns | ||
195 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
196 | */ | ||
197 | static inline u16 count_to_lpf_count(unsigned int d) | ||
198 | { | ||
199 | if (d > FILTR_LPF) | ||
200 | d = FILTR_LPF; | ||
201 | else if (d < 4) | ||
202 | d = 0; | ||
203 | return (u16) d; | ||
204 | } | ||
205 | |||
206 | static inline u16 ns_to_lpf_count(unsigned int ns) | ||
207 | { | ||
208 | return count_to_lpf_count( | ||
209 | DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); | ||
210 | } | ||
211 | |||
212 | static inline unsigned int lpf_count_to_ns(unsigned int count) | ||
213 | { | ||
214 | /* Duration of the Low Pass Filter rejection window in ns */ | ||
215 | return DIV_ROUND_CLOSEST(count * 1000, | ||
216 | CX25840_IR_REFCLK_FREQ / 1000000); | ||
217 | } | ||
218 | |||
219 | static inline unsigned int lpf_count_to_us(unsigned int count) | ||
220 | { | ||
221 | /* Duration of the Low Pass Filter rejection window in us */ | ||
222 | return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000); | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * FIFO register pulse width count compuations | ||
227 | */ | ||
228 | static u32 clock_divider_to_resolution(u16 divider) | ||
229 | { | ||
230 | /* | ||
231 | * Resolution is the duration of 1 tick of the readable portion of | ||
232 | * of the pulse width counter as read from the FIFO. The two lsb's are | ||
233 | * not readable, hence the << 2. This function returns ns. | ||
234 | */ | ||
235 | return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, | ||
236 | CX25840_IR_REFCLK_FREQ / 1000000); | ||
237 | } | ||
238 | |||
239 | static u64 pulse_width_count_to_ns(u16 count, u16 divider) | ||
240 | { | ||
241 | u64 n; | ||
242 | u32 rem; | ||
243 | |||
244 | /* | ||
245 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
246 | * the (count << 2) | 0x3 | ||
247 | */ | ||
248 | n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ | ||
249 | rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ | ||
250 | if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2) | ||
251 | n++; | ||
252 | return n; | ||
253 | } | ||
254 | |||
255 | #if 0 | ||
256 | /* Keep as we will need this for Transmit functionality */ | ||
257 | static u16 ns_to_pulse_width_count(u32 ns, u16 divider) | ||
258 | { | ||
259 | u64 n; | ||
260 | u32 d; | ||
261 | u32 rem; | ||
262 | |||
263 | /* | ||
264 | * The 2 lsb's of the pulse width timer count are not accessible, hence | ||
265 | * the (1 << 2) | ||
266 | */ | ||
267 | n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */ | ||
268 | d = (1 << 2) * ((u32) divider + 1) * 1000; /* millicycles/count */ | ||
269 | rem = do_div(n, d); | ||
270 | if (rem >= d / 2) | ||
271 | n++; | ||
272 | |||
273 | if (n > FIFO_RXTX) | ||
274 | n = FIFO_RXTX; | ||
275 | else if (n == 0) | ||
276 | n = 1; | ||
277 | return (u16) n; | ||
278 | } | ||
279 | |||
280 | #endif | ||
281 | static unsigned int pulse_width_count_to_us(u16 count, u16 divider) | ||
282 | { | ||
283 | u64 n; | ||
284 | u32 rem; | ||
285 | |||
286 | /* | ||
287 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
288 | * the (count << 2) | 0x3 | ||
289 | */ | ||
290 | n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ | ||
291 | rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => us */ | ||
292 | if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2) | ||
293 | n++; | ||
294 | return (unsigned int) n; | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts | ||
299 | * | ||
300 | * The total pulse clock count is an 18 bit pulse width timer count as the most | ||
301 | * significant part and (up to) 16 bit clock divider count as a modulus. | ||
302 | * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse | ||
303 | * width timer count's least significant bit. | ||
304 | */ | ||
305 | static u64 ns_to_pulse_clocks(u32 ns) | ||
306 | { | ||
307 | u64 clocks; | ||
308 | u32 rem; | ||
309 | clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ | ||
310 | rem = do_div(clocks, 1000); /* /1000 = cycles */ | ||
311 | if (rem >= 1000 / 2) | ||
312 | clocks++; | ||
313 | return clocks; | ||
314 | } | ||
315 | |||
316 | static u16 pulse_clocks_to_clock_divider(u64 count) | ||
317 | { | ||
318 | u32 rem; | ||
319 | |||
320 | rem = do_div(count, (FIFO_RXTX << 2) | 0x3); | ||
321 | |||
322 | /* net result needs to be rounded down and decremented by 1 */ | ||
323 | if (count > RXCLK_RCD + 1) | ||
324 | count = RXCLK_RCD; | ||
325 | else if (count < 2) | ||
326 | count = 1; | ||
327 | else | ||
328 | count--; | ||
329 | return (u16) count; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * IR Control Register helpers | ||
334 | */ | ||
335 | enum tx_fifo_watermark { | ||
336 | TX_FIFO_HALF_EMPTY = 0, | ||
337 | TX_FIFO_EMPTY = CNTRL_TIC, | ||
338 | }; | ||
339 | |||
340 | enum rx_fifo_watermark { | ||
341 | RX_FIFO_HALF_FULL = 0, | ||
342 | RX_FIFO_NOT_EMPTY = CNTRL_RIC, | ||
343 | }; | ||
344 | |||
345 | static inline void control_tx_irq_watermark(struct i2c_client *c, | ||
346 | enum tx_fifo_watermark level) | ||
347 | { | ||
348 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_TIC, level); | ||
349 | } | ||
350 | |||
351 | static inline void control_rx_irq_watermark(struct i2c_client *c, | ||
352 | enum rx_fifo_watermark level) | ||
353 | { | ||
354 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_RIC, level); | ||
355 | } | ||
356 | |||
357 | static inline void control_tx_enable(struct i2c_client *c, bool enable) | ||
358 | { | ||
359 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), | ||
360 | enable ? (CNTRL_TXE | CNTRL_TFE) : 0); | ||
361 | } | ||
362 | |||
363 | static inline void control_rx_enable(struct i2c_client *c, bool enable) | ||
364 | { | ||
365 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), | ||
366 | enable ? (CNTRL_RXE | CNTRL_RFE) : 0); | ||
367 | } | ||
368 | |||
369 | static inline void control_tx_modulation_enable(struct i2c_client *c, | ||
370 | bool enable) | ||
371 | { | ||
372 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_MOD, | ||
373 | enable ? CNTRL_MOD : 0); | ||
374 | } | ||
375 | |||
376 | static inline void control_rx_demodulation_enable(struct i2c_client *c, | ||
377 | bool enable) | ||
378 | { | ||
379 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_DMD, | ||
380 | enable ? CNTRL_DMD : 0); | ||
381 | } | ||
382 | |||
383 | static inline void control_rx_s_edge_detection(struct i2c_client *c, | ||
384 | u32 edge_types) | ||
385 | { | ||
386 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, | ||
387 | edge_types & CNTRL_EDG_BOTH); | ||
388 | } | ||
389 | |||
390 | static void control_rx_s_carrier_window(struct i2c_client *c, | ||
391 | unsigned int carrier, | ||
392 | unsigned int *carrier_range_low, | ||
393 | unsigned int *carrier_range_high) | ||
394 | { | ||
395 | u32 v; | ||
396 | unsigned int c16 = carrier * 16; | ||
397 | |||
398 | if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { | ||
399 | v = CNTRL_WIN_3_4; | ||
400 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); | ||
401 | } else { | ||
402 | v = CNTRL_WIN_3_3; | ||
403 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); | ||
404 | } | ||
405 | |||
406 | if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { | ||
407 | v |= CNTRL_WIN_4_3; | ||
408 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); | ||
409 | } else { | ||
410 | v |= CNTRL_WIN_3_3; | ||
411 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); | ||
412 | } | ||
413 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_WIN, v); | ||
414 | } | ||
415 | |||
416 | static inline void control_tx_polarity_invert(struct i2c_client *c, | ||
417 | bool invert) | ||
418 | { | ||
419 | cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_CPL, | ||
420 | invert ? CNTRL_CPL : 0); | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * IR Rx & Tx Clock Register helpers | ||
425 | */ | ||
426 | static unsigned int txclk_tx_s_carrier(struct i2c_client *c, | ||
427 | unsigned int freq, | ||
428 | u16 *divider) | ||
429 | { | ||
430 | *divider = carrier_freq_to_clock_divider(freq); | ||
431 | cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider); | ||
432 | return clock_divider_to_carrier_freq(*divider); | ||
433 | } | ||
434 | |||
435 | static unsigned int rxclk_rx_s_carrier(struct i2c_client *c, | ||
436 | unsigned int freq, | ||
437 | u16 *divider) | ||
438 | { | ||
439 | *divider = carrier_freq_to_clock_divider(freq); | ||
440 | cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider); | ||
441 | return clock_divider_to_carrier_freq(*divider); | ||
442 | } | ||
443 | |||
444 | static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns, | ||
445 | u16 *divider) | ||
446 | { | ||
447 | u64 pulse_clocks; | ||
448 | |||
449 | if (ns > IR_MAX_DURATION) | ||
450 | ns = IR_MAX_DURATION; | ||
451 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
452 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
453 | cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider); | ||
454 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
455 | } | ||
456 | |||
457 | static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns, | ||
458 | u16 *divider) | ||
459 | { | ||
460 | u64 pulse_clocks; | ||
461 | |||
462 | if (ns > IR_MAX_DURATION) | ||
463 | ns = IR_MAX_DURATION; | ||
464 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
465 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
466 | cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider); | ||
467 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * IR Tx Carrier Duty Cycle register helpers | ||
472 | */ | ||
473 | static unsigned int cduty_tx_s_duty_cycle(struct i2c_client *c, | ||
474 | unsigned int duty_cycle) | ||
475 | { | ||
476 | u32 n; | ||
477 | n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ | ||
478 | if (n != 0) | ||
479 | n--; | ||
480 | if (n > 15) | ||
481 | n = 15; | ||
482 | cx25840_write4(c, CX25840_IR_CDUTY_REG, n); | ||
483 | return DIV_ROUND_CLOSEST((n + 1) * 100, 16); | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * IR Filter Register helpers | ||
488 | */ | ||
489 | static u32 filter_rx_s_min_width(struct i2c_client *c, u32 min_width_ns) | ||
490 | { | ||
491 | u32 count = ns_to_lpf_count(min_width_ns); | ||
492 | cx25840_write4(c, CX25840_IR_FILTR_REG, count); | ||
493 | return lpf_count_to_ns(count); | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * IR IRQ Enable Register helpers | ||
498 | */ | ||
499 | static inline void irqenable_rx(struct v4l2_subdev *sd, u32 mask) | ||
500 | { | ||
501 | struct cx25840_state *state = to_state(sd); | ||
502 | |||
503 | if (is_cx23885(state) || is_cx23887(state)) | ||
504 | mask ^= IRQEN_MSK; | ||
505 | mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); | ||
506 | cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, | ||
507 | ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); | ||
508 | } | ||
509 | |||
510 | static inline void irqenable_tx(struct v4l2_subdev *sd, u32 mask) | ||
511 | { | ||
512 | struct cx25840_state *state = to_state(sd); | ||
513 | |||
514 | if (is_cx23885(state) || is_cx23887(state)) | ||
515 | mask ^= IRQEN_MSK; | ||
516 | mask &= IRQEN_TSE; | ||
517 | cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask); | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * V4L2 Subdevice IR Ops | ||
522 | */ | ||
523 | int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled) | ||
524 | { | ||
525 | struct cx25840_state *state = to_state(sd); | ||
526 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
527 | struct i2c_client *c = NULL; | ||
528 | unsigned long flags; | ||
529 | |||
530 | union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; | ||
531 | unsigned int i, j, k; | ||
532 | u32 events, v; | ||
533 | int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; | ||
534 | u32 cntrl, irqen, stats; | ||
535 | |||
536 | *handled = false; | ||
537 | if (ir_state == NULL) | ||
538 | return -ENODEV; | ||
539 | |||
540 | c = ir_state->c; | ||
541 | |||
542 | /* Only support the IR controller for the CX2388[57] AV Core for now */ | ||
543 | if (!(is_cx23885(state) || is_cx23887(state))) | ||
544 | return -ENODEV; | ||
545 | |||
546 | cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG); | ||
547 | irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG); | ||
548 | if (is_cx23885(state) || is_cx23887(state)) | ||
549 | irqen ^= IRQEN_MSK; | ||
550 | stats = cx25840_read4(c, CX25840_IR_STATS_REG); | ||
551 | |||
552 | tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ | ||
553 | rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ | ||
554 | rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ | ||
555 | ror = stats & STATS_ROR; /* Rx FIFO Over Run */ | ||
556 | |||
557 | tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ | ||
558 | rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ | ||
559 | rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ | ||
560 | roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ | ||
561 | |||
562 | v4l2_dbg(2, ir_debug, sd, "IR IRQ Status: %s %s %s %s %s %s\n", | ||
563 | tsr ? "tsr" : " ", rsr ? "rsr" : " ", | ||
564 | rto ? "rto" : " ", ror ? "ror" : " ", | ||
565 | stats & STATS_TBY ? "tby" : " ", | ||
566 | stats & STATS_RBY ? "rby" : " "); | ||
567 | |||
568 | v4l2_dbg(2, ir_debug, sd, "IR IRQ Enables: %s %s %s %s\n", | ||
569 | tse ? "tse" : " ", rse ? "rse" : " ", | ||
570 | rte ? "rte" : " ", roe ? "roe" : " "); | ||
571 | |||
572 | /* | ||
573 | * Transmitter interrupt service | ||
574 | */ | ||
575 | if (tse && tsr) { | ||
576 | /* | ||
577 | * TODO: | ||
578 | * Check the watermark threshold setting | ||
579 | * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo | ||
580 | * Push the data to the hardware FIFO. | ||
581 | * If there was nothing more to send in the tx_kfifo, disable | ||
582 | * the TSR IRQ and notify the v4l2_device. | ||
583 | * If there was something in the tx_kfifo, check the tx_kfifo | ||
584 | * level and notify the v4l2_device, if it is low. | ||
585 | */ | ||
586 | /* For now, inhibit TSR interrupt until Tx is implemented */ | ||
587 | irqenable_tx(sd, 0); | ||
588 | events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; | ||
589 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); | ||
590 | *handled = true; | ||
591 | } | ||
592 | |||
593 | /* | ||
594 | * Receiver interrupt service | ||
595 | */ | ||
596 | kror = 0; | ||
597 | if ((rse && rsr) || (rte && rto)) { | ||
598 | /* | ||
599 | * Receive data on RSR to clear the STATS_RSR. | ||
600 | * Receive data on RTO, since we may not have yet hit the RSR | ||
601 | * watermark when we receive the RTO. | ||
602 | */ | ||
603 | for (i = 0, v = FIFO_RX_NDV; | ||
604 | (v & FIFO_RX_NDV) && !kror; i = 0) { | ||
605 | for (j = 0; | ||
606 | (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { | ||
607 | v = cx25840_read4(c, CX25840_IR_FIFO_REG); | ||
608 | rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV; | ||
609 | i++; | ||
610 | } | ||
611 | if (i == 0) | ||
612 | break; | ||
613 | j = i * sizeof(union cx25840_ir_fifo_rec); | ||
614 | k = kfifo_in_locked(&ir_state->rx_kfifo, | ||
615 | (unsigned char *) rx_data, j, | ||
616 | &ir_state->rx_kfifo_lock); | ||
617 | if (k != j) | ||
618 | kror++; /* rx_kfifo over run */ | ||
619 | } | ||
620 | *handled = true; | ||
621 | } | ||
622 | |||
623 | events = 0; | ||
624 | v = 0; | ||
625 | if (kror) { | ||
626 | events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; | ||
627 | v4l2_err(sd, "IR receiver software FIFO overrun\n"); | ||
628 | } | ||
629 | if (roe && ror) { | ||
630 | /* | ||
631 | * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear | ||
632 | * the Rx FIFO Over Run status (STATS_ROR) | ||
633 | */ | ||
634 | v |= CNTRL_RFE; | ||
635 | events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; | ||
636 | v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); | ||
637 | } | ||
638 | if (rte && rto) { | ||
639 | /* | ||
640 | * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear | ||
641 | * the Rx Pulse Width Timer Time Out (STATS_RTO) | ||
642 | */ | ||
643 | v |= CNTRL_RXE; | ||
644 | events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; | ||
645 | } | ||
646 | if (v) { | ||
647 | /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ | ||
648 | cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v); | ||
649 | cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl); | ||
650 | *handled = true; | ||
651 | } | ||
652 | spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); | ||
653 | if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) | ||
654 | events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; | ||
655 | spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); | ||
656 | |||
657 | if (events) | ||
658 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | /* Receiver */ | ||
663 | static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
664 | ssize_t *num) | ||
665 | { | ||
666 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
667 | bool invert; | ||
668 | u16 divider; | ||
669 | unsigned int i, n; | ||
670 | union cx25840_ir_fifo_rec *p; | ||
671 | unsigned u, v; | ||
672 | |||
673 | if (ir_state == NULL) | ||
674 | return -ENODEV; | ||
675 | |||
676 | invert = (bool) atomic_read(&ir_state->rx_invert); | ||
677 | divider = (u16) atomic_read(&ir_state->rxclk_divider); | ||
678 | |||
679 | n = count / sizeof(union cx25840_ir_fifo_rec) | ||
680 | * sizeof(union cx25840_ir_fifo_rec); | ||
681 | if (n == 0) { | ||
682 | *num = 0; | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n, | ||
687 | &ir_state->rx_kfifo_lock); | ||
688 | |||
689 | n /= sizeof(union cx25840_ir_fifo_rec); | ||
690 | *num = n * sizeof(union cx25840_ir_fifo_rec); | ||
691 | |||
692 | for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) { | ||
693 | |||
694 | if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { | ||
695 | /* Assume RTO was because of no IR light input */ | ||
696 | u = 0; | ||
697 | v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n"); | ||
698 | } else { | ||
699 | u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; | ||
700 | if (invert) | ||
701 | u = u ? 0 : 1; | ||
702 | } | ||
703 | |||
704 | v = (unsigned) pulse_width_count_to_ns( | ||
705 | (u16) (p->hw_fifo_data & FIFO_RXTX), divider); | ||
706 | if (v > IR_MAX_DURATION) | ||
707 | v = IR_MAX_DURATION; | ||
708 | |||
709 | init_ir_raw_event(&p->ir_core_data); | ||
710 | p->ir_core_data.pulse = u; | ||
711 | p->ir_core_data.duration = v; | ||
712 | |||
713 | v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n", | ||
714 | v, u ? "mark" : "space"); | ||
715 | } | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int cx25840_ir_rx_g_parameters(struct v4l2_subdev *sd, | ||
720 | struct v4l2_subdev_ir_parameters *p) | ||
721 | { | ||
722 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
723 | |||
724 | if (ir_state == NULL) | ||
725 | return -ENODEV; | ||
726 | |||
727 | mutex_lock(&ir_state->rx_params_lock); | ||
728 | memcpy(p, &ir_state->rx_params, | ||
729 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
730 | mutex_unlock(&ir_state->rx_params_lock); | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | static int cx25840_ir_rx_shutdown(struct v4l2_subdev *sd) | ||
735 | { | ||
736 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
737 | struct i2c_client *c; | ||
738 | |||
739 | if (ir_state == NULL) | ||
740 | return -ENODEV; | ||
741 | |||
742 | c = ir_state->c; | ||
743 | mutex_lock(&ir_state->rx_params_lock); | ||
744 | |||
745 | /* Disable or slow down all IR Rx circuits and counters */ | ||
746 | irqenable_rx(sd, 0); | ||
747 | control_rx_enable(c, false); | ||
748 | control_rx_demodulation_enable(c, false); | ||
749 | control_rx_s_edge_detection(c, CNTRL_EDG_NONE); | ||
750 | filter_rx_s_min_width(c, 0); | ||
751 | cx25840_write4(c, CX25840_IR_RXCLK_REG, RXCLK_RCD); | ||
752 | |||
753 | ir_state->rx_params.shutdown = true; | ||
754 | |||
755 | mutex_unlock(&ir_state->rx_params_lock); | ||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd, | ||
760 | struct v4l2_subdev_ir_parameters *p) | ||
761 | { | ||
762 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
763 | struct i2c_client *c; | ||
764 | struct v4l2_subdev_ir_parameters *o; | ||
765 | u16 rxclk_divider; | ||
766 | |||
767 | if (ir_state == NULL) | ||
768 | return -ENODEV; | ||
769 | |||
770 | if (p->shutdown) | ||
771 | return cx25840_ir_rx_shutdown(sd); | ||
772 | |||
773 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
774 | return -ENOSYS; | ||
775 | |||
776 | c = ir_state->c; | ||
777 | o = &ir_state->rx_params; | ||
778 | |||
779 | mutex_lock(&ir_state->rx_params_lock); | ||
780 | |||
781 | o->shutdown = p->shutdown; | ||
782 | |||
783 | p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
784 | o->mode = p->mode; | ||
785 | |||
786 | p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); | ||
787 | o->bytes_per_data_element = p->bytes_per_data_element; | ||
788 | |||
789 | /* Before we tweak the hardware, we have to disable the receiver */ | ||
790 | irqenable_rx(sd, 0); | ||
791 | control_rx_enable(c, false); | ||
792 | |||
793 | control_rx_demodulation_enable(c, p->modulation); | ||
794 | o->modulation = p->modulation; | ||
795 | |||
796 | if (p->modulation) { | ||
797 | p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq, | ||
798 | &rxclk_divider); | ||
799 | |||
800 | o->carrier_freq = p->carrier_freq; | ||
801 | |||
802 | p->duty_cycle = 50; | ||
803 | o->duty_cycle = p->duty_cycle; | ||
804 | |||
805 | control_rx_s_carrier_window(c, p->carrier_freq, | ||
806 | &p->carrier_range_lower, | ||
807 | &p->carrier_range_upper); | ||
808 | o->carrier_range_lower = p->carrier_range_lower; | ||
809 | o->carrier_range_upper = p->carrier_range_upper; | ||
810 | |||
811 | p->max_pulse_width = | ||
812 | (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider); | ||
813 | } else { | ||
814 | p->max_pulse_width = | ||
815 | rxclk_rx_s_max_pulse_width(c, p->max_pulse_width, | ||
816 | &rxclk_divider); | ||
817 | } | ||
818 | o->max_pulse_width = p->max_pulse_width; | ||
819 | atomic_set(&ir_state->rxclk_divider, rxclk_divider); | ||
820 | |||
821 | p->noise_filter_min_width = | ||
822 | filter_rx_s_min_width(c, p->noise_filter_min_width); | ||
823 | o->noise_filter_min_width = p->noise_filter_min_width; | ||
824 | |||
825 | p->resolution = clock_divider_to_resolution(rxclk_divider); | ||
826 | o->resolution = p->resolution; | ||
827 | |||
828 | /* FIXME - make this dependent on resolution for better performance */ | ||
829 | control_rx_irq_watermark(c, RX_FIFO_HALF_FULL); | ||
830 | |||
831 | control_rx_s_edge_detection(c, CNTRL_EDG_BOTH); | ||
832 | |||
833 | o->invert_level = p->invert_level; | ||
834 | atomic_set(&ir_state->rx_invert, p->invert_level); | ||
835 | |||
836 | o->interrupt_enable = p->interrupt_enable; | ||
837 | o->enable = p->enable; | ||
838 | if (p->enable) { | ||
839 | unsigned long flags; | ||
840 | |||
841 | spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); | ||
842 | kfifo_reset(&ir_state->rx_kfifo); | ||
843 | spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); | ||
844 | if (p->interrupt_enable) | ||
845 | irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); | ||
846 | control_rx_enable(c, p->enable); | ||
847 | } | ||
848 | |||
849 | mutex_unlock(&ir_state->rx_params_lock); | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | /* Transmitter */ | ||
854 | static int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
855 | ssize_t *num) | ||
856 | { | ||
857 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
858 | struct i2c_client *c; | ||
859 | |||
860 | if (ir_state == NULL) | ||
861 | return -ENODEV; | ||
862 | |||
863 | c = ir_state->c; | ||
864 | #if 0 | ||
865 | /* | ||
866 | * FIXME - the code below is an incomplete and untested sketch of what | ||
867 | * may need to be done. The critical part is to get 4 (or 8) pulses | ||
868 | * from the tx_kfifo, or converted from ns to the proper units from the | ||
869 | * input, and push them off to the hardware Tx FIFO right away, if the | ||
870 | * HW TX fifo needs service. The rest can be pushed to the tx_kfifo in | ||
871 | * a less critical timeframe. Also watch out for overruning the | ||
872 | * tx_kfifo - don't let it happen and let the caller know not all his | ||
873 | * pulses were written. | ||
874 | */ | ||
875 | u32 *ns_pulse = (u32 *) buf; | ||
876 | unsigned int n; | ||
877 | u32 fifo_pulse[FIFO_TX_DEPTH]; | ||
878 | u32 mark; | ||
879 | |||
880 | /* Compute how much we can fit in the tx kfifo */ | ||
881 | n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo); | ||
882 | n = min(n, (unsigned int) count); | ||
883 | n /= sizeof(u32); | ||
884 | |||
885 | /* FIXME - turn on Tx Fifo service interrupt | ||
886 | * check hardware fifo level, and other stuff | ||
887 | */ | ||
888 | for (i = 0; i < n; ) { | ||
889 | for (j = 0; j < FIFO_TX_DEPTH / 2 && i < n; j++) { | ||
890 | mark = ns_pulse[i] & LEVEL_MASK; | ||
891 | fifo_pulse[j] = ns_to_pulse_width_count( | ||
892 | ns_pulse[i] & | ||
893 | ~LEVEL_MASK, | ||
894 | ir_state->txclk_divider); | ||
895 | if (mark) | ||
896 | fifo_pulse[j] &= FIFO_RXTX_LVL; | ||
897 | i++; | ||
898 | } | ||
899 | kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse, | ||
900 | j * sizeof(u32)); | ||
901 | } | ||
902 | *num = n * sizeof(u32); | ||
903 | #else | ||
904 | /* For now enable the Tx FIFO Service interrupt & pretend we did work */ | ||
905 | irqenable_tx(sd, IRQEN_TSE); | ||
906 | *num = count; | ||
907 | #endif | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static int cx25840_ir_tx_g_parameters(struct v4l2_subdev *sd, | ||
912 | struct v4l2_subdev_ir_parameters *p) | ||
913 | { | ||
914 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
915 | |||
916 | if (ir_state == NULL) | ||
917 | return -ENODEV; | ||
918 | |||
919 | mutex_lock(&ir_state->tx_params_lock); | ||
920 | memcpy(p, &ir_state->tx_params, | ||
921 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
922 | mutex_unlock(&ir_state->tx_params_lock); | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | static int cx25840_ir_tx_shutdown(struct v4l2_subdev *sd) | ||
927 | { | ||
928 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
929 | struct i2c_client *c; | ||
930 | |||
931 | if (ir_state == NULL) | ||
932 | return -ENODEV; | ||
933 | |||
934 | c = ir_state->c; | ||
935 | mutex_lock(&ir_state->tx_params_lock); | ||
936 | |||
937 | /* Disable or slow down all IR Tx circuits and counters */ | ||
938 | irqenable_tx(sd, 0); | ||
939 | control_tx_enable(c, false); | ||
940 | control_tx_modulation_enable(c, false); | ||
941 | cx25840_write4(c, CX25840_IR_TXCLK_REG, TXCLK_TCD); | ||
942 | |||
943 | ir_state->tx_params.shutdown = true; | ||
944 | |||
945 | mutex_unlock(&ir_state->tx_params_lock); | ||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | static int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd, | ||
950 | struct v4l2_subdev_ir_parameters *p) | ||
951 | { | ||
952 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
953 | struct i2c_client *c; | ||
954 | struct v4l2_subdev_ir_parameters *o; | ||
955 | u16 txclk_divider; | ||
956 | |||
957 | if (ir_state == NULL) | ||
958 | return -ENODEV; | ||
959 | |||
960 | if (p->shutdown) | ||
961 | return cx25840_ir_tx_shutdown(sd); | ||
962 | |||
963 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
964 | return -ENOSYS; | ||
965 | |||
966 | c = ir_state->c; | ||
967 | o = &ir_state->tx_params; | ||
968 | mutex_lock(&ir_state->tx_params_lock); | ||
969 | |||
970 | o->shutdown = p->shutdown; | ||
971 | |||
972 | p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
973 | o->mode = p->mode; | ||
974 | |||
975 | p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); | ||
976 | o->bytes_per_data_element = p->bytes_per_data_element; | ||
977 | |||
978 | /* Before we tweak the hardware, we have to disable the transmitter */ | ||
979 | irqenable_tx(sd, 0); | ||
980 | control_tx_enable(c, false); | ||
981 | |||
982 | control_tx_modulation_enable(c, p->modulation); | ||
983 | o->modulation = p->modulation; | ||
984 | |||
985 | if (p->modulation) { | ||
986 | p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq, | ||
987 | &txclk_divider); | ||
988 | o->carrier_freq = p->carrier_freq; | ||
989 | |||
990 | p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle); | ||
991 | o->duty_cycle = p->duty_cycle; | ||
992 | |||
993 | p->max_pulse_width = | ||
994 | (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider); | ||
995 | } else { | ||
996 | p->max_pulse_width = | ||
997 | txclk_tx_s_max_pulse_width(c, p->max_pulse_width, | ||
998 | &txclk_divider); | ||
999 | } | ||
1000 | o->max_pulse_width = p->max_pulse_width; | ||
1001 | atomic_set(&ir_state->txclk_divider, txclk_divider); | ||
1002 | |||
1003 | p->resolution = clock_divider_to_resolution(txclk_divider); | ||
1004 | o->resolution = p->resolution; | ||
1005 | |||
1006 | /* FIXME - make this dependent on resolution for better performance */ | ||
1007 | control_tx_irq_watermark(c, TX_FIFO_HALF_EMPTY); | ||
1008 | |||
1009 | control_tx_polarity_invert(c, p->invert_carrier_sense); | ||
1010 | o->invert_carrier_sense = p->invert_carrier_sense; | ||
1011 | |||
1012 | /* | ||
1013 | * FIXME: we don't have hardware help for IO pin level inversion | ||
1014 | * here like we have on the CX23888. | ||
1015 | * Act on this with some mix of logical inversion of data levels, | ||
1016 | * carrier polarity, and carrier duty cycle. | ||
1017 | */ | ||
1018 | o->invert_level = p->invert_level; | ||
1019 | |||
1020 | o->interrupt_enable = p->interrupt_enable; | ||
1021 | o->enable = p->enable; | ||
1022 | if (p->enable) { | ||
1023 | /* reset tx_fifo here */ | ||
1024 | if (p->interrupt_enable) | ||
1025 | irqenable_tx(sd, IRQEN_TSE); | ||
1026 | control_tx_enable(c, p->enable); | ||
1027 | } | ||
1028 | |||
1029 | mutex_unlock(&ir_state->tx_params_lock); | ||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | |||
1034 | /* | ||
1035 | * V4L2 Subdevice Core Ops support | ||
1036 | */ | ||
1037 | int cx25840_ir_log_status(struct v4l2_subdev *sd) | ||
1038 | { | ||
1039 | struct cx25840_state *state = to_state(sd); | ||
1040 | struct i2c_client *c = state->c; | ||
1041 | char *s; | ||
1042 | int i, j; | ||
1043 | u32 cntrl, txclk, rxclk, cduty, stats, irqen, filtr; | ||
1044 | |||
1045 | /* The CX23888 chip doesn't have an IR controller on the A/V core */ | ||
1046 | if (is_cx23888(state)) | ||
1047 | return 0; | ||
1048 | |||
1049 | cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG); | ||
1050 | txclk = cx25840_read4(c, CX25840_IR_TXCLK_REG) & TXCLK_TCD; | ||
1051 | rxclk = cx25840_read4(c, CX25840_IR_RXCLK_REG) & RXCLK_RCD; | ||
1052 | cduty = cx25840_read4(c, CX25840_IR_CDUTY_REG) & CDUTY_CDC; | ||
1053 | stats = cx25840_read4(c, CX25840_IR_STATS_REG); | ||
1054 | irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG); | ||
1055 | if (is_cx23885(state) || is_cx23887(state)) | ||
1056 | irqen ^= IRQEN_MSK; | ||
1057 | filtr = cx25840_read4(c, CX25840_IR_FILTR_REG) & FILTR_LPF; | ||
1058 | |||
1059 | v4l2_info(sd, "IR Receiver:\n"); | ||
1060 | v4l2_info(sd, "\tEnabled: %s\n", | ||
1061 | cntrl & CNTRL_RXE ? "yes" : "no"); | ||
1062 | v4l2_info(sd, "\tDemodulation from a carrier: %s\n", | ||
1063 | cntrl & CNTRL_DMD ? "enabled" : "disabled"); | ||
1064 | v4l2_info(sd, "\tFIFO: %s\n", | ||
1065 | cntrl & CNTRL_RFE ? "enabled" : "disabled"); | ||
1066 | switch (cntrl & CNTRL_EDG) { | ||
1067 | case CNTRL_EDG_NONE: | ||
1068 | s = "disabled"; | ||
1069 | break; | ||
1070 | case CNTRL_EDG_FALL: | ||
1071 | s = "falling edge"; | ||
1072 | break; | ||
1073 | case CNTRL_EDG_RISE: | ||
1074 | s = "rising edge"; | ||
1075 | break; | ||
1076 | case CNTRL_EDG_BOTH: | ||
1077 | s = "rising & falling edges"; | ||
1078 | break; | ||
1079 | default: | ||
1080 | s = "??? edge"; | ||
1081 | break; | ||
1082 | } | ||
1083 | v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); | ||
1084 | v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", | ||
1085 | cntrl & CNTRL_R ? "not loaded" : "overflow marker"); | ||
1086 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
1087 | cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); | ||
1088 | v4l2_info(sd, "\tLoopback mode: %s\n", | ||
1089 | cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); | ||
1090 | if (cntrl & CNTRL_DMD) { | ||
1091 | v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", | ||
1092 | clock_divider_to_carrier_freq(rxclk)); | ||
1093 | switch (cntrl & CNTRL_WIN) { | ||
1094 | case CNTRL_WIN_3_3: | ||
1095 | i = 3; | ||
1096 | j = 3; | ||
1097 | break; | ||
1098 | case CNTRL_WIN_4_3: | ||
1099 | i = 4; | ||
1100 | j = 3; | ||
1101 | break; | ||
1102 | case CNTRL_WIN_3_4: | ||
1103 | i = 3; | ||
1104 | j = 4; | ||
1105 | break; | ||
1106 | case CNTRL_WIN_4_4: | ||
1107 | i = 4; | ||
1108 | j = 4; | ||
1109 | break; | ||
1110 | default: | ||
1111 | i = 0; | ||
1112 | j = 0; | ||
1113 | break; | ||
1114 | } | ||
1115 | v4l2_info(sd, "\tNext carrier edge window: 16 clocks " | ||
1116 | "-%1d/+%1d, %u to %u Hz\n", i, j, | ||
1117 | clock_divider_to_freq(rxclk, 16 + j), | ||
1118 | clock_divider_to_freq(rxclk, 16 - i)); | ||
1119 | } | ||
1120 | v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", | ||
1121 | pulse_width_count_to_us(FIFO_RXTX, rxclk), | ||
1122 | pulse_width_count_to_ns(FIFO_RXTX, rxclk)); | ||
1123 | v4l2_info(sd, "\tLow pass filter: %s\n", | ||
1124 | filtr ? "enabled" : "disabled"); | ||
1125 | if (filtr) | ||
1126 | v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " | ||
1127 | "%u ns\n", | ||
1128 | lpf_count_to_us(filtr), | ||
1129 | lpf_count_to_ns(filtr)); | ||
1130 | v4l2_info(sd, "\tPulse width timer timed-out: %s\n", | ||
1131 | stats & STATS_RTO ? "yes" : "no"); | ||
1132 | v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", | ||
1133 | irqen & IRQEN_RTE ? "enabled" : "disabled"); | ||
1134 | v4l2_info(sd, "\tFIFO overrun: %s\n", | ||
1135 | stats & STATS_ROR ? "yes" : "no"); | ||
1136 | v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", | ||
1137 | irqen & IRQEN_ROE ? "enabled" : "disabled"); | ||
1138 | v4l2_info(sd, "\tBusy: %s\n", | ||
1139 | stats & STATS_RBY ? "yes" : "no"); | ||
1140 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1141 | stats & STATS_RSR ? "yes" : "no"); | ||
1142 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1143 | irqen & IRQEN_RSE ? "enabled" : "disabled"); | ||
1144 | |||
1145 | v4l2_info(sd, "IR Transmitter:\n"); | ||
1146 | v4l2_info(sd, "\tEnabled: %s\n", | ||
1147 | cntrl & CNTRL_TXE ? "yes" : "no"); | ||
1148 | v4l2_info(sd, "\tModulation onto a carrier: %s\n", | ||
1149 | cntrl & CNTRL_MOD ? "enabled" : "disabled"); | ||
1150 | v4l2_info(sd, "\tFIFO: %s\n", | ||
1151 | cntrl & CNTRL_TFE ? "enabled" : "disabled"); | ||
1152 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
1153 | cntrl & CNTRL_TIC ? "not empty" : "half full or less"); | ||
1154 | v4l2_info(sd, "\tCarrier polarity: %s\n", | ||
1155 | cntrl & CNTRL_CPL ? "space:burst mark:noburst" | ||
1156 | : "space:noburst mark:burst"); | ||
1157 | if (cntrl & CNTRL_MOD) { | ||
1158 | v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", | ||
1159 | clock_divider_to_carrier_freq(txclk)); | ||
1160 | v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", | ||
1161 | cduty + 1); | ||
1162 | } | ||
1163 | v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", | ||
1164 | pulse_width_count_to_us(FIFO_RXTX, txclk), | ||
1165 | pulse_width_count_to_ns(FIFO_RXTX, txclk)); | ||
1166 | v4l2_info(sd, "\tBusy: %s\n", | ||
1167 | stats & STATS_TBY ? "yes" : "no"); | ||
1168 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1169 | stats & STATS_TSR ? "yes" : "no"); | ||
1170 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1171 | irqen & IRQEN_TSE ? "enabled" : "disabled"); | ||
1172 | |||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | |||
1177 | const struct v4l2_subdev_ir_ops cx25840_ir_ops = { | ||
1178 | .rx_read = cx25840_ir_rx_read, | ||
1179 | .rx_g_parameters = cx25840_ir_rx_g_parameters, | ||
1180 | .rx_s_parameters = cx25840_ir_rx_s_parameters, | ||
1181 | |||
1182 | .tx_write = cx25840_ir_tx_write, | ||
1183 | .tx_g_parameters = cx25840_ir_tx_g_parameters, | ||
1184 | .tx_s_parameters = cx25840_ir_tx_s_parameters, | ||
1185 | }; | ||
1186 | |||
1187 | |||
1188 | static const struct v4l2_subdev_ir_parameters default_rx_params = { | ||
1189 | .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec), | ||
1190 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1191 | |||
1192 | .enable = false, | ||
1193 | .interrupt_enable = false, | ||
1194 | .shutdown = true, | ||
1195 | |||
1196 | .modulation = true, | ||
1197 | .carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */ | ||
1198 | |||
1199 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
1200 | /* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
1201 | .noise_filter_min_width = 333333, /* ns */ | ||
1202 | .carrier_range_lower = 35000, | ||
1203 | .carrier_range_upper = 37000, | ||
1204 | .invert_level = false, | ||
1205 | }; | ||
1206 | |||
1207 | static const struct v4l2_subdev_ir_parameters default_tx_params = { | ||
1208 | .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec), | ||
1209 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1210 | |||
1211 | .enable = false, | ||
1212 | .interrupt_enable = false, | ||
1213 | .shutdown = true, | ||
1214 | |||
1215 | .modulation = true, | ||
1216 | .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ | ||
1217 | .duty_cycle = 25, /* 25 % - RC-5 carrier */ | ||
1218 | .invert_level = false, | ||
1219 | .invert_carrier_sense = false, | ||
1220 | }; | ||
1221 | |||
1222 | int cx25840_ir_probe(struct v4l2_subdev *sd) | ||
1223 | { | ||
1224 | struct cx25840_state *state = to_state(sd); | ||
1225 | struct cx25840_ir_state *ir_state; | ||
1226 | struct v4l2_subdev_ir_parameters default_params; | ||
1227 | |||
1228 | /* Only init the IR controller for the CX2388[57] AV Core for now */ | ||
1229 | if (!(is_cx23885(state) || is_cx23887(state))) | ||
1230 | return 0; | ||
1231 | |||
1232 | ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL); | ||
1233 | if (ir_state == NULL) | ||
1234 | return -ENOMEM; | ||
1235 | |||
1236 | spin_lock_init(&ir_state->rx_kfifo_lock); | ||
1237 | if (kfifo_alloc(&ir_state->rx_kfifo, | ||
1238 | CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) { | ||
1239 | kfree(ir_state); | ||
1240 | return -ENOMEM; | ||
1241 | } | ||
1242 | |||
1243 | ir_state->c = state->c; | ||
1244 | state->ir_state = ir_state; | ||
1245 | |||
1246 | /* Ensure no interrupts arrive yet */ | ||
1247 | if (is_cx23885(state) || is_cx23887(state)) | ||
1248 | cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK); | ||
1249 | else | ||
1250 | cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0); | ||
1251 | |||
1252 | mutex_init(&ir_state->rx_params_lock); | ||
1253 | memcpy(&default_params, &default_rx_params, | ||
1254 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1255 | v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); | ||
1256 | |||
1257 | mutex_init(&ir_state->tx_params_lock); | ||
1258 | memcpy(&default_params, &default_tx_params, | ||
1259 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1260 | v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); | ||
1261 | |||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | int cx25840_ir_remove(struct v4l2_subdev *sd) | ||
1266 | { | ||
1267 | struct cx25840_state *state = to_state(sd); | ||
1268 | struct cx25840_ir_state *ir_state = to_ir_state(sd); | ||
1269 | |||
1270 | if (ir_state == NULL) | ||
1271 | return -ENODEV; | ||
1272 | |||
1273 | cx25840_ir_rx_shutdown(sd); | ||
1274 | cx25840_ir_tx_shutdown(sd); | ||
1275 | |||
1276 | kfifo_free(&ir_state->rx_kfifo); | ||
1277 | kfree(ir_state); | ||
1278 | state->ir_state = NULL; | ||
1279 | return 0; | ||
1280 | } | ||
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c new file mode 100644 index 00000000000..64a4004f8a9 --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-vbi.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* cx25840 VBI functions | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of the GNU General Public License | ||
5 | * as published by the Free Software Foundation; either version 2 | ||
6 | * of the License, or (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/videodev2.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <media/v4l2-common.h> | ||
22 | #include <media/cx25840.h> | ||
23 | |||
24 | #include "cx25840-core.h" | ||
25 | |||
26 | static int odd_parity(u8 c) | ||
27 | { | ||
28 | c ^= (c >> 4); | ||
29 | c ^= (c >> 2); | ||
30 | c ^= (c >> 1); | ||
31 | |||
32 | return c & 1; | ||
33 | } | ||
34 | |||
35 | static int decode_vps(u8 * dst, u8 * p) | ||
36 | { | ||
37 | static const u8 biphase_tbl[] = { | ||
38 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
39 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
40 | 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, | ||
41 | 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, | ||
42 | 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, | ||
43 | 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, | ||
44 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
45 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
46 | 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, | ||
47 | 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, | ||
48 | 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, | ||
49 | 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, | ||
50 | 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, | ||
51 | 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, | ||
52 | 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, | ||
53 | 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, | ||
54 | 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, | ||
55 | 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, | ||
56 | 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, | ||
57 | 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, | ||
58 | 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, | ||
59 | 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, | ||
60 | 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, | ||
61 | 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, | ||
62 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
63 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
64 | 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, | ||
65 | 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, | ||
66 | 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, | ||
67 | 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, | ||
68 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
69 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
70 | }; | ||
71 | |||
72 | u8 c, err = 0; | ||
73 | int i; | ||
74 | |||
75 | for (i = 0; i < 2 * 13; i += 2) { | ||
76 | err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; | ||
77 | c = (biphase_tbl[p[i + 1]] & 0xf) | | ||
78 | ((biphase_tbl[p[i]] & 0xf) << 4); | ||
79 | dst[i / 2] = c; | ||
80 | } | ||
81 | |||
82 | return err & 0xf0; | ||
83 | } | ||
84 | |||
85 | int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) | ||
86 | { | ||
87 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
88 | struct cx25840_state *state = to_state(sd); | ||
89 | static const u16 lcr2vbi[] = { | ||
90 | 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ | ||
91 | 0, V4L2_SLICED_WSS_625, 0, /* 4 */ | ||
92 | V4L2_SLICED_CAPTION_525, /* 6 */ | ||
93 | 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ | ||
94 | 0, 0, 0, 0 | ||
95 | }; | ||
96 | int is_pal = !(state->std & V4L2_STD_525_60); | ||
97 | int i; | ||
98 | |||
99 | memset(svbi, 0, sizeof(*svbi)); | ||
100 | /* we're done if raw VBI is active */ | ||
101 | if ((cx25840_read(client, 0x404) & 0x10) == 0) | ||
102 | return 0; | ||
103 | |||
104 | if (is_pal) { | ||
105 | for (i = 7; i <= 23; i++) { | ||
106 | u8 v = cx25840_read(client, 0x424 + i - 7); | ||
107 | |||
108 | svbi->service_lines[0][i] = lcr2vbi[v >> 4]; | ||
109 | svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; | ||
110 | svbi->service_set |= svbi->service_lines[0][i] | | ||
111 | svbi->service_lines[1][i]; | ||
112 | } | ||
113 | } else { | ||
114 | for (i = 10; i <= 21; i++) { | ||
115 | u8 v = cx25840_read(client, 0x424 + i - 10); | ||
116 | |||
117 | svbi->service_lines[0][i] = lcr2vbi[v >> 4]; | ||
118 | svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; | ||
119 | svbi->service_set |= svbi->service_lines[0][i] | | ||
120 | svbi->service_lines[1][i]; | ||
121 | } | ||
122 | } | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) | ||
127 | { | ||
128 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
129 | struct cx25840_state *state = to_state(sd); | ||
130 | int is_pal = !(state->std & V4L2_STD_525_60); | ||
131 | int vbi_offset = is_pal ? 1 : 0; | ||
132 | |||
133 | /* Setup standard */ | ||
134 | cx25840_std_setup(client); | ||
135 | |||
136 | /* VBI Offset */ | ||
137 | cx25840_write(client, 0x47f, vbi_offset); | ||
138 | cx25840_write(client, 0x404, 0x2e); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) | ||
143 | { | ||
144 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
145 | struct cx25840_state *state = to_state(sd); | ||
146 | int is_pal = !(state->std & V4L2_STD_525_60); | ||
147 | int vbi_offset = is_pal ? 1 : 0; | ||
148 | int i, x; | ||
149 | u8 lcr[24]; | ||
150 | |||
151 | for (x = 0; x <= 23; x++) | ||
152 | lcr[x] = 0x00; | ||
153 | |||
154 | /* Setup standard */ | ||
155 | cx25840_std_setup(client); | ||
156 | |||
157 | /* Sliced VBI */ | ||
158 | cx25840_write(client, 0x404, 0x32); /* Ancillary data */ | ||
159 | cx25840_write(client, 0x406, 0x13); | ||
160 | cx25840_write(client, 0x47f, vbi_offset); | ||
161 | |||
162 | if (is_pal) { | ||
163 | for (i = 0; i <= 6; i++) | ||
164 | svbi->service_lines[0][i] = | ||
165 | svbi->service_lines[1][i] = 0; | ||
166 | } else { | ||
167 | for (i = 0; i <= 9; i++) | ||
168 | svbi->service_lines[0][i] = | ||
169 | svbi->service_lines[1][i] = 0; | ||
170 | |||
171 | for (i = 22; i <= 23; i++) | ||
172 | svbi->service_lines[0][i] = | ||
173 | svbi->service_lines[1][i] = 0; | ||
174 | } | ||
175 | |||
176 | for (i = 7; i <= 23; i++) { | ||
177 | for (x = 0; x <= 1; x++) { | ||
178 | switch (svbi->service_lines[1-x][i]) { | ||
179 | case V4L2_SLICED_TELETEXT_B: | ||
180 | lcr[i] |= 1 << (4 * x); | ||
181 | break; | ||
182 | case V4L2_SLICED_WSS_625: | ||
183 | lcr[i] |= 4 << (4 * x); | ||
184 | break; | ||
185 | case V4L2_SLICED_CAPTION_525: | ||
186 | lcr[i] |= 6 << (4 * x); | ||
187 | break; | ||
188 | case V4L2_SLICED_VPS: | ||
189 | lcr[i] |= 9 << (4 * x); | ||
190 | break; | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | if (is_pal) { | ||
196 | for (x = 1, i = 0x424; i <= 0x434; i++, x++) | ||
197 | cx25840_write(client, i, lcr[6 + x]); | ||
198 | } else { | ||
199 | for (x = 1, i = 0x424; i <= 0x430; i++, x++) | ||
200 | cx25840_write(client, i, lcr[9 + x]); | ||
201 | for (i = 0x431; i <= 0x434; i++) | ||
202 | cx25840_write(client, i, 0); | ||
203 | } | ||
204 | |||
205 | cx25840_write(client, 0x43c, 0x16); | ||
206 | cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi) | ||
211 | { | ||
212 | struct cx25840_state *state = to_state(sd); | ||
213 | u8 *p = vbi->p; | ||
214 | int id1, id2, l, err = 0; | ||
215 | |||
216 | if (p[0] || p[1] != 0xff || p[2] != 0xff || | ||
217 | (p[3] != 0x55 && p[3] != 0x91)) { | ||
218 | vbi->line = vbi->type = 0; | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | p += 4; | ||
223 | id1 = p[-1]; | ||
224 | id2 = p[0] & 0xf; | ||
225 | l = p[2] & 0x3f; | ||
226 | l += state->vbi_line_offset; | ||
227 | p += 4; | ||
228 | |||
229 | switch (id2) { | ||
230 | case 1: | ||
231 | id2 = V4L2_SLICED_TELETEXT_B; | ||
232 | break; | ||
233 | case 4: | ||
234 | id2 = V4L2_SLICED_WSS_625; | ||
235 | break; | ||
236 | case 6: | ||
237 | id2 = V4L2_SLICED_CAPTION_525; | ||
238 | err = !odd_parity(p[0]) || !odd_parity(p[1]); | ||
239 | break; | ||
240 | case 9: | ||
241 | id2 = V4L2_SLICED_VPS; | ||
242 | if (decode_vps(p, p) != 0) | ||
243 | err = 1; | ||
244 | break; | ||
245 | default: | ||
246 | id2 = 0; | ||
247 | err = 1; | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | vbi->type = err ? 0 : id2; | ||
252 | vbi->line = err ? 0 : l; | ||
253 | vbi->is_second_field = err ? 0 : (id1 == 0x55); | ||
254 | vbi->p = p; | ||
255 | return 0; | ||
256 | } | ||