1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * bt856 - BT856A 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 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net> 14cb7a01acSMauro Carvalho Chehab * - moved over to linux>=2.4.x i2c protocol (9/9/2002) 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> 35cb7a01acSMauro Carvalho Chehab #include <asm/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 #include <media/v4l2-chip-ident.h> 40cb7a01acSMauro Carvalho Chehab 41cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Brooktree-856A video encoder driver"); 42cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mike Bernson & Dave Perks"); 43cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 44cb7a01acSMauro Carvalho Chehab 45cb7a01acSMauro Carvalho Chehab static int debug; 46cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0); 47cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)"); 48cb7a01acSMauro Carvalho Chehab 49cb7a01acSMauro Carvalho Chehab 50cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 51cb7a01acSMauro Carvalho Chehab 52cb7a01acSMauro Carvalho Chehab #define BT856_REG_OFFSET 0xDA 53cb7a01acSMauro Carvalho Chehab #define BT856_NR_REG 6 54cb7a01acSMauro Carvalho Chehab 55cb7a01acSMauro Carvalho Chehab struct bt856 { 56cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 57cb7a01acSMauro Carvalho Chehab unsigned char reg[BT856_NR_REG]; 58cb7a01acSMauro Carvalho Chehab 59cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; 60cb7a01acSMauro Carvalho Chehab }; 61cb7a01acSMauro Carvalho Chehab 62cb7a01acSMauro Carvalho Chehab static inline struct bt856 *to_bt856(struct v4l2_subdev *sd) 63cb7a01acSMauro Carvalho Chehab { 64cb7a01acSMauro Carvalho Chehab return container_of(sd, struct bt856, sd); 65cb7a01acSMauro Carvalho Chehab } 66cb7a01acSMauro Carvalho Chehab 67cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 68cb7a01acSMauro Carvalho Chehab 69cb7a01acSMauro Carvalho Chehab static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value) 70cb7a01acSMauro Carvalho Chehab { 71cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); 72cb7a01acSMauro Carvalho Chehab 73cb7a01acSMauro Carvalho Chehab encoder->reg[reg - BT856_REG_OFFSET] = value; 74cb7a01acSMauro Carvalho Chehab return i2c_smbus_write_byte_data(client, reg, value); 75cb7a01acSMauro Carvalho Chehab } 76cb7a01acSMauro Carvalho Chehab 77cb7a01acSMauro Carvalho Chehab static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value) 78cb7a01acSMauro Carvalho Chehab { 79cb7a01acSMauro Carvalho Chehab return bt856_write(encoder, reg, 80cb7a01acSMauro Carvalho Chehab (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) | 81cb7a01acSMauro Carvalho Chehab (value ? (1 << bit) : 0)); 82cb7a01acSMauro Carvalho Chehab } 83cb7a01acSMauro Carvalho Chehab 84cb7a01acSMauro Carvalho Chehab static void bt856_dump(struct bt856 *encoder) 85cb7a01acSMauro Carvalho Chehab { 86cb7a01acSMauro Carvalho Chehab int i; 87cb7a01acSMauro Carvalho Chehab 88cb7a01acSMauro Carvalho Chehab v4l2_info(&encoder->sd, "register dump:\n"); 89cb7a01acSMauro Carvalho Chehab for (i = 0; i < BT856_NR_REG; i += 2) 90cb7a01acSMauro Carvalho Chehab printk(KERN_CONT " %02x", encoder->reg[i]); 91cb7a01acSMauro Carvalho Chehab printk(KERN_CONT "\n"); 92cb7a01acSMauro Carvalho Chehab } 93cb7a01acSMauro Carvalho Chehab 94cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 95cb7a01acSMauro Carvalho Chehab 96cb7a01acSMauro Carvalho Chehab static int bt856_init(struct v4l2_subdev *sd, u32 arg) 97cb7a01acSMauro Carvalho Chehab { 98cb7a01acSMauro Carvalho Chehab struct bt856 *encoder = to_bt856(sd); 99cb7a01acSMauro Carvalho Chehab 100cb7a01acSMauro Carvalho Chehab /* This is just for testing!!! */ 101cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "init\n"); 102cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xdc, 0x18); 103cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xda, 0); 104cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xde, 0); 105cb7a01acSMauro Carvalho Chehab 106cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 107cb7a01acSMauro Carvalho Chehab /*bt856_setbit(encoder, 0xdc, 6, 0);*/ 108cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 4, 1); 109cb7a01acSMauro Carvalho Chehab 110cb7a01acSMauro Carvalho Chehab if (encoder->norm & V4L2_STD_NTSC) 111cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 0); 112cb7a01acSMauro Carvalho Chehab else 113cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 1); 114cb7a01acSMauro Carvalho Chehab 115cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 1, 1); 116cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 117cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 118cb7a01acSMauro Carvalho Chehab if (debug != 0) 119cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 120cb7a01acSMauro Carvalho Chehab return 0; 121cb7a01acSMauro Carvalho Chehab } 122cb7a01acSMauro Carvalho Chehab 123cb7a01acSMauro Carvalho Chehab static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 124cb7a01acSMauro Carvalho Chehab { 125cb7a01acSMauro Carvalho Chehab struct bt856 *encoder = to_bt856(sd); 126cb7a01acSMauro Carvalho Chehab 127cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); 128cb7a01acSMauro Carvalho Chehab 129cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) { 130cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 0); 131cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_PAL) { 132cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 1); 133cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xda, 0, 0); 134cb7a01acSMauro Carvalho Chehab /*bt856_setbit(encoder, 0xda, 0, 1);*/ 135cb7a01acSMauro Carvalho Chehab } else { 136cb7a01acSMauro Carvalho Chehab return -EINVAL; 137cb7a01acSMauro Carvalho Chehab } 138cb7a01acSMauro Carvalho Chehab encoder->norm = std; 139cb7a01acSMauro Carvalho Chehab if (debug != 0) 140cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 141cb7a01acSMauro Carvalho Chehab return 0; 142cb7a01acSMauro Carvalho Chehab } 143cb7a01acSMauro Carvalho Chehab 144cb7a01acSMauro Carvalho Chehab static int bt856_s_routing(struct v4l2_subdev *sd, 145cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 146cb7a01acSMauro Carvalho Chehab { 147cb7a01acSMauro Carvalho Chehab struct bt856 *encoder = to_bt856(sd); 148cb7a01acSMauro Carvalho Chehab 149cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set input %d\n", input); 150cb7a01acSMauro Carvalho Chehab 151cb7a01acSMauro Carvalho Chehab /* We only have video bus. 152cb7a01acSMauro Carvalho Chehab * input= 0: input is from bt819 153cb7a01acSMauro Carvalho Chehab * input= 1: input is from ZR36060 */ 154cb7a01acSMauro Carvalho Chehab switch (input) { 155cb7a01acSMauro Carvalho Chehab case 0: 156cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 157cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 158cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 159cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 6, 0); 160cb7a01acSMauro Carvalho Chehab break; 161cb7a01acSMauro Carvalho Chehab case 1: 162cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 163cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 164cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 165cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 6, 1); 166cb7a01acSMauro Carvalho Chehab break; 167cb7a01acSMauro Carvalho Chehab case 2: /* Color bar */ 168cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 0); 169cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 1); 170cb7a01acSMauro Carvalho Chehab break; 171cb7a01acSMauro Carvalho Chehab default: 172cb7a01acSMauro Carvalho Chehab return -EINVAL; 173cb7a01acSMauro Carvalho Chehab } 174cb7a01acSMauro Carvalho Chehab 175cb7a01acSMauro Carvalho Chehab if (debug != 0) 176cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 177cb7a01acSMauro Carvalho Chehab return 0; 178cb7a01acSMauro Carvalho Chehab } 179cb7a01acSMauro Carvalho Chehab 180cb7a01acSMauro Carvalho Chehab static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) 181cb7a01acSMauro Carvalho Chehab { 182cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd); 183cb7a01acSMauro Carvalho Chehab 184cb7a01acSMauro Carvalho Chehab return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0); 185cb7a01acSMauro Carvalho Chehab } 186cb7a01acSMauro Carvalho Chehab 187cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 188cb7a01acSMauro Carvalho Chehab 189cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops bt856_core_ops = { 190cb7a01acSMauro Carvalho Chehab .g_chip_ident = bt856_g_chip_ident, 191cb7a01acSMauro Carvalho Chehab .init = bt856_init, 192cb7a01acSMauro Carvalho Chehab }; 193cb7a01acSMauro Carvalho Chehab 194cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops bt856_video_ops = { 195cb7a01acSMauro Carvalho Chehab .s_std_output = bt856_s_std_output, 196cb7a01acSMauro Carvalho Chehab .s_routing = bt856_s_routing, 197cb7a01acSMauro Carvalho Chehab }; 198cb7a01acSMauro Carvalho Chehab 199cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops bt856_ops = { 200cb7a01acSMauro Carvalho Chehab .core = &bt856_core_ops, 201cb7a01acSMauro Carvalho Chehab .video = &bt856_video_ops, 202cb7a01acSMauro Carvalho Chehab }; 203cb7a01acSMauro Carvalho Chehab 204cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 205cb7a01acSMauro Carvalho Chehab 206cb7a01acSMauro Carvalho Chehab static int bt856_probe(struct i2c_client *client, 207cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 208cb7a01acSMauro Carvalho Chehab { 209cb7a01acSMauro Carvalho Chehab struct bt856 *encoder; 210cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 211cb7a01acSMauro Carvalho Chehab 212cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 213cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 214cb7a01acSMauro Carvalho Chehab return -ENODEV; 215cb7a01acSMauro Carvalho Chehab 216cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%x (%s)\n", 217cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name); 218cb7a01acSMauro Carvalho Chehab 219cb7a01acSMauro Carvalho Chehab encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL); 220cb7a01acSMauro Carvalho Chehab if (encoder == NULL) 221cb7a01acSMauro Carvalho Chehab return -ENOMEM; 222cb7a01acSMauro Carvalho Chehab sd = &encoder->sd; 223cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &bt856_ops); 224cb7a01acSMauro Carvalho Chehab encoder->norm = V4L2_STD_NTSC; 225cb7a01acSMauro Carvalho Chehab 226cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xdc, 0x18); 227cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xda, 0); 228cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xde, 0); 229cb7a01acSMauro Carvalho Chehab 230cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 231cb7a01acSMauro Carvalho Chehab /*bt856_setbit(encoder, 0xdc, 6, 0);*/ 232cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 4, 1); 233cb7a01acSMauro Carvalho Chehab 234cb7a01acSMauro Carvalho Chehab if (encoder->norm & V4L2_STD_NTSC) 235cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 0); 236cb7a01acSMauro Carvalho Chehab else 237cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 1); 238cb7a01acSMauro Carvalho Chehab 239cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 1, 1); 240cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 241cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 242cb7a01acSMauro Carvalho Chehab 243cb7a01acSMauro Carvalho Chehab if (debug != 0) 244cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 245cb7a01acSMauro Carvalho Chehab return 0; 246cb7a01acSMauro Carvalho Chehab } 247cb7a01acSMauro Carvalho Chehab 248cb7a01acSMauro Carvalho Chehab static int bt856_remove(struct i2c_client *client) 249cb7a01acSMauro Carvalho Chehab { 250cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 251cb7a01acSMauro Carvalho Chehab 252cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd); 253cb7a01acSMauro Carvalho Chehab kfree(to_bt856(sd)); 254cb7a01acSMauro Carvalho Chehab return 0; 255cb7a01acSMauro Carvalho Chehab } 256cb7a01acSMauro Carvalho Chehab 257cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id bt856_id[] = { 258cb7a01acSMauro Carvalho Chehab { "bt856", 0 }, 259cb7a01acSMauro Carvalho Chehab { } 260cb7a01acSMauro Carvalho Chehab }; 261cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, bt856_id); 262cb7a01acSMauro Carvalho Chehab 263cb7a01acSMauro Carvalho Chehab static struct i2c_driver bt856_driver = { 264cb7a01acSMauro Carvalho Chehab .driver = { 265cb7a01acSMauro Carvalho Chehab .owner = THIS_MODULE, 266cb7a01acSMauro Carvalho Chehab .name = "bt856", 267cb7a01acSMauro Carvalho Chehab }, 268cb7a01acSMauro Carvalho Chehab .probe = bt856_probe, 269cb7a01acSMauro Carvalho Chehab .remove = bt856_remove, 270cb7a01acSMauro Carvalho Chehab .id_table = bt856_id, 271cb7a01acSMauro Carvalho Chehab }; 272cb7a01acSMauro Carvalho Chehab 273cb7a01acSMauro Carvalho Chehab module_i2c_driver(bt856_driver); 274