xref: /openbmc/linux/drivers/media/i2c/tvp5150.c (revision ee9a6ff6)
1459ee17cSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
2459ee17cSMauro Carvalho Chehab //
3459ee17cSMauro Carvalho Chehab // tvp5150 - Texas Instruments TVP5150A/AM1 and TVP5151 video decoder driver
4459ee17cSMauro Carvalho Chehab //
532590819SMauro Carvalho Chehab // Copyright (c) 2005,2006 Mauro Carvalho Chehab <mchehab@kernel.org>
6cb7a01acSMauro Carvalho Chehab 
7b802fb99SJavier Martinez Canillas #include <dt-bindings/media/tvp5150.h>
8cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
9cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
10cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
11cb7a01acSMauro Carvalho Chehab #include <linux/delay.h>
1209aa2609SJavier Martinez Canillas #include <linux/gpio/consumer.h>
138e4c97e0SPhilipp Zabel #include <linux/interrupt.h>
14cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
15859969b3SSakari Ailus #include <linux/of_graph.h>
1628b9e227SPhilipp Zabel #include <linux/regmap.h>
17c7d97499SJavier Martinez Canillas #include <media/v4l2-async.h>
18cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
19cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
20859969b3SSakari Ailus #include <media/v4l2-fwnode.h>
2155606310SMauro Carvalho Chehab #include <media/v4l2-mc.h>
22cb7a01acSMauro Carvalho Chehab 
23cb7a01acSMauro Carvalho Chehab #include "tvp5150_reg.h"
24cb7a01acSMauro Carvalho Chehab 
25785a3de1SPhilipp Zabel #define TVP5150_H_MAX		720U
26785a3de1SPhilipp Zabel #define TVP5150_V_MAX_525_60	480U
27785a3de1SPhilipp Zabel #define TVP5150_V_MAX_OTHERS	576U
28cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_LEFT	511
29cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_TOP	127
30cb7a01acSMauro Carvalho Chehab #define TVP5150_CROP_SHIFT	2
315cb82940SMarco Felsch #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
325cb82940SMarco Felsch #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
335cb82940SMarco Felsch #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
34cb7a01acSMauro Carvalho Chehab 
35c43875f6SMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
36cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab");
37459ee17cSMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
38cb7a01acSMauro Carvalho Chehab 
39cb7a01acSMauro Carvalho Chehab 
40cb7a01acSMauro Carvalho Chehab static int debug;
412a0489d3SPhilipp Zabel module_param(debug, int, 0644);
42cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-2)");
43cb7a01acSMauro Carvalho Chehab 
44ad0e3744SMauro Carvalho Chehab #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
45ad0e3744SMauro Carvalho Chehab 
46bc322c0dSMauro Carvalho Chehab enum tvp5150_pads {
47bc322c0dSMauro Carvalho Chehab 	TVP5150_PAD_IF_INPUT,
48bc322c0dSMauro Carvalho Chehab 	TVP5150_PAD_VID_OUT,
49bc322c0dSMauro Carvalho Chehab 	TVP5150_NUM_PADS
50bc322c0dSMauro Carvalho Chehab };
51bc322c0dSMauro Carvalho Chehab 
52cb7a01acSMauro Carvalho Chehab struct tvp5150 {
53cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev sd;
5455606310SMauro Carvalho Chehab #ifdef CONFIG_MEDIA_CONTROLLER
55bc322c0dSMauro Carvalho Chehab 	struct media_pad pads[TVP5150_NUM_PADS];
56f7b4b54eSJavier Martinez Canillas 	struct media_entity input_ent[TVP5150_INPUT_NUM];
57f7b4b54eSJavier Martinez Canillas 	struct media_pad input_pad[TVP5150_INPUT_NUM];
5855606310SMauro Carvalho Chehab #endif
59cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler hdl;
60cb7a01acSMauro Carvalho Chehab 	struct v4l2_rect rect;
6128b9e227SPhilipp Zabel 	struct regmap *regmap;
628e4c97e0SPhilipp Zabel 	int irq;
63cb7a01acSMauro Carvalho Chehab 
64cb7a01acSMauro Carvalho Chehab 	v4l2_std_id norm;	/* Current set standard */
65b440b733SPhilipp Zabel 	v4l2_std_id detected_norm;
66cb7a01acSMauro Carvalho Chehab 	u32 input;
67cb7a01acSMauro Carvalho Chehab 	u32 output;
6862a764e1SPhilipp Zabel 	u32 oe;
69cb7a01acSMauro Carvalho Chehab 	int enable;
708e4c97e0SPhilipp Zabel 	bool lock;
71a2e5f1b3SJavier Martinez Canillas 
7282275133SJavier Martinez Canillas 	u16 dev_id;
7382275133SJavier Martinez Canillas 	u16 rom_ver;
7482275133SJavier Martinez Canillas 
75a2e5f1b3SJavier Martinez Canillas 	enum v4l2_mbus_type mbus_type;
76cb7a01acSMauro Carvalho Chehab };
77cb7a01acSMauro Carvalho Chehab 
78cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
79cb7a01acSMauro Carvalho Chehab {
80cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct tvp5150, sd);
81cb7a01acSMauro Carvalho Chehab }
82cb7a01acSMauro Carvalho Chehab 
83cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
84cb7a01acSMauro Carvalho Chehab {
85cb7a01acSMauro Carvalho Chehab 	return &container_of(ctrl->handler, struct tvp5150, hdl)->sd;
86cb7a01acSMauro Carvalho Chehab }
87cb7a01acSMauro Carvalho Chehab 
88cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
89cb7a01acSMauro Carvalho Chehab {
9028b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
9128b9e227SPhilipp Zabel 	int ret, val;
92cb7a01acSMauro Carvalho Chehab 
9328b9e227SPhilipp Zabel 	ret = regmap_read(decoder->regmap, addr, &val);
9428b9e227SPhilipp Zabel 	if (ret < 0)
9528b9e227SPhilipp Zabel 		return ret;
96cb7a01acSMauro Carvalho Chehab 
9728b9e227SPhilipp Zabel 	return val;
98cb7a01acSMauro Carvalho Chehab }
99cb7a01acSMauro Carvalho Chehab 
100cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
101cb7a01acSMauro Carvalho Chehab 				const u8 end, int max_line)
102cb7a01acSMauro Carvalho Chehab {
103e5134114SMauro Carvalho Chehab 	u8 buf[16];
104e5134114SMauro Carvalho Chehab 	int i = 0, j, len;
105cb7a01acSMauro Carvalho Chehab 
106e5134114SMauro Carvalho Chehab 	if (max_line > 16) {
107e5134114SMauro Carvalho Chehab 		dprintk0(sd->dev, "too much data to dump\n");
108e5134114SMauro Carvalho Chehab 		return;
109cb7a01acSMauro Carvalho Chehab 	}
110cb7a01acSMauro Carvalho Chehab 
111e5134114SMauro Carvalho Chehab 	for (i = init; i < end; i += max_line) {
112e5134114SMauro Carvalho Chehab 		len = (end - i > max_line) ? max_line : end - i;
113e5134114SMauro Carvalho Chehab 
114e5134114SMauro Carvalho Chehab 		for (j = 0; j < len; j++)
115e5134114SMauro Carvalho Chehab 			buf[j] = tvp5150_read(sd, i + j);
116e5134114SMauro Carvalho Chehab 
117e5134114SMauro Carvalho Chehab 		dprintk0(sd->dev, "%s reg %02x = %*ph\n", s, i, len, buf);
118cb7a01acSMauro Carvalho Chehab 	}
119cb7a01acSMauro Carvalho Chehab }
120cb7a01acSMauro Carvalho Chehab 
121cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd)
122cb7a01acSMauro Carvalho Chehab {
123ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Video input source selection #1 = 0x%02x\n",
124cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1));
125ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Analog channel controls = 0x%02x\n",
126cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ANAL_CHL_CTL));
127ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Operation mode controls = 0x%02x\n",
128cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_OP_MODE_CTL));
129ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Miscellaneous controls = 0x%02x\n",
130cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MISC_CTL));
131ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Autoswitch mask= 0x%02x\n",
132cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_AUTOSW_MSK));
133ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Color killer threshold control = 0x%02x\n",
134cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL));
135ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
136cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1),
137cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2),
138cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3));
139ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Brightness control = 0x%02x\n",
140cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_BRIGHT_CTL));
141ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Color saturation control = 0x%02x\n",
142cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_SATURATION_CTL));
143ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Hue control = 0x%02x\n",
144cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_HUE_CTL));
145ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Contrast control = 0x%02x\n",
146cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CONTRAST_CTL));
147ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Outputs and data rates select = 0x%02x\n",
148cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_DATA_RATE_SEL));
149ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Configuration shared pins = 0x%02x\n",
150cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CONF_SHARED_PIN));
151ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Active video cropping start = 0x%02x%02x\n",
152cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB),
153cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB));
154ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Active video cropping stop  = 0x%02x%02x\n",
155cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB),
156cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB));
157ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Genlock/RTC = 0x%02x\n",
158cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_GENLOCK));
159ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Horizontal sync start = 0x%02x\n",
160cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_HORIZ_SYNC_START));
161ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Vertical blanking start = 0x%02x\n",
162cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_BLANKING_START));
163ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Vertical blanking stop = 0x%02x\n",
164cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP));
165ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
166cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1),
167cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2));
168ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt reset register B = 0x%02x\n",
169cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_RESET_REG_B));
170ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt enable register B = 0x%02x\n",
171cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B));
172ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt configuration register B = 0x%02x\n",
173cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B));
174ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Video standard = 0x%02x\n",
175cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VIDEO_STD));
176ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
177cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CB_GAIN_FACT),
178cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR));
179ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Macrovision on counter = 0x%02x\n",
180cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR));
181ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Macrovision off counter = 0x%02x\n",
182cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR));
183ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
184cb7a01acSMauro Carvalho Chehab 		(tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4);
185ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Device ID = %02x%02x\n",
186cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MSB_DEV_ID),
187cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LSB_DEV_ID));
188ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: ROM version = (hex) %02x.%02x\n",
189cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ROM_MAJOR_VER),
190cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ROM_MINOR_VER));
191ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Vertical line count = 0x%02x%02x\n",
192cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB),
193cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB));
194ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt status register B = 0x%02x\n",
195cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_STATUS_REG_B));
196ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt active register B = 0x%02x\n",
197cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B));
198ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
199cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_1),
200cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_2),
201cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_3),
202cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_4),
203cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_5));
204cb7a01acSMauro Carvalho Chehab 
205cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
206cb7a01acSMauro Carvalho Chehab 			TVP5150_TELETEXT_FIL1_END, 8);
207cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
208cb7a01acSMauro Carvalho Chehab 			TVP5150_TELETEXT_FIL2_END, 8);
209cb7a01acSMauro Carvalho Chehab 
210ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Teletext filter enable = 0x%02x\n",
211cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA));
212ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt status register A = 0x%02x\n",
213cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_STATUS_REG_A));
214ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt enable register A = 0x%02x\n",
215cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A));
216ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt configuration = 0x%02x\n",
217cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_CONF));
218ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: VDP status register = 0x%02x\n",
219cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VDP_STATUS_REG));
220ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO word count = 0x%02x\n",
221cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT));
222ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO interrupt threshold = 0x%02x\n",
223cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD));
224ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO reset = 0x%02x\n",
225cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_RESET));
226ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Line number interrupt = 0x%02x\n",
227cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LINE_NUMBER_INT));
228ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Pixel alignment register = 0x%02x%02x\n",
229cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH),
230cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW));
231ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO output control = 0x%02x\n",
232cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL));
233ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Full field enable = 0x%02x\n",
234cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FULL_FIELD_ENA));
235ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Full field mode register = 0x%02x\n",
236cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG));
237cb7a01acSMauro Carvalho Chehab 
238cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "CC   data",   TVP5150_CC_DATA_INI,
239cb7a01acSMauro Carvalho Chehab 			TVP5150_CC_DATA_END, 8);
240cb7a01acSMauro Carvalho Chehab 
241cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "WSS  data",   TVP5150_WSS_DATA_INI,
242cb7a01acSMauro Carvalho Chehab 			TVP5150_WSS_DATA_END, 8);
243cb7a01acSMauro Carvalho Chehab 
244cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "VPS  data",   TVP5150_VPS_DATA_INI,
245cb7a01acSMauro Carvalho Chehab 			TVP5150_VPS_DATA_END, 8);
246cb7a01acSMauro Carvalho Chehab 
247cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "VITC data",   TVP5150_VITC_DATA_INI,
248cb7a01acSMauro Carvalho Chehab 			TVP5150_VITC_DATA_END, 10);
249cb7a01acSMauro Carvalho Chehab 
250cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "Line mode",   TVP5150_LINE_MODE_INI,
251cb7a01acSMauro Carvalho Chehab 			TVP5150_LINE_MODE_END, 8);
252cb7a01acSMauro Carvalho Chehab 	return 0;
253cb7a01acSMauro Carvalho Chehab }
254cb7a01acSMauro Carvalho Chehab 
255cb7a01acSMauro Carvalho Chehab /****************************************************************************
256cb7a01acSMauro Carvalho Chehab 			Basic functions
257cb7a01acSMauro Carvalho Chehab  ****************************************************************************/
258cb7a01acSMauro Carvalho Chehab 
2596e98bee2SLaurent Pinchart static void tvp5150_selmux(struct v4l2_subdev *sd)
260cb7a01acSMauro Carvalho Chehab {
261cb7a01acSMauro Carvalho Chehab 	int opmode = 0;
262cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
2638a7441baSMarco Felsch 	unsigned int mask, val;
264cb7a01acSMauro Carvalho Chehab 	int input = 0;
265cb7a01acSMauro Carvalho Chehab 
266c43875f6SMauro Carvalho Chehab 	/* Only tvp5150am1 and tvp5151 have signal generator support */
267c43875f6SMauro Carvalho Chehab 	if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) ||
268c43875f6SMauro Carvalho Chehab 	    (decoder->dev_id == 0x5151 && decoder->rom_ver == 0x0100)) {
269c43875f6SMauro Carvalho Chehab 		if (!decoder->enable)
270cb7a01acSMauro Carvalho Chehab 			input = 8;
271c43875f6SMauro Carvalho Chehab 	}
272cb7a01acSMauro Carvalho Chehab 
273cb7a01acSMauro Carvalho Chehab 	switch (decoder->input) {
274cb7a01acSMauro Carvalho Chehab 	case TVP5150_COMPOSITE1:
275cb7a01acSMauro Carvalho Chehab 		input |= 2;
276cb7a01acSMauro Carvalho Chehab 		/* fall through */
277cb7a01acSMauro Carvalho Chehab 	case TVP5150_COMPOSITE0:
278cb7a01acSMauro Carvalho Chehab 		break;
279cb7a01acSMauro Carvalho Chehab 	case TVP5150_SVIDEO:
280cb7a01acSMauro Carvalho Chehab 	default:
281cb7a01acSMauro Carvalho Chehab 		input |= 1;
282cb7a01acSMauro Carvalho Chehab 		break;
283cb7a01acSMauro Carvalho Chehab 	}
284cb7a01acSMauro Carvalho Chehab 
285257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n",
286cb7a01acSMauro Carvalho Chehab 			decoder->input, decoder->output,
287cb7a01acSMauro Carvalho Chehab 			input, opmode);
288cb7a01acSMauro Carvalho Chehab 
28928b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
29028b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
291cb7a01acSMauro Carvalho Chehab 
292b4b2de38SLaurent Pinchart 	/*
293b4b2de38SLaurent Pinchart 	 * Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For
294b4b2de38SLaurent Pinchart 	 * S-Video we output the vertical lock (VLK) signal on FID/GLCO/VLK/HVLK
295b4b2de38SLaurent Pinchart 	 * and set INTREQ/GPCL/VBLK to logic 0. For composite we output the
296b4b2de38SLaurent Pinchart 	 * field indicator (FID) signal on FID/GLCO/VLK/HVLK and set
297b4b2de38SLaurent Pinchart 	 * INTREQ/GPCL/VBLK to logic 1.
298cb7a01acSMauro Carvalho Chehab 	 */
2998a7441baSMarco Felsch 	mask = TVP5150_MISC_CTL_GPCL | TVP5150_MISC_CTL_HVLK;
300cb7a01acSMauro Carvalho Chehab 	if (decoder->input == TVP5150_SVIDEO)
3018a7441baSMarco Felsch 		val = TVP5150_MISC_CTL_HVLK;
302cb7a01acSMauro Carvalho Chehab 	else
3038a7441baSMarco Felsch 		val = TVP5150_MISC_CTL_GPCL;
3048a7441baSMarco Felsch 	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
305cb7a01acSMauro Carvalho Chehab };
306cb7a01acSMauro Carvalho Chehab 
307cb7a01acSMauro Carvalho Chehab struct i2c_reg_value {
308cb7a01acSMauro Carvalho Chehab 	unsigned char reg;
309cb7a01acSMauro Carvalho Chehab 	unsigned char value;
310cb7a01acSMauro Carvalho Chehab };
311cb7a01acSMauro Carvalho Chehab 
312cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */
313cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = {
314cb7a01acSMauro Carvalho Chehab 	{ /* 0x00 */
315cb7a01acSMauro Carvalho Chehab 		TVP5150_VD_IN_SRC_SEL_1, 0x00
316cb7a01acSMauro Carvalho Chehab 	},
317cb7a01acSMauro Carvalho Chehab 	{ /* 0x01 */
318cb7a01acSMauro Carvalho Chehab 		TVP5150_ANAL_CHL_CTL, 0x15
319cb7a01acSMauro Carvalho Chehab 	},
320cb7a01acSMauro Carvalho Chehab 	{ /* 0x02 */
321cb7a01acSMauro Carvalho Chehab 		TVP5150_OP_MODE_CTL, 0x00
322cb7a01acSMauro Carvalho Chehab 	},
323cb7a01acSMauro Carvalho Chehab 	{ /* 0x03 */
324cb7a01acSMauro Carvalho Chehab 		TVP5150_MISC_CTL, 0x01
325cb7a01acSMauro Carvalho Chehab 	},
326cb7a01acSMauro Carvalho Chehab 	{ /* 0x06 */
327cb7a01acSMauro Carvalho Chehab 		TVP5150_COLOR_KIL_THSH_CTL, 0x10
328cb7a01acSMauro Carvalho Chehab 	},
329cb7a01acSMauro Carvalho Chehab 	{ /* 0x07 */
330cb7a01acSMauro Carvalho Chehab 		TVP5150_LUMA_PROC_CTL_1, 0x60
331cb7a01acSMauro Carvalho Chehab 	},
332cb7a01acSMauro Carvalho Chehab 	{ /* 0x08 */
333cb7a01acSMauro Carvalho Chehab 		TVP5150_LUMA_PROC_CTL_2, 0x00
334cb7a01acSMauro Carvalho Chehab 	},
335cb7a01acSMauro Carvalho Chehab 	{ /* 0x09 */
336cb7a01acSMauro Carvalho Chehab 		TVP5150_BRIGHT_CTL, 0x80
337cb7a01acSMauro Carvalho Chehab 	},
338cb7a01acSMauro Carvalho Chehab 	{ /* 0x0a */
339cb7a01acSMauro Carvalho Chehab 		TVP5150_SATURATION_CTL, 0x80
340cb7a01acSMauro Carvalho Chehab 	},
341cb7a01acSMauro Carvalho Chehab 	{ /* 0x0b */
342cb7a01acSMauro Carvalho Chehab 		TVP5150_HUE_CTL, 0x00
343cb7a01acSMauro Carvalho Chehab 	},
344cb7a01acSMauro Carvalho Chehab 	{ /* 0x0c */
345cb7a01acSMauro Carvalho Chehab 		TVP5150_CONTRAST_CTL, 0x80
346cb7a01acSMauro Carvalho Chehab 	},
347cb7a01acSMauro Carvalho Chehab 	{ /* 0x0d */
348cb7a01acSMauro Carvalho Chehab 		TVP5150_DATA_RATE_SEL, 0x47
349cb7a01acSMauro Carvalho Chehab 	},
350cb7a01acSMauro Carvalho Chehab 	{ /* 0x0e */
351cb7a01acSMauro Carvalho Chehab 		TVP5150_LUMA_PROC_CTL_3, 0x00
352cb7a01acSMauro Carvalho Chehab 	},
353cb7a01acSMauro Carvalho Chehab 	{ /* 0x0f */
354cb7a01acSMauro Carvalho Chehab 		TVP5150_CONF_SHARED_PIN, 0x08
355cb7a01acSMauro Carvalho Chehab 	},
356cb7a01acSMauro Carvalho Chehab 	{ /* 0x11 */
357cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_ST_MSB, 0x00
358cb7a01acSMauro Carvalho Chehab 	},
359cb7a01acSMauro Carvalho Chehab 	{ /* 0x12 */
360cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_ST_LSB, 0x00
361cb7a01acSMauro Carvalho Chehab 	},
362cb7a01acSMauro Carvalho Chehab 	{ /* 0x13 */
363cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_STP_MSB, 0x00
364cb7a01acSMauro Carvalho Chehab 	},
365cb7a01acSMauro Carvalho Chehab 	{ /* 0x14 */
366cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_STP_LSB, 0x00
367cb7a01acSMauro Carvalho Chehab 	},
368cb7a01acSMauro Carvalho Chehab 	{ /* 0x15 */
369cb7a01acSMauro Carvalho Chehab 		TVP5150_GENLOCK, 0x01
370cb7a01acSMauro Carvalho Chehab 	},
371cb7a01acSMauro Carvalho Chehab 	{ /* 0x16 */
372cb7a01acSMauro Carvalho Chehab 		TVP5150_HORIZ_SYNC_START, 0x80
373cb7a01acSMauro Carvalho Chehab 	},
374cb7a01acSMauro Carvalho Chehab 	{ /* 0x18 */
375cb7a01acSMauro Carvalho Chehab 		TVP5150_VERT_BLANKING_START, 0x00
376cb7a01acSMauro Carvalho Chehab 	},
377cb7a01acSMauro Carvalho Chehab 	{ /* 0x19 */
378cb7a01acSMauro Carvalho Chehab 		TVP5150_VERT_BLANKING_STOP, 0x00
379cb7a01acSMauro Carvalho Chehab 	},
380cb7a01acSMauro Carvalho Chehab 	{ /* 0x1a */
381cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_1, 0x0c
382cb7a01acSMauro Carvalho Chehab 	},
383cb7a01acSMauro Carvalho Chehab 	{ /* 0x1b */
384cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_2, 0x14
385cb7a01acSMauro Carvalho Chehab 	},
386cb7a01acSMauro Carvalho Chehab 	{ /* 0x1c */
387cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_RESET_REG_B, 0x00
388cb7a01acSMauro Carvalho Chehab 	},
389cb7a01acSMauro Carvalho Chehab 	{ /* 0x1d */
390cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_ENABLE_REG_B, 0x00
391cb7a01acSMauro Carvalho Chehab 	},
392cb7a01acSMauro Carvalho Chehab 	{ /* 0x1e */
393cb7a01acSMauro Carvalho Chehab 		TVP5150_INTT_CONFIG_REG_B, 0x00
394cb7a01acSMauro Carvalho Chehab 	},
395cb7a01acSMauro Carvalho Chehab 	{ /* 0x28 */
396cb7a01acSMauro Carvalho Chehab 		TVP5150_VIDEO_STD, 0x00
397cb7a01acSMauro Carvalho Chehab 	},
398cb7a01acSMauro Carvalho Chehab 	{ /* 0x2e */
399cb7a01acSMauro Carvalho Chehab 		TVP5150_MACROVISION_ON_CTR, 0x0f
400cb7a01acSMauro Carvalho Chehab 	},
401cb7a01acSMauro Carvalho Chehab 	{ /* 0x2f */
402cb7a01acSMauro Carvalho Chehab 		TVP5150_MACROVISION_OFF_CTR, 0x01
403cb7a01acSMauro Carvalho Chehab 	},
404cb7a01acSMauro Carvalho Chehab 	{ /* 0xbb */
405cb7a01acSMauro Carvalho Chehab 		TVP5150_TELETEXT_FIL_ENA, 0x00
406cb7a01acSMauro Carvalho Chehab 	},
407cb7a01acSMauro Carvalho Chehab 	{ /* 0xc0 */
408cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_STATUS_REG_A, 0x00
409cb7a01acSMauro Carvalho Chehab 	},
410cb7a01acSMauro Carvalho Chehab 	{ /* 0xc1 */
411cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_ENABLE_REG_A, 0x00
412cb7a01acSMauro Carvalho Chehab 	},
413cb7a01acSMauro Carvalho Chehab 	{ /* 0xc2 */
414cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_CONF, 0x04
415cb7a01acSMauro Carvalho Chehab 	},
416cb7a01acSMauro Carvalho Chehab 	{ /* 0xc8 */
417cb7a01acSMauro Carvalho Chehab 		TVP5150_FIFO_INT_THRESHOLD, 0x80
418cb7a01acSMauro Carvalho Chehab 	},
419cb7a01acSMauro Carvalho Chehab 	{ /* 0xc9 */
420cb7a01acSMauro Carvalho Chehab 		TVP5150_FIFO_RESET, 0x00
421cb7a01acSMauro Carvalho Chehab 	},
422cb7a01acSMauro Carvalho Chehab 	{ /* 0xca */
423cb7a01acSMauro Carvalho Chehab 		TVP5150_LINE_NUMBER_INT, 0x00
424cb7a01acSMauro Carvalho Chehab 	},
425cb7a01acSMauro Carvalho Chehab 	{ /* 0xcb */
426cb7a01acSMauro Carvalho Chehab 		TVP5150_PIX_ALIGN_REG_LOW, 0x4e
427cb7a01acSMauro Carvalho Chehab 	},
428cb7a01acSMauro Carvalho Chehab 	{ /* 0xcc */
429cb7a01acSMauro Carvalho Chehab 		TVP5150_PIX_ALIGN_REG_HIGH, 0x00
430cb7a01acSMauro Carvalho Chehab 	},
431cb7a01acSMauro Carvalho Chehab 	{ /* 0xcd */
432cb7a01acSMauro Carvalho Chehab 		TVP5150_FIFO_OUT_CTRL, 0x01
433cb7a01acSMauro Carvalho Chehab 	},
434cb7a01acSMauro Carvalho Chehab 	{ /* 0xcf */
435cb7a01acSMauro Carvalho Chehab 		TVP5150_FULL_FIELD_ENA, 0x00
436cb7a01acSMauro Carvalho Chehab 	},
437cb7a01acSMauro Carvalho Chehab 	{ /* 0xd0 */
438cb7a01acSMauro Carvalho Chehab 		TVP5150_LINE_MODE_INI, 0x00
439cb7a01acSMauro Carvalho Chehab 	},
440cb7a01acSMauro Carvalho Chehab 	{ /* 0xfc */
441cb7a01acSMauro Carvalho Chehab 		TVP5150_FULL_FIELD_MODE_REG, 0x7f
442cb7a01acSMauro Carvalho Chehab 	},
443cb7a01acSMauro Carvalho Chehab 	{ /* end of data */
444cb7a01acSMauro Carvalho Chehab 		0xff, 0xff
445cb7a01acSMauro Carvalho Chehab 	}
446cb7a01acSMauro Carvalho Chehab };
447cb7a01acSMauro Carvalho Chehab 
448cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */
449cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = {
4508105e1bcSPhilipp Zabel 	{	/* Automatic offset and AGC enabled */
451cb7a01acSMauro Carvalho Chehab 		TVP5150_ANAL_CHL_CTL, 0x15
452cb7a01acSMauro Carvalho Chehab 	}, {	/* Activate YCrCb output 0x9 or 0xd ? */
453b4b2de38SLaurent Pinchart 		TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL |
454b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_INTREQ_OE |
455b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_YCBCR_OE |
456b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_SYNC_OE |
457b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_VBLANK |
458b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_CLOCK_OE,
459cb7a01acSMauro Carvalho Chehab 	}, {	/* Activates video std autodetection for all standards */
460cb7a01acSMauro Carvalho Chehab 		TVP5150_AUTOSW_MSK, 0x0
461cb7a01acSMauro Carvalho Chehab 	}, {	/* Default format: 0x47. For 4:2:2: 0x40 */
462cb7a01acSMauro Carvalho Chehab 		TVP5150_DATA_RATE_SEL, 0x47
463cb7a01acSMauro Carvalho Chehab 	}, {
464cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_1, 0x0c
465cb7a01acSMauro Carvalho Chehab 	}, {
466cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_2, 0x54
467cb7a01acSMauro Carvalho Chehab 	}, {	/* Non documented, but initialized on WinTV USB2 */
468cb7a01acSMauro Carvalho Chehab 		0x27, 0x20
469cb7a01acSMauro Carvalho Chehab 	}, {
470cb7a01acSMauro Carvalho Chehab 		0xff, 0xff
471cb7a01acSMauro Carvalho Chehab 	}
472cb7a01acSMauro Carvalho Chehab };
473cb7a01acSMauro Carvalho Chehab 
474cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type {
475cb7a01acSMauro Carvalho Chehab 	unsigned int vbi_type;
476cb7a01acSMauro Carvalho Chehab 	unsigned int ini_line;
477cb7a01acSMauro Carvalho Chehab 	unsigned int end_line;
478cb7a01acSMauro Carvalho Chehab 	unsigned int by_field :1;
479cb7a01acSMauro Carvalho Chehab };
480cb7a01acSMauro Carvalho Chehab 
481cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value {
482cb7a01acSMauro Carvalho Chehab 	u16 reg;
483cb7a01acSMauro Carvalho Chehab 	struct tvp5150_vbi_type type;
484cb7a01acSMauro Carvalho Chehab 	unsigned char values[16];
485cb7a01acSMauro Carvalho Chehab };
486cb7a01acSMauro Carvalho Chehab 
487cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard
488cb7a01acSMauro Carvalho Chehab  * by
489cb7a01acSMauro Carvalho Chehab  tvp5150_vbi_types should follow the same order as vbi_ram_default
490cb7a01acSMauro Carvalho Chehab  * value 0 means rom position 0x10, value 1 means rom position 0x30
491cb7a01acSMauro Carvalho Chehab  * and so on. There are 16 possible locations from 0 to 15.
492cb7a01acSMauro Carvalho Chehab  */
493cb7a01acSMauro Carvalho Chehab 
49465dc760bSNasser Afshin static struct i2c_vbi_ram_value vbi_ram_default[] = {
49565dc760bSNasser Afshin 
4969bfd8f88SNasser Afshin 	/*
4979bfd8f88SNasser Afshin 	 * FIXME: Current api doesn't handle all VBI types, those not
4989bfd8f88SNasser Afshin 	 * yet supported are placed under #if 0
4999bfd8f88SNasser Afshin 	 */
500cb7a01acSMauro Carvalho Chehab #if 0
5013dd6b560SMauro Carvalho Chehab 	[0] = {0x010, /* Teletext, SECAM, WST System A */
502cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_SECAM, 6, 23, 1},
503cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
504cb7a01acSMauro Carvalho Chehab 		  0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
505cb7a01acSMauro Carvalho Chehab 	},
506cb7a01acSMauro Carvalho Chehab #endif
5073dd6b560SMauro Carvalho Chehab 	[1] = {0x030, /* Teletext, PAL, WST System B */
508cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_B, 6, 22, 1},
509cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
510cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
511cb7a01acSMauro Carvalho Chehab 	},
512cb7a01acSMauro Carvalho Chehab #if 0
5133dd6b560SMauro Carvalho Chehab 	[2] = {0x050, /* Teletext, PAL, WST System C */
514cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_PAL_C, 6, 22, 1},
515cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
516cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
517cb7a01acSMauro Carvalho Chehab 	},
5183dd6b560SMauro Carvalho Chehab 	[3] = {0x070, /* Teletext, NTSC, WST System B */
519cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_NTSC_B, 10, 21, 1},
520cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
521cb7a01acSMauro Carvalho Chehab 		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
522cb7a01acSMauro Carvalho Chehab 	},
5233dd6b560SMauro Carvalho Chehab 	[4] = {0x090, /* Tetetext, NTSC NABTS System C */
524cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_NTSC_C, 10, 21, 1},
525cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
526cb7a01acSMauro Carvalho Chehab 		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
527cb7a01acSMauro Carvalho Chehab 	},
5283dd6b560SMauro Carvalho Chehab 	[5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */
529cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_NTSC_D, 10, 21, 1},
530cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
531cb7a01acSMauro Carvalho Chehab 		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
532cb7a01acSMauro Carvalho Chehab 	},
5333dd6b560SMauro Carvalho Chehab 	[6] = {0x0d0, /* Closed Caption, PAL/SECAM */
534cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_CAPTION_625, 22, 22, 1},
535cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
536cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
537cb7a01acSMauro Carvalho Chehab 	},
538cb7a01acSMauro Carvalho Chehab #endif
5393dd6b560SMauro Carvalho Chehab 	[7] = {0x0f0, /* Closed Caption, NTSC */
540cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_CAPTION_525, 21, 21, 1},
541cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
542cb7a01acSMauro Carvalho Chehab 		  0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
543cb7a01acSMauro Carvalho Chehab 	},
5443dd6b560SMauro Carvalho Chehab 	[8] = {0x110, /* Wide Screen Signal, PAL/SECAM */
545cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_WSS_625, 23, 23, 1},
546cb7a01acSMauro Carvalho Chehab 		{ 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
547cb7a01acSMauro Carvalho Chehab 		  0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
548cb7a01acSMauro Carvalho Chehab 	},
549cb7a01acSMauro Carvalho Chehab #if 0
5503dd6b560SMauro Carvalho Chehab 	[9] = {0x130, /* Wide Screen Signal, NTSC C */
551cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_WSS_525, 20, 20, 1},
552cb7a01acSMauro Carvalho Chehab 		{ 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
553cb7a01acSMauro Carvalho Chehab 		  0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
554cb7a01acSMauro Carvalho Chehab 	},
5553dd6b560SMauro Carvalho Chehab 	[10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
556cb7a01acSMauro Carvalho Chehab 		{V4l2_SLICED_VITC_625, 6, 22, 0},
557cb7a01acSMauro Carvalho Chehab 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
558cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
559cb7a01acSMauro Carvalho Chehab 	},
5603dd6b560SMauro Carvalho Chehab 	[11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */
561cb7a01acSMauro Carvalho Chehab 		{V4l2_SLICED_VITC_525, 10, 20, 0},
562cb7a01acSMauro Carvalho Chehab 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
563cb7a01acSMauro Carvalho Chehab 		  0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
564cb7a01acSMauro Carvalho Chehab 	},
565cb7a01acSMauro Carvalho Chehab #endif
5663dd6b560SMauro Carvalho Chehab 	[12] = {0x190, /* Video Program System (VPS), PAL */
567cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_VPS, 16, 16, 0},
568cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
569cb7a01acSMauro Carvalho Chehab 		  0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
570cb7a01acSMauro Carvalho Chehab 	},
571cb7a01acSMauro Carvalho Chehab 	/* 0x1d0 User programmable */
572cb7a01acSMauro Carvalho Chehab };
573cb7a01acSMauro Carvalho Chehab 
574cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd,
575cb7a01acSMauro Carvalho Chehab 				const struct i2c_reg_value *regs)
576cb7a01acSMauro Carvalho Chehab {
57728b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
57828b9e227SPhilipp Zabel 
579cb7a01acSMauro Carvalho Chehab 	while (regs->reg != 0xff) {
58028b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, regs->reg, regs->value);
581cb7a01acSMauro Carvalho Chehab 		regs++;
582cb7a01acSMauro Carvalho Chehab 	}
583cb7a01acSMauro Carvalho Chehab 	return 0;
584cb7a01acSMauro Carvalho Chehab }
585cb7a01acSMauro Carvalho Chehab 
5863dd6b560SMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd)
587cb7a01acSMauro Carvalho Chehab {
58828b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
58928b9e227SPhilipp Zabel 	struct regmap *map = decoder->regmap;
590cb7a01acSMauro Carvalho Chehab 	unsigned int i;
5913dd6b560SMauro Carvalho Chehab 	int j;
592cb7a01acSMauro Carvalho Chehab 
593cb7a01acSMauro Carvalho Chehab 	/* Disable Full Field */
59428b9e227SPhilipp Zabel 	regmap_write(map, TVP5150_FULL_FIELD_ENA, 0);
595cb7a01acSMauro Carvalho Chehab 
596cb7a01acSMauro Carvalho Chehab 	/* Before programming, Line mode should be at 0xff */
597cb7a01acSMauro Carvalho Chehab 	for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
59828b9e227SPhilipp Zabel 		regmap_write(map, i, 0xff);
599cb7a01acSMauro Carvalho Chehab 
600cb7a01acSMauro Carvalho Chehab 	/* Load Ram Table */
6013dd6b560SMauro Carvalho Chehab 	for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) {
6023dd6b560SMauro Carvalho Chehab 		const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j];
6033dd6b560SMauro Carvalho Chehab 
6043dd6b560SMauro Carvalho Chehab 		if (!regs->type.vbi_type)
6053dd6b560SMauro Carvalho Chehab 			continue;
6063dd6b560SMauro Carvalho Chehab 
60728b9e227SPhilipp Zabel 		regmap_write(map, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
60828b9e227SPhilipp Zabel 		regmap_write(map, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
609cb7a01acSMauro Carvalho Chehab 
610cb7a01acSMauro Carvalho Chehab 		for (i = 0; i < 16; i++)
61128b9e227SPhilipp Zabel 			regmap_write(map, TVP5150_VDP_CONF_RAM_DATA,
61228b9e227SPhilipp Zabel 				     regs->values[i]);
613cb7a01acSMauro Carvalho Chehab 	}
614cb7a01acSMauro Carvalho Chehab 	return 0;
615cb7a01acSMauro Carvalho Chehab }
616cb7a01acSMauro Carvalho Chehab 
617cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */
618cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
619cb7a01acSMauro Carvalho Chehab 				struct v4l2_sliced_vbi_cap *cap)
620cb7a01acSMauro Carvalho Chehab {
6213dd6b560SMauro Carvalho Chehab 	int line, i;
622cb7a01acSMauro Carvalho Chehab 
623257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n");
624bb7a3681SNasser Afshin 	memset(cap, 0, sizeof(*cap));
625cb7a01acSMauro Carvalho Chehab 
6263dd6b560SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) {
6273dd6b560SMauro Carvalho Chehab 		const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i];
6283dd6b560SMauro Carvalho Chehab 
6293dd6b560SMauro Carvalho Chehab 		if (!regs->type.vbi_type)
6303dd6b560SMauro Carvalho Chehab 			continue;
6313dd6b560SMauro Carvalho Chehab 
6323dd6b560SMauro Carvalho Chehab 		for (line = regs->type.ini_line;
6333dd6b560SMauro Carvalho Chehab 		     line <= regs->type.end_line;
6343dd6b560SMauro Carvalho Chehab 		     line++) {
635cb7a01acSMauro Carvalho Chehab 			cap->service_lines[0][line] |= regs->type.vbi_type;
636cb7a01acSMauro Carvalho Chehab 		}
637cb7a01acSMauro Carvalho Chehab 		cap->service_set |= regs->type.vbi_type;
638cb7a01acSMauro Carvalho Chehab 	}
639cb7a01acSMauro Carvalho Chehab 	return 0;
640cb7a01acSMauro Carvalho Chehab }
641cb7a01acSMauro Carvalho Chehab 
642cb7a01acSMauro Carvalho Chehab /* Set vbi processing
643cb7a01acSMauro Carvalho Chehab  * type - one of tvp5150_vbi_types
644cb7a01acSMauro Carvalho Chehab  * line - line to gather data
645cb7a01acSMauro Carvalho Chehab  * fields: bit 0 field1, bit 1, field2
646cb7a01acSMauro Carvalho Chehab  * flags (default=0xf0) is a bitmask, were set means:
647cb7a01acSMauro Carvalho Chehab  *	bit 7: enable filtering null bytes on CC
648cb7a01acSMauro Carvalho Chehab  *	bit 6: send data also to FIFO
649cb7a01acSMauro Carvalho Chehab  *	bit 5: don't allow data with errors on FIFO
650cb7a01acSMauro Carvalho Chehab  *	bit 4: enable ECC when possible
651cb7a01acSMauro Carvalho Chehab  * pix_align = pix alignment:
652cb7a01acSMauro Carvalho Chehab  *	LSB = field1
653cb7a01acSMauro Carvalho Chehab  *	MSB = field2
654cb7a01acSMauro Carvalho Chehab  */
655cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd,
656cb7a01acSMauro Carvalho Chehab 			unsigned int type, u8 flags, int line,
657cb7a01acSMauro Carvalho Chehab 			const int fields)
658cb7a01acSMauro Carvalho Chehab {
659cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
660cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std = decoder->norm;
661cb7a01acSMauro Carvalho Chehab 	u8 reg;
6623dd6b560SMauro Carvalho Chehab 	int i, pos = 0;
663cb7a01acSMauro Carvalho Chehab 
664cb7a01acSMauro Carvalho Chehab 	if (std == V4L2_STD_ALL) {
665257e29f8SMauro Carvalho Chehab 		dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n");
666cb7a01acSMauro Carvalho Chehab 		return 0;
667cb7a01acSMauro Carvalho Chehab 	} else if (std & V4L2_STD_625_50) {
668cb7a01acSMauro Carvalho Chehab 		/* Don't follow NTSC Line number convension */
669cb7a01acSMauro Carvalho Chehab 		line += 3;
670cb7a01acSMauro Carvalho Chehab 	}
671cb7a01acSMauro Carvalho Chehab 
672cb7a01acSMauro Carvalho Chehab 	if (line < 6 || line > 27)
673cb7a01acSMauro Carvalho Chehab 		return 0;
674cb7a01acSMauro Carvalho Chehab 
6753dd6b560SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) {
6763dd6b560SMauro Carvalho Chehab 		const struct i2c_vbi_ram_value *regs =  &vbi_ram_default[i];
6773dd6b560SMauro Carvalho Chehab 
6783dd6b560SMauro Carvalho Chehab 		if (!regs->type.vbi_type)
6793dd6b560SMauro Carvalho Chehab 			continue;
6803dd6b560SMauro Carvalho Chehab 
681cb7a01acSMauro Carvalho Chehab 		if ((type & regs->type.vbi_type) &&
682cb7a01acSMauro Carvalho Chehab 		    (line >= regs->type.ini_line) &&
683b3d930aaSGustavo A. R. Silva 		    (line <= regs->type.end_line))
684cb7a01acSMauro Carvalho Chehab 			break;
685cb7a01acSMauro Carvalho Chehab 		pos++;
686cb7a01acSMauro Carvalho Chehab 	}
687b3d930aaSGustavo A. R. Silva 
688cb7a01acSMauro Carvalho Chehab 	type = pos | (flags & 0xf0);
689cb7a01acSMauro Carvalho Chehab 	reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
690cb7a01acSMauro Carvalho Chehab 
691b3d930aaSGustavo A. R. Silva 	if (fields & 1)
69228b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, reg, type);
693cb7a01acSMauro Carvalho Chehab 
694b3d930aaSGustavo A. R. Silva 	if (fields & 2)
69528b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, reg + 1, type);
696cb7a01acSMauro Carvalho Chehab 
697cb7a01acSMauro Carvalho Chehab 	return type;
698cb7a01acSMauro Carvalho Chehab }
699cb7a01acSMauro Carvalho Chehab 
7003dd6b560SMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line)
701cb7a01acSMauro Carvalho Chehab {
702cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
703cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std = decoder->norm;
704cb7a01acSMauro Carvalho Chehab 	u8 reg;
705cb7a01acSMauro Carvalho Chehab 	int pos, type = 0;
706cb7a01acSMauro Carvalho Chehab 	int i, ret = 0;
707cb7a01acSMauro Carvalho Chehab 
708cb7a01acSMauro Carvalho Chehab 	if (std == V4L2_STD_ALL) {
709257e29f8SMauro Carvalho Chehab 		dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n");
710cb7a01acSMauro Carvalho Chehab 		return 0;
711cb7a01acSMauro Carvalho Chehab 	} else if (std & V4L2_STD_625_50) {
712cb7a01acSMauro Carvalho Chehab 		/* Don't follow NTSC Line number convension */
713cb7a01acSMauro Carvalho Chehab 		line += 3;
714cb7a01acSMauro Carvalho Chehab 	}
715cb7a01acSMauro Carvalho Chehab 
716cb7a01acSMauro Carvalho Chehab 	if (line < 6 || line > 27)
717cb7a01acSMauro Carvalho Chehab 		return 0;
718cb7a01acSMauro Carvalho Chehab 
719cb7a01acSMauro Carvalho Chehab 	reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
720cb7a01acSMauro Carvalho Chehab 
721cb7a01acSMauro Carvalho Chehab 	for (i = 0; i <= 1; i++) {
722cb7a01acSMauro Carvalho Chehab 		ret = tvp5150_read(sd, reg + i);
723cb7a01acSMauro Carvalho Chehab 		if (ret < 0) {
724257e29f8SMauro Carvalho Chehab 			dev_err(sd->dev, "%s: failed with error = %d\n",
725cb7a01acSMauro Carvalho Chehab 				 __func__, ret);
726cb7a01acSMauro Carvalho Chehab 			return 0;
727cb7a01acSMauro Carvalho Chehab 		}
728cb7a01acSMauro Carvalho Chehab 		pos = ret & 0x0f;
7293dd6b560SMauro Carvalho Chehab 		if (pos < ARRAY_SIZE(vbi_ram_default))
7303dd6b560SMauro Carvalho Chehab 			type |= vbi_ram_default[pos].type.vbi_type;
731cb7a01acSMauro Carvalho Chehab 	}
732cb7a01acSMauro Carvalho Chehab 
733cb7a01acSMauro Carvalho Chehab 	return type;
734cb7a01acSMauro Carvalho Chehab }
735cb7a01acSMauro Carvalho Chehab 
736cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
737cb7a01acSMauro Carvalho Chehab {
738cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
739cb7a01acSMauro Carvalho Chehab 	int fmt = 0;
740cb7a01acSMauro Carvalho Chehab 
741cb7a01acSMauro Carvalho Chehab 	/* First tests should be against specific std */
742cb7a01acSMauro Carvalho Chehab 
74326811ae0SHans Verkuil 	if (std == V4L2_STD_NTSC_443) {
744cb7a01acSMauro Carvalho Chehab 		fmt = VIDEO_STD_NTSC_4_43_BIT;
74526811ae0SHans Verkuil 	} else if (std == V4L2_STD_PAL_M) {
746cb7a01acSMauro Carvalho Chehab 		fmt = VIDEO_STD_PAL_M_BIT;
74726811ae0SHans Verkuil 	} else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) {
748cb7a01acSMauro Carvalho Chehab 		fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
749cb7a01acSMauro Carvalho Chehab 	} else {
750cb7a01acSMauro Carvalho Chehab 		/* Then, test against generic ones */
751cb7a01acSMauro Carvalho Chehab 		if (std & V4L2_STD_NTSC)
752cb7a01acSMauro Carvalho Chehab 			fmt = VIDEO_STD_NTSC_MJ_BIT;
753cb7a01acSMauro Carvalho Chehab 		else if (std & V4L2_STD_PAL)
754cb7a01acSMauro Carvalho Chehab 			fmt = VIDEO_STD_PAL_BDGHIN_BIT;
755cb7a01acSMauro Carvalho Chehab 		else if (std & V4L2_STD_SECAM)
756cb7a01acSMauro Carvalho Chehab 			fmt = VIDEO_STD_SECAM_BIT;
757cb7a01acSMauro Carvalho Chehab 	}
758cb7a01acSMauro Carvalho Chehab 
759257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt);
76028b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_VIDEO_STD, fmt);
761cb7a01acSMauro Carvalho Chehab 	return 0;
762cb7a01acSMauro Carvalho Chehab }
763cb7a01acSMauro Carvalho Chehab 
7640db87cc7SMarco Felsch static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
7650db87cc7SMarco Felsch {
7660db87cc7SMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
7670db87cc7SMarco Felsch 
7680db87cc7SMarco Felsch 	*std = decoder->norm;
7690db87cc7SMarco Felsch 
7700db87cc7SMarco Felsch 	return 0;
7710db87cc7SMarco Felsch }
7720db87cc7SMarco Felsch 
773cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
774cb7a01acSMauro Carvalho Chehab {
775cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
776cb7a01acSMauro Carvalho Chehab 
777cb7a01acSMauro Carvalho Chehab 	if (decoder->norm == std)
778cb7a01acSMauro Carvalho Chehab 		return 0;
779cb7a01acSMauro Carvalho Chehab 
780cb7a01acSMauro Carvalho Chehab 	/* Change cropping height limits */
781cb7a01acSMauro Carvalho Chehab 	if (std & V4L2_STD_525_60)
782cb7a01acSMauro Carvalho Chehab 		decoder->rect.height = TVP5150_V_MAX_525_60;
783cb7a01acSMauro Carvalho Chehab 	else
784cb7a01acSMauro Carvalho Chehab 		decoder->rect.height = TVP5150_V_MAX_OTHERS;
785cb7a01acSMauro Carvalho Chehab 
78615695866SPhilipp Zabel 	decoder->norm = std;
787cb7a01acSMauro Carvalho Chehab 
788cb7a01acSMauro Carvalho Chehab 	return tvp5150_set_std(sd, std);
789cb7a01acSMauro Carvalho Chehab }
790cb7a01acSMauro Carvalho Chehab 
79115695866SPhilipp Zabel static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
79215695866SPhilipp Zabel {
79315695866SPhilipp Zabel 	int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
79415695866SPhilipp Zabel 
79515695866SPhilipp Zabel 	switch (val & 0x0F) {
79615695866SPhilipp Zabel 	case 0x01:
79715695866SPhilipp Zabel 		return V4L2_STD_NTSC;
79815695866SPhilipp Zabel 	case 0x03:
79915695866SPhilipp Zabel 		return V4L2_STD_PAL;
80015695866SPhilipp Zabel 	case 0x05:
80115695866SPhilipp Zabel 		return V4L2_STD_PAL_M;
80215695866SPhilipp Zabel 	case 0x07:
80315695866SPhilipp Zabel 		return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
80415695866SPhilipp Zabel 	case 0x09:
80515695866SPhilipp Zabel 		return V4L2_STD_NTSC_443;
80615695866SPhilipp Zabel 	case 0xb:
80715695866SPhilipp Zabel 		return V4L2_STD_SECAM;
80815695866SPhilipp Zabel 	default:
80915695866SPhilipp Zabel 		return V4L2_STD_UNKNOWN;
81015695866SPhilipp Zabel 	}
81115695866SPhilipp Zabel }
81215695866SPhilipp Zabel 
813ee9a6ff6SPhilipp Zabel static int tvp5150_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
814ee9a6ff6SPhilipp Zabel {
815ee9a6ff6SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
816ee9a6ff6SPhilipp Zabel 
817ee9a6ff6SPhilipp Zabel 	*std_id = decoder->lock ? tvp5150_read_std(sd) : V4L2_STD_UNKNOWN;
818ee9a6ff6SPhilipp Zabel 
819ee9a6ff6SPhilipp Zabel 	return 0;
820ee9a6ff6SPhilipp Zabel }
821ee9a6ff6SPhilipp Zabel 
8222f0a5c65SPhilipp Zabel static const struct v4l2_event tvp5150_ev_fmt = {
8232f0a5c65SPhilipp Zabel 	.type = V4L2_EVENT_SOURCE_CHANGE,
8242f0a5c65SPhilipp Zabel 	.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
8252f0a5c65SPhilipp Zabel };
8262f0a5c65SPhilipp Zabel 
8278e4c97e0SPhilipp Zabel static irqreturn_t tvp5150_isr(int irq, void *dev_id)
8288e4c97e0SPhilipp Zabel {
8298e4c97e0SPhilipp Zabel 	struct tvp5150 *decoder = dev_id;
8308e4c97e0SPhilipp Zabel 	struct regmap *map = decoder->regmap;
83162a764e1SPhilipp Zabel 	unsigned int mask, active = 0, status = 0;
83262a764e1SPhilipp Zabel 
83362a764e1SPhilipp Zabel 	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
83462a764e1SPhilipp Zabel 	       TVP5150_MISC_CTL_CLOCK_OE;
8358e4c97e0SPhilipp Zabel 
8368e4c97e0SPhilipp Zabel 	regmap_read(map, TVP5150_INT_STATUS_REG_A, &status);
8378e4c97e0SPhilipp Zabel 	if (status) {
8388e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INT_STATUS_REG_A, status);
8398e4c97e0SPhilipp Zabel 
84062a764e1SPhilipp Zabel 		if (status & TVP5150_INT_A_LOCK) {
8418e4c97e0SPhilipp Zabel 			decoder->lock = !!(status & TVP5150_INT_A_LOCK_STATUS);
8427bb3c338SPhilipp Zabel 			dev_dbg_lvl(decoder->sd.dev, 1, debug,
8437bb3c338SPhilipp Zabel 				    "sync lo%s signal\n",
8447bb3c338SPhilipp Zabel 				    decoder->lock ? "ck" : "ss");
8452f0a5c65SPhilipp Zabel 			v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
84662a764e1SPhilipp Zabel 			regmap_update_bits(map, TVP5150_MISC_CTL, mask,
84762a764e1SPhilipp Zabel 					   decoder->lock ? decoder->oe : 0);
84862a764e1SPhilipp Zabel 		}
8498e4c97e0SPhilipp Zabel 
8508e4c97e0SPhilipp Zabel 		return IRQ_HANDLED;
8518e4c97e0SPhilipp Zabel 	}
8528e4c97e0SPhilipp Zabel 
8538e4c97e0SPhilipp Zabel 	regmap_read(map, TVP5150_INT_ACTIVE_REG_B, &active);
8548e4c97e0SPhilipp Zabel 	if (active) {
8558e4c97e0SPhilipp Zabel 		status = 0;
8568e4c97e0SPhilipp Zabel 		regmap_read(map, TVP5150_INT_STATUS_REG_B, &status);
8578e4c97e0SPhilipp Zabel 		if (status)
8588e4c97e0SPhilipp Zabel 			regmap_write(map, TVP5150_INT_RESET_REG_B, status);
8598e4c97e0SPhilipp Zabel 	}
8608e4c97e0SPhilipp Zabel 
8618e4c97e0SPhilipp Zabel 	return IRQ_HANDLED;
8628e4c97e0SPhilipp Zabel }
8638e4c97e0SPhilipp Zabel 
864cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
865cb7a01acSMauro Carvalho Chehab {
866cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
8678105e1bcSPhilipp Zabel 	struct regmap *map = decoder->regmap;
868cb7a01acSMauro Carvalho Chehab 
869cb7a01acSMauro Carvalho Chehab 	/* Initializes TVP5150 to its default values */
870cb7a01acSMauro Carvalho Chehab 	tvp5150_write_inittab(sd, tvp5150_init_default);
871cb7a01acSMauro Carvalho Chehab 
8728e4c97e0SPhilipp Zabel 	if (decoder->irq) {
8738e4c97e0SPhilipp Zabel 		/* Configure pins: FID, VSYNC, INTREQ, SCLK */
8748e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x0);
8758e4c97e0SPhilipp Zabel 		/* Set interrupt polarity to active high */
8768e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE | 0x1);
8778e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x1);
8788e4c97e0SPhilipp Zabel 	} else {
8798105e1bcSPhilipp Zabel 		/* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */
8808105e1bcSPhilipp Zabel 		regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2);
8818e4c97e0SPhilipp Zabel 		/* Keep interrupt polarity active low */
8828e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE);
8838e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0);
8848e4c97e0SPhilipp Zabel 	}
8858105e1bcSPhilipp Zabel 
886cb7a01acSMauro Carvalho Chehab 	/* Initializes VDP registers */
8873dd6b560SMauro Carvalho Chehab 	tvp5150_vdp_init(sd);
888cb7a01acSMauro Carvalho Chehab 
889cb7a01acSMauro Carvalho Chehab 	/* Selects decoder input */
890cb7a01acSMauro Carvalho Chehab 	tvp5150_selmux(sd);
891cb7a01acSMauro Carvalho Chehab 
892cb7a01acSMauro Carvalho Chehab 	/* Initialize image preferences */
893cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_setup(&decoder->hdl);
894cb7a01acSMauro Carvalho Chehab 
8951bb086bcSPhilipp Zabel 	return 0;
8961bb086bcSPhilipp Zabel }
8971bb086bcSPhilipp Zabel 
8981bb086bcSPhilipp Zabel static int tvp5150_enable(struct v4l2_subdev *sd)
8991bb086bcSPhilipp Zabel {
9001bb086bcSPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
9011bb086bcSPhilipp Zabel 	v4l2_std_id std;
9021bb086bcSPhilipp Zabel 
9031bb086bcSPhilipp Zabel 	/* Initializes TVP5150 to stream enabled values */
9041bb086bcSPhilipp Zabel 	tvp5150_write_inittab(sd, tvp5150_init_enable);
9051bb086bcSPhilipp Zabel 
90615695866SPhilipp Zabel 	if (decoder->norm == V4L2_STD_ALL)
90715695866SPhilipp Zabel 		std = tvp5150_read_std(sd);
90815695866SPhilipp Zabel 	else
90915695866SPhilipp Zabel 		std = decoder->norm;
91015695866SPhilipp Zabel 
91115695866SPhilipp Zabel 	/* Disable autoswitch mode */
91215695866SPhilipp Zabel 	tvp5150_set_std(sd, std);
913a2e5f1b3SJavier Martinez Canillas 
91462a764e1SPhilipp Zabel 	/*
91562a764e1SPhilipp Zabel 	 * Enable the YCbCr and clock outputs. In discrete sync mode
91662a764e1SPhilipp Zabel 	 * (non-BT.656) additionally enable the the sync outputs.
91762a764e1SPhilipp Zabel 	 */
91862a764e1SPhilipp Zabel 	switch (decoder->mbus_type) {
91962a764e1SPhilipp Zabel 	case V4L2_MBUS_PARALLEL:
9208a7441baSMarco Felsch 		/* 8-bit 4:2:2 YUV with discrete sync output */
9218a7441baSMarco Felsch 		regmap_update_bits(decoder->regmap, TVP5150_DATA_RATE_SEL,
9228a7441baSMarco Felsch 				   0x7, 0x0);
92362a764e1SPhilipp Zabel 		decoder->oe = TVP5150_MISC_CTL_YCBCR_OE |
92462a764e1SPhilipp Zabel 			      TVP5150_MISC_CTL_CLOCK_OE |
92562a764e1SPhilipp Zabel 			      TVP5150_MISC_CTL_SYNC_OE;
92662a764e1SPhilipp Zabel 		break;
92762a764e1SPhilipp Zabel 	case V4L2_MBUS_BT656:
92862a764e1SPhilipp Zabel 		decoder->oe = TVP5150_MISC_CTL_YCBCR_OE |
92962a764e1SPhilipp Zabel 			      TVP5150_MISC_CTL_CLOCK_OE;
93062a764e1SPhilipp Zabel 		break;
93162a764e1SPhilipp Zabel 	default:
93262a764e1SPhilipp Zabel 		return -EINVAL;
93362a764e1SPhilipp Zabel 	}
934a2e5f1b3SJavier Martinez Canillas 
935cb7a01acSMauro Carvalho Chehab 	return 0;
936cb7a01acSMauro Carvalho Chehab };
937cb7a01acSMauro Carvalho Chehab 
938cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
939cb7a01acSMauro Carvalho Chehab {
940cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = to_sd(ctrl);
941c43875f6SMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
942cb7a01acSMauro Carvalho Chehab 
943cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
944cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
94528b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_BRIGHT_CTL, ctrl->val);
946cb7a01acSMauro Carvalho Chehab 		return 0;
947cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
94828b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_CONTRAST_CTL, ctrl->val);
949cb7a01acSMauro Carvalho Chehab 		return 0;
950cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
95128b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_SATURATION_CTL,
95228b9e227SPhilipp Zabel 			     ctrl->val);
953cb7a01acSMauro Carvalho Chehab 		return 0;
954cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_HUE:
95528b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_HUE_CTL, ctrl->val);
9562d29bcc8SMarco Felsch 		return 0;
957c43875f6SMauro Carvalho Chehab 	case V4L2_CID_TEST_PATTERN:
958c43875f6SMauro Carvalho Chehab 		decoder->enable = ctrl->val ? false : true;
959c43875f6SMauro Carvalho Chehab 		tvp5150_selmux(sd);
960cb7a01acSMauro Carvalho Chehab 		return 0;
961cb7a01acSMauro Carvalho Chehab 	}
962cb7a01acSMauro Carvalho Chehab 	return -EINVAL;
963cb7a01acSMauro Carvalho Chehab }
964cb7a01acSMauro Carvalho Chehab 
9655cb82940SMarco Felsch static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
9665cb82940SMarco Felsch {
9675cb82940SMarco Felsch 	/* Default is no cropping */
9685cb82940SMarco Felsch 	crop->top = 0;
9695cb82940SMarco Felsch 	crop->left = 0;
9705cb82940SMarco Felsch 	crop->width = TVP5150_H_MAX;
9715cb82940SMarco Felsch 	if (std & V4L2_STD_525_60)
9725cb82940SMarco Felsch 		crop->height = TVP5150_V_MAX_525_60;
9735cb82940SMarco Felsch 	else
9745cb82940SMarco Felsch 		crop->height = TVP5150_V_MAX_OTHERS;
9755cb82940SMarco Felsch }
9765cb82940SMarco Felsch 
977da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
978da298c6dSHans Verkuil 			    struct v4l2_subdev_pad_config *cfg,
979da298c6dSHans Verkuil 			    struct v4l2_subdev_format *format)
980cb7a01acSMauro Carvalho Chehab {
981da298c6dSHans Verkuil 	struct v4l2_mbus_framefmt *f;
982cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
983cb7a01acSMauro Carvalho Chehab 
984bc322c0dSMauro Carvalho Chehab 	if (!format || (format->pad != TVP5150_PAD_VID_OUT))
985cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
986cb7a01acSMauro Carvalho Chehab 
987da298c6dSHans Verkuil 	f = &format->format;
988da298c6dSHans Verkuil 
989cb7a01acSMauro Carvalho Chehab 	f->width = decoder->rect.width;
9901831af09SJavier Martinez Canillas 	f->height = decoder->rect.height / 2;
991cb7a01acSMauro Carvalho Chehab 
9925cb82940SMarco Felsch 	f->code = TVP5150_MBUS_FMT;
9935cb82940SMarco Felsch 	f->field = TVP5150_FIELD;
9945cb82940SMarco Felsch 	f->colorspace = TVP5150_COLORSPACE;
995cb7a01acSMauro Carvalho Chehab 
996257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width,
997cb7a01acSMauro Carvalho Chehab 		    f->height);
998cb7a01acSMauro Carvalho Chehab 	return 0;
999cb7a01acSMauro Carvalho Chehab }
1000cb7a01acSMauro Carvalho Chehab 
100110d5509cSHans Verkuil static int tvp5150_set_selection(struct v4l2_subdev *sd,
100210d5509cSHans Verkuil 				 struct v4l2_subdev_pad_config *cfg,
100310d5509cSHans Verkuil 				 struct v4l2_subdev_selection *sel)
1004cb7a01acSMauro Carvalho Chehab {
1005cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
100610d5509cSHans Verkuil 	struct v4l2_rect rect = sel->r;
1007cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std;
100810d5509cSHans Verkuil 	int hmax;
100910d5509cSHans Verkuil 
101010d5509cSHans Verkuil 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
101110d5509cSHans Verkuil 	    sel->target != V4L2_SEL_TGT_CROP)
101210d5509cSHans Verkuil 		return -EINVAL;
1013cb7a01acSMauro Carvalho Chehab 
1014257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
1015cb7a01acSMauro Carvalho Chehab 		__func__, rect.left, rect.top, rect.width, rect.height);
1016cb7a01acSMauro Carvalho Chehab 
1017cb7a01acSMauro Carvalho Chehab 	/* tvp5150 has some special limits */
1018cb7a01acSMauro Carvalho Chehab 	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
1019cb7a01acSMauro Carvalho Chehab 	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
1020cb7a01acSMauro Carvalho Chehab 
1021cb7a01acSMauro Carvalho Chehab 	/* Calculate height based on current standard */
1022cb7a01acSMauro Carvalho Chehab 	if (decoder->norm == V4L2_STD_ALL)
1023cb7a01acSMauro Carvalho Chehab 		std = tvp5150_read_std(sd);
1024cb7a01acSMauro Carvalho Chehab 	else
1025cb7a01acSMauro Carvalho Chehab 		std = decoder->norm;
1026cb7a01acSMauro Carvalho Chehab 
1027cb7a01acSMauro Carvalho Chehab 	if (std & V4L2_STD_525_60)
1028cb7a01acSMauro Carvalho Chehab 		hmax = TVP5150_V_MAX_525_60;
1029cb7a01acSMauro Carvalho Chehab 	else
1030cb7a01acSMauro Carvalho Chehab 		hmax = TVP5150_V_MAX_OTHERS;
1031cb7a01acSMauro Carvalho Chehab 
1032bd24db04SMarco Felsch 	/*
1033bd24db04SMarco Felsch 	 * alignments:
1034bd24db04SMarco Felsch 	 *  - width = 2 due to UYVY colorspace
1035bd24db04SMarco Felsch 	 *  - height, image = no special alignment
1036bd24db04SMarco Felsch 	 */
1037bd24db04SMarco Felsch 	v4l_bound_align_image(&rect.width,
1038bd24db04SMarco Felsch 			      TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
1039bd24db04SMarco Felsch 			      TVP5150_H_MAX - rect.left, 1, &rect.height,
1040cb7a01acSMauro Carvalho Chehab 			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
1041bd24db04SMarco Felsch 			      hmax - rect.top, 0, 0);
1042cb7a01acSMauro Carvalho Chehab 
104328b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
104428b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
1045cb7a01acSMauro Carvalho Chehab 		     rect.top + rect.height - hmax);
104628b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
1047cb7a01acSMauro Carvalho Chehab 		     rect.left >> TVP5150_CROP_SHIFT);
104828b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
1049cb7a01acSMauro Carvalho Chehab 		     rect.left | (1 << TVP5150_CROP_SHIFT));
105028b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
1051cb7a01acSMauro Carvalho Chehab 		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
1052cb7a01acSMauro Carvalho Chehab 		     TVP5150_CROP_SHIFT);
105328b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
1054cb7a01acSMauro Carvalho Chehab 		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
1055cb7a01acSMauro Carvalho Chehab 
1056cb7a01acSMauro Carvalho Chehab 	decoder->rect = rect;
1057cb7a01acSMauro Carvalho Chehab 
1058cb7a01acSMauro Carvalho Chehab 	return 0;
1059cb7a01acSMauro Carvalho Chehab }
1060cb7a01acSMauro Carvalho Chehab 
106110d5509cSHans Verkuil static int tvp5150_get_selection(struct v4l2_subdev *sd,
106210d5509cSHans Verkuil 				 struct v4l2_subdev_pad_config *cfg,
106310d5509cSHans Verkuil 				 struct v4l2_subdev_selection *sel)
1064cb7a01acSMauro Carvalho Chehab {
106510d5509cSHans Verkuil 	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
1066cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std;
1067cb7a01acSMauro Carvalho Chehab 
106810d5509cSHans Verkuil 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
1069cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1070cb7a01acSMauro Carvalho Chehab 
107110d5509cSHans Verkuil 	switch (sel->target) {
107210d5509cSHans Verkuil 	case V4L2_SEL_TGT_CROP_BOUNDS:
107310d5509cSHans Verkuil 	case V4L2_SEL_TGT_CROP_DEFAULT:
107410d5509cSHans Verkuil 		sel->r.left = 0;
107510d5509cSHans Verkuil 		sel->r.top = 0;
107610d5509cSHans Verkuil 		sel->r.width = TVP5150_H_MAX;
1077cb7a01acSMauro Carvalho Chehab 
1078cb7a01acSMauro Carvalho Chehab 		/* Calculate height based on current standard */
1079cb7a01acSMauro Carvalho Chehab 		if (decoder->norm == V4L2_STD_ALL)
1080cb7a01acSMauro Carvalho Chehab 			std = tvp5150_read_std(sd);
1081cb7a01acSMauro Carvalho Chehab 		else
1082cb7a01acSMauro Carvalho Chehab 			std = decoder->norm;
1083cb7a01acSMauro Carvalho Chehab 		if (std & V4L2_STD_525_60)
108410d5509cSHans Verkuil 			sel->r.height = TVP5150_V_MAX_525_60;
1085cb7a01acSMauro Carvalho Chehab 		else
108610d5509cSHans Verkuil 			sel->r.height = TVP5150_V_MAX_OTHERS;
1087cb7a01acSMauro Carvalho Chehab 		return 0;
108810d5509cSHans Verkuil 	case V4L2_SEL_TGT_CROP:
108910d5509cSHans Verkuil 		sel->r = decoder->rect;
109010d5509cSHans Verkuil 		return 0;
109110d5509cSHans Verkuil 	default:
109210d5509cSHans Verkuil 		return -EINVAL;
109310d5509cSHans Verkuil 	}
1094cb7a01acSMauro Carvalho Chehab }
1095cb7a01acSMauro Carvalho Chehab 
1096dd3a46bbSLaurent Pinchart static int tvp5150_g_mbus_config(struct v4l2_subdev *sd,
1097dd3a46bbSLaurent Pinchart 				 struct v4l2_mbus_config *cfg)
1098dd3a46bbSLaurent Pinchart {
1099a2e5f1b3SJavier Martinez Canillas 	struct tvp5150 *decoder = to_tvp5150(sd);
1100a2e5f1b3SJavier Martinez Canillas 
1101a2e5f1b3SJavier Martinez Canillas 	cfg->type = decoder->mbus_type;
1102dd3a46bbSLaurent Pinchart 	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING
1103dd3a46bbSLaurent Pinchart 		   | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH;
1104dd3a46bbSLaurent Pinchart 
1105dd3a46bbSLaurent Pinchart 	return 0;
1106dd3a46bbSLaurent Pinchart }
1107dd3a46bbSLaurent Pinchart 
1108cb7a01acSMauro Carvalho Chehab /****************************************************************************
1109e545ac87SLaurent Pinchart 			V4L2 subdev pad ops
1110e545ac87SLaurent Pinchart  ****************************************************************************/
1111b440b733SPhilipp Zabel static int tvp5150_init_cfg(struct v4l2_subdev *sd,
1112b440b733SPhilipp Zabel 			    struct v4l2_subdev_pad_config *cfg)
1113b440b733SPhilipp Zabel {
1114b440b733SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
1115b440b733SPhilipp Zabel 	v4l2_std_id std;
1116b440b733SPhilipp Zabel 
1117b440b733SPhilipp Zabel 	/*
1118b440b733SPhilipp Zabel 	 * Reset selection to maximum on subdev_open() if autodetection is on
1119b440b733SPhilipp Zabel 	 * and a standard change is detected.
1120b440b733SPhilipp Zabel 	 */
1121b440b733SPhilipp Zabel 	if (decoder->norm == V4L2_STD_ALL) {
1122b440b733SPhilipp Zabel 		std = tvp5150_read_std(sd);
1123b440b733SPhilipp Zabel 		if (std != decoder->detected_norm) {
1124b440b733SPhilipp Zabel 			decoder->detected_norm = std;
1125b440b733SPhilipp Zabel 			tvp5150_set_default(std, &decoder->rect);
1126b440b733SPhilipp Zabel 		}
1127b440b733SPhilipp Zabel 	}
1128b440b733SPhilipp Zabel 
1129b440b733SPhilipp Zabel 	return 0;
1130b440b733SPhilipp Zabel }
1131b440b733SPhilipp Zabel 
1132e545ac87SLaurent Pinchart static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
1133e545ac87SLaurent Pinchart 		struct v4l2_subdev_pad_config *cfg,
1134e545ac87SLaurent Pinchart 		struct v4l2_subdev_mbus_code_enum *code)
1135e545ac87SLaurent Pinchart {
1136e545ac87SLaurent Pinchart 	if (code->pad || code->index)
1137e545ac87SLaurent Pinchart 		return -EINVAL;
1138e545ac87SLaurent Pinchart 
11395cb82940SMarco Felsch 	code->code = TVP5150_MBUS_FMT;
1140e545ac87SLaurent Pinchart 	return 0;
1141e545ac87SLaurent Pinchart }
1142e545ac87SLaurent Pinchart 
1143e545ac87SLaurent Pinchart static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
1144e545ac87SLaurent Pinchart 				   struct v4l2_subdev_pad_config *cfg,
1145e545ac87SLaurent Pinchart 				   struct v4l2_subdev_frame_size_enum *fse)
1146e545ac87SLaurent Pinchart {
1147e545ac87SLaurent Pinchart 	struct tvp5150 *decoder = to_tvp5150(sd);
1148e545ac87SLaurent Pinchart 
11495cb82940SMarco Felsch 	if (fse->index >= 8 || fse->code != TVP5150_MBUS_FMT)
1150e545ac87SLaurent Pinchart 		return -EINVAL;
1151e545ac87SLaurent Pinchart 
11525cb82940SMarco Felsch 	fse->code = TVP5150_MBUS_FMT;
1153e545ac87SLaurent Pinchart 	fse->min_width = decoder->rect.width;
1154e545ac87SLaurent Pinchart 	fse->max_width = decoder->rect.width;
1155e545ac87SLaurent Pinchart 	fse->min_height = decoder->rect.height / 2;
1156e545ac87SLaurent Pinchart 	fse->max_height = decoder->rect.height / 2;
1157e545ac87SLaurent Pinchart 
1158e545ac87SLaurent Pinchart 	return 0;
1159e545ac87SLaurent Pinchart }
1160e545ac87SLaurent Pinchart 
1161e545ac87SLaurent Pinchart /****************************************************************************
1162f7b4b54eSJavier Martinez Canillas 			Media entity ops
1163f7b4b54eSJavier Martinez Canillas  ****************************************************************************/
1164f7b4b54eSJavier Martinez Canillas 
1165406ff67dSLaurent Pinchart #ifdef CONFIG_MEDIA_CONTROLLER
1166f7b4b54eSJavier Martinez Canillas static int tvp5150_link_setup(struct media_entity *entity,
1167f7b4b54eSJavier Martinez Canillas 			      const struct media_pad *local,
1168f7b4b54eSJavier Martinez Canillas 			      const struct media_pad *remote, u32 flags)
1169f7b4b54eSJavier Martinez Canillas {
1170f7b4b54eSJavier Martinez Canillas 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1171f7b4b54eSJavier Martinez Canillas 	struct tvp5150 *decoder = to_tvp5150(sd);
1172f7b4b54eSJavier Martinez Canillas 	int i;
1173f7b4b54eSJavier Martinez Canillas 
1174f7b4b54eSJavier Martinez Canillas 	for (i = 0; i < TVP5150_INPUT_NUM; i++) {
1175f7b4b54eSJavier Martinez Canillas 		if (remote->entity == &decoder->input_ent[i])
1176f7b4b54eSJavier Martinez Canillas 			break;
1177f7b4b54eSJavier Martinez Canillas 	}
1178f7b4b54eSJavier Martinez Canillas 
1179f7b4b54eSJavier Martinez Canillas 	/* Do nothing for entities that are not input connectors */
1180f7b4b54eSJavier Martinez Canillas 	if (i == TVP5150_INPUT_NUM)
1181f7b4b54eSJavier Martinez Canillas 		return 0;
1182f7b4b54eSJavier Martinez Canillas 
1183f7b4b54eSJavier Martinez Canillas 	decoder->input = i;
1184f7b4b54eSJavier Martinez Canillas 
1185f7b4b54eSJavier Martinez Canillas 	tvp5150_selmux(sd);
1186f7b4b54eSJavier Martinez Canillas 
1187f7b4b54eSJavier Martinez Canillas 	return 0;
1188f7b4b54eSJavier Martinez Canillas }
1189f7b4b54eSJavier Martinez Canillas 
1190f7b4b54eSJavier Martinez Canillas static const struct media_entity_operations tvp5150_sd_media_ops = {
1191f7b4b54eSJavier Martinez Canillas 	.link_setup = tvp5150_link_setup,
1192f7b4b54eSJavier Martinez Canillas };
1193406ff67dSLaurent Pinchart #endif
1194f7b4b54eSJavier Martinez Canillas 
1195f7b4b54eSJavier Martinez Canillas /****************************************************************************
1196cb7a01acSMauro Carvalho Chehab 			I2C Command
1197cb7a01acSMauro Carvalho Chehab  ****************************************************************************/
1198cb7a01acSMauro Carvalho Chehab 
1199460b6c08SLaurent Pinchart static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
1200460b6c08SLaurent Pinchart {
1201a2e5f1b3SJavier Martinez Canillas 	struct tvp5150 *decoder = to_tvp5150(sd);
12028e4c97e0SPhilipp Zabel 	unsigned int mask, val = 0, int_val = 0;
1203a2e5f1b3SJavier Martinez Canillas 
12048a7441baSMarco Felsch 	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
12058a7441baSMarco Felsch 	       TVP5150_MISC_CTL_CLOCK_OE;
120679d6205aSLaurent Pinchart 
120779d6205aSLaurent Pinchart 	if (enable) {
12081bb086bcSPhilipp Zabel 		tvp5150_enable(sd);
12091bb086bcSPhilipp Zabel 
121062a764e1SPhilipp Zabel 		/* Enable outputs if decoder is locked */
121162a764e1SPhilipp Zabel 		val = decoder->lock ? decoder->oe : 0;
12128e4c97e0SPhilipp Zabel 		int_val = TVP5150_INT_A_LOCK;
12132f0a5c65SPhilipp Zabel 		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
121479d6205aSLaurent Pinchart 	}
1215a2e5f1b3SJavier Martinez Canillas 
12168a7441baSMarco Felsch 	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
12178e4c97e0SPhilipp Zabel 	if (decoder->irq)
12188e4c97e0SPhilipp Zabel 		/* Enable / Disable lock interrupt */
12198e4c97e0SPhilipp Zabel 		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
12208e4c97e0SPhilipp Zabel 				   TVP5150_INT_A_LOCK, int_val);
1221460b6c08SLaurent Pinchart 
1222460b6c08SLaurent Pinchart 	return 0;
1223460b6c08SLaurent Pinchart }
1224460b6c08SLaurent Pinchart 
1225cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd,
1226cb7a01acSMauro Carvalho Chehab 			     u32 input, u32 output, u32 config)
1227cb7a01acSMauro Carvalho Chehab {
1228cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
1229cb7a01acSMauro Carvalho Chehab 
1230cb7a01acSMauro Carvalho Chehab 	decoder->input = input;
1231cb7a01acSMauro Carvalho Chehab 	decoder->output = output;
1232c43875f6SMauro Carvalho Chehab 
1233c43875f6SMauro Carvalho Chehab 	if (output == TVP5150_BLACK_SCREEN)
1234c43875f6SMauro Carvalho Chehab 		decoder->enable = false;
1235c43875f6SMauro Carvalho Chehab 	else
1236c43875f6SMauro Carvalho Chehab 		decoder->enable = true;
1237c43875f6SMauro Carvalho Chehab 
1238cb7a01acSMauro Carvalho Chehab 	tvp5150_selmux(sd);
1239cb7a01acSMauro Carvalho Chehab 	return 0;
1240cb7a01acSMauro Carvalho Chehab }
1241cb7a01acSMauro Carvalho Chehab 
1242cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
1243cb7a01acSMauro Carvalho Chehab {
124428b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
124528b9e227SPhilipp Zabel 
12469bfd8f88SNasser Afshin 	/*
12479bfd8f88SNasser Afshin 	 * this is for capturing 36 raw vbi lines
12489bfd8f88SNasser Afshin 	 * if there's a way to cut off the beginning 2 vbi lines
12499bfd8f88SNasser Afshin 	 * with the tvp5150 then the vbi line count could be lowered
12509bfd8f88SNasser Afshin 	 * to 17 lines/field again, although I couldn't find a register
12519bfd8f88SNasser Afshin 	 * which could do that cropping
12529bfd8f88SNasser Afshin 	 */
12539bfd8f88SNasser Afshin 
1254cb7a01acSMauro Carvalho Chehab 	if (fmt->sample_format == V4L2_PIX_FMT_GREY)
125528b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_LUMA_PROC_CTL_1, 0x70);
1256cb7a01acSMauro Carvalho Chehab 	if (fmt->count[0] == 18 && fmt->count[1] == 18) {
125728b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START,
125828b9e227SPhilipp Zabel 			     0x00);
125928b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 0x01);
1260cb7a01acSMauro Carvalho Chehab 	}
1261cb7a01acSMauro Carvalho Chehab 	return 0;
1262cb7a01acSMauro Carvalho Chehab }
1263cb7a01acSMauro Carvalho Chehab 
1264cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
1265cb7a01acSMauro Carvalho Chehab {
126628b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
1267cb7a01acSMauro Carvalho Chehab 	int i;
1268cb7a01acSMauro Carvalho Chehab 
1269cb7a01acSMauro Carvalho Chehab 	if (svbi->service_set != 0) {
1270cb7a01acSMauro Carvalho Chehab 		for (i = 0; i <= 23; i++) {
1271cb7a01acSMauro Carvalho Chehab 			svbi->service_lines[1][i] = 0;
1272cb7a01acSMauro Carvalho Chehab 			svbi->service_lines[0][i] =
12733dd6b560SMauro Carvalho Chehab 				tvp5150_set_vbi(sd, svbi->service_lines[0][i],
12743dd6b560SMauro Carvalho Chehab 						0xf0, i, 3);
1275cb7a01acSMauro Carvalho Chehab 		}
1276cb7a01acSMauro Carvalho Chehab 		/* Enables FIFO */
127728b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 1);
1278cb7a01acSMauro Carvalho Chehab 	} else {
1279cb7a01acSMauro Carvalho Chehab 		/* Disables FIFO*/
128028b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 0);
1281cb7a01acSMauro Carvalho Chehab 
1282cb7a01acSMauro Carvalho Chehab 		/* Disable Full Field */
128328b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_FULL_FIELD_ENA, 0);
1284cb7a01acSMauro Carvalho Chehab 
1285cb7a01acSMauro Carvalho Chehab 		/* Disable Line modes */
1286cb7a01acSMauro Carvalho Chehab 		for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
128728b9e227SPhilipp Zabel 			regmap_write(decoder->regmap, i, 0xff);
1288cb7a01acSMauro Carvalho Chehab 	}
1289cb7a01acSMauro Carvalho Chehab 	return 0;
1290cb7a01acSMauro Carvalho Chehab }
1291cb7a01acSMauro Carvalho Chehab 
1292cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
1293cb7a01acSMauro Carvalho Chehab {
1294cb7a01acSMauro Carvalho Chehab 	int i, mask = 0;
1295cb7a01acSMauro Carvalho Chehab 
129630634e8eSHans Verkuil 	memset(svbi->service_lines, 0, sizeof(svbi->service_lines));
1297cb7a01acSMauro Carvalho Chehab 
1298cb7a01acSMauro Carvalho Chehab 	for (i = 0; i <= 23; i++) {
1299cb7a01acSMauro Carvalho Chehab 		svbi->service_lines[0][i] =
13003dd6b560SMauro Carvalho Chehab 			tvp5150_get_vbi(sd, i);
1301cb7a01acSMauro Carvalho Chehab 		mask |= svbi->service_lines[0][i];
1302cb7a01acSMauro Carvalho Chehab 	}
1303cb7a01acSMauro Carvalho Chehab 	svbi->service_set = mask;
1304cb7a01acSMauro Carvalho Chehab 	return 0;
1305cb7a01acSMauro Carvalho Chehab }
1306cb7a01acSMauro Carvalho Chehab 
1307cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
1308cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
1309cb7a01acSMauro Carvalho Chehab {
1310cb7a01acSMauro Carvalho Chehab 	int res;
1311cb7a01acSMauro Carvalho Chehab 
1312cb7a01acSMauro Carvalho Chehab 	res = tvp5150_read(sd, reg->reg & 0xff);
1313cb7a01acSMauro Carvalho Chehab 	if (res < 0) {
1314257e29f8SMauro Carvalho Chehab 		dev_err(sd->dev, "%s: failed with error = %d\n", __func__, res);
1315cb7a01acSMauro Carvalho Chehab 		return res;
1316cb7a01acSMauro Carvalho Chehab 	}
1317cb7a01acSMauro Carvalho Chehab 
1318cb7a01acSMauro Carvalho Chehab 	reg->val = res;
1319cb7a01acSMauro Carvalho Chehab 	reg->size = 1;
1320cb7a01acSMauro Carvalho Chehab 	return 0;
1321cb7a01acSMauro Carvalho Chehab }
1322cb7a01acSMauro Carvalho Chehab 
1323977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
1324cb7a01acSMauro Carvalho Chehab {
132528b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
132628b9e227SPhilipp Zabel 
132728b9e227SPhilipp Zabel 	return regmap_write(decoder->regmap, reg->reg & 0xff, reg->val & 0xff);
1328cb7a01acSMauro Carvalho Chehab }
1329cb7a01acSMauro Carvalho Chehab #endif
1330cb7a01acSMauro Carvalho Chehab 
1331cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1332cb7a01acSMauro Carvalho Chehab {
1333cb7a01acSMauro Carvalho Chehab 	int status = tvp5150_read(sd, 0x88);
1334cb7a01acSMauro Carvalho Chehab 
1335cb7a01acSMauro Carvalho Chehab 	vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
1336cb7a01acSMauro Carvalho Chehab 	return 0;
1337cb7a01acSMauro Carvalho Chehab }
1338cb7a01acSMauro Carvalho Chehab 
13395a08bc00SJavier Martinez Canillas static int tvp5150_registered(struct v4l2_subdev *sd)
1340f7b4b54eSJavier Martinez Canillas {
1341f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER
1342f7b4b54eSJavier Martinez Canillas 	struct tvp5150 *decoder = to_tvp5150(sd);
1343f7b4b54eSJavier Martinez Canillas 	int ret = 0;
1344f7b4b54eSJavier Martinez Canillas 	int i;
1345f7b4b54eSJavier Martinez Canillas 
1346f7b4b54eSJavier Martinez Canillas 	for (i = 0; i < TVP5150_INPUT_NUM; i++) {
1347f7b4b54eSJavier Martinez Canillas 		struct media_entity *input = &decoder->input_ent[i];
1348f7b4b54eSJavier Martinez Canillas 		struct media_pad *pad = &decoder->input_pad[i];
1349f7b4b54eSJavier Martinez Canillas 
1350f7b4b54eSJavier Martinez Canillas 		if (!input->name)
1351f7b4b54eSJavier Martinez Canillas 			continue;
1352f7b4b54eSJavier Martinez Canillas 
1353f7b4b54eSJavier Martinez Canillas 		decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
1354f7b4b54eSJavier Martinez Canillas 
1355f7b4b54eSJavier Martinez Canillas 		ret = media_entity_pads_init(input, 1, pad);
1356f7b4b54eSJavier Martinez Canillas 		if (ret < 0)
1357f7b4b54eSJavier Martinez Canillas 			return ret;
1358f7b4b54eSJavier Martinez Canillas 
1359f7b4b54eSJavier Martinez Canillas 		ret = media_device_register_entity(sd->v4l2_dev->mdev, input);
1360f7b4b54eSJavier Martinez Canillas 		if (ret < 0)
1361f7b4b54eSJavier Martinez Canillas 			return ret;
1362f7b4b54eSJavier Martinez Canillas 
1363f7b4b54eSJavier Martinez Canillas 		ret = media_create_pad_link(input, 0, &sd->entity,
1364bc322c0dSMauro Carvalho Chehab 					    TVP5150_PAD_IF_INPUT, 0);
1365f7b4b54eSJavier Martinez Canillas 		if (ret < 0) {
1366f7b4b54eSJavier Martinez Canillas 			media_device_unregister_entity(input);
1367f7b4b54eSJavier Martinez Canillas 			return ret;
1368f7b4b54eSJavier Martinez Canillas 		}
1369f7b4b54eSJavier Martinez Canillas 	}
1370f7b4b54eSJavier Martinez Canillas #endif
1371f7b4b54eSJavier Martinez Canillas 
1372f7b4b54eSJavier Martinez Canillas 	return 0;
1373f7b4b54eSJavier Martinez Canillas }
1374f7b4b54eSJavier Martinez Canillas 
1375cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1376cb7a01acSMauro Carvalho Chehab 
1377cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
1378cb7a01acSMauro Carvalho Chehab 	.s_ctrl = tvp5150_s_ctrl,
1379cb7a01acSMauro Carvalho Chehab };
1380cb7a01acSMauro Carvalho Chehab 
1381cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
1382cb7a01acSMauro Carvalho Chehab 	.log_status = tvp5150_log_status,
1383cb7a01acSMauro Carvalho Chehab 	.reset = tvp5150_reset,
1384cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
1385cb7a01acSMauro Carvalho Chehab 	.g_register = tvp5150_g_register,
1386cb7a01acSMauro Carvalho Chehab 	.s_register = tvp5150_s_register,
1387cb7a01acSMauro Carvalho Chehab #endif
1388cb7a01acSMauro Carvalho Chehab };
1389cb7a01acSMauro Carvalho Chehab 
1390cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
1391cb7a01acSMauro Carvalho Chehab 	.g_tuner = tvp5150_g_tuner,
1392cb7a01acSMauro Carvalho Chehab };
1393cb7a01acSMauro Carvalho Chehab 
1394cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
13958774bed9SLaurent Pinchart 	.s_std = tvp5150_s_std,
13960db87cc7SMarco Felsch 	.g_std = tvp5150_g_std,
1397ee9a6ff6SPhilipp Zabel 	.querystd = tvp5150_querystd,
1398460b6c08SLaurent Pinchart 	.s_stream = tvp5150_s_stream,
1399cb7a01acSMauro Carvalho Chehab 	.s_routing = tvp5150_s_routing,
1400dd3a46bbSLaurent Pinchart 	.g_mbus_config = tvp5150_g_mbus_config,
1401cb7a01acSMauro Carvalho Chehab };
1402cb7a01acSMauro Carvalho Chehab 
1403cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
1404cb7a01acSMauro Carvalho Chehab 	.g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap,
1405cb7a01acSMauro Carvalho Chehab 	.g_sliced_fmt = tvp5150_g_sliced_fmt,
1406cb7a01acSMauro Carvalho Chehab 	.s_sliced_fmt = tvp5150_s_sliced_fmt,
1407cb7a01acSMauro Carvalho Chehab 	.s_raw_fmt = tvp5150_s_raw_fmt,
1408cb7a01acSMauro Carvalho Chehab };
1409cb7a01acSMauro Carvalho Chehab 
1410ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
1411b440b733SPhilipp Zabel 	.init_cfg = tvp5150_init_cfg,
1412ebcff5fcSHans Verkuil 	.enum_mbus_code = tvp5150_enum_mbus_code,
1413e545ac87SLaurent Pinchart 	.enum_frame_size = tvp5150_enum_frame_size,
1414da298c6dSHans Verkuil 	.set_fmt = tvp5150_fill_fmt,
1415da298c6dSHans Verkuil 	.get_fmt = tvp5150_fill_fmt,
141610d5509cSHans Verkuil 	.get_selection = tvp5150_get_selection,
141710d5509cSHans Verkuil 	.set_selection = tvp5150_set_selection,
1418ebcff5fcSHans Verkuil };
1419ebcff5fcSHans Verkuil 
1420cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = {
1421cb7a01acSMauro Carvalho Chehab 	.core = &tvp5150_core_ops,
1422cb7a01acSMauro Carvalho Chehab 	.tuner = &tvp5150_tuner_ops,
1423cb7a01acSMauro Carvalho Chehab 	.video = &tvp5150_video_ops,
1424cb7a01acSMauro Carvalho Chehab 	.vbi = &tvp5150_vbi_ops,
1425ebcff5fcSHans Verkuil 	.pad = &tvp5150_pad_ops,
1426cb7a01acSMauro Carvalho Chehab };
1427cb7a01acSMauro Carvalho Chehab 
14285a08bc00SJavier Martinez Canillas static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
14295a08bc00SJavier Martinez Canillas 	.registered = tvp5150_registered,
14305a08bc00SJavier Martinez Canillas };
14315a08bc00SJavier Martinez Canillas 
1432cb7a01acSMauro Carvalho Chehab /****************************************************************************
1433cb7a01acSMauro Carvalho Chehab 			I2C Client & Driver
1434cb7a01acSMauro Carvalho Chehab  ****************************************************************************/
1435cb7a01acSMauro Carvalho Chehab 
143628b9e227SPhilipp Zabel static const struct regmap_range tvp5150_readable_ranges[] = {
143728b9e227SPhilipp Zabel 	{
143828b9e227SPhilipp Zabel 		.range_min = TVP5150_VD_IN_SRC_SEL_1,
143928b9e227SPhilipp Zabel 		.range_max = TVP5150_AUTOSW_MSK,
144028b9e227SPhilipp Zabel 	}, {
144128b9e227SPhilipp Zabel 		.range_min = TVP5150_COLOR_KIL_THSH_CTL,
144228b9e227SPhilipp Zabel 		.range_max = TVP5150_CONF_SHARED_PIN,
144328b9e227SPhilipp Zabel 	}, {
144428b9e227SPhilipp Zabel 		.range_min = TVP5150_ACT_VD_CROP_ST_MSB,
144528b9e227SPhilipp Zabel 		.range_max = TVP5150_HORIZ_SYNC_START,
144628b9e227SPhilipp Zabel 	}, {
144728b9e227SPhilipp Zabel 		.range_min = TVP5150_VERT_BLANKING_START,
144828b9e227SPhilipp Zabel 		.range_max = TVP5150_INTT_CONFIG_REG_B,
144928b9e227SPhilipp Zabel 	}, {
145028b9e227SPhilipp Zabel 		.range_min = TVP5150_VIDEO_STD,
145128b9e227SPhilipp Zabel 		.range_max = TVP5150_VIDEO_STD,
145228b9e227SPhilipp Zabel 	}, {
145328b9e227SPhilipp Zabel 		.range_min = TVP5150_CB_GAIN_FACT,
145428b9e227SPhilipp Zabel 		.range_max = TVP5150_REV_SELECT,
145528b9e227SPhilipp Zabel 	}, {
145628b9e227SPhilipp Zabel 		.range_min = TVP5150_MSB_DEV_ID,
145728b9e227SPhilipp Zabel 		.range_max = TVP5150_STATUS_REG_5,
145828b9e227SPhilipp Zabel 	}, {
145928b9e227SPhilipp Zabel 		.range_min = TVP5150_CC_DATA_INI,
146028b9e227SPhilipp Zabel 		.range_max = TVP5150_TELETEXT_FIL_ENA,
146128b9e227SPhilipp Zabel 	}, {
146228b9e227SPhilipp Zabel 		.range_min = TVP5150_INT_STATUS_REG_A,
146328b9e227SPhilipp Zabel 		.range_max = TVP5150_FIFO_OUT_CTRL,
146428b9e227SPhilipp Zabel 	}, {
146528b9e227SPhilipp Zabel 		.range_min = TVP5150_FULL_FIELD_ENA,
146628b9e227SPhilipp Zabel 		.range_max = TVP5150_FULL_FIELD_MODE_REG,
146728b9e227SPhilipp Zabel 	},
146828b9e227SPhilipp Zabel };
146928b9e227SPhilipp Zabel 
147028b9e227SPhilipp Zabel bool tvp5150_volatile_reg(struct device *dev, unsigned int reg)
147128b9e227SPhilipp Zabel {
147228b9e227SPhilipp Zabel 	switch (reg) {
147328b9e227SPhilipp Zabel 	case TVP5150_VERT_LN_COUNT_MSB:
147428b9e227SPhilipp Zabel 	case TVP5150_VERT_LN_COUNT_LSB:
147528b9e227SPhilipp Zabel 	case TVP5150_INT_STATUS_REG_A:
147628b9e227SPhilipp Zabel 	case TVP5150_INT_STATUS_REG_B:
147728b9e227SPhilipp Zabel 	case TVP5150_INT_ACTIVE_REG_B:
147828b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_1:
147928b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_2:
148028b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_3:
148128b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_4:
148228b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_5:
148328b9e227SPhilipp Zabel 	/* CC, WSS, VPS, VITC data? */
148428b9e227SPhilipp Zabel 	case TVP5150_VBI_FIFO_READ_DATA:
148528b9e227SPhilipp Zabel 	case TVP5150_VDP_STATUS_REG:
148628b9e227SPhilipp Zabel 	case TVP5150_FIFO_WORD_COUNT:
148728b9e227SPhilipp Zabel 		return true;
148828b9e227SPhilipp Zabel 	default:
148928b9e227SPhilipp Zabel 		return false;
149028b9e227SPhilipp Zabel 	}
149128b9e227SPhilipp Zabel }
149228b9e227SPhilipp Zabel 
149328b9e227SPhilipp Zabel static const struct regmap_access_table tvp5150_readable_table = {
149428b9e227SPhilipp Zabel 	.yes_ranges = tvp5150_readable_ranges,
149528b9e227SPhilipp Zabel 	.n_yes_ranges = ARRAY_SIZE(tvp5150_readable_ranges),
149628b9e227SPhilipp Zabel };
149728b9e227SPhilipp Zabel 
149828b9e227SPhilipp Zabel static struct regmap_config tvp5150_config = {
149928b9e227SPhilipp Zabel 	.reg_bits = 8,
150028b9e227SPhilipp Zabel 	.val_bits = 8,
150128b9e227SPhilipp Zabel 	.max_register = 0xff,
150228b9e227SPhilipp Zabel 
150328b9e227SPhilipp Zabel 	.cache_type = REGCACHE_RBTREE,
150428b9e227SPhilipp Zabel 
150528b9e227SPhilipp Zabel 	.rd_table = &tvp5150_readable_table,
150628b9e227SPhilipp Zabel 	.volatile_reg = tvp5150_volatile_reg,
150728b9e227SPhilipp Zabel };
150828b9e227SPhilipp Zabel 
15097871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core)
15107871597aSLaurent Pinchart {
15117871597aSLaurent Pinchart 	struct v4l2_subdev *sd = &core->sd;
15127871597aSLaurent Pinchart 	struct i2c_client *c = v4l2_get_subdevdata(sd);
15137871597aSLaurent Pinchart 	u8 regs[4];
15147871597aSLaurent Pinchart 	int res;
15157871597aSLaurent Pinchart 
15167871597aSLaurent Pinchart 	/*
15177871597aSLaurent Pinchart 	 * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
15187871597aSLaurent Pinchart 	 * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER
15197871597aSLaurent Pinchart 	 */
152028b9e227SPhilipp Zabel 	res = regmap_bulk_read(core->regmap, TVP5150_MSB_DEV_ID, regs, 4);
152128b9e227SPhilipp Zabel 	if (res < 0) {
152228b9e227SPhilipp Zabel 		dev_err(&c->dev, "reading ID registers failed: %d\n", res);
15237871597aSLaurent Pinchart 		return res;
15247871597aSLaurent Pinchart 	}
15257871597aSLaurent Pinchart 
152682275133SJavier Martinez Canillas 	core->dev_id = (regs[0] << 8) | regs[1];
152782275133SJavier Martinez Canillas 	core->rom_ver = (regs[2] << 8) | regs[3];
15287871597aSLaurent Pinchart 
1529257e29f8SMauro Carvalho Chehab 	dev_info(sd->dev, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n",
153082275133SJavier Martinez Canillas 		  core->dev_id, regs[2], regs[3], c->addr << 1,
153182275133SJavier Martinez Canillas 		  c->adapter->name);
15327871597aSLaurent Pinchart 
153382275133SJavier Martinez Canillas 	if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) {
1534257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "tvp5150a detected.\n");
153582275133SJavier Martinez Canillas 	} else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) {
1536257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "tvp5150am1 detected.\n");
15377871597aSLaurent Pinchart 
15387871597aSLaurent Pinchart 		/* ITU-T BT.656.4 timing */
153928b9e227SPhilipp Zabel 		regmap_write(core->regmap, TVP5150_REV_SELECT, 0);
154082275133SJavier Martinez Canillas 	} else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) {
1541257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "tvp5151 detected.\n");
15427871597aSLaurent Pinchart 	} else {
1543257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "*** unknown tvp%04x chip detected.\n",
154482275133SJavier Martinez Canillas 			  core->dev_id);
15457871597aSLaurent Pinchart 	}
15467871597aSLaurent Pinchart 
15477871597aSLaurent Pinchart 	return 0;
15487871597aSLaurent Pinchart }
15497871597aSLaurent Pinchart 
155009aa2609SJavier Martinez Canillas static int tvp5150_init(struct i2c_client *c)
155109aa2609SJavier Martinez Canillas {
155209aa2609SJavier Martinez Canillas 	struct gpio_desc *pdn_gpio;
155309aa2609SJavier Martinez Canillas 	struct gpio_desc *reset_gpio;
155409aa2609SJavier Martinez Canillas 
155509aa2609SJavier Martinez Canillas 	pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH);
155609aa2609SJavier Martinez Canillas 	if (IS_ERR(pdn_gpio))
155709aa2609SJavier Martinez Canillas 		return PTR_ERR(pdn_gpio);
155809aa2609SJavier Martinez Canillas 
155909aa2609SJavier Martinez Canillas 	if (pdn_gpio) {
156009aa2609SJavier Martinez Canillas 		gpiod_set_value_cansleep(pdn_gpio, 0);
156109aa2609SJavier Martinez Canillas 		/* Delay time between power supplies active and reset */
156209aa2609SJavier Martinez Canillas 		msleep(20);
156309aa2609SJavier Martinez Canillas 	}
156409aa2609SJavier Martinez Canillas 
156509aa2609SJavier Martinez Canillas 	reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH);
156609aa2609SJavier Martinez Canillas 	if (IS_ERR(reset_gpio))
156709aa2609SJavier Martinez Canillas 		return PTR_ERR(reset_gpio);
156809aa2609SJavier Martinez Canillas 
156909aa2609SJavier Martinez Canillas 	if (reset_gpio) {
157009aa2609SJavier Martinez Canillas 		/* RESETB pulse duration */
157109aa2609SJavier Martinez Canillas 		ndelay(500);
157209aa2609SJavier Martinez Canillas 		gpiod_set_value_cansleep(reset_gpio, 0);
157309aa2609SJavier Martinez Canillas 		/* Delay time between end of reset to I2C active */
157409aa2609SJavier Martinez Canillas 		usleep_range(200, 250);
157509aa2609SJavier Martinez Canillas 	}
157609aa2609SJavier Martinez Canillas 
157709aa2609SJavier Martinez Canillas 	return 0;
157809aa2609SJavier Martinez Canillas }
157909aa2609SJavier Martinez Canillas 
1580a2e5f1b3SJavier Martinez Canillas static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
1581a2e5f1b3SJavier Martinez Canillas {
1582859969b3SSakari Ailus 	struct v4l2_fwnode_endpoint bus_cfg;
1583a2e5f1b3SJavier Martinez Canillas 	struct device_node *ep;
1584f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER
1585f7b4b54eSJavier Martinez Canillas 	struct device_node *connectors, *child;
1586f7b4b54eSJavier Martinez Canillas 	struct media_entity *input;
1587f7b4b54eSJavier Martinez Canillas 	const char *name;
1588f7b4b54eSJavier Martinez Canillas 	u32 input_type;
1589f7b4b54eSJavier Martinez Canillas #endif
1590a2e5f1b3SJavier Martinez Canillas 	unsigned int flags;
1591a2e5f1b3SJavier Martinez Canillas 	int ret = 0;
1592a2e5f1b3SJavier Martinez Canillas 
1593a2e5f1b3SJavier Martinez Canillas 	ep = of_graph_get_next_endpoint(np, NULL);
1594a2e5f1b3SJavier Martinez Canillas 	if (!ep)
1595a2e5f1b3SJavier Martinez Canillas 		return -EINVAL;
1596a2e5f1b3SJavier Martinez Canillas 
1597859969b3SSakari Ailus 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
1598a2e5f1b3SJavier Martinez Canillas 	if (ret)
1599a2e5f1b3SJavier Martinez Canillas 		goto err;
1600a2e5f1b3SJavier Martinez Canillas 
1601a2e5f1b3SJavier Martinez Canillas 	flags = bus_cfg.bus.parallel.flags;
1602a2e5f1b3SJavier Martinez Canillas 
1603a2e5f1b3SJavier Martinez Canillas 	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
1604a2e5f1b3SJavier Martinez Canillas 	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
1605a2e5f1b3SJavier Martinez Canillas 	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
16062bd5e437SJavier Martinez Canillas 	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
16072bd5e437SJavier Martinez Canillas 		ret = -EINVAL;
16082bd5e437SJavier Martinez Canillas 		goto err;
16092bd5e437SJavier Martinez Canillas 	}
1610a2e5f1b3SJavier Martinez Canillas 
1611a2e5f1b3SJavier Martinez Canillas 	decoder->mbus_type = bus_cfg.bus_type;
1612a2e5f1b3SJavier Martinez Canillas 
1613f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER
1614f7b4b54eSJavier Martinez Canillas 	connectors = of_get_child_by_name(np, "connectors");
1615f7b4b54eSJavier Martinez Canillas 
1616f7b4b54eSJavier Martinez Canillas 	if (!connectors)
1617f7b4b54eSJavier Martinez Canillas 		goto err;
1618f7b4b54eSJavier Martinez Canillas 
1619f7b4b54eSJavier Martinez Canillas 	for_each_available_child_of_node(connectors, child) {
1620f7b4b54eSJavier Martinez Canillas 		ret = of_property_read_u32(child, "input", &input_type);
1621f7b4b54eSJavier Martinez Canillas 		if (ret) {
1622257e29f8SMauro Carvalho Chehab 			dev_err(decoder->sd.dev,
1623f764e6d6SRob Herring 				 "missing type property in node %pOFn\n",
1624f764e6d6SRob Herring 				 child);
1625f7b4b54eSJavier Martinez Canillas 			goto err_connector;
1626f7b4b54eSJavier Martinez Canillas 		}
1627f7b4b54eSJavier Martinez Canillas 
162860ad7689SMauro Carvalho Chehab 		if (input_type >= TVP5150_INPUT_NUM) {
1629f7b4b54eSJavier Martinez Canillas 			ret = -EINVAL;
1630f7b4b54eSJavier Martinez Canillas 			goto err_connector;
1631f7b4b54eSJavier Martinez Canillas 		}
1632f7b4b54eSJavier Martinez Canillas 
1633f7b4b54eSJavier Martinez Canillas 		input = &decoder->input_ent[input_type];
1634f7b4b54eSJavier Martinez Canillas 
1635f7b4b54eSJavier Martinez Canillas 		/* Each input connector can only be defined once */
1636f7b4b54eSJavier Martinez Canillas 		if (input->name) {
1637257e29f8SMauro Carvalho Chehab 			dev_err(decoder->sd.dev,
1638f7b4b54eSJavier Martinez Canillas 				 "input %s with same type already exists\n",
1639f7b4b54eSJavier Martinez Canillas 				 input->name);
1640f7b4b54eSJavier Martinez Canillas 			ret = -EINVAL;
1641f7b4b54eSJavier Martinez Canillas 			goto err_connector;
1642f7b4b54eSJavier Martinez Canillas 		}
1643f7b4b54eSJavier Martinez Canillas 
1644f7b4b54eSJavier Martinez Canillas 		switch (input_type) {
1645f7b4b54eSJavier Martinez Canillas 		case TVP5150_COMPOSITE0:
1646f7b4b54eSJavier Martinez Canillas 		case TVP5150_COMPOSITE1:
1647f7b4b54eSJavier Martinez Canillas 			input->function = MEDIA_ENT_F_CONN_COMPOSITE;
1648f7b4b54eSJavier Martinez Canillas 			break;
1649f7b4b54eSJavier Martinez Canillas 		case TVP5150_SVIDEO:
1650f7b4b54eSJavier Martinez Canillas 			input->function = MEDIA_ENT_F_CONN_SVIDEO;
1651f7b4b54eSJavier Martinez Canillas 			break;
1652f7b4b54eSJavier Martinez Canillas 		}
1653f7b4b54eSJavier Martinez Canillas 
1654f7b4b54eSJavier Martinez Canillas 		input->flags = MEDIA_ENT_FL_CONNECTOR;
1655f7b4b54eSJavier Martinez Canillas 
1656f7b4b54eSJavier Martinez Canillas 		ret = of_property_read_string(child, "label", &name);
1657f7b4b54eSJavier Martinez Canillas 		if (ret < 0) {
1658257e29f8SMauro Carvalho Chehab 			dev_err(decoder->sd.dev,
1659f764e6d6SRob Herring 				 "missing label property in node %pOFn\n",
1660f764e6d6SRob Herring 				 child);
1661f7b4b54eSJavier Martinez Canillas 			goto err_connector;
1662f7b4b54eSJavier Martinez Canillas 		}
1663f7b4b54eSJavier Martinez Canillas 
1664f7b4b54eSJavier Martinez Canillas 		input->name = name;
1665f7b4b54eSJavier Martinez Canillas 	}
1666f7b4b54eSJavier Martinez Canillas 
1667f7b4b54eSJavier Martinez Canillas err_connector:
1668f7b4b54eSJavier Martinez Canillas 	of_node_put(connectors);
1669f7b4b54eSJavier Martinez Canillas #endif
1670a2e5f1b3SJavier Martinez Canillas err:
1671a2e5f1b3SJavier Martinez Canillas 	of_node_put(ep);
1672a2e5f1b3SJavier Martinez Canillas 	return ret;
1673a2e5f1b3SJavier Martinez Canillas }
1674a2e5f1b3SJavier Martinez Canillas 
1675c43875f6SMauro Carvalho Chehab static const char * const tvp5150_test_patterns[2] = {
1676c43875f6SMauro Carvalho Chehab 	"Disabled",
1677c43875f6SMauro Carvalho Chehab 	"Black screen"
1678c43875f6SMauro Carvalho Chehab };
1679c43875f6SMauro Carvalho Chehab 
1680cb7a01acSMauro Carvalho Chehab static int tvp5150_probe(struct i2c_client *c,
1681cb7a01acSMauro Carvalho Chehab 			 const struct i2c_device_id *id)
1682cb7a01acSMauro Carvalho Chehab {
1683cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *core;
1684cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
1685a2e5f1b3SJavier Martinez Canillas 	struct device_node *np = c->dev.of_node;
168628b9e227SPhilipp Zabel 	struct regmap *map;
16877871597aSLaurent Pinchart 	int res;
1688cb7a01acSMauro Carvalho Chehab 
1689cb7a01acSMauro Carvalho Chehab 	/* Check if the adapter supports the needed features */
1690cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(c->adapter,
1691cb7a01acSMauro Carvalho Chehab 	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
1692cb7a01acSMauro Carvalho Chehab 		return -EIO;
1693cb7a01acSMauro Carvalho Chehab 
169409aa2609SJavier Martinez Canillas 	res = tvp5150_init(c);
169509aa2609SJavier Martinez Canillas 	if (res)
169609aa2609SJavier Martinez Canillas 		return res;
169709aa2609SJavier Martinez Canillas 
1698c02b211dSLaurent Pinchart 	core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL);
1699c02b211dSLaurent Pinchart 	if (!core)
1700cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
1701a2e5f1b3SJavier Martinez Canillas 
170228b9e227SPhilipp Zabel 	map = devm_regmap_init_i2c(c, &tvp5150_config);
170328b9e227SPhilipp Zabel 	if (IS_ERR(map))
170428b9e227SPhilipp Zabel 		return PTR_ERR(map);
170528b9e227SPhilipp Zabel 
170628b9e227SPhilipp Zabel 	core->regmap = map;
1707cb7a01acSMauro Carvalho Chehab 	sd = &core->sd;
1708a2e5f1b3SJavier Martinez Canillas 
1709a2e5f1b3SJavier Martinez Canillas 	if (IS_ENABLED(CONFIG_OF) && np) {
1710a2e5f1b3SJavier Martinez Canillas 		res = tvp5150_parse_dt(core, np);
1711a2e5f1b3SJavier Martinez Canillas 		if (res) {
1712257e29f8SMauro Carvalho Chehab 			dev_err(sd->dev, "DT parsing error: %d\n", res);
1713a2e5f1b3SJavier Martinez Canillas 			return res;
1714a2e5f1b3SJavier Martinez Canillas 		}
1715a2e5f1b3SJavier Martinez Canillas 	} else {
1716a2e5f1b3SJavier Martinez Canillas 		/* Default to BT.656 embedded sync */
1717a2e5f1b3SJavier Martinez Canillas 		core->mbus_type = V4L2_MBUS_BT656;
1718a2e5f1b3SJavier Martinez Canillas 	}
1719a2e5f1b3SJavier Martinez Canillas 
1720cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
17215a08bc00SJavier Martinez Canillas 	sd->internal_ops = &tvp5150_internal_ops;
1722e545ac87SLaurent Pinchart 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1723e545ac87SLaurent Pinchart 
1724e545ac87SLaurent Pinchart #if defined(CONFIG_MEDIA_CONTROLLER)
1725bc322c0dSMauro Carvalho Chehab 	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
1726bc322c0dSMauro Carvalho Chehab 	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
1727bc322c0dSMauro Carvalho Chehab 	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
1728bc322c0dSMauro Carvalho Chehab 	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
1729f92c70adSMauro Carvalho Chehab 
1730f92c70adSMauro Carvalho Chehab 	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
1731f92c70adSMauro Carvalho Chehab 
1732bc322c0dSMauro Carvalho Chehab 	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
1733e545ac87SLaurent Pinchart 	if (res < 0)
1734e545ac87SLaurent Pinchart 		return res;
1735f7b4b54eSJavier Martinez Canillas 
1736f7b4b54eSJavier Martinez Canillas 	sd->entity.ops = &tvp5150_sd_media_ops;
1737e545ac87SLaurent Pinchart #endif
1738cb7a01acSMauro Carvalho Chehab 
17397871597aSLaurent Pinchart 	res = tvp5150_detect_version(core);
1740cb7a01acSMauro Carvalho Chehab 	if (res < 0)
1741c02b211dSLaurent Pinchart 		return res;
1742cb7a01acSMauro Carvalho Chehab 
1743cb7a01acSMauro Carvalho Chehab 	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
1744b440b733SPhilipp Zabel 	core->detected_norm = V4L2_STD_UNKNOWN;
1745cb7a01acSMauro Carvalho Chehab 	core->input = TVP5150_COMPOSITE1;
1746c43875f6SMauro Carvalho Chehab 	core->enable = true;
1747cb7a01acSMauro Carvalho Chehab 
1748b1950b8dSLaurent Pinchart 	v4l2_ctrl_handler_init(&core->hdl, 5);
1749cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
1750cb7a01acSMauro Carvalho Chehab 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1751cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
1752cb7a01acSMauro Carvalho Chehab 			V4L2_CID_CONTRAST, 0, 255, 1, 128);
1753cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
1754cb7a01acSMauro Carvalho Chehab 			V4L2_CID_SATURATION, 0, 255, 1, 128);
1755cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
1756cb7a01acSMauro Carvalho Chehab 			V4L2_CID_HUE, -128, 127, 1, 0);
1757b1950b8dSLaurent Pinchart 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
1758b1950b8dSLaurent Pinchart 			V4L2_CID_PIXEL_RATE, 27000000,
1759b1950b8dSLaurent Pinchart 			27000000, 1, 27000000);
1760c43875f6SMauro Carvalho Chehab 	v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops,
1761c43875f6SMauro Carvalho Chehab 				     V4L2_CID_TEST_PATTERN,
17625c4c4505SMauro Carvalho Chehab 				     ARRAY_SIZE(tvp5150_test_patterns) - 1,
1763c43875f6SMauro Carvalho Chehab 				     0, 0, tvp5150_test_patterns);
1764cb7a01acSMauro Carvalho Chehab 	sd->ctrl_handler = &core->hdl;
1765cb7a01acSMauro Carvalho Chehab 	if (core->hdl.error) {
1766cb7a01acSMauro Carvalho Chehab 		res = core->hdl.error;
1767c7d97499SJavier Martinez Canillas 		goto err;
1768cb7a01acSMauro Carvalho Chehab 	}
1769cb7a01acSMauro Carvalho Chehab 
17705cb82940SMarco Felsch 	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
1771cb7a01acSMauro Carvalho Chehab 
17728e4c97e0SPhilipp Zabel 	core->irq = c->irq;
1773aff808e8SLaurent Pinchart 	tvp5150_reset(sd, 0);	/* Calls v4l2_ctrl_handler_setup() */
17748e4c97e0SPhilipp Zabel 	if (c->irq) {
17758e4c97e0SPhilipp Zabel 		res = devm_request_threaded_irq(&c->dev, c->irq, NULL,
17768e4c97e0SPhilipp Zabel 						tvp5150_isr, IRQF_TRIGGER_HIGH |
17778e4c97e0SPhilipp Zabel 						IRQF_ONESHOT, "tvp5150", core);
17788e4c97e0SPhilipp Zabel 		if (res)
17798e4c97e0SPhilipp Zabel 			return res;
17808e4c97e0SPhilipp Zabel 	} else {
17818e4c97e0SPhilipp Zabel 		core->lock = true;
17828e4c97e0SPhilipp Zabel 	}
1783aff808e8SLaurent Pinchart 
1784c7d97499SJavier Martinez Canillas 	res = v4l2_async_register_subdev(sd);
1785c7d97499SJavier Martinez Canillas 	if (res < 0)
1786c7d97499SJavier Martinez Canillas 		goto err;
1787c7d97499SJavier Martinez Canillas 
1788cb7a01acSMauro Carvalho Chehab 	if (debug > 1)
1789cb7a01acSMauro Carvalho Chehab 		tvp5150_log_status(sd);
1790cb7a01acSMauro Carvalho Chehab 	return 0;
1791c7d97499SJavier Martinez Canillas 
1792c7d97499SJavier Martinez Canillas err:
1793c7d97499SJavier Martinez Canillas 	v4l2_ctrl_handler_free(&core->hdl);
1794c7d97499SJavier Martinez Canillas 	return res;
1795cb7a01acSMauro Carvalho Chehab }
1796cb7a01acSMauro Carvalho Chehab 
1797cb7a01acSMauro Carvalho Chehab static int tvp5150_remove(struct i2c_client *c)
1798cb7a01acSMauro Carvalho Chehab {
1799cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(c);
1800cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
1801cb7a01acSMauro Carvalho Chehab 
1802257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug,
1803cb7a01acSMauro Carvalho Chehab 		"tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
1804cb7a01acSMauro Carvalho Chehab 		c->addr << 1);
1805cb7a01acSMauro Carvalho Chehab 
1806c7d97499SJavier Martinez Canillas 	v4l2_async_unregister_subdev(sd);
1807cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_free(&decoder->hdl);
1808cb7a01acSMauro Carvalho Chehab 	return 0;
1809cb7a01acSMauro Carvalho Chehab }
1810cb7a01acSMauro Carvalho Chehab 
1811cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1812cb7a01acSMauro Carvalho Chehab 
1813cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = {
1814cb7a01acSMauro Carvalho Chehab 	{ "tvp5150", 0 },
1815cb7a01acSMauro Carvalho Chehab 	{ }
1816cb7a01acSMauro Carvalho Chehab };
1817cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id);
1818cb7a01acSMauro Carvalho Chehab 
18197ef930a7SEduard Gavin #if IS_ENABLED(CONFIG_OF)
18207ef930a7SEduard Gavin static const struct of_device_id tvp5150_of_match[] = {
18217ef930a7SEduard Gavin 	{ .compatible = "ti,tvp5150", },
18227ef930a7SEduard Gavin 	{ /* sentinel */ },
18237ef930a7SEduard Gavin };
18247ef930a7SEduard Gavin MODULE_DEVICE_TABLE(of, tvp5150_of_match);
18257ef930a7SEduard Gavin #endif
18267ef930a7SEduard Gavin 
1827cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = {
1828cb7a01acSMauro Carvalho Chehab 	.driver = {
18297ef930a7SEduard Gavin 		.of_match_table = of_match_ptr(tvp5150_of_match),
1830cb7a01acSMauro Carvalho Chehab 		.name	= "tvp5150",
1831cb7a01acSMauro Carvalho Chehab 	},
1832cb7a01acSMauro Carvalho Chehab 	.probe		= tvp5150_probe,
1833cb7a01acSMauro Carvalho Chehab 	.remove		= tvp5150_remove,
1834cb7a01acSMauro Carvalho Chehab 	.id_table	= tvp5150_id,
1835cb7a01acSMauro Carvalho Chehab };
1836cb7a01acSMauro Carvalho Chehab 
1837cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver);
1838