1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2cb7a01acSMauro Carvalho Chehab /* 3cb7a01acSMauro Carvalho Chehab * bt856 - BT856A Digital Video Encoder (Rockwell Part) 4cb7a01acSMauro Carvalho Chehab * 5cb7a01acSMauro Carvalho Chehab * Copyright (C) 1999 Mike Bernson <mike@mlb.org> 6cb7a01acSMauro Carvalho Chehab * Copyright (C) 1998 Dave Perks <dperks@ibm.net> 7cb7a01acSMauro Carvalho Chehab * 8cb7a01acSMauro Carvalho Chehab * Modifications for LML33/DC10plus unified driver 9cb7a01acSMauro Carvalho Chehab * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> 10cb7a01acSMauro Carvalho Chehab * 11cb7a01acSMauro Carvalho Chehab * This code was modify/ported from the saa7111 driver written 12cb7a01acSMauro Carvalho Chehab * by Dave Perks. 13cb7a01acSMauro Carvalho Chehab * 14cb7a01acSMauro Carvalho Chehab * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net> 15cb7a01acSMauro Carvalho Chehab * - moved over to linux>=2.4.x i2c protocol (9/9/2002) 16cb7a01acSMauro Carvalho Chehab */ 17cb7a01acSMauro Carvalho Chehab 18cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 19cb7a01acSMauro Carvalho Chehab #include <linux/types.h> 20cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 21cb7a01acSMauro Carvalho Chehab #include <linux/ioctl.h> 227c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 23cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 24cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 25cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 26cb7a01acSMauro Carvalho Chehab 27cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Brooktree-856A video encoder driver"); 28cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mike Bernson & Dave Perks"); 29cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 30cb7a01acSMauro Carvalho Chehab 31cb7a01acSMauro Carvalho Chehab static int debug; 32cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0); 33cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)"); 34cb7a01acSMauro Carvalho Chehab 35cb7a01acSMauro Carvalho Chehab 36cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 37cb7a01acSMauro Carvalho Chehab 38cb7a01acSMauro Carvalho Chehab #define BT856_REG_OFFSET 0xDA 39cb7a01acSMauro Carvalho Chehab #define BT856_NR_REG 6 40cb7a01acSMauro Carvalho Chehab 41cb7a01acSMauro Carvalho Chehab struct bt856 { 42cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 43cb7a01acSMauro Carvalho Chehab unsigned char reg[BT856_NR_REG]; 44cb7a01acSMauro Carvalho Chehab 45cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; 46cb7a01acSMauro Carvalho Chehab }; 47cb7a01acSMauro Carvalho Chehab 48cb7a01acSMauro Carvalho Chehab static inline struct bt856 *to_bt856(struct v4l2_subdev *sd) 49cb7a01acSMauro Carvalho Chehab { 50cb7a01acSMauro Carvalho Chehab return container_of(sd, struct bt856, sd); 51cb7a01acSMauro Carvalho Chehab } 52cb7a01acSMauro Carvalho Chehab 53cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 54cb7a01acSMauro Carvalho Chehab 55cb7a01acSMauro Carvalho Chehab static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value) 56cb7a01acSMauro Carvalho Chehab { 57cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); 58cb7a01acSMauro Carvalho Chehab 59cb7a01acSMauro Carvalho Chehab encoder->reg[reg - BT856_REG_OFFSET] = value; 60cb7a01acSMauro Carvalho Chehab return i2c_smbus_write_byte_data(client, reg, value); 61cb7a01acSMauro Carvalho Chehab } 62cb7a01acSMauro Carvalho Chehab 63cb7a01acSMauro Carvalho Chehab static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value) 64cb7a01acSMauro Carvalho Chehab { 65cb7a01acSMauro Carvalho Chehab return bt856_write(encoder, reg, 66cb7a01acSMauro Carvalho Chehab (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) | 67cb7a01acSMauro Carvalho Chehab (value ? (1 << bit) : 0)); 68cb7a01acSMauro Carvalho Chehab } 69cb7a01acSMauro Carvalho Chehab 70cb7a01acSMauro Carvalho Chehab static void bt856_dump(struct bt856 *encoder) 71cb7a01acSMauro Carvalho Chehab { 72cb7a01acSMauro Carvalho Chehab int i; 73cb7a01acSMauro Carvalho Chehab 74cb7a01acSMauro Carvalho Chehab v4l2_info(&encoder->sd, "register dump:\n"); 75cb7a01acSMauro Carvalho Chehab for (i = 0; i < BT856_NR_REG; i += 2) 76cb7a01acSMauro Carvalho Chehab printk(KERN_CONT " %02x", encoder->reg[i]); 77cb7a01acSMauro Carvalho Chehab printk(KERN_CONT "\n"); 78cb7a01acSMauro Carvalho Chehab } 79cb7a01acSMauro Carvalho Chehab 80cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 81cb7a01acSMauro Carvalho Chehab 82cb7a01acSMauro Carvalho Chehab static int bt856_init(struct v4l2_subdev *sd, u32 arg) 83cb7a01acSMauro Carvalho Chehab { 84cb7a01acSMauro Carvalho Chehab struct bt856 *encoder = to_bt856(sd); 85cb7a01acSMauro Carvalho Chehab 86cb7a01acSMauro Carvalho Chehab /* This is just for testing!!! */ 87cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "init\n"); 88cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xdc, 0x18); 89cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xda, 0); 90cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xde, 0); 91cb7a01acSMauro Carvalho Chehab 92cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 93cb7a01acSMauro Carvalho Chehab /*bt856_setbit(encoder, 0xdc, 6, 0);*/ 94cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 4, 1); 95cb7a01acSMauro Carvalho Chehab 96cb7a01acSMauro Carvalho Chehab if (encoder->norm & V4L2_STD_NTSC) 97cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 0); 98cb7a01acSMauro Carvalho Chehab else 99cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 1); 100cb7a01acSMauro Carvalho Chehab 101cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 1, 1); 102cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 103cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 104cb7a01acSMauro Carvalho Chehab if (debug != 0) 105cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 106cb7a01acSMauro Carvalho Chehab return 0; 107cb7a01acSMauro Carvalho Chehab } 108cb7a01acSMauro Carvalho Chehab 109cb7a01acSMauro Carvalho Chehab static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 110cb7a01acSMauro Carvalho Chehab { 111cb7a01acSMauro Carvalho Chehab struct bt856 *encoder = to_bt856(sd); 112cb7a01acSMauro Carvalho Chehab 113cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); 114cb7a01acSMauro Carvalho Chehab 115cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) { 116cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 0); 117cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_PAL) { 118cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 1); 119cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xda, 0, 0); 120cb7a01acSMauro Carvalho Chehab /*bt856_setbit(encoder, 0xda, 0, 1);*/ 121cb7a01acSMauro Carvalho Chehab } else { 122cb7a01acSMauro Carvalho Chehab return -EINVAL; 123cb7a01acSMauro Carvalho Chehab } 124cb7a01acSMauro Carvalho Chehab encoder->norm = std; 125cb7a01acSMauro Carvalho Chehab if (debug != 0) 126cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 127cb7a01acSMauro Carvalho Chehab return 0; 128cb7a01acSMauro Carvalho Chehab } 129cb7a01acSMauro Carvalho Chehab 130cb7a01acSMauro Carvalho Chehab static int bt856_s_routing(struct v4l2_subdev *sd, 131cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 132cb7a01acSMauro Carvalho Chehab { 133cb7a01acSMauro Carvalho Chehab struct bt856 *encoder = to_bt856(sd); 134cb7a01acSMauro Carvalho Chehab 135cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set input %d\n", input); 136cb7a01acSMauro Carvalho Chehab 137cb7a01acSMauro Carvalho Chehab /* We only have video bus. 138cb7a01acSMauro Carvalho Chehab * input= 0: input is from bt819 139cb7a01acSMauro Carvalho Chehab * input= 1: input is from ZR36060 */ 140cb7a01acSMauro Carvalho Chehab switch (input) { 141cb7a01acSMauro Carvalho Chehab case 0: 142cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 143cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 144cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 145cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 6, 0); 146cb7a01acSMauro Carvalho Chehab break; 147cb7a01acSMauro Carvalho Chehab case 1: 148cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 149cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 150cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 151cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 6, 1); 152cb7a01acSMauro Carvalho Chehab break; 153cb7a01acSMauro Carvalho Chehab case 2: /* Color bar */ 154cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 0); 155cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 1); 156cb7a01acSMauro Carvalho Chehab break; 157cb7a01acSMauro Carvalho Chehab default: 158cb7a01acSMauro Carvalho Chehab return -EINVAL; 159cb7a01acSMauro Carvalho Chehab } 160cb7a01acSMauro Carvalho Chehab 161cb7a01acSMauro Carvalho Chehab if (debug != 0) 162cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 163cb7a01acSMauro Carvalho Chehab return 0; 164cb7a01acSMauro Carvalho Chehab } 165cb7a01acSMauro Carvalho Chehab 166cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 167cb7a01acSMauro Carvalho Chehab 168cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops bt856_core_ops = { 169cb7a01acSMauro Carvalho Chehab .init = bt856_init, 170cb7a01acSMauro Carvalho Chehab }; 171cb7a01acSMauro Carvalho Chehab 172cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops bt856_video_ops = { 173cb7a01acSMauro Carvalho Chehab .s_std_output = bt856_s_std_output, 174cb7a01acSMauro Carvalho Chehab .s_routing = bt856_s_routing, 175cb7a01acSMauro Carvalho Chehab }; 176cb7a01acSMauro Carvalho Chehab 177cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops bt856_ops = { 178cb7a01acSMauro Carvalho Chehab .core = &bt856_core_ops, 179cb7a01acSMauro Carvalho Chehab .video = &bt856_video_ops, 180cb7a01acSMauro Carvalho Chehab }; 181cb7a01acSMauro Carvalho Chehab 182cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 183cb7a01acSMauro Carvalho Chehab 184b1995c56SUwe Kleine-König static int bt856_probe(struct i2c_client *client) 185cb7a01acSMauro Carvalho Chehab { 186cb7a01acSMauro Carvalho Chehab struct bt856 *encoder; 187cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 188cb7a01acSMauro Carvalho Chehab 189cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 190cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 191cb7a01acSMauro Carvalho Chehab return -ENODEV; 192cb7a01acSMauro Carvalho Chehab 193cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%x (%s)\n", 194cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name); 195cb7a01acSMauro Carvalho Chehab 196c02b211dSLaurent Pinchart encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL); 197cb7a01acSMauro Carvalho Chehab if (encoder == NULL) 198cb7a01acSMauro Carvalho Chehab return -ENOMEM; 199cb7a01acSMauro Carvalho Chehab sd = &encoder->sd; 200cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &bt856_ops); 201cb7a01acSMauro Carvalho Chehab encoder->norm = V4L2_STD_NTSC; 202cb7a01acSMauro Carvalho Chehab 203cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xdc, 0x18); 204cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xda, 0); 205cb7a01acSMauro Carvalho Chehab bt856_write(encoder, 0xde, 0); 206cb7a01acSMauro Carvalho Chehab 207cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 3, 1); 208cb7a01acSMauro Carvalho Chehab /*bt856_setbit(encoder, 0xdc, 6, 0);*/ 209cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 4, 1); 210cb7a01acSMauro Carvalho Chehab 211cb7a01acSMauro Carvalho Chehab if (encoder->norm & V4L2_STD_NTSC) 212cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 0); 213cb7a01acSMauro Carvalho Chehab else 214cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 2, 1); 215cb7a01acSMauro Carvalho Chehab 216cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xdc, 1, 1); 217cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 4, 0); 218cb7a01acSMauro Carvalho Chehab bt856_setbit(encoder, 0xde, 3, 1); 219cb7a01acSMauro Carvalho Chehab 220cb7a01acSMauro Carvalho Chehab if (debug != 0) 221cb7a01acSMauro Carvalho Chehab bt856_dump(encoder); 222cb7a01acSMauro Carvalho Chehab return 0; 223cb7a01acSMauro Carvalho Chehab } 224cb7a01acSMauro Carvalho Chehab 225ed5c2f5fSUwe Kleine-König static void bt856_remove(struct i2c_client *client) 226cb7a01acSMauro Carvalho Chehab { 227cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 228cb7a01acSMauro Carvalho Chehab 229cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd); 230cb7a01acSMauro Carvalho Chehab } 231cb7a01acSMauro Carvalho Chehab 232cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id bt856_id[] = { 233cb7a01acSMauro Carvalho Chehab { "bt856", 0 }, 234cb7a01acSMauro Carvalho Chehab { } 235cb7a01acSMauro Carvalho Chehab }; 236cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, bt856_id); 237cb7a01acSMauro Carvalho Chehab 238cb7a01acSMauro Carvalho Chehab static struct i2c_driver bt856_driver = { 239cb7a01acSMauro Carvalho Chehab .driver = { 240cb7a01acSMauro Carvalho Chehab .name = "bt856", 241cb7a01acSMauro Carvalho Chehab }, 242*aaeb31c0SUwe Kleine-König .probe = bt856_probe, 243cb7a01acSMauro Carvalho Chehab .remove = bt856_remove, 244cb7a01acSMauro Carvalho Chehab .id_table = bt856_id, 245cb7a01acSMauro Carvalho Chehab }; 246cb7a01acSMauro Carvalho Chehab 247cb7a01acSMauro Carvalho Chehab module_i2c_driver(bt856_driver); 248