1e58f3082SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0+
23e89586aSKieran Bingham /*
33e89586aSKieran Bingham  * Driver for Analog Devices ADV748X 8 channel analog front end (AFE) receiver
43e89586aSKieran Bingham  * with standard definition processor (SDP)
53e89586aSKieran Bingham  *
63e89586aSKieran Bingham  * Copyright (C) 2017 Renesas Electronics Corp.
73e89586aSKieran Bingham  */
83e89586aSKieran Bingham 
93e89586aSKieran Bingham #include <linux/delay.h>
103e89586aSKieran Bingham #include <linux/module.h>
113e89586aSKieran Bingham #include <linux/mutex.h>
123e89586aSKieran Bingham #include <linux/v4l2-dv-timings.h>
133e89586aSKieran Bingham 
143e89586aSKieran Bingham #include <media/v4l2-ctrls.h>
153e89586aSKieran Bingham #include <media/v4l2-device.h>
163e89586aSKieran Bingham #include <media/v4l2-dv-timings.h>
173e89586aSKieran Bingham #include <media/v4l2-ioctl.h>
183e89586aSKieran Bingham 
193e89586aSKieran Bingham #include "adv748x.h"
203e89586aSKieran Bingham 
213e89586aSKieran Bingham /* -----------------------------------------------------------------------------
223e89586aSKieran Bingham  * SDP
233e89586aSKieran Bingham  */
243e89586aSKieran Bingham 
253e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM		0x0
263e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM_PED	0x1
273e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_N_NTSC_J_SECAM		0x2
283e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_N_NTSC_M_SECAM		0x3
293e89586aSKieran Bingham #define ADV748X_AFE_STD_NTSC_J				0x4
303e89586aSKieran Bingham #define ADV748X_AFE_STD_NTSC_M				0x5
313e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL60				0x6
323e89586aSKieran Bingham #define ADV748X_AFE_STD_NTSC_443			0x7
333e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_BG				0x8
343e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_N				0x9
353e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_M				0xa
363e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_M_PED			0xb
373e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_COMB_N			0xc
383e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_COMB_N_PED			0xd
393e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_SECAM			0xe
403e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_SECAM_PED			0xf
413e89586aSKieran Bingham 
adv748x_afe_read_ro_map(struct adv748x_state * state,u8 reg)423e89586aSKieran Bingham static int adv748x_afe_read_ro_map(struct adv748x_state *state, u8 reg)
433e89586aSKieran Bingham {
443e89586aSKieran Bingham 	int ret;
453e89586aSKieran Bingham 
463e89586aSKieran Bingham 	/* Select SDP Read-Only Main Map */
473e89586aSKieran Bingham 	ret = sdp_write(state, ADV748X_SDP_MAP_SEL,
483e89586aSKieran Bingham 			ADV748X_SDP_MAP_SEL_RO_MAIN);
493e89586aSKieran Bingham 	if (ret < 0)
503e89586aSKieran Bingham 		return ret;
513e89586aSKieran Bingham 
523e89586aSKieran Bingham 	return sdp_read(state, reg);
533e89586aSKieran Bingham }
543e89586aSKieran Bingham 
adv748x_afe_status(struct adv748x_afe * afe,u32 * signal,v4l2_std_id * std)553e89586aSKieran Bingham static int adv748x_afe_status(struct adv748x_afe *afe, u32 *signal,
563e89586aSKieran Bingham 			      v4l2_std_id *std)
573e89586aSKieran Bingham {
583e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
593e89586aSKieran Bingham 	int info;
603e89586aSKieran Bingham 
613e89586aSKieran Bingham 	/* Read status from reg 0x10 of SDP RO Map */
623e89586aSKieran Bingham 	info = adv748x_afe_read_ro_map(state, ADV748X_SDP_RO_10);
633e89586aSKieran Bingham 	if (info < 0)
643e89586aSKieran Bingham 		return info;
653e89586aSKieran Bingham 
663e89586aSKieran Bingham 	if (signal)
673e89586aSKieran Bingham 		*signal = info & ADV748X_SDP_RO_10_IN_LOCK ?
683e89586aSKieran Bingham 				0 : V4L2_IN_ST_NO_SIGNAL;
693e89586aSKieran Bingham 
703e89586aSKieran Bingham 	if (!std)
713e89586aSKieran Bingham 		return 0;
723e89586aSKieran Bingham 
733e89586aSKieran Bingham 	/* Standard not valid if there is no signal */
743e89586aSKieran Bingham 	if (!(info & ADV748X_SDP_RO_10_IN_LOCK)) {
753e89586aSKieran Bingham 		*std = V4L2_STD_UNKNOWN;
763e89586aSKieran Bingham 		return 0;
773e89586aSKieran Bingham 	}
783e89586aSKieran Bingham 
793e89586aSKieran Bingham 	switch (info & 0x70) {
803e89586aSKieran Bingham 	case 0x00:
813e89586aSKieran Bingham 		*std = V4L2_STD_NTSC;
823e89586aSKieran Bingham 		break;
833e89586aSKieran Bingham 	case 0x10:
843e89586aSKieran Bingham 		*std = V4L2_STD_NTSC_443;
853e89586aSKieran Bingham 		break;
863e89586aSKieran Bingham 	case 0x20:
873e89586aSKieran Bingham 		*std = V4L2_STD_PAL_M;
883e89586aSKieran Bingham 		break;
893e89586aSKieran Bingham 	case 0x30:
903e89586aSKieran Bingham 		*std = V4L2_STD_PAL_60;
913e89586aSKieran Bingham 		break;
923e89586aSKieran Bingham 	case 0x40:
933e89586aSKieran Bingham 		*std = V4L2_STD_PAL;
943e89586aSKieran Bingham 		break;
953e89586aSKieran Bingham 	case 0x50:
963e89586aSKieran Bingham 		*std = V4L2_STD_SECAM;
973e89586aSKieran Bingham 		break;
983e89586aSKieran Bingham 	case 0x60:
993e89586aSKieran Bingham 		*std = V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
1003e89586aSKieran Bingham 		break;
1013e89586aSKieran Bingham 	case 0x70:
1023e89586aSKieran Bingham 		*std = V4L2_STD_SECAM;
1033e89586aSKieran Bingham 		break;
1043e89586aSKieran Bingham 	default:
1053e89586aSKieran Bingham 		*std = V4L2_STD_UNKNOWN;
1063e89586aSKieran Bingham 		break;
1073e89586aSKieran Bingham 	}
1083e89586aSKieran Bingham 
1093e89586aSKieran Bingham 	return 0;
1103e89586aSKieran Bingham }
1113e89586aSKieran Bingham 
adv748x_afe_fill_format(struct adv748x_afe * afe,struct v4l2_mbus_framefmt * fmt)1123e89586aSKieran Bingham static void adv748x_afe_fill_format(struct adv748x_afe *afe,
1133e89586aSKieran Bingham 				    struct v4l2_mbus_framefmt *fmt)
1143e89586aSKieran Bingham {
1153e89586aSKieran Bingham 	memset(fmt, 0, sizeof(*fmt));
1163e89586aSKieran Bingham 
1173e89586aSKieran Bingham 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
1183e89586aSKieran Bingham 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
1193e89586aSKieran Bingham 	fmt->field = V4L2_FIELD_ALTERNATE;
1203e89586aSKieran Bingham 
1213e89586aSKieran Bingham 	fmt->width = 720;
1223e89586aSKieran Bingham 	fmt->height = afe->curr_norm & V4L2_STD_525_60 ? 480 : 576;
1233e89586aSKieran Bingham 
1243e89586aSKieran Bingham 	/* Field height */
1253e89586aSKieran Bingham 	fmt->height /= 2;
1263e89586aSKieran Bingham }
1273e89586aSKieran Bingham 
adv748x_afe_std(v4l2_std_id std)1283e89586aSKieran Bingham static int adv748x_afe_std(v4l2_std_id std)
1293e89586aSKieran Bingham {
1303e89586aSKieran Bingham 	if (std == V4L2_STD_PAL_60)
1313e89586aSKieran Bingham 		return ADV748X_AFE_STD_PAL60;
1323e89586aSKieran Bingham 	if (std == V4L2_STD_NTSC_443)
1333e89586aSKieran Bingham 		return ADV748X_AFE_STD_NTSC_443;
1343e89586aSKieran Bingham 	if (std == V4L2_STD_PAL_N)
1353e89586aSKieran Bingham 		return ADV748X_AFE_STD_PAL_N;
1363e89586aSKieran Bingham 	if (std == V4L2_STD_PAL_M)
1373e89586aSKieran Bingham 		return ADV748X_AFE_STD_PAL_M;
1383e89586aSKieran Bingham 	if (std == V4L2_STD_PAL_Nc)
1393e89586aSKieran Bingham 		return ADV748X_AFE_STD_PAL_COMB_N;
1403e89586aSKieran Bingham 	if (std & V4L2_STD_NTSC)
1413e89586aSKieran Bingham 		return ADV748X_AFE_STD_NTSC_M;
1423e89586aSKieran Bingham 	if (std & V4L2_STD_PAL)
1433e89586aSKieran Bingham 		return ADV748X_AFE_STD_PAL_BG;
1443e89586aSKieran Bingham 	if (std & V4L2_STD_SECAM)
1453e89586aSKieran Bingham 		return ADV748X_AFE_STD_PAL_SECAM;
1463e89586aSKieran Bingham 
1473e89586aSKieran Bingham 	return -EINVAL;
1483e89586aSKieran Bingham }
1493e89586aSKieran Bingham 
adv748x_afe_set_video_standard(struct adv748x_state * state,int sdpstd)1503e89586aSKieran Bingham static void adv748x_afe_set_video_standard(struct adv748x_state *state,
1513e89586aSKieran Bingham 					  int sdpstd)
1523e89586aSKieran Bingham {
1533e89586aSKieran Bingham 	sdp_clrset(state, ADV748X_SDP_VID_SEL, ADV748X_SDP_VID_SEL_MASK,
1543e89586aSKieran Bingham 		   (sdpstd & 0xf) << ADV748X_SDP_VID_SEL_SHIFT);
1553e89586aSKieran Bingham }
1563e89586aSKieran Bingham 
adv748x_afe_s_input(struct adv748x_afe * afe,unsigned int input)157c30ed81aSNiklas Söderlund int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input)
1583e89586aSKieran Bingham {
1593e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
1603e89586aSKieran Bingham 
1613e89586aSKieran Bingham 	return sdp_write(state, ADV748X_SDP_INSEL, input);
1623e89586aSKieran Bingham }
1633e89586aSKieran Bingham 
adv748x_afe_g_pixelaspect(struct v4l2_subdev * sd,struct v4l2_fract * aspect)1643e89586aSKieran Bingham static int adv748x_afe_g_pixelaspect(struct v4l2_subdev *sd,
1653e89586aSKieran Bingham 				     struct v4l2_fract *aspect)
1663e89586aSKieran Bingham {
1673e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
1683e89586aSKieran Bingham 
1693e89586aSKieran Bingham 	if (afe->curr_norm & V4L2_STD_525_60) {
1703e89586aSKieran Bingham 		aspect->numerator = 11;
1713e89586aSKieran Bingham 		aspect->denominator = 10;
1723e89586aSKieran Bingham 	} else {
1733e89586aSKieran Bingham 		aspect->numerator = 54;
1743e89586aSKieran Bingham 		aspect->denominator = 59;
1753e89586aSKieran Bingham 	}
1763e89586aSKieran Bingham 
1773e89586aSKieran Bingham 	return 0;
1783e89586aSKieran Bingham }
1793e89586aSKieran Bingham 
1803e89586aSKieran Bingham /* -----------------------------------------------------------------------------
1813e89586aSKieran Bingham  * v4l2_subdev_video_ops
1823e89586aSKieran Bingham  */
1833e89586aSKieran Bingham 
adv748x_afe_g_std(struct v4l2_subdev * sd,v4l2_std_id * norm)1843e89586aSKieran Bingham static int adv748x_afe_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
1853e89586aSKieran Bingham {
1863e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
1873e89586aSKieran Bingham 
1883e89586aSKieran Bingham 	*norm = afe->curr_norm;
1893e89586aSKieran Bingham 
1903e89586aSKieran Bingham 	return 0;
1913e89586aSKieran Bingham }
1923e89586aSKieran Bingham 
adv748x_afe_s_std(struct v4l2_subdev * sd,v4l2_std_id std)1933e89586aSKieran Bingham static int adv748x_afe_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1943e89586aSKieran Bingham {
1953e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
1963e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
1973e89586aSKieran Bingham 	int afe_std = adv748x_afe_std(std);
1983e89586aSKieran Bingham 
1993e89586aSKieran Bingham 	if (afe_std < 0)
2003e89586aSKieran Bingham 		return afe_std;
2013e89586aSKieran Bingham 
2023e89586aSKieran Bingham 	mutex_lock(&state->mutex);
2033e89586aSKieran Bingham 
2043e89586aSKieran Bingham 	adv748x_afe_set_video_standard(state, afe_std);
2053e89586aSKieran Bingham 	afe->curr_norm = std;
2063e89586aSKieran Bingham 
2073e89586aSKieran Bingham 	mutex_unlock(&state->mutex);
2083e89586aSKieran Bingham 
2093e89586aSKieran Bingham 	return 0;
2103e89586aSKieran Bingham }
2113e89586aSKieran Bingham 
adv748x_afe_querystd(struct v4l2_subdev * sd,v4l2_std_id * std)2123e89586aSKieran Bingham static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
2133e89586aSKieran Bingham {
2143e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
2153e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
216bc66c99aSSimon Yuan 	int afe_std;
2173e89586aSKieran Bingham 	int ret;
2183e89586aSKieran Bingham 
2193e89586aSKieran Bingham 	mutex_lock(&state->mutex);
2203e89586aSKieran Bingham 
2213e89586aSKieran Bingham 	if (afe->streaming) {
2223e89586aSKieran Bingham 		ret = -EBUSY;
2233e89586aSKieran Bingham 		goto unlock;
2243e89586aSKieran Bingham 	}
2253e89586aSKieran Bingham 
2263e89586aSKieran Bingham 	/* Set auto detect mode */
2273e89586aSKieran Bingham 	adv748x_afe_set_video_standard(state,
2283e89586aSKieran Bingham 				       ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM);
2293e89586aSKieran Bingham 
2303e89586aSKieran Bingham 	msleep(100);
2313e89586aSKieran Bingham 
2323e89586aSKieran Bingham 	/* Read detected standard */
2333e89586aSKieran Bingham 	ret = adv748x_afe_status(afe, NULL, std);
2343e89586aSKieran Bingham 
235bc66c99aSSimon Yuan 	afe_std = adv748x_afe_std(afe->curr_norm);
236bc66c99aSSimon Yuan 	if (afe_std < 0)
237bc66c99aSSimon Yuan 		goto unlock;
238bc66c99aSSimon Yuan 
2393e89586aSKieran Bingham 	/* Restore original state */
240bc66c99aSSimon Yuan 	adv748x_afe_set_video_standard(state, afe_std);
2413e89586aSKieran Bingham 
2423e89586aSKieran Bingham unlock:
2433e89586aSKieran Bingham 	mutex_unlock(&state->mutex);
2443e89586aSKieran Bingham 
2453e89586aSKieran Bingham 	return ret;
2463e89586aSKieran Bingham }
2473e89586aSKieran Bingham 
adv748x_afe_g_tvnorms(struct v4l2_subdev * sd,v4l2_std_id * norm)2483e89586aSKieran Bingham static int adv748x_afe_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
2493e89586aSKieran Bingham {
2503e89586aSKieran Bingham 	*norm = V4L2_STD_ALL;
2513e89586aSKieran Bingham 
2523e89586aSKieran Bingham 	return 0;
2533e89586aSKieran Bingham }
2543e89586aSKieran Bingham 
adv748x_afe_g_input_status(struct v4l2_subdev * sd,u32 * status)2553e89586aSKieran Bingham static int adv748x_afe_g_input_status(struct v4l2_subdev *sd, u32 *status)
2563e89586aSKieran Bingham {
2573e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
2583e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
2593e89586aSKieran Bingham 	int ret;
2603e89586aSKieran Bingham 
2613e89586aSKieran Bingham 	mutex_lock(&state->mutex);
2623e89586aSKieran Bingham 
2633e89586aSKieran Bingham 	ret = adv748x_afe_status(afe, status, NULL);
2643e89586aSKieran Bingham 
2653e89586aSKieran Bingham 	mutex_unlock(&state->mutex);
266b0fe7778SKieran Bingham 
2673e89586aSKieran Bingham 	return ret;
2683e89586aSKieran Bingham }
2693e89586aSKieran Bingham 
adv748x_afe_s_stream(struct v4l2_subdev * sd,int enable)2703e89586aSKieran Bingham static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable)
2713e89586aSKieran Bingham {
2723e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
2733e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
2742b8677ecSNiklas Söderlund 	u32 signal = V4L2_IN_ST_NO_SIGNAL;
2752b8677ecSNiklas Söderlund 	int ret;
2763e89586aSKieran Bingham 
2773e89586aSKieran Bingham 	mutex_lock(&state->mutex);
2783e89586aSKieran Bingham 
2793e89586aSKieran Bingham 	if (enable) {
2803e89586aSKieran Bingham 		ret = adv748x_afe_s_input(afe, afe->input);
2813e89586aSKieran Bingham 		if (ret)
2823e89586aSKieran Bingham 			goto unlock;
2833e89586aSKieran Bingham 	}
2843e89586aSKieran Bingham 
285a33df6acSJacopo Mondi 	ret = adv748x_tx_power(afe->tx, enable);
2863e89586aSKieran Bingham 	if (ret)
2873e89586aSKieran Bingham 		goto unlock;
2883e89586aSKieran Bingham 
2893e89586aSKieran Bingham 	afe->streaming = enable;
2903e89586aSKieran Bingham 
2913e89586aSKieran Bingham 	adv748x_afe_status(afe, &signal, NULL);
2923e89586aSKieran Bingham 	if (signal != V4L2_IN_ST_NO_SIGNAL)
2933e89586aSKieran Bingham 		adv_dbg(state, "Detected SDP signal\n");
2943e89586aSKieran Bingham 	else
2953e89586aSKieran Bingham 		adv_dbg(state, "Couldn't detect SDP video signal\n");
2963e89586aSKieran Bingham 
2973e89586aSKieran Bingham unlock:
2983e89586aSKieran Bingham 	mutex_unlock(&state->mutex);
2993e89586aSKieran Bingham 
3003e89586aSKieran Bingham 	return ret;
3013e89586aSKieran Bingham }
3023e89586aSKieran Bingham 
3033e89586aSKieran Bingham static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = {
3043e89586aSKieran Bingham 	.g_std = adv748x_afe_g_std,
3053e89586aSKieran Bingham 	.s_std = adv748x_afe_s_std,
3063e89586aSKieran Bingham 	.querystd = adv748x_afe_querystd,
3073e89586aSKieran Bingham 	.g_tvnorms = adv748x_afe_g_tvnorms,
3083e89586aSKieran Bingham 	.g_input_status = adv748x_afe_g_input_status,
3093e89586aSKieran Bingham 	.s_stream = adv748x_afe_s_stream,
3103e89586aSKieran Bingham 	.g_pixelaspect = adv748x_afe_g_pixelaspect,
3113e89586aSKieran Bingham };
3123e89586aSKieran Bingham 
3133e89586aSKieran Bingham /* -----------------------------------------------------------------------------
3143e89586aSKieran Bingham  * v4l2_subdev_pad_ops
3153e89586aSKieran Bingham  */
3163e89586aSKieran Bingham 
adv748x_afe_propagate_pixelrate(struct adv748x_afe * afe)3173e89586aSKieran Bingham static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe)
3183e89586aSKieran Bingham {
3193e89586aSKieran Bingham 	struct v4l2_subdev *tx;
3203e89586aSKieran Bingham 
3213e89586aSKieran Bingham 	tx = adv748x_get_remote_sd(&afe->pads[ADV748X_AFE_SOURCE]);
3223e89586aSKieran Bingham 	if (!tx)
3233e89586aSKieran Bingham 		return -ENOLINK;
3243e89586aSKieran Bingham 
32550eea4abSLaurent Pinchart 	/*
32650eea4abSLaurent Pinchart 	 * The ADV748x ADC sampling frequency is twice the externally supplied
32750eea4abSLaurent Pinchart 	 * clock whose frequency is required to be 28.63636 MHz. It oversamples
32850eea4abSLaurent Pinchart 	 * with a factor of 4 resulting in a pixel rate of 14.3180180 MHz.
32950eea4abSLaurent Pinchart 	 */
33050eea4abSLaurent Pinchart 	return adv748x_csi2_set_pixelrate(tx, 14318180);
3313e89586aSKieran Bingham }
3323e89586aSKieran Bingham 
adv748x_afe_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)3333e89586aSKieran Bingham static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
3340d346d2aSTomi Valkeinen 				      struct v4l2_subdev_state *sd_state,
3353e89586aSKieran Bingham 				      struct v4l2_subdev_mbus_code_enum *code)
3363e89586aSKieran Bingham {
3373e89586aSKieran Bingham 	if (code->index != 0)
3383e89586aSKieran Bingham 		return -EINVAL;
3393e89586aSKieran Bingham 
3403e89586aSKieran Bingham 	code->code = MEDIA_BUS_FMT_UYVY8_2X8;
3413e89586aSKieran Bingham 
3423e89586aSKieran Bingham 	return 0;
3433e89586aSKieran Bingham }
3443e89586aSKieran Bingham 
adv748x_afe_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * sdformat)3453e89586aSKieran Bingham static int adv748x_afe_get_format(struct v4l2_subdev *sd,
3460d346d2aSTomi Valkeinen 				      struct v4l2_subdev_state *sd_state,
3473e89586aSKieran Bingham 				      struct v4l2_subdev_format *sdformat)
3483e89586aSKieran Bingham {
3493e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
3503e89586aSKieran Bingham 	struct v4l2_mbus_framefmt *mbusformat;
3513e89586aSKieran Bingham 
3523e89586aSKieran Bingham 	/* It makes no sense to get the format of the analog sink pads */
3533e89586aSKieran Bingham 	if (sdformat->pad != ADV748X_AFE_SOURCE)
3543e89586aSKieran Bingham 		return -EINVAL;
3553e89586aSKieran Bingham 
3563e89586aSKieran Bingham 	if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
3570d346d2aSTomi Valkeinen 		mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
3580d346d2aSTomi Valkeinen 							sdformat->pad);
3593e89586aSKieran Bingham 		sdformat->format = *mbusformat;
3603e89586aSKieran Bingham 	} else {
3613e89586aSKieran Bingham 		adv748x_afe_fill_format(afe, &sdformat->format);
3623e89586aSKieran Bingham 		adv748x_afe_propagate_pixelrate(afe);
3633e89586aSKieran Bingham 	}
3643e89586aSKieran Bingham 
3653e89586aSKieran Bingham 	return 0;
3663e89586aSKieran Bingham }
3673e89586aSKieran Bingham 
adv748x_afe_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * sdformat)3683e89586aSKieran Bingham static int adv748x_afe_set_format(struct v4l2_subdev *sd,
3690d346d2aSTomi Valkeinen 				      struct v4l2_subdev_state *sd_state,
3703e89586aSKieran Bingham 				      struct v4l2_subdev_format *sdformat)
3713e89586aSKieran Bingham {
3723e89586aSKieran Bingham 	struct v4l2_mbus_framefmt *mbusformat;
3733e89586aSKieran Bingham 
3743e89586aSKieran Bingham 	/* It makes no sense to get the format of the analog sink pads */
3753e89586aSKieran Bingham 	if (sdformat->pad != ADV748X_AFE_SOURCE)
3763e89586aSKieran Bingham 		return -EINVAL;
3773e89586aSKieran Bingham 
3783e89586aSKieran Bingham 	if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
3790d346d2aSTomi Valkeinen 		return adv748x_afe_get_format(sd, sd_state, sdformat);
3803e89586aSKieran Bingham 
3810d346d2aSTomi Valkeinen 	mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
3823e89586aSKieran Bingham 	*mbusformat = sdformat->format;
3833e89586aSKieran Bingham 
3843e89586aSKieran Bingham 	return 0;
3853e89586aSKieran Bingham }
3863e89586aSKieran Bingham 
3873e89586aSKieran Bingham static const struct v4l2_subdev_pad_ops adv748x_afe_pad_ops = {
3883e89586aSKieran Bingham 	.enum_mbus_code = adv748x_afe_enum_mbus_code,
3893e89586aSKieran Bingham 	.set_fmt = adv748x_afe_set_format,
3903e89586aSKieran Bingham 	.get_fmt = adv748x_afe_get_format,
3913e89586aSKieran Bingham };
3923e89586aSKieran Bingham 
3933e89586aSKieran Bingham /* -----------------------------------------------------------------------------
3943e89586aSKieran Bingham  * v4l2_subdev_ops
3953e89586aSKieran Bingham  */
3963e89586aSKieran Bingham 
3973e89586aSKieran Bingham static const struct v4l2_subdev_ops adv748x_afe_ops = {
3983e89586aSKieran Bingham 	.video = &adv748x_afe_video_ops,
3993e89586aSKieran Bingham 	.pad = &adv748x_afe_pad_ops,
4003e89586aSKieran Bingham };
4013e89586aSKieran Bingham 
4023e89586aSKieran Bingham /* -----------------------------------------------------------------------------
4033e89586aSKieran Bingham  * Controls
4043e89586aSKieran Bingham  */
4053e89586aSKieran Bingham 
4063e89586aSKieran Bingham static const char * const afe_ctrl_frp_menu[] = {
4073e89586aSKieran Bingham 	"Disabled",
4083e89586aSKieran Bingham 	"Solid Blue",
4093e89586aSKieran Bingham 	"Color Bars",
4103e89586aSKieran Bingham 	"Grey Ramp",
4113e89586aSKieran Bingham 	"Cb Ramp",
4123e89586aSKieran Bingham 	"Cr Ramp",
4133e89586aSKieran Bingham 	"Boundary"
4143e89586aSKieran Bingham };
4153e89586aSKieran Bingham 
adv748x_afe_s_ctrl(struct v4l2_ctrl * ctrl)4163e89586aSKieran Bingham static int adv748x_afe_s_ctrl(struct v4l2_ctrl *ctrl)
4173e89586aSKieran Bingham {
4183e89586aSKieran Bingham 	struct adv748x_afe *afe = adv748x_ctrl_to_afe(ctrl);
4193e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
4203e89586aSKieran Bingham 	bool enable;
4213e89586aSKieran Bingham 	int ret;
4223e89586aSKieran Bingham 
4233e89586aSKieran Bingham 	ret = sdp_write(state, 0x0e, 0x00);
4243e89586aSKieran Bingham 	if (ret < 0)
4253e89586aSKieran Bingham 		return ret;
4263e89586aSKieran Bingham 
4273e89586aSKieran Bingham 	switch (ctrl->id) {
4283e89586aSKieran Bingham 	case V4L2_CID_BRIGHTNESS:
4293e89586aSKieran Bingham 		ret = sdp_write(state, ADV748X_SDP_BRI, ctrl->val);
4303e89586aSKieran Bingham 		break;
4313e89586aSKieran Bingham 	case V4L2_CID_HUE:
4323e89586aSKieran Bingham 		/* Hue is inverted according to HSL chart */
4333e89586aSKieran Bingham 		ret = sdp_write(state, ADV748X_SDP_HUE, -ctrl->val);
4343e89586aSKieran Bingham 		break;
4353e89586aSKieran Bingham 	case V4L2_CID_CONTRAST:
4363e89586aSKieran Bingham 		ret = sdp_write(state, ADV748X_SDP_CON, ctrl->val);
4373e89586aSKieran Bingham 		break;
4383e89586aSKieran Bingham 	case V4L2_CID_SATURATION:
4393e89586aSKieran Bingham 		ret = sdp_write(state, ADV748X_SDP_SD_SAT_U, ctrl->val);
4403e89586aSKieran Bingham 		if (ret)
4413e89586aSKieran Bingham 			break;
4423e89586aSKieran Bingham 		ret = sdp_write(state, ADV748X_SDP_SD_SAT_V, ctrl->val);
4433e89586aSKieran Bingham 		break;
4443e89586aSKieran Bingham 	case V4L2_CID_TEST_PATTERN:
4453e89586aSKieran Bingham 		enable = !!ctrl->val;
4463e89586aSKieran Bingham 
4473e89586aSKieran Bingham 		/* Enable/Disable Color bar test patterns */
4483e89586aSKieran Bingham 		ret = sdp_clrset(state, ADV748X_SDP_DEF, ADV748X_SDP_DEF_VAL_EN,
4493e89586aSKieran Bingham 				enable);
4503e89586aSKieran Bingham 		if (ret)
4513e89586aSKieran Bingham 			break;
4523e89586aSKieran Bingham 		ret = sdp_clrset(state, ADV748X_SDP_FRP, ADV748X_SDP_FRP_MASK,
4533e89586aSKieran Bingham 				enable ? ctrl->val - 1 : 0);
4543e89586aSKieran Bingham 		break;
4553e89586aSKieran Bingham 	default:
4563e89586aSKieran Bingham 		return -EINVAL;
4573e89586aSKieran Bingham 	}
4583e89586aSKieran Bingham 
4593e89586aSKieran Bingham 	return ret;
4603e89586aSKieran Bingham }
4613e89586aSKieran Bingham 
4623e89586aSKieran Bingham static const struct v4l2_ctrl_ops adv748x_afe_ctrl_ops = {
4633e89586aSKieran Bingham 	.s_ctrl = adv748x_afe_s_ctrl,
4643e89586aSKieran Bingham };
4653e89586aSKieran Bingham 
adv748x_afe_init_controls(struct adv748x_afe * afe)4663e89586aSKieran Bingham static int adv748x_afe_init_controls(struct adv748x_afe *afe)
4673e89586aSKieran Bingham {
4683e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
4693e89586aSKieran Bingham 
4703e89586aSKieran Bingham 	v4l2_ctrl_handler_init(&afe->ctrl_hdl, 5);
4713e89586aSKieran Bingham 
4723e89586aSKieran Bingham 	/* Use our mutex for the controls */
4733e89586aSKieran Bingham 	afe->ctrl_hdl.lock = &state->mutex;
4743e89586aSKieran Bingham 
4753e89586aSKieran Bingham 	v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops,
4763e89586aSKieran Bingham 			  V4L2_CID_BRIGHTNESS, ADV748X_SDP_BRI_MIN,
4773e89586aSKieran Bingham 			  ADV748X_SDP_BRI_MAX, 1, ADV748X_SDP_BRI_DEF);
4783e89586aSKieran Bingham 	v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops,
4793e89586aSKieran Bingham 			  V4L2_CID_CONTRAST, ADV748X_SDP_CON_MIN,
4803e89586aSKieran Bingham 			  ADV748X_SDP_CON_MAX, 1, ADV748X_SDP_CON_DEF);
4813e89586aSKieran Bingham 	v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops,
4823e89586aSKieran Bingham 			  V4L2_CID_SATURATION, ADV748X_SDP_SAT_MIN,
4833e89586aSKieran Bingham 			  ADV748X_SDP_SAT_MAX, 1, ADV748X_SDP_SAT_DEF);
4843e89586aSKieran Bingham 	v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops,
4853e89586aSKieran Bingham 			  V4L2_CID_HUE, ADV748X_SDP_HUE_MIN,
4863e89586aSKieran Bingham 			  ADV748X_SDP_HUE_MAX, 1, ADV748X_SDP_HUE_DEF);
4873e89586aSKieran Bingham 
4883e89586aSKieran Bingham 	v4l2_ctrl_new_std_menu_items(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops,
4893e89586aSKieran Bingham 				     V4L2_CID_TEST_PATTERN,
4903e89586aSKieran Bingham 				     ARRAY_SIZE(afe_ctrl_frp_menu) - 1,
4913e89586aSKieran Bingham 				     0, 0, afe_ctrl_frp_menu);
4923e89586aSKieran Bingham 
4933e89586aSKieran Bingham 	afe->sd.ctrl_handler = &afe->ctrl_hdl;
4943e89586aSKieran Bingham 	if (afe->ctrl_hdl.error) {
4953e89586aSKieran Bingham 		v4l2_ctrl_handler_free(&afe->ctrl_hdl);
4963e89586aSKieran Bingham 		return afe->ctrl_hdl.error;
4973e89586aSKieran Bingham 	}
4983e89586aSKieran Bingham 
4993e89586aSKieran Bingham 	return v4l2_ctrl_handler_setup(&afe->ctrl_hdl);
5003e89586aSKieran Bingham }
5013e89586aSKieran Bingham 
adv748x_afe_init(struct adv748x_afe * afe)5023e89586aSKieran Bingham int adv748x_afe_init(struct adv748x_afe *afe)
5033e89586aSKieran Bingham {
5043e89586aSKieran Bingham 	struct adv748x_state *state = adv748x_afe_to_state(afe);
5053e89586aSKieran Bingham 	int ret;
5063e89586aSKieran Bingham 	unsigned int i;
5073e89586aSKieran Bingham 
5083e89586aSKieran Bingham 	afe->input = 0;
5093e89586aSKieran Bingham 	afe->streaming = false;
5103e89586aSKieran Bingham 	afe->curr_norm = V4L2_STD_NTSC_M;
5113e89586aSKieran Bingham 
5123e89586aSKieran Bingham 	adv748x_subdev_init(&afe->sd, state, &adv748x_afe_ops,
5133e89586aSKieran Bingham 			    MEDIA_ENT_F_ATV_DECODER, "afe");
5143e89586aSKieran Bingham 
5153e89586aSKieran Bingham 	/* Identify the first connector found as a default input if set */
5163e89586aSKieran Bingham 	for (i = ADV748X_PORT_AIN0; i <= ADV748X_PORT_AIN7; i++) {
5173e89586aSKieran Bingham 		/* Inputs and ports are 1-indexed to match the data sheet */
5183e89586aSKieran Bingham 		if (state->endpoints[i]) {
5193e89586aSKieran Bingham 			afe->input = i;
5203e89586aSKieran Bingham 			break;
5213e89586aSKieran Bingham 		}
5223e89586aSKieran Bingham 	}
5233e89586aSKieran Bingham 
524*23ddb85dSNiklas Söderlund 	adv748x_afe_s_input(afe, afe->input);
525*23ddb85dSNiklas Söderlund 
526*23ddb85dSNiklas Söderlund 	adv_dbg(state, "AFE Default input set to %d\n", afe->input);
527*23ddb85dSNiklas Söderlund 
5283e89586aSKieran Bingham 	/* Entity pads and sinks are 0-indexed to match the pads */
5293e89586aSKieran Bingham 	for (i = ADV748X_AFE_SINK_AIN0; i <= ADV748X_AFE_SINK_AIN7; i++)
5303e89586aSKieran Bingham 		afe->pads[i].flags = MEDIA_PAD_FL_SINK;
5313e89586aSKieran Bingham 
5323e89586aSKieran Bingham 	afe->pads[ADV748X_AFE_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
5333e89586aSKieran Bingham 
5343e89586aSKieran Bingham 	ret = media_entity_pads_init(&afe->sd.entity, ADV748X_AFE_NR_PADS,
5353e89586aSKieran Bingham 			afe->pads);
5363e89586aSKieran Bingham 	if (ret)
5373e89586aSKieran Bingham 		return ret;
5383e89586aSKieran Bingham 
5393e89586aSKieran Bingham 	ret = adv748x_afe_init_controls(afe);
5403e89586aSKieran Bingham 	if (ret)
5413e89586aSKieran Bingham 		goto error;
5423e89586aSKieran Bingham 
5433e89586aSKieran Bingham 	return 0;
5443e89586aSKieran Bingham 
5453e89586aSKieran Bingham error:
5463e89586aSKieran Bingham 	media_entity_cleanup(&afe->sd.entity);
5473e89586aSKieran Bingham 
5483e89586aSKieran Bingham 	return ret;
5493e89586aSKieran Bingham }
5503e89586aSKieran Bingham 
adv748x_afe_cleanup(struct adv748x_afe * afe)5513e89586aSKieran Bingham void adv748x_afe_cleanup(struct adv748x_afe *afe)
5523e89586aSKieran Bingham {
5533e89586aSKieran Bingham 	v4l2_device_unregister_subdev(&afe->sd);
5543e89586aSKieran Bingham 	media_entity_cleanup(&afe->sd.entity);
5553e89586aSKieran Bingham 	v4l2_ctrl_handler_free(&afe->ctrl_hdl);
5563e89586aSKieran Bingham }
557