1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Video Capture Driver (Video for Linux 1/2) |
4 | * for the Matrox Marvel G200,G400 and Rainbow Runner-G series |
5 | * |
6 | * This module is an interface to the KS0127 video decoder chip. |
7 | * |
8 | * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.net> |
9 | * |
10 | ***************************************************************************** |
11 | * |
12 | * Modified and extended by |
13 | * Mike Bernson <mike@mlb.org> |
14 | * Gerard v.d. Horst |
15 | * Leon van Stuivenberg <l.vanstuivenberg@chello.nl> |
16 | * Gernot Ziegler <gz@lysator.liu.se> |
17 | * |
18 | * Version History: |
19 | * V1.0 Ryan Drake Initial version by Ryan Drake |
20 | * V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard |
21 | */ |
22 | |
23 | #include <linux/init.h> |
24 | #include <linux/module.h> |
25 | #include <linux/delay.h> |
26 | #include <linux/errno.h> |
27 | #include <linux/kernel.h> |
28 | #include <linux/i2c.h> |
29 | #include <linux/videodev2.h> |
30 | #include <linux/slab.h> |
31 | #include <media/v4l2-device.h> |
32 | #include "ks0127.h" |
33 | |
34 | MODULE_DESCRIPTION("KS0127 video decoder driver" ); |
35 | MODULE_AUTHOR("Ryan Drake" ); |
36 | MODULE_LICENSE("GPL" ); |
37 | |
38 | /* Addresses */ |
39 | #define I2C_KS0127_ADDON 0xD8 |
40 | #define I2C_KS0127_ONBOARD 0xDA |
41 | |
42 | |
43 | /* ks0127 control registers */ |
44 | #define KS_STAT 0x00 |
45 | #define KS_CMDA 0x01 |
46 | #define KS_CMDB 0x02 |
47 | #define KS_CMDC 0x03 |
48 | #define KS_CMDD 0x04 |
49 | #define KS_HAVB 0x05 |
50 | #define KS_HAVE 0x06 |
51 | #define KS_HS1B 0x07 |
52 | #define KS_HS1E 0x08 |
53 | #define KS_HS2B 0x09 |
54 | #define KS_HS2E 0x0a |
55 | #define KS_AGC 0x0b |
56 | #define KS_HXTRA 0x0c |
57 | #define KS_CDEM 0x0d |
58 | #define KS_PORTAB 0x0e |
59 | #define KS_LUMA 0x0f |
60 | #define KS_CON 0x10 |
61 | #define KS_BRT 0x11 |
62 | #define KS_CHROMA 0x12 |
63 | #define KS_CHROMB 0x13 |
64 | #define KS_DEMOD 0x14 |
65 | #define KS_SAT 0x15 |
66 | #define KS_HUE 0x16 |
67 | #define KS_VERTIA 0x17 |
68 | #define KS_VERTIB 0x18 |
69 | #define KS_VERTIC 0x19 |
70 | #define KS_HSCLL 0x1a |
71 | #define KS_HSCLH 0x1b |
72 | #define KS_VSCLL 0x1c |
73 | #define KS_VSCLH 0x1d |
74 | #define KS_OFMTA 0x1e |
75 | #define KS_OFMTB 0x1f |
76 | #define KS_VBICTL 0x20 |
77 | #define KS_CCDAT2 0x21 |
78 | #define KS_CCDAT1 0x22 |
79 | #define KS_VBIL30 0x23 |
80 | #define KS_VBIL74 0x24 |
81 | #define KS_VBIL118 0x25 |
82 | #define KS_VBIL1512 0x26 |
83 | #define KS_TTFRAM 0x27 |
84 | #define KS_TESTA 0x28 |
85 | #define KS_UVOFFH 0x29 |
86 | #define KS_UVOFFL 0x2a |
87 | #define KS_UGAIN 0x2b |
88 | #define KS_VGAIN 0x2c |
89 | #define KS_VAVB 0x2d |
90 | #define KS_VAVE 0x2e |
91 | #define KS_CTRACK 0x2f |
92 | #define KS_POLCTL 0x30 |
93 | #define KS_REFCOD 0x31 |
94 | #define KS_INVALY 0x32 |
95 | #define KS_INVALU 0x33 |
96 | #define KS_INVALV 0x34 |
97 | #define KS_UNUSEY 0x35 |
98 | #define KS_UNUSEU 0x36 |
99 | #define KS_UNUSEV 0x37 |
100 | #define KS_USRSAV 0x38 |
101 | #define KS_USREAV 0x39 |
102 | #define KS_SHS1A 0x3a |
103 | #define KS_SHS1B 0x3b |
104 | #define KS_SHS1C 0x3c |
105 | #define KS_CMDE 0x3d |
106 | #define KS_VSDEL 0x3e |
107 | #define KS_CMDF 0x3f |
108 | #define KS_GAMMA0 0x40 |
109 | #define KS_GAMMA1 0x41 |
110 | #define KS_GAMMA2 0x42 |
111 | #define KS_GAMMA3 0x43 |
112 | #define KS_GAMMA4 0x44 |
113 | #define KS_GAMMA5 0x45 |
114 | #define KS_GAMMA6 0x46 |
115 | #define KS_GAMMA7 0x47 |
116 | #define KS_GAMMA8 0x48 |
117 | #define KS_GAMMA9 0x49 |
118 | #define KS_GAMMA10 0x4a |
119 | #define KS_GAMMA11 0x4b |
120 | #define KS_GAMMA12 0x4c |
121 | #define KS_GAMMA13 0x4d |
122 | #define KS_GAMMA14 0x4e |
123 | #define KS_GAMMA15 0x4f |
124 | #define KS_GAMMA16 0x50 |
125 | #define KS_GAMMA17 0x51 |
126 | #define KS_GAMMA18 0x52 |
127 | #define KS_GAMMA19 0x53 |
128 | #define KS_GAMMA20 0x54 |
129 | #define KS_GAMMA21 0x55 |
130 | #define KS_GAMMA22 0x56 |
131 | #define KS_GAMMA23 0x57 |
132 | #define KS_GAMMA24 0x58 |
133 | #define KS_GAMMA25 0x59 |
134 | #define KS_GAMMA26 0x5a |
135 | #define KS_GAMMA27 0x5b |
136 | #define KS_GAMMA28 0x5c |
137 | #define KS_GAMMA29 0x5d |
138 | #define KS_GAMMA30 0x5e |
139 | #define KS_GAMMA31 0x5f |
140 | #define KS_GAMMAD0 0x60 |
141 | #define KS_GAMMAD1 0x61 |
142 | #define KS_GAMMAD2 0x62 |
143 | #define KS_GAMMAD3 0x63 |
144 | #define KS_GAMMAD4 0x64 |
145 | #define KS_GAMMAD5 0x65 |
146 | #define KS_GAMMAD6 0x66 |
147 | #define KS_GAMMAD7 0x67 |
148 | #define KS_GAMMAD8 0x68 |
149 | #define KS_GAMMAD9 0x69 |
150 | #define KS_GAMMAD10 0x6a |
151 | #define KS_GAMMAD11 0x6b |
152 | #define KS_GAMMAD12 0x6c |
153 | #define KS_GAMMAD13 0x6d |
154 | #define KS_GAMMAD14 0x6e |
155 | #define KS_GAMMAD15 0x6f |
156 | #define KS_GAMMAD16 0x70 |
157 | #define KS_GAMMAD17 0x71 |
158 | #define KS_GAMMAD18 0x72 |
159 | #define KS_GAMMAD19 0x73 |
160 | #define KS_GAMMAD20 0x74 |
161 | #define KS_GAMMAD21 0x75 |
162 | #define KS_GAMMAD22 0x76 |
163 | #define KS_GAMMAD23 0x77 |
164 | #define KS_GAMMAD24 0x78 |
165 | #define KS_GAMMAD25 0x79 |
166 | #define KS_GAMMAD26 0x7a |
167 | #define KS_GAMMAD27 0x7b |
168 | #define KS_GAMMAD28 0x7c |
169 | #define KS_GAMMAD29 0x7d |
170 | #define KS_GAMMAD30 0x7e |
171 | #define KS_GAMMAD31 0x7f |
172 | |
173 | |
174 | /**************************************************************************** |
175 | * mga_dev : represents one ks0127 chip. |
176 | ****************************************************************************/ |
177 | |
178 | struct adjust { |
179 | int contrast; |
180 | int bright; |
181 | int hue; |
182 | int ugain; |
183 | int vgain; |
184 | }; |
185 | |
186 | struct ks0127 { |
187 | struct v4l2_subdev sd; |
188 | v4l2_std_id norm; |
189 | u8 regs[256]; |
190 | }; |
191 | |
192 | static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd) |
193 | { |
194 | return container_of(sd, struct ks0127, sd); |
195 | } |
196 | |
197 | |
198 | static int debug; /* insmod parameter */ |
199 | |
200 | module_param(debug, int, 0); |
201 | MODULE_PARM_DESC(debug, "Debug output" ); |
202 | |
203 | static u8 reg_defaults[64]; |
204 | |
205 | static void init_reg_defaults(void) |
206 | { |
207 | static int initialized; |
208 | u8 *table = reg_defaults; |
209 | |
210 | if (initialized) |
211 | return; |
212 | initialized = 1; |
213 | |
214 | table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */ |
215 | table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */ |
216 | table[KS_CMDC] = 0x00; /* Test options */ |
217 | /* clock & input select, write 1 to PORTA */ |
218 | table[KS_CMDD] = 0x01; |
219 | table[KS_HAVB] = 0x00; /* HAV Start Control */ |
220 | table[KS_HAVE] = 0x00; /* HAV End Control */ |
221 | table[KS_HS1B] = 0x10; /* HS1 Start Control */ |
222 | table[KS_HS1E] = 0x00; /* HS1 End Control */ |
223 | table[KS_HS2B] = 0x00; /* HS2 Start Control */ |
224 | table[KS_HS2E] = 0x00; /* HS2 End Control */ |
225 | table[KS_AGC] = 0x53; /* Manual setting for AGC */ |
226 | table[KS_HXTRA] = 0x00; /* Extra Bits for HAV and HS1/2 */ |
227 | table[KS_CDEM] = 0x00; /* Chroma Demodulation Control */ |
228 | table[KS_PORTAB] = 0x0f; /* port B is input, port A output GPPORT */ |
229 | table[KS_LUMA] = 0x01; /* Luma control */ |
230 | table[KS_CON] = 0x00; /* Contrast Control */ |
231 | table[KS_BRT] = 0x00; /* Brightness Control */ |
232 | table[KS_CHROMA] = 0x2a; /* Chroma control A */ |
233 | table[KS_CHROMB] = 0x90; /* Chroma control B */ |
234 | table[KS_DEMOD] = 0x00; /* Chroma Demodulation Control & Status */ |
235 | table[KS_SAT] = 0x00; /* Color Saturation Control*/ |
236 | table[KS_HUE] = 0x00; /* Hue Control */ |
237 | table[KS_VERTIA] = 0x00; /* Vertical Processing Control A */ |
238 | /* Vertical Processing Control B, luma 1 line delayed */ |
239 | table[KS_VERTIB] = 0x12; |
240 | table[KS_VERTIC] = 0x0b; /* Vertical Processing Control C */ |
241 | table[KS_HSCLL] = 0x00; /* Horizontal Scaling Ratio Low */ |
242 | table[KS_HSCLH] = 0x00; /* Horizontal Scaling Ratio High */ |
243 | table[KS_VSCLL] = 0x00; /* Vertical Scaling Ratio Low */ |
244 | table[KS_VSCLH] = 0x00; /* Vertical Scaling Ratio High */ |
245 | /* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */ |
246 | table[KS_OFMTA] = 0x30; |
247 | table[KS_OFMTB] = 0x00; /* Output Control B */ |
248 | /* VBI Decoder Control; 4bit fmt: avoid Y overflow */ |
249 | table[KS_VBICTL] = 0x5d; |
250 | table[KS_CCDAT2] = 0x00; /* Read Only register */ |
251 | table[KS_CCDAT1] = 0x00; /* Read Only register */ |
252 | table[KS_VBIL30] = 0xa8; /* VBI data decoding options */ |
253 | table[KS_VBIL74] = 0xaa; /* VBI data decoding options */ |
254 | table[KS_VBIL118] = 0x2a; /* VBI data decoding options */ |
255 | table[KS_VBIL1512] = 0x00; /* VBI data decoding options */ |
256 | table[KS_TTFRAM] = 0x00; /* Teletext frame alignment pattern */ |
257 | table[KS_TESTA] = 0x00; /* test register, shouldn't be written */ |
258 | table[KS_UVOFFH] = 0x00; /* UV Offset Adjustment High */ |
259 | table[KS_UVOFFL] = 0x00; /* UV Offset Adjustment Low */ |
260 | table[KS_UGAIN] = 0x00; /* U Component Gain Adjustment */ |
261 | table[KS_VGAIN] = 0x00; /* V Component Gain Adjustment */ |
262 | table[KS_VAVB] = 0x07; /* VAV Begin */ |
263 | table[KS_VAVE] = 0x00; /* VAV End */ |
264 | table[KS_CTRACK] = 0x00; /* Chroma Tracking Control */ |
265 | table[KS_POLCTL] = 0x41; /* Timing Signal Polarity Control */ |
266 | table[KS_REFCOD] = 0x80; /* Reference Code Insertion Control */ |
267 | table[KS_INVALY] = 0x10; /* Invalid Y Code */ |
268 | table[KS_INVALU] = 0x80; /* Invalid U Code */ |
269 | table[KS_INVALV] = 0x80; /* Invalid V Code */ |
270 | table[KS_UNUSEY] = 0x10; /* Unused Y Code */ |
271 | table[KS_UNUSEU] = 0x80; /* Unused U Code */ |
272 | table[KS_UNUSEV] = 0x80; /* Unused V Code */ |
273 | table[KS_USRSAV] = 0x00; /* reserved */ |
274 | table[KS_USREAV] = 0x00; /* reserved */ |
275 | table[KS_SHS1A] = 0x00; /* User Defined SHS1 A */ |
276 | /* User Defined SHS1 B, ALT656=1 on 0127B */ |
277 | table[KS_SHS1B] = 0x80; |
278 | table[KS_SHS1C] = 0x00; /* User Defined SHS1 C */ |
279 | table[KS_CMDE] = 0x00; /* Command Register E */ |
280 | table[KS_VSDEL] = 0x00; /* VS Delay Control */ |
281 | /* Command Register F, update -immediately- */ |
282 | /* (there might come no vsync)*/ |
283 | table[KS_CMDF] = 0x02; |
284 | } |
285 | |
286 | |
287 | /* We need to manually read because of a bug in the KS0127 chip. |
288 | * |
289 | * An explanation from kayork@mail.utexas.edu: |
290 | * |
291 | * During I2C reads, the KS0127 only samples for a stop condition |
292 | * during the place where the acknowledge bit should be. Any standard |
293 | * I2C implementation (correctly) throws in another clock transition |
294 | * at the 9th bit, and the KS0127 will not recognize the stop condition |
295 | * and will continue to clock out data. |
296 | * |
297 | * So we have to do the read ourself. Big deal. |
298 | * workaround in i2c-algo-bit |
299 | */ |
300 | |
301 | |
302 | static u8 ks0127_read(struct v4l2_subdev *sd, u8 reg) |
303 | { |
304 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
305 | char val = 0; |
306 | struct i2c_msg msgs[] = { |
307 | { |
308 | .addr = client->addr, |
309 | .len = sizeof(reg), |
310 | .buf = ® |
311 | }, |
312 | { |
313 | .addr = client->addr, |
314 | .flags = I2C_M_RD | I2C_M_NO_RD_ACK, |
315 | .len = sizeof(val), |
316 | .buf = &val |
317 | } |
318 | }; |
319 | int ret; |
320 | |
321 | ret = i2c_transfer(adap: client->adapter, msgs, ARRAY_SIZE(msgs)); |
322 | if (ret != ARRAY_SIZE(msgs)) |
323 | v4l2_dbg(1, debug, sd, "read error\n" ); |
324 | |
325 | return val; |
326 | } |
327 | |
328 | |
329 | static void ks0127_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
330 | { |
331 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
332 | struct ks0127 *ks = to_ks0127(sd); |
333 | char msg[] = { reg, val }; |
334 | |
335 | if (i2c_master_send(client, buf: msg, count: sizeof(msg)) != sizeof(msg)) |
336 | v4l2_dbg(1, debug, sd, "write error\n" ); |
337 | |
338 | ks->regs[reg] = val; |
339 | } |
340 | |
341 | |
342 | /* generic bit-twiddling */ |
343 | static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v) |
344 | { |
345 | struct ks0127 *ks = to_ks0127(sd); |
346 | |
347 | u8 val = ks->regs[reg]; |
348 | val = (val & and_v) | or_v; |
349 | ks0127_write(sd, reg, val); |
350 | } |
351 | |
352 | |
353 | |
354 | /**************************************************************************** |
355 | * ks0127 private api |
356 | ****************************************************************************/ |
357 | static void ks0127_init(struct v4l2_subdev *sd) |
358 | { |
359 | u8 *table = reg_defaults; |
360 | int i; |
361 | |
362 | v4l2_dbg(1, debug, sd, "reset\n" ); |
363 | msleep(msecs: 1); |
364 | |
365 | /* initialize all registers to known values */ |
366 | /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */ |
367 | |
368 | for (i = 1; i < 33; i++) |
369 | ks0127_write(sd, reg: i, val: table[i]); |
370 | |
371 | for (i = 35; i < 40; i++) |
372 | ks0127_write(sd, reg: i, val: table[i]); |
373 | |
374 | for (i = 41; i < 56; i++) |
375 | ks0127_write(sd, reg: i, val: table[i]); |
376 | |
377 | for (i = 58; i < 64; i++) |
378 | ks0127_write(sd, reg: i, val: table[i]); |
379 | |
380 | |
381 | if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) { |
382 | v4l2_dbg(1, debug, sd, "ks0122s found\n" ); |
383 | return; |
384 | } |
385 | |
386 | switch (ks0127_read(sd, KS_CMDE) & 0x0f) { |
387 | case 0: |
388 | v4l2_dbg(1, debug, sd, "ks0127 found\n" ); |
389 | break; |
390 | |
391 | case 9: |
392 | v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n" ); |
393 | break; |
394 | |
395 | default: |
396 | v4l2_dbg(1, debug, sd, "unknown revision\n" ); |
397 | break; |
398 | } |
399 | } |
400 | |
401 | static int ks0127_s_routing(struct v4l2_subdev *sd, |
402 | u32 input, u32 output, u32 config) |
403 | { |
404 | struct ks0127 *ks = to_ks0127(sd); |
405 | |
406 | switch (input) { |
407 | case KS_INPUT_COMPOSITE_1: |
408 | case KS_INPUT_COMPOSITE_2: |
409 | case KS_INPUT_COMPOSITE_3: |
410 | case KS_INPUT_COMPOSITE_4: |
411 | case KS_INPUT_COMPOSITE_5: |
412 | case KS_INPUT_COMPOSITE_6: |
413 | v4l2_dbg(1, debug, sd, |
414 | "s_routing %d: Composite\n" , input); |
415 | /* autodetect 50/60 Hz */ |
416 | ks0127_and_or(sd, KS_CMDA, and_v: 0xfc, or_v: 0x00); |
417 | /* VSE=0 */ |
418 | ks0127_and_or(sd, KS_CMDA, and_v: ~0x40, or_v: 0x00); |
419 | /* set input line */ |
420 | ks0127_and_or(sd, KS_CMDB, and_v: 0xb0, or_v: input); |
421 | /* non-freerunning mode */ |
422 | ks0127_and_or(sd, KS_CMDC, and_v: 0x70, or_v: 0x0a); |
423 | /* analog input */ |
424 | ks0127_and_or(sd, KS_CMDD, and_v: 0x03, or_v: 0x00); |
425 | /* enable chroma demodulation */ |
426 | ks0127_and_or(sd, KS_CTRACK, and_v: 0xcf, or_v: 0x00); |
427 | /* chroma trap, HYBWR=1 */ |
428 | ks0127_and_or(sd, KS_LUMA, and_v: 0x00, |
429 | or_v: (reg_defaults[KS_LUMA])|0x0c); |
430 | /* scaler fullbw, luma comb off */ |
431 | ks0127_and_or(sd, KS_VERTIA, and_v: 0x08, or_v: 0x81); |
432 | /* manual chroma comb .25 .5 .25 */ |
433 | ks0127_and_or(sd, KS_VERTIC, and_v: 0x0f, or_v: 0x90); |
434 | |
435 | /* chroma path delay */ |
436 | ks0127_and_or(sd, KS_CHROMB, and_v: 0x0f, or_v: 0x90); |
437 | |
438 | ks0127_write(sd, KS_UGAIN, val: reg_defaults[KS_UGAIN]); |
439 | ks0127_write(sd, KS_VGAIN, val: reg_defaults[KS_VGAIN]); |
440 | ks0127_write(sd, KS_UVOFFH, val: reg_defaults[KS_UVOFFH]); |
441 | ks0127_write(sd, KS_UVOFFL, val: reg_defaults[KS_UVOFFL]); |
442 | break; |
443 | |
444 | case KS_INPUT_SVIDEO_1: |
445 | case KS_INPUT_SVIDEO_2: |
446 | case KS_INPUT_SVIDEO_3: |
447 | v4l2_dbg(1, debug, sd, |
448 | "s_routing %d: S-Video\n" , input); |
449 | /* autodetect 50/60 Hz */ |
450 | ks0127_and_or(sd, KS_CMDA, and_v: 0xfc, or_v: 0x00); |
451 | /* VSE=0 */ |
452 | ks0127_and_or(sd, KS_CMDA, and_v: ~0x40, or_v: 0x00); |
453 | /* set input line */ |
454 | ks0127_and_or(sd, KS_CMDB, and_v: 0xb0, or_v: input); |
455 | /* non-freerunning mode */ |
456 | ks0127_and_or(sd, KS_CMDC, and_v: 0x70, or_v: 0x0a); |
457 | /* analog input */ |
458 | ks0127_and_or(sd, KS_CMDD, and_v: 0x03, or_v: 0x00); |
459 | /* enable chroma demodulation */ |
460 | ks0127_and_or(sd, KS_CTRACK, and_v: 0xcf, or_v: 0x00); |
461 | ks0127_and_or(sd, KS_LUMA, and_v: 0x00, |
462 | or_v: reg_defaults[KS_LUMA]); |
463 | /* disable luma comb */ |
464 | ks0127_and_or(sd, KS_VERTIA, and_v: 0x08, |
465 | or_v: (reg_defaults[KS_VERTIA]&0xf0)|0x01); |
466 | ks0127_and_or(sd, KS_VERTIC, and_v: 0x0f, |
467 | or_v: reg_defaults[KS_VERTIC]&0xf0); |
468 | |
469 | ks0127_and_or(sd, KS_CHROMB, and_v: 0x0f, |
470 | or_v: reg_defaults[KS_CHROMB]&0xf0); |
471 | |
472 | ks0127_write(sd, KS_UGAIN, val: reg_defaults[KS_UGAIN]); |
473 | ks0127_write(sd, KS_VGAIN, val: reg_defaults[KS_VGAIN]); |
474 | ks0127_write(sd, KS_UVOFFH, val: reg_defaults[KS_UVOFFH]); |
475 | ks0127_write(sd, KS_UVOFFL, val: reg_defaults[KS_UVOFFL]); |
476 | break; |
477 | |
478 | case KS_INPUT_YUV656: |
479 | v4l2_dbg(1, debug, sd, "s_routing 15: YUV656\n" ); |
480 | if (ks->norm & V4L2_STD_525_60) |
481 | /* force 60 Hz */ |
482 | ks0127_and_or(sd, KS_CMDA, and_v: 0xfc, or_v: 0x03); |
483 | else |
484 | /* force 50 Hz */ |
485 | ks0127_and_or(sd, KS_CMDA, and_v: 0xfc, or_v: 0x02); |
486 | |
487 | ks0127_and_or(sd, KS_CMDA, and_v: 0xff, or_v: 0x40); /* VSE=1 */ |
488 | /* set input line and VALIGN */ |
489 | ks0127_and_or(sd, KS_CMDB, and_v: 0xb0, or_v: (input | 0x40)); |
490 | /* freerunning mode, */ |
491 | /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/ |
492 | ks0127_and_or(sd, KS_CMDC, and_v: 0x70, or_v: 0x87); |
493 | /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */ |
494 | ks0127_and_or(sd, KS_CMDD, and_v: 0x03, or_v: 0x08); |
495 | /* disable chroma demodulation */ |
496 | ks0127_and_or(sd, KS_CTRACK, and_v: 0xcf, or_v: 0x30); |
497 | /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */ |
498 | ks0127_and_or(sd, KS_LUMA, and_v: 0x00, or_v: 0x71); |
499 | ks0127_and_or(sd, KS_VERTIC, and_v: 0x0f, |
500 | or_v: reg_defaults[KS_VERTIC]&0xf0); |
501 | |
502 | /* scaler fullbw, luma comb off */ |
503 | ks0127_and_or(sd, KS_VERTIA, and_v: 0x08, or_v: 0x81); |
504 | |
505 | ks0127_and_or(sd, KS_CHROMB, and_v: 0x0f, |
506 | or_v: reg_defaults[KS_CHROMB]&0xf0); |
507 | |
508 | ks0127_and_or(sd, KS_CON, and_v: 0x00, or_v: 0x00); |
509 | ks0127_and_or(sd, KS_BRT, and_v: 0x00, or_v: 32); /* spec: 34 */ |
510 | /* spec: 229 (e5) */ |
511 | ks0127_and_or(sd, KS_SAT, and_v: 0x00, or_v: 0xe8); |
512 | ks0127_and_or(sd, KS_HUE, and_v: 0x00, or_v: 0); |
513 | |
514 | ks0127_and_or(sd, KS_UGAIN, and_v: 0x00, or_v: 238); |
515 | ks0127_and_or(sd, KS_VGAIN, and_v: 0x00, or_v: 0x00); |
516 | |
517 | /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */ |
518 | ks0127_and_or(sd, KS_UVOFFH, and_v: 0x00, or_v: 0x4f); |
519 | ks0127_and_or(sd, KS_UVOFFL, and_v: 0x00, or_v: 0x00); |
520 | break; |
521 | |
522 | default: |
523 | v4l2_dbg(1, debug, sd, |
524 | "s_routing: Unknown input %d\n" , input); |
525 | break; |
526 | } |
527 | |
528 | /* hack: CDMLPF sometimes spontaneously switches on; */ |
529 | /* force back off */ |
530 | ks0127_write(sd, KS_DEMOD, val: reg_defaults[KS_DEMOD]); |
531 | return 0; |
532 | } |
533 | |
534 | static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std) |
535 | { |
536 | struct ks0127 *ks = to_ks0127(sd); |
537 | |
538 | /* Set to automatic SECAM/Fsc mode */ |
539 | ks0127_and_or(sd, KS_DEMOD, and_v: 0xf0, or_v: 0x00); |
540 | |
541 | ks->norm = std; |
542 | if (std & V4L2_STD_NTSC) { |
543 | v4l2_dbg(1, debug, sd, |
544 | "s_std: NTSC_M\n" ); |
545 | ks0127_and_or(sd, KS_CHROMA, and_v: 0x9f, or_v: 0x20); |
546 | } else if (std & V4L2_STD_PAL_N) { |
547 | v4l2_dbg(1, debug, sd, |
548 | "s_std: NTSC_N (fixme)\n" ); |
549 | ks0127_and_or(sd, KS_CHROMA, and_v: 0x9f, or_v: 0x40); |
550 | } else if (std & V4L2_STD_PAL) { |
551 | v4l2_dbg(1, debug, sd, |
552 | "s_std: PAL_N\n" ); |
553 | ks0127_and_or(sd, KS_CHROMA, and_v: 0x9f, or_v: 0x20); |
554 | } else if (std & V4L2_STD_PAL_M) { |
555 | v4l2_dbg(1, debug, sd, |
556 | "s_std: PAL_M (fixme)\n" ); |
557 | ks0127_and_or(sd, KS_CHROMA, and_v: 0x9f, or_v: 0x40); |
558 | } else if (std & V4L2_STD_SECAM) { |
559 | v4l2_dbg(1, debug, sd, |
560 | "s_std: SECAM\n" ); |
561 | |
562 | /* set to secam autodetection */ |
563 | ks0127_and_or(sd, KS_CHROMA, and_v: 0xdf, or_v: 0x20); |
564 | ks0127_and_or(sd, KS_DEMOD, and_v: 0xf0, or_v: 0x00); |
565 | schedule_timeout_interruptible(HZ/10+1); |
566 | |
567 | /* did it autodetect? */ |
568 | if (!(ks0127_read(sd, KS_DEMOD) & 0x40)) |
569 | /* force to secam mode */ |
570 | ks0127_and_or(sd, KS_DEMOD, and_v: 0xf0, or_v: 0x0f); |
571 | } else { |
572 | v4l2_dbg(1, debug, sd, "s_std: Unknown norm %llx\n" , |
573 | (unsigned long long)std); |
574 | } |
575 | return 0; |
576 | } |
577 | |
578 | static int ks0127_s_stream(struct v4l2_subdev *sd, int enable) |
579 | { |
580 | v4l2_dbg(1, debug, sd, "s_stream(%d)\n" , enable); |
581 | if (enable) { |
582 | /* All output pins on */ |
583 | ks0127_and_or(sd, KS_OFMTA, and_v: 0xcf, or_v: 0x30); |
584 | /* Obey the OEN pin */ |
585 | ks0127_and_or(sd, KS_CDEM, and_v: 0x7f, or_v: 0x00); |
586 | } else { |
587 | /* Video output pins off */ |
588 | ks0127_and_or(sd, KS_OFMTA, and_v: 0xcf, or_v: 0x00); |
589 | /* Ignore the OEN pin */ |
590 | ks0127_and_or(sd, KS_CDEM, and_v: 0x7f, or_v: 0x80); |
591 | } |
592 | return 0; |
593 | } |
594 | |
595 | static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) |
596 | { |
597 | int stat = V4L2_IN_ST_NO_SIGNAL; |
598 | u8 status; |
599 | v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL; |
600 | |
601 | status = ks0127_read(sd, KS_STAT); |
602 | if (!(status & 0x20)) /* NOVID not set */ |
603 | stat = 0; |
604 | if (!(status & 0x01)) { /* CLOCK set */ |
605 | stat |= V4L2_IN_ST_NO_COLOR; |
606 | std = V4L2_STD_UNKNOWN; |
607 | } else { |
608 | if ((status & 0x08)) /* PALDET set */ |
609 | std &= V4L2_STD_PAL; |
610 | else |
611 | std &= V4L2_STD_NTSC; |
612 | } |
613 | if ((status & 0x10)) /* PALDET set */ |
614 | std &= V4L2_STD_525_60; |
615 | else |
616 | std &= V4L2_STD_625_50; |
617 | if (pstd) |
618 | *pstd = std; |
619 | if (pstatus) |
620 | *pstatus = stat; |
621 | return 0; |
622 | } |
623 | |
624 | static int ks0127_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) |
625 | { |
626 | v4l2_dbg(1, debug, sd, "querystd\n" ); |
627 | return ks0127_status(sd, NULL, pstd: std); |
628 | } |
629 | |
630 | static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status) |
631 | { |
632 | v4l2_dbg(1, debug, sd, "g_input_status\n" ); |
633 | return ks0127_status(sd, pstatus: status, NULL); |
634 | } |
635 | |
636 | /* ----------------------------------------------------------------------- */ |
637 | |
638 | static const struct v4l2_subdev_video_ops ks0127_video_ops = { |
639 | .s_std = ks0127_s_std, |
640 | .s_routing = ks0127_s_routing, |
641 | .s_stream = ks0127_s_stream, |
642 | .querystd = ks0127_querystd, |
643 | .g_input_status = ks0127_g_input_status, |
644 | }; |
645 | |
646 | static const struct v4l2_subdev_ops ks0127_ops = { |
647 | .video = &ks0127_video_ops, |
648 | }; |
649 | |
650 | /* ----------------------------------------------------------------------- */ |
651 | |
652 | |
653 | static int ks0127_probe(struct i2c_client *client) |
654 | { |
655 | struct ks0127 *ks; |
656 | struct v4l2_subdev *sd; |
657 | |
658 | v4l_info(client, "%s chip found @ 0x%x (%s)\n" , |
659 | client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board" , |
660 | client->addr << 1, client->adapter->name); |
661 | |
662 | ks = devm_kzalloc(dev: &client->dev, size: sizeof(*ks), GFP_KERNEL); |
663 | if (ks == NULL) |
664 | return -ENOMEM; |
665 | sd = &ks->sd; |
666 | v4l2_i2c_subdev_init(sd, client, ops: &ks0127_ops); |
667 | |
668 | /* power up */ |
669 | init_reg_defaults(); |
670 | ks0127_write(sd, KS_CMDA, val: 0x2c); |
671 | mdelay(10); |
672 | |
673 | /* reset the device */ |
674 | ks0127_init(sd); |
675 | return 0; |
676 | } |
677 | |
678 | static void ks0127_remove(struct i2c_client *client) |
679 | { |
680 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
681 | |
682 | v4l2_device_unregister_subdev(sd); |
683 | ks0127_write(sd, KS_OFMTA, val: 0x20); /* tristate */ |
684 | ks0127_write(sd, KS_CMDA, val: 0x2c | 0x80); /* power down */ |
685 | } |
686 | |
687 | static const struct i2c_device_id ks0127_id[] = { |
688 | { "ks0127" , 0 }, |
689 | { "ks0127b" , 0 }, |
690 | { "ks0122s" , 0 }, |
691 | { } |
692 | }; |
693 | MODULE_DEVICE_TABLE(i2c, ks0127_id); |
694 | |
695 | static struct i2c_driver ks0127_driver = { |
696 | .driver = { |
697 | .name = "ks0127" , |
698 | }, |
699 | .probe = ks0127_probe, |
700 | .remove = ks0127_remove, |
701 | .id_table = ks0127_id, |
702 | }; |
703 | |
704 | module_i2c_driver(ks0127_driver); |
705 | |