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 27struct wis_tw9903 { 28 int norm; 29 int brightness; 30 int contrast; 31 int hue; 32}; 33 34static u8 initial_registers[] = 35{ 36 0x02, 0x44, /* input 1, composite */ 37 0x03, 0x92, /* correct digital format */ 38 0x04, 0x00, 39 0x05, 0x80, /* or 0x00 for PAL */ 40 0x06, 0x40, /* second internal current reference */ 41 0x07, 0x02, /* window */ 42 0x08, 0x14, /* window */ 43 0x09, 0xf0, /* window */ 44 0x0a, 0x81, /* window */ 45 0x0b, 0xd0, /* window */ 46 0x0c, 0x8c, 47 0x0d, 0x00, /* scaling */ 48 0x0e, 0x11, /* scaling */ 49 0x0f, 0x00, /* scaling */ 50 0x10, 0x00, /* brightness */ 51 0x11, 0x60, /* contrast */ 52 0x12, 0x01, /* sharpness */ 53 0x13, 0x7f, /* U gain */ 54 0x14, 0x5a, /* V gain */ 55 0x15, 0x00, /* hue */ 56 0x16, 0xc3, /* sharpness */ 57 0x18, 0x00, 58 0x19, 0x58, /* vbi */ 59 0x1a, 0x80, 60 0x1c, 0x0f, /* video norm */ 61 0x1d, 0x7f, /* video norm */ 62 0x20, 0xa0, /* clamping gain (working 0x50) */ 63 0x21, 0x22, 64 0x22, 0xf0, 65 0x23, 0xfe, 66 0x24, 0x3c, 67 0x25, 0x38, 68 0x26, 0x44, 69 0x27, 0x20, 70 0x28, 0x00, 71 0x29, 0x15, 72 0x2a, 0xa0, 73 0x2b, 0x44, 74 0x2c, 0x37, 75 0x2d, 0x00, 76 0x2e, 0xa5, /* burst PLL control (working: a9) */ 77 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */ 78 0x31, 0x00, 79 0x33, 0x22, 80 0x34, 0x11, 81 0x35, 0x35, 82 0x3b, 0x05, 83 0x06, 0xc0, /* reset device */ 84 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ 85}; 86 87static int write_reg(struct i2c_client *client, u8 reg, u8 value) 88{ 89 return i2c_smbus_write_byte_data(client, reg, value); 90} 91 92static int write_regs(struct i2c_client *client, u8 *regs) 93{ 94 int i; 95 96 for (i = 0; regs[i] != 0x00; i += 2) 97 if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) 98 return -1; 99 return 0; 100} 101 102static int wis_tw9903_command(struct i2c_client *client, 103 unsigned int cmd, void *arg) 104{ 105 struct wis_tw9903 *dec = i2c_get_clientdata(client); 106 107 switch (cmd) { 108 case VIDIOC_S_INPUT: 109 { 110 int *input = arg; 111 112 i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1)); 113 break; 114 } 115#if 0 116 /* The scaler on this thing seems to be horribly broken */ 117 case DECODER_SET_RESOLUTION: 118 { 119 struct video_decoder_resolution *res = arg; 120 /*int hscale = 256 * 720 / res->width;*/ 121 int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8)); 122 int vscale = 256 * (dec->norm & V4L2_STD_NTSC ? 240 : 288) 123 / res->height; 124 u8 regs[] = { 125 0x0d, vscale & 0xff, 126 0x0f, hscale & 0xff, 127 0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8), 128 0x06, 0xc0, /* reset device */ 129 0, 0, 130 }; 131 printk(KERN_DEBUG "vscale is %04x, hscale is %04x\n", 132 vscale, hscale); 133 /*write_regs(client, regs);*/ 134 break; 135 } 136#endif 137 case VIDIOC_S_STD: 138 { 139 v4l2_std_id *input = arg; 140 u8 regs[] = { 141 0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00, 142 0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12, 143 0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18, 144 0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, 145 0, 0, 146 }; 147 write_regs(client, regs); 148 dec->norm = *input; 149 break; 150 } 151 case VIDIOC_QUERYCTRL: 152 { 153 struct v4l2_queryctrl *ctrl = arg; 154 155 switch (ctrl->id) { 156 case V4L2_CID_BRIGHTNESS: 157 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 158 strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); 159 ctrl->minimum = -128; 160 ctrl->maximum = 127; 161 ctrl->step = 1; 162 ctrl->default_value = 0x00; 163 ctrl->flags = 0; 164 break; 165 case V4L2_CID_CONTRAST: 166 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 167 strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); 168 ctrl->minimum = 0; 169 ctrl->maximum = 255; 170 ctrl->step = 1; 171 ctrl->default_value = 0x60; 172 ctrl->flags = 0; 173 break; 174#if 0 175 /* I don't understand how the Chroma Gain registers work... */ 176 case V4L2_CID_SATURATION: 177 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 178 strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); 179 ctrl->minimum = 0; 180 ctrl->maximum = 127; 181 ctrl->step = 1; 182 ctrl->default_value = 64; 183 ctrl->flags = 0; 184 break; 185#endif 186 case V4L2_CID_HUE: 187 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 188 strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); 189 ctrl->minimum = -128; 190 ctrl->maximum = 127; 191 ctrl->step = 1; 192 ctrl->default_value = 0; 193 ctrl->flags = 0; 194 break; 195 } 196 break; 197 } 198 case VIDIOC_S_CTRL: 199 { 200 struct v4l2_control *ctrl = arg; 201 202 switch (ctrl->id) { 203 case V4L2_CID_BRIGHTNESS: 204 if (ctrl->value > 127) 205 dec->brightness = 127; 206 else if (ctrl->value < -128) 207 dec->brightness = -128; 208 else 209 dec->brightness = ctrl->value; 210 write_reg(client, 0x10, dec->brightness); 211 break; 212 case V4L2_CID_CONTRAST: 213 if (ctrl->value > 255) 214 dec->contrast = 255; 215 else if (ctrl->value < 0) 216 dec->contrast = 0; 217 else 218 dec->contrast = ctrl->value; 219 write_reg(client, 0x11, dec->contrast); 220 break; 221#if 0 222 case V4L2_CID_SATURATION: 223 if (ctrl->value > 127) 224 dec->saturation = 127; 225 else if (ctrl->value < 0) 226 dec->saturation = 0; 227 else 228 dec->saturation = ctrl->value; 229 /*write_reg(client, 0x0c, dec->saturation);*/ 230 break; 231#endif 232 case V4L2_CID_HUE: 233 if (ctrl->value > 127) 234 dec->hue = 127; 235 else if (ctrl->value < -128) 236 dec->hue = -128; 237 else 238 dec->hue = ctrl->value; 239 write_reg(client, 0x15, dec->hue); 240 break; 241 } 242 break; 243 } 244 case VIDIOC_G_CTRL: 245 { 246 struct v4l2_control *ctrl = arg; 247 248 switch (ctrl->id) { 249 case V4L2_CID_BRIGHTNESS: 250 ctrl->value = dec->brightness; 251 break; 252 case V4L2_CID_CONTRAST: 253 ctrl->value = dec->contrast; 254 break; 255#if 0 256 case V4L2_CID_SATURATION: 257 ctrl->value = dec->saturation; 258 break; 259#endif 260 case V4L2_CID_HUE: 261 ctrl->value = dec->hue; 262 break; 263 } 264 break; 265 } 266 default: 267 break; 268 } 269 return 0; 270} 271 272static int wis_tw9903_probe(struct i2c_client *client, 273 const struct i2c_device_id *id) 274{ 275 struct i2c_adapter *adapter = client->adapter; 276 struct wis_tw9903 *dec; 277 278 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 279 return -ENODEV; 280 281 dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL); 282 if (dec == NULL) 283 return -ENOMEM; 284 285 dec->norm = V4L2_STD_NTSC; 286 dec->brightness = 0; 287 dec->contrast = 0x60; 288 dec->hue = 0; 289 i2c_set_clientdata(client, dec); 290 291 printk(KERN_DEBUG 292 "wis-tw9903: initializing TW9903 at address %d on %s\n", 293 client->addr, adapter->name); 294 295 if (write_regs(client, initial_registers) < 0) { 296 printk(KERN_ERR "wis-tw9903: error initializing TW9903\n"); 297 kfree(dec); 298 return -ENODEV; 299 } 300 301 return 0; 302} 303 304static int wis_tw9903_remove(struct i2c_client *client) 305{ 306 struct wis_tw9903 *dec = i2c_get_clientdata(client); 307 308 kfree(dec); 309 return 0; 310} 311 312static const struct i2c_device_id wis_tw9903_id[] = { 313 { "wis_tw9903", 0 }, 314 { } 315}; 316MODULE_DEVICE_TABLE(i2c, wis_tw9903_id); 317 318static struct i2c_driver wis_tw9903_driver = { 319 .driver = { 320 .name = "WIS TW9903 I2C driver", 321 }, 322 .probe = wis_tw9903_probe, 323 .remove = wis_tw9903_remove, 324 .command = wis_tw9903_command, 325 .id_table = wis_tw9903_id, 326}; 327 328static int __init wis_tw9903_init(void) 329{ 330 return i2c_add_driver(&wis_tw9903_driver); 331} 332 333static void __exit wis_tw9903_cleanup(void) 334{ 335 i2c_del_driver(&wis_tw9903_driver); 336} 337 338module_init(wis_tw9903_init); 339module_exit(wis_tw9903_cleanup); 340 341MODULE_LICENSE("GPL v2"); 342