xref: /openbmc/linux/drivers/media/i2c/tvp5150.c (revision 26ce7054)
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>
1673549a69SMarco Felsch #include <linux/pm_runtime.h>
1728b9e227SPhilipp Zabel #include <linux/regmap.h>
18c7d97499SJavier Martinez Canillas #include <media/v4l2-async.h>
19cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
20e953c103SMarco Felsch #include <media/v4l2-event.h>
21cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
22859969b3SSakari Ailus #include <media/v4l2-fwnode.h>
2355606310SMauro Carvalho Chehab #include <media/v4l2-mc.h>
2446fe6e7dSMarco Felsch #include <media/v4l2-rect.h>
25cb7a01acSMauro Carvalho Chehab 
26cb7a01acSMauro Carvalho Chehab #include "tvp5150_reg.h"
27cb7a01acSMauro Carvalho Chehab 
28785a3de1SPhilipp Zabel #define TVP5150_H_MAX		720U
29785a3de1SPhilipp Zabel #define TVP5150_V_MAX_525_60	480U
30785a3de1SPhilipp Zabel #define TVP5150_V_MAX_OTHERS	576U
31cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_LEFT	511
32cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_TOP	127
33cb7a01acSMauro Carvalho Chehab #define TVP5150_CROP_SHIFT	2
345cb82940SMarco Felsch #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
355cb82940SMarco Felsch #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
365cb82940SMarco Felsch #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
37baf17821SMarco Felsch #define TVP5150_STD_MASK	(V4L2_STD_NTSC     | \
38baf17821SMarco Felsch 				 V4L2_STD_NTSC_443 | \
39baf17821SMarco Felsch 				 V4L2_STD_PAL      | \
40baf17821SMarco Felsch 				 V4L2_STD_PAL_M    | \
41baf17821SMarco Felsch 				 V4L2_STD_PAL_N    | \
42baf17821SMarco Felsch 				 V4L2_STD_PAL_Nc   | \
43baf17821SMarco Felsch 				 V4L2_STD_SECAM)
44cb7a01acSMauro Carvalho Chehab 
450556f1d5SMarco Felsch #define TVP5150_MAX_CONNECTORS	3 /* Check dt-bindings for more information */
460556f1d5SMarco Felsch 
47c43875f6SMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
48cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab");
49459ee17cSMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
50cb7a01acSMauro Carvalho Chehab 
51cb7a01acSMauro Carvalho Chehab 
52cb7a01acSMauro Carvalho Chehab static int debug;
532a0489d3SPhilipp Zabel module_param(debug, int, 0644);
54cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-2)");
55cb7a01acSMauro Carvalho Chehab 
56ad0e3744SMauro Carvalho Chehab #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
57ad0e3744SMauro Carvalho Chehab 
58bc322c0dSMauro Carvalho Chehab enum tvp5150_pads {
590556f1d5SMarco Felsch 	TVP5150_PAD_AIP1A,
600556f1d5SMarco Felsch 	TVP5150_PAD_AIP1B,
61bc322c0dSMauro Carvalho Chehab 	TVP5150_PAD_VID_OUT,
62bc322c0dSMauro Carvalho Chehab 	TVP5150_NUM_PADS
63bc322c0dSMauro Carvalho Chehab };
64bc322c0dSMauro Carvalho Chehab 
650556f1d5SMarco Felsch struct tvp5150_connector {
660556f1d5SMarco Felsch 	struct v4l2_fwnode_connector base;
670556f1d5SMarco Felsch 	struct media_entity ent;
680556f1d5SMarco Felsch 	struct media_pad pad;
690556f1d5SMarco Felsch };
700556f1d5SMarco Felsch 
71cb7a01acSMauro Carvalho Chehab struct tvp5150 {
72cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev sd;
730556f1d5SMarco Felsch 
74bc322c0dSMauro Carvalho Chehab 	struct media_pad pads[TVP5150_NUM_PADS];
750556f1d5SMarco Felsch 	struct tvp5150_connector connectors[TVP5150_MAX_CONNECTORS];
76baf17821SMarco Felsch 	struct tvp5150_connector *cur_connector;
770556f1d5SMarco Felsch 	unsigned int connectors_num;
780556f1d5SMarco Felsch 
79cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler hdl;
80cb7a01acSMauro Carvalho Chehab 	struct v4l2_rect rect;
8128b9e227SPhilipp Zabel 	struct regmap *regmap;
828e4c97e0SPhilipp Zabel 	int irq;
83cb7a01acSMauro Carvalho Chehab 
84cb7a01acSMauro Carvalho Chehab 	v4l2_std_id norm;	/* Current set standard */
85b440b733SPhilipp Zabel 	v4l2_std_id detected_norm;
86cb7a01acSMauro Carvalho Chehab 	u32 input;
87cb7a01acSMauro Carvalho Chehab 	u32 output;
8862a764e1SPhilipp Zabel 	u32 oe;
89cb7a01acSMauro Carvalho Chehab 	int enable;
908e4c97e0SPhilipp Zabel 	bool lock;
91a2e5f1b3SJavier Martinez Canillas 
9282275133SJavier Martinez Canillas 	u16 dev_id;
9382275133SJavier Martinez Canillas 	u16 rom_ver;
9482275133SJavier Martinez Canillas 
95a2e5f1b3SJavier Martinez Canillas 	enum v4l2_mbus_type mbus_type;
96cb7a01acSMauro Carvalho Chehab };
97cb7a01acSMauro Carvalho Chehab 
to_tvp5150(struct v4l2_subdev * sd)98cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
99cb7a01acSMauro Carvalho Chehab {
100cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct tvp5150, sd);
101cb7a01acSMauro Carvalho Chehab }
102cb7a01acSMauro Carvalho Chehab 
to_sd(struct v4l2_ctrl * ctrl)103cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
104cb7a01acSMauro Carvalho Chehab {
105cb7a01acSMauro Carvalho Chehab 	return &container_of(ctrl->handler, struct tvp5150, hdl)->sd;
106cb7a01acSMauro Carvalho Chehab }
107cb7a01acSMauro Carvalho Chehab 
tvp5150_read(struct v4l2_subdev * sd,unsigned char addr)108cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
109cb7a01acSMauro Carvalho Chehab {
11028b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
11128b9e227SPhilipp Zabel 	int ret, val;
112cb7a01acSMauro Carvalho Chehab 
11328b9e227SPhilipp Zabel 	ret = regmap_read(decoder->regmap, addr, &val);
11428b9e227SPhilipp Zabel 	if (ret < 0)
11528b9e227SPhilipp Zabel 		return ret;
116cb7a01acSMauro Carvalho Chehab 
11728b9e227SPhilipp Zabel 	return val;
118cb7a01acSMauro Carvalho Chehab }
119cb7a01acSMauro Carvalho Chehab 
dump_reg_range(struct v4l2_subdev * sd,char * s,u8 init,const u8 end,int max_line)120cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
121cb7a01acSMauro Carvalho Chehab 				const u8 end, int max_line)
122cb7a01acSMauro Carvalho Chehab {
123e5134114SMauro Carvalho Chehab 	u8 buf[16];
124e5134114SMauro Carvalho Chehab 	int i = 0, j, len;
125cb7a01acSMauro Carvalho Chehab 
126e5134114SMauro Carvalho Chehab 	if (max_line > 16) {
127e5134114SMauro Carvalho Chehab 		dprintk0(sd->dev, "too much data to dump\n");
128e5134114SMauro Carvalho Chehab 		return;
129cb7a01acSMauro Carvalho Chehab 	}
130cb7a01acSMauro Carvalho Chehab 
131e5134114SMauro Carvalho Chehab 	for (i = init; i < end; i += max_line) {
132e5134114SMauro Carvalho Chehab 		len = (end - i > max_line) ? max_line : end - i;
133e5134114SMauro Carvalho Chehab 
134e5134114SMauro Carvalho Chehab 		for (j = 0; j < len; j++)
135e5134114SMauro Carvalho Chehab 			buf[j] = tvp5150_read(sd, i + j);
136e5134114SMauro Carvalho Chehab 
137e5134114SMauro Carvalho Chehab 		dprintk0(sd->dev, "%s reg %02x = %*ph\n", s, i, len, buf);
138cb7a01acSMauro Carvalho Chehab 	}
139cb7a01acSMauro Carvalho Chehab }
140cb7a01acSMauro Carvalho Chehab 
tvp5150_log_status(struct v4l2_subdev * sd)141cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd)
142cb7a01acSMauro Carvalho Chehab {
143ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Video input source selection #1 = 0x%02x\n",
144cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1));
145ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Analog channel controls = 0x%02x\n",
146cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ANAL_CHL_CTL));
147ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Operation mode controls = 0x%02x\n",
148cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_OP_MODE_CTL));
149ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Miscellaneous controls = 0x%02x\n",
150cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MISC_CTL));
151ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Autoswitch mask= 0x%02x\n",
152cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_AUTOSW_MSK));
153ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Color killer threshold control = 0x%02x\n",
154cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL));
155ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
156cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1),
157cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2),
158cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3));
159ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Brightness control = 0x%02x\n",
160cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_BRIGHT_CTL));
161ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Color saturation control = 0x%02x\n",
162cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_SATURATION_CTL));
163ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Hue control = 0x%02x\n",
164cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_HUE_CTL));
165ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Contrast control = 0x%02x\n",
166cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CONTRAST_CTL));
167ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Outputs and data rates select = 0x%02x\n",
168cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_DATA_RATE_SEL));
169ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Configuration shared pins = 0x%02x\n",
170cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CONF_SHARED_PIN));
171ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Active video cropping start = 0x%02x%02x\n",
172cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB),
173cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB));
174ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Active video cropping stop  = 0x%02x%02x\n",
175cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB),
176cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB));
177ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Genlock/RTC = 0x%02x\n",
178cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_GENLOCK));
179ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Horizontal sync start = 0x%02x\n",
180cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_HORIZ_SYNC_START));
181ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Vertical blanking start = 0x%02x\n",
182cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_BLANKING_START));
183ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Vertical blanking stop = 0x%02x\n",
184cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP));
185ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
186cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1),
187cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2));
188ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt reset register B = 0x%02x\n",
189cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_RESET_REG_B));
190ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt enable register B = 0x%02x\n",
191cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B));
192ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt configuration register B = 0x%02x\n",
193cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B));
194ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Video standard = 0x%02x\n",
195cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VIDEO_STD));
196ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
197cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CB_GAIN_FACT),
198cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR));
199ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Macrovision on counter = 0x%02x\n",
200cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR));
201ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Macrovision off counter = 0x%02x\n",
202cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR));
203ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
204cb7a01acSMauro Carvalho Chehab 		(tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4);
205ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Device ID = %02x%02x\n",
206cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_MSB_DEV_ID),
207cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LSB_DEV_ID));
208ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: ROM version = (hex) %02x.%02x\n",
209cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ROM_MAJOR_VER),
210cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_ROM_MINOR_VER));
211ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Vertical line count = 0x%02x%02x\n",
212cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB),
213cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB));
214ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt status register B = 0x%02x\n",
215cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_STATUS_REG_B));
216ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt active register B = 0x%02x\n",
217cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B));
218ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
219cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_1),
220cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_2),
221cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_3),
222cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_4),
223cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_STATUS_REG_5));
224cb7a01acSMauro Carvalho Chehab 
225cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
226cb7a01acSMauro Carvalho Chehab 			TVP5150_TELETEXT_FIL1_END, 8);
227cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
228cb7a01acSMauro Carvalho Chehab 			TVP5150_TELETEXT_FIL2_END, 8);
229cb7a01acSMauro Carvalho Chehab 
230ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Teletext filter enable = 0x%02x\n",
231cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA));
232ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt status register A = 0x%02x\n",
233cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_STATUS_REG_A));
234ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt enable register A = 0x%02x\n",
235cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A));
236ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Interrupt configuration = 0x%02x\n",
237cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_INT_CONF));
238ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: VDP status register = 0x%02x\n",
239cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_VDP_STATUS_REG));
240ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO word count = 0x%02x\n",
241cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT));
242ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO interrupt threshold = 0x%02x\n",
243cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD));
244ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO reset = 0x%02x\n",
245cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_RESET));
246ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Line number interrupt = 0x%02x\n",
247cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_LINE_NUMBER_INT));
248ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Pixel alignment register = 0x%02x%02x\n",
249cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH),
250cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW));
251ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: FIFO output control = 0x%02x\n",
252cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL));
253ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Full field enable = 0x%02x\n",
254cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FULL_FIELD_ENA));
255ad0e3744SMauro Carvalho Chehab 	dprintk0(sd->dev, "tvp5150: Full field mode register = 0x%02x\n",
256cb7a01acSMauro Carvalho Chehab 		tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG));
257cb7a01acSMauro Carvalho Chehab 
258cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "CC   data",   TVP5150_CC_DATA_INI,
259cb7a01acSMauro Carvalho Chehab 			TVP5150_CC_DATA_END, 8);
260cb7a01acSMauro Carvalho Chehab 
261cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "WSS  data",   TVP5150_WSS_DATA_INI,
262cb7a01acSMauro Carvalho Chehab 			TVP5150_WSS_DATA_END, 8);
263cb7a01acSMauro Carvalho Chehab 
264cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "VPS  data",   TVP5150_VPS_DATA_INI,
265cb7a01acSMauro Carvalho Chehab 			TVP5150_VPS_DATA_END, 8);
266cb7a01acSMauro Carvalho Chehab 
267cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "VITC data",   TVP5150_VITC_DATA_INI,
268cb7a01acSMauro Carvalho Chehab 			TVP5150_VITC_DATA_END, 10);
269cb7a01acSMauro Carvalho Chehab 
270cb7a01acSMauro Carvalho Chehab 	dump_reg_range(sd, "Line mode",   TVP5150_LINE_MODE_INI,
271cb7a01acSMauro Carvalho Chehab 			TVP5150_LINE_MODE_END, 8);
272cb7a01acSMauro Carvalho Chehab 	return 0;
273cb7a01acSMauro Carvalho Chehab }
274cb7a01acSMauro Carvalho Chehab 
275cb7a01acSMauro Carvalho Chehab /****************************************************************************
276cb7a01acSMauro Carvalho Chehab 			Basic functions
277cb7a01acSMauro Carvalho Chehab  ****************************************************************************/
278cb7a01acSMauro Carvalho Chehab 
tvp5150_selmux(struct v4l2_subdev * sd)2796e98bee2SLaurent Pinchart static void tvp5150_selmux(struct v4l2_subdev *sd)
280cb7a01acSMauro Carvalho Chehab {
281cb7a01acSMauro Carvalho Chehab 	int opmode = 0;
282cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
2838a7441baSMarco Felsch 	unsigned int mask, val;
284cb7a01acSMauro Carvalho Chehab 	int input = 0;
285cb7a01acSMauro Carvalho Chehab 
286c43875f6SMauro Carvalho Chehab 	/* Only tvp5150am1 and tvp5151 have signal generator support */
287c43875f6SMauro Carvalho Chehab 	if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) ||
288c43875f6SMauro Carvalho Chehab 	    (decoder->dev_id == 0x5151 && decoder->rom_ver == 0x0100)) {
289c43875f6SMauro Carvalho Chehab 		if (!decoder->enable)
290cb7a01acSMauro Carvalho Chehab 			input = 8;
291c43875f6SMauro Carvalho Chehab 	}
292cb7a01acSMauro Carvalho Chehab 
293cb7a01acSMauro Carvalho Chehab 	switch (decoder->input) {
294cb7a01acSMauro Carvalho Chehab 	case TVP5150_COMPOSITE1:
295cb7a01acSMauro Carvalho Chehab 		input |= 2;
2961771e9fbSGustavo A. R. Silva 		fallthrough;
297cb7a01acSMauro Carvalho Chehab 	case TVP5150_COMPOSITE0:
298cb7a01acSMauro Carvalho Chehab 		break;
299cb7a01acSMauro Carvalho Chehab 	case TVP5150_SVIDEO:
300cb7a01acSMauro Carvalho Chehab 	default:
301cb7a01acSMauro Carvalho Chehab 		input |= 1;
302cb7a01acSMauro Carvalho Chehab 		break;
303cb7a01acSMauro Carvalho Chehab 	}
304cb7a01acSMauro Carvalho Chehab 
305430f35b7SMarco Felsch 	dev_dbg_lvl(sd->dev, 1, debug,
306430f35b7SMarco Felsch 		    "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n",
307430f35b7SMarco Felsch 		    decoder->input == 0 ? "aip1a" :
308430f35b7SMarco Felsch 		    decoder->input == 2 ? "aip1b" : "svideo",
309430f35b7SMarco Felsch 		    decoder->output == 0 ? "normal" : "black-frame-gen",
310cb7a01acSMauro Carvalho Chehab 		    input, opmode);
311cb7a01acSMauro Carvalho Chehab 
31228b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
31328b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
314cb7a01acSMauro Carvalho Chehab 
315b4b2de38SLaurent Pinchart 	/*
316b4b2de38SLaurent Pinchart 	 * Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For
317b4b2de38SLaurent Pinchart 	 * S-Video we output the vertical lock (VLK) signal on FID/GLCO/VLK/HVLK
318b4b2de38SLaurent Pinchart 	 * and set INTREQ/GPCL/VBLK to logic 0. For composite we output the
319b4b2de38SLaurent Pinchart 	 * field indicator (FID) signal on FID/GLCO/VLK/HVLK and set
320b4b2de38SLaurent Pinchart 	 * INTREQ/GPCL/VBLK to logic 1.
321cb7a01acSMauro Carvalho Chehab 	 */
3228a7441baSMarco Felsch 	mask = TVP5150_MISC_CTL_GPCL | TVP5150_MISC_CTL_HVLK;
323cb7a01acSMauro Carvalho Chehab 	if (decoder->input == TVP5150_SVIDEO)
3248a7441baSMarco Felsch 		val = TVP5150_MISC_CTL_HVLK;
325cb7a01acSMauro Carvalho Chehab 	else
3268a7441baSMarco Felsch 		val = TVP5150_MISC_CTL_GPCL;
3278a7441baSMarco Felsch 	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
328cb7a01acSMauro Carvalho Chehab };
329cb7a01acSMauro Carvalho Chehab 
330cb7a01acSMauro Carvalho Chehab struct i2c_reg_value {
331cb7a01acSMauro Carvalho Chehab 	unsigned char reg;
332cb7a01acSMauro Carvalho Chehab 	unsigned char value;
333cb7a01acSMauro Carvalho Chehab };
334cb7a01acSMauro Carvalho Chehab 
335cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */
336cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = {
337cb7a01acSMauro Carvalho Chehab 	{ /* 0x00 */
338cb7a01acSMauro Carvalho Chehab 		TVP5150_VD_IN_SRC_SEL_1, 0x00
339cb7a01acSMauro Carvalho Chehab 	},
340cb7a01acSMauro Carvalho Chehab 	{ /* 0x01 */
341cb7a01acSMauro Carvalho Chehab 		TVP5150_ANAL_CHL_CTL, 0x15
342cb7a01acSMauro Carvalho Chehab 	},
343cb7a01acSMauro Carvalho Chehab 	{ /* 0x02 */
344cb7a01acSMauro Carvalho Chehab 		TVP5150_OP_MODE_CTL, 0x00
345cb7a01acSMauro Carvalho Chehab 	},
346cb7a01acSMauro Carvalho Chehab 	{ /* 0x03 */
347cb7a01acSMauro Carvalho Chehab 		TVP5150_MISC_CTL, 0x01
348cb7a01acSMauro Carvalho Chehab 	},
349cb7a01acSMauro Carvalho Chehab 	{ /* 0x06 */
350cb7a01acSMauro Carvalho Chehab 		TVP5150_COLOR_KIL_THSH_CTL, 0x10
351cb7a01acSMauro Carvalho Chehab 	},
352cb7a01acSMauro Carvalho Chehab 	{ /* 0x07 */
353cb7a01acSMauro Carvalho Chehab 		TVP5150_LUMA_PROC_CTL_1, 0x60
354cb7a01acSMauro Carvalho Chehab 	},
355cb7a01acSMauro Carvalho Chehab 	{ /* 0x08 */
356cb7a01acSMauro Carvalho Chehab 		TVP5150_LUMA_PROC_CTL_2, 0x00
357cb7a01acSMauro Carvalho Chehab 	},
358cb7a01acSMauro Carvalho Chehab 	{ /* 0x09 */
359cb7a01acSMauro Carvalho Chehab 		TVP5150_BRIGHT_CTL, 0x80
360cb7a01acSMauro Carvalho Chehab 	},
361cb7a01acSMauro Carvalho Chehab 	{ /* 0x0a */
362cb7a01acSMauro Carvalho Chehab 		TVP5150_SATURATION_CTL, 0x80
363cb7a01acSMauro Carvalho Chehab 	},
364cb7a01acSMauro Carvalho Chehab 	{ /* 0x0b */
365cb7a01acSMauro Carvalho Chehab 		TVP5150_HUE_CTL, 0x00
366cb7a01acSMauro Carvalho Chehab 	},
367cb7a01acSMauro Carvalho Chehab 	{ /* 0x0c */
368cb7a01acSMauro Carvalho Chehab 		TVP5150_CONTRAST_CTL, 0x80
369cb7a01acSMauro Carvalho Chehab 	},
370cb7a01acSMauro Carvalho Chehab 	{ /* 0x0d */
371cb7a01acSMauro Carvalho Chehab 		TVP5150_DATA_RATE_SEL, 0x47
372cb7a01acSMauro Carvalho Chehab 	},
373cb7a01acSMauro Carvalho Chehab 	{ /* 0x0e */
374cb7a01acSMauro Carvalho Chehab 		TVP5150_LUMA_PROC_CTL_3, 0x00
375cb7a01acSMauro Carvalho Chehab 	},
376cb7a01acSMauro Carvalho Chehab 	{ /* 0x0f */
377cb7a01acSMauro Carvalho Chehab 		TVP5150_CONF_SHARED_PIN, 0x08
378cb7a01acSMauro Carvalho Chehab 	},
379cb7a01acSMauro Carvalho Chehab 	{ /* 0x11 */
380cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_ST_MSB, 0x00
381cb7a01acSMauro Carvalho Chehab 	},
382cb7a01acSMauro Carvalho Chehab 	{ /* 0x12 */
383cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_ST_LSB, 0x00
384cb7a01acSMauro Carvalho Chehab 	},
385cb7a01acSMauro Carvalho Chehab 	{ /* 0x13 */
386cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_STP_MSB, 0x00
387cb7a01acSMauro Carvalho Chehab 	},
388cb7a01acSMauro Carvalho Chehab 	{ /* 0x14 */
389cb7a01acSMauro Carvalho Chehab 		TVP5150_ACT_VD_CROP_STP_LSB, 0x00
390cb7a01acSMauro Carvalho Chehab 	},
391cb7a01acSMauro Carvalho Chehab 	{ /* 0x15 */
392cb7a01acSMauro Carvalho Chehab 		TVP5150_GENLOCK, 0x01
393cb7a01acSMauro Carvalho Chehab 	},
394cb7a01acSMauro Carvalho Chehab 	{ /* 0x16 */
395cb7a01acSMauro Carvalho Chehab 		TVP5150_HORIZ_SYNC_START, 0x80
396cb7a01acSMauro Carvalho Chehab 	},
397cb7a01acSMauro Carvalho Chehab 	{ /* 0x18 */
398cb7a01acSMauro Carvalho Chehab 		TVP5150_VERT_BLANKING_START, 0x00
399cb7a01acSMauro Carvalho Chehab 	},
400cb7a01acSMauro Carvalho Chehab 	{ /* 0x19 */
401cb7a01acSMauro Carvalho Chehab 		TVP5150_VERT_BLANKING_STOP, 0x00
402cb7a01acSMauro Carvalho Chehab 	},
403cb7a01acSMauro Carvalho Chehab 	{ /* 0x1a */
404cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_1, 0x0c
405cb7a01acSMauro Carvalho Chehab 	},
406cb7a01acSMauro Carvalho Chehab 	{ /* 0x1b */
407cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_2, 0x14
408cb7a01acSMauro Carvalho Chehab 	},
409cb7a01acSMauro Carvalho Chehab 	{ /* 0x1c */
410cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_RESET_REG_B, 0x00
411cb7a01acSMauro Carvalho Chehab 	},
412cb7a01acSMauro Carvalho Chehab 	{ /* 0x1d */
413cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_ENABLE_REG_B, 0x00
414cb7a01acSMauro Carvalho Chehab 	},
415cb7a01acSMauro Carvalho Chehab 	{ /* 0x1e */
416cb7a01acSMauro Carvalho Chehab 		TVP5150_INTT_CONFIG_REG_B, 0x00
417cb7a01acSMauro Carvalho Chehab 	},
418cb7a01acSMauro Carvalho Chehab 	{ /* 0x28 */
419cb7a01acSMauro Carvalho Chehab 		TVP5150_VIDEO_STD, 0x00
420cb7a01acSMauro Carvalho Chehab 	},
421cb7a01acSMauro Carvalho Chehab 	{ /* 0x2e */
422cb7a01acSMauro Carvalho Chehab 		TVP5150_MACROVISION_ON_CTR, 0x0f
423cb7a01acSMauro Carvalho Chehab 	},
424cb7a01acSMauro Carvalho Chehab 	{ /* 0x2f */
425cb7a01acSMauro Carvalho Chehab 		TVP5150_MACROVISION_OFF_CTR, 0x01
426cb7a01acSMauro Carvalho Chehab 	},
427cb7a01acSMauro Carvalho Chehab 	{ /* 0xbb */
428cb7a01acSMauro Carvalho Chehab 		TVP5150_TELETEXT_FIL_ENA, 0x00
429cb7a01acSMauro Carvalho Chehab 	},
430cb7a01acSMauro Carvalho Chehab 	{ /* 0xc0 */
431cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_STATUS_REG_A, 0x00
432cb7a01acSMauro Carvalho Chehab 	},
433cb7a01acSMauro Carvalho Chehab 	{ /* 0xc1 */
434cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_ENABLE_REG_A, 0x00
435cb7a01acSMauro Carvalho Chehab 	},
436cb7a01acSMauro Carvalho Chehab 	{ /* 0xc2 */
437cb7a01acSMauro Carvalho Chehab 		TVP5150_INT_CONF, 0x04
438cb7a01acSMauro Carvalho Chehab 	},
439cb7a01acSMauro Carvalho Chehab 	{ /* 0xc8 */
440cb7a01acSMauro Carvalho Chehab 		TVP5150_FIFO_INT_THRESHOLD, 0x80
441cb7a01acSMauro Carvalho Chehab 	},
442cb7a01acSMauro Carvalho Chehab 	{ /* 0xc9 */
443cb7a01acSMauro Carvalho Chehab 		TVP5150_FIFO_RESET, 0x00
444cb7a01acSMauro Carvalho Chehab 	},
445cb7a01acSMauro Carvalho Chehab 	{ /* 0xca */
446cb7a01acSMauro Carvalho Chehab 		TVP5150_LINE_NUMBER_INT, 0x00
447cb7a01acSMauro Carvalho Chehab 	},
448cb7a01acSMauro Carvalho Chehab 	{ /* 0xcb */
449cb7a01acSMauro Carvalho Chehab 		TVP5150_PIX_ALIGN_REG_LOW, 0x4e
450cb7a01acSMauro Carvalho Chehab 	},
451cb7a01acSMauro Carvalho Chehab 	{ /* 0xcc */
452cb7a01acSMauro Carvalho Chehab 		TVP5150_PIX_ALIGN_REG_HIGH, 0x00
453cb7a01acSMauro Carvalho Chehab 	},
454cb7a01acSMauro Carvalho Chehab 	{ /* 0xcd */
455cb7a01acSMauro Carvalho Chehab 		TVP5150_FIFO_OUT_CTRL, 0x01
456cb7a01acSMauro Carvalho Chehab 	},
457cb7a01acSMauro Carvalho Chehab 	{ /* 0xcf */
458cb7a01acSMauro Carvalho Chehab 		TVP5150_FULL_FIELD_ENA, 0x00
459cb7a01acSMauro Carvalho Chehab 	},
460cb7a01acSMauro Carvalho Chehab 	{ /* 0xd0 */
461cb7a01acSMauro Carvalho Chehab 		TVP5150_LINE_MODE_INI, 0x00
462cb7a01acSMauro Carvalho Chehab 	},
463cb7a01acSMauro Carvalho Chehab 	{ /* 0xfc */
464cb7a01acSMauro Carvalho Chehab 		TVP5150_FULL_FIELD_MODE_REG, 0x7f
465cb7a01acSMauro Carvalho Chehab 	},
466cb7a01acSMauro Carvalho Chehab 	{ /* end of data */
467cb7a01acSMauro Carvalho Chehab 		0xff, 0xff
468cb7a01acSMauro Carvalho Chehab 	}
469cb7a01acSMauro Carvalho Chehab };
470cb7a01acSMauro Carvalho Chehab 
471cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */
472cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = {
4738105e1bcSPhilipp Zabel 	{	/* Automatic offset and AGC enabled */
474cb7a01acSMauro Carvalho Chehab 		TVP5150_ANAL_CHL_CTL, 0x15
475cb7a01acSMauro Carvalho Chehab 	}, {	/* Activate YCrCb output 0x9 or 0xd ? */
476b4b2de38SLaurent Pinchart 		TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL |
477b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_INTREQ_OE |
478b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_YCBCR_OE |
479b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_SYNC_OE |
480b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_VBLANK |
481b4b2de38SLaurent Pinchart 				  TVP5150_MISC_CTL_CLOCK_OE,
482cb7a01acSMauro Carvalho Chehab 	}, {	/* Activates video std autodetection for all standards */
483cb7a01acSMauro Carvalho Chehab 		TVP5150_AUTOSW_MSK, 0x0
484cb7a01acSMauro Carvalho Chehab 	}, {	/* Default format: 0x47. For 4:2:2: 0x40 */
485cb7a01acSMauro Carvalho Chehab 		TVP5150_DATA_RATE_SEL, 0x47
486cb7a01acSMauro Carvalho Chehab 	}, {
487cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_1, 0x0c
488cb7a01acSMauro Carvalho Chehab 	}, {
489cb7a01acSMauro Carvalho Chehab 		TVP5150_CHROMA_PROC_CTL_2, 0x54
490cb7a01acSMauro Carvalho Chehab 	}, {	/* Non documented, but initialized on WinTV USB2 */
491cb7a01acSMauro Carvalho Chehab 		0x27, 0x20
492cb7a01acSMauro Carvalho Chehab 	}, {
493cb7a01acSMauro Carvalho Chehab 		0xff, 0xff
494cb7a01acSMauro Carvalho Chehab 	}
495cb7a01acSMauro Carvalho Chehab };
496cb7a01acSMauro Carvalho Chehab 
497cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type {
498cb7a01acSMauro Carvalho Chehab 	unsigned int vbi_type;
499cb7a01acSMauro Carvalho Chehab 	unsigned int ini_line;
500cb7a01acSMauro Carvalho Chehab 	unsigned int end_line;
501cb7a01acSMauro Carvalho Chehab 	unsigned int by_field :1;
502cb7a01acSMauro Carvalho Chehab };
503cb7a01acSMauro Carvalho Chehab 
504cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value {
505cb7a01acSMauro Carvalho Chehab 	u16 reg;
506cb7a01acSMauro Carvalho Chehab 	struct tvp5150_vbi_type type;
507cb7a01acSMauro Carvalho Chehab 	unsigned char values[16];
508cb7a01acSMauro Carvalho Chehab };
509cb7a01acSMauro Carvalho Chehab 
510cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard
511cb7a01acSMauro Carvalho Chehab  * by
512cb7a01acSMauro Carvalho Chehab  tvp5150_vbi_types should follow the same order as vbi_ram_default
513cb7a01acSMauro Carvalho Chehab  * value 0 means rom position 0x10, value 1 means rom position 0x30
514cb7a01acSMauro Carvalho Chehab  * and so on. There are 16 possible locations from 0 to 15.
515cb7a01acSMauro Carvalho Chehab  */
516cb7a01acSMauro Carvalho Chehab 
51765dc760bSNasser Afshin static struct i2c_vbi_ram_value vbi_ram_default[] = {
51865dc760bSNasser Afshin 
5199bfd8f88SNasser Afshin 	/*
5209bfd8f88SNasser Afshin 	 * FIXME: Current api doesn't handle all VBI types, those not
5219bfd8f88SNasser Afshin 	 * yet supported are placed under #if 0
5229bfd8f88SNasser Afshin 	 */
523cb7a01acSMauro Carvalho Chehab #if 0
5243dd6b560SMauro Carvalho Chehab 	[0] = {0x010, /* Teletext, SECAM, WST System A */
525cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_SECAM, 6, 23, 1},
526cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
527cb7a01acSMauro Carvalho Chehab 		  0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
528cb7a01acSMauro Carvalho Chehab 	},
529cb7a01acSMauro Carvalho Chehab #endif
5303dd6b560SMauro Carvalho Chehab 	[1] = {0x030, /* Teletext, PAL, WST System B */
531cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_B, 6, 22, 1},
532cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
533cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
534cb7a01acSMauro Carvalho Chehab 	},
535cb7a01acSMauro Carvalho Chehab #if 0
5363dd6b560SMauro Carvalho Chehab 	[2] = {0x050, /* Teletext, PAL, WST System C */
537cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_PAL_C, 6, 22, 1},
538cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
539cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
540cb7a01acSMauro Carvalho Chehab 	},
5413dd6b560SMauro Carvalho Chehab 	[3] = {0x070, /* Teletext, NTSC, WST System B */
542cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_NTSC_B, 10, 21, 1},
543cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
544cb7a01acSMauro Carvalho Chehab 		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
545cb7a01acSMauro Carvalho Chehab 	},
5463dd6b560SMauro Carvalho Chehab 	[4] = {0x090, /* Tetetext, NTSC NABTS System C */
547cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_NTSC_C, 10, 21, 1},
548cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
549cb7a01acSMauro Carvalho Chehab 		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
550cb7a01acSMauro Carvalho Chehab 	},
5513dd6b560SMauro Carvalho Chehab 	[5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */
552cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_TELETEXT_NTSC_D, 10, 21, 1},
553cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
554cb7a01acSMauro Carvalho Chehab 		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
555cb7a01acSMauro Carvalho Chehab 	},
5563dd6b560SMauro Carvalho Chehab 	[6] = {0x0d0, /* Closed Caption, PAL/SECAM */
557cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_CAPTION_625, 22, 22, 1},
558cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
559cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
560cb7a01acSMauro Carvalho Chehab 	},
561cb7a01acSMauro Carvalho Chehab #endif
5623dd6b560SMauro Carvalho Chehab 	[7] = {0x0f0, /* Closed Caption, NTSC */
563cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_CAPTION_525, 21, 21, 1},
564cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
565cb7a01acSMauro Carvalho Chehab 		  0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
566cb7a01acSMauro Carvalho Chehab 	},
5673dd6b560SMauro Carvalho Chehab 	[8] = {0x110, /* Wide Screen Signal, PAL/SECAM */
568cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_WSS_625, 23, 23, 1},
569cb7a01acSMauro Carvalho Chehab 		{ 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
570cb7a01acSMauro Carvalho Chehab 		  0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
571cb7a01acSMauro Carvalho Chehab 	},
572cb7a01acSMauro Carvalho Chehab #if 0
5733dd6b560SMauro Carvalho Chehab 	[9] = {0x130, /* Wide Screen Signal, NTSC C */
574cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_WSS_525, 20, 20, 1},
575cb7a01acSMauro Carvalho Chehab 		{ 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
576cb7a01acSMauro Carvalho Chehab 		  0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
577cb7a01acSMauro Carvalho Chehab 	},
5783dd6b560SMauro Carvalho Chehab 	[10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
579cb7a01acSMauro Carvalho Chehab 		{V4l2_SLICED_VITC_625, 6, 22, 0},
580cb7a01acSMauro Carvalho Chehab 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
581cb7a01acSMauro Carvalho Chehab 		  0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
582cb7a01acSMauro Carvalho Chehab 	},
5833dd6b560SMauro Carvalho Chehab 	[11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */
584cb7a01acSMauro Carvalho Chehab 		{V4l2_SLICED_VITC_525, 10, 20, 0},
585cb7a01acSMauro Carvalho Chehab 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
586cb7a01acSMauro Carvalho Chehab 		  0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
587cb7a01acSMauro Carvalho Chehab 	},
588cb7a01acSMauro Carvalho Chehab #endif
5893dd6b560SMauro Carvalho Chehab 	[12] = {0x190, /* Video Program System (VPS), PAL */
590cb7a01acSMauro Carvalho Chehab 		{V4L2_SLICED_VPS, 16, 16, 0},
591cb7a01acSMauro Carvalho Chehab 		{ 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
592cb7a01acSMauro Carvalho Chehab 		  0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
593cb7a01acSMauro Carvalho Chehab 	},
594cb7a01acSMauro Carvalho Chehab 	/* 0x1d0 User programmable */
595cb7a01acSMauro Carvalho Chehab };
596cb7a01acSMauro Carvalho Chehab 
tvp5150_write_inittab(struct v4l2_subdev * sd,const struct i2c_reg_value * regs)597cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd,
598cb7a01acSMauro Carvalho Chehab 				const struct i2c_reg_value *regs)
599cb7a01acSMauro Carvalho Chehab {
60028b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
60128b9e227SPhilipp Zabel 
602cb7a01acSMauro Carvalho Chehab 	while (regs->reg != 0xff) {
60328b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, regs->reg, regs->value);
604cb7a01acSMauro Carvalho Chehab 		regs++;
605cb7a01acSMauro Carvalho Chehab 	}
606cb7a01acSMauro Carvalho Chehab 	return 0;
607cb7a01acSMauro Carvalho Chehab }
608cb7a01acSMauro Carvalho Chehab 
tvp5150_vdp_init(struct v4l2_subdev * sd)6093dd6b560SMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd)
610cb7a01acSMauro Carvalho Chehab {
61128b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
61228b9e227SPhilipp Zabel 	struct regmap *map = decoder->regmap;
613cb7a01acSMauro Carvalho Chehab 	unsigned int i;
6143dd6b560SMauro Carvalho Chehab 	int j;
615cb7a01acSMauro Carvalho Chehab 
616cb7a01acSMauro Carvalho Chehab 	/* Disable Full Field */
61728b9e227SPhilipp Zabel 	regmap_write(map, TVP5150_FULL_FIELD_ENA, 0);
618cb7a01acSMauro Carvalho Chehab 
619cb7a01acSMauro Carvalho Chehab 	/* Before programming, Line mode should be at 0xff */
620cb7a01acSMauro Carvalho Chehab 	for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
62128b9e227SPhilipp Zabel 		regmap_write(map, i, 0xff);
622cb7a01acSMauro Carvalho Chehab 
623cb7a01acSMauro Carvalho Chehab 	/* Load Ram Table */
6243dd6b560SMauro Carvalho Chehab 	for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) {
6253dd6b560SMauro Carvalho Chehab 		const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j];
6263dd6b560SMauro Carvalho Chehab 
6273dd6b560SMauro Carvalho Chehab 		if (!regs->type.vbi_type)
6283dd6b560SMauro Carvalho Chehab 			continue;
6293dd6b560SMauro Carvalho Chehab 
63028b9e227SPhilipp Zabel 		regmap_write(map, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
63128b9e227SPhilipp Zabel 		regmap_write(map, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
632cb7a01acSMauro Carvalho Chehab 
633cb7a01acSMauro Carvalho Chehab 		for (i = 0; i < 16; i++)
63428b9e227SPhilipp Zabel 			regmap_write(map, TVP5150_VDP_CONF_RAM_DATA,
63528b9e227SPhilipp Zabel 				     regs->values[i]);
636cb7a01acSMauro Carvalho Chehab 	}
637cb7a01acSMauro Carvalho Chehab 	return 0;
638cb7a01acSMauro Carvalho Chehab }
639cb7a01acSMauro Carvalho Chehab 
640cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */
tvp5150_g_sliced_vbi_cap(struct v4l2_subdev * sd,struct v4l2_sliced_vbi_cap * cap)641cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
642cb7a01acSMauro Carvalho Chehab 				struct v4l2_sliced_vbi_cap *cap)
643cb7a01acSMauro Carvalho Chehab {
6443dd6b560SMauro Carvalho Chehab 	int line, i;
645cb7a01acSMauro Carvalho Chehab 
646257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n");
647bb7a3681SNasser Afshin 	memset(cap, 0, sizeof(*cap));
648cb7a01acSMauro Carvalho Chehab 
6493dd6b560SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) {
6503dd6b560SMauro Carvalho Chehab 		const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i];
6513dd6b560SMauro Carvalho Chehab 
6523dd6b560SMauro Carvalho Chehab 		if (!regs->type.vbi_type)
6533dd6b560SMauro Carvalho Chehab 			continue;
6543dd6b560SMauro Carvalho Chehab 
6553dd6b560SMauro Carvalho Chehab 		for (line = regs->type.ini_line;
6563dd6b560SMauro Carvalho Chehab 		     line <= regs->type.end_line;
6573dd6b560SMauro Carvalho Chehab 		     line++) {
658cb7a01acSMauro Carvalho Chehab 			cap->service_lines[0][line] |= regs->type.vbi_type;
659cb7a01acSMauro Carvalho Chehab 		}
660cb7a01acSMauro Carvalho Chehab 		cap->service_set |= regs->type.vbi_type;
661cb7a01acSMauro Carvalho Chehab 	}
662cb7a01acSMauro Carvalho Chehab 	return 0;
663cb7a01acSMauro Carvalho Chehab }
664cb7a01acSMauro Carvalho Chehab 
665cb7a01acSMauro Carvalho Chehab /* Set vbi processing
666cb7a01acSMauro Carvalho Chehab  * type - one of tvp5150_vbi_types
667cb7a01acSMauro Carvalho Chehab  * line - line to gather data
668cb7a01acSMauro Carvalho Chehab  * fields: bit 0 field1, bit 1, field2
669cb7a01acSMauro Carvalho Chehab  * flags (default=0xf0) is a bitmask, were set means:
670cb7a01acSMauro Carvalho Chehab  *	bit 7: enable filtering null bytes on CC
671cb7a01acSMauro Carvalho Chehab  *	bit 6: send data also to FIFO
672cb7a01acSMauro Carvalho Chehab  *	bit 5: don't allow data with errors on FIFO
673cb7a01acSMauro Carvalho Chehab  *	bit 4: enable ECC when possible
674cb7a01acSMauro Carvalho Chehab  * pix_align = pix alignment:
675cb7a01acSMauro Carvalho Chehab  *	LSB = field1
676cb7a01acSMauro Carvalho Chehab  *	MSB = field2
677cb7a01acSMauro Carvalho Chehab  */
tvp5150_set_vbi(struct v4l2_subdev * sd,unsigned int type,u8 flags,int line,const int fields)678cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd,
679cb7a01acSMauro Carvalho Chehab 			unsigned int type, u8 flags, int line,
680cb7a01acSMauro Carvalho Chehab 			const int fields)
681cb7a01acSMauro Carvalho Chehab {
682cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
683cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std = decoder->norm;
684cb7a01acSMauro Carvalho Chehab 	u8 reg;
6853dd6b560SMauro Carvalho Chehab 	int i, pos = 0;
686cb7a01acSMauro Carvalho Chehab 
687cb7a01acSMauro Carvalho Chehab 	if (std == V4L2_STD_ALL) {
688257e29f8SMauro Carvalho Chehab 		dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n");
689cb7a01acSMauro Carvalho Chehab 		return 0;
690cb7a01acSMauro Carvalho Chehab 	} else if (std & V4L2_STD_625_50) {
691cb7a01acSMauro Carvalho Chehab 		/* Don't follow NTSC Line number convension */
692cb7a01acSMauro Carvalho Chehab 		line += 3;
693cb7a01acSMauro Carvalho Chehab 	}
694cb7a01acSMauro Carvalho Chehab 
695cb7a01acSMauro Carvalho Chehab 	if (line < 6 || line > 27)
696cb7a01acSMauro Carvalho Chehab 		return 0;
697cb7a01acSMauro Carvalho Chehab 
6983dd6b560SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) {
6993dd6b560SMauro Carvalho Chehab 		const struct i2c_vbi_ram_value *regs =  &vbi_ram_default[i];
7003dd6b560SMauro Carvalho Chehab 
7013dd6b560SMauro Carvalho Chehab 		if (!regs->type.vbi_type)
7023dd6b560SMauro Carvalho Chehab 			continue;
7033dd6b560SMauro Carvalho Chehab 
704cb7a01acSMauro Carvalho Chehab 		if ((type & regs->type.vbi_type) &&
705cb7a01acSMauro Carvalho Chehab 		    (line >= regs->type.ini_line) &&
706b3d930aaSGustavo A. R. Silva 		    (line <= regs->type.end_line))
707cb7a01acSMauro Carvalho Chehab 			break;
708cb7a01acSMauro Carvalho Chehab 		pos++;
709cb7a01acSMauro Carvalho Chehab 	}
710b3d930aaSGustavo A. R. Silva 
711cb7a01acSMauro Carvalho Chehab 	type = pos | (flags & 0xf0);
712cb7a01acSMauro Carvalho Chehab 	reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
713cb7a01acSMauro Carvalho Chehab 
714b3d930aaSGustavo A. R. Silva 	if (fields & 1)
71528b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, reg, type);
716cb7a01acSMauro Carvalho Chehab 
717b3d930aaSGustavo A. R. Silva 	if (fields & 2)
71828b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, reg + 1, type);
719cb7a01acSMauro Carvalho Chehab 
720cb7a01acSMauro Carvalho Chehab 	return type;
721cb7a01acSMauro Carvalho Chehab }
722cb7a01acSMauro Carvalho Chehab 
tvp5150_get_vbi(struct v4l2_subdev * sd,int line)7233dd6b560SMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line)
724cb7a01acSMauro Carvalho Chehab {
725cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
726cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std = decoder->norm;
727cb7a01acSMauro Carvalho Chehab 	u8 reg;
728cb7a01acSMauro Carvalho Chehab 	int pos, type = 0;
729cb7a01acSMauro Carvalho Chehab 	int i, ret = 0;
730cb7a01acSMauro Carvalho Chehab 
731cb7a01acSMauro Carvalho Chehab 	if (std == V4L2_STD_ALL) {
732257e29f8SMauro Carvalho Chehab 		dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n");
733cb7a01acSMauro Carvalho Chehab 		return 0;
734cb7a01acSMauro Carvalho Chehab 	} else if (std & V4L2_STD_625_50) {
735cb7a01acSMauro Carvalho Chehab 		/* Don't follow NTSC Line number convension */
736cb7a01acSMauro Carvalho Chehab 		line += 3;
737cb7a01acSMauro Carvalho Chehab 	}
738cb7a01acSMauro Carvalho Chehab 
739cb7a01acSMauro Carvalho Chehab 	if (line < 6 || line > 27)
740cb7a01acSMauro Carvalho Chehab 		return 0;
741cb7a01acSMauro Carvalho Chehab 
742cb7a01acSMauro Carvalho Chehab 	reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
743cb7a01acSMauro Carvalho Chehab 
744cb7a01acSMauro Carvalho Chehab 	for (i = 0; i <= 1; i++) {
745cb7a01acSMauro Carvalho Chehab 		ret = tvp5150_read(sd, reg + i);
746cb7a01acSMauro Carvalho Chehab 		if (ret < 0) {
747257e29f8SMauro Carvalho Chehab 			dev_err(sd->dev, "%s: failed with error = %d\n",
748cb7a01acSMauro Carvalho Chehab 				 __func__, ret);
749cb7a01acSMauro Carvalho Chehab 			return 0;
750cb7a01acSMauro Carvalho Chehab 		}
751cb7a01acSMauro Carvalho Chehab 		pos = ret & 0x0f;
7523dd6b560SMauro Carvalho Chehab 		if (pos < ARRAY_SIZE(vbi_ram_default))
7533dd6b560SMauro Carvalho Chehab 			type |= vbi_ram_default[pos].type.vbi_type;
754cb7a01acSMauro Carvalho Chehab 	}
755cb7a01acSMauro Carvalho Chehab 
756cb7a01acSMauro Carvalho Chehab 	return type;
757cb7a01acSMauro Carvalho Chehab }
758cb7a01acSMauro Carvalho Chehab 
tvp5150_set_std(struct v4l2_subdev * sd,v4l2_std_id std)759cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
760cb7a01acSMauro Carvalho Chehab {
761cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
762cb7a01acSMauro Carvalho Chehab 	int fmt = 0;
763cb7a01acSMauro Carvalho Chehab 
764cb7a01acSMauro Carvalho Chehab 	/* First tests should be against specific std */
765cb7a01acSMauro Carvalho Chehab 
76626811ae0SHans Verkuil 	if (std == V4L2_STD_NTSC_443) {
767cb7a01acSMauro Carvalho Chehab 		fmt = VIDEO_STD_NTSC_4_43_BIT;
76826811ae0SHans Verkuil 	} else if (std == V4L2_STD_PAL_M) {
769cb7a01acSMauro Carvalho Chehab 		fmt = VIDEO_STD_PAL_M_BIT;
77026811ae0SHans Verkuil 	} else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) {
771cb7a01acSMauro Carvalho Chehab 		fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
772cb7a01acSMauro Carvalho Chehab 	} else {
773cb7a01acSMauro Carvalho Chehab 		/* Then, test against generic ones */
774cb7a01acSMauro Carvalho Chehab 		if (std & V4L2_STD_NTSC)
775cb7a01acSMauro Carvalho Chehab 			fmt = VIDEO_STD_NTSC_MJ_BIT;
776cb7a01acSMauro Carvalho Chehab 		else if (std & V4L2_STD_PAL)
777cb7a01acSMauro Carvalho Chehab 			fmt = VIDEO_STD_PAL_BDGHIN_BIT;
778cb7a01acSMauro Carvalho Chehab 		else if (std & V4L2_STD_SECAM)
779cb7a01acSMauro Carvalho Chehab 			fmt = VIDEO_STD_SECAM_BIT;
780cb7a01acSMauro Carvalho Chehab 	}
781cb7a01acSMauro Carvalho Chehab 
782257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt);
78328b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_VIDEO_STD, fmt);
784cb7a01acSMauro Carvalho Chehab 	return 0;
785cb7a01acSMauro Carvalho Chehab }
786cb7a01acSMauro Carvalho Chehab 
tvp5150_g_std(struct v4l2_subdev * sd,v4l2_std_id * std)7870db87cc7SMarco Felsch static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
7880db87cc7SMarco Felsch {
7890db87cc7SMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
7900db87cc7SMarco Felsch 
7910db87cc7SMarco Felsch 	*std = decoder->norm;
7920db87cc7SMarco Felsch 
7930db87cc7SMarco Felsch 	return 0;
7940db87cc7SMarco Felsch }
7950db87cc7SMarco Felsch 
tvp5150_s_std(struct v4l2_subdev * sd,v4l2_std_id std)796cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
797cb7a01acSMauro Carvalho Chehab {
798cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
799baf17821SMarco Felsch 	struct tvp5150_connector *cur_con = decoder->cur_connector;
800baf17821SMarco Felsch 	v4l2_std_id supported_stds;
801cb7a01acSMauro Carvalho Chehab 
802cb7a01acSMauro Carvalho Chehab 	if (decoder->norm == std)
803cb7a01acSMauro Carvalho Chehab 		return 0;
804cb7a01acSMauro Carvalho Chehab 
805baf17821SMarco Felsch 	/* In case of no of-connectors are available no limitations are made */
806baf17821SMarco Felsch 	if (!decoder->connectors_num)
807baf17821SMarco Felsch 		supported_stds = V4L2_STD_ALL;
808baf17821SMarco Felsch 	else
809baf17821SMarco Felsch 		supported_stds = cur_con->base.connector.analog.sdtv_stds;
810baf17821SMarco Felsch 
811baf17821SMarco Felsch 	/*
812baf17821SMarco Felsch 	 * Check if requested std or group of std's is/are supported by the
813baf17821SMarco Felsch 	 * connector.
814baf17821SMarco Felsch 	 */
815baf17821SMarco Felsch 	if ((supported_stds & std) == 0)
816baf17821SMarco Felsch 		return -EINVAL;
817baf17821SMarco Felsch 
818cb7a01acSMauro Carvalho Chehab 	/* Change cropping height limits */
819cb7a01acSMauro Carvalho Chehab 	if (std & V4L2_STD_525_60)
820cb7a01acSMauro Carvalho Chehab 		decoder->rect.height = TVP5150_V_MAX_525_60;
821cb7a01acSMauro Carvalho Chehab 	else
822cb7a01acSMauro Carvalho Chehab 		decoder->rect.height = TVP5150_V_MAX_OTHERS;
823cb7a01acSMauro Carvalho Chehab 
824baf17821SMarco Felsch 	/* Set only the specific supported std in case of group of std's. */
825baf17821SMarco Felsch 	decoder->norm = supported_stds & std;
826cb7a01acSMauro Carvalho Chehab 
827cb7a01acSMauro Carvalho Chehab 	return tvp5150_set_std(sd, std);
828cb7a01acSMauro Carvalho Chehab }
829cb7a01acSMauro Carvalho Chehab 
tvp5150_read_std(struct v4l2_subdev * sd)83015695866SPhilipp Zabel static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
83115695866SPhilipp Zabel {
83215695866SPhilipp Zabel 	int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
83315695866SPhilipp Zabel 
83415695866SPhilipp Zabel 	switch (val & 0x0F) {
83515695866SPhilipp Zabel 	case 0x01:
83615695866SPhilipp Zabel 		return V4L2_STD_NTSC;
83715695866SPhilipp Zabel 	case 0x03:
83815695866SPhilipp Zabel 		return V4L2_STD_PAL;
83915695866SPhilipp Zabel 	case 0x05:
84015695866SPhilipp Zabel 		return V4L2_STD_PAL_M;
84115695866SPhilipp Zabel 	case 0x07:
84215695866SPhilipp Zabel 		return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
84315695866SPhilipp Zabel 	case 0x09:
84415695866SPhilipp Zabel 		return V4L2_STD_NTSC_443;
84515695866SPhilipp Zabel 	case 0xb:
84615695866SPhilipp Zabel 		return V4L2_STD_SECAM;
84715695866SPhilipp Zabel 	default:
84815695866SPhilipp Zabel 		return V4L2_STD_UNKNOWN;
84915695866SPhilipp Zabel 	}
85015695866SPhilipp Zabel }
85115695866SPhilipp Zabel 
query_lock(struct v4l2_subdev * sd)8525bd1d91dSMauro Carvalho Chehab static int query_lock(struct v4l2_subdev *sd)
8535bd1d91dSMauro Carvalho Chehab {
8545bd1d91dSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
8555bd1d91dSMauro Carvalho Chehab 	int status;
8565bd1d91dSMauro Carvalho Chehab 
8575bd1d91dSMauro Carvalho Chehab 	if (decoder->irq)
8585bd1d91dSMauro Carvalho Chehab 		return decoder->lock;
8595bd1d91dSMauro Carvalho Chehab 
8605bd1d91dSMauro Carvalho Chehab 	regmap_read(decoder->regmap, TVP5150_STATUS_REG_1, &status);
8615bd1d91dSMauro Carvalho Chehab 
8625bd1d91dSMauro Carvalho Chehab 	/* For standard detection, we need the 3 locks */
8635bd1d91dSMauro Carvalho Chehab 	return (status & 0x0e) == 0x0e;
8645bd1d91dSMauro Carvalho Chehab }
8655bd1d91dSMauro Carvalho Chehab 
tvp5150_querystd(struct v4l2_subdev * sd,v4l2_std_id * std_id)866ee9a6ff6SPhilipp Zabel static int tvp5150_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
867ee9a6ff6SPhilipp Zabel {
8685bd1d91dSMauro Carvalho Chehab 	*std_id = query_lock(sd) ? tvp5150_read_std(sd) : V4L2_STD_UNKNOWN;
869ee9a6ff6SPhilipp Zabel 
870ee9a6ff6SPhilipp Zabel 	return 0;
871ee9a6ff6SPhilipp Zabel }
872ee9a6ff6SPhilipp Zabel 
8732f0a5c65SPhilipp Zabel static const struct v4l2_event tvp5150_ev_fmt = {
8742f0a5c65SPhilipp Zabel 	.type = V4L2_EVENT_SOURCE_CHANGE,
8752f0a5c65SPhilipp Zabel 	.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
8762f0a5c65SPhilipp Zabel };
8772f0a5c65SPhilipp Zabel 
tvp5150_isr(int irq,void * dev_id)8788e4c97e0SPhilipp Zabel static irqreturn_t tvp5150_isr(int irq, void *dev_id)
8798e4c97e0SPhilipp Zabel {
8808e4c97e0SPhilipp Zabel 	struct tvp5150 *decoder = dev_id;
8818e4c97e0SPhilipp Zabel 	struct regmap *map = decoder->regmap;
88262a764e1SPhilipp Zabel 	unsigned int mask, active = 0, status = 0;
88362a764e1SPhilipp Zabel 
88462a764e1SPhilipp Zabel 	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
88562a764e1SPhilipp Zabel 	       TVP5150_MISC_CTL_CLOCK_OE;
8868e4c97e0SPhilipp Zabel 
8878e4c97e0SPhilipp Zabel 	regmap_read(map, TVP5150_INT_STATUS_REG_A, &status);
8888e4c97e0SPhilipp Zabel 	if (status) {
8898e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INT_STATUS_REG_A, status);
8908e4c97e0SPhilipp Zabel 
89162a764e1SPhilipp Zabel 		if (status & TVP5150_INT_A_LOCK) {
8928e4c97e0SPhilipp Zabel 			decoder->lock = !!(status & TVP5150_INT_A_LOCK_STATUS);
8937bb3c338SPhilipp Zabel 			dev_dbg_lvl(decoder->sd.dev, 1, debug,
8947bb3c338SPhilipp Zabel 				    "sync lo%s signal\n",
8957bb3c338SPhilipp Zabel 				    decoder->lock ? "ck" : "ss");
8962f0a5c65SPhilipp Zabel 			v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
89762a764e1SPhilipp Zabel 			regmap_update_bits(map, TVP5150_MISC_CTL, mask,
89862a764e1SPhilipp Zabel 					   decoder->lock ? decoder->oe : 0);
89962a764e1SPhilipp Zabel 		}
9008e4c97e0SPhilipp Zabel 
9018e4c97e0SPhilipp Zabel 		return IRQ_HANDLED;
9028e4c97e0SPhilipp Zabel 	}
9038e4c97e0SPhilipp Zabel 
9048e4c97e0SPhilipp Zabel 	regmap_read(map, TVP5150_INT_ACTIVE_REG_B, &active);
9058e4c97e0SPhilipp Zabel 	if (active) {
9068e4c97e0SPhilipp Zabel 		status = 0;
9078e4c97e0SPhilipp Zabel 		regmap_read(map, TVP5150_INT_STATUS_REG_B, &status);
9088e4c97e0SPhilipp Zabel 		if (status)
9098e4c97e0SPhilipp Zabel 			regmap_write(map, TVP5150_INT_RESET_REG_B, status);
9108e4c97e0SPhilipp Zabel 	}
9118e4c97e0SPhilipp Zabel 
9128e4c97e0SPhilipp Zabel 	return IRQ_HANDLED;
9138e4c97e0SPhilipp Zabel }
9148e4c97e0SPhilipp Zabel 
tvp5150_reset(struct v4l2_subdev * sd,u32 val)915cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
916cb7a01acSMauro Carvalho Chehab {
917cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
9188105e1bcSPhilipp Zabel 	struct regmap *map = decoder->regmap;
919cb7a01acSMauro Carvalho Chehab 
920cb7a01acSMauro Carvalho Chehab 	/* Initializes TVP5150 to its default values */
921cb7a01acSMauro Carvalho Chehab 	tvp5150_write_inittab(sd, tvp5150_init_default);
922cb7a01acSMauro Carvalho Chehab 
9238e4c97e0SPhilipp Zabel 	if (decoder->irq) {
9248e4c97e0SPhilipp Zabel 		/* Configure pins: FID, VSYNC, INTREQ, SCLK */
9258e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x0);
9268e4c97e0SPhilipp Zabel 		/* Set interrupt polarity to active high */
9278e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE | 0x1);
9288e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x1);
9298e4c97e0SPhilipp Zabel 	} else {
9308105e1bcSPhilipp Zabel 		/* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */
9318105e1bcSPhilipp Zabel 		regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2);
9328e4c97e0SPhilipp Zabel 		/* Keep interrupt polarity active low */
9338e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE);
9348e4c97e0SPhilipp Zabel 		regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0);
9358e4c97e0SPhilipp Zabel 	}
9368105e1bcSPhilipp Zabel 
937cb7a01acSMauro Carvalho Chehab 	/* Initializes VDP registers */
9383dd6b560SMauro Carvalho Chehab 	tvp5150_vdp_init(sd);
939cb7a01acSMauro Carvalho Chehab 
940cb7a01acSMauro Carvalho Chehab 	/* Selects decoder input */
941cb7a01acSMauro Carvalho Chehab 	tvp5150_selmux(sd);
942cb7a01acSMauro Carvalho Chehab 
943cb7a01acSMauro Carvalho Chehab 	/* Initialize image preferences */
944cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_setup(&decoder->hdl);
945cb7a01acSMauro Carvalho Chehab 
9461bb086bcSPhilipp Zabel 	return 0;
9471bb086bcSPhilipp Zabel }
9481bb086bcSPhilipp Zabel 
tvp5150_enable(struct v4l2_subdev * sd)9491bb086bcSPhilipp Zabel static int tvp5150_enable(struct v4l2_subdev *sd)
9501bb086bcSPhilipp Zabel {
9511bb086bcSPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
9521bb086bcSPhilipp Zabel 	v4l2_std_id std;
9531bb086bcSPhilipp Zabel 
9541bb086bcSPhilipp Zabel 	/* Initializes TVP5150 to stream enabled values */
9551bb086bcSPhilipp Zabel 	tvp5150_write_inittab(sd, tvp5150_init_enable);
9561bb086bcSPhilipp Zabel 
95715695866SPhilipp Zabel 	if (decoder->norm == V4L2_STD_ALL)
95815695866SPhilipp Zabel 		std = tvp5150_read_std(sd);
95915695866SPhilipp Zabel 	else
96015695866SPhilipp Zabel 		std = decoder->norm;
96115695866SPhilipp Zabel 
96215695866SPhilipp Zabel 	/* Disable autoswitch mode */
96315695866SPhilipp Zabel 	tvp5150_set_std(sd, std);
964a2e5f1b3SJavier Martinez Canillas 
96562a764e1SPhilipp Zabel 	/*
96662a764e1SPhilipp Zabel 	 * Enable the YCbCr and clock outputs. In discrete sync mode
967331ca86aSlijian 	 * (non-BT.656) additionally enable the sync outputs.
96862a764e1SPhilipp Zabel 	 */
96962a764e1SPhilipp Zabel 	switch (decoder->mbus_type) {
97062a764e1SPhilipp Zabel 	case V4L2_MBUS_PARALLEL:
9718a7441baSMarco Felsch 		/* 8-bit 4:2:2 YUV with discrete sync output */
9728a7441baSMarco Felsch 		regmap_update_bits(decoder->regmap, TVP5150_DATA_RATE_SEL,
9738a7441baSMarco Felsch 				   0x7, 0x0);
97462a764e1SPhilipp Zabel 		decoder->oe = TVP5150_MISC_CTL_YCBCR_OE |
97562a764e1SPhilipp Zabel 			      TVP5150_MISC_CTL_CLOCK_OE |
97662a764e1SPhilipp Zabel 			      TVP5150_MISC_CTL_SYNC_OE;
97762a764e1SPhilipp Zabel 		break;
97862a764e1SPhilipp Zabel 	case V4L2_MBUS_BT656:
97962a764e1SPhilipp Zabel 		decoder->oe = TVP5150_MISC_CTL_YCBCR_OE |
98062a764e1SPhilipp Zabel 			      TVP5150_MISC_CTL_CLOCK_OE;
98162a764e1SPhilipp Zabel 		break;
98262a764e1SPhilipp Zabel 	default:
98362a764e1SPhilipp Zabel 		return -EINVAL;
98462a764e1SPhilipp Zabel 	}
985a2e5f1b3SJavier Martinez Canillas 
986cb7a01acSMauro Carvalho Chehab 	return 0;
987cb7a01acSMauro Carvalho Chehab };
988cb7a01acSMauro Carvalho Chehab 
tvp5150_s_ctrl(struct v4l2_ctrl * ctrl)989cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
990cb7a01acSMauro Carvalho Chehab {
991cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = to_sd(ctrl);
992c43875f6SMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
993cb7a01acSMauro Carvalho Chehab 
994cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
995cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
99628b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_BRIGHT_CTL, ctrl->val);
997cb7a01acSMauro Carvalho Chehab 		return 0;
998cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
99928b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_CONTRAST_CTL, ctrl->val);
1000cb7a01acSMauro Carvalho Chehab 		return 0;
1001cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
100228b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_SATURATION_CTL,
100328b9e227SPhilipp Zabel 			     ctrl->val);
1004cb7a01acSMauro Carvalho Chehab 		return 0;
1005cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_HUE:
100628b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_HUE_CTL, ctrl->val);
10072d29bcc8SMarco Felsch 		return 0;
1008c43875f6SMauro Carvalho Chehab 	case V4L2_CID_TEST_PATTERN:
1009c43875f6SMauro Carvalho Chehab 		decoder->enable = ctrl->val ? false : true;
1010c43875f6SMauro Carvalho Chehab 		tvp5150_selmux(sd);
1011cb7a01acSMauro Carvalho Chehab 		return 0;
1012cb7a01acSMauro Carvalho Chehab 	}
1013cb7a01acSMauro Carvalho Chehab 	return -EINVAL;
1014cb7a01acSMauro Carvalho Chehab }
1015cb7a01acSMauro Carvalho Chehab 
tvp5150_set_default(v4l2_std_id std,struct v4l2_rect * crop)10165cb82940SMarco Felsch static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
10175cb82940SMarco Felsch {
10185cb82940SMarco Felsch 	/* Default is no cropping */
10195cb82940SMarco Felsch 	crop->top = 0;
10205cb82940SMarco Felsch 	crop->left = 0;
10215cb82940SMarco Felsch 	crop->width = TVP5150_H_MAX;
10225cb82940SMarco Felsch 	if (std & V4L2_STD_525_60)
10235cb82940SMarco Felsch 		crop->height = TVP5150_V_MAX_525_60;
10245cb82940SMarco Felsch 	else
10255cb82940SMarco Felsch 		crop->height = TVP5150_V_MAX_OTHERS;
10265cb82940SMarco Felsch }
10275cb82940SMarco Felsch 
102846fe6e7dSMarco Felsch static struct v4l2_rect *
tvp5150_get_pad_crop(struct tvp5150 * decoder,struct v4l2_subdev_state * sd_state,unsigned int pad,enum v4l2_subdev_format_whence which)102946fe6e7dSMarco Felsch tvp5150_get_pad_crop(struct tvp5150 *decoder,
10300d346d2aSTomi Valkeinen 		     struct v4l2_subdev_state *sd_state, unsigned int pad,
103146fe6e7dSMarco Felsch 		     enum v4l2_subdev_format_whence which)
103246fe6e7dSMarco Felsch {
103346fe6e7dSMarco Felsch 	switch (which) {
103446fe6e7dSMarco Felsch 	case V4L2_SUBDEV_FORMAT_ACTIVE:
103546fe6e7dSMarco Felsch 		return &decoder->rect;
103646fe6e7dSMarco Felsch 	case V4L2_SUBDEV_FORMAT_TRY:
103746fe6e7dSMarco Felsch #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
10380d346d2aSTomi Valkeinen 		return v4l2_subdev_get_try_crop(&decoder->sd, sd_state, pad);
103946fe6e7dSMarco Felsch #else
104046fe6e7dSMarco Felsch 		return ERR_PTR(-EINVAL);
104146fe6e7dSMarco Felsch #endif
104246fe6e7dSMarco Felsch 	default:
104346fe6e7dSMarco Felsch 		return ERR_PTR(-EINVAL);
104446fe6e7dSMarco Felsch 	}
104546fe6e7dSMarco Felsch }
104646fe6e7dSMarco Felsch 
tvp5150_fill_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1047da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
10480d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state,
1049da298c6dSHans Verkuil 			    struct v4l2_subdev_format *format)
1050cb7a01acSMauro Carvalho Chehab {
1051da298c6dSHans Verkuil 	struct v4l2_mbus_framefmt *f;
1052cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
1053cb7a01acSMauro Carvalho Chehab 
1054bc322c0dSMauro Carvalho Chehab 	if (!format || (format->pad != TVP5150_PAD_VID_OUT))
1055cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1056cb7a01acSMauro Carvalho Chehab 
1057da298c6dSHans Verkuil 	f = &format->format;
1058da298c6dSHans Verkuil 
1059cb7a01acSMauro Carvalho Chehab 	f->width = decoder->rect.width;
10601831af09SJavier Martinez Canillas 	f->height = decoder->rect.height / 2;
1061cb7a01acSMauro Carvalho Chehab 
10625cb82940SMarco Felsch 	f->code = TVP5150_MBUS_FMT;
10635cb82940SMarco Felsch 	f->field = TVP5150_FIELD;
10645cb82940SMarco Felsch 	f->colorspace = TVP5150_COLORSPACE;
1065cb7a01acSMauro Carvalho Chehab 
1066257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width,
1067cb7a01acSMauro Carvalho Chehab 		    f->height);
1068cb7a01acSMauro Carvalho Chehab 	return 0;
1069cb7a01acSMauro Carvalho Chehab }
1070cb7a01acSMauro Carvalho Chehab 
tvp5150_get_hmax(struct v4l2_subdev * sd)107146fe6e7dSMarco Felsch static unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
1072cb7a01acSMauro Carvalho Chehab {
1073cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
1074cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std;
1075cb7a01acSMauro Carvalho Chehab 
1076cb7a01acSMauro Carvalho Chehab 	/* Calculate height based on current standard */
1077cb7a01acSMauro Carvalho Chehab 	if (decoder->norm == V4L2_STD_ALL)
1078cb7a01acSMauro Carvalho Chehab 		std = tvp5150_read_std(sd);
1079cb7a01acSMauro Carvalho Chehab 	else
1080cb7a01acSMauro Carvalho Chehab 		std = decoder->norm;
1081cb7a01acSMauro Carvalho Chehab 
108246fe6e7dSMarco Felsch 	return (std & V4L2_STD_525_60) ?
108346fe6e7dSMarco Felsch 		TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
108446fe6e7dSMarco Felsch }
1085cb7a01acSMauro Carvalho Chehab 
tvp5150_set_hw_selection(struct v4l2_subdev * sd,struct v4l2_rect * rect)108646fe6e7dSMarco Felsch static void tvp5150_set_hw_selection(struct v4l2_subdev *sd,
108746fe6e7dSMarco Felsch 				     struct v4l2_rect *rect)
108846fe6e7dSMarco Felsch {
108946fe6e7dSMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
109046fe6e7dSMarco Felsch 	unsigned int hmax = tvp5150_get_hmax(sd);
1091cb7a01acSMauro Carvalho Chehab 
1092b4125e5bSMarco Felsch 	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect->top);
109328b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
1094b4125e5bSMarco Felsch 		     rect->top + rect->height - hmax);
109528b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
1096b4125e5bSMarco Felsch 		     rect->left >> TVP5150_CROP_SHIFT);
109728b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
1098b4125e5bSMarco Felsch 		     rect->left | (1 << TVP5150_CROP_SHIFT));
109928b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
1100b4125e5bSMarco Felsch 		     (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >>
1101cb7a01acSMauro Carvalho Chehab 		     TVP5150_CROP_SHIFT);
110228b9e227SPhilipp Zabel 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
1103b4125e5bSMarco Felsch 		     rect->left + rect->width - TVP5150_MAX_CROP_LEFT);
110446fe6e7dSMarco Felsch }
1105cb7a01acSMauro Carvalho Chehab 
tvp5150_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)110646fe6e7dSMarco Felsch static int tvp5150_set_selection(struct v4l2_subdev *sd,
11070d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
110846fe6e7dSMarco Felsch 				 struct v4l2_subdev_selection *sel)
110946fe6e7dSMarco Felsch {
111046fe6e7dSMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
111146fe6e7dSMarco Felsch 	struct v4l2_rect *rect = &sel->r;
111246fe6e7dSMarco Felsch 	struct v4l2_rect *crop;
111346fe6e7dSMarco Felsch 	unsigned int hmax;
111446fe6e7dSMarco Felsch 
111546fe6e7dSMarco Felsch 	if (sel->target != V4L2_SEL_TGT_CROP)
111646fe6e7dSMarco Felsch 		return -EINVAL;
111746fe6e7dSMarco Felsch 
111846fe6e7dSMarco Felsch 	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
111946fe6e7dSMarco Felsch 		__func__, rect->left, rect->top, rect->width, rect->height);
112046fe6e7dSMarco Felsch 
112146fe6e7dSMarco Felsch 	/* tvp5150 has some special limits */
112246fe6e7dSMarco Felsch 	rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
112346fe6e7dSMarco Felsch 	rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
112446fe6e7dSMarco Felsch 	hmax = tvp5150_get_hmax(sd);
112546fe6e7dSMarco Felsch 
112646fe6e7dSMarco Felsch 	/*
112746fe6e7dSMarco Felsch 	 * alignments:
112846fe6e7dSMarco Felsch 	 *  - width = 2 due to UYVY colorspace
112946fe6e7dSMarco Felsch 	 *  - height, image = no special alignment
113046fe6e7dSMarco Felsch 	 */
113146fe6e7dSMarco Felsch 	v4l_bound_align_image(&rect->width,
113246fe6e7dSMarco Felsch 			      TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left,
113346fe6e7dSMarco Felsch 			      TVP5150_H_MAX - rect->left, 1, &rect->height,
113446fe6e7dSMarco Felsch 			      hmax - TVP5150_MAX_CROP_TOP - rect->top,
113546fe6e7dSMarco Felsch 			      hmax - rect->top, 0, 0);
113646fe6e7dSMarco Felsch 
113746fe6e7dSMarco Felsch 	if (!IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API) &&
113846fe6e7dSMarco Felsch 	    sel->which == V4L2_SUBDEV_FORMAT_TRY)
113946fe6e7dSMarco Felsch 		return 0;
114046fe6e7dSMarco Felsch 
11410d346d2aSTomi Valkeinen 	crop = tvp5150_get_pad_crop(decoder, sd_state, sel->pad, sel->which);
114246fe6e7dSMarco Felsch 	if (IS_ERR(crop))
114346fe6e7dSMarco Felsch 		return PTR_ERR(crop);
114446fe6e7dSMarco Felsch 
114546fe6e7dSMarco Felsch 	/*
114646fe6e7dSMarco Felsch 	 * Update output image size if the selection (crop) rectangle size or
114746fe6e7dSMarco Felsch 	 * position has been modified.
114846fe6e7dSMarco Felsch 	 */
114946fe6e7dSMarco Felsch 	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
115046fe6e7dSMarco Felsch 	    !v4l2_rect_equal(rect, crop))
115146fe6e7dSMarco Felsch 		tvp5150_set_hw_selection(sd, rect);
115246fe6e7dSMarco Felsch 
115346fe6e7dSMarco Felsch 	*crop = *rect;
1154cb7a01acSMauro Carvalho Chehab 
1155cb7a01acSMauro Carvalho Chehab 	return 0;
1156cb7a01acSMauro Carvalho Chehab }
1157cb7a01acSMauro Carvalho Chehab 
tvp5150_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)115810d5509cSHans Verkuil static int tvp5150_get_selection(struct v4l2_subdev *sd,
11590d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
116010d5509cSHans Verkuil 				 struct v4l2_subdev_selection *sel)
1161cb7a01acSMauro Carvalho Chehab {
116210d5509cSHans Verkuil 	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
116346fe6e7dSMarco Felsch 	struct v4l2_rect *crop;
1164cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std;
1165cb7a01acSMauro Carvalho Chehab 
116610d5509cSHans Verkuil 	switch (sel->target) {
116710d5509cSHans Verkuil 	case V4L2_SEL_TGT_CROP_BOUNDS:
116810d5509cSHans Verkuil 		sel->r.left = 0;
116910d5509cSHans Verkuil 		sel->r.top = 0;
117010d5509cSHans Verkuil 		sel->r.width = TVP5150_H_MAX;
1171cb7a01acSMauro Carvalho Chehab 
1172cb7a01acSMauro Carvalho Chehab 		/* Calculate height based on current standard */
1173cb7a01acSMauro Carvalho Chehab 		if (decoder->norm == V4L2_STD_ALL)
1174cb7a01acSMauro Carvalho Chehab 			std = tvp5150_read_std(sd);
1175cb7a01acSMauro Carvalho Chehab 		else
1176cb7a01acSMauro Carvalho Chehab 			std = decoder->norm;
1177cb7a01acSMauro Carvalho Chehab 		if (std & V4L2_STD_525_60)
117810d5509cSHans Verkuil 			sel->r.height = TVP5150_V_MAX_525_60;
1179cb7a01acSMauro Carvalho Chehab 		else
118010d5509cSHans Verkuil 			sel->r.height = TVP5150_V_MAX_OTHERS;
1181cb7a01acSMauro Carvalho Chehab 		return 0;
118210d5509cSHans Verkuil 	case V4L2_SEL_TGT_CROP:
11830d346d2aSTomi Valkeinen 		crop = tvp5150_get_pad_crop(decoder, sd_state, sel->pad,
118446fe6e7dSMarco Felsch 					    sel->which);
118546fe6e7dSMarco Felsch 		if (IS_ERR(crop))
118646fe6e7dSMarco Felsch 			return PTR_ERR(crop);
118746fe6e7dSMarco Felsch 		sel->r = *crop;
118810d5509cSHans Verkuil 		return 0;
118910d5509cSHans Verkuil 	default:
119010d5509cSHans Verkuil 		return -EINVAL;
119110d5509cSHans Verkuil 	}
1192cb7a01acSMauro Carvalho Chehab }
1193cb7a01acSMauro Carvalho Chehab 
tvp5150_get_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)11940c3da525SJacopo Mondi static int tvp5150_get_mbus_config(struct v4l2_subdev *sd,
11950c3da525SJacopo Mondi 				   unsigned int pad,
1196dd3a46bbSLaurent Pinchart 				   struct v4l2_mbus_config *cfg)
1197dd3a46bbSLaurent Pinchart {
1198a2e5f1b3SJavier Martinez Canillas 	struct tvp5150 *decoder = to_tvp5150(sd);
1199a2e5f1b3SJavier Martinez Canillas 
1200a2e5f1b3SJavier Martinez Canillas 	cfg->type = decoder->mbus_type;
12016a7bdd89SLaurent Pinchart 	cfg->bus.parallel.flags = V4L2_MBUS_MASTER
12026a7bdd89SLaurent Pinchart 				| V4L2_MBUS_PCLK_SAMPLE_RISING
12036a7bdd89SLaurent Pinchart 				| V4L2_MBUS_FIELD_EVEN_LOW
12046a7bdd89SLaurent Pinchart 				| V4L2_MBUS_DATA_ACTIVE_HIGH;
1205dd3a46bbSLaurent Pinchart 
1206dd3a46bbSLaurent Pinchart 	return 0;
1207dd3a46bbSLaurent Pinchart }
1208dd3a46bbSLaurent Pinchart 
1209cb7a01acSMauro Carvalho Chehab /****************************************************************************
1210e545ac87SLaurent Pinchart 			V4L2 subdev pad ops
1211e545ac87SLaurent Pinchart  ****************************************************************************/
tvp5150_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)1212b440b733SPhilipp Zabel static int tvp5150_init_cfg(struct v4l2_subdev *sd,
12130d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state)
1214b440b733SPhilipp Zabel {
1215b440b733SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
1216b440b733SPhilipp Zabel 	v4l2_std_id std;
1217b440b733SPhilipp Zabel 
1218b440b733SPhilipp Zabel 	/*
1219b440b733SPhilipp Zabel 	 * Reset selection to maximum on subdev_open() if autodetection is on
1220b440b733SPhilipp Zabel 	 * and a standard change is detected.
1221b440b733SPhilipp Zabel 	 */
1222b440b733SPhilipp Zabel 	if (decoder->norm == V4L2_STD_ALL) {
1223b440b733SPhilipp Zabel 		std = tvp5150_read_std(sd);
1224b440b733SPhilipp Zabel 		if (std != decoder->detected_norm) {
1225b440b733SPhilipp Zabel 			decoder->detected_norm = std;
1226b440b733SPhilipp Zabel 			tvp5150_set_default(std, &decoder->rect);
1227b440b733SPhilipp Zabel 		}
1228b440b733SPhilipp Zabel 	}
1229b440b733SPhilipp Zabel 
1230b440b733SPhilipp Zabel 	return 0;
1231b440b733SPhilipp Zabel }
1232b440b733SPhilipp Zabel 
tvp5150_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1233e545ac87SLaurent Pinchart static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
12340d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
1235e545ac87SLaurent Pinchart 		struct v4l2_subdev_mbus_code_enum *code)
1236e545ac87SLaurent Pinchart {
1237e545ac87SLaurent Pinchart 	if (code->pad || code->index)
1238e545ac87SLaurent Pinchart 		return -EINVAL;
1239e545ac87SLaurent Pinchart 
12405cb82940SMarco Felsch 	code->code = TVP5150_MBUS_FMT;
1241e545ac87SLaurent Pinchart 	return 0;
1242e545ac87SLaurent Pinchart }
1243e545ac87SLaurent Pinchart 
tvp5150_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)1244e545ac87SLaurent Pinchart static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
12450d346d2aSTomi Valkeinen 				   struct v4l2_subdev_state *sd_state,
1246e545ac87SLaurent Pinchart 				   struct v4l2_subdev_frame_size_enum *fse)
1247e545ac87SLaurent Pinchart {
1248e545ac87SLaurent Pinchart 	struct tvp5150 *decoder = to_tvp5150(sd);
1249e545ac87SLaurent Pinchart 
12505cb82940SMarco Felsch 	if (fse->index >= 8 || fse->code != TVP5150_MBUS_FMT)
1251e545ac87SLaurent Pinchart 		return -EINVAL;
1252e545ac87SLaurent Pinchart 
12535cb82940SMarco Felsch 	fse->code = TVP5150_MBUS_FMT;
1254e545ac87SLaurent Pinchart 	fse->min_width = decoder->rect.width;
1255e545ac87SLaurent Pinchart 	fse->max_width = decoder->rect.width;
1256e545ac87SLaurent Pinchart 	fse->min_height = decoder->rect.height / 2;
1257e545ac87SLaurent Pinchart 	fse->max_height = decoder->rect.height / 2;
1258e545ac87SLaurent Pinchart 
1259e545ac87SLaurent Pinchart 	return 0;
1260e545ac87SLaurent Pinchart }
1261e545ac87SLaurent Pinchart 
1262e545ac87SLaurent Pinchart /****************************************************************************
12630556f1d5SMarco Felsch  *			Media entity ops
12640556f1d5SMarco Felsch  ****************************************************************************/
12650556f1d5SMarco Felsch #if defined(CONFIG_MEDIA_CONTROLLER)
tvp5150_set_link(struct media_pad * connector_pad,struct media_pad * tvp5150_pad,u32 flags)12660556f1d5SMarco Felsch static int tvp5150_set_link(struct media_pad *connector_pad,
12670556f1d5SMarco Felsch 			    struct media_pad *tvp5150_pad, u32 flags)
12680556f1d5SMarco Felsch {
12690556f1d5SMarco Felsch 	struct media_link *link;
12700556f1d5SMarco Felsch 
12710556f1d5SMarco Felsch 	link = media_entity_find_link(connector_pad, tvp5150_pad);
12720556f1d5SMarco Felsch 	if (!link)
12730556f1d5SMarco Felsch 		return -EINVAL;
12740556f1d5SMarco Felsch 
12750556f1d5SMarco Felsch 	link->flags = flags;
12760556f1d5SMarco Felsch 	link->reverse->flags = link->flags;
12770556f1d5SMarco Felsch 
12780556f1d5SMarco Felsch 	return 0;
12790556f1d5SMarco Felsch }
12800556f1d5SMarco Felsch 
tvp5150_disable_all_input_links(struct tvp5150 * decoder)12810556f1d5SMarco Felsch static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
12820556f1d5SMarco Felsch {
12830556f1d5SMarco Felsch 	struct media_pad *connector_pad;
12840556f1d5SMarco Felsch 	unsigned int i;
12850556f1d5SMarco Felsch 	int err;
12860556f1d5SMarco Felsch 
12870556f1d5SMarco Felsch 	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
1288b2e44430SLaurent Pinchart 		connector_pad = media_pad_remote_pad_first(&decoder->pads[i]);
12890556f1d5SMarco Felsch 		if (!connector_pad)
12900556f1d5SMarco Felsch 			continue;
12910556f1d5SMarco Felsch 
12920556f1d5SMarco Felsch 		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
12930556f1d5SMarco Felsch 		if (err)
12940556f1d5SMarco Felsch 			return err;
12950556f1d5SMarco Felsch 	}
12960556f1d5SMarco Felsch 
12970556f1d5SMarco Felsch 	return 0;
12980556f1d5SMarco Felsch }
12990556f1d5SMarco Felsch 
13000556f1d5SMarco Felsch static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
13010556f1d5SMarco Felsch 			     u32 config);
13020556f1d5SMarco Felsch 
tvp5150_link_setup(struct media_entity * entity,const struct media_pad * tvp5150_pad,const struct media_pad * remote,u32 flags)13030556f1d5SMarco Felsch static int tvp5150_link_setup(struct media_entity *entity,
13040556f1d5SMarco Felsch 			      const struct media_pad *tvp5150_pad,
13050556f1d5SMarco Felsch 			      const struct media_pad *remote, u32 flags)
13060556f1d5SMarco Felsch {
13070556f1d5SMarco Felsch 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
13080556f1d5SMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
13090556f1d5SMarco Felsch 	struct media_pad *other_tvp5150_pad =
13100556f1d5SMarco Felsch 		&decoder->pads[tvp5150_pad->index ^ 1];
13110556f1d5SMarco Felsch 	struct v4l2_fwnode_connector *v4l2c;
13120556f1d5SMarco Felsch 	bool is_svideo = false;
13130556f1d5SMarco Felsch 	unsigned int i;
13140556f1d5SMarco Felsch 	int err;
13150556f1d5SMarco Felsch 
13160556f1d5SMarco Felsch 	/*
13170556f1d5SMarco Felsch 	 * The TVP5150 state is determined by the enabled sink pad link(s).
13180556f1d5SMarco Felsch 	 * Enabling or disabling the source pad link has no effect.
13190556f1d5SMarco Felsch 	 */
13200556f1d5SMarco Felsch 	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
13210556f1d5SMarco Felsch 		return 0;
13220556f1d5SMarco Felsch 
13230556f1d5SMarco Felsch 	/* Check if the svideo connector should be enabled */
13240556f1d5SMarco Felsch 	for (i = 0; i < decoder->connectors_num; i++) {
13250556f1d5SMarco Felsch 		if (remote->entity == &decoder->connectors[i].ent) {
13260556f1d5SMarco Felsch 			v4l2c = &decoder->connectors[i].base;
13270556f1d5SMarco Felsch 			is_svideo = v4l2c->type == V4L2_CONN_SVIDEO;
13280556f1d5SMarco Felsch 			break;
13290556f1d5SMarco Felsch 		}
13300556f1d5SMarco Felsch 	}
13310556f1d5SMarco Felsch 
13320556f1d5SMarco Felsch 	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
13330556f1d5SMarco Felsch 		    remote->entity->name, remote->index,
13340556f1d5SMarco Felsch 		    tvp5150_pad->entity->name, tvp5150_pad->index,
13350556f1d5SMarco Felsch 		    flags & MEDIA_LNK_FL_ENABLED);
13360556f1d5SMarco Felsch 	if (is_svideo)
13370556f1d5SMarco Felsch 		dev_dbg_lvl(sd->dev, 1, debug,
13380556f1d5SMarco Felsch 			    "link setup '%s':%d->'%s':%d[%d]",
13390556f1d5SMarco Felsch 			    remote->entity->name, remote->index,
13400556f1d5SMarco Felsch 			    other_tvp5150_pad->entity->name,
13410556f1d5SMarco Felsch 			    other_tvp5150_pad->index,
13420556f1d5SMarco Felsch 			    flags & MEDIA_LNK_FL_ENABLED);
13430556f1d5SMarco Felsch 
13440556f1d5SMarco Felsch 	/*
13450556f1d5SMarco Felsch 	 * The TVP5150 has an internal mux which allows the following setup:
13460556f1d5SMarco Felsch 	 *
13470556f1d5SMarco Felsch 	 * comp-connector1  --\
13480556f1d5SMarco Felsch 	 *		       |---> AIP1A
13490556f1d5SMarco Felsch 	 *		      /
13500556f1d5SMarco Felsch 	 * svideo-connector -|
13510556f1d5SMarco Felsch 	 *		      \
13520556f1d5SMarco Felsch 	 *		       |---> AIP1B
13530556f1d5SMarco Felsch 	 * comp-connector2  --/
13540556f1d5SMarco Felsch 	 *
13550556f1d5SMarco Felsch 	 * We can't rely on user space that the current connector gets disabled
13560556f1d5SMarco Felsch 	 * first before enabling the new connector. Disable all active
13570556f1d5SMarco Felsch 	 * connector links to be on the safe side.
13580556f1d5SMarco Felsch 	 */
13590556f1d5SMarco Felsch 	err = tvp5150_disable_all_input_links(decoder);
13600556f1d5SMarco Felsch 	if (err)
13610556f1d5SMarco Felsch 		return err;
13620556f1d5SMarco Felsch 
13630556f1d5SMarco Felsch 	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
13640556f1d5SMarco Felsch 			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
13650556f1d5SMarco Felsch 			  TVP5150_BLACK_SCREEN, 0);
13660556f1d5SMarco Felsch 
13670556f1d5SMarco Felsch 	if (flags & MEDIA_LNK_FL_ENABLED) {
1368baf17821SMarco Felsch 		struct v4l2_fwnode_connector_analog *v4l2ca;
1369baf17821SMarco Felsch 		u32 new_norm;
1370baf17821SMarco Felsch 
13710556f1d5SMarco Felsch 		/*
13720556f1d5SMarco Felsch 		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
13730556f1d5SMarco Felsch 		 * Both links must be enabled in one-shot regardless which link
13740556f1d5SMarco Felsch 		 * the user requests.
13750556f1d5SMarco Felsch 		 */
13760556f1d5SMarco Felsch 		if (is_svideo) {
13770556f1d5SMarco Felsch 			err = tvp5150_set_link((struct media_pad *)remote,
13780556f1d5SMarco Felsch 					       other_tvp5150_pad, flags);
13790556f1d5SMarco Felsch 			if (err)
13800556f1d5SMarco Felsch 				return err;
13810556f1d5SMarco Felsch 		}
1382baf17821SMarco Felsch 
1383baf17821SMarco Felsch 		if (!decoder->connectors_num)
1384baf17821SMarco Felsch 			return 0;
1385baf17821SMarco Felsch 
1386baf17821SMarco Felsch 		/* Update the current connector */
1387baf17821SMarco Felsch 		decoder->cur_connector =
1388baf17821SMarco Felsch 			container_of(remote, struct tvp5150_connector, pad);
1389baf17821SMarco Felsch 
1390baf17821SMarco Felsch 		/*
1391baf17821SMarco Felsch 		 * Do nothing if the new connector supports the same tv-norms as
1392baf17821SMarco Felsch 		 * the old one.
1393baf17821SMarco Felsch 		 */
1394baf17821SMarco Felsch 		v4l2ca = &decoder->cur_connector->base.connector.analog;
1395baf17821SMarco Felsch 		new_norm = decoder->norm & v4l2ca->sdtv_stds;
1396baf17821SMarco Felsch 		if (decoder->norm == new_norm)
1397baf17821SMarco Felsch 			return 0;
1398baf17821SMarco Felsch 
1399baf17821SMarco Felsch 		/*
1400baf17821SMarco Felsch 		 * Fallback to the new connector tv-norms if we can't find any
1401baf17821SMarco Felsch 		 * common between the current tv-norm and the new one.
1402baf17821SMarco Felsch 		 */
1403baf17821SMarco Felsch 		tvp5150_s_std(sd, new_norm ? new_norm : v4l2ca->sdtv_stds);
14040556f1d5SMarco Felsch 	}
14050556f1d5SMarco Felsch 
14060556f1d5SMarco Felsch 	return 0;
14070556f1d5SMarco Felsch }
14080556f1d5SMarco Felsch 
14090556f1d5SMarco Felsch static const struct media_entity_operations tvp5150_sd_media_ops = {
14100556f1d5SMarco Felsch 	.link_setup = tvp5150_link_setup,
14110556f1d5SMarco Felsch };
14120556f1d5SMarco Felsch #endif
14130556f1d5SMarco Felsch /****************************************************************************
1414cb7a01acSMauro Carvalho Chehab 			I2C Command
1415cb7a01acSMauro Carvalho Chehab  ****************************************************************************/
tvp5150_runtime_suspend(struct device * dev)141673549a69SMarco Felsch static int __maybe_unused tvp5150_runtime_suspend(struct device *dev)
141773549a69SMarco Felsch {
14181c891423SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
141973549a69SMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
142073549a69SMarco Felsch 
142173549a69SMarco Felsch 	if (decoder->irq)
142273549a69SMarco Felsch 		/* Disable lock interrupt */
142373549a69SMarco Felsch 		return regmap_update_bits(decoder->regmap,
142473549a69SMarco Felsch 					  TVP5150_INT_ENABLE_REG_A,
142573549a69SMarco Felsch 					  TVP5150_INT_A_LOCK, 0);
142673549a69SMarco Felsch 	return 0;
142773549a69SMarco Felsch }
142873549a69SMarco Felsch 
tvp5150_runtime_resume(struct device * dev)142973549a69SMarco Felsch static int __maybe_unused tvp5150_runtime_resume(struct device *dev)
143073549a69SMarco Felsch {
14311c891423SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
143273549a69SMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
143373549a69SMarco Felsch 
143473549a69SMarco Felsch 	if (decoder->irq)
143573549a69SMarco Felsch 		/* Enable lock interrupt */
143673549a69SMarco Felsch 		return regmap_update_bits(decoder->regmap,
143773549a69SMarco Felsch 					  TVP5150_INT_ENABLE_REG_A,
143873549a69SMarco Felsch 					  TVP5150_INT_A_LOCK,
143973549a69SMarco Felsch 					  TVP5150_INT_A_LOCK);
144073549a69SMarco Felsch 	return 0;
144173549a69SMarco Felsch }
1442cb7a01acSMauro Carvalho Chehab 
tvp5150_s_stream(struct v4l2_subdev * sd,int enable)1443460b6c08SLaurent Pinchart static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
1444460b6c08SLaurent Pinchart {
1445a2e5f1b3SJavier Martinez Canillas 	struct tvp5150 *decoder = to_tvp5150(sd);
144673549a69SMarco Felsch 	unsigned int mask, val = 0;
144773549a69SMarco Felsch 	int ret;
1448a2e5f1b3SJavier Martinez Canillas 
14498a7441baSMarco Felsch 	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
14508a7441baSMarco Felsch 	       TVP5150_MISC_CTL_CLOCK_OE;
145179d6205aSLaurent Pinchart 
145279d6205aSLaurent Pinchart 	if (enable) {
145381f2fe55SMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(sd->dev);
145481f2fe55SMauro Carvalho Chehab 		if (ret < 0)
145573549a69SMarco Felsch 			return ret;
145673549a69SMarco Felsch 
14571bb086bcSPhilipp Zabel 		tvp5150_enable(sd);
14581bb086bcSPhilipp Zabel 
145962a764e1SPhilipp Zabel 		/* Enable outputs if decoder is locked */
14605bd1d91dSMauro Carvalho Chehab 		if (decoder->irq)
146162a764e1SPhilipp Zabel 			val = decoder->lock ? decoder->oe : 0;
14625bd1d91dSMauro Carvalho Chehab 		else
14635bd1d91dSMauro Carvalho Chehab 			val = decoder->oe;
146473549a69SMarco Felsch 
14652f0a5c65SPhilipp Zabel 		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
146673549a69SMarco Felsch 	} else {
146773549a69SMarco Felsch 		pm_runtime_put(sd->dev);
146879d6205aSLaurent Pinchart 	}
1469a2e5f1b3SJavier Martinez Canillas 
14708a7441baSMarco Felsch 	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
1471460b6c08SLaurent Pinchart 
1472460b6c08SLaurent Pinchart 	return 0;
1473460b6c08SLaurent Pinchart }
1474460b6c08SLaurent Pinchart 
tvp5150_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)1475cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd,
1476cb7a01acSMauro Carvalho Chehab 			     u32 input, u32 output, u32 config)
1477cb7a01acSMauro Carvalho Chehab {
1478cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
1479cb7a01acSMauro Carvalho Chehab 
1480cb7a01acSMauro Carvalho Chehab 	decoder->input = input;
1481cb7a01acSMauro Carvalho Chehab 	decoder->output = output;
1482c43875f6SMauro Carvalho Chehab 
1483c43875f6SMauro Carvalho Chehab 	if (output == TVP5150_BLACK_SCREEN)
1484c43875f6SMauro Carvalho Chehab 		decoder->enable = false;
1485c43875f6SMauro Carvalho Chehab 	else
1486c43875f6SMauro Carvalho Chehab 		decoder->enable = true;
1487c43875f6SMauro Carvalho Chehab 
1488cb7a01acSMauro Carvalho Chehab 	tvp5150_selmux(sd);
1489cb7a01acSMauro Carvalho Chehab 	return 0;
1490cb7a01acSMauro Carvalho Chehab }
1491cb7a01acSMauro Carvalho Chehab 
tvp5150_s_raw_fmt(struct v4l2_subdev * sd,struct v4l2_vbi_format * fmt)1492cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
1493cb7a01acSMauro Carvalho Chehab {
149428b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
149528b9e227SPhilipp Zabel 
14969bfd8f88SNasser Afshin 	/*
14979bfd8f88SNasser Afshin 	 * this is for capturing 36 raw vbi lines
14989bfd8f88SNasser Afshin 	 * if there's a way to cut off the beginning 2 vbi lines
14999bfd8f88SNasser Afshin 	 * with the tvp5150 then the vbi line count could be lowered
15009bfd8f88SNasser Afshin 	 * to 17 lines/field again, although I couldn't find a register
15019bfd8f88SNasser Afshin 	 * which could do that cropping
15029bfd8f88SNasser Afshin 	 */
15039bfd8f88SNasser Afshin 
1504cb7a01acSMauro Carvalho Chehab 	if (fmt->sample_format == V4L2_PIX_FMT_GREY)
150528b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_LUMA_PROC_CTL_1, 0x70);
1506cb7a01acSMauro Carvalho Chehab 	if (fmt->count[0] == 18 && fmt->count[1] == 18) {
150728b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START,
150828b9e227SPhilipp Zabel 			     0x00);
150928b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 0x01);
1510cb7a01acSMauro Carvalho Chehab 	}
1511cb7a01acSMauro Carvalho Chehab 	return 0;
1512cb7a01acSMauro Carvalho Chehab }
1513cb7a01acSMauro Carvalho Chehab 
tvp5150_s_sliced_fmt(struct v4l2_subdev * sd,struct v4l2_sliced_vbi_format * svbi)1514cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
1515cb7a01acSMauro Carvalho Chehab {
151628b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
1517cb7a01acSMauro Carvalho Chehab 	int i;
1518cb7a01acSMauro Carvalho Chehab 
1519cb7a01acSMauro Carvalho Chehab 	if (svbi->service_set != 0) {
1520cb7a01acSMauro Carvalho Chehab 		for (i = 0; i <= 23; i++) {
1521cb7a01acSMauro Carvalho Chehab 			svbi->service_lines[1][i] = 0;
1522cb7a01acSMauro Carvalho Chehab 			svbi->service_lines[0][i] =
15233dd6b560SMauro Carvalho Chehab 				tvp5150_set_vbi(sd, svbi->service_lines[0][i],
15243dd6b560SMauro Carvalho Chehab 						0xf0, i, 3);
1525cb7a01acSMauro Carvalho Chehab 		}
1526cb7a01acSMauro Carvalho Chehab 		/* Enables FIFO */
152728b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 1);
1528cb7a01acSMauro Carvalho Chehab 	} else {
1529cb7a01acSMauro Carvalho Chehab 		/* Disables FIFO*/
153028b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 0);
1531cb7a01acSMauro Carvalho Chehab 
1532cb7a01acSMauro Carvalho Chehab 		/* Disable Full Field */
153328b9e227SPhilipp Zabel 		regmap_write(decoder->regmap, TVP5150_FULL_FIELD_ENA, 0);
1534cb7a01acSMauro Carvalho Chehab 
1535cb7a01acSMauro Carvalho Chehab 		/* Disable Line modes */
1536cb7a01acSMauro Carvalho Chehab 		for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
153728b9e227SPhilipp Zabel 			regmap_write(decoder->regmap, i, 0xff);
1538cb7a01acSMauro Carvalho Chehab 	}
1539cb7a01acSMauro Carvalho Chehab 	return 0;
1540cb7a01acSMauro Carvalho Chehab }
1541cb7a01acSMauro Carvalho Chehab 
tvp5150_g_sliced_fmt(struct v4l2_subdev * sd,struct v4l2_sliced_vbi_format * svbi)1542cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
1543cb7a01acSMauro Carvalho Chehab {
1544cb7a01acSMauro Carvalho Chehab 	int i, mask = 0;
1545cb7a01acSMauro Carvalho Chehab 
154630634e8eSHans Verkuil 	memset(svbi->service_lines, 0, sizeof(svbi->service_lines));
1547cb7a01acSMauro Carvalho Chehab 
1548cb7a01acSMauro Carvalho Chehab 	for (i = 0; i <= 23; i++) {
1549cb7a01acSMauro Carvalho Chehab 		svbi->service_lines[0][i] =
15503dd6b560SMauro Carvalho Chehab 			tvp5150_get_vbi(sd, i);
1551cb7a01acSMauro Carvalho Chehab 		mask |= svbi->service_lines[0][i];
1552cb7a01acSMauro Carvalho Chehab 	}
1553cb7a01acSMauro Carvalho Chehab 	svbi->service_set = mask;
1554cb7a01acSMauro Carvalho Chehab 	return 0;
1555cb7a01acSMauro Carvalho Chehab }
1556cb7a01acSMauro Carvalho Chehab 
1557cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
tvp5150_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)1558cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
1559cb7a01acSMauro Carvalho Chehab {
1560cb7a01acSMauro Carvalho Chehab 	int res;
1561cb7a01acSMauro Carvalho Chehab 
1562cb7a01acSMauro Carvalho Chehab 	res = tvp5150_read(sd, reg->reg & 0xff);
1563cb7a01acSMauro Carvalho Chehab 	if (res < 0) {
1564257e29f8SMauro Carvalho Chehab 		dev_err(sd->dev, "%s: failed with error = %d\n", __func__, res);
1565cb7a01acSMauro Carvalho Chehab 		return res;
1566cb7a01acSMauro Carvalho Chehab 	}
1567cb7a01acSMauro Carvalho Chehab 
1568cb7a01acSMauro Carvalho Chehab 	reg->val = res;
1569cb7a01acSMauro Carvalho Chehab 	reg->size = 1;
1570cb7a01acSMauro Carvalho Chehab 	return 0;
1571cb7a01acSMauro Carvalho Chehab }
1572cb7a01acSMauro Carvalho Chehab 
tvp5150_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)1573977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
1574cb7a01acSMauro Carvalho Chehab {
157528b9e227SPhilipp Zabel 	struct tvp5150 *decoder = to_tvp5150(sd);
157628b9e227SPhilipp Zabel 
157728b9e227SPhilipp Zabel 	return regmap_write(decoder->regmap, reg->reg & 0xff, reg->val & 0xff);
1578cb7a01acSMauro Carvalho Chehab }
1579cb7a01acSMauro Carvalho Chehab #endif
1580cb7a01acSMauro Carvalho Chehab 
tvp5150_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)1581e953c103SMarco Felsch static int tvp5150_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
1582e953c103SMarco Felsch 				   struct v4l2_event_subscription *sub)
1583e953c103SMarco Felsch {
1584e953c103SMarco Felsch 	switch (sub->type) {
1585e953c103SMarco Felsch 	case V4L2_EVENT_SOURCE_CHANGE:
1586e953c103SMarco Felsch 		return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
1587e953c103SMarco Felsch 	case V4L2_EVENT_CTRL:
1588e953c103SMarco Felsch 		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
1589e953c103SMarco Felsch 	default:
1590e953c103SMarco Felsch 		return -EINVAL;
1591e953c103SMarco Felsch 	}
1592e953c103SMarco Felsch }
1593e953c103SMarco Felsch 
tvp5150_g_tuner(struct v4l2_subdev * sd,struct v4l2_tuner * vt)1594cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1595cb7a01acSMauro Carvalho Chehab {
1596cb7a01acSMauro Carvalho Chehab 	int status = tvp5150_read(sd, 0x88);
1597cb7a01acSMauro Carvalho Chehab 
1598cb7a01acSMauro Carvalho Chehab 	vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
1599cb7a01acSMauro Carvalho Chehab 	return 0;
1600cb7a01acSMauro Carvalho Chehab }
1601cb7a01acSMauro Carvalho Chehab 
tvp5150_registered(struct v4l2_subdev * sd)16020556f1d5SMarco Felsch static int tvp5150_registered(struct v4l2_subdev *sd)
16030556f1d5SMarco Felsch {
16040556f1d5SMarco Felsch #if defined(CONFIG_MEDIA_CONTROLLER)
16050556f1d5SMarco Felsch 	struct tvp5150 *decoder = to_tvp5150(sd);
16060556f1d5SMarco Felsch 	unsigned int i;
16070556f1d5SMarco Felsch 	int ret;
16080556f1d5SMarco Felsch 
16090556f1d5SMarco Felsch 	/*
16100556f1d5SMarco Felsch 	 * Setup connector pads and links. Enable the link to the first
16110556f1d5SMarco Felsch 	 * available connector per default.
16120556f1d5SMarco Felsch 	 */
16130556f1d5SMarco Felsch 	for (i = 0; i < decoder->connectors_num; i++) {
16140556f1d5SMarco Felsch 		struct media_entity *con = &decoder->connectors[i].ent;
16150556f1d5SMarco Felsch 		struct media_pad *pad = &decoder->connectors[i].pad;
16160556f1d5SMarco Felsch 		struct v4l2_fwnode_connector *v4l2c =
16170556f1d5SMarco Felsch 			&decoder->connectors[i].base;
16180556f1d5SMarco Felsch 		struct v4l2_connector_link *link =
16190556f1d5SMarco Felsch 			v4l2_connector_first_link(v4l2c);
16200556f1d5SMarco Felsch 		unsigned int port = link->fwnode_link.remote_port;
16210556f1d5SMarco Felsch 		unsigned int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
16220556f1d5SMarco Felsch 		bool is_svideo = v4l2c->type == V4L2_CONN_SVIDEO;
16230556f1d5SMarco Felsch 
16240556f1d5SMarco Felsch 		pad->flags = MEDIA_PAD_FL_SOURCE;
16250556f1d5SMarco Felsch 		ret = media_entity_pads_init(con, 1, pad);
16260556f1d5SMarco Felsch 		if (ret < 0)
16270556f1d5SMarco Felsch 			goto err;
16280556f1d5SMarco Felsch 
16290556f1d5SMarco Felsch 		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
16300556f1d5SMarco Felsch 		if (ret < 0)
16310556f1d5SMarco Felsch 			goto err;
16320556f1d5SMarco Felsch 
16330556f1d5SMarco Felsch 		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
16340556f1d5SMarco Felsch 		if (ret < 0)
16350556f1d5SMarco Felsch 			goto err;
16360556f1d5SMarco Felsch 
16370556f1d5SMarco Felsch 		if (is_svideo) {
16380556f1d5SMarco Felsch 			/*
16390556f1d5SMarco Felsch 			 * Check tvp5150_link_setup() comments for more
16400556f1d5SMarco Felsch 			 * information.
16410556f1d5SMarco Felsch 			 */
16420556f1d5SMarco Felsch 			link = v4l2_connector_last_link(v4l2c);
16430556f1d5SMarco Felsch 			port = link->fwnode_link.remote_port;
16440556f1d5SMarco Felsch 			ret = media_create_pad_link(con, 0, &sd->entity, port,
16450556f1d5SMarco Felsch 						    flags);
16460556f1d5SMarco Felsch 			if (ret < 0)
16470556f1d5SMarco Felsch 				goto err;
16480556f1d5SMarco Felsch 		}
16490556f1d5SMarco Felsch 
16500556f1d5SMarco Felsch 		/* Enable default input. */
16510556f1d5SMarco Felsch 		if (flags == MEDIA_LNK_FL_ENABLED) {
16520556f1d5SMarco Felsch 			decoder->input =
16530556f1d5SMarco Felsch 				is_svideo ? TVP5150_SVIDEO :
16540556f1d5SMarco Felsch 				port == 0 ? TVP5150_COMPOSITE0 :
16550556f1d5SMarco Felsch 				TVP5150_COMPOSITE1;
16560556f1d5SMarco Felsch 
16570556f1d5SMarco Felsch 			tvp5150_selmux(sd);
1658baf17821SMarco Felsch 			decoder->cur_connector = &decoder->connectors[i];
1659baf17821SMarco Felsch 			tvp5150_s_std(sd, v4l2c->connector.analog.sdtv_stds);
16600556f1d5SMarco Felsch 		}
16610556f1d5SMarco Felsch 	}
16620556f1d5SMarco Felsch 
16630556f1d5SMarco Felsch 	return 0;
16640556f1d5SMarco Felsch 
16650556f1d5SMarco Felsch err:
1666d000e9b5SChuhong Yuan 	for (i = 0; i < decoder->connectors_num; i++) {
16670556f1d5SMarco Felsch 		media_device_unregister_entity(&decoder->connectors[i].ent);
1668d000e9b5SChuhong Yuan 		media_entity_cleanup(&decoder->connectors[i].ent);
1669d000e9b5SChuhong Yuan 	}
16700556f1d5SMarco Felsch 	return ret;
16710556f1d5SMarco Felsch #endif
16720556f1d5SMarco Felsch 
16730556f1d5SMarco Felsch 	return 0;
16740556f1d5SMarco Felsch }
16750556f1d5SMarco Felsch 
tvp5150_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)16769c8e5098SMarco Felsch static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
16779c8e5098SMarco Felsch {
167881f2fe55SMauro Carvalho Chehab 	return pm_runtime_resume_and_get(sd->dev);
16799c8e5098SMarco Felsch }
16809c8e5098SMarco Felsch 
tvp5150_close(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)16819c8e5098SMarco Felsch static int tvp5150_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
16829c8e5098SMarco Felsch {
16839c8e5098SMarco Felsch 	pm_runtime_put(sd->dev);
16849c8e5098SMarco Felsch 
16859c8e5098SMarco Felsch 	return 0;
16869c8e5098SMarco Felsch }
16879c8e5098SMarco Felsch 
1688cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1689cb7a01acSMauro Carvalho Chehab 
1690cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
1691cb7a01acSMauro Carvalho Chehab 	.s_ctrl = tvp5150_s_ctrl,
1692cb7a01acSMauro Carvalho Chehab };
1693cb7a01acSMauro Carvalho Chehab 
1694cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
1695cb7a01acSMauro Carvalho Chehab 	.log_status = tvp5150_log_status,
1696cb7a01acSMauro Carvalho Chehab 	.reset = tvp5150_reset,
1697cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
1698cb7a01acSMauro Carvalho Chehab 	.g_register = tvp5150_g_register,
1699cb7a01acSMauro Carvalho Chehab 	.s_register = tvp5150_s_register,
1700cb7a01acSMauro Carvalho Chehab #endif
1701e953c103SMarco Felsch 	.subscribe_event = tvp5150_subscribe_event,
1702e953c103SMarco Felsch 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
1703cb7a01acSMauro Carvalho Chehab };
1704cb7a01acSMauro Carvalho Chehab 
1705cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
1706cb7a01acSMauro Carvalho Chehab 	.g_tuner = tvp5150_g_tuner,
1707cb7a01acSMauro Carvalho Chehab };
1708cb7a01acSMauro Carvalho Chehab 
1709cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
17108774bed9SLaurent Pinchart 	.s_std = tvp5150_s_std,
17110db87cc7SMarco Felsch 	.g_std = tvp5150_g_std,
1712ee9a6ff6SPhilipp Zabel 	.querystd = tvp5150_querystd,
1713460b6c08SLaurent Pinchart 	.s_stream = tvp5150_s_stream,
1714cb7a01acSMauro Carvalho Chehab 	.s_routing = tvp5150_s_routing,
1715cb7a01acSMauro Carvalho Chehab };
1716cb7a01acSMauro Carvalho Chehab 
1717cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
1718cb7a01acSMauro Carvalho Chehab 	.g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap,
1719cb7a01acSMauro Carvalho Chehab 	.g_sliced_fmt = tvp5150_g_sliced_fmt,
1720cb7a01acSMauro Carvalho Chehab 	.s_sliced_fmt = tvp5150_s_sliced_fmt,
1721cb7a01acSMauro Carvalho Chehab 	.s_raw_fmt = tvp5150_s_raw_fmt,
1722cb7a01acSMauro Carvalho Chehab };
1723cb7a01acSMauro Carvalho Chehab 
1724ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
1725b440b733SPhilipp Zabel 	.init_cfg = tvp5150_init_cfg,
1726ebcff5fcSHans Verkuil 	.enum_mbus_code = tvp5150_enum_mbus_code,
1727e545ac87SLaurent Pinchart 	.enum_frame_size = tvp5150_enum_frame_size,
1728da298c6dSHans Verkuil 	.set_fmt = tvp5150_fill_fmt,
1729da298c6dSHans Verkuil 	.get_fmt = tvp5150_fill_fmt,
173010d5509cSHans Verkuil 	.get_selection = tvp5150_get_selection,
173110d5509cSHans Verkuil 	.set_selection = tvp5150_set_selection,
17320c3da525SJacopo Mondi 	.get_mbus_config = tvp5150_get_mbus_config,
1733ebcff5fcSHans Verkuil };
1734ebcff5fcSHans Verkuil 
1735cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = {
1736cb7a01acSMauro Carvalho Chehab 	.core = &tvp5150_core_ops,
1737cb7a01acSMauro Carvalho Chehab 	.tuner = &tvp5150_tuner_ops,
1738cb7a01acSMauro Carvalho Chehab 	.video = &tvp5150_video_ops,
1739cb7a01acSMauro Carvalho Chehab 	.vbi = &tvp5150_vbi_ops,
1740ebcff5fcSHans Verkuil 	.pad = &tvp5150_pad_ops,
1741cb7a01acSMauro Carvalho Chehab };
1742cb7a01acSMauro Carvalho Chehab 
17430556f1d5SMarco Felsch static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
17440556f1d5SMarco Felsch 	.registered = tvp5150_registered,
17459c8e5098SMarco Felsch 	.open = tvp5150_open,
17469c8e5098SMarco Felsch 	.close = tvp5150_close,
17470556f1d5SMarco Felsch };
17480556f1d5SMarco Felsch 
1749cb7a01acSMauro Carvalho Chehab /****************************************************************************
1750cb7a01acSMauro Carvalho Chehab 			I2C Client & Driver
1751cb7a01acSMauro Carvalho Chehab  ****************************************************************************/
1752cb7a01acSMauro Carvalho Chehab 
175328b9e227SPhilipp Zabel static const struct regmap_range tvp5150_readable_ranges[] = {
175428b9e227SPhilipp Zabel 	{
175528b9e227SPhilipp Zabel 		.range_min = TVP5150_VD_IN_SRC_SEL_1,
175628b9e227SPhilipp Zabel 		.range_max = TVP5150_AUTOSW_MSK,
175728b9e227SPhilipp Zabel 	}, {
175828b9e227SPhilipp Zabel 		.range_min = TVP5150_COLOR_KIL_THSH_CTL,
175928b9e227SPhilipp Zabel 		.range_max = TVP5150_CONF_SHARED_PIN,
176028b9e227SPhilipp Zabel 	}, {
176128b9e227SPhilipp Zabel 		.range_min = TVP5150_ACT_VD_CROP_ST_MSB,
176228b9e227SPhilipp Zabel 		.range_max = TVP5150_HORIZ_SYNC_START,
176328b9e227SPhilipp Zabel 	}, {
176428b9e227SPhilipp Zabel 		.range_min = TVP5150_VERT_BLANKING_START,
176528b9e227SPhilipp Zabel 		.range_max = TVP5150_INTT_CONFIG_REG_B,
176628b9e227SPhilipp Zabel 	}, {
176728b9e227SPhilipp Zabel 		.range_min = TVP5150_VIDEO_STD,
176828b9e227SPhilipp Zabel 		.range_max = TVP5150_VIDEO_STD,
176928b9e227SPhilipp Zabel 	}, {
177028b9e227SPhilipp Zabel 		.range_min = TVP5150_CB_GAIN_FACT,
177128b9e227SPhilipp Zabel 		.range_max = TVP5150_REV_SELECT,
177228b9e227SPhilipp Zabel 	}, {
177328b9e227SPhilipp Zabel 		.range_min = TVP5150_MSB_DEV_ID,
177428b9e227SPhilipp Zabel 		.range_max = TVP5150_STATUS_REG_5,
177528b9e227SPhilipp Zabel 	}, {
177628b9e227SPhilipp Zabel 		.range_min = TVP5150_CC_DATA_INI,
177728b9e227SPhilipp Zabel 		.range_max = TVP5150_TELETEXT_FIL_ENA,
177828b9e227SPhilipp Zabel 	}, {
177928b9e227SPhilipp Zabel 		.range_min = TVP5150_INT_STATUS_REG_A,
178028b9e227SPhilipp Zabel 		.range_max = TVP5150_FIFO_OUT_CTRL,
178128b9e227SPhilipp Zabel 	}, {
178228b9e227SPhilipp Zabel 		.range_min = TVP5150_FULL_FIELD_ENA,
178328b9e227SPhilipp Zabel 		.range_max = TVP5150_FULL_FIELD_MODE_REG,
178428b9e227SPhilipp Zabel 	},
178528b9e227SPhilipp Zabel };
178628b9e227SPhilipp Zabel 
tvp5150_volatile_reg(struct device * dev,unsigned int reg)1787c135e997SMauro Carvalho Chehab static bool tvp5150_volatile_reg(struct device *dev, unsigned int reg)
178828b9e227SPhilipp Zabel {
178928b9e227SPhilipp Zabel 	switch (reg) {
179028b9e227SPhilipp Zabel 	case TVP5150_VERT_LN_COUNT_MSB:
179128b9e227SPhilipp Zabel 	case TVP5150_VERT_LN_COUNT_LSB:
179228b9e227SPhilipp Zabel 	case TVP5150_INT_STATUS_REG_A:
179328b9e227SPhilipp Zabel 	case TVP5150_INT_STATUS_REG_B:
179428b9e227SPhilipp Zabel 	case TVP5150_INT_ACTIVE_REG_B:
179528b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_1:
179628b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_2:
179728b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_3:
179828b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_4:
179928b9e227SPhilipp Zabel 	case TVP5150_STATUS_REG_5:
180028b9e227SPhilipp Zabel 	/* CC, WSS, VPS, VITC data? */
180128b9e227SPhilipp Zabel 	case TVP5150_VBI_FIFO_READ_DATA:
180228b9e227SPhilipp Zabel 	case TVP5150_VDP_STATUS_REG:
180328b9e227SPhilipp Zabel 	case TVP5150_FIFO_WORD_COUNT:
180428b9e227SPhilipp Zabel 		return true;
180528b9e227SPhilipp Zabel 	default:
180628b9e227SPhilipp Zabel 		return false;
180728b9e227SPhilipp Zabel 	}
180828b9e227SPhilipp Zabel }
180928b9e227SPhilipp Zabel 
181028b9e227SPhilipp Zabel static const struct regmap_access_table tvp5150_readable_table = {
181128b9e227SPhilipp Zabel 	.yes_ranges = tvp5150_readable_ranges,
181228b9e227SPhilipp Zabel 	.n_yes_ranges = ARRAY_SIZE(tvp5150_readable_ranges),
181328b9e227SPhilipp Zabel };
181428b9e227SPhilipp Zabel 
181528b9e227SPhilipp Zabel static struct regmap_config tvp5150_config = {
181628b9e227SPhilipp Zabel 	.reg_bits = 8,
181728b9e227SPhilipp Zabel 	.val_bits = 8,
181828b9e227SPhilipp Zabel 	.max_register = 0xff,
181928b9e227SPhilipp Zabel 
182028b9e227SPhilipp Zabel 	.cache_type = REGCACHE_RBTREE,
182128b9e227SPhilipp Zabel 
182228b9e227SPhilipp Zabel 	.rd_table = &tvp5150_readable_table,
182328b9e227SPhilipp Zabel 	.volatile_reg = tvp5150_volatile_reg,
182428b9e227SPhilipp Zabel };
182528b9e227SPhilipp Zabel 
tvp5150_detect_version(struct tvp5150 * core)18267871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core)
18277871597aSLaurent Pinchart {
18287871597aSLaurent Pinchart 	struct v4l2_subdev *sd = &core->sd;
18297871597aSLaurent Pinchart 	struct i2c_client *c = v4l2_get_subdevdata(sd);
18307871597aSLaurent Pinchart 	u8 regs[4];
18317871597aSLaurent Pinchart 	int res;
18327871597aSLaurent Pinchart 
18337871597aSLaurent Pinchart 	/*
18347871597aSLaurent Pinchart 	 * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
18357871597aSLaurent Pinchart 	 * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER
18367871597aSLaurent Pinchart 	 */
183728b9e227SPhilipp Zabel 	res = regmap_bulk_read(core->regmap, TVP5150_MSB_DEV_ID, regs, 4);
183828b9e227SPhilipp Zabel 	if (res < 0) {
183928b9e227SPhilipp Zabel 		dev_err(&c->dev, "reading ID registers failed: %d\n", res);
18407871597aSLaurent Pinchart 		return res;
18417871597aSLaurent Pinchart 	}
18427871597aSLaurent Pinchart 
184382275133SJavier Martinez Canillas 	core->dev_id = (regs[0] << 8) | regs[1];
184482275133SJavier Martinez Canillas 	core->rom_ver = (regs[2] << 8) | regs[3];
18457871597aSLaurent Pinchart 
1846257e29f8SMauro Carvalho Chehab 	dev_info(sd->dev, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n",
184782275133SJavier Martinez Canillas 		  core->dev_id, regs[2], regs[3], c->addr << 1,
184882275133SJavier Martinez Canillas 		  c->adapter->name);
18497871597aSLaurent Pinchart 
185082275133SJavier Martinez Canillas 	if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) {
1851257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "tvp5150a detected.\n");
185282275133SJavier Martinez Canillas 	} else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) {
1853257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "tvp5150am1 detected.\n");
18547871597aSLaurent Pinchart 
18557871597aSLaurent Pinchart 		/* ITU-T BT.656.4 timing */
185628b9e227SPhilipp Zabel 		regmap_write(core->regmap, TVP5150_REV_SELECT, 0);
185782275133SJavier Martinez Canillas 	} else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) {
1858257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "tvp5151 detected.\n");
18597871597aSLaurent Pinchart 	} else {
1860257e29f8SMauro Carvalho Chehab 		dev_info(sd->dev, "*** unknown tvp%04x chip detected.\n",
186182275133SJavier Martinez Canillas 			  core->dev_id);
18627871597aSLaurent Pinchart 	}
18637871597aSLaurent Pinchart 
18647871597aSLaurent Pinchart 	return 0;
18657871597aSLaurent Pinchart }
18667871597aSLaurent Pinchart 
tvp5150_init(struct i2c_client * c)186709aa2609SJavier Martinez Canillas static int tvp5150_init(struct i2c_client *c)
186809aa2609SJavier Martinez Canillas {
186909aa2609SJavier Martinez Canillas 	struct gpio_desc *pdn_gpio;
187009aa2609SJavier Martinez Canillas 	struct gpio_desc *reset_gpio;
187109aa2609SJavier Martinez Canillas 
187209aa2609SJavier Martinez Canillas 	pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH);
187309aa2609SJavier Martinez Canillas 	if (IS_ERR(pdn_gpio))
187409aa2609SJavier Martinez Canillas 		return PTR_ERR(pdn_gpio);
187509aa2609SJavier Martinez Canillas 
187609aa2609SJavier Martinez Canillas 	if (pdn_gpio) {
187709aa2609SJavier Martinez Canillas 		gpiod_set_value_cansleep(pdn_gpio, 0);
187809aa2609SJavier Martinez Canillas 		/* Delay time between power supplies active and reset */
187909aa2609SJavier Martinez Canillas 		msleep(20);
188009aa2609SJavier Martinez Canillas 	}
188109aa2609SJavier Martinez Canillas 
188209aa2609SJavier Martinez Canillas 	reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH);
188309aa2609SJavier Martinez Canillas 	if (IS_ERR(reset_gpio))
188409aa2609SJavier Martinez Canillas 		return PTR_ERR(reset_gpio);
188509aa2609SJavier Martinez Canillas 
188609aa2609SJavier Martinez Canillas 	if (reset_gpio) {
188709aa2609SJavier Martinez Canillas 		/* RESETB pulse duration */
188809aa2609SJavier Martinez Canillas 		ndelay(500);
188909aa2609SJavier Martinez Canillas 		gpiod_set_value_cansleep(reset_gpio, 0);
189009aa2609SJavier Martinez Canillas 		/* Delay time between end of reset to I2C active */
189109aa2609SJavier Martinez Canillas 		usleep_range(200, 250);
189209aa2609SJavier Martinez Canillas 	}
189309aa2609SJavier Martinez Canillas 
189409aa2609SJavier Martinez Canillas 	return 0;
189509aa2609SJavier Martinez Canillas }
189609aa2609SJavier Martinez Canillas 
18970556f1d5SMarco Felsch #if defined(CONFIG_MEDIA_CONTROLLER)
tvp5150_mc_init(struct tvp5150 * decoder)18980556f1d5SMarco Felsch static int tvp5150_mc_init(struct tvp5150 *decoder)
18990556f1d5SMarco Felsch {
19000556f1d5SMarco Felsch 	struct v4l2_subdev *sd = &decoder->sd;
19010556f1d5SMarco Felsch 	unsigned int i;
19020556f1d5SMarco Felsch 
19030556f1d5SMarco Felsch 	sd->entity.ops = &tvp5150_sd_media_ops;
19040556f1d5SMarco Felsch 	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
19050556f1d5SMarco Felsch 
19060556f1d5SMarco Felsch 	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
19070556f1d5SMarco Felsch 		decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
19080556f1d5SMarco Felsch 		decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
19090556f1d5SMarco Felsch 	}
19100556f1d5SMarco Felsch 
19110556f1d5SMarco Felsch 	decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
19120556f1d5SMarco Felsch 	decoder->pads[i].sig_type = PAD_SIGNAL_DV;
19130556f1d5SMarco Felsch 
19140556f1d5SMarco Felsch 	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
19150556f1d5SMarco Felsch 				      decoder->pads);
19160556f1d5SMarco Felsch }
19170556f1d5SMarco Felsch 
19180556f1d5SMarco Felsch #else /* !defined(CONFIG_MEDIA_CONTROLLER) */
19190556f1d5SMarco Felsch 
tvp5150_mc_init(struct tvp5150 * decoder)19200556f1d5SMarco Felsch static inline int tvp5150_mc_init(struct tvp5150 *decoder)
19210556f1d5SMarco Felsch {
19220556f1d5SMarco Felsch 	return 0;
19230556f1d5SMarco Felsch }
19240556f1d5SMarco Felsch #endif /* defined(CONFIG_MEDIA_CONTROLLER) */
19250556f1d5SMarco Felsch 
tvp5150_validate_connectors(struct tvp5150 * decoder)19260556f1d5SMarco Felsch static int tvp5150_validate_connectors(struct tvp5150 *decoder)
19270556f1d5SMarco Felsch {
19280556f1d5SMarco Felsch 	struct device *dev = decoder->sd.dev;
19290556f1d5SMarco Felsch 	struct tvp5150_connector *tvpc;
19300556f1d5SMarco Felsch 	struct v4l2_fwnode_connector *v4l2c;
19310556f1d5SMarco Felsch 	unsigned int i;
19320556f1d5SMarco Felsch 
19330556f1d5SMarco Felsch 	if (!decoder->connectors_num) {
19340556f1d5SMarco Felsch 		dev_err(dev, "No valid connector found\n");
19350556f1d5SMarco Felsch 		return -ENODEV;
19360556f1d5SMarco Felsch 	}
19370556f1d5SMarco Felsch 
19380556f1d5SMarco Felsch 	for (i = 0; i < decoder->connectors_num; i++) {
19390556f1d5SMarco Felsch 		struct v4l2_connector_link *link0 = NULL;
19400556f1d5SMarco Felsch 		struct v4l2_connector_link *link1;
19410556f1d5SMarco Felsch 
19420556f1d5SMarco Felsch 		tvpc = &decoder->connectors[i];
19430556f1d5SMarco Felsch 		v4l2c = &tvpc->base;
19440556f1d5SMarco Felsch 
19450556f1d5SMarco Felsch 		if (v4l2c->type == V4L2_CONN_COMPOSITE) {
19460556f1d5SMarco Felsch 			if (v4l2c->nr_of_links != 1) {
19470556f1d5SMarco Felsch 				dev_err(dev, "Composite: connector needs 1 link\n");
19480556f1d5SMarco Felsch 				return -EINVAL;
19490556f1d5SMarco Felsch 			}
19500556f1d5SMarco Felsch 			link0 = v4l2_connector_first_link(v4l2c);
19510556f1d5SMarco Felsch 			if (!link0) {
19520556f1d5SMarco Felsch 				dev_err(dev, "Composite: invalid first link\n");
19530556f1d5SMarco Felsch 				return -EINVAL;
19540556f1d5SMarco Felsch 			}
19550556f1d5SMarco Felsch 			if (link0->fwnode_link.remote_id == 1) {
19560556f1d5SMarco Felsch 				dev_err(dev, "Composite: invalid endpoint id\n");
19570556f1d5SMarco Felsch 				return -EINVAL;
19580556f1d5SMarco Felsch 			}
19590556f1d5SMarco Felsch 		}
19600556f1d5SMarco Felsch 
19610556f1d5SMarco Felsch 		if (v4l2c->type == V4L2_CONN_SVIDEO) {
19620556f1d5SMarco Felsch 			if (v4l2c->nr_of_links != 2) {
19630556f1d5SMarco Felsch 				dev_err(dev, "SVideo: connector needs 2 links\n");
19640556f1d5SMarco Felsch 				return -EINVAL;
19650556f1d5SMarco Felsch 			}
19660556f1d5SMarco Felsch 			link0 = v4l2_connector_first_link(v4l2c);
19670556f1d5SMarco Felsch 			if (!link0) {
19680556f1d5SMarco Felsch 				dev_err(dev, "SVideo: invalid first link\n");
19690556f1d5SMarco Felsch 				return -EINVAL;
19700556f1d5SMarco Felsch 			}
19710556f1d5SMarco Felsch 			link1 = v4l2_connector_last_link(v4l2c);
19720556f1d5SMarco Felsch 			if (link0->fwnode_link.remote_port ==
19730556f1d5SMarco Felsch 			    link1->fwnode_link.remote_port) {
19740556f1d5SMarco Felsch 				dev_err(dev, "SVideo: invalid link setup\n");
19750556f1d5SMarco Felsch 				return -EINVAL;
19760556f1d5SMarco Felsch 			}
19770556f1d5SMarco Felsch 		}
1978baf17821SMarco Felsch 
1979baf17821SMarco Felsch 		if (!(v4l2c->connector.analog.sdtv_stds & TVP5150_STD_MASK)) {
1980baf17821SMarco Felsch 			dev_err(dev, "Unsupported tv-norm on connector %s\n",
1981baf17821SMarco Felsch 				v4l2c->name);
1982baf17821SMarco Felsch 			return -EINVAL;
1983baf17821SMarco Felsch 		}
19840556f1d5SMarco Felsch 	}
19850556f1d5SMarco Felsch 
19860556f1d5SMarco Felsch 	return 0;
19870556f1d5SMarco Felsch }
19880556f1d5SMarco Felsch 
tvp5150_parse_dt(struct tvp5150 * decoder,struct device_node * np)1989a2e5f1b3SJavier Martinez Canillas static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
1990a2e5f1b3SJavier Martinez Canillas {
19910556f1d5SMarco Felsch 	struct device *dev = decoder->sd.dev;
19920556f1d5SMarco Felsch 	struct v4l2_fwnode_endpoint bus_cfg = {
19930556f1d5SMarco Felsch 		.bus_type = V4L2_MBUS_UNKNOWN
19940556f1d5SMarco Felsch 	};
19950556f1d5SMarco Felsch 	struct device_node *ep_np;
19960556f1d5SMarco Felsch 	struct tvp5150_connector *tvpc;
19970556f1d5SMarco Felsch 	struct v4l2_fwnode_connector *v4l2c;
19980556f1d5SMarco Felsch 	unsigned int flags, ep_num;
19990556f1d5SMarco Felsch 	unsigned int i;
20000556f1d5SMarco Felsch 	int ret;
2001a2e5f1b3SJavier Martinez Canillas 
20020556f1d5SMarco Felsch 	/* At least 1 output and 1 input */
20030556f1d5SMarco Felsch 	ep_num = of_graph_get_endpoint_count(np);
20040556f1d5SMarco Felsch 	if (ep_num < 2 || ep_num > 5) {
20050556f1d5SMarco Felsch 		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
2006a2e5f1b3SJavier Martinez Canillas 		return -EINVAL;
20070556f1d5SMarco Felsch 	}
2008a2e5f1b3SJavier Martinez Canillas 
20090556f1d5SMarco Felsch 	/* Layout if all connectors are used:
20100556f1d5SMarco Felsch 	 *
20110556f1d5SMarco Felsch 	 * tvp-5150 port@0 (AIP1A)
20120556f1d5SMarco Felsch 	 *	endpoint@0 -----------> Comp0-Con  port
20130556f1d5SMarco Felsch 	 *	endpoint@1 --------+--> Svideo-Con port
20140556f1d5SMarco Felsch 	 * tvp-5150 port@1 (AIP1B) |
20150556f1d5SMarco Felsch 	 *	endpoint@1 --------+
20160556f1d5SMarco Felsch 	 *	endpoint@0 -----------> Comp1-Con  port
20170556f1d5SMarco Felsch 	 * tvp-5150 port@2
20180556f1d5SMarco Felsch 	 *	endpoint (video bitstream output at YOUT[0-7] parallel bus)
20190556f1d5SMarco Felsch 	 */
20200556f1d5SMarco Felsch 	for_each_endpoint_of_node(np, ep_np) {
20210556f1d5SMarco Felsch 		struct fwnode_handle *ep_fwnode = of_fwnode_handle(ep_np);
20220556f1d5SMarco Felsch 		unsigned int next_connector = decoder->connectors_num;
20230556f1d5SMarco Felsch 		struct of_endpoint ep;
20240556f1d5SMarco Felsch 
20250556f1d5SMarco Felsch 		of_graph_parse_endpoint(ep_np, &ep);
20260556f1d5SMarco Felsch 		if (ep.port > 1 || ep.id > 1) {
20270556f1d5SMarco Felsch 			dev_dbg(dev, "Ignore connector on port@%u/ep@%u\n",
20280556f1d5SMarco Felsch 				ep.port, ep.id);
20290556f1d5SMarco Felsch 			continue;
20300556f1d5SMarco Felsch 		}
20310556f1d5SMarco Felsch 
20320556f1d5SMarco Felsch 		tvpc = &decoder->connectors[next_connector];
20330556f1d5SMarco Felsch 		v4l2c = &tvpc->base;
20340556f1d5SMarco Felsch 
20350556f1d5SMarco Felsch 		if (ep.port == 0 || (ep.port == 1 && ep.id == 0)) {
20360556f1d5SMarco Felsch 			ret = v4l2_fwnode_connector_parse(ep_fwnode, v4l2c);
2037a2e5f1b3SJavier Martinez Canillas 			if (ret)
20380556f1d5SMarco Felsch 				goto err_put;
20390556f1d5SMarco Felsch 			ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c);
20400556f1d5SMarco Felsch 			if (ret)
20410556f1d5SMarco Felsch 				goto err_put;
20420556f1d5SMarco Felsch 			decoder->connectors_num++;
20430556f1d5SMarco Felsch 		} else {
20440556f1d5SMarco Felsch 			/* Adding the 2nd svideo link */
20450556f1d5SMarco Felsch 			for (i = 0; i < TVP5150_MAX_CONNECTORS; i++) {
20460556f1d5SMarco Felsch 				tvpc = &decoder->connectors[i];
20470556f1d5SMarco Felsch 				v4l2c = &tvpc->base;
20480556f1d5SMarco Felsch 				if (v4l2c->type == V4L2_CONN_SVIDEO)
20490556f1d5SMarco Felsch 					break;
20500556f1d5SMarco Felsch 			}
20510556f1d5SMarco Felsch 
20520556f1d5SMarco Felsch 			ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c);
20530556f1d5SMarco Felsch 			if (ret)
20540556f1d5SMarco Felsch 				goto err_put;
20550556f1d5SMarco Felsch 		}
20560556f1d5SMarco Felsch 	}
20570556f1d5SMarco Felsch 
20580556f1d5SMarco Felsch 	ret = tvp5150_validate_connectors(decoder);
20590556f1d5SMarco Felsch 	if (ret)
20600556f1d5SMarco Felsch 		goto err_free;
20610556f1d5SMarco Felsch 
20620556f1d5SMarco Felsch 	for (i = 0; i < decoder->connectors_num; i++) {
20630556f1d5SMarco Felsch 		tvpc = &decoder->connectors[i];
20640556f1d5SMarco Felsch 		v4l2c = &tvpc->base;
20650556f1d5SMarco Felsch 		tvpc->ent.flags = MEDIA_ENT_FL_CONNECTOR;
20660556f1d5SMarco Felsch 		tvpc->ent.function = v4l2c->type == V4L2_CONN_SVIDEO ?
20670556f1d5SMarco Felsch 			MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
20680556f1d5SMarco Felsch 		tvpc->ent.name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
20690556f1d5SMarco Felsch 						v4l2c->name, v4l2c->label ?
20700556f1d5SMarco Felsch 						v4l2c->label : "");
2071*26ce7054SClaudiu Beznea 		if (!tvpc->ent.name) {
2072*26ce7054SClaudiu Beznea 			ret = -ENOMEM;
2073*26ce7054SClaudiu Beznea 			goto err_free;
2074*26ce7054SClaudiu Beznea 		}
20750556f1d5SMarco Felsch 	}
20760556f1d5SMarco Felsch 
20770556f1d5SMarco Felsch 	ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0);
20780556f1d5SMarco Felsch 	if (!ep_np) {
2079eb08c481SZhang Xiaoxu 		ret = -EINVAL;
20800556f1d5SMarco Felsch 		dev_err(dev, "Error no output endpoint available\n");
20810556f1d5SMarco Felsch 		goto err_free;
20820556f1d5SMarco Felsch 	}
20830556f1d5SMarco Felsch 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np), &bus_cfg);
20840556f1d5SMarco Felsch 	of_node_put(ep_np);
20850556f1d5SMarco Felsch 	if (ret)
20860556f1d5SMarco Felsch 		goto err_free;
2087a2e5f1b3SJavier Martinez Canillas 
2088a2e5f1b3SJavier Martinez Canillas 	flags = bus_cfg.bus.parallel.flags;
2089a2e5f1b3SJavier Martinez Canillas 	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
2090a2e5f1b3SJavier Martinez Canillas 	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
2091a2e5f1b3SJavier Martinez Canillas 	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
20922bd5e437SJavier Martinez Canillas 	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
20932bd5e437SJavier Martinez Canillas 		ret = -EINVAL;
20940556f1d5SMarco Felsch 		goto err_free;
20952bd5e437SJavier Martinez Canillas 	}
2096a2e5f1b3SJavier Martinez Canillas 
2097a2e5f1b3SJavier Martinez Canillas 	decoder->mbus_type = bus_cfg.bus_type;
2098a2e5f1b3SJavier Martinez Canillas 
20990556f1d5SMarco Felsch 	return 0;
21000556f1d5SMarco Felsch 
21010556f1d5SMarco Felsch err_put:
21020556f1d5SMarco Felsch 	of_node_put(ep_np);
21030556f1d5SMarco Felsch err_free:
21040556f1d5SMarco Felsch 	for (i = 0; i < TVP5150_MAX_CONNECTORS; i++)
21050556f1d5SMarco Felsch 		v4l2_fwnode_connector_free(&decoder->connectors[i].base);
21060556f1d5SMarco Felsch 
2107a2e5f1b3SJavier Martinez Canillas 	return ret;
2108a2e5f1b3SJavier Martinez Canillas }
2109a2e5f1b3SJavier Martinez Canillas 
2110c43875f6SMauro Carvalho Chehab static const char * const tvp5150_test_patterns[2] = {
2111c43875f6SMauro Carvalho Chehab 	"Disabled",
2112c43875f6SMauro Carvalho Chehab 	"Black screen"
2113c43875f6SMauro Carvalho Chehab };
2114c43875f6SMauro Carvalho Chehab 
tvp5150_probe(struct i2c_client * c)2115e6714993SKieran Bingham static int tvp5150_probe(struct i2c_client *c)
2116cb7a01acSMauro Carvalho Chehab {
2117cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *core;
2118cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
2119a2e5f1b3SJavier Martinez Canillas 	struct device_node *np = c->dev.of_node;
212028b9e227SPhilipp Zabel 	struct regmap *map;
2121baf17821SMarco Felsch 	unsigned int i;
21227871597aSLaurent Pinchart 	int res;
2123cb7a01acSMauro Carvalho Chehab 
2124cb7a01acSMauro Carvalho Chehab 	/* Check if the adapter supports the needed features */
2125cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(c->adapter,
2126cb7a01acSMauro Carvalho Chehab 	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
2127cb7a01acSMauro Carvalho Chehab 		return -EIO;
2128cb7a01acSMauro Carvalho Chehab 
212909aa2609SJavier Martinez Canillas 	res = tvp5150_init(c);
213009aa2609SJavier Martinez Canillas 	if (res)
213109aa2609SJavier Martinez Canillas 		return res;
213209aa2609SJavier Martinez Canillas 
2133c02b211dSLaurent Pinchart 	core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL);
2134c02b211dSLaurent Pinchart 	if (!core)
2135cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
2136a2e5f1b3SJavier Martinez Canillas 
213728b9e227SPhilipp Zabel 	map = devm_regmap_init_i2c(c, &tvp5150_config);
213828b9e227SPhilipp Zabel 	if (IS_ERR(map))
213928b9e227SPhilipp Zabel 		return PTR_ERR(map);
214028b9e227SPhilipp Zabel 
214128b9e227SPhilipp Zabel 	core->regmap = map;
2142cb7a01acSMauro Carvalho Chehab 	sd = &core->sd;
214396ca7c41SMichael Tretter 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
214496ca7c41SMichael Tretter 	sd->internal_ops = &tvp5150_internal_ops;
2145e953c103SMarco Felsch 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
2146a2e5f1b3SJavier Martinez Canillas 
2147a2e5f1b3SJavier Martinez Canillas 	if (IS_ENABLED(CONFIG_OF) && np) {
2148a2e5f1b3SJavier Martinez Canillas 		res = tvp5150_parse_dt(core, np);
2149a2e5f1b3SJavier Martinez Canillas 		if (res) {
2150257e29f8SMauro Carvalho Chehab 			dev_err(sd->dev, "DT parsing error: %d\n", res);
2151a2e5f1b3SJavier Martinez Canillas 			return res;
2152a2e5f1b3SJavier Martinez Canillas 		}
2153a2e5f1b3SJavier Martinez Canillas 	} else {
2154a2e5f1b3SJavier Martinez Canillas 		/* Default to BT.656 embedded sync */
2155a2e5f1b3SJavier Martinez Canillas 		core->mbus_type = V4L2_MBUS_BT656;
2156a2e5f1b3SJavier Martinez Canillas 	}
2157a2e5f1b3SJavier Martinez Canillas 
21580556f1d5SMarco Felsch 	res = tvp5150_mc_init(core);
21590556f1d5SMarco Felsch 	if (res)
2160e545ac87SLaurent Pinchart 		return res;
2161f7b4b54eSJavier Martinez Canillas 
21627871597aSLaurent Pinchart 	res = tvp5150_detect_version(core);
2163cb7a01acSMauro Carvalho Chehab 	if (res < 0)
2164c02b211dSLaurent Pinchart 		return res;
2165cb7a01acSMauro Carvalho Chehab 
2166baf17821SMarco Felsch 	/*
2167baf17821SMarco Felsch 	 * Iterate over all available connectors in case they are supported and
2168baf17821SMarco Felsch 	 * successfully parsed. Fallback to default autodetect in case they
2169baf17821SMarco Felsch 	 * aren't supported.
2170baf17821SMarco Felsch 	 */
2171baf17821SMarco Felsch 	for (i = 0; i < core->connectors_num; i++) {
2172baf17821SMarco Felsch 		struct v4l2_fwnode_connector *v4l2c;
2173baf17821SMarco Felsch 
2174baf17821SMarco Felsch 		v4l2c = &core->connectors[i].base;
2175baf17821SMarco Felsch 		core->norm |= v4l2c->connector.analog.sdtv_stds;
2176baf17821SMarco Felsch 	}
2177baf17821SMarco Felsch 
2178baf17821SMarco Felsch 	if (!core->connectors_num)
2179baf17821SMarco Felsch 		core->norm = V4L2_STD_ALL;
2180baf17821SMarco Felsch 
2181b440b733SPhilipp Zabel 	core->detected_norm = V4L2_STD_UNKNOWN;
2182cb7a01acSMauro Carvalho Chehab 	core->input = TVP5150_COMPOSITE1;
2183c43875f6SMauro Carvalho Chehab 	core->enable = true;
2184cb7a01acSMauro Carvalho Chehab 
2185b1950b8dSLaurent Pinchart 	v4l2_ctrl_handler_init(&core->hdl, 5);
2186cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
2187cb7a01acSMauro Carvalho Chehab 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
2188cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
2189cb7a01acSMauro Carvalho Chehab 			V4L2_CID_CONTRAST, 0, 255, 1, 128);
2190cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
2191cb7a01acSMauro Carvalho Chehab 			V4L2_CID_SATURATION, 0, 255, 1, 128);
2192cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
2193cb7a01acSMauro Carvalho Chehab 			V4L2_CID_HUE, -128, 127, 1, 0);
2194b1950b8dSLaurent Pinchart 	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
2195b1950b8dSLaurent Pinchart 			V4L2_CID_PIXEL_RATE, 27000000,
2196b1950b8dSLaurent Pinchart 			27000000, 1, 27000000);
2197c43875f6SMauro Carvalho Chehab 	v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops,
2198c43875f6SMauro Carvalho Chehab 				     V4L2_CID_TEST_PATTERN,
21995c4c4505SMauro Carvalho Chehab 				     ARRAY_SIZE(tvp5150_test_patterns) - 1,
2200c43875f6SMauro Carvalho Chehab 				     0, 0, tvp5150_test_patterns);
2201cb7a01acSMauro Carvalho Chehab 	sd->ctrl_handler = &core->hdl;
2202cb7a01acSMauro Carvalho Chehab 	if (core->hdl.error) {
2203cb7a01acSMauro Carvalho Chehab 		res = core->hdl.error;
2204c7d97499SJavier Martinez Canillas 		goto err;
2205cb7a01acSMauro Carvalho Chehab 	}
2206cb7a01acSMauro Carvalho Chehab 
22075cb82940SMarco Felsch 	tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
2208cb7a01acSMauro Carvalho Chehab 
22098e4c97e0SPhilipp Zabel 	core->irq = c->irq;
2210aff808e8SLaurent Pinchart 	tvp5150_reset(sd, 0);	/* Calls v4l2_ctrl_handler_setup() */
22118e4c97e0SPhilipp Zabel 	if (c->irq) {
22128e4c97e0SPhilipp Zabel 		res = devm_request_threaded_irq(&c->dev, c->irq, NULL,
22138e4c97e0SPhilipp Zabel 						tvp5150_isr, IRQF_TRIGGER_HIGH |
22148e4c97e0SPhilipp Zabel 						IRQF_ONESHOT, "tvp5150", core);
22158e4c97e0SPhilipp Zabel 		if (res)
221681fd5fd4SMarco Felsch 			goto err;
22178e4c97e0SPhilipp Zabel 	}
2218aff808e8SLaurent Pinchart 
2219c7d97499SJavier Martinez Canillas 	res = v4l2_async_register_subdev(sd);
2220c7d97499SJavier Martinez Canillas 	if (res < 0)
2221c7d97499SJavier Martinez Canillas 		goto err;
2222c7d97499SJavier Martinez Canillas 
2223cb7a01acSMauro Carvalho Chehab 	if (debug > 1)
2224cb7a01acSMauro Carvalho Chehab 		tvp5150_log_status(sd);
222573549a69SMarco Felsch 
222673549a69SMarco Felsch 	pm_runtime_set_active(&c->dev);
222773549a69SMarco Felsch 	pm_runtime_enable(&c->dev);
222873549a69SMarco Felsch 	pm_runtime_idle(&c->dev);
222973549a69SMarco Felsch 
2230cb7a01acSMauro Carvalho Chehab 	return 0;
2231c7d97499SJavier Martinez Canillas 
2232c7d97499SJavier Martinez Canillas err:
2233c7d97499SJavier Martinez Canillas 	v4l2_ctrl_handler_free(&core->hdl);
2234c7d97499SJavier Martinez Canillas 	return res;
2235cb7a01acSMauro Carvalho Chehab }
2236cb7a01acSMauro Carvalho Chehab 
tvp5150_remove(struct i2c_client * c)2237ed5c2f5fSUwe Kleine-König static void tvp5150_remove(struct i2c_client *c)
2238cb7a01acSMauro Carvalho Chehab {
2239cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(c);
2240cb7a01acSMauro Carvalho Chehab 	struct tvp5150 *decoder = to_tvp5150(sd);
22410556f1d5SMarco Felsch 	unsigned int i;
2242cb7a01acSMauro Carvalho Chehab 
2243257e29f8SMauro Carvalho Chehab 	dev_dbg_lvl(sd->dev, 1, debug,
2244cb7a01acSMauro Carvalho Chehab 		"tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
2245cb7a01acSMauro Carvalho Chehab 		c->addr << 1);
2246cb7a01acSMauro Carvalho Chehab 
22470556f1d5SMarco Felsch 	for (i = 0; i < decoder->connectors_num; i++)
22480556f1d5SMarco Felsch 		v4l2_fwnode_connector_free(&decoder->connectors[i].base);
2249d000e9b5SChuhong Yuan 	for (i = 0; i < decoder->connectors_num; i++) {
22500556f1d5SMarco Felsch 		media_device_unregister_entity(&decoder->connectors[i].ent);
2251d000e9b5SChuhong Yuan 		media_entity_cleanup(&decoder->connectors[i].ent);
2252d000e9b5SChuhong Yuan 	}
2253c7d97499SJavier Martinez Canillas 	v4l2_async_unregister_subdev(sd);
2254cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_free(&decoder->hdl);
225573549a69SMarco Felsch 	pm_runtime_disable(&c->dev);
225673549a69SMarco Felsch 	pm_runtime_set_suspended(&c->dev);
2257cb7a01acSMauro Carvalho Chehab }
2258cb7a01acSMauro Carvalho Chehab 
2259cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
2260cb7a01acSMauro Carvalho Chehab 
226173549a69SMarco Felsch static const struct dev_pm_ops tvp5150_pm_ops = {
226273549a69SMarco Felsch 	SET_RUNTIME_PM_OPS(tvp5150_runtime_suspend,
226373549a69SMarco Felsch 			   tvp5150_runtime_resume,
226473549a69SMarco Felsch 			   NULL)
226573549a69SMarco Felsch };
226673549a69SMarco Felsch 
2267cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = {
2268cb7a01acSMauro Carvalho Chehab 	{ "tvp5150", 0 },
2269cb7a01acSMauro Carvalho Chehab 	{ }
2270cb7a01acSMauro Carvalho Chehab };
2271cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id);
2272cb7a01acSMauro Carvalho Chehab 
22737ef930a7SEduard Gavin #if IS_ENABLED(CONFIG_OF)
22747ef930a7SEduard Gavin static const struct of_device_id tvp5150_of_match[] = {
22757ef930a7SEduard Gavin 	{ .compatible = "ti,tvp5150", },
22767ef930a7SEduard Gavin 	{ /* sentinel */ },
22777ef930a7SEduard Gavin };
22787ef930a7SEduard Gavin MODULE_DEVICE_TABLE(of, tvp5150_of_match);
22797ef930a7SEduard Gavin #endif
22807ef930a7SEduard Gavin 
2281cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = {
2282cb7a01acSMauro Carvalho Chehab 	.driver = {
22837ef930a7SEduard Gavin 		.of_match_table = of_match_ptr(tvp5150_of_match),
2284cb7a01acSMauro Carvalho Chehab 		.name	= "tvp5150",
228573549a69SMarco Felsch 		.pm	= &tvp5150_pm_ops,
2286cb7a01acSMauro Carvalho Chehab 	},
2287aaeb31c0SUwe Kleine-König 	.probe		= tvp5150_probe,
2288cb7a01acSMauro Carvalho Chehab 	.remove		= tvp5150_remove,
2289cb7a01acSMauro Carvalho Chehab 	.id_table	= tvp5150_id,
2290cb7a01acSMauro Carvalho Chehab };
2291cb7a01acSMauro Carvalho Chehab 
2292cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver);
2293