1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cb7a01acSMauro Carvalho Chehab /*
3cb7a01acSMauro Carvalho Chehab * bt819 - BT819A VideoStream Decoder (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 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
12cb7a01acSMauro Carvalho Chehab * - moved over to linux>=2.4.x i2c protocol (9/9/2002)
13cb7a01acSMauro Carvalho Chehab *
14cb7a01acSMauro Carvalho Chehab * This code was modify/ported from the saa7111 driver written
15cb7a01acSMauro Carvalho Chehab * by Dave Perks.
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/ioctl.h>
21cb7a01acSMauro Carvalho Chehab #include <linux/delay.h>
22cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
23cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
24cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
25cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
26cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
27b5dcee22SMauro Carvalho Chehab #include <media/i2c/bt819.h>
28cb7a01acSMauro Carvalho Chehab
29cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
30cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mike Bernson & Dave Perks");
31cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL");
32cb7a01acSMauro Carvalho Chehab
33cb7a01acSMauro Carvalho Chehab static int debug;
34cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0);
35cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)");
36cb7a01acSMauro Carvalho Chehab
37cb7a01acSMauro Carvalho Chehab
38cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
39cb7a01acSMauro Carvalho Chehab
40cb7a01acSMauro Carvalho Chehab struct bt819 {
41cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd;
42cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl;
43cb7a01acSMauro Carvalho Chehab unsigned char reg[32];
44cb7a01acSMauro Carvalho Chehab
45cb7a01acSMauro Carvalho Chehab v4l2_std_id norm;
46cb7a01acSMauro Carvalho Chehab int input;
47cb7a01acSMauro Carvalho Chehab int enable;
48cb7a01acSMauro Carvalho Chehab };
49cb7a01acSMauro Carvalho Chehab
to_bt819(struct v4l2_subdev * sd)50cb7a01acSMauro Carvalho Chehab static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
51cb7a01acSMauro Carvalho Chehab {
52cb7a01acSMauro Carvalho Chehab return container_of(sd, struct bt819, sd);
53cb7a01acSMauro Carvalho Chehab }
54cb7a01acSMauro Carvalho Chehab
to_sd(struct v4l2_ctrl * ctrl)55cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
56cb7a01acSMauro Carvalho Chehab {
57cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct bt819, hdl)->sd;
58cb7a01acSMauro Carvalho Chehab }
59cb7a01acSMauro Carvalho Chehab
60cb7a01acSMauro Carvalho Chehab struct timing {
61cb7a01acSMauro Carvalho Chehab int hactive;
62cb7a01acSMauro Carvalho Chehab int hdelay;
63cb7a01acSMauro Carvalho Chehab int vactive;
64cb7a01acSMauro Carvalho Chehab int vdelay;
65cb7a01acSMauro Carvalho Chehab int hscale;
66cb7a01acSMauro Carvalho Chehab int vscale;
67cb7a01acSMauro Carvalho Chehab };
68cb7a01acSMauro Carvalho Chehab
69cb7a01acSMauro Carvalho Chehab /* for values, see the bt819 datasheet */
70cb7a01acSMauro Carvalho Chehab static struct timing timing_data[] = {
71cb7a01acSMauro Carvalho Chehab {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000},
72cb7a01acSMauro Carvalho Chehab {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
73cb7a01acSMauro Carvalho Chehab };
74cb7a01acSMauro Carvalho Chehab
75cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
76cb7a01acSMauro Carvalho Chehab
bt819_write(struct bt819 * decoder,u8 reg,u8 value)77cb7a01acSMauro Carvalho Chehab static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value)
78cb7a01acSMauro Carvalho Chehab {
79cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
80cb7a01acSMauro Carvalho Chehab
81cb7a01acSMauro Carvalho Chehab decoder->reg[reg] = value;
82cb7a01acSMauro Carvalho Chehab return i2c_smbus_write_byte_data(client, reg, value);
83cb7a01acSMauro Carvalho Chehab }
84cb7a01acSMauro Carvalho Chehab
bt819_setbit(struct bt819 * decoder,u8 reg,u8 bit,u8 value)85cb7a01acSMauro Carvalho Chehab static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value)
86cb7a01acSMauro Carvalho Chehab {
87cb7a01acSMauro Carvalho Chehab return bt819_write(decoder, reg,
88cb7a01acSMauro Carvalho Chehab (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
89cb7a01acSMauro Carvalho Chehab }
90cb7a01acSMauro Carvalho Chehab
bt819_write_block(struct bt819 * decoder,const u8 * data,unsigned int len)91cb7a01acSMauro Carvalho Chehab static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len)
92cb7a01acSMauro Carvalho Chehab {
93cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
94cb7a01acSMauro Carvalho Chehab int ret = -1;
95cb7a01acSMauro Carvalho Chehab u8 reg;
96cb7a01acSMauro Carvalho Chehab
97cb7a01acSMauro Carvalho Chehab /* the bt819 has an autoincrement function, use it if
98cb7a01acSMauro Carvalho Chehab * the adapter understands raw I2C */
99cb7a01acSMauro Carvalho Chehab if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
100cb7a01acSMauro Carvalho Chehab /* do raw I2C, not smbus compatible */
101cb7a01acSMauro Carvalho Chehab u8 block_data[32];
102cb7a01acSMauro Carvalho Chehab int block_len;
103cb7a01acSMauro Carvalho Chehab
104cb7a01acSMauro Carvalho Chehab while (len >= 2) {
105cb7a01acSMauro Carvalho Chehab block_len = 0;
106cb7a01acSMauro Carvalho Chehab block_data[block_len++] = reg = data[0];
107cb7a01acSMauro Carvalho Chehab do {
108cb7a01acSMauro Carvalho Chehab block_data[block_len++] =
109cb7a01acSMauro Carvalho Chehab decoder->reg[reg++] = data[1];
110cb7a01acSMauro Carvalho Chehab len -= 2;
111cb7a01acSMauro Carvalho Chehab data += 2;
112cb7a01acSMauro Carvalho Chehab } while (len >= 2 && data[0] == reg && block_len < 32);
113cb7a01acSMauro Carvalho Chehab ret = i2c_master_send(client, block_data, block_len);
114cb7a01acSMauro Carvalho Chehab if (ret < 0)
115cb7a01acSMauro Carvalho Chehab break;
116cb7a01acSMauro Carvalho Chehab }
117cb7a01acSMauro Carvalho Chehab } else {
118cb7a01acSMauro Carvalho Chehab /* do some slow I2C emulation kind of thing */
119cb7a01acSMauro Carvalho Chehab while (len >= 2) {
120cb7a01acSMauro Carvalho Chehab reg = *data++;
121cb7a01acSMauro Carvalho Chehab ret = bt819_write(decoder, reg, *data++);
122cb7a01acSMauro Carvalho Chehab if (ret < 0)
123cb7a01acSMauro Carvalho Chehab break;
124cb7a01acSMauro Carvalho Chehab len -= 2;
125cb7a01acSMauro Carvalho Chehab }
126cb7a01acSMauro Carvalho Chehab }
127cb7a01acSMauro Carvalho Chehab
128cb7a01acSMauro Carvalho Chehab return ret;
129cb7a01acSMauro Carvalho Chehab }
130cb7a01acSMauro Carvalho Chehab
bt819_read(struct bt819 * decoder,u8 reg)131cb7a01acSMauro Carvalho Chehab static inline int bt819_read(struct bt819 *decoder, u8 reg)
132cb7a01acSMauro Carvalho Chehab {
133cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
134cb7a01acSMauro Carvalho Chehab
135cb7a01acSMauro Carvalho Chehab return i2c_smbus_read_byte_data(client, reg);
136cb7a01acSMauro Carvalho Chehab }
137cb7a01acSMauro Carvalho Chehab
bt819_init(struct v4l2_subdev * sd)138cb7a01acSMauro Carvalho Chehab static int bt819_init(struct v4l2_subdev *sd)
139cb7a01acSMauro Carvalho Chehab {
140cb7a01acSMauro Carvalho Chehab static unsigned char init[] = {
141cb7a01acSMauro Carvalho Chehab /*0x1f, 0x00,*/ /* Reset */
142cb7a01acSMauro Carvalho Chehab 0x01, 0x59, /* 0x01 input format */
143cb7a01acSMauro Carvalho Chehab 0x02, 0x00, /* 0x02 temporal decimation */
144cb7a01acSMauro Carvalho Chehab 0x03, 0x12, /* 0x03 Cropping msb */
145cb7a01acSMauro Carvalho Chehab 0x04, 0x16, /* 0x04 Vertical Delay, lsb */
146cb7a01acSMauro Carvalho Chehab 0x05, 0xe0, /* 0x05 Vertical Active lsb */
147cb7a01acSMauro Carvalho Chehab 0x06, 0x80, /* 0x06 Horizontal Delay lsb */
148cb7a01acSMauro Carvalho Chehab 0x07, 0xd0, /* 0x07 Horizontal Active lsb */
149cb7a01acSMauro Carvalho Chehab 0x08, 0x00, /* 0x08 Horizontal Scaling msb */
150cb7a01acSMauro Carvalho Chehab 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */
151cb7a01acSMauro Carvalho Chehab 0x0a, 0x00, /* 0x0a Brightness control */
152cb7a01acSMauro Carvalho Chehab 0x0b, 0x30, /* 0x0b Miscellaneous control */
153cb7a01acSMauro Carvalho Chehab 0x0c, 0xd8, /* 0x0c Luma Gain lsb */
154cb7a01acSMauro Carvalho Chehab 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */
155cb7a01acSMauro Carvalho Chehab 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */
156cb7a01acSMauro Carvalho Chehab 0x0f, 0x00, /* 0x0f Hue control */
157cb7a01acSMauro Carvalho Chehab 0x12, 0x04, /* 0x12 Output Format */
158f8a7647dSMauro Carvalho Chehab 0x13, 0x20, /* 0x13 Vertical Scaling msb 0x00
159cb7a01acSMauro Carvalho Chehab chroma comb OFF, line drop scaling, interlace scaling
160fa7662aaSAndy Shevchenko BUG? Why does turning the chroma comb on screw up color?
161cb7a01acSMauro Carvalho Chehab Bug in the bt819 stepping on my board?
162cb7a01acSMauro Carvalho Chehab */
163f8a7647dSMauro Carvalho Chehab 0x14, 0x00, /* 0x14 Vertical Scaling lsb */
164cb7a01acSMauro Carvalho Chehab 0x16, 0x07, /* 0x16 Video Timing Polarity
165cb7a01acSMauro Carvalho Chehab ACTIVE=active low
166cb7a01acSMauro Carvalho Chehab FIELD: high=odd,
167cb7a01acSMauro Carvalho Chehab vreset=active high,
168cb7a01acSMauro Carvalho Chehab hreset=active high */
169cb7a01acSMauro Carvalho Chehab 0x18, 0x68, /* 0x18 AGC Delay */
170cb7a01acSMauro Carvalho Chehab 0x19, 0x5d, /* 0x19 Burst Gate Delay */
171cb7a01acSMauro Carvalho Chehab 0x1a, 0x80, /* 0x1a ADC Interface */
172cb7a01acSMauro Carvalho Chehab };
173cb7a01acSMauro Carvalho Chehab
174cb7a01acSMauro Carvalho Chehab struct bt819 *decoder = to_bt819(sd);
175cb7a01acSMauro Carvalho Chehab struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0];
176cb7a01acSMauro Carvalho Chehab
177cb7a01acSMauro Carvalho Chehab init[0x03 * 2 - 1] =
178cb7a01acSMauro Carvalho Chehab (((timing->vdelay >> 8) & 0x03) << 6) |
179cb7a01acSMauro Carvalho Chehab (((timing->vactive >> 8) & 0x03) << 4) |
180cb7a01acSMauro Carvalho Chehab (((timing->hdelay >> 8) & 0x03) << 2) |
181cb7a01acSMauro Carvalho Chehab ((timing->hactive >> 8) & 0x03);
182cb7a01acSMauro Carvalho Chehab init[0x04 * 2 - 1] = timing->vdelay & 0xff;
183cb7a01acSMauro Carvalho Chehab init[0x05 * 2 - 1] = timing->vactive & 0xff;
184cb7a01acSMauro Carvalho Chehab init[0x06 * 2 - 1] = timing->hdelay & 0xff;
185cb7a01acSMauro Carvalho Chehab init[0x07 * 2 - 1] = timing->hactive & 0xff;
186cb7a01acSMauro Carvalho Chehab init[0x08 * 2 - 1] = timing->hscale >> 8;
187cb7a01acSMauro Carvalho Chehab init[0x09 * 2 - 1] = timing->hscale & 0xff;
188cb7a01acSMauro Carvalho Chehab /* 0x15 in array is address 0x19 */
189cb7a01acSMauro Carvalho Chehab init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */
190cb7a01acSMauro Carvalho Chehab /* reset */
191cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x1f, 0x00);
192cb7a01acSMauro Carvalho Chehab mdelay(1);
193cb7a01acSMauro Carvalho Chehab
194cb7a01acSMauro Carvalho Chehab /* init */
195cb7a01acSMauro Carvalho Chehab return bt819_write_block(decoder, init, sizeof(init));
196cb7a01acSMauro Carvalho Chehab }
197cb7a01acSMauro Carvalho Chehab
198cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
199cb7a01acSMauro Carvalho Chehab
bt819_status(struct v4l2_subdev * sd,u32 * pstatus,v4l2_std_id * pstd)200cb7a01acSMauro Carvalho Chehab static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
201cb7a01acSMauro Carvalho Chehab {
202cb7a01acSMauro Carvalho Chehab struct bt819 *decoder = to_bt819(sd);
203cb7a01acSMauro Carvalho Chehab int status = bt819_read(decoder, 0x00);
204cb7a01acSMauro Carvalho Chehab int res = V4L2_IN_ST_NO_SIGNAL;
205ddc7f72aSHans Verkuil v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
206cb7a01acSMauro Carvalho Chehab
207cb7a01acSMauro Carvalho Chehab if ((status & 0x80))
208cb7a01acSMauro Carvalho Chehab res = 0;
209ddc7f72aSHans Verkuil else
210ddc7f72aSHans Verkuil std = V4L2_STD_UNKNOWN;
211cb7a01acSMauro Carvalho Chehab
212cb7a01acSMauro Carvalho Chehab if ((status & 0x10))
213ddc7f72aSHans Verkuil std &= V4L2_STD_PAL;
214cb7a01acSMauro Carvalho Chehab else
215ddc7f72aSHans Verkuil std &= V4L2_STD_NTSC;
216cb7a01acSMauro Carvalho Chehab if (pstd)
217cb7a01acSMauro Carvalho Chehab *pstd = std;
218cb7a01acSMauro Carvalho Chehab if (pstatus)
219cb7a01acSMauro Carvalho Chehab *pstatus = res;
220cb7a01acSMauro Carvalho Chehab
221cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "get status %x\n", status);
222cb7a01acSMauro Carvalho Chehab return 0;
223cb7a01acSMauro Carvalho Chehab }
224cb7a01acSMauro Carvalho Chehab
bt819_querystd(struct v4l2_subdev * sd,v4l2_std_id * std)225cb7a01acSMauro Carvalho Chehab static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
226cb7a01acSMauro Carvalho Chehab {
227cb7a01acSMauro Carvalho Chehab return bt819_status(sd, NULL, std);
228cb7a01acSMauro Carvalho Chehab }
229cb7a01acSMauro Carvalho Chehab
bt819_g_input_status(struct v4l2_subdev * sd,u32 * status)230cb7a01acSMauro Carvalho Chehab static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status)
231cb7a01acSMauro Carvalho Chehab {
232cb7a01acSMauro Carvalho Chehab return bt819_status(sd, status, NULL);
233cb7a01acSMauro Carvalho Chehab }
234cb7a01acSMauro Carvalho Chehab
bt819_s_std(struct v4l2_subdev * sd,v4l2_std_id std)235cb7a01acSMauro Carvalho Chehab static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
236cb7a01acSMauro Carvalho Chehab {
237cb7a01acSMauro Carvalho Chehab struct bt819 *decoder = to_bt819(sd);
238cb7a01acSMauro Carvalho Chehab struct timing *timing = NULL;
239cb7a01acSMauro Carvalho Chehab
240cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
241cb7a01acSMauro Carvalho Chehab
242cb7a01acSMauro Carvalho Chehab if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
243cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "no notify found!\n");
244cb7a01acSMauro Carvalho Chehab
245cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) {
246cb7a01acSMauro Carvalho Chehab v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
247cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x01, 0, 1);
248cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x01, 1, 0);
249cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x01, 5, 0);
250cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x18, 0x68);
251cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x19, 0x5d);
252cb7a01acSMauro Carvalho Chehab /* bt819_setbit(decoder, 0x1a, 5, 1); */
253cb7a01acSMauro Carvalho Chehab timing = &timing_data[1];
254cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_PAL) {
255cb7a01acSMauro Carvalho Chehab v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
256cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x01, 0, 1);
257cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x01, 1, 1);
258cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x01, 5, 1);
259cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x18, 0x7f);
260cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x19, 0x72);
261cb7a01acSMauro Carvalho Chehab /* bt819_setbit(decoder, 0x1a, 5, 0); */
262cb7a01acSMauro Carvalho Chehab timing = &timing_data[0];
263cb7a01acSMauro Carvalho Chehab } else {
264cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "unsupported norm %llx\n",
265cb7a01acSMauro Carvalho Chehab (unsigned long long)std);
266cb7a01acSMauro Carvalho Chehab return -EINVAL;
267cb7a01acSMauro Carvalho Chehab }
268cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x03,
269cb7a01acSMauro Carvalho Chehab (((timing->vdelay >> 8) & 0x03) << 6) |
270cb7a01acSMauro Carvalho Chehab (((timing->vactive >> 8) & 0x03) << 4) |
271cb7a01acSMauro Carvalho Chehab (((timing->hdelay >> 8) & 0x03) << 2) |
272cb7a01acSMauro Carvalho Chehab ((timing->hactive >> 8) & 0x03));
273cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x04, timing->vdelay & 0xff);
274cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x05, timing->vactive & 0xff);
275cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x06, timing->hdelay & 0xff);
276cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x07, timing->hactive & 0xff);
277cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff);
278cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x09, timing->hscale & 0xff);
279cb7a01acSMauro Carvalho Chehab decoder->norm = std;
280cb7a01acSMauro Carvalho Chehab v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
281cb7a01acSMauro Carvalho Chehab return 0;
282cb7a01acSMauro Carvalho Chehab }
283cb7a01acSMauro Carvalho Chehab
bt819_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)284cb7a01acSMauro Carvalho Chehab static int bt819_s_routing(struct v4l2_subdev *sd,
285cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config)
286cb7a01acSMauro Carvalho Chehab {
287cb7a01acSMauro Carvalho Chehab struct bt819 *decoder = to_bt819(sd);
288cb7a01acSMauro Carvalho Chehab
289cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "set input %x\n", input);
290cb7a01acSMauro Carvalho Chehab
291cb7a01acSMauro Carvalho Chehab if (input > 7)
292cb7a01acSMauro Carvalho Chehab return -EINVAL;
293cb7a01acSMauro Carvalho Chehab
294cb7a01acSMauro Carvalho Chehab if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
295cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "no notify found!\n");
296cb7a01acSMauro Carvalho Chehab
297cb7a01acSMauro Carvalho Chehab if (decoder->input != input) {
298cb7a01acSMauro Carvalho Chehab v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
299cb7a01acSMauro Carvalho Chehab decoder->input = input;
300cb7a01acSMauro Carvalho Chehab /* select mode */
301cb7a01acSMauro Carvalho Chehab if (decoder->input == 0) {
302cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x0b, 6, 0);
303cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x1a, 1, 1);
304cb7a01acSMauro Carvalho Chehab } else {
305cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x0b, 6, 1);
306cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x1a, 1, 0);
307cb7a01acSMauro Carvalho Chehab }
308cb7a01acSMauro Carvalho Chehab v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
309cb7a01acSMauro Carvalho Chehab }
310cb7a01acSMauro Carvalho Chehab return 0;
311cb7a01acSMauro Carvalho Chehab }
312cb7a01acSMauro Carvalho Chehab
bt819_s_stream(struct v4l2_subdev * sd,int enable)313cb7a01acSMauro Carvalho Chehab static int bt819_s_stream(struct v4l2_subdev *sd, int enable)
314cb7a01acSMauro Carvalho Chehab {
315cb7a01acSMauro Carvalho Chehab struct bt819 *decoder = to_bt819(sd);
316cb7a01acSMauro Carvalho Chehab
317cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "enable output %x\n", enable);
318cb7a01acSMauro Carvalho Chehab
319cb7a01acSMauro Carvalho Chehab if (decoder->enable != enable) {
320cb7a01acSMauro Carvalho Chehab decoder->enable = enable;
321cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x16, 7, !enable);
322cb7a01acSMauro Carvalho Chehab }
323cb7a01acSMauro Carvalho Chehab return 0;
324cb7a01acSMauro Carvalho Chehab }
325cb7a01acSMauro Carvalho Chehab
bt819_s_ctrl(struct v4l2_ctrl * ctrl)326cb7a01acSMauro Carvalho Chehab static int bt819_s_ctrl(struct v4l2_ctrl *ctrl)
327cb7a01acSMauro Carvalho Chehab {
328cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl);
329cb7a01acSMauro Carvalho Chehab struct bt819 *decoder = to_bt819(sd);
330cb7a01acSMauro Carvalho Chehab int temp;
331cb7a01acSMauro Carvalho Chehab
332cb7a01acSMauro Carvalho Chehab switch (ctrl->id) {
333cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS:
334cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x0a, ctrl->val);
335cb7a01acSMauro Carvalho Chehab break;
336cb7a01acSMauro Carvalho Chehab
337cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST:
338cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x0c, ctrl->val & 0xff);
339cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01));
340cb7a01acSMauro Carvalho Chehab break;
341cb7a01acSMauro Carvalho Chehab
342cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION:
343cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff);
344cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01));
345cb7a01acSMauro Carvalho Chehab
346cb7a01acSMauro Carvalho Chehab /* Ratio between U gain and V gain must stay the same as
347cb7a01acSMauro Carvalho Chehab the ratio between the default U and V gain values. */
348cb7a01acSMauro Carvalho Chehab temp = (ctrl->val * 180) / 254;
349cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x0e, (temp >> 7) & 0xff);
350cb7a01acSMauro Carvalho Chehab bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01);
351cb7a01acSMauro Carvalho Chehab break;
352cb7a01acSMauro Carvalho Chehab
353cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE:
354cb7a01acSMauro Carvalho Chehab bt819_write(decoder, 0x0f, ctrl->val);
355cb7a01acSMauro Carvalho Chehab break;
356cb7a01acSMauro Carvalho Chehab
357cb7a01acSMauro Carvalho Chehab default:
358cb7a01acSMauro Carvalho Chehab return -EINVAL;
359cb7a01acSMauro Carvalho Chehab }
360cb7a01acSMauro Carvalho Chehab return 0;
361cb7a01acSMauro Carvalho Chehab }
362cb7a01acSMauro Carvalho Chehab
363cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
364cb7a01acSMauro Carvalho Chehab
365cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
366cb7a01acSMauro Carvalho Chehab .s_ctrl = bt819_s_ctrl,
367cb7a01acSMauro Carvalho Chehab };
368cb7a01acSMauro Carvalho Chehab
369cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops bt819_video_ops = {
3708774bed9SLaurent Pinchart .s_std = bt819_s_std,
371cb7a01acSMauro Carvalho Chehab .s_routing = bt819_s_routing,
372cb7a01acSMauro Carvalho Chehab .s_stream = bt819_s_stream,
373cb7a01acSMauro Carvalho Chehab .querystd = bt819_querystd,
374cb7a01acSMauro Carvalho Chehab .g_input_status = bt819_g_input_status,
375cb7a01acSMauro Carvalho Chehab };
376cb7a01acSMauro Carvalho Chehab
377cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops bt819_ops = {
378cb7a01acSMauro Carvalho Chehab .video = &bt819_video_ops,
379cb7a01acSMauro Carvalho Chehab };
380cb7a01acSMauro Carvalho Chehab
381cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
382cb7a01acSMauro Carvalho Chehab
bt819_probe(struct i2c_client * client)3830a1533e3SUwe Kleine-König static int bt819_probe(struct i2c_client *client)
384cb7a01acSMauro Carvalho Chehab {
385cb7a01acSMauro Carvalho Chehab int i, ver;
386cb7a01acSMauro Carvalho Chehab struct bt819 *decoder;
387cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd;
388cb7a01acSMauro Carvalho Chehab const char *name;
389cb7a01acSMauro Carvalho Chehab
390cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */
391cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
392cb7a01acSMauro Carvalho Chehab return -ENODEV;
393cb7a01acSMauro Carvalho Chehab
394c02b211dSLaurent Pinchart decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
395cb7a01acSMauro Carvalho Chehab if (decoder == NULL)
396cb7a01acSMauro Carvalho Chehab return -ENOMEM;
397cb7a01acSMauro Carvalho Chehab sd = &decoder->sd;
398cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &bt819_ops);
399cb7a01acSMauro Carvalho Chehab
400cb7a01acSMauro Carvalho Chehab ver = bt819_read(decoder, 0x17);
401cb7a01acSMauro Carvalho Chehab switch (ver & 0xf0) {
402cb7a01acSMauro Carvalho Chehab case 0x70:
403cb7a01acSMauro Carvalho Chehab name = "bt819a";
404cb7a01acSMauro Carvalho Chehab break;
405cb7a01acSMauro Carvalho Chehab case 0x60:
406cb7a01acSMauro Carvalho Chehab name = "bt817a";
407cb7a01acSMauro Carvalho Chehab break;
408cb7a01acSMauro Carvalho Chehab case 0x20:
409cb7a01acSMauro Carvalho Chehab name = "bt815a";
410cb7a01acSMauro Carvalho Chehab break;
411cb7a01acSMauro Carvalho Chehab default:
412cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd,
413cb7a01acSMauro Carvalho Chehab "unknown chip version 0x%02x\n", ver);
414cb7a01acSMauro Carvalho Chehab return -ENODEV;
415cb7a01acSMauro Carvalho Chehab }
416cb7a01acSMauro Carvalho Chehab
417cb7a01acSMauro Carvalho Chehab v4l_info(client, "%s found @ 0x%x (%s)\n", name,
418cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name);
419cb7a01acSMauro Carvalho Chehab
420cb7a01acSMauro Carvalho Chehab decoder->norm = V4L2_STD_NTSC;
421cb7a01acSMauro Carvalho Chehab decoder->input = 0;
422cb7a01acSMauro Carvalho Chehab decoder->enable = 1;
423cb7a01acSMauro Carvalho Chehab
424cb7a01acSMauro Carvalho Chehab i = bt819_init(sd);
425cb7a01acSMauro Carvalho Chehab if (i < 0)
426cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "init status %d\n", i);
427cb7a01acSMauro Carvalho Chehab
428cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&decoder->hdl, 4);
429cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
430cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
431cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
432cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 511, 1, 0xd8);
433cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
434cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 511, 1, 0xfe);
435cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
436cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, -128, 127, 1, 0);
437cb7a01acSMauro Carvalho Chehab sd->ctrl_handler = &decoder->hdl;
438cb7a01acSMauro Carvalho Chehab if (decoder->hdl.error) {
439cb7a01acSMauro Carvalho Chehab int err = decoder->hdl.error;
440cb7a01acSMauro Carvalho Chehab
441cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl);
442cb7a01acSMauro Carvalho Chehab return err;
443cb7a01acSMauro Carvalho Chehab }
444cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&decoder->hdl);
445cb7a01acSMauro Carvalho Chehab return 0;
446cb7a01acSMauro Carvalho Chehab }
447cb7a01acSMauro Carvalho Chehab
bt819_remove(struct i2c_client * client)448ed5c2f5fSUwe Kleine-König static void bt819_remove(struct i2c_client *client)
449cb7a01acSMauro Carvalho Chehab {
450cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client);
451cb7a01acSMauro Carvalho Chehab struct bt819 *decoder = to_bt819(sd);
452cb7a01acSMauro Carvalho Chehab
453cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd);
454cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl);
455cb7a01acSMauro Carvalho Chehab }
456cb7a01acSMauro Carvalho Chehab
457cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
458cb7a01acSMauro Carvalho Chehab
459cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id bt819_id[] = {
460cb7a01acSMauro Carvalho Chehab { "bt819a", 0 },
461cb7a01acSMauro Carvalho Chehab { "bt817a", 0 },
462cb7a01acSMauro Carvalho Chehab { "bt815a", 0 },
463cb7a01acSMauro Carvalho Chehab { }
464cb7a01acSMauro Carvalho Chehab };
465cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, bt819_id);
466cb7a01acSMauro Carvalho Chehab
467cb7a01acSMauro Carvalho Chehab static struct i2c_driver bt819_driver = {
468cb7a01acSMauro Carvalho Chehab .driver = {
469cb7a01acSMauro Carvalho Chehab .name = "bt819",
470cb7a01acSMauro Carvalho Chehab },
471*aaeb31c0SUwe Kleine-König .probe = bt819_probe,
472cb7a01acSMauro Carvalho Chehab .remove = bt819_remove,
473cb7a01acSMauro Carvalho Chehab .id_table = bt819_id,
474cb7a01acSMauro Carvalho Chehab };
475cb7a01acSMauro Carvalho Chehab
476cb7a01acSMauro Carvalho Chehab module_i2c_driver(bt819_driver);
477