aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/saa7110.c468
-rw-r--r--include/media/v4l2-chip-ident.h4
2 files changed, 251 insertions, 221 deletions
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 9ef6b2bb1b77..ea16e3cf1793 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -33,15 +33,19 @@
33#include <linux/wait.h> 33#include <linux/wait.h>
34#include <asm/uaccess.h> 34#include <asm/uaccess.h>
35#include <linux/i2c.h> 35#include <linux/i2c.h>
36#include <linux/videodev.h> 36#include <linux/videodev2.h>
37#include <linux/video_decoder.h> 37#include <media/v4l2-device.h>
38#include <media/v4l2-common.h> 38#include <media/v4l2-chip-ident.h>
39#include <media/v4l2-i2c-drv-legacy.h> 39#include <media/v4l2-i2c-drv-legacy.h>
40 40
41MODULE_DESCRIPTION("Philips SAA7110 video decoder driver"); 41MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
42MODULE_AUTHOR("Pauline Middelink"); 42MODULE_AUTHOR("Pauline Middelink");
43MODULE_LICENSE("GPL"); 43MODULE_LICENSE("GPL");
44 44
45static unsigned short normal_i2c[] = { 0x9c >> 1, 0x9e >> 1, I2C_CLIENT_END };
46
47I2C_CLIENT_INSMOD;
48
45static int debug; 49static int debug;
46module_param(debug, int, 0); 50module_param(debug, int, 0);
47MODULE_PARM_DESC(debug, "Debug level (0-1)"); 51MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -52,6 +56,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
52#define SAA7110_NR_REG 0x35 56#define SAA7110_NR_REG 0x35
53 57
54struct saa7110 { 58struct saa7110 {
59 struct v4l2_subdev sd;
55 u8 reg[SAA7110_NR_REG]; 60 u8 reg[SAA7110_NR_REG];
56 61
57 v4l2_std_id norm; 62 v4l2_std_id norm;
@@ -65,20 +70,28 @@ struct saa7110 {
65 wait_queue_head_t wq; 70 wait_queue_head_t wq;
66}; 71};
67 72
73static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
74{
75 return container_of(sd, struct saa7110, sd);
76}
77
68/* ----------------------------------------------------------------------- */ 78/* ----------------------------------------------------------------------- */
69/* I2C support functions */ 79/* I2C support functions */
70/* ----------------------------------------------------------------------- */ 80/* ----------------------------------------------------------------------- */
71 81
72static int saa7110_write(struct i2c_client *client, u8 reg, u8 value) 82static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value)
73{ 83{
74 struct saa7110 *decoder = i2c_get_clientdata(client); 84 struct i2c_client *client = v4l2_get_subdevdata(sd);
85 struct saa7110 *decoder = to_saa7110(sd);
75 86
76 decoder->reg[reg] = value; 87 decoder->reg[reg] = value;
77 return i2c_smbus_write_byte_data(client, reg, value); 88 return i2c_smbus_write_byte_data(client, reg, value);
78} 89}
79 90
80static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsigned int len) 91static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
81{ 92{
93 struct i2c_client *client = v4l2_get_subdevdata(sd);
94 struct saa7110 *decoder = to_saa7110(sd);
82 int ret = -1; 95 int ret = -1;
83 u8 reg = *data; /* first register to write to */ 96 u8 reg = *data; /* first register to write to */
84 97
@@ -89,15 +102,13 @@ static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsign
89 /* the saa7110 has an autoincrement function, use it if 102 /* the saa7110 has an autoincrement function, use it if
90 * the adapter understands raw I2C */ 103 * the adapter understands raw I2C */
91 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 104 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
92 struct saa7110 *decoder = i2c_get_clientdata(client);
93
94 ret = i2c_master_send(client, data, len); 105 ret = i2c_master_send(client, data, len);
95 106
96 /* Cache the written data */ 107 /* Cache the written data */
97 memcpy(decoder->reg + reg, data + 1, len - 1); 108 memcpy(decoder->reg + reg, data + 1, len - 1);
98 } else { 109 } else {
99 for (++data, --len; len; len--) { 110 for (++data, --len; len; len--) {
100 ret = saa7110_write(client, reg++, *data++); 111 ret = saa7110_write(sd, reg++, *data++);
101 if (ret < 0) 112 if (ret < 0)
102 break; 113 break;
103 } 114 }
@@ -106,8 +117,10 @@ static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsign
106 return ret; 117 return ret;
107} 118}
108 119
109static inline int saa7110_read(struct i2c_client *client) 120static inline int saa7110_read(struct v4l2_subdev *sd)
110{ 121{
122 struct i2c_client *client = v4l2_get_subdevdata(sd);
123
111 return i2c_smbus_read_byte(client); 124 return i2c_smbus_read_byte(client);
112} 125}
113 126
@@ -115,11 +128,11 @@ static inline int saa7110_read(struct i2c_client *client)
115/* SAA7110 functions */ 128/* SAA7110 functions */
116/* ----------------------------------------------------------------------- */ 129/* ----------------------------------------------------------------------- */
117 130
118#define FRESP_06H_COMPST 0x03 //0x13 131#define FRESP_06H_COMPST 0x03 /*0x13*/
119#define FRESP_06H_SVIDEO 0x83 //0xC0 132#define FRESP_06H_SVIDEO 0x83 /*0xC0*/
120 133
121 134
122static int saa7110_selmux(struct i2c_client *client, int chan) 135static int saa7110_selmux(struct v4l2_subdev *sd, int chan)
123{ 136{
124 static const unsigned char modes[9][8] = { 137 static const unsigned char modes[9][8] = {
125 /* mode 0 */ 138 /* mode 0 */
@@ -150,17 +163,17 @@ static int saa7110_selmux(struct i2c_client *client, int chan)
150 {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23, 163 {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
151 0x44, 0x75, 0x21} 164 0x44, 0x75, 0x21}
152 }; 165 };
153 struct saa7110 *decoder = i2c_get_clientdata(client); 166 struct saa7110 *decoder = to_saa7110(sd);
154 const unsigned char *ptr = modes[chan]; 167 const unsigned char *ptr = modes[chan];
155 168
156 saa7110_write(client, 0x06, ptr[0]); /* Luminance control */ 169 saa7110_write(sd, 0x06, ptr[0]); /* Luminance control */
157 saa7110_write(client, 0x20, ptr[1]); /* Analog Control #1 */ 170 saa7110_write(sd, 0x20, ptr[1]); /* Analog Control #1 */
158 saa7110_write(client, 0x21, ptr[2]); /* Analog Control #2 */ 171 saa7110_write(sd, 0x21, ptr[2]); /* Analog Control #2 */
159 saa7110_write(client, 0x22, ptr[3]); /* Mixer Control #1 */ 172 saa7110_write(sd, 0x22, ptr[3]); /* Mixer Control #1 */
160 saa7110_write(client, 0x2C, ptr[4]); /* Mixer Control #2 */ 173 saa7110_write(sd, 0x2C, ptr[4]); /* Mixer Control #2 */
161 saa7110_write(client, 0x30, ptr[5]); /* ADCs gain control */ 174 saa7110_write(sd, 0x30, ptr[5]); /* ADCs gain control */
162 saa7110_write(client, 0x31, ptr[6]); /* Mixer Control #3 */ 175 saa7110_write(sd, 0x31, ptr[6]); /* Mixer Control #3 */
163 saa7110_write(client, 0x21, ptr[7]); /* Analog Control #2 */ 176 saa7110_write(sd, 0x21, ptr[7]); /* Analog Control #2 */
164 decoder->input = chan; 177 decoder->input = chan;
165 178
166 return 0; 179 return 0;
@@ -176,250 +189,265 @@ static const unsigned char initseq[1 + SAA7110_NR_REG] = {
176 /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02 189 /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
177}; 190};
178 191
179static v4l2_std_id determine_norm(struct i2c_client *client) 192static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
180{ 193{
181 DEFINE_WAIT(wait); 194 DEFINE_WAIT(wait);
182 struct saa7110 *decoder = i2c_get_clientdata(client); 195 struct saa7110 *decoder = to_saa7110(sd);
183 int status; 196 int status;
184 197
185 /* mode changed, start automatic detection */ 198 /* mode changed, start automatic detection */
186 saa7110_write_block(client, initseq, sizeof(initseq)); 199 saa7110_write_block(sd, initseq, sizeof(initseq));
187 saa7110_selmux(client, decoder->input); 200 saa7110_selmux(sd, decoder->input);
188 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); 201 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
189 schedule_timeout(msecs_to_jiffies(250)); 202 schedule_timeout(msecs_to_jiffies(250));
190 finish_wait(&decoder->wq, &wait); 203 finish_wait(&decoder->wq, &wait);
191 status = saa7110_read(client); 204 status = saa7110_read(sd);
192 if (status & 0x40) { 205 if (status & 0x40) {
193 v4l_dbg(1, debug, client, "status=0x%02x (no signal)\n", status); 206 v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
194 return decoder->norm; // no change 207 return decoder->norm; /* no change*/
195 } 208 }
196 if ((status & 3) == 0) { 209 if ((status & 3) == 0) {
197 saa7110_write(client, 0x06, 0x83); 210 saa7110_write(sd, 0x06, 0x83);
198 if (status & 0x20) { 211 if (status & 0x20) {
199 v4l_dbg(1, debug, client, "status=0x%02x (NTSC/no color)\n", status); 212 v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status);
200 //saa7110_write(client,0x2E,0x81); 213 /*saa7110_write(sd,0x2E,0x81);*/
201 return V4L2_STD_NTSC; 214 return V4L2_STD_NTSC;
202 } 215 }
203 v4l_dbg(1, debug, client, "status=0x%02x (PAL/no color)\n", status); 216 v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status);
204 //saa7110_write(client,0x2E,0x9A); 217 /*saa7110_write(sd,0x2E,0x9A);*/
205 return V4L2_STD_PAL; 218 return V4L2_STD_PAL;
206 } 219 }
207 //saa7110_write(client,0x06,0x03); 220 /*saa7110_write(sd,0x06,0x03);*/
208 if (status & 0x20) { /* 60Hz */ 221 if (status & 0x20) { /* 60Hz */
209 v4l_dbg(1, debug, client, "status=0x%02x (NTSC)\n", status); 222 v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status);
210 saa7110_write(client, 0x0D, 0x86); 223 saa7110_write(sd, 0x0D, 0x86);
211 saa7110_write(client, 0x0F, 0x50); 224 saa7110_write(sd, 0x0F, 0x50);
212 saa7110_write(client, 0x11, 0x2C); 225 saa7110_write(sd, 0x11, 0x2C);
213 //saa7110_write(client,0x2E,0x81); 226 /*saa7110_write(sd,0x2E,0x81);*/
214 return V4L2_STD_NTSC; 227 return V4L2_STD_NTSC;
215 } 228 }
216 229
217 /* 50Hz -> PAL/SECAM */ 230 /* 50Hz -> PAL/SECAM */
218 saa7110_write(client, 0x0D, 0x86); 231 saa7110_write(sd, 0x0D, 0x86);
219 saa7110_write(client, 0x0F, 0x10); 232 saa7110_write(sd, 0x0F, 0x10);
220 saa7110_write(client, 0x11, 0x59); 233 saa7110_write(sd, 0x11, 0x59);
221 //saa7110_write(client,0x2E,0x9A); 234 /*saa7110_write(sd,0x2E,0x9A);*/
222 235
223 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); 236 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
224 schedule_timeout(msecs_to_jiffies(250)); 237 schedule_timeout(msecs_to_jiffies(250));
225 finish_wait(&decoder->wq, &wait); 238 finish_wait(&decoder->wq, &wait);
226 239
227 status = saa7110_read(client); 240 status = saa7110_read(sd);
228 if ((status & 0x03) == 0x01) { 241 if ((status & 0x03) == 0x01) {
229 v4l_dbg(1, debug, client, "status=0x%02x (SECAM)\n", status); 242 v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status);
230 saa7110_write(client, 0x0D, 0x87); 243 saa7110_write(sd, 0x0D, 0x87);
231 return V4L2_STD_SECAM; 244 return V4L2_STD_SECAM;
232 } 245 }
233 v4l_dbg(1, debug, client, "status=0x%02x (PAL)\n", status); 246 v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status);
234 return V4L2_STD_PAL; 247 return V4L2_STD_PAL;
235} 248}
236 249
237static int 250static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
238saa7110_command (struct i2c_client *client,
239 unsigned int cmd,
240 void *arg)
241{ 251{
242 struct saa7110 *decoder = i2c_get_clientdata(client); 252 struct saa7110 *decoder = to_saa7110(sd);
243 struct v4l2_routing *route = arg; 253 int res = V4L2_IN_ST_NO_SIGNAL;
244 v4l2_std_id std; 254 int status = saa7110_read(sd);
245 int v; 255
246 256 v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
247 switch (cmd) { 257 status, decoder->norm);
248 case VIDIOC_INT_INIT: 258 if (!(status & 0x40))
249 //saa7110_write_block(client, initseq, sizeof(initseq)); 259 res = 0;
250 break; 260 if (!(status & 0x03))
261 res |= V4L2_IN_ST_NO_COLOR;
262
263 *pstatus = res;
264 return 0;
265}
251 266
252 case VIDIOC_INT_G_INPUT_STATUS: 267static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
253 { 268{
254 int res = V4L2_IN_ST_NO_SIGNAL; 269 *(v4l2_std_id *)std = determine_norm(sd);
255 int status; 270 return 0;
271}
256 272
257 status = saa7110_read(client); 273static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
258 v4l_dbg(1, debug, client, "status=0x%02x norm=%llx\n", 274{
259 status, decoder->norm); 275 struct saa7110 *decoder = to_saa7110(sd);
260 if (!(status & 0x40)) 276
261 res = 0; 277 if (decoder->norm != std) {
262 if (!(status & 0x03)) 278 decoder->norm = std;
263 res |= V4L2_IN_ST_NO_COLOR; 279 /*saa7110_write(sd, 0x06, 0x03);*/
280 if (std & V4L2_STD_NTSC) {
281 saa7110_write(sd, 0x0D, 0x86);
282 saa7110_write(sd, 0x0F, 0x50);
283 saa7110_write(sd, 0x11, 0x2C);
284 /*saa7110_write(sd, 0x2E, 0x81);*/
285 v4l2_dbg(1, debug, sd, "switched to NTSC\n");
286 } else if (std & V4L2_STD_PAL) {
287 saa7110_write(sd, 0x0D, 0x86);
288 saa7110_write(sd, 0x0F, 0x10);
289 saa7110_write(sd, 0x11, 0x59);
290 /*saa7110_write(sd, 0x2E, 0x9A);*/
291 v4l2_dbg(1, debug, sd, "switched to PAL\n");
292 } else if (std & V4L2_STD_SECAM) {
293 saa7110_write(sd, 0x0D, 0x87);
294 saa7110_write(sd, 0x0F, 0x10);
295 saa7110_write(sd, 0x11, 0x59);
296 /*saa7110_write(sd, 0x2E, 0x9A);*/
297 v4l2_dbg(1, debug, sd, "switched to SECAM\n");
298 } else {
299 return -EINVAL;
300 }
301 }
302 return 0;
303}
264 304
265 *(int *) arg = res; 305static int saa7110_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
266 break; 306{
307 struct saa7110 *decoder = to_saa7110(sd);
308
309 if (route->input < 0 || route->input >= SAA7110_MAX_INPUT) {
310 v4l2_dbg(1, debug, sd, "input=%d not available\n", route->input);
311 return -EINVAL;
267 } 312 }
313 if (decoder->input != route->input) {
314 saa7110_selmux(sd, route->input);
315 v4l2_dbg(1, debug, sd, "switched to input=%d\n", route->input);
316 }
317 return 0;
318}
268 319
269 case VIDIOC_QUERYSTD: 320static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
270 { 321{
271 *(v4l2_std_id *)arg = determine_norm(client); 322 struct saa7110 *decoder = to_saa7110(sd);
272 break; 323
324 if (decoder->enable != enable) {
325 decoder->enable = enable;
326 saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80);
327 v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off");
273 } 328 }
329 return 0;
330}
274 331
275 case VIDIOC_S_STD: 332static int saa7110_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
276 std = *(v4l2_std_id *) arg; 333{
277 if (decoder->norm != std) { 334 switch (qc->id) {
278 decoder->norm = std; 335 case V4L2_CID_BRIGHTNESS:
279 //saa7110_write(client, 0x06, 0x03); 336 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
280 if (std & V4L2_STD_NTSC) { 337 case V4L2_CID_CONTRAST:
281 saa7110_write(client, 0x0D, 0x86); 338 case V4L2_CID_SATURATION:
282 saa7110_write(client, 0x0F, 0x50); 339 return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
283 saa7110_write(client, 0x11, 0x2C); 340 case V4L2_CID_HUE:
284 //saa7110_write(client, 0x2E, 0x81); 341 return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
285 v4l_dbg(1, debug, client, "switched to NTSC\n"); 342 default:
286 } else if (std & V4L2_STD_PAL) { 343 return -EINVAL;
287 saa7110_write(client, 0x0D, 0x86); 344 }
288 saa7110_write(client, 0x0F, 0x10); 345 return 0;
289 saa7110_write(client, 0x11, 0x59); 346}
290 //saa7110_write(client, 0x2E, 0x9A);
291 v4l_dbg(1, debug, client, "switched to PAL\n");
292 } else if (std & V4L2_STD_SECAM) {
293 saa7110_write(client, 0x0D, 0x87);
294 saa7110_write(client, 0x0F, 0x10);
295 saa7110_write(client, 0x11, 0x59);
296 //saa7110_write(client, 0x2E, 0x9A);
297 v4l_dbg(1, debug, client, "switched to SECAM\n");
298 } else {
299 return -EINVAL;
300 }
301 }
302 break;
303 347
304 case VIDIOC_INT_S_VIDEO_ROUTING: 348static int saa7110_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
305 if (route->input < 0 || route->input >= SAA7110_MAX_INPUT) { 349{
306 v4l_dbg(1, debug, client, "input=%d not available\n", route->input); 350 struct saa7110 *decoder = to_saa7110(sd);
307 return -EINVAL; 351
308 } 352 switch (ctrl->id) {
309 if (decoder->input != route->input) { 353 case V4L2_CID_BRIGHTNESS:
310 saa7110_selmux(client, route->input); 354 ctrl->value = decoder->bright;
311 v4l_dbg(1, debug, client, "switched to input=%d\n", route->input); 355 break;
312 } 356 case V4L2_CID_CONTRAST:
357 ctrl->value = decoder->contrast;
358 break;
359 case V4L2_CID_SATURATION:
360 ctrl->value = decoder->sat;
361 break;
362 case V4L2_CID_HUE:
363 ctrl->value = decoder->hue;
313 break; 364 break;
365 default:
366 return -EINVAL;
367 }
368 return 0;
369}
314 370
315 case VIDIOC_STREAMON: 371static int saa7110_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
316 case VIDIOC_STREAMOFF: 372{
317 v = cmd == VIDIOC_STREAMON; 373 struct saa7110 *decoder = to_saa7110(sd);
318 if (decoder->enable != v) { 374
319 decoder->enable = v; 375 switch (ctrl->id) {
320 saa7110_write(client, 0x0E, v ? 0x18 : 0x80); 376 case V4L2_CID_BRIGHTNESS:
321 v4l_dbg(1, debug, client, "YUV %s\n", v ? "on" : "off"); 377 if (decoder->bright != ctrl->value) {
378 decoder->bright = ctrl->value;
379 saa7110_write(sd, 0x19, decoder->bright);
322 } 380 }
323 break; 381 break;
324 382 case V4L2_CID_CONTRAST:
325 case VIDIOC_QUERYCTRL: 383 if (decoder->contrast != ctrl->value) {
326 { 384 decoder->contrast = ctrl->value;
327 struct v4l2_queryctrl *qc = arg; 385 saa7110_write(sd, 0x13, decoder->contrast);
328
329 switch (qc->id) {
330 case V4L2_CID_BRIGHTNESS:
331 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
332 case V4L2_CID_CONTRAST:
333 case V4L2_CID_SATURATION:
334 return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
335 case V4L2_CID_HUE:
336 return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
337 default:
338 return -EINVAL;
339 } 386 }
340 break; 387 break;
341 } 388 case V4L2_CID_SATURATION:
342 389 if (decoder->sat != ctrl->value) {
343 case VIDIOC_G_CTRL: 390 decoder->sat = ctrl->value;
344 { 391 saa7110_write(sd, 0x12, decoder->sat);
345 struct v4l2_control *ctrl = arg;
346
347 switch (ctrl->id) {
348 case V4L2_CID_BRIGHTNESS:
349 ctrl->value = decoder->bright;
350 break;
351 case V4L2_CID_CONTRAST:
352 ctrl->value = decoder->contrast;
353 break;
354 case V4L2_CID_SATURATION:
355 ctrl->value = decoder->sat;
356 break;
357 case V4L2_CID_HUE:
358 ctrl->value = decoder->hue;
359 break;
360 default:
361 return -EINVAL;
362 } 392 }
363 break; 393 break;
364 } 394 case V4L2_CID_HUE:
365 395 if (decoder->hue != ctrl->value) {
366 case VIDIOC_S_CTRL: 396 decoder->hue = ctrl->value;
367 { 397 saa7110_write(sd, 0x07, decoder->hue);
368 struct v4l2_control *ctrl = arg;
369
370 switch (ctrl->id) {
371 case V4L2_CID_BRIGHTNESS:
372 if (decoder->bright != ctrl->value) {
373 decoder->bright = ctrl->value;
374 saa7110_write(client, 0x19, decoder->bright);
375 }
376 break;
377 case V4L2_CID_CONTRAST:
378 if (decoder->contrast != ctrl->value) {
379 decoder->contrast = ctrl->value;
380 saa7110_write(client, 0x13, decoder->contrast);
381 }
382 break;
383 case V4L2_CID_SATURATION:
384 if (decoder->sat != ctrl->value) {
385 decoder->sat = ctrl->value;
386 saa7110_write(client, 0x12, decoder->sat);
387 }
388 break;
389 case V4L2_CID_HUE:
390 if (decoder->hue != ctrl->value) {
391 decoder->hue = ctrl->value;
392 saa7110_write(client, 0x07, decoder->hue);
393 }
394 break;
395 default:
396 return -EINVAL;
397 } 398 }
398 break; 399 break;
399 }
400
401 default: 400 default:
402 v4l_dbg(1, debug, client, "unknown command %08x\n", cmd);
403 return -EINVAL; 401 return -EINVAL;
404 } 402 }
405 return 0; 403 return 0;
406} 404}
407 405
406static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
407{
408 struct i2c_client *client = v4l2_get_subdevdata(sd);
409
410 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
411}
412
413static int saa7110_command(struct i2c_client *client, unsigned cmd, void *arg)
414{
415 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
416}
417
408/* ----------------------------------------------------------------------- */ 418/* ----------------------------------------------------------------------- */
409 419
410/* 420static const struct v4l2_subdev_core_ops saa7110_core_ops = {
411 * Generic i2c probe 421 .g_chip_ident = saa7110_g_chip_ident,
412 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' 422 .g_ctrl = saa7110_g_ctrl,
413 */ 423 .s_ctrl = saa7110_s_ctrl,
424 .queryctrl = saa7110_queryctrl,
425};
414 426
415static unsigned short normal_i2c[] = { 0x9c >> 1, 0x9e >> 1, I2C_CLIENT_END }; 427static const struct v4l2_subdev_tuner_ops saa7110_tuner_ops = {
428 .s_std = saa7110_s_std,
429};
416 430
417I2C_CLIENT_INSMOD; 431static const struct v4l2_subdev_video_ops saa7110_video_ops = {
432 .s_routing = saa7110_s_routing,
433 .s_stream = saa7110_s_stream,
434 .querystd = saa7110_querystd,
435 .g_input_status = saa7110_g_input_status,
436};
437
438static const struct v4l2_subdev_ops saa7110_ops = {
439 .core = &saa7110_core_ops,
440 .tuner = &saa7110_tuner_ops,
441 .video = &saa7110_video_ops,
442};
443
444/* ----------------------------------------------------------------------- */
418 445
419static int saa7110_probe(struct i2c_client *client, 446static int saa7110_probe(struct i2c_client *client,
420 const struct i2c_device_id *id) 447 const struct i2c_device_id *id)
421{ 448{
422 struct saa7110 *decoder; 449 struct saa7110 *decoder;
450 struct v4l2_subdev *sd;
423 int rv; 451 int rv;
424 452
425 /* Check if the adapter supports the needed features */ 453 /* Check if the adapter supports the needed features */
@@ -433,6 +461,8 @@ static int saa7110_probe(struct i2c_client *client,
433 decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL); 461 decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
434 if (!decoder) 462 if (!decoder)
435 return -ENOMEM; 463 return -ENOMEM;
464 sd = &decoder->sd;
465 v4l2_i2c_subdev_init(sd, client, &saa7110_ops);
436 decoder->norm = V4L2_STD_PAL; 466 decoder->norm = V4L2_STD_PAL;
437 decoder->input = 0; 467 decoder->input = 0;
438 decoder->enable = 1; 468 decoder->enable = 1;
@@ -441,30 +471,29 @@ static int saa7110_probe(struct i2c_client *client,
441 decoder->hue = 32768; 471 decoder->hue = 32768;
442 decoder->sat = 32768; 472 decoder->sat = 32768;
443 init_waitqueue_head(&decoder->wq); 473 init_waitqueue_head(&decoder->wq);
444 i2c_set_clientdata(client, decoder);
445 474
446 rv = saa7110_write_block(client, initseq, sizeof(initseq)); 475 rv = saa7110_write_block(sd, initseq, sizeof(initseq));
447 if (rv < 0) { 476 if (rv < 0) {
448 v4l_dbg(1, debug, client, "init status %d\n", rv); 477 v4l2_dbg(1, debug, sd, "init status %d\n", rv);
449 } else { 478 } else {
450 int ver, status; 479 int ver, status;
451 saa7110_write(client, 0x21, 0x10); 480 saa7110_write(sd, 0x21, 0x10);
452 saa7110_write(client, 0x0e, 0x18); 481 saa7110_write(sd, 0x0e, 0x18);
453 saa7110_write(client, 0x0D, 0x04); 482 saa7110_write(sd, 0x0D, 0x04);
454 ver = saa7110_read(client); 483 ver = saa7110_read(sd);
455 saa7110_write(client, 0x0D, 0x06); 484 saa7110_write(sd, 0x0D, 0x06);
456 //mdelay(150); 485 /*mdelay(150);*/
457 status = saa7110_read(client); 486 status = saa7110_read(sd);
458 v4l_dbg(1, debug, client, "version %x, status=0x%02x\n", 487 v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n",
459 ver, status); 488 ver, status);
460 saa7110_write(client, 0x0D, 0x86); 489 saa7110_write(sd, 0x0D, 0x86);
461 saa7110_write(client, 0x0F, 0x10); 490 saa7110_write(sd, 0x0F, 0x10);
462 saa7110_write(client, 0x11, 0x59); 491 saa7110_write(sd, 0x11, 0x59);
463 //saa7110_write(client, 0x2E, 0x9A); 492 /*saa7110_write(sd, 0x2E, 0x9A);*/
464 } 493 }
465 494
466 //saa7110_selmux(client,0); 495 /*saa7110_selmux(sd,0);*/
467 //determine_norm(client); 496 /*determine_norm(sd);*/
468 /* setup and implicit mode 0 select has been performed */ 497 /* setup and implicit mode 0 select has been performed */
469 498
470 return 0; 499 return 0;
@@ -472,7 +501,10 @@ static int saa7110_probe(struct i2c_client *client,
472 501
473static int saa7110_remove(struct i2c_client *client) 502static int saa7110_remove(struct i2c_client *client)
474{ 503{
475 kfree(i2c_get_clientdata(client)); 504 struct v4l2_subdev *sd = i2c_get_clientdata(client);
505
506 v4l2_device_unregister_subdev(sd);
507 kfree(to_saa7110(sd));
476 return 0; 508 return 0;
477} 509}
478 510
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index b5ed91a4ce92..f3fdada21963 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -37,10 +37,8 @@ enum {
37 /* module saa7110: just ident 100 */ 37 /* module saa7110: just ident 100 */
38 V4L2_IDENT_SAA7110 = 100, 38 V4L2_IDENT_SAA7110 = 100,
39 39
40 /* module saa7111: just ident 101 */ 40 /* module saa7115: reserved range 101-149 */
41 V4L2_IDENT_SAA7111 = 101, 41 V4L2_IDENT_SAA7111 = 101,
42
43 /* module saa7115: reserved range 102-149 */
44 V4L2_IDENT_SAA7113 = 103, 42 V4L2_IDENT_SAA7113 = 103,
45 V4L2_IDENT_SAA7114 = 104, 43 V4L2_IDENT_SAA7114 = 104,
46 V4L2_IDENT_SAA7115 = 105, 44 V4L2_IDENT_SAA7115 = 105,