140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S/*
288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar * ths7303/53- THS7303/53 Video Amplifier driver
340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S *
440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar *
788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar * Author: Chaithrika U S <chaithrika@ti.com>
888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar *
988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar * Contributors:
1088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar *     Hans Verkuil <hans.verkuil@cisco.com>
1188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar *     Lad, Prabhakar <prabhakar.lad@ti.com>
1288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar *     Martin Bugge <marbugge@cisco.com>
1340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S *
1440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * This program is free software; you can redistribute it and/or
1540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * modify it under the terms of the GNU General Public License as
1640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * published by the Free Software Foundation version 2.
1740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S *
1840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * This program is distributed .as is. WITHOUT ANY WARRANTY of any
1940199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * kind, whether express or implied; without even the implied warranty
2040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S * GNU General Public License for more details.
2240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S */
2340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
2440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S#include <linux/i2c.h>
2540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S#include <linux/module.h>
2688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar#include <linux/slab.h>
2740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
2888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar#include <media/ths7303.h>
2988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar#include <media/v4l2-device.h>
3040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
31ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli#define THS7303_CHANNEL_1	1
32ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli#define THS7303_CHANNEL_2	2
33ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli#define THS7303_CHANNEL_3	3
34ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli
3588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstruct ths7303_state {
3688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct v4l2_subdev		sd;
37dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar	const struct ths7303_platform_data *pdata;
3888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct v4l2_bt_timings		bt;
3988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	int std_id;
4088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	int stream_on;
4188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar};
4288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
43ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadlienum ths7303_filter_mode {
44ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	THS7303_FILTER_MODE_480I_576I,
45ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	THS7303_FILTER_MODE_480P_576P,
46ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	THS7303_FILTER_MODE_720P_1080I,
47ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	THS7303_FILTER_MODE_1080P,
48ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	THS7303_FILTER_MODE_DISABLE
49ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli};
50ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli
5140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U SMODULE_DESCRIPTION("TI THS7303 video amplifier driver");
5240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U SMODULE_AUTHOR("Chaithrika U S");
5340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U SMODULE_LICENSE("GPL");
5440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
5540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic int debug;
5640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Smodule_param(debug, int, 0644);
5740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U SMODULE_PARM_DESC(debug, "Debug level 0-1");
5840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
5988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic inline struct ths7303_state *to_state(struct v4l2_subdev *sd)
6088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
6188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return container_of(sd, struct ths7303_state, sd);
6288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
6388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
6488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_read(struct v4l2_subdev *sd, u8 reg)
6588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
6688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct i2c_client *client = v4l2_get_subdevdata(sd);
6788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
6888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return i2c_smbus_read_byte_data(client, reg);
6988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
7088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
7188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_write(struct v4l2_subdev *sd, u8 reg, u8 val)
7288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
7388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct i2c_client *client = v4l2_get_subdevdata(sd);
7488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	int ret;
7588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	int i;
7688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
7788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	for (i = 0; i < 3; i++) {
7888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		ret = i2c_smbus_write_byte_data(client, reg, val);
7988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		if (ret == 0)
8088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			return 0;
8188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	}
8288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return ret;
8388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
8488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
8540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S/* following function is used to set ths7303 */
8606eb891edb4009245278a0ae50ccfd6fc99004d2Ricardo Ribaldastatic int ths7303_setval(struct v4l2_subdev *sd,
8706eb891edb4009245278a0ae50ccfd6fc99004d2Ricardo Ribalda			  enum ths7303_filter_mode mode)
8840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S{
89ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	struct i2c_client *client = v4l2_get_subdevdata(sd);
9088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_state *state = to_state(sd);
91dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar	const struct ths7303_platform_data *pdata = state->pdata;
9288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	u8 val, sel = 0;
9388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	int err, disable = 0;
9440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
95ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	if (!client)
96ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		return -EINVAL;
97ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli
98ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	switch (mode) {
99ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	case THS7303_FILTER_MODE_1080P:
10088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		sel = 0x3;	/*1080p and SXGA/UXGA */
101ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		break;
102ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	case THS7303_FILTER_MODE_720P_1080I:
10388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		sel = 0x2;	/*720p, 1080i and SVGA/XGA */
104ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		break;
105ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	case THS7303_FILTER_MODE_480P_576P:
10688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		sel = 0x1;	/* EDTV 480p/576p and VGA */
107ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		break;
108ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	case THS7303_FILTER_MODE_480I_576I:
10988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		sel = 0x0;	/* SDTV, S-Video, 480i/576i */
110ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		break;
111ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	default:
112ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		/* disable all channels */
113ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		disable = 1;
11440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	}
11588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
11688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	val = (sel << 6) | (sel << 3);
117ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	if (!disable)
11888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		val |= (pdata->ch_1 & 0x27);
11988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	err = ths7303_write(sd, THS7303_CHANNEL_1, val);
120ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	if (err)
121ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		goto out;
12240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
12388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	val = (sel << 6) | (sel << 3);
124ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	if (!disable)
12588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		val |= (pdata->ch_2 & 0x27);
12688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	err = ths7303_write(sd, THS7303_CHANNEL_2, val);
12740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	if (err)
128ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		goto out;
12940199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
13088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	val = (sel << 6) | (sel << 3);
13188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if (!disable)
13288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		val |= (pdata->ch_3 & 0x27);
13388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	err = ths7303_write(sd, THS7303_CHANNEL_3, val);
134ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	if (err)
135ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		goto out;
13688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
13788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return 0;
138ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadliout:
139ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	pr_info("write byte data failed\n");
14040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	return err;
14140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S}
14240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
14340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
14440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S{
14588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_state *state = to_state(sd);
14688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
14788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) {
14888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		state->std_id = 1;
14988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		state->bt.pixelclock = 0;
150ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
15188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	}
15288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
15388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
154ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli}
155ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli
15688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_config(struct v4l2_subdev *sd)
157ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli{
15888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_state *state = to_state(sd);
15988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	int res;
16088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
16188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if (!state->stream_on) {
16288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		ths7303_write(sd, THS7303_CHANNEL_1,
16388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			      (ths7303_read(sd, THS7303_CHANNEL_1) & 0xf8) |
16488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			      0x00);
16588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		ths7303_write(sd, THS7303_CHANNEL_2,
16688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			      (ths7303_read(sd, THS7303_CHANNEL_2) & 0xf8) |
16788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			      0x00);
16888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		ths7303_write(sd, THS7303_CHANNEL_3,
16988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			      (ths7303_read(sd, THS7303_CHANNEL_3) & 0xf8) |
17088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			      0x00);
17188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		return 0;
17288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	}
173ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli
17488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if (state->bt.pixelclock > 120000000)
175ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P);
17688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	else if (state->bt.pixelclock > 70000000)
177ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I);
17888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	else if (state->bt.pixelclock > 20000000)
179ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P);
18088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	else if (state->std_id)
18188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		res = ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
182ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	else
183ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		/* disable all channels */
184ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli		res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
185ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli
186ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cfManjunath Hadli	return res;
18788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
18888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
18988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
19088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_s_stream(struct v4l2_subdev *sd, int enable)
19188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
19288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_state *state = to_state(sd);
19388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
19488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	state->stream_on = enable;
19588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
19688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return ths7303_config(sd);
19788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
19888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
19988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar/* for setting filter for HD output */
20088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_s_dv_timings(struct v4l2_subdev *sd,
20188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			       struct v4l2_dv_timings *dv_timings)
20288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
20388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_state *state = to_state(sd);
20488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
20588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if (!dv_timings || dv_timings->type != V4L2_DV_BT_656_1120)
20688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		return -EINVAL;
20788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
20888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	state->bt = dv_timings->bt;
20988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	state->std_id = 0;
21088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
21188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return ths7303_config(sd);
21240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S}
21340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
21440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic const struct v4l2_subdev_video_ops ths7303_video_ops = {
21588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	.s_stream	= ths7303_s_stream,
21640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	.s_std_output	= ths7303_s_std_output,
21788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	.s_dv_timings   = ths7303_s_dv_timings,
21840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S};
21940199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
22088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar#ifdef CONFIG_VIDEO_ADV_DEBUG
22188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
22288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_g_register(struct v4l2_subdev *sd,
22388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			      struct v4l2_dbg_register *reg)
22488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
22588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	reg->size = 1;
22688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	reg->val = ths7303_read(sd, reg->reg);
22788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return 0;
22888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
22988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
23088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_s_register(struct v4l2_subdev *sd,
231977ba3b1b73f24fae2d0c8bd59d7a4696f1e0cccHans Verkuil			      const struct v4l2_dbg_register *reg)
23288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
23388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	ths7303_write(sd, reg->reg, reg->val);
23488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return 0;
23588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
23688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar#endif
23788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
23888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic const char * const stc_lpf_sel_txt[4] = {
23988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"500-kHz Filter",
24088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"2.5-MHz Filter",
24188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"5-MHz Filter",
24288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"5-MHz Filter",
24388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar};
24488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
24588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic const char * const in_mux_sel_txt[2] = {
24688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Input A Select",
24788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Input B Select",
24888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar};
24988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
25088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic const char * const lpf_freq_sel_txt[4] = {
25188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"9-MHz LPF",
25288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"16-MHz LPF",
25388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"35-MHz LPF",
25488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Bypass LPF",
25588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar};
25688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
25788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic const char * const in_bias_sel_dis_cont_txt[8] = {
25888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Disable Channel",
25988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Mute Function - No Output",
26088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"DC Bias Select",
26188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"DC Bias + 250 mV Offset Select",
26288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"AC Bias Select",
26388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Sync Tip Clamp with low bias",
26488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Sync Tip Clamp with mid bias",
26588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	"Sync Tip Clamp with high bias",
26688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar};
26788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
26888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic void ths7303_log_channel_status(struct v4l2_subdev *sd, u8 reg)
26988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
27088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	u8 val = ths7303_read(sd, reg);
27188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
27288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if ((val & 0x7) == 0) {
27388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		v4l2_info(sd, "Channel %d Off\n", reg);
27488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		return;
27588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	}
27688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
27788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	v4l2_info(sd, "Channel %d On\n", reg);
27888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	v4l2_info(sd, "  value 0x%x\n", val);
27988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	v4l2_info(sd, "  %s\n", stc_lpf_sel_txt[(val >> 6) & 0x3]);
28088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	v4l2_info(sd, "  %s\n", in_mux_sel_txt[(val >> 5) & 0x1]);
28188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	v4l2_info(sd, "  %s\n", lpf_freq_sel_txt[(val >> 3) & 0x3]);
28288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	v4l2_info(sd, "  %s\n", in_bias_sel_dis_cont_txt[(val >> 0) & 0x7]);
28388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
28488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
28588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakarstatic int ths7303_log_status(struct v4l2_subdev *sd)
28688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar{
28788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_state *state = to_state(sd);
28888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
28988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off");
29088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
29188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if (state->bt.pixelclock) {
29288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		struct v4l2_bt_timings *bt = bt = &state->bt;
29388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		u32 frame_width, frame_height;
29488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
295eacf8f9aa80e2231af43b589cfc18c054e417220Hans Verkuil		frame_width = V4L2_DV_BT_FRAME_WIDTH(bt);
296eacf8f9aa80e2231af43b589cfc18c054e417220Hans Verkuil		frame_height = V4L2_DV_BT_FRAME_HEIGHT(bt);
29788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		v4l2_info(sd,
29888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			  "timings: %dx%d%s%d (%dx%d). Pix freq. = %d Hz. Polarities = 0x%x\n",
29988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			  bt->width, bt->height, bt->interlaced ? "i" : "p",
30088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			  (frame_height * frame_width) > 0 ?
30188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			  (int)bt->pixelclock /
30288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			  (frame_height * frame_width) : 0,
30388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			  frame_width, frame_height,
30488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			  (int)bt->pixelclock, bt->polarities);
30588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	} else {
30688da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		v4l2_info(sd, "no timings set\n");
30788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	}
30888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
30988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	ths7303_log_channel_status(sd, THS7303_CHANNEL_1);
31088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	ths7303_log_channel_status(sd, THS7303_CHANNEL_2);
31188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	ths7303_log_channel_status(sd, THS7303_CHANNEL_3);
31288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
31388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return 0;
31488da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar}
31588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
31640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic const struct v4l2_subdev_core_ops ths7303_core_ops = {
31788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	.log_status = ths7303_log_status,
31888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar#ifdef CONFIG_VIDEO_ADV_DEBUG
31988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	.g_register = ths7303_g_register,
32088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	.s_register = ths7303_s_register,
32188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar#endif
32240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S};
32340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
32440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic const struct v4l2_subdev_ops ths7303_ops = {
32540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	.core	= &ths7303_core_ops,
32640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	.video 	= &ths7303_video_ops,
32740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S};
32840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
32940199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic int ths7303_probe(struct i2c_client *client,
33040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S			const struct i2c_device_id *id)
33140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S{
33288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_platform_data *pdata = client->dev.platform_data;
33388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	struct ths7303_state *state;
33440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	struct v4l2_subdev *sd;
33540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
336dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar	if (pdata == NULL) {
337dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar		dev_err(&client->dev, "No platform data\n");
338dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar		return -EINVAL;
339dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar	}
340dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar
34140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
34240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S		return -ENODEV;
34340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
34440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	v4l_info(client, "chip found @ 0x%x (%s)\n",
34540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S			client->addr << 1, client->adapter->name);
34640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
34788da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	state = devm_kzalloc(&client->dev, sizeof(struct ths7303_state),
34888da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar			     GFP_KERNEL);
34988da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	if (!state)
35040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S		return -ENOMEM;
35140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
352dd8c393b3c39f7ebd9ad69ce50cc836773d512b6Lad, Prabhakar	state->pdata = pdata;
35388da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	sd = &state->sd;
35440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
35540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
3568524ce558a0111762efa1a6b5ba9ce5e092b4707Lad, Prabhakar	/* set to default 480I_576I filter mode */
3578524ce558a0111762efa1a6b5ba9ce5e092b4707Lad, Prabhakar	if (ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I) < 0) {
3588524ce558a0111762efa1a6b5ba9ce5e092b4707Lad, Prabhakar		v4l_err(client, "Setting to 480I_576I filter mode failed!\n");
3598524ce558a0111762efa1a6b5ba9ce5e092b4707Lad, Prabhakar		return -EINVAL;
36088da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	}
36188da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar
36288da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar	return 0;
36340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S}
36440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
36540199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic int ths7303_remove(struct i2c_client *client)
36640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S{
36740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	struct v4l2_subdev *sd = i2c_get_clientdata(client);
36840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
36940199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	v4l2_device_unregister_subdev(sd);
37040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
37140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	return 0;
37240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S}
37340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
37440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic const struct i2c_device_id ths7303_id[] = {
375e12771100c93e101a7a8b302b6c5d57cff7b1551Hans Verkuil	{"ths7303", 0},
376e12771100c93e101a7a8b302b6c5d57cff7b1551Hans Verkuil	{"ths7353", 0},
37740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	{},
37840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S};
37940199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
38040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U SMODULE_DEVICE_TABLE(i2c, ths7303_id);
38140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
38240199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U Sstatic struct i2c_driver ths7303_driver = {
38340199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	.driver = {
38440199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S		.owner	= THIS_MODULE,
38588da0183eb2b72048099b4e0ecae1705f5309c94Lad, Prabhakar		.name	= "ths73x3",
38640199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	},
38740199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	.probe		= ths7303_probe,
38840199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	.remove		= ths7303_remove,
38940199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S	.id_table	= ths7303_id,
39040199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S};
39140199c50b891d24d1a8f1d480f886680a3ac9b74Chaithrika U S
392c6e8d86fffd8edf1bfccbd441b1812ee919fe3d5Axel Linmodule_i2c_driver(ths7303_driver);
393