18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bt856 - BT856A Digital Video Encoder (Rockwell Part) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1999 Mike Bernson <mike@mlb.org> 68c2ecf20Sopenharmony_ci * Copyright (C) 1998 Dave Perks <dperks@ibm.net> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Modifications for LML33/DC10plus unified driver 98c2ecf20Sopenharmony_ci * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This code was modify/ported from the saa7111 driver written 128c2ecf20Sopenharmony_ci * by Dave Perks. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net> 158c2ecf20Sopenharmony_ci * - moved over to linux>=2.4.x i2c protocol (9/9/2002) 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/ioctl.h> 228c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 238c2ecf20Sopenharmony_ci#include <linux/i2c.h> 248c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Brooktree-856A video encoder driver"); 288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mike Bernson & Dave Perks"); 298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int debug; 328c2ecf20Sopenharmony_cimodule_param(debug, int, 0); 338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level (0-1)"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define BT856_REG_OFFSET 0xDA 398c2ecf20Sopenharmony_ci#define BT856_NR_REG 6 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct bt856 { 428c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 438c2ecf20Sopenharmony_ci unsigned char reg[BT856_NR_REG]; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci v4l2_std_id norm; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline struct bt856 *to_bt856(struct v4l2_subdev *sd) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return container_of(sd, struct bt856, sd); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci encoder->reg[reg - BT856_REG_OFFSET] = value; 608c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(client, reg, value); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return bt856_write(encoder, reg, 668c2ecf20Sopenharmony_ci (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) | 678c2ecf20Sopenharmony_ci (value ? (1 << bit) : 0)); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void bt856_dump(struct bt856 *encoder) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int i; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci v4l2_info(&encoder->sd, "register dump:\n"); 758c2ecf20Sopenharmony_ci for (i = 0; i < BT856_NR_REG; i += 2) 768c2ecf20Sopenharmony_ci printk(KERN_CONT " %02x", encoder->reg[i]); 778c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int bt856_init(struct v4l2_subdev *sd, u32 arg) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct bt856 *encoder = to_bt856(sd); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* This is just for testing!!! */ 878c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "init\n"); 888c2ecf20Sopenharmony_ci bt856_write(encoder, 0xdc, 0x18); 898c2ecf20Sopenharmony_ci bt856_write(encoder, 0xda, 0); 908c2ecf20Sopenharmony_ci bt856_write(encoder, 0xde, 0); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 3, 1); 938c2ecf20Sopenharmony_ci /*bt856_setbit(encoder, 0xdc, 6, 0);*/ 948c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 4, 1); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (encoder->norm & V4L2_STD_NTSC) 978c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 2, 0); 988c2ecf20Sopenharmony_ci else 998c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 2, 1); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 1, 1); 1028c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 4, 0); 1038c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 3, 1); 1048c2ecf20Sopenharmony_ci if (debug != 0) 1058c2ecf20Sopenharmony_ci bt856_dump(encoder); 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct bt856 *encoder = to_bt856(sd); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (std & V4L2_STD_NTSC) { 1168c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 2, 0); 1178c2ecf20Sopenharmony_ci } else if (std & V4L2_STD_PAL) { 1188c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 2, 1); 1198c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xda, 0, 0); 1208c2ecf20Sopenharmony_ci /*bt856_setbit(encoder, 0xda, 0, 1);*/ 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci encoder->norm = std; 1258c2ecf20Sopenharmony_ci if (debug != 0) 1268c2ecf20Sopenharmony_ci bt856_dump(encoder); 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int bt856_s_routing(struct v4l2_subdev *sd, 1318c2ecf20Sopenharmony_ci u32 input, u32 output, u32 config) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct bt856 *encoder = to_bt856(sd); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "set input %d\n", input); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* We only have video bus. 1388c2ecf20Sopenharmony_ci * input= 0: input is from bt819 1398c2ecf20Sopenharmony_ci * input= 1: input is from ZR36060 */ 1408c2ecf20Sopenharmony_ci switch (input) { 1418c2ecf20Sopenharmony_ci case 0: 1428c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 4, 0); 1438c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 3, 1); 1448c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 3, 1); 1458c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 6, 0); 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case 1: 1488c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 4, 0); 1498c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 3, 1); 1508c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 3, 1); 1518c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 6, 1); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case 2: /* Color bar */ 1548c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 3, 0); 1558c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 4, 1); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (debug != 0) 1628c2ecf20Sopenharmony_ci bt856_dump(encoder); 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops bt856_core_ops = { 1698c2ecf20Sopenharmony_ci .init = bt856_init, 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops bt856_video_ops = { 1738c2ecf20Sopenharmony_ci .s_std_output = bt856_s_std_output, 1748c2ecf20Sopenharmony_ci .s_routing = bt856_s_routing, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops bt856_ops = { 1788c2ecf20Sopenharmony_ci .core = &bt856_core_ops, 1798c2ecf20Sopenharmony_ci .video = &bt856_video_ops, 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int bt856_probe(struct i2c_client *client, 1858c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct bt856 *encoder; 1888c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Check if the adapter supports the needed features */ 1918c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1928c2ecf20Sopenharmony_ci return -ENODEV; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci v4l_info(client, "chip found @ 0x%x (%s)\n", 1958c2ecf20Sopenharmony_ci client->addr << 1, client->adapter->name); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL); 1988c2ecf20Sopenharmony_ci if (encoder == NULL) 1998c2ecf20Sopenharmony_ci return -ENOMEM; 2008c2ecf20Sopenharmony_ci sd = &encoder->sd; 2018c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(sd, client, &bt856_ops); 2028c2ecf20Sopenharmony_ci encoder->norm = V4L2_STD_NTSC; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci bt856_write(encoder, 0xdc, 0x18); 2058c2ecf20Sopenharmony_ci bt856_write(encoder, 0xda, 0); 2068c2ecf20Sopenharmony_ci bt856_write(encoder, 0xde, 0); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 3, 1); 2098c2ecf20Sopenharmony_ci /*bt856_setbit(encoder, 0xdc, 6, 0);*/ 2108c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 4, 1); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (encoder->norm & V4L2_STD_NTSC) 2138c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 2, 0); 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 2, 1); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xdc, 1, 1); 2188c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 4, 0); 2198c2ecf20Sopenharmony_ci bt856_setbit(encoder, 0xde, 3, 1); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (debug != 0) 2228c2ecf20Sopenharmony_ci bt856_dump(encoder); 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int bt856_remove(struct i2c_client *client) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(sd); 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic const struct i2c_device_id bt856_id[] = { 2358c2ecf20Sopenharmony_ci { "bt856", 0 }, 2368c2ecf20Sopenharmony_ci { } 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bt856_id); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic struct i2c_driver bt856_driver = { 2418c2ecf20Sopenharmony_ci .driver = { 2428c2ecf20Sopenharmony_ci .name = "bt856", 2438c2ecf20Sopenharmony_ci }, 2448c2ecf20Sopenharmony_ci .probe = bt856_probe, 2458c2ecf20Sopenharmony_ci .remove = bt856_remove, 2468c2ecf20Sopenharmony_ci .id_table = bt856_id, 2478c2ecf20Sopenharmony_ci}; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cimodule_i2c_driver(bt856_driver); 250