diff options
author | Ladislav Michl <ladis@linux-mips.org> | 2005-09-01 11:07:34 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-11-07 13:05:41 -0500 |
commit | a637a114f36b94a1ad8b9867f43bac0414958420 (patch) | |
tree | 3ad9a5c60817c8d0b4e2de30672da706c44ecbfa /drivers/media/video/saa7191.c | |
parent | a06d61c648890ad7e86d5ea04bd6999b254db193 (diff) |
VINO driver version 0.0.5.
Second cut of the VINO / Indycam driver for the Silicon Graphics Indy,
much more feature complete and bug free.
Diffstat (limited to 'drivers/media/video/saa7191.c')
-rw-r--r-- | drivers/media/video/saa7191.c | 533 |
1 files changed, 417 insertions, 116 deletions
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c index 3ddbb62312be..cbca896e8cfa 100644 --- a/drivers/media/video/saa7191.c +++ b/drivers/media/video/saa7191.c | |||
@@ -26,71 +26,95 @@ | |||
26 | 26 | ||
27 | #include "saa7191.h" | 27 | #include "saa7191.h" |
28 | 28 | ||
29 | #define SAA7191_MODULE_VERSION "0.0.3" | 29 | #define SAA7191_MODULE_VERSION "0.0.5" |
30 | 30 | ||
31 | MODULE_DESCRIPTION("Philips SAA7191 video decoder driver"); | 31 | MODULE_DESCRIPTION("Philips SAA7191 video decoder driver"); |
32 | MODULE_VERSION(SAA7191_MODULE_VERSION); | 32 | MODULE_VERSION(SAA7191_MODULE_VERSION); |
33 | MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); | 33 | MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); |
34 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
35 | 35 | ||
36 | // #define SAA7191_DEBUG | ||
37 | |||
38 | #ifdef SAA7191_DEBUG | ||
39 | #define dprintk(x...) printk("SAA7191: " x); | ||
40 | #else | ||
41 | #define dprintk(x...) | ||
42 | #endif | ||
43 | |||
44 | #define SAA7191_SYNC_COUNT 30 | ||
45 | #define SAA7191_SYNC_DELAY 100 /* milliseconds */ | ||
46 | |||
36 | struct saa7191 { | 47 | struct saa7191 { |
37 | struct i2c_client *client; | 48 | struct i2c_client *client; |
38 | 49 | ||
39 | /* the register values are stored here as the actual | 50 | /* the register values are stored here as the actual |
40 | * I2C-registers are write-only */ | 51 | * I2C-registers are write-only */ |
41 | unsigned char reg[25]; | 52 | u8 reg[25]; |
42 | 53 | ||
43 | unsigned char norm; | 54 | int input; |
44 | unsigned char input; | 55 | int norm; |
45 | }; | 56 | }; |
46 | 57 | ||
47 | static struct i2c_driver i2c_driver_saa7191; | 58 | static struct i2c_driver i2c_driver_saa7191; |
48 | 59 | ||
49 | static const unsigned char initseq[] = { | 60 | static const u8 initseq[] = { |
50 | 0, /* Subaddress */ | 61 | 0, /* Subaddress */ |
51 | 0x50, /* SAA7191_REG_IDEL */ | 62 | |
52 | 0x30, /* SAA7191_REG_HSYB */ | 63 | 0x50, /* (0x50) SAA7191_REG_IDEL */ |
53 | 0x00, /* SAA7191_REG_HSYS */ | 64 | |
54 | 0xe8, /* SAA7191_REG_HCLB */ | 65 | /* 50 Hz signal timing */ |
55 | 0xb6, /* SAA7191_REG_HCLS */ | 66 | 0x30, /* (0x30) SAA7191_REG_HSYB */ |
56 | 0xf4, /* SAA7191_REG_HPHI */ | 67 | 0x00, /* (0x00) SAA7191_REG_HSYS */ |
57 | 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */ | 68 | 0xe8, /* (0xe8) SAA7191_REG_HCLB */ |
58 | 0x00, /* SAA7191_REG_HUEC */ | 69 | 0xb6, /* (0xb6) SAA7191_REG_HCLS */ |
59 | 0xf8, /* SAA7191_REG_CKTQ */ | 70 | 0xf4, /* (0xf4) SAA7191_REG_HPHI */ |
60 | 0xf8, /* SAA7191_REG_CKTS */ | 71 | |
61 | 0x90, /* SAA7191_REG_PLSE */ | 72 | /* control */ |
62 | 0x90, /* SAA7191_REG_SESE */ | 73 | SAA7191_LUMA_APER_1, /* (0x01) SAA7191_REG_LUMA - CVBS mode */ |
63 | 0x00, /* SAA7191_REG_GAIN */ | 74 | 0x00, /* (0x00) SAA7191_REG_HUEC */ |
64 | 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */ | 75 | 0xf8, /* (0xf8) SAA7191_REG_CKTQ */ |
65 | 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */ | 76 | 0xf8, /* (0xf8) SAA7191_REG_CKTS */ |
66 | 0x99, /* SAA7191_REG_CTL3 - automatic field detection */ | 77 | 0x90, /* (0x90) SAA7191_REG_PLSE */ |
67 | 0x00, /* SAA7191_REG_CTL4 */ | 78 | 0x90, /* (0x90) SAA7191_REG_SESE */ |
68 | 0x2c, /* SAA7191_REG_CHCV */ | 79 | 0x00, /* (0x00) SAA7191_REG_GAIN */ |
80 | SAA7191_STDC_NFEN | SAA7191_STDC_HRMV, /* (0x0c) SAA7191_REG_STDC | ||
81 | * - not SECAM, | ||
82 | * slow time constant */ | ||
83 | SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS | ||
84 | | SAA7191_IOCK_OEDY, /* (0x78) SAA7191_REG_IOCK | ||
85 | * - chroma from CVBS, GPSW1 & 2 off */ | ||
86 | SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS | ||
87 | | SAA7191_CTL3_YDEL0, /* (0x99) SAA7191_REG_CTL3 | ||
88 | * - automatic field detection */ | ||
89 | 0x00, /* (0x00) SAA7191_REG_CTL4 */ | ||
90 | 0x2c, /* (0x2c) SAA7191_REG_CHCV - PAL nominal value */ | ||
69 | 0x00, /* unused */ | 91 | 0x00, /* unused */ |
70 | 0x00, /* unused */ | 92 | 0x00, /* unused */ |
71 | 0x34, /* SAA7191_REG_HS6B */ | 93 | |
72 | 0x0a, /* SAA7191_REG_HS6S */ | 94 | /* 60 Hz signal timing */ |
73 | 0xf4, /* SAA7191_REG_HC6B */ | 95 | 0x34, /* (0x34) SAA7191_REG_HS6B */ |
74 | 0xce, /* SAA7191_REG_HC6S */ | 96 | 0x0a, /* (0x0a) SAA7191_REG_HS6S */ |
75 | 0xf4, /* SAA7191_REG_HP6I */ | 97 | 0xf4, /* (0xf4) SAA7191_REG_HC6B */ |
98 | 0xce, /* (0xce) SAA7191_REG_HC6S */ | ||
99 | 0xf4, /* (0xf4) SAA7191_REG_HP6I */ | ||
76 | }; | 100 | }; |
77 | 101 | ||
78 | /* SAA7191 register handling */ | 102 | /* SAA7191 register handling */ |
79 | 103 | ||
80 | static unsigned char saa7191_read_reg(struct i2c_client *client, | 104 | static u8 saa7191_read_reg(struct i2c_client *client, |
81 | unsigned char reg) | 105 | u8 reg) |
82 | { | 106 | { |
83 | return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg]; | 107 | return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg]; |
84 | } | 108 | } |
85 | 109 | ||
86 | static int saa7191_read_status(struct i2c_client *client, | 110 | static int saa7191_read_status(struct i2c_client *client, |
87 | unsigned char *value) | 111 | u8 *value) |
88 | { | 112 | { |
89 | int ret; | 113 | int ret; |
90 | 114 | ||
91 | ret = i2c_master_recv(client, value, 1); | 115 | ret = i2c_master_recv(client, value, 1); |
92 | if (ret < 0) { | 116 | if (ret < 0) { |
93 | printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed"); | 117 | printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed\n"); |
94 | return ret; | 118 | return ret; |
95 | } | 119 | } |
96 | 120 | ||
@@ -98,17 +122,16 @@ static int saa7191_read_status(struct i2c_client *client, | |||
98 | } | 122 | } |
99 | 123 | ||
100 | 124 | ||
101 | static int saa7191_write_reg(struct i2c_client *client, unsigned char reg, | 125 | static int saa7191_write_reg(struct i2c_client *client, u8 reg, |
102 | unsigned char value) | 126 | u8 value) |
103 | { | 127 | { |
104 | |||
105 | ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value; | 128 | ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value; |
106 | return i2c_smbus_write_byte_data(client, reg, value); | 129 | return i2c_smbus_write_byte_data(client, reg, value); |
107 | } | 130 | } |
108 | 131 | ||
109 | /* the first byte of data must be the first subaddress number (register) */ | 132 | /* the first byte of data must be the first subaddress number (register) */ |
110 | static int saa7191_write_block(struct i2c_client *client, | 133 | static int saa7191_write_block(struct i2c_client *client, |
111 | unsigned char length, unsigned char *data) | 134 | u8 length, u8 *data) |
112 | { | 135 | { |
113 | int i; | 136 | int i; |
114 | int ret; | 137 | int ret; |
@@ -121,7 +144,7 @@ static int saa7191_write_block(struct i2c_client *client, | |||
121 | ret = i2c_master_send(client, data, length); | 144 | ret = i2c_master_send(client, data, length); |
122 | if (ret < 0) { | 145 | if (ret < 0) { |
123 | printk(KERN_ERR "SAA7191: saa7191_write_block(): " | 146 | printk(KERN_ERR "SAA7191: saa7191_write_block(): " |
124 | "write failed"); | 147 | "write failed\n"); |
125 | return ret; | 148 | return ret; |
126 | } | 149 | } |
127 | 150 | ||
@@ -132,8 +155,9 @@ static int saa7191_write_block(struct i2c_client *client, | |||
132 | 155 | ||
133 | static int saa7191_set_input(struct i2c_client *client, int input) | 156 | static int saa7191_set_input(struct i2c_client *client, int input) |
134 | { | 157 | { |
135 | unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA); | 158 | struct saa7191 *decoder = i2c_get_clientdata(client); |
136 | unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK); | 159 | u8 luma = saa7191_read_reg(client, SAA7191_REG_LUMA); |
160 | u8 iock = saa7191_read_reg(client, SAA7191_REG_IOCK); | ||
137 | int err; | 161 | int err; |
138 | 162 | ||
139 | switch (input) { | 163 | switch (input) { |
@@ -159,32 +183,20 @@ static int saa7191_set_input(struct i2c_client *client, int input) | |||
159 | if (err) | 183 | if (err) |
160 | return -EIO; | 184 | return -EIO; |
161 | 185 | ||
186 | decoder->input = input; | ||
187 | |||
162 | return 0; | 188 | return 0; |
163 | } | 189 | } |
164 | 190 | ||
165 | static int saa7191_set_norm(struct i2c_client *client, int norm) | 191 | static int saa7191_set_norm(struct i2c_client *client, int norm) |
166 | { | 192 | { |
167 | struct saa7191 *decoder = i2c_get_clientdata(client); | 193 | struct saa7191 *decoder = i2c_get_clientdata(client); |
168 | unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); | 194 | u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC); |
169 | unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); | 195 | u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); |
170 | unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV); | 196 | u8 chcv = saa7191_read_reg(client, SAA7191_REG_CHCV); |
171 | int err; | 197 | int err; |
172 | 198 | ||
173 | switch(norm) { | 199 | switch(norm) { |
174 | case SAA7191_NORM_AUTO: { | ||
175 | unsigned char status; | ||
176 | |||
177 | // does status depend on current norm ? | ||
178 | if (saa7191_read_status(client, &status)) | ||
179 | return -EIO; | ||
180 | |||
181 | stdc &= ~SAA7191_STDC_SECS; | ||
182 | ctl3 &= ~SAA7191_CTL3_FSEL; | ||
183 | ctl3 |= SAA7191_CTL3_AUFD; | ||
184 | chcv = (status & SAA7191_STATUS_FIDT) | ||
185 | ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL; | ||
186 | break; | ||
187 | } | ||
188 | case SAA7191_NORM_PAL: | 200 | case SAA7191_NORM_PAL: |
189 | stdc &= ~SAA7191_STDC_SECS; | 201 | stdc &= ~SAA7191_STDC_SECS; |
190 | ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); | 202 | ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); |
@@ -217,60 +229,335 @@ static int saa7191_set_norm(struct i2c_client *client, int norm) | |||
217 | 229 | ||
218 | decoder->norm = norm; | 230 | decoder->norm = norm; |
219 | 231 | ||
232 | dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3, | ||
233 | stdc, chcv); | ||
234 | dprintk("norm: %d\n", norm); | ||
235 | |||
220 | return 0; | 236 | return 0; |
221 | } | 237 | } |
222 | 238 | ||
223 | static int saa7191_get_controls(struct i2c_client *client, | 239 | static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status) |
224 | struct saa7191_control *ctrl) | ||
225 | { | 240 | { |
226 | unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC); | 241 | int i = 0; |
227 | unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); | ||
228 | 242 | ||
229 | if (hue < 0x80) { | 243 | dprintk("Checking for signal...\n"); |
230 | hue += 0x80; | 244 | |
231 | } else { | 245 | for (i = 0; i < SAA7191_SYNC_COUNT; i++) { |
232 | hue -= 0x80; | 246 | if (saa7191_read_status(client, status)) |
247 | return -EIO; | ||
248 | |||
249 | if (((*status) & SAA7191_STATUS_HLCK) == 0) { | ||
250 | dprintk("Signal found\n"); | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | msleep(SAA7191_SYNC_DELAY); | ||
233 | } | 255 | } |
234 | ctrl->hue = hue; | ||
235 | 256 | ||
236 | ctrl->vtrc = (stdc & SAA7191_STDC_VTRC) | 257 | dprintk("No signal\n"); |
237 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | ||
238 | 258 | ||
239 | return 0; | 259 | return -EBUSY; |
240 | } | 260 | } |
241 | 261 | ||
242 | static int saa7191_set_controls(struct i2c_client *client, | 262 | static int saa7191_autodetect_norm_extended(struct i2c_client *client) |
243 | struct saa7191_control *ctrl) | ||
244 | { | 263 | { |
245 | int err; | 264 | u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC); |
265 | u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); | ||
266 | u8 status; | ||
267 | int err = 0; | ||
246 | 268 | ||
247 | if (ctrl->hue >= 0) { | 269 | dprintk("SAA7191 extended signal auto-detection...\n"); |
248 | unsigned char hue = ctrl->hue & 0xff; | 270 | |
249 | if (hue < 0x80) { | 271 | stdc &= ~SAA7191_STDC_SECS; |
250 | hue += 0x80; | 272 | ctl3 &= ~(SAA7191_CTL3_FSEL); |
251 | } else { | 273 | |
252 | hue -= 0x80; | 274 | err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); |
275 | if (err) { | ||
276 | err = -EIO; | ||
277 | goto out; | ||
278 | } | ||
279 | err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); | ||
280 | if (err) { | ||
281 | err = -EIO; | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | ctl3 |= SAA7191_CTL3_AUFD; | ||
286 | err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); | ||
287 | if (err) { | ||
288 | err = -EIO; | ||
289 | goto out; | ||
290 | } | ||
291 | |||
292 | msleep(SAA7191_SYNC_DELAY); | ||
293 | |||
294 | err = saa7191_wait_for_signal(client, &status); | ||
295 | if (err) | ||
296 | goto out; | ||
297 | |||
298 | if (status & SAA7191_STATUS_FIDT) { | ||
299 | /* 60Hz signal -> NTSC */ | ||
300 | dprintk("60Hz signal: NTSC\n"); | ||
301 | return saa7191_set_norm(client, SAA7191_NORM_NTSC); | ||
302 | } | ||
303 | |||
304 | /* 50Hz signal */ | ||
305 | dprintk("50Hz signal: Trying PAL...\n"); | ||
306 | |||
307 | /* try PAL first */ | ||
308 | err = saa7191_set_norm(client, SAA7191_NORM_PAL); | ||
309 | if (err) | ||
310 | goto out; | ||
311 | |||
312 | msleep(SAA7191_SYNC_DELAY); | ||
313 | |||
314 | err = saa7191_wait_for_signal(client, &status); | ||
315 | if (err) | ||
316 | goto out; | ||
317 | |||
318 | /* not 50Hz ? */ | ||
319 | if (status & SAA7191_STATUS_FIDT) { | ||
320 | dprintk("No 50Hz signal\n"); | ||
321 | err = -EAGAIN; | ||
322 | goto out; | ||
323 | } | ||
324 | |||
325 | if (status & SAA7191_STATUS_CODE) { | ||
326 | dprintk("PAL\n"); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | dprintk("No color detected with PAL - Trying SECAM...\n"); | ||
331 | |||
332 | /* no color detected ? -> try SECAM */ | ||
333 | err = saa7191_set_norm(client, | ||
334 | SAA7191_NORM_SECAM); | ||
335 | if (err) | ||
336 | goto out; | ||
337 | |||
338 | msleep(SAA7191_SYNC_DELAY); | ||
339 | |||
340 | err = saa7191_wait_for_signal(client, &status); | ||
341 | if (err) | ||
342 | goto out; | ||
343 | |||
344 | /* not 50Hz ? */ | ||
345 | if (status & SAA7191_STATUS_FIDT) { | ||
346 | dprintk("No 50Hz signal\n"); | ||
347 | err = -EAGAIN; | ||
348 | goto out; | ||
349 | } | ||
350 | |||
351 | if (status & SAA7191_STATUS_CODE) { | ||
352 | /* Color detected -> SECAM */ | ||
353 | dprintk("SECAM\n"); | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | dprintk("No color detected with SECAM - Going back to PAL.\n"); | ||
358 | |||
359 | /* still no color detected ? | ||
360 | * -> set norm back to PAL */ | ||
361 | err = saa7191_set_norm(client, | ||
362 | SAA7191_NORM_PAL); | ||
363 | if (err) | ||
364 | goto out; | ||
365 | |||
366 | out: | ||
367 | ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); | ||
368 | if (ctl3 & SAA7191_CTL3_AUFD) { | ||
369 | ctl3 &= ~(SAA7191_CTL3_AUFD); | ||
370 | err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); | ||
371 | if (err) { | ||
372 | err = -EIO; | ||
253 | } | 373 | } |
254 | err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue); | ||
255 | if (err) | ||
256 | return -EIO; | ||
257 | } | 374 | } |
258 | if (ctrl->vtrc >= 0) { | ||
259 | unsigned char stdc = | ||
260 | saa7191_read_reg(client, SAA7191_REG_STDC); | ||
261 | 375 | ||
262 | if (ctrl->vtrc) { | 376 | return err; |
263 | stdc |= SAA7191_STDC_VTRC; | 377 | } |
264 | } else { | 378 | |
265 | stdc &= ~SAA7191_STDC_VTRC; | 379 | static int saa7191_autodetect_norm(struct i2c_client *client) |
380 | { | ||
381 | u8 status; | ||
382 | |||
383 | dprintk("SAA7191 signal auto-detection...\n"); | ||
384 | |||
385 | dprintk("Reading status...\n"); | ||
386 | |||
387 | if (saa7191_read_status(client, &status)) | ||
388 | return -EIO; | ||
389 | |||
390 | dprintk("Checking for signal...\n"); | ||
391 | |||
392 | /* no signal ? */ | ||
393 | if (status & SAA7191_STATUS_HLCK) { | ||
394 | dprintk("No signal\n"); | ||
395 | return -EBUSY; | ||
396 | } | ||
397 | |||
398 | dprintk("Signal found\n"); | ||
399 | |||
400 | if (status & SAA7191_STATUS_FIDT) { | ||
401 | /* 60hz signal -> NTSC */ | ||
402 | dprintk("NTSC\n"); | ||
403 | return saa7191_set_norm(client, SAA7191_NORM_NTSC); | ||
404 | } else { | ||
405 | /* 50hz signal -> PAL */ | ||
406 | dprintk("PAL\n"); | ||
407 | return saa7191_set_norm(client, SAA7191_NORM_PAL); | ||
408 | } | ||
409 | } | ||
410 | |||
411 | static int saa7191_get_control(struct i2c_client *client, | ||
412 | struct saa7191_control *ctrl) | ||
413 | { | ||
414 | u8 reg; | ||
415 | int ret = 0; | ||
416 | |||
417 | switch (ctrl->type) { | ||
418 | case SAA7191_CONTROL_BANDPASS: | ||
419 | case SAA7191_CONTROL_BANDPASS_WEIGHT: | ||
420 | case SAA7191_CONTROL_CORING: | ||
421 | reg = saa7191_read_reg(client, SAA7191_REG_LUMA); | ||
422 | switch (ctrl->type) { | ||
423 | case SAA7191_CONTROL_BANDPASS: | ||
424 | ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK) | ||
425 | >> SAA7191_LUMA_BPSS_SHIFT; | ||
426 | break; | ||
427 | case SAA7191_CONTROL_BANDPASS_WEIGHT: | ||
428 | ctrl->value = ((s32)reg & SAA7191_LUMA_APER_MASK) | ||
429 | >> SAA7191_LUMA_APER_SHIFT; | ||
430 | break; | ||
431 | case SAA7191_CONTROL_CORING: | ||
432 | ctrl->value = ((s32)reg & SAA7191_LUMA_CORI_MASK) | ||
433 | >> SAA7191_LUMA_CORI_SHIFT; | ||
434 | break; | ||
266 | } | 435 | } |
436 | break; | ||
437 | case SAA7191_CONTROL_FORCE_COLOUR: | ||
438 | case SAA7191_CONTROL_CHROMA_GAIN: | ||
439 | reg = saa7191_read_reg(client, SAA7191_REG_GAIN); | ||
440 | if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) | ||
441 | ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0; | ||
442 | else | ||
443 | ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK) | ||
444 | >> SAA7191_GAIN_LFIS_SHIFT; | ||
445 | break; | ||
446 | case SAA7191_CONTROL_HUE: | ||
447 | reg = saa7191_read_reg(client, SAA7191_REG_HUEC); | ||
448 | if (reg < 0x80) | ||
449 | reg += 0x80; | ||
450 | else | ||
451 | reg -= 0x80; | ||
452 | ctrl->value = (s32)reg; | ||
453 | break; | ||
454 | case SAA7191_CONTROL_VTRC: | ||
455 | reg = saa7191_read_reg(client, SAA7191_REG_STDC); | ||
456 | ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0; | ||
457 | break; | ||
458 | case SAA7191_CONTROL_LUMA_DELAY: | ||
459 | reg = saa7191_read_reg(client, SAA7191_REG_CTL3); | ||
460 | ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK) | ||
461 | >> SAA7191_CTL3_YDEL_SHIFT; | ||
462 | if (ctrl->value >= 4) | ||
463 | ctrl->value -= 8; | ||
464 | break; | ||
465 | case SAA7191_CONTROL_VNR: | ||
466 | reg = saa7191_read_reg(client, SAA7191_REG_CTL4); | ||
467 | ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK) | ||
468 | >> SAA7191_CTL4_VNOI_SHIFT; | ||
469 | break; | ||
470 | default: | ||
471 | ret = -EINVAL; | ||
472 | } | ||
267 | 473 | ||
268 | err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); | 474 | return ret; |
269 | if (err) | 475 | } |
270 | return -EIO; | 476 | |
477 | static int saa7191_set_control(struct i2c_client *client, | ||
478 | struct saa7191_control *ctrl) | ||
479 | { | ||
480 | u8 reg; | ||
481 | int ret = 0; | ||
482 | |||
483 | switch (ctrl->type) { | ||
484 | case SAA7191_CONTROL_BANDPASS: | ||
485 | case SAA7191_CONTROL_BANDPASS_WEIGHT: | ||
486 | case SAA7191_CONTROL_CORING: | ||
487 | reg = saa7191_read_reg(client, SAA7191_REG_LUMA); | ||
488 | switch (ctrl->type) { | ||
489 | case SAA7191_CONTROL_BANDPASS: | ||
490 | reg &= ~SAA7191_LUMA_BPSS_MASK; | ||
491 | reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT) | ||
492 | & SAA7191_LUMA_BPSS_MASK; | ||
493 | break; | ||
494 | case SAA7191_CONTROL_BANDPASS_WEIGHT: | ||
495 | reg &= ~SAA7191_LUMA_APER_MASK; | ||
496 | reg |= (ctrl->value << SAA7191_LUMA_APER_SHIFT) | ||
497 | & SAA7191_LUMA_APER_MASK; | ||
498 | break; | ||
499 | case SAA7191_CONTROL_CORING: | ||
500 | reg &= ~SAA7191_LUMA_CORI_MASK; | ||
501 | reg |= (ctrl->value << SAA7191_LUMA_CORI_SHIFT) | ||
502 | & SAA7191_LUMA_CORI_MASK; | ||
503 | break; | ||
504 | } | ||
505 | ret = saa7191_write_reg(client, SAA7191_REG_LUMA, reg); | ||
506 | break; | ||
507 | case SAA7191_CONTROL_FORCE_COLOUR: | ||
508 | case SAA7191_CONTROL_CHROMA_GAIN: | ||
509 | reg = saa7191_read_reg(client, SAA7191_REG_GAIN); | ||
510 | if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) { | ||
511 | if (ctrl->value) | ||
512 | reg |= SAA7191_GAIN_COLO; | ||
513 | else | ||
514 | reg &= ~SAA7191_GAIN_COLO; | ||
515 | } else { | ||
516 | reg &= ~SAA7191_GAIN_LFIS_MASK; | ||
517 | reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT) | ||
518 | & SAA7191_GAIN_LFIS_MASK; | ||
519 | } | ||
520 | ret = saa7191_write_reg(client, SAA7191_REG_GAIN, reg); | ||
521 | break; | ||
522 | case SAA7191_CONTROL_HUE: | ||
523 | reg = ctrl->value & 0xff; | ||
524 | if (reg < 0x80) | ||
525 | reg += 0x80; | ||
526 | else | ||
527 | reg -= 0x80; | ||
528 | ret = saa7191_write_reg(client, SAA7191_REG_HUEC, reg); | ||
529 | break; | ||
530 | case SAA7191_CONTROL_VTRC: | ||
531 | reg = saa7191_read_reg(client, SAA7191_REG_STDC); | ||
532 | if (ctrl->value) | ||
533 | reg |= SAA7191_STDC_VTRC; | ||
534 | else | ||
535 | reg &= ~SAA7191_STDC_VTRC; | ||
536 | ret = saa7191_write_reg(client, SAA7191_REG_STDC, reg); | ||
537 | break; | ||
538 | case SAA7191_CONTROL_LUMA_DELAY: { | ||
539 | s32 value = ctrl->value; | ||
540 | if (value < 0) | ||
541 | value += 8; | ||
542 | reg = saa7191_read_reg(client, SAA7191_REG_CTL3); | ||
543 | reg &= ~SAA7191_CTL3_YDEL_MASK; | ||
544 | reg |= (value << SAA7191_CTL3_YDEL_SHIFT) | ||
545 | & SAA7191_CTL3_YDEL_MASK; | ||
546 | ret = saa7191_write_reg(client, SAA7191_REG_CTL3, reg); | ||
547 | break; | ||
548 | } | ||
549 | case SAA7191_CONTROL_VNR: | ||
550 | reg = saa7191_read_reg(client, SAA7191_REG_CTL4); | ||
551 | reg &= ~SAA7191_CTL4_VNOI_MASK; | ||
552 | reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT) | ||
553 | & SAA7191_CTL4_VNOI_MASK; | ||
554 | ret = saa7191_write_reg(client, SAA7191_REG_CTL4, reg); | ||
555 | break; | ||
556 | default: | ||
557 | ret = -EINVAL; | ||
271 | } | 558 | } |
272 | 559 | ||
273 | return 0; | 560 | return ret; |
274 | } | 561 | } |
275 | 562 | ||
276 | /* I2C-interface */ | 563 | /* I2C-interface */ |
@@ -309,11 +596,7 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) | |||
309 | if (err) | 596 | if (err) |
310 | goto out_free_decoder; | 597 | goto out_free_decoder; |
311 | 598 | ||
312 | decoder->input = SAA7191_INPUT_COMPOSITE; | 599 | err = saa7191_write_block(client, sizeof(initseq), (u8 *)initseq); |
313 | decoder->norm = SAA7191_NORM_AUTO; | ||
314 | |||
315 | err = saa7191_write_block(client, sizeof(initseq), | ||
316 | (unsigned char *)initseq); | ||
317 | if (err) { | 600 | if (err) { |
318 | printk(KERN_ERR "SAA7191 initialization failed\n"); | 601 | printk(KERN_ERR "SAA7191 initialization failed\n"); |
319 | goto out_detach_client; | 602 | goto out_detach_client; |
@@ -321,6 +604,14 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) | |||
321 | 604 | ||
322 | printk(KERN_INFO "SAA7191 initialized\n"); | 605 | printk(KERN_INFO "SAA7191 initialized\n"); |
323 | 606 | ||
607 | decoder->input = SAA7191_INPUT_COMPOSITE; | ||
608 | decoder->norm = SAA7191_NORM_PAL; | ||
609 | |||
610 | err = saa7191_autodetect_norm(client); | ||
611 | if (err && (err != -EBUSY)) { | ||
612 | printk(KERN_ERR "SAA7191: Signal auto-detection failed\n"); | ||
613 | } | ||
614 | |||
324 | return 0; | 615 | return 0; |
325 | 616 | ||
326 | out_detach_client: | 617 | out_detach_client: |
@@ -368,7 +659,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, | |||
368 | } | 659 | } |
369 | case DECODER_GET_STATUS: { | 660 | case DECODER_GET_STATUS: { |
370 | int *iarg = arg; | 661 | int *iarg = arg; |
371 | unsigned char status; | 662 | u8 status; |
372 | int res = 0; | 663 | int res = 0; |
373 | 664 | ||
374 | if (saa7191_read_status(client, &status)) { | 665 | if (saa7191_read_status(client, &status)) { |
@@ -404,7 +695,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, | |||
404 | 695 | ||
405 | switch (*iarg) { | 696 | switch (*iarg) { |
406 | case VIDEO_MODE_AUTO: | 697 | case VIDEO_MODE_AUTO: |
407 | return saa7191_set_norm(client, SAA7191_NORM_AUTO); | 698 | return saa7191_autodetect_norm(client); |
408 | case VIDEO_MODE_PAL: | 699 | case VIDEO_MODE_PAL: |
409 | return saa7191_set_norm(client, SAA7191_NORM_PAL); | 700 | return saa7191_set_norm(client, SAA7191_NORM_PAL); |
410 | case VIDEO_MODE_NTSC: | 701 | case VIDEO_MODE_NTSC: |
@@ -446,38 +737,48 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, | |||
446 | int err; | 737 | int err; |
447 | 738 | ||
448 | val = (pic->hue >> 8) - 0x80; | 739 | val = (pic->hue >> 8) - 0x80; |
740 | |||
449 | err = saa7191_write_reg(client, SAA7191_REG_HUEC, val); | 741 | err = saa7191_write_reg(client, SAA7191_REG_HUEC, val); |
450 | if (err) | 742 | if (err) |
451 | return -EIO; | 743 | return -EIO; |
744 | |||
452 | break; | 745 | break; |
453 | } | 746 | } |
454 | case DECODER_SAA7191_GET_STATUS: { | 747 | case DECODER_SAA7191_GET_STATUS: { |
455 | struct saa7191_status *status = arg; | 748 | struct saa7191_status *status = arg; |
456 | unsigned char status_reg; | 749 | u8 status_reg; |
457 | 750 | ||
458 | if (saa7191_read_status(client, &status_reg)) | 751 | if (saa7191_read_status(client, &status_reg)) |
459 | return -EIO; | 752 | return -EIO; |
753 | |||
460 | status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0) | 754 | status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0) |
461 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | 755 | ? 1 : 0; |
462 | status->ntsc = (status_reg & SAA7191_STATUS_FIDT) | 756 | status->signal_60hz = (status_reg & SAA7191_STATUS_FIDT) |
463 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | 757 | ? 1 : 0; |
464 | status->color = (status_reg & SAA7191_STATUS_CODE) | 758 | status->color = (status_reg & SAA7191_STATUS_CODE) ? 1 : 0; |
465 | ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; | ||
466 | 759 | ||
467 | status->input = decoder->input; | 760 | status->input = decoder->input; |
468 | status->norm = decoder->norm; | 761 | status->norm = decoder->norm; |
762 | |||
763 | break; | ||
469 | } | 764 | } |
470 | case DECODER_SAA7191_SET_NORM: { | 765 | case DECODER_SAA7191_SET_NORM: { |
471 | int *norm = arg; | 766 | int *norm = arg; |
472 | return saa7191_set_norm(client, *norm); | 767 | |
768 | switch (*norm) { | ||
769 | case SAA7191_NORM_AUTO: | ||
770 | return saa7191_autodetect_norm(client); | ||
771 | case SAA7191_NORM_AUTO_EXT: | ||
772 | return saa7191_autodetect_norm_extended(client); | ||
773 | default: | ||
774 | return saa7191_set_norm(client, *norm); | ||
775 | } | ||
473 | } | 776 | } |
474 | case DECODER_SAA7191_GET_CONTROLS: { | 777 | case DECODER_SAA7191_GET_CONTROL: { |
475 | struct saa7191_control *ctrl = arg; | 778 | return saa7191_get_control(client, arg); |
476 | return saa7191_get_controls(client, ctrl); | ||
477 | } | 779 | } |
478 | case DECODER_SAA7191_SET_CONTROLS: { | 780 | case DECODER_SAA7191_SET_CONTROL: { |
479 | struct saa7191_control *ctrl = arg; | 781 | return saa7191_set_control(client, arg); |
480 | return saa7191_set_controls(client, ctrl); | ||
481 | } | 782 | } |
482 | default: | 783 | default: |
483 | return -EINVAL; | 784 | return -EINVAL; |
@@ -488,12 +789,12 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, | |||
488 | 789 | ||
489 | static struct i2c_driver i2c_driver_saa7191 = { | 790 | static struct i2c_driver i2c_driver_saa7191 = { |
490 | .owner = THIS_MODULE, | 791 | .owner = THIS_MODULE, |
491 | .name = "saa7191", | 792 | .name = "saa7191", |
492 | .id = I2C_DRIVERID_SAA7191, | 793 | .id = I2C_DRIVERID_SAA7191, |
493 | .flags = I2C_DF_NOTIFY, | 794 | .flags = I2C_DF_NOTIFY, |
494 | .attach_adapter = saa7191_probe, | 795 | .attach_adapter = saa7191_probe, |
495 | .detach_client = saa7191_detach, | 796 | .detach_client = saa7191_detach, |
496 | .command = saa7191_command | 797 | .command = saa7191_command |
497 | }; | 798 | }; |
498 | 799 | ||
499 | static int saa7191_init(void) | 800 | static int saa7191_init(void) |