1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab bt866 - BT866 Digital Video Encoder (Rockwell Part) 3cb7a01acSMauro Carvalho Chehab 4cb7a01acSMauro Carvalho Chehab Copyright (C) 1999 Mike Bernson <mike@mlb.org> 5cb7a01acSMauro Carvalho Chehab Copyright (C) 1998 Dave Perks <dperks@ibm.net> 6cb7a01acSMauro Carvalho Chehab 7cb7a01acSMauro Carvalho Chehab Modifications for LML33/DC10plus unified driver 8cb7a01acSMauro Carvalho Chehab Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> 9cb7a01acSMauro Carvalho Chehab 10cb7a01acSMauro Carvalho Chehab This code was modify/ported from the saa7111 driver written 11cb7a01acSMauro Carvalho Chehab by Dave Perks. 12cb7a01acSMauro Carvalho Chehab 13cb7a01acSMauro Carvalho Chehab This code was adapted for the bt866 by Christer Weinigel and ported 14cb7a01acSMauro Carvalho Chehab to 2.6 by Martin Samuelsson. 15cb7a01acSMauro Carvalho Chehab 16cb7a01acSMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 17cb7a01acSMauro Carvalho Chehab it under the terms of the GNU General Public License as published by 18cb7a01acSMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 19cb7a01acSMauro Carvalho Chehab (at your option) any later version. 20cb7a01acSMauro Carvalho Chehab 21cb7a01acSMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 22cb7a01acSMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 23cb7a01acSMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24cb7a01acSMauro Carvalho Chehab GNU General Public License for more details. 25cb7a01acSMauro Carvalho Chehab 26cb7a01acSMauro Carvalho Chehab You should have received a copy of the GNU General Public License 27cb7a01acSMauro Carvalho Chehab along with this program; if not, write to the Free Software 28cb7a01acSMauro Carvalho Chehab Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 29cb7a01acSMauro Carvalho Chehab */ 30cb7a01acSMauro Carvalho Chehab 31cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 32cb7a01acSMauro Carvalho Chehab #include <linux/types.h> 33cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 34cb7a01acSMauro Carvalho Chehab #include <linux/ioctl.h> 35*7c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 36cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 37cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 38cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 39cb7a01acSMauro Carvalho Chehab 40cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Brooktree-866 video encoder driver"); 41cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mike Bernson & Dave Perks"); 42cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 43cb7a01acSMauro Carvalho Chehab 44cb7a01acSMauro Carvalho Chehab static int debug; 45cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0); 46cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)"); 47cb7a01acSMauro Carvalho Chehab 48cb7a01acSMauro Carvalho Chehab 49cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 50cb7a01acSMauro Carvalho Chehab 51cb7a01acSMauro Carvalho Chehab struct bt866 { 52cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 53cb7a01acSMauro Carvalho Chehab u8 reg[256]; 54cb7a01acSMauro Carvalho Chehab }; 55cb7a01acSMauro Carvalho Chehab 56cb7a01acSMauro Carvalho Chehab static inline struct bt866 *to_bt866(struct v4l2_subdev *sd) 57cb7a01acSMauro Carvalho Chehab { 58cb7a01acSMauro Carvalho Chehab return container_of(sd, struct bt866, sd); 59cb7a01acSMauro Carvalho Chehab } 60cb7a01acSMauro Carvalho Chehab 61cb7a01acSMauro Carvalho Chehab static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data) 62cb7a01acSMauro Carvalho Chehab { 63cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); 64cb7a01acSMauro Carvalho Chehab u8 buffer[2]; 65cb7a01acSMauro Carvalho Chehab int err; 66cb7a01acSMauro Carvalho Chehab 67cb7a01acSMauro Carvalho Chehab buffer[0] = subaddr; 68cb7a01acSMauro Carvalho Chehab buffer[1] = data; 69cb7a01acSMauro Carvalho Chehab 70cb7a01acSMauro Carvalho Chehab encoder->reg[subaddr] = data; 71cb7a01acSMauro Carvalho Chehab 72cb7a01acSMauro Carvalho Chehab v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data); 73cb7a01acSMauro Carvalho Chehab 74cb7a01acSMauro Carvalho Chehab for (err = 0; err < 3;) { 75cb7a01acSMauro Carvalho Chehab if (i2c_master_send(client, buffer, 2) == 2) 76cb7a01acSMauro Carvalho Chehab break; 77cb7a01acSMauro Carvalho Chehab err++; 78cb7a01acSMauro Carvalho Chehab v4l_warn(client, "error #%d writing to 0x%02x\n", 79cb7a01acSMauro Carvalho Chehab err, subaddr); 80cb7a01acSMauro Carvalho Chehab schedule_timeout_interruptible(msecs_to_jiffies(100)); 81cb7a01acSMauro Carvalho Chehab } 82cb7a01acSMauro Carvalho Chehab if (err == 3) { 83cb7a01acSMauro Carvalho Chehab v4l_warn(client, "giving up\n"); 84cb7a01acSMauro Carvalho Chehab return -1; 85cb7a01acSMauro Carvalho Chehab } 86cb7a01acSMauro Carvalho Chehab 87cb7a01acSMauro Carvalho Chehab return 0; 88cb7a01acSMauro Carvalho Chehab } 89cb7a01acSMauro Carvalho Chehab 90cb7a01acSMauro Carvalho Chehab static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 91cb7a01acSMauro Carvalho Chehab { 92cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); 93cb7a01acSMauro Carvalho Chehab 94cb7a01acSMauro Carvalho Chehab /* Only PAL supported by this driver at the moment! */ 95cb7a01acSMauro Carvalho Chehab if (!(std & V4L2_STD_NTSC)) 96cb7a01acSMauro Carvalho Chehab return -EINVAL; 97cb7a01acSMauro Carvalho Chehab return 0; 98cb7a01acSMauro Carvalho Chehab } 99cb7a01acSMauro Carvalho Chehab 100cb7a01acSMauro Carvalho Chehab static int bt866_s_routing(struct v4l2_subdev *sd, 101cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 102cb7a01acSMauro Carvalho Chehab { 103cb7a01acSMauro Carvalho Chehab static const __u8 init[] = { 104cb7a01acSMauro Carvalho Chehab 0xc8, 0xcc, /* CRSCALE */ 105cb7a01acSMauro Carvalho Chehab 0xca, 0x91, /* CBSCALE */ 106cb7a01acSMauro Carvalho Chehab 0xcc, 0x24, /* YC16 | OSDNUM */ 107cb7a01acSMauro Carvalho Chehab 0xda, 0x00, /* */ 108cb7a01acSMauro Carvalho Chehab 0xdc, 0x24, /* SETMODE | PAL */ 109cb7a01acSMauro Carvalho Chehab 0xde, 0x02, /* EACTIVE */ 110cb7a01acSMauro Carvalho Chehab 111cb7a01acSMauro Carvalho Chehab /* overlay colors */ 112cb7a01acSMauro Carvalho Chehab 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */ 113cb7a01acSMauro Carvalho Chehab 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */ 114cb7a01acSMauro Carvalho Chehab 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */ 115cb7a01acSMauro Carvalho Chehab 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */ 116cb7a01acSMauro Carvalho Chehab 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */ 117cb7a01acSMauro Carvalho Chehab 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */ 118cb7a01acSMauro Carvalho Chehab 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */ 119cb7a01acSMauro Carvalho Chehab 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */ 120cb7a01acSMauro Carvalho Chehab 121cb7a01acSMauro Carvalho Chehab 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */ 122cb7a01acSMauro Carvalho Chehab 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */ 123cb7a01acSMauro Carvalho Chehab 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */ 124cb7a01acSMauro Carvalho Chehab 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */ 125cb7a01acSMauro Carvalho Chehab 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */ 126cb7a01acSMauro Carvalho Chehab 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */ 127cb7a01acSMauro Carvalho Chehab 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */ 128cb7a01acSMauro Carvalho Chehab 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */ 129cb7a01acSMauro Carvalho Chehab }; 130cb7a01acSMauro Carvalho Chehab struct bt866 *encoder = to_bt866(sd); 131cb7a01acSMauro Carvalho Chehab u8 val; 132cb7a01acSMauro Carvalho Chehab int i; 133cb7a01acSMauro Carvalho Chehab 134cb7a01acSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2) 135cb7a01acSMauro Carvalho Chehab bt866_write(encoder, init[i], init[i+1]); 136cb7a01acSMauro Carvalho Chehab 137cb7a01acSMauro Carvalho Chehab val = encoder->reg[0xdc]; 138cb7a01acSMauro Carvalho Chehab 139cb7a01acSMauro Carvalho Chehab if (input == 0) 140cb7a01acSMauro Carvalho Chehab val |= 0x40; /* CBSWAP */ 141cb7a01acSMauro Carvalho Chehab else 142cb7a01acSMauro Carvalho Chehab val &= ~0x40; /* !CBSWAP */ 143cb7a01acSMauro Carvalho Chehab 144cb7a01acSMauro Carvalho Chehab bt866_write(encoder, 0xdc, val); 145cb7a01acSMauro Carvalho Chehab 146cb7a01acSMauro Carvalho Chehab val = encoder->reg[0xcc]; 147cb7a01acSMauro Carvalho Chehab if (input == 2) 148cb7a01acSMauro Carvalho Chehab val |= 0x01; /* OSDBAR */ 149cb7a01acSMauro Carvalho Chehab else 150cb7a01acSMauro Carvalho Chehab val &= ~0x01; /* !OSDBAR */ 151cb7a01acSMauro Carvalho Chehab bt866_write(encoder, 0xcc, val); 152cb7a01acSMauro Carvalho Chehab 153cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set input %d\n", input); 154cb7a01acSMauro Carvalho Chehab 155cb7a01acSMauro Carvalho Chehab switch (input) { 156cb7a01acSMauro Carvalho Chehab case 0: 157cb7a01acSMauro Carvalho Chehab case 1: 158cb7a01acSMauro Carvalho Chehab case 2: 159cb7a01acSMauro Carvalho Chehab break; 160cb7a01acSMauro Carvalho Chehab default: 161cb7a01acSMauro Carvalho Chehab return -EINVAL; 162cb7a01acSMauro Carvalho Chehab } 163cb7a01acSMauro Carvalho Chehab return 0; 164cb7a01acSMauro Carvalho Chehab } 165cb7a01acSMauro Carvalho Chehab 166cb7a01acSMauro Carvalho Chehab #if 0 167cb7a01acSMauro Carvalho Chehab /* Code to setup square pixels, might be of some use in the future, 168cb7a01acSMauro Carvalho Chehab but is currently unused. */ 169cb7a01acSMauro Carvalho Chehab val = encoder->reg[0xdc]; 170cb7a01acSMauro Carvalho Chehab if (*iarg) 171cb7a01acSMauro Carvalho Chehab val |= 1; /* SQUARE */ 172cb7a01acSMauro Carvalho Chehab else 173cb7a01acSMauro Carvalho Chehab val &= ~1; /* !SQUARE */ 174cb7a01acSMauro Carvalho Chehab bt866_write(client, 0xdc, val); 175cb7a01acSMauro Carvalho Chehab #endif 176cb7a01acSMauro Carvalho Chehab 177cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 178cb7a01acSMauro Carvalho Chehab 179cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops bt866_video_ops = { 180cb7a01acSMauro Carvalho Chehab .s_std_output = bt866_s_std_output, 181cb7a01acSMauro Carvalho Chehab .s_routing = bt866_s_routing, 182cb7a01acSMauro Carvalho Chehab }; 183cb7a01acSMauro Carvalho Chehab 184cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops bt866_ops = { 185cb7a01acSMauro Carvalho Chehab .video = &bt866_video_ops, 186cb7a01acSMauro Carvalho Chehab }; 187cb7a01acSMauro Carvalho Chehab 188cb7a01acSMauro Carvalho Chehab static int bt866_probe(struct i2c_client *client, 189cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 190cb7a01acSMauro Carvalho Chehab { 191cb7a01acSMauro Carvalho Chehab struct bt866 *encoder; 192cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 193cb7a01acSMauro Carvalho Chehab 194cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%x (%s)\n", 195cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name); 196cb7a01acSMauro Carvalho Chehab 197c02b211dSLaurent Pinchart encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL); 198cb7a01acSMauro Carvalho Chehab if (encoder == NULL) 199cb7a01acSMauro Carvalho Chehab return -ENOMEM; 200cb7a01acSMauro Carvalho Chehab sd = &encoder->sd; 201cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &bt866_ops); 202cb7a01acSMauro Carvalho Chehab return 0; 203cb7a01acSMauro Carvalho Chehab } 204cb7a01acSMauro Carvalho Chehab 205cb7a01acSMauro Carvalho Chehab static int bt866_remove(struct i2c_client *client) 206cb7a01acSMauro Carvalho Chehab { 207cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 208cb7a01acSMauro Carvalho Chehab 209cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd); 210cb7a01acSMauro Carvalho Chehab return 0; 211cb7a01acSMauro Carvalho Chehab } 212cb7a01acSMauro Carvalho Chehab 213cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id bt866_id[] = { 214cb7a01acSMauro Carvalho Chehab { "bt866", 0 }, 215cb7a01acSMauro Carvalho Chehab { } 216cb7a01acSMauro Carvalho Chehab }; 217cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, bt866_id); 218cb7a01acSMauro Carvalho Chehab 219cb7a01acSMauro Carvalho Chehab static struct i2c_driver bt866_driver = { 220cb7a01acSMauro Carvalho Chehab .driver = { 221cb7a01acSMauro Carvalho Chehab .name = "bt866", 222cb7a01acSMauro Carvalho Chehab }, 223cb7a01acSMauro Carvalho Chehab .probe = bt866_probe, 224cb7a01acSMauro Carvalho Chehab .remove = bt866_remove, 225cb7a01acSMauro Carvalho Chehab .id_table = bt866_id, 226cb7a01acSMauro Carvalho Chehab }; 227cb7a01acSMauro Carvalho Chehab 228cb7a01acSMauro Carvalho Chehab module_i2c_driver(bt866_driver); 229