Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
wis-tw2804.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_tw2804 {
28  int channel;
29  int norm;
31  int contrast;
33  int hue;
34 };
35 
36 static u8 global_registers[] = {
37  0x39, 0x00,
38  0x3a, 0xff,
39  0x3b, 0x84,
40  0x3c, 0x80,
41  0x3d, 0x80,
42  0x3e, 0x82,
43  0x3f, 0x82,
44  0xff, 0xff, /* Terminator (reg 0xff does not exist) */
45 };
46 
47 static u8 channel_registers[] = {
48  0x01, 0xc4,
49  0x02, 0xa5,
50  0x03, 0x20,
51  0x04, 0xd0,
52  0x05, 0x20,
53  0x06, 0xd0,
54  0x07, 0x88,
55  0x08, 0x20,
56  0x09, 0x07,
57  0x0a, 0xf0,
58  0x0b, 0x07,
59  0x0c, 0xf0,
60  0x0d, 0x40,
61  0x0e, 0xd2,
62  0x0f, 0x80,
63  0x10, 0x80,
64  0x11, 0x80,
65  0x12, 0x80,
66  0x13, 0x1f,
67  0x14, 0x00,
68  0x15, 0x00,
69  0x16, 0x00,
70  0x17, 0x00,
71  0x18, 0xff,
72  0x19, 0xff,
73  0x1a, 0xff,
74  0x1b, 0xff,
75  0x1c, 0xff,
76  0x1d, 0xff,
77  0x1e, 0xff,
78  0x1f, 0xff,
79  0x20, 0x07,
80  0x21, 0x07,
81  0x22, 0x00,
82  0x23, 0x91,
83  0x24, 0x51,
84  0x25, 0x03,
85  0x26, 0x00,
86  0x27, 0x00,
87  0x28, 0x00,
88  0x29, 0x00,
89  0x2a, 0x00,
90  0x2b, 0x00,
91  0x2c, 0x00,
92  0x2d, 0x00,
93  0x2e, 0x00,
94  0x2f, 0x00,
95  0x30, 0x00,
96  0x31, 0x00,
97  0x32, 0x00,
98  0x33, 0x00,
99  0x34, 0x00,
100  0x35, 0x00,
101  0x36, 0x00,
102  0x37, 0x00,
103  0xff, 0xff, /* Terminator (reg 0xff does not exist) */
104 };
105 
106 static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel)
107 {
108  return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
109 }
110 
111 static int write_regs(struct i2c_client *client, u8 *regs, int channel)
112 {
113  int i;
114 
115  for (i = 0; regs[i] != 0xff; i += 2)
116  if (i2c_smbus_write_byte_data(client,
117  regs[i] | (channel << 6), regs[i + 1]) < 0)
118  return -1;
119  return 0;
120 }
121 
122 static int wis_tw2804_command(struct i2c_client *client,
123  unsigned int cmd, void *arg)
124 {
125  struct wis_tw2804 *dec = i2c_get_clientdata(client);
126 
127  if (cmd == DECODER_SET_CHANNEL) {
128  int *input = arg;
129 
130  if (*input < 0 || *input > 3) {
131  printk(KERN_ERR "wis-tw2804: channel %d is not "
132  "between 0 and 3!\n", *input);
133  return 0;
134  }
135  dec->channel = *input;
136  printk(KERN_DEBUG "wis-tw2804: initializing TW2804 "
137  "channel %d\n", dec->channel);
138  if (dec->channel == 0 &&
139  write_regs(client, global_registers, 0) < 0) {
140  printk(KERN_ERR "wis-tw2804: error initializing "
141  "TW2804 global registers\n");
142  return 0;
143  }
144  if (write_regs(client, channel_registers, dec->channel) < 0) {
145  printk(KERN_ERR "wis-tw2804: error initializing "
146  "TW2804 channel %d\n", dec->channel);
147  return 0;
148  }
149  return 0;
150  }
151 
152  if (dec->channel < 0) {
153  printk(KERN_DEBUG "wis-tw2804: ignoring command %08x until "
154  "channel number is set\n", cmd);
155  return 0;
156  }
157 
158  switch (cmd) {
159  case VIDIOC_S_STD:
160  {
161  v4l2_std_id *input = arg;
162  u8 regs[] = {
163  0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84,
164  0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
165  0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
166  0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
167  0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
168  0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a,
169  0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
170  0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
171  0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
172  0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
173  0xff, 0xff,
174  };
175  write_regs(client, regs, dec->channel);
176  dec->norm = *input;
177  break;
178  }
179  case VIDIOC_QUERYCTRL:
180  {
181  struct v4l2_queryctrl *ctrl = arg;
182 
183  switch (ctrl->id) {
184  case V4L2_CID_BRIGHTNESS:
186  strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
187  ctrl->minimum = 0;
188  ctrl->maximum = 255;
189  ctrl->step = 1;
190  ctrl->default_value = 128;
191  ctrl->flags = 0;
192  break;
193  case V4L2_CID_CONTRAST:
195  strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
196  ctrl->minimum = 0;
197  ctrl->maximum = 255;
198  ctrl->step = 1;
199  ctrl->default_value = 128;
200  ctrl->flags = 0;
201  break;
202  case V4L2_CID_SATURATION:
204  strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
205  ctrl->minimum = 0;
206  ctrl->maximum = 255;
207  ctrl->step = 1;
208  ctrl->default_value = 128;
209  ctrl->flags = 0;
210  break;
211  case V4L2_CID_HUE:
213  strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
214  ctrl->minimum = 0;
215  ctrl->maximum = 255;
216  ctrl->step = 1;
217  ctrl->default_value = 128;
218  ctrl->flags = 0;
219  break;
220  }
221  break;
222  }
223  case VIDIOC_S_CTRL:
224  {
225  struct v4l2_control *ctrl = arg;
226 
227  switch (ctrl->id) {
228  case V4L2_CID_BRIGHTNESS:
229  if (ctrl->value > 255)
230  dec->brightness = 255;
231  else if (ctrl->value < 0)
232  dec->brightness = 0;
233  else
234  dec->brightness = ctrl->value;
235  write_reg(client, 0x12, dec->brightness, dec->channel);
236  break;
237  case V4L2_CID_CONTRAST:
238  if (ctrl->value > 255)
239  dec->contrast = 255;
240  else if (ctrl->value < 0)
241  dec->contrast = 0;
242  else
243  dec->contrast = ctrl->value;
244  write_reg(client, 0x11, dec->contrast, dec->channel);
245  break;
246  case V4L2_CID_SATURATION:
247  if (ctrl->value > 255)
248  dec->saturation = 255;
249  else if (ctrl->value < 0)
250  dec->saturation = 0;
251  else
252  dec->saturation = ctrl->value;
253  write_reg(client, 0x10, dec->saturation, dec->channel);
254  break;
255  case V4L2_CID_HUE:
256  if (ctrl->value > 255)
257  dec->hue = 255;
258  else if (ctrl->value < 0)
259  dec->hue = 0;
260  else
261  dec->hue = ctrl->value;
262  write_reg(client, 0x0f, dec->hue, dec->channel);
263  break;
264  }
265  break;
266  }
267  case VIDIOC_G_CTRL:
268  {
269  struct v4l2_control *ctrl = arg;
270 
271  switch (ctrl->id) {
272  case V4L2_CID_BRIGHTNESS:
273  ctrl->value = dec->brightness;
274  break;
275  case V4L2_CID_CONTRAST:
276  ctrl->value = dec->contrast;
277  break;
278  case V4L2_CID_SATURATION:
279  ctrl->value = dec->saturation;
280  break;
281  case V4L2_CID_HUE:
282  ctrl->value = dec->hue;
283  break;
284  }
285  break;
286  }
287  default:
288  break;
289  }
290  return 0;
291 }
292 
293 static int wis_tw2804_probe(struct i2c_client *client,
294  const struct i2c_device_id *id)
295 {
296  struct i2c_adapter *adapter = client->adapter;
297  struct wis_tw2804 *dec;
298 
299  if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
300  return -ENODEV;
301 
302  dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL);
303  if (dec == NULL)
304  return -ENOMEM;
305 
306  dec->channel = -1;
307  dec->norm = V4L2_STD_NTSC;
308  dec->brightness = 128;
309  dec->contrast = 128;
310  dec->saturation = 128;
311  dec->hue = 128;
312  i2c_set_clientdata(client, dec);
313 
314  printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n",
315  client->addr, adapter->name);
316 
317  return 0;
318 }
319 
320 static int wis_tw2804_remove(struct i2c_client *client)
321 {
322  struct wis_tw2804 *dec = i2c_get_clientdata(client);
323 
324  kfree(dec);
325  return 0;
326 }
327 
328 static const struct i2c_device_id wis_tw2804_id[] = {
329  { "wis_tw2804", 0 },
330  { }
331 };
332 MODULE_DEVICE_TABLE(i2c, wis_tw2804_id);
333 
334 static struct i2c_driver wis_tw2804_driver = {
335  .driver = {
336  .name = "WIS TW2804 I2C driver",
337  },
338  .probe = wis_tw2804_probe,
339  .remove = wis_tw2804_remove,
340  .command = wis_tw2804_command,
341  .id_table = wis_tw2804_id,
342 };
343 
344 static int __init wis_tw2804_init(void)
345 {
346  return i2c_add_driver(&wis_tw2804_driver);
347 }
348 
349 static void __exit wis_tw2804_cleanup(void)
350 {
351  i2c_del_driver(&wis_tw2804_driver);
352 }
353 
354 module_init(wis_tw2804_init);
355 module_exit(wis_tw2804_cleanup);
356 
357 MODULE_LICENSE("GPL v2");