18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bt819 - BT819A VideoStream Decoder (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 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net> 128c2ecf20Sopenharmony_ci * - moved over to linux>=2.4.x i2c protocol (9/9/2002) 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This code was modify/ported from the saa7111 driver written 158c2ecf20Sopenharmony_ci * by Dave Perks. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/ioctl.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/i2c.h> 238c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 268c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 278c2ecf20Sopenharmony_ci#include <media/i2c/bt819.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Brooktree-819 video decoder driver"); 308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mike Bernson & Dave Perks"); 318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int debug; 348c2ecf20Sopenharmony_cimodule_param(debug, int, 0); 358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level (0-1)"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct bt819 { 418c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 428c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler hdl; 438c2ecf20Sopenharmony_ci unsigned char reg[32]; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci v4l2_std_id norm; 468c2ecf20Sopenharmony_ci int input; 478c2ecf20Sopenharmony_ci int enable; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline struct bt819 *to_bt819(struct v4l2_subdev *sd) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return container_of(sd, struct bt819, sd); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci return &container_of(ctrl->handler, struct bt819, hdl)->sd; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct timing { 618c2ecf20Sopenharmony_ci int hactive; 628c2ecf20Sopenharmony_ci int hdelay; 638c2ecf20Sopenharmony_ci int vactive; 648c2ecf20Sopenharmony_ci int vdelay; 658c2ecf20Sopenharmony_ci int hscale; 668c2ecf20Sopenharmony_ci int vscale; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* for values, see the bt819 datasheet */ 708c2ecf20Sopenharmony_cistatic struct timing timing_data[] = { 718c2ecf20Sopenharmony_ci {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000}, 728c2ecf20Sopenharmony_ci {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000}, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci decoder->reg[reg] = value; 828c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(client, reg, value); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return bt819_write(decoder, reg, 888c2ecf20Sopenharmony_ci (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0)); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); 948c2ecf20Sopenharmony_ci int ret = -1; 958c2ecf20Sopenharmony_ci u8 reg; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* the bt819 has an autoincrement function, use it if 988c2ecf20Sopenharmony_ci * the adapter understands raw I2C */ 998c2ecf20Sopenharmony_ci if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 1008c2ecf20Sopenharmony_ci /* do raw I2C, not smbus compatible */ 1018c2ecf20Sopenharmony_ci u8 block_data[32]; 1028c2ecf20Sopenharmony_ci int block_len; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci while (len >= 2) { 1058c2ecf20Sopenharmony_ci block_len = 0; 1068c2ecf20Sopenharmony_ci block_data[block_len++] = reg = data[0]; 1078c2ecf20Sopenharmony_ci do { 1088c2ecf20Sopenharmony_ci block_data[block_len++] = 1098c2ecf20Sopenharmony_ci decoder->reg[reg++] = data[1]; 1108c2ecf20Sopenharmony_ci len -= 2; 1118c2ecf20Sopenharmony_ci data += 2; 1128c2ecf20Sopenharmony_ci } while (len >= 2 && data[0] == reg && block_len < 32); 1138c2ecf20Sopenharmony_ci ret = i2c_master_send(client, block_data, block_len); 1148c2ecf20Sopenharmony_ci if (ret < 0) 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } else { 1188c2ecf20Sopenharmony_ci /* do some slow I2C emulation kind of thing */ 1198c2ecf20Sopenharmony_ci while (len >= 2) { 1208c2ecf20Sopenharmony_ci reg = *data++; 1218c2ecf20Sopenharmony_ci ret = bt819_write(decoder, reg, *data++); 1228c2ecf20Sopenharmony_ci if (ret < 0) 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci len -= 2; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return ret; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline int bt819_read(struct bt819 *decoder, u8 reg) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return i2c_smbus_read_byte_data(client, reg); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int bt819_init(struct v4l2_subdev *sd) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci static unsigned char init[] = { 1418c2ecf20Sopenharmony_ci /*0x1f, 0x00,*/ /* Reset */ 1428c2ecf20Sopenharmony_ci 0x01, 0x59, /* 0x01 input format */ 1438c2ecf20Sopenharmony_ci 0x02, 0x00, /* 0x02 temporal decimation */ 1448c2ecf20Sopenharmony_ci 0x03, 0x12, /* 0x03 Cropping msb */ 1458c2ecf20Sopenharmony_ci 0x04, 0x16, /* 0x04 Vertical Delay, lsb */ 1468c2ecf20Sopenharmony_ci 0x05, 0xe0, /* 0x05 Vertical Active lsb */ 1478c2ecf20Sopenharmony_ci 0x06, 0x80, /* 0x06 Horizontal Delay lsb */ 1488c2ecf20Sopenharmony_ci 0x07, 0xd0, /* 0x07 Horizontal Active lsb */ 1498c2ecf20Sopenharmony_ci 0x08, 0x00, /* 0x08 Horizontal Scaling msb */ 1508c2ecf20Sopenharmony_ci 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */ 1518c2ecf20Sopenharmony_ci 0x0a, 0x00, /* 0x0a Brightness control */ 1528c2ecf20Sopenharmony_ci 0x0b, 0x30, /* 0x0b Miscellaneous control */ 1538c2ecf20Sopenharmony_ci 0x0c, 0xd8, /* 0x0c Luma Gain lsb */ 1548c2ecf20Sopenharmony_ci 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */ 1558c2ecf20Sopenharmony_ci 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */ 1568c2ecf20Sopenharmony_ci 0x0f, 0x00, /* 0x0f Hue control */ 1578c2ecf20Sopenharmony_ci 0x12, 0x04, /* 0x12 Output Format */ 1588c2ecf20Sopenharmony_ci 0x13, 0x20, /* 0x13 Vertical Scaling msb 0x00 1598c2ecf20Sopenharmony_ci chroma comb OFF, line drop scaling, interlace scaling 1608c2ecf20Sopenharmony_ci BUG? Why does turning the chroma comb on screw up color? 1618c2ecf20Sopenharmony_ci Bug in the bt819 stepping on my board? 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci 0x14, 0x00, /* 0x14 Vertical Scaling lsb */ 1648c2ecf20Sopenharmony_ci 0x16, 0x07, /* 0x16 Video Timing Polarity 1658c2ecf20Sopenharmony_ci ACTIVE=active low 1668c2ecf20Sopenharmony_ci FIELD: high=odd, 1678c2ecf20Sopenharmony_ci vreset=active high, 1688c2ecf20Sopenharmony_ci hreset=active high */ 1698c2ecf20Sopenharmony_ci 0x18, 0x68, /* 0x18 AGC Delay */ 1708c2ecf20Sopenharmony_ci 0x19, 0x5d, /* 0x19 Burst Gate Delay */ 1718c2ecf20Sopenharmony_ci 0x1a, 0x80, /* 0x1a ADC Interface */ 1728c2ecf20Sopenharmony_ci }; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci struct bt819 *decoder = to_bt819(sd); 1758c2ecf20Sopenharmony_ci struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0]; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci init[0x03 * 2 - 1] = 1788c2ecf20Sopenharmony_ci (((timing->vdelay >> 8) & 0x03) << 6) | 1798c2ecf20Sopenharmony_ci (((timing->vactive >> 8) & 0x03) << 4) | 1808c2ecf20Sopenharmony_ci (((timing->hdelay >> 8) & 0x03) << 2) | 1818c2ecf20Sopenharmony_ci ((timing->hactive >> 8) & 0x03); 1828c2ecf20Sopenharmony_ci init[0x04 * 2 - 1] = timing->vdelay & 0xff; 1838c2ecf20Sopenharmony_ci init[0x05 * 2 - 1] = timing->vactive & 0xff; 1848c2ecf20Sopenharmony_ci init[0x06 * 2 - 1] = timing->hdelay & 0xff; 1858c2ecf20Sopenharmony_ci init[0x07 * 2 - 1] = timing->hactive & 0xff; 1868c2ecf20Sopenharmony_ci init[0x08 * 2 - 1] = timing->hscale >> 8; 1878c2ecf20Sopenharmony_ci init[0x09 * 2 - 1] = timing->hscale & 0xff; 1888c2ecf20Sopenharmony_ci /* 0x15 in array is address 0x19 */ 1898c2ecf20Sopenharmony_ci init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */ 1908c2ecf20Sopenharmony_ci /* reset */ 1918c2ecf20Sopenharmony_ci bt819_write(decoder, 0x1f, 0x00); 1928c2ecf20Sopenharmony_ci mdelay(1); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* init */ 1958c2ecf20Sopenharmony_ci return bt819_write_block(decoder, init, sizeof(init)); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct bt819 *decoder = to_bt819(sd); 2038c2ecf20Sopenharmony_ci int status = bt819_read(decoder, 0x00); 2048c2ecf20Sopenharmony_ci int res = V4L2_IN_ST_NO_SIGNAL; 2058c2ecf20Sopenharmony_ci v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if ((status & 0x80)) 2088c2ecf20Sopenharmony_ci res = 0; 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci std = V4L2_STD_UNKNOWN; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if ((status & 0x10)) 2138c2ecf20Sopenharmony_ci std &= V4L2_STD_PAL; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci std &= V4L2_STD_NTSC; 2168c2ecf20Sopenharmony_ci if (pstd) 2178c2ecf20Sopenharmony_ci *pstd = std; 2188c2ecf20Sopenharmony_ci if (pstatus) 2198c2ecf20Sopenharmony_ci *pstatus = res; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "get status %x\n", status); 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci return bt819_status(sd, NULL, std); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci return bt819_status(sd, status, NULL); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct bt819 *decoder = to_bt819(sd); 2388c2ecf20Sopenharmony_ci struct timing *timing = NULL; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) 2438c2ecf20Sopenharmony_ci v4l2_err(sd, "no notify found!\n"); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (std & V4L2_STD_NTSC) { 2468c2ecf20Sopenharmony_ci v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); 2478c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x01, 0, 1); 2488c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x01, 1, 0); 2498c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x01, 5, 0); 2508c2ecf20Sopenharmony_ci bt819_write(decoder, 0x18, 0x68); 2518c2ecf20Sopenharmony_ci bt819_write(decoder, 0x19, 0x5d); 2528c2ecf20Sopenharmony_ci /* bt819_setbit(decoder, 0x1a, 5, 1); */ 2538c2ecf20Sopenharmony_ci timing = &timing_data[1]; 2548c2ecf20Sopenharmony_ci } else if (std & V4L2_STD_PAL) { 2558c2ecf20Sopenharmony_ci v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); 2568c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x01, 0, 1); 2578c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x01, 1, 1); 2588c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x01, 5, 1); 2598c2ecf20Sopenharmony_ci bt819_write(decoder, 0x18, 0x7f); 2608c2ecf20Sopenharmony_ci bt819_write(decoder, 0x19, 0x72); 2618c2ecf20Sopenharmony_ci /* bt819_setbit(decoder, 0x1a, 5, 0); */ 2628c2ecf20Sopenharmony_ci timing = &timing_data[0]; 2638c2ecf20Sopenharmony_ci } else { 2648c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "unsupported norm %llx\n", 2658c2ecf20Sopenharmony_ci (unsigned long long)std); 2668c2ecf20Sopenharmony_ci return -EINVAL; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci bt819_write(decoder, 0x03, 2698c2ecf20Sopenharmony_ci (((timing->vdelay >> 8) & 0x03) << 6) | 2708c2ecf20Sopenharmony_ci (((timing->vactive >> 8) & 0x03) << 4) | 2718c2ecf20Sopenharmony_ci (((timing->hdelay >> 8) & 0x03) << 2) | 2728c2ecf20Sopenharmony_ci ((timing->hactive >> 8) & 0x03)); 2738c2ecf20Sopenharmony_ci bt819_write(decoder, 0x04, timing->vdelay & 0xff); 2748c2ecf20Sopenharmony_ci bt819_write(decoder, 0x05, timing->vactive & 0xff); 2758c2ecf20Sopenharmony_ci bt819_write(decoder, 0x06, timing->hdelay & 0xff); 2768c2ecf20Sopenharmony_ci bt819_write(decoder, 0x07, timing->hactive & 0xff); 2778c2ecf20Sopenharmony_ci bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff); 2788c2ecf20Sopenharmony_ci bt819_write(decoder, 0x09, timing->hscale & 0xff); 2798c2ecf20Sopenharmony_ci decoder->norm = std; 2808c2ecf20Sopenharmony_ci v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL); 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int bt819_s_routing(struct v4l2_subdev *sd, 2858c2ecf20Sopenharmony_ci u32 input, u32 output, u32 config) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct bt819 *decoder = to_bt819(sd); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "set input %x\n", input); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (input > 7) 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) 2958c2ecf20Sopenharmony_ci v4l2_err(sd, "no notify found!\n"); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (decoder->input != input) { 2988c2ecf20Sopenharmony_ci v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); 2998c2ecf20Sopenharmony_ci decoder->input = input; 3008c2ecf20Sopenharmony_ci /* select mode */ 3018c2ecf20Sopenharmony_ci if (decoder->input == 0) { 3028c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x0b, 6, 0); 3038c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x1a, 1, 1); 3048c2ecf20Sopenharmony_ci } else { 3058c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x0b, 6, 1); 3068c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x1a, 1, 0); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int bt819_s_stream(struct v4l2_subdev *sd, int enable) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct bt819 *decoder = to_bt819(sd); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "enable output %x\n", enable); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (decoder->enable != enable) { 3208c2ecf20Sopenharmony_ci decoder->enable = enable; 3218c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x16, 7, !enable); 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int bt819_s_ctrl(struct v4l2_ctrl *ctrl) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = to_sd(ctrl); 3298c2ecf20Sopenharmony_ci struct bt819 *decoder = to_bt819(sd); 3308c2ecf20Sopenharmony_ci int temp; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci switch (ctrl->id) { 3338c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 3348c2ecf20Sopenharmony_ci bt819_write(decoder, 0x0a, ctrl->val); 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 3388c2ecf20Sopenharmony_ci bt819_write(decoder, 0x0c, ctrl->val & 0xff); 3398c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01)); 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 3438c2ecf20Sopenharmony_ci bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff); 3448c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01)); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Ratio between U gain and V gain must stay the same as 3478c2ecf20Sopenharmony_ci the ratio between the default U and V gain values. */ 3488c2ecf20Sopenharmony_ci temp = (ctrl->val * 180) / 254; 3498c2ecf20Sopenharmony_ci bt819_write(decoder, 0x0e, (temp >> 7) & 0xff); 3508c2ecf20Sopenharmony_ci bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 3548c2ecf20Sopenharmony_ci bt819_write(decoder, 0x0f, ctrl->val); 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci default: 3588c2ecf20Sopenharmony_ci return -EINVAL; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops bt819_ctrl_ops = { 3668c2ecf20Sopenharmony_ci .s_ctrl = bt819_s_ctrl, 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops bt819_video_ops = { 3708c2ecf20Sopenharmony_ci .s_std = bt819_s_std, 3718c2ecf20Sopenharmony_ci .s_routing = bt819_s_routing, 3728c2ecf20Sopenharmony_ci .s_stream = bt819_s_stream, 3738c2ecf20Sopenharmony_ci .querystd = bt819_querystd, 3748c2ecf20Sopenharmony_ci .g_input_status = bt819_g_input_status, 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops bt819_ops = { 3788c2ecf20Sopenharmony_ci .video = &bt819_video_ops, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int bt819_probe(struct i2c_client *client, 3848c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci int i, ver; 3878c2ecf20Sopenharmony_ci struct bt819 *decoder; 3888c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 3898c2ecf20Sopenharmony_ci const char *name; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Check if the adapter supports the needed features */ 3928c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 3938c2ecf20Sopenharmony_ci return -ENODEV; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL); 3968c2ecf20Sopenharmony_ci if (decoder == NULL) 3978c2ecf20Sopenharmony_ci return -ENOMEM; 3988c2ecf20Sopenharmony_ci sd = &decoder->sd; 3998c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(sd, client, &bt819_ops); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci ver = bt819_read(decoder, 0x17); 4028c2ecf20Sopenharmony_ci switch (ver & 0xf0) { 4038c2ecf20Sopenharmony_ci case 0x70: 4048c2ecf20Sopenharmony_ci name = "bt819a"; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case 0x60: 4078c2ecf20Sopenharmony_ci name = "bt817a"; 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case 0x20: 4108c2ecf20Sopenharmony_ci name = "bt815a"; 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci default: 4138c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, 4148c2ecf20Sopenharmony_ci "unknown chip version 0x%02x\n", ver); 4158c2ecf20Sopenharmony_ci return -ENODEV; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci v4l_info(client, "%s found @ 0x%x (%s)\n", name, 4198c2ecf20Sopenharmony_ci client->addr << 1, client->adapter->name); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci decoder->norm = V4L2_STD_NTSC; 4228c2ecf20Sopenharmony_ci decoder->input = 0; 4238c2ecf20Sopenharmony_ci decoder->enable = 1; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci i = bt819_init(sd); 4268c2ecf20Sopenharmony_ci if (i < 0) 4278c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "init status %d\n", i); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&decoder->hdl, 4); 4308c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, 4318c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); 4328c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, 4338c2ecf20Sopenharmony_ci V4L2_CID_CONTRAST, 0, 511, 1, 0xd8); 4348c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, 4358c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, 0, 511, 1, 0xfe); 4368c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, 4378c2ecf20Sopenharmony_ci V4L2_CID_HUE, -128, 127, 1, 0); 4388c2ecf20Sopenharmony_ci sd->ctrl_handler = &decoder->hdl; 4398c2ecf20Sopenharmony_ci if (decoder->hdl.error) { 4408c2ecf20Sopenharmony_ci int err = decoder->hdl.error; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&decoder->hdl); 4438c2ecf20Sopenharmony_ci return err; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(&decoder->hdl); 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int bt819_remove(struct i2c_client *client) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 4528c2ecf20Sopenharmony_ci struct bt819 *decoder = to_bt819(sd); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(sd); 4558c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&decoder->hdl); 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic const struct i2c_device_id bt819_id[] = { 4628c2ecf20Sopenharmony_ci { "bt819a", 0 }, 4638c2ecf20Sopenharmony_ci { "bt817a", 0 }, 4648c2ecf20Sopenharmony_ci { "bt815a", 0 }, 4658c2ecf20Sopenharmony_ci { } 4668c2ecf20Sopenharmony_ci}; 4678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bt819_id); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic struct i2c_driver bt819_driver = { 4708c2ecf20Sopenharmony_ci .driver = { 4718c2ecf20Sopenharmony_ci .name = "bt819", 4728c2ecf20Sopenharmony_ci }, 4738c2ecf20Sopenharmony_ci .probe = bt819_probe, 4748c2ecf20Sopenharmony_ci .remove = bt819_remove, 4758c2ecf20Sopenharmony_ci .id_table = bt819_id, 4768c2ecf20Sopenharmony_ci}; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cimodule_i2c_driver(bt819_driver); 479