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 case VIDIOC_S_STD: 116 { 117 v4l2_std_id *input = arg; 118 u8 regs[] = { 119 0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00, 120 0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12, 121 0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18, 122 0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, 123 0, 0, 124 }; 125 write_regs(client, regs); 126 dec->norm = *input; 127 break; 128 } 129 case VIDIOC_QUERYCTRL: 130 { 131 struct v4l2_queryctrl *ctrl = arg; 132 133 switch (ctrl->id) { 134 case V4L2_CID_BRIGHTNESS: 135 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 136 strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); 137 ctrl->minimum = -128; 138 ctrl->maximum = 127; 139 ctrl->step = 1; 140 ctrl->default_value = 0x00; 141 ctrl->flags = 0; 142 break; 143 case V4L2_CID_CONTRAST: 144 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 145 strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); 146 ctrl->minimum = 0; 147 ctrl->maximum = 255; 148 ctrl->step = 1; 149 ctrl->default_value = 0x60; 150 ctrl->flags = 0; 151 break; 152 case V4L2_CID_HUE: 153 ctrl->type = V4L2_CTRL_TYPE_INTEGER; 154 strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); 155 ctrl->minimum = -128; 156 ctrl->maximum = 127; 157 ctrl->step = 1; 158 ctrl->default_value = 0; 159 ctrl->flags = 0; 160 break; 161 } 162 break; 163 } 164 case VIDIOC_S_CTRL: 165 { 166 struct v4l2_control *ctrl = arg; 167 168 switch (ctrl->id) { 169 case V4L2_CID_BRIGHTNESS: 170 if (ctrl->value > 127) 171 dec->brightness = 127; 172 else if (ctrl->value < -128) 173 dec->brightness = -128; 174 else 175 dec->brightness = ctrl->value; 176 write_reg(client, 0x10, dec->brightness); 177 break; 178 case V4L2_CID_CONTRAST: 179 if (ctrl->value > 255) 180 dec->contrast = 255; 181 else if (ctrl->value < 0) 182 dec->contrast = 0; 183 else 184 dec->contrast = ctrl->value; 185 write_reg(client, 0x11, dec->contrast); 186 break; 187 case V4L2_CID_HUE: 188 if (ctrl->value > 127) 189 dec->hue = 127; 190 else if (ctrl->value < -128) 191 dec->hue = -128; 192 else 193 dec->hue = ctrl->value; 194 write_reg(client, 0x15, dec->hue); 195 break; 196 } 197 break; 198 } 199 case VIDIOC_G_CTRL: 200 { 201 struct v4l2_control *ctrl = arg; 202 203 switch (ctrl->id) { 204 case V4L2_CID_BRIGHTNESS: 205 ctrl->value = dec->brightness; 206 break; 207 case V4L2_CID_CONTRAST: 208 ctrl->value = dec->contrast; 209 break; 210 case V4L2_CID_HUE: 211 ctrl->value = dec->hue; 212 break; 213 } 214 break; 215 } 216 default: 217 break; 218 } 219 return 0; 220} 221 222static int wis_tw9903_probe(struct i2c_client *client, 223 const struct i2c_device_id *id) 224{ 225 struct i2c_adapter *adapter = client->adapter; 226 struct wis_tw9903 *dec; 227 228 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 229 return -ENODEV; 230 231 dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL); 232 if (dec == NULL) 233 return -ENOMEM; 234 235 dec->norm = V4L2_STD_NTSC; 236 dec->brightness = 0; 237 dec->contrast = 0x60; 238 dec->hue = 0; 239 i2c_set_clientdata(client, dec); 240 241 printk(KERN_DEBUG 242 "wis-tw9903: initializing TW9903 at address %d on %s\n", 243 client->addr, adapter->name); 244 245 if (write_regs(client, initial_registers) < 0) { 246 printk(KERN_ERR "wis-tw9903: error initializing TW9903\n"); 247 kfree(dec); 248 return -ENODEV; 249 } 250 251 return 0; 252} 253 254static int wis_tw9903_remove(struct i2c_client *client) 255{ 256 struct wis_tw9903 *dec = i2c_get_clientdata(client); 257 258 kfree(dec); 259 return 0; 260} 261 262static const struct i2c_device_id wis_tw9903_id[] = { 263 { "wis_tw9903", 0 }, 264 { } 265}; 266 267static struct i2c_driver wis_tw9903_driver = { 268 .driver = { 269 .name = "WIS TW9903 I2C driver", 270 }, 271 .probe = wis_tw9903_probe, 272 .remove = wis_tw9903_remove, 273 .command = wis_tw9903_command, 274 .id_table = wis_tw9903_id, 275}; 276 277static int __init wis_tw9903_init(void) 278{ 279 return i2c_add_driver(&wis_tw9903_driver); 280} 281 282static void __exit wis_tw9903_cleanup(void) 283{ 284 i2c_del_driver(&wis_tw9903_driver); 285} 286 287module_init(wis_tw9903_init); 288module_exit(wis_tw9903_cleanup); 289 290MODULE_LICENSE("GPL v2"); 291