Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
wis-saa7115.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2006 Micronas USA Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License (Version 2) as
6  * published by the Free Software Foundation.
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 Foundation,
15  * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16  */
17 
18 #include <linux/module.h>
19 #include <linux/init.h>
20 #include <linux/i2c.h>
21 #include <linux/videodev2.h>
22 #include <linux/ioctl.h>
23 #include <linux/slab.h>
24 
25 #include "wis-i2c.h"
26 
27 struct wis_saa7115 {
28  int norm;
30  int contrast;
32  int hue;
33 };
34 
35 static u8 initial_registers[] =
36 {
37  0x01, 0x08,
38  0x02, 0xc0,
39  0x03, 0x20,
40  0x04, 0x80,
41  0x05, 0x80,
42  0x06, 0xeb,
43  0x07, 0xe0,
44  0x08, 0xf0, /* always toggle FID */
45  0x09, 0x40,
46  0x0a, 0x80,
47  0x0b, 0x40,
48  0x0c, 0x40,
49  0x0d, 0x00,
50  0x0e, 0x03,
51  0x0f, 0x2a,
52  0x10, 0x0e,
53  0x11, 0x00,
54  0x12, 0x8d,
55  0x13, 0x00,
56  0x14, 0x00,
57  0x15, 0x11,
58  0x16, 0x01,
59  0x17, 0xda,
60  0x18, 0x40,
61  0x19, 0x80,
62  0x1a, 0x00,
63  0x1b, 0x42,
64  0x1c, 0xa9,
65  0x30, 0x66,
66  0x31, 0x90,
67  0x32, 0x01,
68  0x34, 0x00,
69  0x35, 0x00,
70  0x36, 0x20,
71  0x38, 0x03,
72  0x39, 0x20,
73  0x3a, 0x88,
74  0x40, 0x00,
75  0x41, 0xff,
76  0x42, 0xff,
77  0x43, 0xff,
78  0x44, 0xff,
79  0x45, 0xff,
80  0x46, 0xff,
81  0x47, 0xff,
82  0x48, 0xff,
83  0x49, 0xff,
84  0x4a, 0xff,
85  0x4b, 0xff,
86  0x4c, 0xff,
87  0x4d, 0xff,
88  0x4e, 0xff,
89  0x4f, 0xff,
90  0x50, 0xff,
91  0x51, 0xff,
92  0x52, 0xff,
93  0x53, 0xff,
94  0x54, 0xf4 /*0xff*/,
95  0x55, 0xff,
96  0x56, 0xff,
97  0x57, 0xff,
98  0x58, 0x40,
99  0x59, 0x47,
100  0x5a, 0x06 /*0x03*/,
101  0x5b, 0x83,
102  0x5d, 0x06,
103  0x5e, 0x00,
104  0x80, 0x30, /* window defined scaler operation, task A and B enabled */
105  0x81, 0x03, /* use scaler datapath generated V */
106  0x83, 0x00,
107  0x84, 0x00,
108  0x85, 0x00,
109  0x86, 0x45,
110  0x87, 0x31,
111  0x88, 0xc0,
112  0x90, 0x02, /* task A process top field */
113  0x91, 0x08,
114  0x92, 0x09,
115  0x93, 0x80,
116  0x94, 0x06,
117  0x95, 0x00,
118  0x96, 0xc0,
119  0x97, 0x02,
120  0x98, 0x12,
121  0x99, 0x00,
122  0x9a, 0xf2,
123  0x9b, 0x00,
124  0x9c, 0xd0,
125  0x9d, 0x02,
126  0x9e, 0xf2,
127  0x9f, 0x00,
128  0xa0, 0x01,
129  0xa1, 0x01,
130  0xa2, 0x01,
131  0xa4, 0x80,
132  0xa5, 0x40,
133  0xa6, 0x40,
134  0xa8, 0x00,
135  0xa9, 0x04,
136  0xaa, 0x00,
137  0xac, 0x00,
138  0xad, 0x02,
139  0xae, 0x00,
140  0xb0, 0x00,
141  0xb1, 0x04,
142  0xb2, 0x00,
143  0xb3, 0x04,
144  0xb4, 0x00,
145  0xb8, 0x00,
146  0xbc, 0x00,
147  0xc0, 0x03, /* task B process bottom field */
148  0xc1, 0x08,
149  0xc2, 0x09,
150  0xc3, 0x80,
151  0xc4, 0x06,
152  0xc5, 0x00,
153  0xc6, 0xc0,
154  0xc7, 0x02,
155  0xc8, 0x12,
156  0xc9, 0x00,
157  0xca, 0xf2,
158  0xcb, 0x00,
159  0xcc, 0xd0,
160  0xcd, 0x02,
161  0xce, 0xf2,
162  0xcf, 0x00,
163  0xd0, 0x01,
164  0xd1, 0x01,
165  0xd2, 0x01,
166  0xd4, 0x80,
167  0xd5, 0x40,
168  0xd6, 0x40,
169  0xd8, 0x00,
170  0xd9, 0x04,
171  0xda, 0x00,
172  0xdc, 0x00,
173  0xdd, 0x02,
174  0xde, 0x00,
175  0xe0, 0x00,
176  0xe1, 0x04,
177  0xe2, 0x00,
178  0xe3, 0x04,
179  0xe4, 0x00,
180  0xe8, 0x00,
181  0x88, 0xf0, /* End of original static list */
182  0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
183 };
184 
185 static int write_reg(struct i2c_client *client, u8 reg, u8 value)
186 {
187  return i2c_smbus_write_byte_data(client, reg, value);
188 }
189 
190 static int write_regs(struct i2c_client *client, u8 *regs)
191 {
192  int i;
193 
194  for (i = 0; regs[i] != 0x00; i += 2)
195  if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
196  return -1;
197  return 0;
198 }
199 
200 static int wis_saa7115_command(struct i2c_client *client,
201  unsigned int cmd, void *arg)
202 {
203  struct wis_saa7115 *dec = i2c_get_clientdata(client);
204 
205  switch (cmd) {
206  case VIDIOC_S_INPUT:
207  {
208  int *input = arg;
209 
210  i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
211  i2c_smbus_write_byte_data(client, 0x09,
212  *input < 6 ? 0x40 : 0xC0);
213  break;
214  }
216  {
217  struct video_decoder_resolution *res = arg;
218  /* Course-grained scaler */
219  int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
220  /* Fine-grained scaler to take care of remainder */
221  int h_scaling_increment = (704 / h_integer_scaler) *
222  1024 / res->width;
223  /* Fine-grained scaler only */
224  int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
225  240 : 288) * 1024 / res->height;
226  u8 regs[] = {
227  0x88, 0xc0,
228  0x9c, res->width & 0xff,
229  0x9d, res->width >> 8,
230  0x9e, res->height & 0xff,
231  0x9f, res->height >> 8,
232  0xa0, h_integer_scaler,
233  0xa1, 1,
234  0xa2, 1,
235  0xa8, h_scaling_increment & 0xff,
236  0xa9, h_scaling_increment >> 8,
237  0xac, (h_scaling_increment / 2) & 0xff,
238  0xad, (h_scaling_increment / 2) >> 8,
239  0xb0, v_scaling_increment & 0xff,
240  0xb1, v_scaling_increment >> 8,
241  0xb2, v_scaling_increment & 0xff,
242  0xb3, v_scaling_increment >> 8,
243  0xcc, res->width & 0xff,
244  0xcd, res->width >> 8,
245  0xce, res->height & 0xff,
246  0xcf, res->height >> 8,
247  0xd0, h_integer_scaler,
248  0xd1, 1,
249  0xd2, 1,
250  0xd8, h_scaling_increment & 0xff,
251  0xd9, h_scaling_increment >> 8,
252  0xdc, (h_scaling_increment / 2) & 0xff,
253  0xdd, (h_scaling_increment / 2) >> 8,
254  0xe0, v_scaling_increment & 0xff,
255  0xe1, v_scaling_increment >> 8,
256  0xe2, v_scaling_increment & 0xff,
257  0xe3, v_scaling_increment >> 8,
258  0x88, 0xf0,
259  0, 0,
260  };
261  write_regs(client, regs);
262  break;
263  }
264  case VIDIOC_S_STD:
265  {
266  v4l2_std_id *input = arg;
267  u8 regs[] = {
268  0x88, 0xc0,
269  0x98, *input & V4L2_STD_NTSC ? 0x12 : 0x16,
270  0x9a, *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
271  0x9b, *input & V4L2_STD_NTSC ? 0x00 : 0x01,
272  0xc8, *input & V4L2_STD_NTSC ? 0x12 : 0x16,
273  0xca, *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
274  0xcb, *input & V4L2_STD_NTSC ? 0x00 : 0x01,
275  0x88, 0xf0,
276  0x30, *input & V4L2_STD_NTSC ? 0x66 : 0x00,
277  0x31, *input & V4L2_STD_NTSC ? 0x90 : 0xe0,
278  0, 0,
279  };
280  write_regs(client, regs);
281  dec->norm = *input;
282  break;
283  }
284  case VIDIOC_QUERYCTRL:
285  {
286  struct v4l2_queryctrl *ctrl = arg;
287 
288  switch (ctrl->id) {
289  case V4L2_CID_BRIGHTNESS:
291  strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
292  ctrl->minimum = 0;
293  ctrl->maximum = 255;
294  ctrl->step = 1;
295  ctrl->default_value = 128;
296  ctrl->flags = 0;
297  break;
298  case V4L2_CID_CONTRAST:
300  strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
301  ctrl->minimum = 0;
302  ctrl->maximum = 127;
303  ctrl->step = 1;
304  ctrl->default_value = 64;
305  ctrl->flags = 0;
306  break;
307  case V4L2_CID_SATURATION:
309  strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
310  ctrl->minimum = 0;
311  ctrl->maximum = 127;
312  ctrl->step = 1;
313  ctrl->default_value = 64;
314  ctrl->flags = 0;
315  break;
316  case V4L2_CID_HUE:
318  strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
319  ctrl->minimum = -128;
320  ctrl->maximum = 127;
321  ctrl->step = 1;
322  ctrl->default_value = 0;
323  ctrl->flags = 0;
324  break;
325  }
326  break;
327  }
328  case VIDIOC_S_CTRL:
329  {
330  struct v4l2_control *ctrl = arg;
331 
332  switch (ctrl->id) {
333  case V4L2_CID_BRIGHTNESS:
334  if (ctrl->value > 255)
335  dec->brightness = 255;
336  else if (ctrl->value < 0)
337  dec->brightness = 0;
338  else
339  dec->brightness = ctrl->value;
340  write_reg(client, 0x0a, dec->brightness);
341  break;
342  case V4L2_CID_CONTRAST:
343  if (ctrl->value > 127)
344  dec->contrast = 127;
345  else if (ctrl->value < 0)
346  dec->contrast = 0;
347  else
348  dec->contrast = ctrl->value;
349  write_reg(client, 0x0b, dec->contrast);
350  break;
351  case V4L2_CID_SATURATION:
352  if (ctrl->value > 127)
353  dec->saturation = 127;
354  else if (ctrl->value < 0)
355  dec->saturation = 0;
356  else
357  dec->saturation = ctrl->value;
358  write_reg(client, 0x0c, dec->saturation);
359  break;
360  case V4L2_CID_HUE:
361  if (ctrl->value > 127)
362  dec->hue = 127;
363  else if (ctrl->value < -128)
364  dec->hue = -128;
365  else
366  dec->hue = ctrl->value;
367  write_reg(client, 0x0d, dec->hue);
368  break;
369  }
370  break;
371  }
372  case VIDIOC_G_CTRL:
373  {
374  struct v4l2_control *ctrl = arg;
375 
376  switch (ctrl->id) {
377  case V4L2_CID_BRIGHTNESS:
378  ctrl->value = dec->brightness;
379  break;
380  case V4L2_CID_CONTRAST:
381  ctrl->value = dec->contrast;
382  break;
383  case V4L2_CID_SATURATION:
384  ctrl->value = dec->saturation;
385  break;
386  case V4L2_CID_HUE:
387  ctrl->value = dec->hue;
388  break;
389  }
390  break;
391  }
392  default:
393  break;
394  }
395  return 0;
396 }
397 
398 static int wis_saa7115_probe(struct i2c_client *client,
399  const struct i2c_device_id *id)
400 {
401  struct i2c_adapter *adapter = client->adapter;
402  struct wis_saa7115 *dec;
403 
404  if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
405  return -ENODEV;
406 
407  dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
408  if (dec == NULL)
409  return -ENOMEM;
410 
411  dec->norm = V4L2_STD_NTSC;
412  dec->brightness = 128;
413  dec->contrast = 64;
414  dec->saturation = 64;
415  dec->hue = 0;
416  i2c_set_clientdata(client, dec);
417 
419  "wis-saa7115: initializing SAA7115 at address %d on %s\n",
420  client->addr, adapter->name);
421 
422  if (write_regs(client, initial_registers) < 0) {
424  "wis-saa7115: error initializing SAA7115\n");
425  kfree(dec);
426  return -ENODEV;
427  }
428 
429  return 0;
430 }
431 
432 static int wis_saa7115_remove(struct i2c_client *client)
433 {
434  struct wis_saa7115 *dec = i2c_get_clientdata(client);
435 
436  kfree(dec);
437  return 0;
438 }
439 
440 static const struct i2c_device_id wis_saa7115_id[] = {
441  { "wis_saa7115", 0 },
442  { }
443 };
444 MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);
445 
446 static struct i2c_driver wis_saa7115_driver = {
447  .driver = {
448  .name = "WIS SAA7115 I2C driver",
449  },
450  .probe = wis_saa7115_probe,
451  .remove = wis_saa7115_remove,
452  .command = wis_saa7115_command,
453  .id_table = wis_saa7115_id,
454 };
455 
456 static int __init wis_saa7115_init(void)
457 {
458  return i2c_add_driver(&wis_saa7115_driver);
459 }
460 
461 static void __exit wis_saa7115_cleanup(void)
462 {
463  i2c_del_driver(&wis_saa7115_driver);
464 }
465 
466 module_init(wis_saa7115_init);
467 module_exit(wis_saa7115_cleanup);
468 
469 MODULE_LICENSE("GPL v2");