1cb7a01acSMauro Carvalho Chehab /*
288da0183SLad, Prabhakar * ths7303/53- THS7303/53 Video Amplifier driver
3cb7a01acSMauro Carvalho Chehab *
4cb7a01acSMauro Carvalho Chehab * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
588da0183SLad, Prabhakar * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
688da0183SLad, Prabhakar *
788da0183SLad, Prabhakar * Author: Chaithrika U S <chaithrika@ti.com>
888da0183SLad, Prabhakar *
988da0183SLad, Prabhakar * Contributors:
1088da0183SLad, Prabhakar * Hans Verkuil <hans.verkuil@cisco.com>
1188da0183SLad, Prabhakar * Lad, Prabhakar <prabhakar.lad@ti.com>
1288da0183SLad, Prabhakar * Martin Bugge <marbugge@cisco.com>
13cb7a01acSMauro Carvalho Chehab *
14cb7a01acSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or
15cb7a01acSMauro Carvalho Chehab * modify it under the terms of the GNU General Public License as
16cb7a01acSMauro Carvalho Chehab * published by the Free Software Foundation version 2.
17cb7a01acSMauro Carvalho Chehab *
18cb7a01acSMauro Carvalho Chehab * This program is distributed .as is. WITHOUT ANY WARRANTY of any
19cb7a01acSMauro Carvalho Chehab * kind, whether express or implied; without even the implied warranty
20cb7a01acSMauro Carvalho Chehab * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21cb7a01acSMauro Carvalho Chehab * GNU General Public License for more details.
22cb7a01acSMauro Carvalho Chehab */
23cb7a01acSMauro Carvalho Chehab
24cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
25cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
2688da0183SLad, Prabhakar #include <linux/slab.h>
27cb7a01acSMauro Carvalho Chehab
28b5dcee22SMauro Carvalho Chehab #include <media/i2c/ths7303.h>
2988da0183SLad, Prabhakar #include <media/v4l2-device.h>
30cb7a01acSMauro Carvalho Chehab
31ad7dcb33SManjunath Hadli #define THS7303_CHANNEL_1 1
32ad7dcb33SManjunath Hadli #define THS7303_CHANNEL_2 2
33ad7dcb33SManjunath Hadli #define THS7303_CHANNEL_3 3
34ad7dcb33SManjunath Hadli
3588da0183SLad, Prabhakar struct ths7303_state {
3688da0183SLad, Prabhakar struct v4l2_subdev sd;
37dd8c393bSLad, Prabhakar const struct ths7303_platform_data *pdata;
3888da0183SLad, Prabhakar struct v4l2_bt_timings bt;
3988da0183SLad, Prabhakar int std_id;
4088da0183SLad, Prabhakar int stream_on;
4188da0183SLad, Prabhakar };
4288da0183SLad, Prabhakar
43ad7dcb33SManjunath Hadli enum ths7303_filter_mode {
44ad7dcb33SManjunath Hadli THS7303_FILTER_MODE_480I_576I,
45ad7dcb33SManjunath Hadli THS7303_FILTER_MODE_480P_576P,
46ad7dcb33SManjunath Hadli THS7303_FILTER_MODE_720P_1080I,
47ad7dcb33SManjunath Hadli THS7303_FILTER_MODE_1080P,
48ad7dcb33SManjunath Hadli THS7303_FILTER_MODE_DISABLE
49ad7dcb33SManjunath Hadli };
50ad7dcb33SManjunath Hadli
51cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("TI THS7303 video amplifier driver");
52cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Chaithrika U S");
53cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL");
54cb7a01acSMauro Carvalho Chehab
to_state(struct v4l2_subdev * sd)5588da0183SLad, Prabhakar static inline struct ths7303_state *to_state(struct v4l2_subdev *sd)
5688da0183SLad, Prabhakar {
5788da0183SLad, Prabhakar return container_of(sd, struct ths7303_state, sd);
5888da0183SLad, Prabhakar }
5988da0183SLad, Prabhakar
ths7303_read(struct v4l2_subdev * sd,u8 reg)6088da0183SLad, Prabhakar static int ths7303_read(struct v4l2_subdev *sd, u8 reg)
6188da0183SLad, Prabhakar {
6288da0183SLad, Prabhakar struct i2c_client *client = v4l2_get_subdevdata(sd);
6388da0183SLad, Prabhakar
6488da0183SLad, Prabhakar return i2c_smbus_read_byte_data(client, reg);
6588da0183SLad, Prabhakar }
6688da0183SLad, Prabhakar
ths7303_write(struct v4l2_subdev * sd,u8 reg,u8 val)6788da0183SLad, Prabhakar static int ths7303_write(struct v4l2_subdev *sd, u8 reg, u8 val)
6888da0183SLad, Prabhakar {
6988da0183SLad, Prabhakar struct i2c_client *client = v4l2_get_subdevdata(sd);
7088da0183SLad, Prabhakar int ret;
7188da0183SLad, Prabhakar int i;
7288da0183SLad, Prabhakar
7388da0183SLad, Prabhakar for (i = 0; i < 3; i++) {
7488da0183SLad, Prabhakar ret = i2c_smbus_write_byte_data(client, reg, val);
7588da0183SLad, Prabhakar if (ret == 0)
7688da0183SLad, Prabhakar return 0;
7788da0183SLad, Prabhakar }
7888da0183SLad, Prabhakar return ret;
7988da0183SLad, Prabhakar }
8088da0183SLad, Prabhakar
81cb7a01acSMauro Carvalho Chehab /* following function is used to set ths7303 */
ths7303_setval(struct v4l2_subdev * sd,enum ths7303_filter_mode mode)8206eb891eSRicardo Ribalda static int ths7303_setval(struct v4l2_subdev *sd,
8306eb891eSRicardo Ribalda enum ths7303_filter_mode mode)
84cb7a01acSMauro Carvalho Chehab {
85ad7dcb33SManjunath Hadli struct i2c_client *client = v4l2_get_subdevdata(sd);
8688da0183SLad, Prabhakar struct ths7303_state *state = to_state(sd);
87dd8c393bSLad, Prabhakar const struct ths7303_platform_data *pdata = state->pdata;
8888da0183SLad, Prabhakar u8 val, sel = 0;
8988da0183SLad, Prabhakar int err, disable = 0;
90cb7a01acSMauro Carvalho Chehab
91ad7dcb33SManjunath Hadli if (!client)
92ad7dcb33SManjunath Hadli return -EINVAL;
93ad7dcb33SManjunath Hadli
94ad7dcb33SManjunath Hadli switch (mode) {
95ad7dcb33SManjunath Hadli case THS7303_FILTER_MODE_1080P:
9688da0183SLad, Prabhakar sel = 0x3; /*1080p and SXGA/UXGA */
97ad7dcb33SManjunath Hadli break;
98ad7dcb33SManjunath Hadli case THS7303_FILTER_MODE_720P_1080I:
9988da0183SLad, Prabhakar sel = 0x2; /*720p, 1080i and SVGA/XGA */
100ad7dcb33SManjunath Hadli break;
101ad7dcb33SManjunath Hadli case THS7303_FILTER_MODE_480P_576P:
10288da0183SLad, Prabhakar sel = 0x1; /* EDTV 480p/576p and VGA */
103ad7dcb33SManjunath Hadli break;
104ad7dcb33SManjunath Hadli case THS7303_FILTER_MODE_480I_576I:
10588da0183SLad, Prabhakar sel = 0x0; /* SDTV, S-Video, 480i/576i */
106ad7dcb33SManjunath Hadli break;
107ad7dcb33SManjunath Hadli default:
108ad7dcb33SManjunath Hadli /* disable all channels */
109ad7dcb33SManjunath Hadli disable = 1;
110cb7a01acSMauro Carvalho Chehab }
11188da0183SLad, Prabhakar
11288da0183SLad, Prabhakar val = (sel << 6) | (sel << 3);
113ad7dcb33SManjunath Hadli if (!disable)
11488da0183SLad, Prabhakar val |= (pdata->ch_1 & 0x27);
11588da0183SLad, Prabhakar err = ths7303_write(sd, THS7303_CHANNEL_1, val);
116cb7a01acSMauro Carvalho Chehab if (err)
117ad7dcb33SManjunath Hadli goto out;
118cb7a01acSMauro Carvalho Chehab
11988da0183SLad, Prabhakar val = (sel << 6) | (sel << 3);
120ad7dcb33SManjunath Hadli if (!disable)
12188da0183SLad, Prabhakar val |= (pdata->ch_2 & 0x27);
12288da0183SLad, Prabhakar err = ths7303_write(sd, THS7303_CHANNEL_2, val);
123ad7dcb33SManjunath Hadli if (err)
124ad7dcb33SManjunath Hadli goto out;
125ad7dcb33SManjunath Hadli
12688da0183SLad, Prabhakar val = (sel << 6) | (sel << 3);
12788da0183SLad, Prabhakar if (!disable)
12888da0183SLad, Prabhakar val |= (pdata->ch_3 & 0x27);
12988da0183SLad, Prabhakar err = ths7303_write(sd, THS7303_CHANNEL_3, val);
130ad7dcb33SManjunath Hadli if (err)
131ad7dcb33SManjunath Hadli goto out;
13288da0183SLad, Prabhakar
13388da0183SLad, Prabhakar return 0;
134ad7dcb33SManjunath Hadli out:
135ad7dcb33SManjunath Hadli pr_info("write byte data failed\n");
136cb7a01acSMauro Carvalho Chehab return err;
137cb7a01acSMauro Carvalho Chehab }
138cb7a01acSMauro Carvalho Chehab
ths7303_s_std_output(struct v4l2_subdev * sd,v4l2_std_id norm)139cb7a01acSMauro Carvalho Chehab static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
140cb7a01acSMauro Carvalho Chehab {
14188da0183SLad, Prabhakar struct ths7303_state *state = to_state(sd);
14288da0183SLad, Prabhakar
14388da0183SLad, Prabhakar if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) {
14488da0183SLad, Prabhakar state->std_id = 1;
14588da0183SLad, Prabhakar state->bt.pixelclock = 0;
146ad7dcb33SManjunath Hadli return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
14788da0183SLad, Prabhakar }
14888da0183SLad, Prabhakar
149ad7dcb33SManjunath Hadli return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
150ad7dcb33SManjunath Hadli }
151ad7dcb33SManjunath Hadli
ths7303_config(struct v4l2_subdev * sd)15288da0183SLad, Prabhakar static int ths7303_config(struct v4l2_subdev *sd)
15388da0183SLad, Prabhakar {
15488da0183SLad, Prabhakar struct ths7303_state *state = to_state(sd);
15588da0183SLad, Prabhakar int res;
15688da0183SLad, Prabhakar
15788da0183SLad, Prabhakar if (!state->stream_on) {
15888da0183SLad, Prabhakar ths7303_write(sd, THS7303_CHANNEL_1,
15988da0183SLad, Prabhakar (ths7303_read(sd, THS7303_CHANNEL_1) & 0xf8) |
16088da0183SLad, Prabhakar 0x00);
16188da0183SLad, Prabhakar ths7303_write(sd, THS7303_CHANNEL_2,
16288da0183SLad, Prabhakar (ths7303_read(sd, THS7303_CHANNEL_2) & 0xf8) |
16388da0183SLad, Prabhakar 0x00);
16488da0183SLad, Prabhakar ths7303_write(sd, THS7303_CHANNEL_3,
16588da0183SLad, Prabhakar (ths7303_read(sd, THS7303_CHANNEL_3) & 0xf8) |
16688da0183SLad, Prabhakar 0x00);
16788da0183SLad, Prabhakar return 0;
16888da0183SLad, Prabhakar }
16988da0183SLad, Prabhakar
17088da0183SLad, Prabhakar if (state->bt.pixelclock > 120000000)
17188da0183SLad, Prabhakar res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P);
17288da0183SLad, Prabhakar else if (state->bt.pixelclock > 70000000)
17388da0183SLad, Prabhakar res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I);
17488da0183SLad, Prabhakar else if (state->bt.pixelclock > 20000000)
17588da0183SLad, Prabhakar res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P);
17688da0183SLad, Prabhakar else if (state->std_id)
17788da0183SLad, Prabhakar res = ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
17888da0183SLad, Prabhakar else
17988da0183SLad, Prabhakar /* disable all channels */
18088da0183SLad, Prabhakar res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
18188da0183SLad, Prabhakar
18288da0183SLad, Prabhakar return res;
18388da0183SLad, Prabhakar
18488da0183SLad, Prabhakar }
18588da0183SLad, Prabhakar
ths7303_s_stream(struct v4l2_subdev * sd,int enable)18688da0183SLad, Prabhakar static int ths7303_s_stream(struct v4l2_subdev *sd, int enable)
18788da0183SLad, Prabhakar {
18888da0183SLad, Prabhakar struct ths7303_state *state = to_state(sd);
18988da0183SLad, Prabhakar
19088da0183SLad, Prabhakar state->stream_on = enable;
19188da0183SLad, Prabhakar
19288da0183SLad, Prabhakar return ths7303_config(sd);
19388da0183SLad, Prabhakar }
19488da0183SLad, Prabhakar
195ad7dcb33SManjunath Hadli /* for setting filter for HD output */
ths7303_s_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * dv_timings)196ad7dcb33SManjunath Hadli static int ths7303_s_dv_timings(struct v4l2_subdev *sd,
197ad7dcb33SManjunath Hadli struct v4l2_dv_timings *dv_timings)
198ad7dcb33SManjunath Hadli {
19988da0183SLad, Prabhakar struct ths7303_state *state = to_state(sd);
200ad7dcb33SManjunath Hadli
20188da0183SLad, Prabhakar if (!dv_timings || dv_timings->type != V4L2_DV_BT_656_1120)
20288da0183SLad, Prabhakar return -EINVAL;
203ad7dcb33SManjunath Hadli
20488da0183SLad, Prabhakar state->bt = dv_timings->bt;
20588da0183SLad, Prabhakar state->std_id = 0;
20688da0183SLad, Prabhakar
20788da0183SLad, Prabhakar return ths7303_config(sd);
208cb7a01acSMauro Carvalho Chehab }
209cb7a01acSMauro Carvalho Chehab
210cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops ths7303_video_ops = {
21188da0183SLad, Prabhakar .s_stream = ths7303_s_stream,
212cb7a01acSMauro Carvalho Chehab .s_std_output = ths7303_s_std_output,
213ad7dcb33SManjunath Hadli .s_dv_timings = ths7303_s_dv_timings,
214cb7a01acSMauro Carvalho Chehab };
215cb7a01acSMauro Carvalho Chehab
21688da0183SLad, Prabhakar #ifdef CONFIG_VIDEO_ADV_DEBUG
21788da0183SLad, Prabhakar
ths7303_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)21888da0183SLad, Prabhakar static int ths7303_g_register(struct v4l2_subdev *sd,
21988da0183SLad, Prabhakar struct v4l2_dbg_register *reg)
22088da0183SLad, Prabhakar {
22188da0183SLad, Prabhakar reg->size = 1;
22288da0183SLad, Prabhakar reg->val = ths7303_read(sd, reg->reg);
22388da0183SLad, Prabhakar return 0;
22488da0183SLad, Prabhakar }
22588da0183SLad, Prabhakar
ths7303_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)22688da0183SLad, Prabhakar static int ths7303_s_register(struct v4l2_subdev *sd,
227977ba3b1SHans Verkuil const struct v4l2_dbg_register *reg)
22888da0183SLad, Prabhakar {
22988da0183SLad, Prabhakar ths7303_write(sd, reg->reg, reg->val);
23088da0183SLad, Prabhakar return 0;
23188da0183SLad, Prabhakar }
23288da0183SLad, Prabhakar #endif
23388da0183SLad, Prabhakar
23488da0183SLad, Prabhakar static const char * const stc_lpf_sel_txt[4] = {
23588da0183SLad, Prabhakar "500-kHz Filter",
23688da0183SLad, Prabhakar "2.5-MHz Filter",
23788da0183SLad, Prabhakar "5-MHz Filter",
23888da0183SLad, Prabhakar "5-MHz Filter",
23988da0183SLad, Prabhakar };
24088da0183SLad, Prabhakar
24188da0183SLad, Prabhakar static const char * const in_mux_sel_txt[2] = {
24288da0183SLad, Prabhakar "Input A Select",
24388da0183SLad, Prabhakar "Input B Select",
24488da0183SLad, Prabhakar };
24588da0183SLad, Prabhakar
24688da0183SLad, Prabhakar static const char * const lpf_freq_sel_txt[4] = {
24788da0183SLad, Prabhakar "9-MHz LPF",
24888da0183SLad, Prabhakar "16-MHz LPF",
24988da0183SLad, Prabhakar "35-MHz LPF",
25088da0183SLad, Prabhakar "Bypass LPF",
25188da0183SLad, Prabhakar };
25288da0183SLad, Prabhakar
25388da0183SLad, Prabhakar static const char * const in_bias_sel_dis_cont_txt[8] = {
25488da0183SLad, Prabhakar "Disable Channel",
25588da0183SLad, Prabhakar "Mute Function - No Output",
25688da0183SLad, Prabhakar "DC Bias Select",
25788da0183SLad, Prabhakar "DC Bias + 250 mV Offset Select",
25888da0183SLad, Prabhakar "AC Bias Select",
25988da0183SLad, Prabhakar "Sync Tip Clamp with low bias",
26088da0183SLad, Prabhakar "Sync Tip Clamp with mid bias",
26188da0183SLad, Prabhakar "Sync Tip Clamp with high bias",
26288da0183SLad, Prabhakar };
26388da0183SLad, Prabhakar
ths7303_log_channel_status(struct v4l2_subdev * sd,u8 reg)26488da0183SLad, Prabhakar static void ths7303_log_channel_status(struct v4l2_subdev *sd, u8 reg)
26588da0183SLad, Prabhakar {
26688da0183SLad, Prabhakar u8 val = ths7303_read(sd, reg);
26788da0183SLad, Prabhakar
26888da0183SLad, Prabhakar if ((val & 0x7) == 0) {
26988da0183SLad, Prabhakar v4l2_info(sd, "Channel %d Off\n", reg);
27088da0183SLad, Prabhakar return;
27188da0183SLad, Prabhakar }
27288da0183SLad, Prabhakar
27388da0183SLad, Prabhakar v4l2_info(sd, "Channel %d On\n", reg);
27488da0183SLad, Prabhakar v4l2_info(sd, " value 0x%x\n", val);
27588da0183SLad, Prabhakar v4l2_info(sd, " %s\n", stc_lpf_sel_txt[(val >> 6) & 0x3]);
27688da0183SLad, Prabhakar v4l2_info(sd, " %s\n", in_mux_sel_txt[(val >> 5) & 0x1]);
27788da0183SLad, Prabhakar v4l2_info(sd, " %s\n", lpf_freq_sel_txt[(val >> 3) & 0x3]);
27888da0183SLad, Prabhakar v4l2_info(sd, " %s\n", in_bias_sel_dis_cont_txt[(val >> 0) & 0x7]);
27988da0183SLad, Prabhakar }
28088da0183SLad, Prabhakar
ths7303_log_status(struct v4l2_subdev * sd)28188da0183SLad, Prabhakar static int ths7303_log_status(struct v4l2_subdev *sd)
28288da0183SLad, Prabhakar {
28388da0183SLad, Prabhakar struct ths7303_state *state = to_state(sd);
28488da0183SLad, Prabhakar
28588da0183SLad, Prabhakar v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off");
28688da0183SLad, Prabhakar
28788da0183SLad, Prabhakar if (state->bt.pixelclock) {
28800303f91SColin Ian King struct v4l2_bt_timings *bt = &state->bt;
28988da0183SLad, Prabhakar u32 frame_width, frame_height;
29088da0183SLad, Prabhakar
291eacf8f9aSHans Verkuil frame_width = V4L2_DV_BT_FRAME_WIDTH(bt);
292eacf8f9aSHans Verkuil frame_height = V4L2_DV_BT_FRAME_HEIGHT(bt);
29388da0183SLad, Prabhakar v4l2_info(sd,
29488da0183SLad, Prabhakar "timings: %dx%d%s%d (%dx%d). Pix freq. = %d Hz. Polarities = 0x%x\n",
29588da0183SLad, Prabhakar bt->width, bt->height, bt->interlaced ? "i" : "p",
29688da0183SLad, Prabhakar (frame_height * frame_width) > 0 ?
29788da0183SLad, Prabhakar (int)bt->pixelclock /
29888da0183SLad, Prabhakar (frame_height * frame_width) : 0,
29988da0183SLad, Prabhakar frame_width, frame_height,
30088da0183SLad, Prabhakar (int)bt->pixelclock, bt->polarities);
30188da0183SLad, Prabhakar } else {
30288da0183SLad, Prabhakar v4l2_info(sd, "no timings set\n");
30388da0183SLad, Prabhakar }
30488da0183SLad, Prabhakar
30588da0183SLad, Prabhakar ths7303_log_channel_status(sd, THS7303_CHANNEL_1);
30688da0183SLad, Prabhakar ths7303_log_channel_status(sd, THS7303_CHANNEL_2);
30788da0183SLad, Prabhakar ths7303_log_channel_status(sd, THS7303_CHANNEL_3);
30888da0183SLad, Prabhakar
30988da0183SLad, Prabhakar return 0;
31088da0183SLad, Prabhakar }
31188da0183SLad, Prabhakar
312cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops ths7303_core_ops = {
31388da0183SLad, Prabhakar .log_status = ths7303_log_status,
31488da0183SLad, Prabhakar #ifdef CONFIG_VIDEO_ADV_DEBUG
31588da0183SLad, Prabhakar .g_register = ths7303_g_register,
31688da0183SLad, Prabhakar .s_register = ths7303_s_register,
31788da0183SLad, Prabhakar #endif
318cb7a01acSMauro Carvalho Chehab };
319cb7a01acSMauro Carvalho Chehab
320cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops ths7303_ops = {
321cb7a01acSMauro Carvalho Chehab .core = &ths7303_core_ops,
322cb7a01acSMauro Carvalho Chehab .video = &ths7303_video_ops,
323cb7a01acSMauro Carvalho Chehab };
324cb7a01acSMauro Carvalho Chehab
ths7303_probe(struct i2c_client * client)325f15f764bSUwe Kleine-König static int ths7303_probe(struct i2c_client *client)
326cb7a01acSMauro Carvalho Chehab {
32788da0183SLad, Prabhakar struct ths7303_platform_data *pdata = client->dev.platform_data;
32888da0183SLad, Prabhakar struct ths7303_state *state;
329cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd;
330cb7a01acSMauro Carvalho Chehab
331dd8c393bSLad, Prabhakar if (pdata == NULL) {
332dd8c393bSLad, Prabhakar dev_err(&client->dev, "No platform data\n");
333dd8c393bSLad, Prabhakar return -EINVAL;
334dd8c393bSLad, Prabhakar }
335dd8c393bSLad, Prabhakar
336cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
337cb7a01acSMauro Carvalho Chehab return -ENODEV;
338cb7a01acSMauro Carvalho Chehab
339cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%x (%s)\n",
340cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name);
341cb7a01acSMauro Carvalho Chehab
34288da0183SLad, Prabhakar state = devm_kzalloc(&client->dev, sizeof(struct ths7303_state),
34388da0183SLad, Prabhakar GFP_KERNEL);
34488da0183SLad, Prabhakar if (!state)
345cb7a01acSMauro Carvalho Chehab return -ENOMEM;
346cb7a01acSMauro Carvalho Chehab
347dd8c393bSLad, Prabhakar state->pdata = pdata;
34888da0183SLad, Prabhakar sd = &state->sd;
349cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
350cb7a01acSMauro Carvalho Chehab
3518524ce55SLad, Prabhakar /* set to default 480I_576I filter mode */
3528524ce55SLad, Prabhakar if (ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I) < 0) {
3538524ce55SLad, Prabhakar v4l_err(client, "Setting to 480I_576I filter mode failed!\n");
3548524ce55SLad, Prabhakar return -EINVAL;
35588da0183SLad, Prabhakar }
35688da0183SLad, Prabhakar
35788da0183SLad, Prabhakar return 0;
358cb7a01acSMauro Carvalho Chehab }
359cb7a01acSMauro Carvalho Chehab
ths7303_remove(struct i2c_client * client)360ed5c2f5fSUwe Kleine-König static void ths7303_remove(struct i2c_client *client)
361cb7a01acSMauro Carvalho Chehab {
362cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client);
363cb7a01acSMauro Carvalho Chehab
364cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd);
365cb7a01acSMauro Carvalho Chehab }
366cb7a01acSMauro Carvalho Chehab
367cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id ths7303_id[] = {
368e1277110SHans Verkuil {"ths7303", 0},
369e1277110SHans Verkuil {"ths7353", 0},
370cb7a01acSMauro Carvalho Chehab {},
371cb7a01acSMauro Carvalho Chehab };
372cb7a01acSMauro Carvalho Chehab
373cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, ths7303_id);
374cb7a01acSMauro Carvalho Chehab
375cb7a01acSMauro Carvalho Chehab static struct i2c_driver ths7303_driver = {
376cb7a01acSMauro Carvalho Chehab .driver = {
37788da0183SLad, Prabhakar .name = "ths73x3",
378cb7a01acSMauro Carvalho Chehab },
379*aaeb31c0SUwe Kleine-König .probe = ths7303_probe,
380cb7a01acSMauro Carvalho Chehab .remove = ths7303_remove,
381cb7a01acSMauro Carvalho Chehab .id_table = ths7303_id,
382cb7a01acSMauro Carvalho Chehab };
383cb7a01acSMauro Carvalho Chehab
384cb7a01acSMauro Carvalho Chehab module_i2c_driver(ths7303_driver);
385