xref: /openbmc/linux/drivers/media/i2c/tda1997x.c (revision aaeb31c0)
19ac0038dSTim Harvey // SPDX-License-Identifier: GPL-2.0
29ac0038dSTim Harvey /*
39ac0038dSTim Harvey  * Copyright (C) 2018 Gateworks Corporation
49ac0038dSTim Harvey  */
59ac0038dSTim Harvey #include <linux/delay.h>
69ac0038dSTim Harvey #include <linux/hdmi.h>
79ac0038dSTim Harvey #include <linux/i2c.h>
89ac0038dSTim Harvey #include <linux/init.h>
99ac0038dSTim Harvey #include <linux/interrupt.h>
109ac0038dSTim Harvey #include <linux/kernel.h>
119ac0038dSTim Harvey #include <linux/module.h>
129ac0038dSTim Harvey #include <linux/of_graph.h>
139ac0038dSTim Harvey #include <linux/platform_device.h>
149ac0038dSTim Harvey #include <linux/regulator/consumer.h>
159ac0038dSTim Harvey #include <linux/types.h>
169ac0038dSTim Harvey #include <linux/v4l2-dv-timings.h>
179ac0038dSTim Harvey #include <linux/videodev2.h>
189ac0038dSTim Harvey 
199ac0038dSTim Harvey #include <media/v4l2-ctrls.h>
209ac0038dSTim Harvey #include <media/v4l2-device.h>
219ac0038dSTim Harvey #include <media/v4l2-dv-timings.h>
229ac0038dSTim Harvey #include <media/v4l2-event.h>
239ac0038dSTim Harvey #include <media/v4l2-fwnode.h>
249ac0038dSTim Harvey #include <media/i2c/tda1997x.h>
259ac0038dSTim Harvey 
269ac0038dSTim Harvey #include <sound/core.h>
279ac0038dSTim Harvey #include <sound/pcm.h>
289ac0038dSTim Harvey #include <sound/pcm_params.h>
299ac0038dSTim Harvey #include <sound/soc.h>
309ac0038dSTim Harvey 
319ac0038dSTim Harvey #include <dt-bindings/media/tda1997x.h>
329ac0038dSTim Harvey 
339ac0038dSTim Harvey #include "tda1997x_regs.h"
349ac0038dSTim Harvey 
359ac0038dSTim Harvey #define TDA1997X_MBUS_CODES	5
369ac0038dSTim Harvey 
379ac0038dSTim Harvey /* debug level */
389ac0038dSTim Harvey static int debug;
399ac0038dSTim Harvey module_param(debug, int, 0644);
409ac0038dSTim Harvey MODULE_PARM_DESC(debug, "debug level (0-2)");
419ac0038dSTim Harvey 
429ac0038dSTim Harvey /* Audio formats */
439ac0038dSTim Harvey static const char * const audtype_names[] = {
449ac0038dSTim Harvey 	"PCM",			/* PCM Samples */
459ac0038dSTim Harvey 	"HBR",			/* High Bit Rate Audio */
469ac0038dSTim Harvey 	"OBA",			/* One-Bit Audio */
479ac0038dSTim Harvey 	"DST"			/* Direct Stream Transfer */
489ac0038dSTim Harvey };
499ac0038dSTim Harvey 
509ac0038dSTim Harvey /* Audio output port formats */
519ac0038dSTim Harvey enum audfmt_types {
529ac0038dSTim Harvey 	AUDFMT_TYPE_DISABLED = 0,
539ac0038dSTim Harvey 	AUDFMT_TYPE_I2S,
549ac0038dSTim Harvey 	AUDFMT_TYPE_SPDIF,
559ac0038dSTim Harvey };
569ac0038dSTim Harvey static const char * const audfmt_names[] = {
579ac0038dSTim Harvey 	"Disabled",
589ac0038dSTim Harvey 	"I2S",
599ac0038dSTim Harvey 	"SPDIF",
609ac0038dSTim Harvey };
619ac0038dSTim Harvey 
629ac0038dSTim Harvey /* Video input formats */
639ac0038dSTim Harvey static const char * const hdmi_colorspace_names[] = {
649ac0038dSTim Harvey 	"RGB", "YUV422", "YUV444", "YUV420", "", "", "", "",
659ac0038dSTim Harvey };
669ac0038dSTim Harvey static const char * const hdmi_colorimetry_names[] = {
679ac0038dSTim Harvey 	"", "ITU601", "ITU709", "Extended",
689ac0038dSTim Harvey };
699ac0038dSTim Harvey static const char * const v4l2_quantization_names[] = {
709ac0038dSTim Harvey 	"Default",
719ac0038dSTim Harvey 	"Full Range (0-255)",
729ac0038dSTim Harvey 	"Limited Range (16-235)",
739ac0038dSTim Harvey };
749ac0038dSTim Harvey 
759ac0038dSTim Harvey /* Video output port formats */
769ac0038dSTim Harvey static const char * const vidfmt_names[] = {
779ac0038dSTim Harvey 	"RGB444/YUV444",	/* RGB/YUV444 16bit data bus, 8bpp */
789ac0038dSTim Harvey 	"YUV422 semi-planar",	/* YUV422 16bit data base, 8bpp */
799ac0038dSTim Harvey 	"YUV422 CCIR656",	/* BT656 (YUV 8bpp 2 clock per pixel) */
809ac0038dSTim Harvey 	"Invalid",
819ac0038dSTim Harvey };
829ac0038dSTim Harvey 
839ac0038dSTim Harvey /*
849ac0038dSTim Harvey  * Colorspace conversion matrices
859ac0038dSTim Harvey  */
869ac0038dSTim Harvey struct color_matrix_coefs {
879ac0038dSTim Harvey 	const char *name;
889ac0038dSTim Harvey 	/* Input offsets */
899ac0038dSTim Harvey 	s16 offint1;
909ac0038dSTim Harvey 	s16 offint2;
919ac0038dSTim Harvey 	s16 offint3;
929ac0038dSTim Harvey 	/* Coeficients */
939ac0038dSTim Harvey 	s16 p11coef;
949ac0038dSTim Harvey 	s16 p12coef;
959ac0038dSTim Harvey 	s16 p13coef;
969ac0038dSTim Harvey 	s16 p21coef;
979ac0038dSTim Harvey 	s16 p22coef;
989ac0038dSTim Harvey 	s16 p23coef;
999ac0038dSTim Harvey 	s16 p31coef;
1009ac0038dSTim Harvey 	s16 p32coef;
1019ac0038dSTim Harvey 	s16 p33coef;
1029ac0038dSTim Harvey 	/* Output offsets */
1039ac0038dSTim Harvey 	s16 offout1;
1049ac0038dSTim Harvey 	s16 offout2;
1059ac0038dSTim Harvey 	s16 offout3;
1069ac0038dSTim Harvey };
1079ac0038dSTim Harvey 
1089ac0038dSTim Harvey enum {
1099ac0038dSTim Harvey 	ITU709_RGBFULL,
1109ac0038dSTim Harvey 	ITU601_RGBFULL,
1119ac0038dSTim Harvey 	RGBLIMITED_RGBFULL,
1129ac0038dSTim Harvey 	RGBLIMITED_ITU601,
1139ac0038dSTim Harvey 	RGBLIMITED_ITU709,
1149ac0038dSTim Harvey 	RGBFULL_ITU601,
1159ac0038dSTim Harvey 	RGBFULL_ITU709,
1169ac0038dSTim Harvey };
1179ac0038dSTim Harvey 
1189ac0038dSTim Harvey /* NB: 4096 is 1.0 using fixed point numbers */
1199ac0038dSTim Harvey static const struct color_matrix_coefs conv_matrix[] = {
1209ac0038dSTim Harvey 	{
1219ac0038dSTim Harvey 		"YUV709 -> RGB full",
1229ac0038dSTim Harvey 		 -256, -2048,  -2048,
1239ac0038dSTim Harvey 		 4769, -2183,   -873,
1249ac0038dSTim Harvey 		 4769,  7343,      0,
1259ac0038dSTim Harvey 		 4769,     0,   8652,
1269ac0038dSTim Harvey 		    0,     0,      0,
1279ac0038dSTim Harvey 	},
1289ac0038dSTim Harvey 	{
1299ac0038dSTim Harvey 		"YUV601 -> RGB full",
1309ac0038dSTim Harvey 		 -256, -2048,  -2048,
1319ac0038dSTim Harvey 		 4769, -3330,  -1602,
1329ac0038dSTim Harvey 		 4769,  6538,      0,
1339ac0038dSTim Harvey 		 4769,     0,   8264,
1349ac0038dSTim Harvey 		  256,   256,    256,
1359ac0038dSTim Harvey 	},
1369ac0038dSTim Harvey 	{
1379ac0038dSTim Harvey 		"RGB limited -> RGB full",
1389ac0038dSTim Harvey 		 -256,  -256,   -256,
1399ac0038dSTim Harvey 		    0,  4769,      0,
1409ac0038dSTim Harvey 		    0,     0,   4769,
1419ac0038dSTim Harvey 		 4769,     0,      0,
1429ac0038dSTim Harvey 		    0,     0,      0,
1439ac0038dSTim Harvey 	},
1449ac0038dSTim Harvey 	{
1459ac0038dSTim Harvey 		"RGB limited -> ITU601",
1469ac0038dSTim Harvey 		 -256,  -256,   -256,
1479ac0038dSTim Harvey 		 2404,  1225,    467,
1489ac0038dSTim Harvey 		-1754,  2095,   -341,
1499ac0038dSTim Harvey 		-1388,  -707,   2095,
1509ac0038dSTim Harvey 		  256,  2048,   2048,
1519ac0038dSTim Harvey 	},
1529ac0038dSTim Harvey 	{
1539ac0038dSTim Harvey 		"RGB limited -> ITU709",
1549ac0038dSTim Harvey 		 -256,  -256,   -256,
1559ac0038dSTim Harvey 		 2918,   867,    295,
1569ac0038dSTim Harvey 		-1894,  2087,   -190,
1579ac0038dSTim Harvey 		-1607,  -477,   2087,
1589ac0038dSTim Harvey 		  256,  2048,   2048,
1599ac0038dSTim Harvey 	},
1609ac0038dSTim Harvey 	{
1619ac0038dSTim Harvey 		"RGB full -> ITU601",
1629ac0038dSTim Harvey 		    0,     0,      0,
1639ac0038dSTim Harvey 		 2065,  1052,    401,
1649ac0038dSTim Harvey 		-1506,  1799,   -293,
1659ac0038dSTim Harvey 		-1192,  -607,   1799,
1669ac0038dSTim Harvey 		  256,  2048,   2048,
1679ac0038dSTim Harvey 	},
1689ac0038dSTim Harvey 	{
1699ac0038dSTim Harvey 		"RGB full -> ITU709",
1709ac0038dSTim Harvey 		    0,     0,      0,
1719ac0038dSTim Harvey 		 2506,   745,    253,
1729ac0038dSTim Harvey 		-1627,  1792,   -163,
1739ac0038dSTim Harvey 		-1380,  -410,   1792,
1749ac0038dSTim Harvey 		  256,  2048,   2048,
1759ac0038dSTim Harvey 	},
1769ac0038dSTim Harvey };
1779ac0038dSTim Harvey 
1789ac0038dSTim Harvey static const struct v4l2_dv_timings_cap tda1997x_dv_timings_cap = {
1799ac0038dSTim Harvey 	.type = V4L2_DV_BT_656_1120,
1809ac0038dSTim Harvey 	/* keep this initialization for compatibility with GCC < 4.4.6 */
1819ac0038dSTim Harvey 	.reserved = { 0 },
1829ac0038dSTim Harvey 
1839ac0038dSTim Harvey 	V4L2_INIT_BT_TIMINGS(
1849ac0038dSTim Harvey 		640, 1920,			/* min/max width */
1859ac0038dSTim Harvey 		350, 1200,			/* min/max height */
1869ac0038dSTim Harvey 		13000000, 165000000,		/* min/max pixelclock */
1879ac0038dSTim Harvey 		/* standards */
1889ac0038dSTim Harvey 		V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
1899ac0038dSTim Harvey 			V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
1909ac0038dSTim Harvey 		/* capabilities */
1919ac0038dSTim Harvey 		V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE |
1929ac0038dSTim Harvey 			V4L2_DV_BT_CAP_REDUCED_BLANKING |
1939ac0038dSTim Harvey 			V4L2_DV_BT_CAP_CUSTOM
1949ac0038dSTim Harvey 	)
1959ac0038dSTim Harvey };
1969ac0038dSTim Harvey 
1979ac0038dSTim Harvey /* regulator supplies */
1989ac0038dSTim Harvey static const char * const tda1997x_supply_name[] = {
1999ac0038dSTim Harvey 	"DOVDD", /* Digital I/O supply */
2009ac0038dSTim Harvey 	"DVDD",  /* Digital Core supply */
2019ac0038dSTim Harvey 	"AVDD",  /* Analog supply */
2029ac0038dSTim Harvey };
2039ac0038dSTim Harvey 
2049ac0038dSTim Harvey #define TDA1997X_NUM_SUPPLIES ARRAY_SIZE(tda1997x_supply_name)
2059ac0038dSTim Harvey 
2069ac0038dSTim Harvey enum tda1997x_type {
2079ac0038dSTim Harvey 	TDA19971,
2089ac0038dSTim Harvey 	TDA19973,
2099ac0038dSTim Harvey };
2109ac0038dSTim Harvey 
2119ac0038dSTim Harvey enum tda1997x_hdmi_pads {
2129ac0038dSTim Harvey 	TDA1997X_PAD_SOURCE,
2139ac0038dSTim Harvey 	TDA1997X_NUM_PADS,
2149ac0038dSTim Harvey };
2159ac0038dSTim Harvey 
2169ac0038dSTim Harvey struct tda1997x_chip_info {
2179ac0038dSTim Harvey 	enum tda1997x_type type;
2189ac0038dSTim Harvey 	const char *name;
2199ac0038dSTim Harvey };
2209ac0038dSTim Harvey 
2219ac0038dSTim Harvey struct tda1997x_state {
2229ac0038dSTim Harvey 	const struct tda1997x_chip_info *info;
2239ac0038dSTim Harvey 	struct tda1997x_platform_data pdata;
2249ac0038dSTim Harvey 	struct i2c_client *client;
2259ac0038dSTim Harvey 	struct i2c_client *client_cec;
2269ac0038dSTim Harvey 	struct v4l2_subdev sd;
2279ac0038dSTim Harvey 	struct regulator_bulk_data supplies[TDA1997X_NUM_SUPPLIES];
2289ac0038dSTim Harvey 	struct media_pad pads[TDA1997X_NUM_PADS];
2299ac0038dSTim Harvey 	struct mutex lock;
2309ac0038dSTim Harvey 	struct mutex page_lock;
2319ac0038dSTim Harvey 	char page;
2329ac0038dSTim Harvey 
2339ac0038dSTim Harvey 	/* detected info from chip */
2349ac0038dSTim Harvey 	int chip_revision;
2359ac0038dSTim Harvey 	char port_30bit;
2369ac0038dSTim Harvey 	char output_2p5;
2379ac0038dSTim Harvey 	char tmdsb_clk;
2389ac0038dSTim Harvey 	char tmdsb_soc;
2399ac0038dSTim Harvey 
2409ac0038dSTim Harvey 	/* status info */
2419ac0038dSTim Harvey 	char hdmi_status;
2429ac0038dSTim Harvey 	char mptrw_in_progress;
2439ac0038dSTim Harvey 	char activity_status;
2449ac0038dSTim Harvey 	char input_detect[2];
2459ac0038dSTim Harvey 
2469ac0038dSTim Harvey 	/* video */
2479ac0038dSTim Harvey 	struct hdmi_avi_infoframe avi_infoframe;
2489ac0038dSTim Harvey 	struct v4l2_hdmi_colorimetry colorimetry;
2499ac0038dSTim Harvey 	u32 rgb_quantization_range;
2509ac0038dSTim Harvey 	struct v4l2_dv_timings timings;
2519ac0038dSTim Harvey 	int fps;
2529ac0038dSTim Harvey 	const struct color_matrix_coefs *conv;
2539ac0038dSTim Harvey 	u32 mbus_codes[TDA1997X_MBUS_CODES];	/* available modes */
2549ac0038dSTim Harvey 	u32 mbus_code;		/* current mode */
2559ac0038dSTim Harvey 	u8 vid_fmt;
2569ac0038dSTim Harvey 
2579ac0038dSTim Harvey 	/* controls */
2589ac0038dSTim Harvey 	struct v4l2_ctrl_handler hdl;
2599ac0038dSTim Harvey 	struct v4l2_ctrl *detect_tx_5v_ctrl;
2609ac0038dSTim Harvey 	struct v4l2_ctrl *rgb_quantization_range_ctrl;
2619ac0038dSTim Harvey 
2629ac0038dSTim Harvey 	/* audio */
2639ac0038dSTim Harvey 	u8  audio_ch_alloc;
2649ac0038dSTim Harvey 	int audio_samplerate;
2659ac0038dSTim Harvey 	int audio_channels;
2669ac0038dSTim Harvey 	int audio_samplesize;
2679ac0038dSTim Harvey 	int audio_type;
2689ac0038dSTim Harvey 	struct mutex audio_lock;
2699ac0038dSTim Harvey 	struct snd_pcm_substream *audio_stream;
2709ac0038dSTim Harvey 
2719ac0038dSTim Harvey 	/* EDID */
2729ac0038dSTim Harvey 	struct {
2739ac0038dSTim Harvey 		u8 edid[256];
2749ac0038dSTim Harvey 		u32 present;
2759ac0038dSTim Harvey 		unsigned int blocks;
2769ac0038dSTim Harvey 	} edid;
2779ac0038dSTim Harvey 	struct delayed_work delayed_work_enable_hpd;
2789ac0038dSTim Harvey };
2799ac0038dSTim Harvey 
2809ac0038dSTim Harvey static const struct v4l2_event tda1997x_ev_fmt = {
2819ac0038dSTim Harvey 	.type = V4L2_EVENT_SOURCE_CHANGE,
2829ac0038dSTim Harvey 	.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
2839ac0038dSTim Harvey };
2849ac0038dSTim Harvey 
2859ac0038dSTim Harvey static const struct tda1997x_chip_info tda1997x_chip_info[] = {
2869ac0038dSTim Harvey 	[TDA19971] = {
2879ac0038dSTim Harvey 		.type = TDA19971,
2889ac0038dSTim Harvey 		.name = "tda19971",
2899ac0038dSTim Harvey 	},
2909ac0038dSTim Harvey 	[TDA19973] = {
2919ac0038dSTim Harvey 		.type = TDA19973,
2929ac0038dSTim Harvey 		.name = "tda19973",
2939ac0038dSTim Harvey 	},
2949ac0038dSTim Harvey };
2959ac0038dSTim Harvey 
to_state(struct v4l2_subdev * sd)2969ac0038dSTim Harvey static inline struct tda1997x_state *to_state(struct v4l2_subdev *sd)
2979ac0038dSTim Harvey {
2989ac0038dSTim Harvey 	return container_of(sd, struct tda1997x_state, sd);
2999ac0038dSTim Harvey }
3009ac0038dSTim Harvey 
to_sd(struct v4l2_ctrl * ctrl)3019ac0038dSTim Harvey static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
3029ac0038dSTim Harvey {
3039ac0038dSTim Harvey 	return &container_of(ctrl->handler, struct tda1997x_state, hdl)->sd;
3049ac0038dSTim Harvey }
3059ac0038dSTim Harvey 
tda1997x_cec_read(struct v4l2_subdev * sd,u8 reg)3069ac0038dSTim Harvey static int tda1997x_cec_read(struct v4l2_subdev *sd, u8 reg)
3079ac0038dSTim Harvey {
3089ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
3099ac0038dSTim Harvey 	int val;
3109ac0038dSTim Harvey 
3119ac0038dSTim Harvey 	val = i2c_smbus_read_byte_data(state->client_cec, reg);
3129ac0038dSTim Harvey 	if (val < 0) {
3139ac0038dSTim Harvey 		v4l_err(state->client, "read reg error: reg=%2x\n", reg);
3149ac0038dSTim Harvey 		val = -1;
3159ac0038dSTim Harvey 	}
3169ac0038dSTim Harvey 
3179ac0038dSTim Harvey 	return val;
3189ac0038dSTim Harvey }
3199ac0038dSTim Harvey 
tda1997x_cec_write(struct v4l2_subdev * sd,u8 reg,u8 val)3209ac0038dSTim Harvey static int tda1997x_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
3219ac0038dSTim Harvey {
3229ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
3239ac0038dSTim Harvey 	int ret = 0;
3249ac0038dSTim Harvey 
3259ac0038dSTim Harvey 	ret = i2c_smbus_write_byte_data(state->client_cec, reg, val);
3269ac0038dSTim Harvey 	if (ret < 0) {
3279ac0038dSTim Harvey 		v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n",
3289ac0038dSTim Harvey 			reg, val);
3299ac0038dSTim Harvey 		ret = -1;
3309ac0038dSTim Harvey 	}
3319ac0038dSTim Harvey 
3329ac0038dSTim Harvey 	return ret;
3339ac0038dSTim Harvey }
3349ac0038dSTim Harvey 
3359ac0038dSTim Harvey /* -----------------------------------------------------------------------------
3369ac0038dSTim Harvey  * I2C transfer
3379ac0038dSTim Harvey  */
3389ac0038dSTim Harvey 
tda1997x_setpage(struct v4l2_subdev * sd,u8 page)3399ac0038dSTim Harvey static int tda1997x_setpage(struct v4l2_subdev *sd, u8 page)
3409ac0038dSTim Harvey {
3419ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
3429ac0038dSTim Harvey 	int ret;
3439ac0038dSTim Harvey 
3449ac0038dSTim Harvey 	if (state->page != page) {
3459ac0038dSTim Harvey 		ret = i2c_smbus_write_byte_data(state->client,
3469ac0038dSTim Harvey 			REG_CURPAGE_00H, page);
3479ac0038dSTim Harvey 		if (ret < 0) {
3489ac0038dSTim Harvey 			v4l_err(state->client,
3499ac0038dSTim Harvey 				"write reg error:reg=%2x,val=%2x\n",
3509ac0038dSTim Harvey 				REG_CURPAGE_00H, page);
3519ac0038dSTim Harvey 			return ret;
3529ac0038dSTim Harvey 		}
3539ac0038dSTim Harvey 		state->page = page;
3549ac0038dSTim Harvey 	}
3559ac0038dSTim Harvey 	return 0;
3569ac0038dSTim Harvey }
3579ac0038dSTim Harvey 
io_read(struct v4l2_subdev * sd,u16 reg)3589ac0038dSTim Harvey static inline int io_read(struct v4l2_subdev *sd, u16 reg)
3599ac0038dSTim Harvey {
3609ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
3619ac0038dSTim Harvey 	int val;
3629ac0038dSTim Harvey 
3639ac0038dSTim Harvey 	mutex_lock(&state->page_lock);
3649ac0038dSTim Harvey 	if (tda1997x_setpage(sd, reg >> 8)) {
3659ac0038dSTim Harvey 		val = -1;
3669ac0038dSTim Harvey 		goto out;
3679ac0038dSTim Harvey 	}
3689ac0038dSTim Harvey 
3699ac0038dSTim Harvey 	val = i2c_smbus_read_byte_data(state->client, reg&0xff);
3709ac0038dSTim Harvey 	if (val < 0) {
3719ac0038dSTim Harvey 		v4l_err(state->client, "read reg error: reg=%2x\n", reg & 0xff);
3729ac0038dSTim Harvey 		val = -1;
3739ac0038dSTim Harvey 		goto out;
3749ac0038dSTim Harvey 	}
3759ac0038dSTim Harvey 
3769ac0038dSTim Harvey out:
3779ac0038dSTim Harvey 	mutex_unlock(&state->page_lock);
3789ac0038dSTim Harvey 	return val;
3799ac0038dSTim Harvey }
3809ac0038dSTim Harvey 
io_read16(struct v4l2_subdev * sd,u16 reg)3819ac0038dSTim Harvey static inline long io_read16(struct v4l2_subdev *sd, u16 reg)
3829ac0038dSTim Harvey {
3839ac0038dSTim Harvey 	int val;
3849ac0038dSTim Harvey 	long lval = 0;
3859ac0038dSTim Harvey 
3869ac0038dSTim Harvey 	val = io_read(sd, reg);
3879ac0038dSTim Harvey 	if (val < 0)
3889ac0038dSTim Harvey 		return val;
3899ac0038dSTim Harvey 	lval |= (val << 8);
3909ac0038dSTim Harvey 	val = io_read(sd, reg + 1);
3919ac0038dSTim Harvey 	if (val < 0)
3929ac0038dSTim Harvey 		return val;
3939ac0038dSTim Harvey 	lval |= val;
3949ac0038dSTim Harvey 
3959ac0038dSTim Harvey 	return lval;
3969ac0038dSTim Harvey }
3979ac0038dSTim Harvey 
io_read24(struct v4l2_subdev * sd,u16 reg)3989ac0038dSTim Harvey static inline long io_read24(struct v4l2_subdev *sd, u16 reg)
3999ac0038dSTim Harvey {
4009ac0038dSTim Harvey 	int val;
4019ac0038dSTim Harvey 	long lval = 0;
4029ac0038dSTim Harvey 
4039ac0038dSTim Harvey 	val = io_read(sd, reg);
4049ac0038dSTim Harvey 	if (val < 0)
4059ac0038dSTim Harvey 		return val;
4069ac0038dSTim Harvey 	lval |= (val << 16);
4079ac0038dSTim Harvey 	val = io_read(sd, reg + 1);
4089ac0038dSTim Harvey 	if (val < 0)
4099ac0038dSTim Harvey 		return val;
4109ac0038dSTim Harvey 	lval |= (val << 8);
4119ac0038dSTim Harvey 	val = io_read(sd, reg + 2);
4129ac0038dSTim Harvey 	if (val < 0)
4139ac0038dSTim Harvey 		return val;
4149ac0038dSTim Harvey 	lval |= val;
4159ac0038dSTim Harvey 
4169ac0038dSTim Harvey 	return lval;
4179ac0038dSTim Harvey }
4189ac0038dSTim Harvey 
io_readn(struct v4l2_subdev * sd,u16 reg,u8 len,u8 * data)4199ac0038dSTim Harvey static unsigned int io_readn(struct v4l2_subdev *sd, u16 reg, u8 len, u8 *data)
4209ac0038dSTim Harvey {
4219ac0038dSTim Harvey 	int i;
4229ac0038dSTim Harvey 	int sz = 0;
4239ac0038dSTim Harvey 	int val;
4249ac0038dSTim Harvey 
4259ac0038dSTim Harvey 	for (i = 0; i < len; i++) {
4269ac0038dSTim Harvey 		val = io_read(sd, reg + i);
4279ac0038dSTim Harvey 		if (val < 0)
4289ac0038dSTim Harvey 			break;
4299ac0038dSTim Harvey 		data[i] = val;
4309ac0038dSTim Harvey 		sz++;
4319ac0038dSTim Harvey 	}
4329ac0038dSTim Harvey 
4339ac0038dSTim Harvey 	return sz;
4349ac0038dSTim Harvey }
4359ac0038dSTim Harvey 
io_write(struct v4l2_subdev * sd,u16 reg,u8 val)4369ac0038dSTim Harvey static int io_write(struct v4l2_subdev *sd, u16 reg, u8 val)
4379ac0038dSTim Harvey {
4389ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
4399ac0038dSTim Harvey 	s32 ret = 0;
4409ac0038dSTim Harvey 
4419ac0038dSTim Harvey 	mutex_lock(&state->page_lock);
4429ac0038dSTim Harvey 	if (tda1997x_setpage(sd, reg >> 8)) {
4439ac0038dSTim Harvey 		ret = -1;
4449ac0038dSTim Harvey 		goto out;
4459ac0038dSTim Harvey 	}
4469ac0038dSTim Harvey 
4479ac0038dSTim Harvey 	ret = i2c_smbus_write_byte_data(state->client, reg & 0xff, val);
4489ac0038dSTim Harvey 	if (ret < 0) {
4499ac0038dSTim Harvey 		v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n",
4509ac0038dSTim Harvey 			reg&0xff, val);
4519ac0038dSTim Harvey 		ret = -1;
4529ac0038dSTim Harvey 		goto out;
4539ac0038dSTim Harvey 	}
4549ac0038dSTim Harvey 
4559ac0038dSTim Harvey out:
4569ac0038dSTim Harvey 	mutex_unlock(&state->page_lock);
4579ac0038dSTim Harvey 	return ret;
4589ac0038dSTim Harvey }
4599ac0038dSTim Harvey 
io_write16(struct v4l2_subdev * sd,u16 reg,u16 val)4609ac0038dSTim Harvey static int io_write16(struct v4l2_subdev *sd, u16 reg, u16 val)
4619ac0038dSTim Harvey {
4629ac0038dSTim Harvey 	int ret;
4639ac0038dSTim Harvey 
4649ac0038dSTim Harvey 	ret = io_write(sd, reg, (val >> 8) & 0xff);
4659ac0038dSTim Harvey 	if (ret < 0)
4669ac0038dSTim Harvey 		return ret;
4679ac0038dSTim Harvey 	ret = io_write(sd, reg + 1, val & 0xff);
4689ac0038dSTim Harvey 	if (ret < 0)
4699ac0038dSTim Harvey 		return ret;
4709ac0038dSTim Harvey 	return 0;
4719ac0038dSTim Harvey }
4729ac0038dSTim Harvey 
io_write24(struct v4l2_subdev * sd,u16 reg,u32 val)4739ac0038dSTim Harvey static int io_write24(struct v4l2_subdev *sd, u16 reg, u32 val)
4749ac0038dSTim Harvey {
4759ac0038dSTim Harvey 	int ret;
4769ac0038dSTim Harvey 
4779ac0038dSTim Harvey 	ret = io_write(sd, reg, (val >> 16) & 0xff);
4789ac0038dSTim Harvey 	if (ret < 0)
4799ac0038dSTim Harvey 		return ret;
4809ac0038dSTim Harvey 	ret = io_write(sd, reg + 1, (val >> 8) & 0xff);
4819ac0038dSTim Harvey 	if (ret < 0)
4829ac0038dSTim Harvey 		return ret;
4839ac0038dSTim Harvey 	ret = io_write(sd, reg + 2, val & 0xff);
4849ac0038dSTim Harvey 	if (ret < 0)
4859ac0038dSTim Harvey 		return ret;
4869ac0038dSTim Harvey 	return 0;
4879ac0038dSTim Harvey }
4889ac0038dSTim Harvey 
4899ac0038dSTim Harvey /* -----------------------------------------------------------------------------
4909ac0038dSTim Harvey  * Hotplug
4919ac0038dSTim Harvey  */
4929ac0038dSTim Harvey 
4939ac0038dSTim Harvey enum hpd_mode {
4949ac0038dSTim Harvey 	HPD_LOW_BP,	/* HPD low and pulse of at least 100ms */
4959ac0038dSTim Harvey 	HPD_LOW_OTHER,	/* HPD low and pulse of at least 100ms */
4969ac0038dSTim Harvey 	HPD_HIGH_BP,	/* HIGH */
4979ac0038dSTim Harvey 	HPD_HIGH_OTHER,
4989ac0038dSTim Harvey 	HPD_PULSE,	/* HPD low pulse */
4999ac0038dSTim Harvey };
5009ac0038dSTim Harvey 
5019ac0038dSTim Harvey /* manual HPD (Hot Plug Detect) control */
tda1997x_manual_hpd(struct v4l2_subdev * sd,enum hpd_mode mode)5029ac0038dSTim Harvey static int tda1997x_manual_hpd(struct v4l2_subdev *sd, enum hpd_mode mode)
5039ac0038dSTim Harvey {
5049ac0038dSTim Harvey 	u8 hpd_auto, hpd_pwr, hpd_man;
5059ac0038dSTim Harvey 
5069ac0038dSTim Harvey 	hpd_auto = io_read(sd, REG_HPD_AUTO_CTRL);
5079ac0038dSTim Harvey 	hpd_pwr = io_read(sd, REG_HPD_POWER);
5089ac0038dSTim Harvey 	hpd_man = io_read(sd, REG_HPD_MAN_CTRL);
5099ac0038dSTim Harvey 
5109ac0038dSTim Harvey 	/* mask out unused bits */
5119ac0038dSTim Harvey 	hpd_man &= (HPD_MAN_CTRL_HPD_PULSE |
5129ac0038dSTim Harvey 		    HPD_MAN_CTRL_5VEN |
5139ac0038dSTim Harvey 		    HPD_MAN_CTRL_HPD_B |
5149ac0038dSTim Harvey 		    HPD_MAN_CTRL_HPD_A);
5159ac0038dSTim Harvey 
5169ac0038dSTim Harvey 	switch (mode) {
5179ac0038dSTim Harvey 	/* HPD low and pulse of at least 100ms */
5189ac0038dSTim Harvey 	case HPD_LOW_BP:
5199ac0038dSTim Harvey 		/* hpd_bp=0 */
5209ac0038dSTim Harvey 		hpd_pwr &= ~HPD_POWER_BP_MASK;
5219ac0038dSTim Harvey 		/* disable HPD_A and HPD_B */
5229ac0038dSTim Harvey 		hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
5239ac0038dSTim Harvey 		io_write(sd, REG_HPD_POWER, hpd_pwr);
5249ac0038dSTim Harvey 		io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
5259ac0038dSTim Harvey 		break;
5269ac0038dSTim Harvey 	/* HPD high */
5279ac0038dSTim Harvey 	case HPD_HIGH_BP:
5289ac0038dSTim Harvey 		/* hpd_bp=1 */
5299ac0038dSTim Harvey 		hpd_pwr &= ~HPD_POWER_BP_MASK;
5309ac0038dSTim Harvey 		hpd_pwr |= 1 << HPD_POWER_BP_SHIFT;
5319ac0038dSTim Harvey 		io_write(sd, REG_HPD_POWER, hpd_pwr);
5329ac0038dSTim Harvey 		break;
5339ac0038dSTim Harvey 	/* HPD low and pulse of at least 100ms */
5349ac0038dSTim Harvey 	case HPD_LOW_OTHER:
5359ac0038dSTim Harvey 		/* disable HPD_A and HPD_B */
5369ac0038dSTim Harvey 		hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
5379ac0038dSTim Harvey 		/* hp_other=0 */
5389ac0038dSTim Harvey 		hpd_auto &= ~HPD_AUTO_HP_OTHER;
5399ac0038dSTim Harvey 		io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto);
5409ac0038dSTim Harvey 		io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
5419ac0038dSTim Harvey 		break;
5429ac0038dSTim Harvey 	/* HPD high */
5439ac0038dSTim Harvey 	case HPD_HIGH_OTHER:
5449ac0038dSTim Harvey 		hpd_auto |= HPD_AUTO_HP_OTHER;
5459ac0038dSTim Harvey 		io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto);
5469ac0038dSTim Harvey 		break;
5479ac0038dSTim Harvey 	/* HPD low pulse */
5489ac0038dSTim Harvey 	case HPD_PULSE:
5499ac0038dSTim Harvey 		/* disable HPD_A and HPD_B */
5509ac0038dSTim Harvey 		hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
5519ac0038dSTim Harvey 		io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
5529ac0038dSTim Harvey 		break;
5539ac0038dSTim Harvey 	}
5549ac0038dSTim Harvey 
5559ac0038dSTim Harvey 	return 0;
5569ac0038dSTim Harvey }
5579ac0038dSTim Harvey 
tda1997x_delayed_work_enable_hpd(struct work_struct * work)5589ac0038dSTim Harvey static void tda1997x_delayed_work_enable_hpd(struct work_struct *work)
5599ac0038dSTim Harvey {
5609ac0038dSTim Harvey 	struct delayed_work *dwork = to_delayed_work(work);
5619ac0038dSTim Harvey 	struct tda1997x_state *state = container_of(dwork,
5629ac0038dSTim Harvey 						    struct tda1997x_state,
5639ac0038dSTim Harvey 						    delayed_work_enable_hpd);
5649ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
5659ac0038dSTim Harvey 
56695d45366SKrzysztof Hałasa 	v4l2_dbg(2, debug, sd, "%s\n", __func__);
5679ac0038dSTim Harvey 
5689ac0038dSTim Harvey 	/* Set HPD high */
5699ac0038dSTim Harvey 	tda1997x_manual_hpd(sd, HPD_HIGH_OTHER);
5709ac0038dSTim Harvey 	tda1997x_manual_hpd(sd, HPD_HIGH_BP);
5719ac0038dSTim Harvey 
5729ac0038dSTim Harvey 	state->edid.present = 1;
5739ac0038dSTim Harvey }
5749ac0038dSTim Harvey 
tda1997x_disable_edid(struct v4l2_subdev * sd)5759ac0038dSTim Harvey static void tda1997x_disable_edid(struct v4l2_subdev *sd)
5769ac0038dSTim Harvey {
5779ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
5789ac0038dSTim Harvey 
5799ac0038dSTim Harvey 	v4l2_dbg(1, debug, sd, "%s\n", __func__);
5809ac0038dSTim Harvey 	cancel_delayed_work_sync(&state->delayed_work_enable_hpd);
5819ac0038dSTim Harvey 
5829ac0038dSTim Harvey 	/* Set HPD low */
5839ac0038dSTim Harvey 	tda1997x_manual_hpd(sd, HPD_LOW_BP);
5849ac0038dSTim Harvey }
5859ac0038dSTim Harvey 
tda1997x_enable_edid(struct v4l2_subdev * sd)5869ac0038dSTim Harvey static void tda1997x_enable_edid(struct v4l2_subdev *sd)
5879ac0038dSTim Harvey {
5889ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
5899ac0038dSTim Harvey 
5909ac0038dSTim Harvey 	v4l2_dbg(1, debug, sd, "%s\n", __func__);
5919ac0038dSTim Harvey 
5929ac0038dSTim Harvey 	/* Enable hotplug after 100ms */
5939ac0038dSTim Harvey 	schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 10);
5949ac0038dSTim Harvey }
5959ac0038dSTim Harvey 
5969ac0038dSTim Harvey /* -----------------------------------------------------------------------------
5979ac0038dSTim Harvey  * Signal Control
5989ac0038dSTim Harvey  */
5999ac0038dSTim Harvey 
6009ac0038dSTim Harvey /*
6019ac0038dSTim Harvey  * configure vid_fmt based on mbus_code
6029ac0038dSTim Harvey  */
6039ac0038dSTim Harvey static int
tda1997x_setup_format(struct tda1997x_state * state,u32 code)6049ac0038dSTim Harvey tda1997x_setup_format(struct tda1997x_state *state, u32 code)
6059ac0038dSTim Harvey {
6069ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s code=0x%x\n", __func__, code);
6079ac0038dSTim Harvey 	switch (code) {
6089ac0038dSTim Harvey 	case MEDIA_BUS_FMT_RGB121212_1X36:
6099ac0038dSTim Harvey 	case MEDIA_BUS_FMT_RGB888_1X24:
6109ac0038dSTim Harvey 	case MEDIA_BUS_FMT_YUV12_1X36:
6119ac0038dSTim Harvey 	case MEDIA_BUS_FMT_YUV8_1X24:
6129ac0038dSTim Harvey 		state->vid_fmt = OF_FMT_444;
6139ac0038dSTim Harvey 		break;
6149ac0038dSTim Harvey 	case MEDIA_BUS_FMT_UYVY12_1X24:
6159ac0038dSTim Harvey 	case MEDIA_BUS_FMT_UYVY10_1X20:
6169ac0038dSTim Harvey 	case MEDIA_BUS_FMT_UYVY8_1X16:
6179ac0038dSTim Harvey 		state->vid_fmt = OF_FMT_422_SMPT;
6189ac0038dSTim Harvey 		break;
6199ac0038dSTim Harvey 	case MEDIA_BUS_FMT_UYVY12_2X12:
6209ac0038dSTim Harvey 	case MEDIA_BUS_FMT_UYVY10_2X10:
6219ac0038dSTim Harvey 	case MEDIA_BUS_FMT_UYVY8_2X8:
6229ac0038dSTim Harvey 		state->vid_fmt = OF_FMT_422_CCIR;
6239ac0038dSTim Harvey 		break;
6249ac0038dSTim Harvey 	default:
6259ac0038dSTim Harvey 		v4l_err(state->client, "incompatible format (0x%x)\n", code);
6269ac0038dSTim Harvey 		return -EINVAL;
6279ac0038dSTim Harvey 	}
6289ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s code=0x%x fmt=%s\n", __func__,
6299ac0038dSTim Harvey 		code, vidfmt_names[state->vid_fmt]);
6309ac0038dSTim Harvey 	state->mbus_code = code;
6319ac0038dSTim Harvey 
6329ac0038dSTim Harvey 	return 0;
6339ac0038dSTim Harvey }
6349ac0038dSTim Harvey 
6359ac0038dSTim Harvey /*
6369ac0038dSTim Harvey  * The color conversion matrix will convert between the colorimetry of the
6379ac0038dSTim Harvey  * HDMI input to the desired output format RGB|YUV. RGB output is to be
6389ac0038dSTim Harvey  * full-range and YUV is to be limited range.
6399ac0038dSTim Harvey  *
6409ac0038dSTim Harvey  * RGB full-range uses values from 0 to 255 which is recommended on a monitor
6419ac0038dSTim Harvey  * and RGB Limited uses values from 16 to 236 (16=black, 235=white) which is
6429ac0038dSTim Harvey  * typically recommended on a TV.
6439ac0038dSTim Harvey  */
6449ac0038dSTim Harvey static void
tda1997x_configure_csc(struct v4l2_subdev * sd)6459ac0038dSTim Harvey tda1997x_configure_csc(struct v4l2_subdev *sd)
6469ac0038dSTim Harvey {
6479ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
6489ac0038dSTim Harvey 	struct hdmi_avi_infoframe *avi = &state->avi_infoframe;
6499ac0038dSTim Harvey 	struct v4l2_hdmi_colorimetry *c = &state->colorimetry;
6509ac0038dSTim Harvey 	/* Blanking code values depend on output colorspace (RGB or YUV) */
6519ac0038dSTim Harvey 	struct blanking_codes {
6529ac0038dSTim Harvey 		s16 code_gy;
6539ac0038dSTim Harvey 		s16 code_bu;
6549ac0038dSTim Harvey 		s16 code_rv;
6559ac0038dSTim Harvey 	};
6569ac0038dSTim Harvey 	static const struct blanking_codes rgb_blanking = { 64, 64, 64 };
6579ac0038dSTim Harvey 	static const struct blanking_codes yuv_blanking = { 64, 512, 512 };
6589ac0038dSTim Harvey 	const struct blanking_codes *blanking_codes = NULL;
6599ac0038dSTim Harvey 	u8 reg;
6609ac0038dSTim Harvey 
6619ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "input:%s quant:%s output:%s\n",
6629ac0038dSTim Harvey 		hdmi_colorspace_names[avi->colorspace],
6639ac0038dSTim Harvey 		v4l2_quantization_names[c->quantization],
6649ac0038dSTim Harvey 		vidfmt_names[state->vid_fmt]);
6659ac0038dSTim Harvey 	state->conv = NULL;
6669ac0038dSTim Harvey 	switch (state->vid_fmt) {
6679ac0038dSTim Harvey 	/* RGB output */
6689ac0038dSTim Harvey 	case OF_FMT_444:
6699ac0038dSTim Harvey 		blanking_codes = &rgb_blanking;
6709ac0038dSTim Harvey 		if (c->colorspace == V4L2_COLORSPACE_SRGB) {
6719ac0038dSTim Harvey 			if (c->quantization == V4L2_QUANTIZATION_LIM_RANGE)
6729ac0038dSTim Harvey 				state->conv = &conv_matrix[RGBLIMITED_RGBFULL];
6739ac0038dSTim Harvey 		} else {
6749ac0038dSTim Harvey 			if (c->colorspace == V4L2_COLORSPACE_REC709)
6759ac0038dSTim Harvey 				state->conv = &conv_matrix[ITU709_RGBFULL];
6769ac0038dSTim Harvey 			else if (c->colorspace == V4L2_COLORSPACE_SMPTE170M)
6779ac0038dSTim Harvey 				state->conv = &conv_matrix[ITU601_RGBFULL];
6789ac0038dSTim Harvey 		}
6799ac0038dSTim Harvey 		break;
6809ac0038dSTim Harvey 
6819ac0038dSTim Harvey 	/* YUV output */
6829ac0038dSTim Harvey 	case OF_FMT_422_SMPT: /* semi-planar */
6839ac0038dSTim Harvey 	case OF_FMT_422_CCIR: /* CCIR656 */
6849ac0038dSTim Harvey 		blanking_codes = &yuv_blanking;
6859ac0038dSTim Harvey 		if ((c->colorspace == V4L2_COLORSPACE_SRGB) &&
6869ac0038dSTim Harvey 		    (c->quantization == V4L2_QUANTIZATION_FULL_RANGE)) {
6879ac0038dSTim Harvey 			if (state->timings.bt.height <= 576)
6889ac0038dSTim Harvey 				state->conv = &conv_matrix[RGBFULL_ITU601];
6899ac0038dSTim Harvey 			else
6909ac0038dSTim Harvey 				state->conv = &conv_matrix[RGBFULL_ITU709];
6919ac0038dSTim Harvey 		} else if ((c->colorspace == V4L2_COLORSPACE_SRGB) &&
6929ac0038dSTim Harvey 			   (c->quantization == V4L2_QUANTIZATION_LIM_RANGE)) {
6939ac0038dSTim Harvey 			if (state->timings.bt.height <= 576)
6949ac0038dSTim Harvey 				state->conv = &conv_matrix[RGBLIMITED_ITU601];
6959ac0038dSTim Harvey 			else
6969ac0038dSTim Harvey 				state->conv = &conv_matrix[RGBLIMITED_ITU709];
6979ac0038dSTim Harvey 		}
6989ac0038dSTim Harvey 		break;
6999ac0038dSTim Harvey 	}
7009ac0038dSTim Harvey 
7019ac0038dSTim Harvey 	if (state->conv) {
7029ac0038dSTim Harvey 		v4l_dbg(1, debug, state->client, "%s\n",
7039ac0038dSTim Harvey 			state->conv->name);
7049ac0038dSTim Harvey 		/* enable matrix conversion */
7059ac0038dSTim Harvey 		reg = io_read(sd, REG_VDP_CTRL);
7069ac0038dSTim Harvey 		reg &= ~VDP_CTRL_MATRIX_BP;
7079ac0038dSTim Harvey 		io_write(sd, REG_VDP_CTRL, reg);
7089ac0038dSTim Harvey 		/* offset inputs */
7099ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 0, state->conv->offint1);
7109ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 2, state->conv->offint2);
7119ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 4, state->conv->offint3);
7129ac0038dSTim Harvey 		/* coefficients */
7139ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 6, state->conv->p11coef);
7149ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 8, state->conv->p12coef);
7159ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 10, state->conv->p13coef);
7169ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 12, state->conv->p21coef);
7179ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 14, state->conv->p22coef);
7189ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 16, state->conv->p23coef);
7199ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 18, state->conv->p31coef);
7209ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 20, state->conv->p32coef);
7219ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 22, state->conv->p33coef);
7229ac0038dSTim Harvey 		/* offset outputs */
7239ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 24, state->conv->offout1);
7249ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 26, state->conv->offout2);
7259ac0038dSTim Harvey 		io_write16(sd, REG_VDP_MATRIX + 28, state->conv->offout3);
7269ac0038dSTim Harvey 	} else {
7279ac0038dSTim Harvey 		/* disable matrix conversion */
7289ac0038dSTim Harvey 		reg = io_read(sd, REG_VDP_CTRL);
7299ac0038dSTim Harvey 		reg |= VDP_CTRL_MATRIX_BP;
7309ac0038dSTim Harvey 		io_write(sd, REG_VDP_CTRL, reg);
7319ac0038dSTim Harvey 	}
7329ac0038dSTim Harvey 
7339ac0038dSTim Harvey 	/* SetBlankingCodes */
7349ac0038dSTim Harvey 	if (blanking_codes) {
7359ac0038dSTim Harvey 		io_write16(sd, REG_BLK_GY, blanking_codes->code_gy);
7369ac0038dSTim Harvey 		io_write16(sd, REG_BLK_BU, blanking_codes->code_bu);
7379ac0038dSTim Harvey 		io_write16(sd, REG_BLK_RV, blanking_codes->code_rv);
7389ac0038dSTim Harvey 	}
7399ac0038dSTim Harvey }
7409ac0038dSTim Harvey 
7419ac0038dSTim Harvey /* Configure frame detection window and VHREF timing generator */
7429ac0038dSTim Harvey static void
tda1997x_configure_vhref(struct v4l2_subdev * sd)7439ac0038dSTim Harvey tda1997x_configure_vhref(struct v4l2_subdev *sd)
7449ac0038dSTim Harvey {
7459ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
7469ac0038dSTim Harvey 	const struct v4l2_bt_timings *bt = &state->timings.bt;
7479ac0038dSTim Harvey 	int width, lines;
7489ac0038dSTim Harvey 	u16 href_start, href_end;
7499ac0038dSTim Harvey 	u16 vref_f1_start, vref_f2_start;
7509ac0038dSTim Harvey 	u8 vref_f1_width, vref_f2_width;
7519ac0038dSTim Harvey 	u8 field_polarity;
7529ac0038dSTim Harvey 	u16 fieldref_f1_start, fieldref_f2_start;
7539ac0038dSTim Harvey 	u8 reg;
7549ac0038dSTim Harvey 
7559ac0038dSTim Harvey 	href_start = bt->hbackporch + bt->hsync + 1;
7569ac0038dSTim Harvey 	href_end = href_start + bt->width;
7579ac0038dSTim Harvey 	vref_f1_start = bt->height + bt->vbackporch + bt->vsync +
7589ac0038dSTim Harvey 			bt->il_vbackporch + bt->il_vsync +
7599ac0038dSTim Harvey 			bt->il_vfrontporch;
7609ac0038dSTim Harvey 	vref_f1_width = bt->vbackporch + bt->vsync + bt->vfrontporch;
7619ac0038dSTim Harvey 	vref_f2_start = 0;
7629ac0038dSTim Harvey 	vref_f2_width = 0;
7639ac0038dSTim Harvey 	fieldref_f1_start = 0;
7649ac0038dSTim Harvey 	fieldref_f2_start = 0;
7659ac0038dSTim Harvey 	if (bt->interlaced) {
7669ac0038dSTim Harvey 		vref_f2_start = (bt->height / 2) +
7679ac0038dSTim Harvey 				(bt->il_vbackporch + bt->il_vsync - 1);
7689ac0038dSTim Harvey 		vref_f2_width = bt->il_vbackporch + bt->il_vsync +
7699ac0038dSTim Harvey 				bt->il_vfrontporch;
7709ac0038dSTim Harvey 		fieldref_f2_start = vref_f2_start + bt->il_vfrontporch +
7719ac0038dSTim Harvey 				    fieldref_f1_start;
7729ac0038dSTim Harvey 	}
7739ac0038dSTim Harvey 	field_polarity = 0;
7749ac0038dSTim Harvey 
7759ac0038dSTim Harvey 	width = V4L2_DV_BT_FRAME_WIDTH(bt);
7769ac0038dSTim Harvey 	lines = V4L2_DV_BT_FRAME_HEIGHT(bt);
7779ac0038dSTim Harvey 
7789ac0038dSTim Harvey 	/*
7799ac0038dSTim Harvey 	 * Configure Frame Detection Window:
7809ac0038dSTim Harvey 	 *  horiz area where the VHREF module consider a VSYNC a new frame
7819ac0038dSTim Harvey 	 */
7829ac0038dSTim Harvey 	io_write16(sd, REG_FDW_S, 0x2ef); /* start position */
7839ac0038dSTim Harvey 	io_write16(sd, REG_FDW_E, 0x141); /* end position */
7849ac0038dSTim Harvey 
7859ac0038dSTim Harvey 	/* Set Pixel And Line Counters */
7869ac0038dSTim Harvey 	if (state->chip_revision == 0)
7879ac0038dSTim Harvey 		io_write16(sd, REG_PXCNT_PR, 4);
7889ac0038dSTim Harvey 	else
7899ac0038dSTim Harvey 		io_write16(sd, REG_PXCNT_PR, 1);
7909ac0038dSTim Harvey 	io_write16(sd, REG_PXCNT_NPIX, width & MASK_VHREF);
7919ac0038dSTim Harvey 	io_write16(sd, REG_LCNT_PR, 1);
7929ac0038dSTim Harvey 	io_write16(sd, REG_LCNT_NLIN, lines & MASK_VHREF);
7939ac0038dSTim Harvey 
7949ac0038dSTim Harvey 	/*
7959ac0038dSTim Harvey 	 * Configure the VHRef timing generator responsible for rebuilding all
7969ac0038dSTim Harvey 	 * horiz and vert synch and ref signals from its input allowing auto
7979ac0038dSTim Harvey 	 * detection algorithms and forcing predefined modes (480i & 576i)
7989ac0038dSTim Harvey 	 */
7999ac0038dSTim Harvey 	reg = VHREF_STD_DET_OFF << VHREF_STD_DET_SHIFT;
8009ac0038dSTim Harvey 	io_write(sd, REG_VHREF_CTRL, reg);
8019ac0038dSTim Harvey 
8029ac0038dSTim Harvey 	/*
8039ac0038dSTim Harvey 	 * Configure the VHRef timing values. In case the VHREF generator has
8049ac0038dSTim Harvey 	 * been configured in manual mode, this will allow to manually set all
8059ac0038dSTim Harvey 	 * horiz and vert ref values (non-active pixel areas) of the generator
8069ac0038dSTim Harvey 	 * and allows setting the frame reference params.
8079ac0038dSTim Harvey 	 */
8089ac0038dSTim Harvey 	/* horizontal reference start/end */
8099ac0038dSTim Harvey 	io_write16(sd, REG_HREF_S, href_start & MASK_VHREF);
8109ac0038dSTim Harvey 	io_write16(sd, REG_HREF_E, href_end & MASK_VHREF);
8119ac0038dSTim Harvey 	/* vertical reference f1 start/end */
8129ac0038dSTim Harvey 	io_write16(sd, REG_VREF_F1_S, vref_f1_start & MASK_VHREF);
8139ac0038dSTim Harvey 	io_write(sd, REG_VREF_F1_WIDTH, vref_f1_width);
8149ac0038dSTim Harvey 	/* vertical reference f2 start/end */
8159ac0038dSTim Harvey 	io_write16(sd, REG_VREF_F2_S, vref_f2_start & MASK_VHREF);
8169ac0038dSTim Harvey 	io_write(sd, REG_VREF_F2_WIDTH, vref_f2_width);
8179ac0038dSTim Harvey 
8189ac0038dSTim Harvey 	/* F1/F2 FREF, field polarity */
8199ac0038dSTim Harvey 	reg = fieldref_f1_start & MASK_VHREF;
8209ac0038dSTim Harvey 	reg |= field_polarity << 8;
8219ac0038dSTim Harvey 	io_write16(sd, REG_FREF_F1_S, reg);
8229ac0038dSTim Harvey 	reg = fieldref_f2_start & MASK_VHREF;
8239ac0038dSTim Harvey 	io_write16(sd, REG_FREF_F2_S, reg);
8249ac0038dSTim Harvey }
8259ac0038dSTim Harvey 
8269ac0038dSTim Harvey /* Configure Video Output port signals */
8279ac0038dSTim Harvey static int
tda1997x_configure_vidout(struct tda1997x_state * state)8289ac0038dSTim Harvey tda1997x_configure_vidout(struct tda1997x_state *state)
8299ac0038dSTim Harvey {
8309ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
8319ac0038dSTim Harvey 	struct tda1997x_platform_data *pdata = &state->pdata;
8329ac0038dSTim Harvey 	u8 prefilter;
8339ac0038dSTim Harvey 	u8 reg;
8349ac0038dSTim Harvey 
8359ac0038dSTim Harvey 	/* Configure pixel clock generator: delay, polarity, rate */
8369ac0038dSTim Harvey 	reg = (state->vid_fmt == OF_FMT_422_CCIR) ?
8379ac0038dSTim Harvey 	       PCLK_SEL_X2 : PCLK_SEL_X1;
8389ac0038dSTim Harvey 	reg |= pdata->vidout_delay_pclk << PCLK_DELAY_SHIFT;
8399ac0038dSTim Harvey 	reg |= pdata->vidout_inv_pclk << PCLK_INV_SHIFT;
8409ac0038dSTim Harvey 	io_write(sd, REG_PCLK, reg);
8419ac0038dSTim Harvey 
8429ac0038dSTim Harvey 	/* Configure pre-filter */
8439ac0038dSTim Harvey 	prefilter = 0; /* filters off */
8449ac0038dSTim Harvey 	/* YUV422 mode requires conversion */
8459ac0038dSTim Harvey 	if ((state->vid_fmt == OF_FMT_422_SMPT) ||
8469ac0038dSTim Harvey 	    (state->vid_fmt == OF_FMT_422_CCIR)) {
8479ac0038dSTim Harvey 		/* 2/7 taps for Rv and Bu */
8489ac0038dSTim Harvey 		prefilter = FILTERS_CTRL_2_7TAP << FILTERS_CTRL_BU_SHIFT |
8499ac0038dSTim Harvey 			    FILTERS_CTRL_2_7TAP << FILTERS_CTRL_RV_SHIFT;
8509ac0038dSTim Harvey 	}
8519ac0038dSTim Harvey 	io_write(sd, REG_FILTERS_CTRL, prefilter);
8529ac0038dSTim Harvey 
8539ac0038dSTim Harvey 	/* Configure video port */
8549ac0038dSTim Harvey 	reg = state->vid_fmt & OF_FMT_MASK;
8559ac0038dSTim Harvey 	if (state->vid_fmt == OF_FMT_422_CCIR)
8569ac0038dSTim Harvey 		reg |= (OF_BLK | OF_TRC);
8579ac0038dSTim Harvey 	reg |= OF_VP_ENABLE;
8589ac0038dSTim Harvey 	io_write(sd, REG_OF, reg);
8599ac0038dSTim Harvey 
8609ac0038dSTim Harvey 	/* Configure formatter and conversions */
8619ac0038dSTim Harvey 	reg = io_read(sd, REG_VDP_CTRL);
8629ac0038dSTim Harvey 	/* pre-filter is needed unless (REG_FILTERS_CTRL == 0) */
8639ac0038dSTim Harvey 	if (!prefilter)
8649ac0038dSTim Harvey 		reg |= VDP_CTRL_PREFILTER_BP;
8659ac0038dSTim Harvey 	else
8669ac0038dSTim Harvey 		reg &= ~VDP_CTRL_PREFILTER_BP;
8679ac0038dSTim Harvey 	/* formatter is needed for YUV422 and for trc/blc codes */
8689ac0038dSTim Harvey 	if (state->vid_fmt == OF_FMT_444)
8699ac0038dSTim Harvey 		reg |= VDP_CTRL_FORMATTER_BP;
8709ac0038dSTim Harvey 	/* formatter and compdel needed for timing/blanking codes */
8719ac0038dSTim Harvey 	else
8729ac0038dSTim Harvey 		reg &= ~(VDP_CTRL_FORMATTER_BP | VDP_CTRL_COMPDEL_BP);
8739ac0038dSTim Harvey 	/* activate compdel for small sync delays */
8749ac0038dSTim Harvey 	if ((pdata->vidout_delay_vs < 4) || (pdata->vidout_delay_hs < 4))
8759ac0038dSTim Harvey 		reg &= ~VDP_CTRL_COMPDEL_BP;
8769ac0038dSTim Harvey 	io_write(sd, REG_VDP_CTRL, reg);
8779ac0038dSTim Harvey 
8789ac0038dSTim Harvey 	/* Configure DE output signal: delay, polarity, and source */
8799ac0038dSTim Harvey 	reg = pdata->vidout_delay_de << DE_FREF_DELAY_SHIFT |
8809ac0038dSTim Harvey 	      pdata->vidout_inv_de << DE_FREF_INV_SHIFT |
8819ac0038dSTim Harvey 	      pdata->vidout_sel_de << DE_FREF_SEL_SHIFT;
8829ac0038dSTim Harvey 	io_write(sd, REG_DE_FREF, reg);
8839ac0038dSTim Harvey 
8849ac0038dSTim Harvey 	/* Configure HS/HREF output signal: delay, polarity, and source */
8859ac0038dSTim Harvey 	if (state->vid_fmt != OF_FMT_422_CCIR) {
8869ac0038dSTim Harvey 		reg = pdata->vidout_delay_hs << HS_HREF_DELAY_SHIFT |
8879ac0038dSTim Harvey 		      pdata->vidout_inv_hs << HS_HREF_INV_SHIFT |
8889ac0038dSTim Harvey 		      pdata->vidout_sel_hs << HS_HREF_SEL_SHIFT;
8899ac0038dSTim Harvey 	} else
8909ac0038dSTim Harvey 		reg = HS_HREF_SEL_NONE << HS_HREF_SEL_SHIFT;
8919ac0038dSTim Harvey 	io_write(sd, REG_HS_HREF, reg);
8929ac0038dSTim Harvey 
8939ac0038dSTim Harvey 	/* Configure VS/VREF output signal: delay, polarity, and source */
8949ac0038dSTim Harvey 	if (state->vid_fmt != OF_FMT_422_CCIR) {
8959ac0038dSTim Harvey 		reg = pdata->vidout_delay_vs << VS_VREF_DELAY_SHIFT |
8969ac0038dSTim Harvey 		      pdata->vidout_inv_vs << VS_VREF_INV_SHIFT |
8979ac0038dSTim Harvey 		      pdata->vidout_sel_vs << VS_VREF_SEL_SHIFT;
8989ac0038dSTim Harvey 	} else
8999ac0038dSTim Harvey 		reg = VS_VREF_SEL_NONE << VS_VREF_SEL_SHIFT;
9009ac0038dSTim Harvey 	io_write(sd, REG_VS_VREF, reg);
9019ac0038dSTim Harvey 
9029ac0038dSTim Harvey 	return 0;
9039ac0038dSTim Harvey }
9049ac0038dSTim Harvey 
9059ac0038dSTim Harvey /* Configure Audio output port signals */
9069ac0038dSTim Harvey static int
tda1997x_configure_audout(struct v4l2_subdev * sd,u8 channel_assignment)9079ac0038dSTim Harvey tda1997x_configure_audout(struct v4l2_subdev *sd, u8 channel_assignment)
9089ac0038dSTim Harvey {
9099ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
9109ac0038dSTim Harvey 	struct tda1997x_platform_data *pdata = &state->pdata;
91108091fc1SDaniel W. S. Almeida 	bool sp_used_by_fifo = true;
9129ac0038dSTim Harvey 	u8 reg;
9139ac0038dSTim Harvey 
9149ac0038dSTim Harvey 	if (!pdata->audout_format)
9159ac0038dSTim Harvey 		return 0;
9169ac0038dSTim Harvey 
9179ac0038dSTim Harvey 	/* channel assignment (CEA-861-D Table 20) */
9189ac0038dSTim Harvey 	io_write(sd, REG_AUDIO_PATH, channel_assignment);
9199ac0038dSTim Harvey 
9209ac0038dSTim Harvey 	/* Audio output configuration */
9219ac0038dSTim Harvey 	reg = 0;
9229ac0038dSTim Harvey 	switch (pdata->audout_format) {
9239ac0038dSTim Harvey 	case AUDFMT_TYPE_I2S:
9249ac0038dSTim Harvey 		reg |= AUDCFG_BUS_I2S << AUDCFG_BUS_SHIFT;
9259ac0038dSTim Harvey 		break;
9269ac0038dSTim Harvey 	case AUDFMT_TYPE_SPDIF:
9279ac0038dSTim Harvey 		reg |= AUDCFG_BUS_SPDIF << AUDCFG_BUS_SHIFT;
9289ac0038dSTim Harvey 		break;
9299ac0038dSTim Harvey 	}
9309ac0038dSTim Harvey 	switch (state->audio_type) {
9319ac0038dSTim Harvey 	case AUDCFG_TYPE_PCM:
9329ac0038dSTim Harvey 		reg |= AUDCFG_TYPE_PCM << AUDCFG_TYPE_SHIFT;
9339ac0038dSTim Harvey 		break;
9349ac0038dSTim Harvey 	case AUDCFG_TYPE_OBA:
9359ac0038dSTim Harvey 		reg |= AUDCFG_TYPE_OBA << AUDCFG_TYPE_SHIFT;
9369ac0038dSTim Harvey 		break;
9379ac0038dSTim Harvey 	case AUDCFG_TYPE_DST:
9389ac0038dSTim Harvey 		reg |= AUDCFG_TYPE_DST << AUDCFG_TYPE_SHIFT;
93908091fc1SDaniel W. S. Almeida 		sp_used_by_fifo = false;
9409ac0038dSTim Harvey 		break;
9419ac0038dSTim Harvey 	case AUDCFG_TYPE_HBR:
9429ac0038dSTim Harvey 		reg |= AUDCFG_TYPE_HBR << AUDCFG_TYPE_SHIFT;
9439ac0038dSTim Harvey 		if (pdata->audout_layout == 1) {
9449ac0038dSTim Harvey 			/* demuxed via AP0:AP3 */
9459ac0038dSTim Harvey 			reg |= AUDCFG_HBR_DEMUX << AUDCFG_HBR_SHIFT;
9469ac0038dSTim Harvey 			if (pdata->audout_format == AUDFMT_TYPE_SPDIF)
94708091fc1SDaniel W. S. Almeida 				sp_used_by_fifo = false;
9489ac0038dSTim Harvey 		} else {
9499ac0038dSTim Harvey 			/* straight via AP0 */
9509ac0038dSTim Harvey 			reg |= AUDCFG_HBR_STRAIGHT << AUDCFG_HBR_SHIFT;
9519ac0038dSTim Harvey 		}
9529ac0038dSTim Harvey 		break;
9539ac0038dSTim Harvey 	}
9549ac0038dSTim Harvey 	if (pdata->audout_width == 32)
9559ac0038dSTim Harvey 		reg |= AUDCFG_I2SW_32 << AUDCFG_I2SW_SHIFT;
9569ac0038dSTim Harvey 	else
9579ac0038dSTim Harvey 		reg |= AUDCFG_I2SW_16 << AUDCFG_I2SW_SHIFT;
9589ac0038dSTim Harvey 
9599ac0038dSTim Harvey 	/* automatic hardware mute */
9609ac0038dSTim Harvey 	if (pdata->audio_auto_mute)
9619ac0038dSTim Harvey 		reg |= AUDCFG_AUTO_MUTE_EN;
9629ac0038dSTim Harvey 	/* clock polarity */
9639ac0038dSTim Harvey 	if (pdata->audout_invert_clk)
9649ac0038dSTim Harvey 		reg |= AUDCFG_CLK_INVERT;
9659ac0038dSTim Harvey 	io_write(sd, REG_AUDCFG, reg);
9669ac0038dSTim Harvey 
9679ac0038dSTim Harvey 	/* audio layout */
9689ac0038dSTim Harvey 	reg = (pdata->audout_layout) ? AUDIO_LAYOUT_LAYOUT1 : 0;
9699ac0038dSTim Harvey 	if (!pdata->audout_layoutauto)
9709ac0038dSTim Harvey 		reg |= AUDIO_LAYOUT_MANUAL;
9719ac0038dSTim Harvey 	if (sp_used_by_fifo)
9729ac0038dSTim Harvey 		reg |= AUDIO_LAYOUT_SP_FLAG;
9739ac0038dSTim Harvey 	io_write(sd, REG_AUDIO_LAYOUT, reg);
9749ac0038dSTim Harvey 
9759ac0038dSTim Harvey 	/* FIFO Latency value */
9769ac0038dSTim Harvey 	io_write(sd, REG_FIFO_LATENCY_VAL, 0x80);
9779ac0038dSTim Harvey 
9789ac0038dSTim Harvey 	/* Audio output port config */
9799ac0038dSTim Harvey 	if (sp_used_by_fifo) {
9809ac0038dSTim Harvey 		reg = AUDIO_OUT_ENABLE_AP0;
9819ac0038dSTim Harvey 		if (channel_assignment >= 0x01)
9829ac0038dSTim Harvey 			reg |= AUDIO_OUT_ENABLE_AP1;
9839ac0038dSTim Harvey 		if (channel_assignment >= 0x04)
9849ac0038dSTim Harvey 			reg |= AUDIO_OUT_ENABLE_AP2;
9859ac0038dSTim Harvey 		if (channel_assignment >= 0x0c)
9869ac0038dSTim Harvey 			reg |= AUDIO_OUT_ENABLE_AP3;
9879ac0038dSTim Harvey 		/* specific cases where AP1 is not used */
9889ac0038dSTim Harvey 		if ((channel_assignment == 0x04)
9899ac0038dSTim Harvey 		 || (channel_assignment == 0x08)
9909ac0038dSTim Harvey 		 || (channel_assignment == 0x0c)
9919ac0038dSTim Harvey 		 || (channel_assignment == 0x10)
9929ac0038dSTim Harvey 		 || (channel_assignment == 0x14)
9939ac0038dSTim Harvey 		 || (channel_assignment == 0x18)
9949ac0038dSTim Harvey 		 || (channel_assignment == 0x1c))
9959ac0038dSTim Harvey 			reg &= ~AUDIO_OUT_ENABLE_AP1;
9969ac0038dSTim Harvey 		/* specific cases where AP2 is not used */
9979ac0038dSTim Harvey 		if ((channel_assignment >= 0x14)
9989ac0038dSTim Harvey 		 && (channel_assignment <= 0x17))
9999ac0038dSTim Harvey 			reg &= ~AUDIO_OUT_ENABLE_AP2;
10009ac0038dSTim Harvey 	} else {
10019ac0038dSTim Harvey 		reg = AUDIO_OUT_ENABLE_AP3 |
10029ac0038dSTim Harvey 		      AUDIO_OUT_ENABLE_AP2 |
10039ac0038dSTim Harvey 		      AUDIO_OUT_ENABLE_AP1 |
10049ac0038dSTim Harvey 		      AUDIO_OUT_ENABLE_AP0;
10059ac0038dSTim Harvey 	}
10069ac0038dSTim Harvey 	if (pdata->audout_format == AUDFMT_TYPE_I2S)
10079ac0038dSTim Harvey 		reg |= (AUDIO_OUT_ENABLE_ACLK | AUDIO_OUT_ENABLE_WS);
10089ac0038dSTim Harvey 	io_write(sd, REG_AUDIO_OUT_ENABLE, reg);
10099ac0038dSTim Harvey 
10109ac0038dSTim Harvey 	/* reset test mode to normal audio freq auto selection */
10119ac0038dSTim Harvey 	io_write(sd, REG_TEST_MODE, 0x00);
10129ac0038dSTim Harvey 
10139ac0038dSTim Harvey 	return 0;
10149ac0038dSTim Harvey }
10159ac0038dSTim Harvey 
10169ac0038dSTim Harvey /* Soft Reset of specific hdmi info */
10179ac0038dSTim Harvey static int
tda1997x_hdmi_info_reset(struct v4l2_subdev * sd,u8 info_rst,bool reset_sus)10189ac0038dSTim Harvey tda1997x_hdmi_info_reset(struct v4l2_subdev *sd, u8 info_rst, bool reset_sus)
10199ac0038dSTim Harvey {
10209ac0038dSTim Harvey 	u8 reg;
10219ac0038dSTim Harvey 
10229ac0038dSTim Harvey 	/* reset infoframe engine packets */
10239ac0038dSTim Harvey 	reg = io_read(sd, REG_HDMI_INFO_RST);
10249ac0038dSTim Harvey 	io_write(sd, REG_HDMI_INFO_RST, info_rst);
10259ac0038dSTim Harvey 
10269ac0038dSTim Harvey 	/* if infoframe engine has been reset clear INT_FLG_MODE */
10279ac0038dSTim Harvey 	if (reg & RESET_IF) {
10289ac0038dSTim Harvey 		reg = io_read(sd, REG_INT_FLG_CLR_MODE);
10299ac0038dSTim Harvey 		io_write(sd, REG_INT_FLG_CLR_MODE, reg);
10309ac0038dSTim Harvey 	}
10319ac0038dSTim Harvey 
10329ac0038dSTim Harvey 	/* Disable REFTIM to restart start-up-sequencer (SUS) */
10339ac0038dSTim Harvey 	reg = io_read(sd, REG_RATE_CTRL);
10349ac0038dSTim Harvey 	reg &= ~RATE_REFTIM_ENABLE;
10359ac0038dSTim Harvey 	if (!reset_sus)
10369ac0038dSTim Harvey 		reg |= RATE_REFTIM_ENABLE;
10379ac0038dSTim Harvey 	reg = io_write(sd, REG_RATE_CTRL, reg);
10389ac0038dSTim Harvey 
10399ac0038dSTim Harvey 	return 0;
10409ac0038dSTim Harvey }
10419ac0038dSTim Harvey 
10429ac0038dSTim Harvey static void
tda1997x_power_mode(struct tda1997x_state * state,bool enable)10439ac0038dSTim Harvey tda1997x_power_mode(struct tda1997x_state *state, bool enable)
10449ac0038dSTim Harvey {
10459ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
10469ac0038dSTim Harvey 	u8 reg;
10479ac0038dSTim Harvey 
10489ac0038dSTim Harvey 	if (enable) {
10499ac0038dSTim Harvey 		/* Automatic control of TMDS */
10509ac0038dSTim Harvey 		io_write(sd, REG_PON_OVR_EN, PON_DIS);
10519ac0038dSTim Harvey 		/* Enable current bias unit */
10529ac0038dSTim Harvey 		io_write(sd, REG_CFG1, PON_EN);
10539ac0038dSTim Harvey 		/* Enable deep color PLL */
10549ac0038dSTim Harvey 		io_write(sd, REG_DEEP_PLL7_BYP, PON_DIS);
10559ac0038dSTim Harvey 		/* Output buffers active */
10569ac0038dSTim Harvey 		reg = io_read(sd, REG_OF);
10579ac0038dSTim Harvey 		reg &= ~OF_VP_ENABLE;
10589ac0038dSTim Harvey 		io_write(sd, REG_OF, reg);
10599ac0038dSTim Harvey 	} else {
10609ac0038dSTim Harvey 		/* Power down EDID mode sequence */
10619ac0038dSTim Harvey 		/* Output buffers in HiZ */
10629ac0038dSTim Harvey 		reg = io_read(sd, REG_OF);
10639ac0038dSTim Harvey 		reg |= OF_VP_ENABLE;
10649ac0038dSTim Harvey 		io_write(sd, REG_OF, reg);
10659ac0038dSTim Harvey 		/* Disable deep color PLL */
10669ac0038dSTim Harvey 		io_write(sd, REG_DEEP_PLL7_BYP, PON_EN);
10679ac0038dSTim Harvey 		/* Disable current bias unit */
10689ac0038dSTim Harvey 		io_write(sd, REG_CFG1, PON_DIS);
10699ac0038dSTim Harvey 		/* Manual control of TMDS */
10709ac0038dSTim Harvey 		io_write(sd, REG_PON_OVR_EN, PON_EN);
10719ac0038dSTim Harvey 	}
10729ac0038dSTim Harvey }
10739ac0038dSTim Harvey 
10749ac0038dSTim Harvey static bool
tda1997x_detect_tx_5v(struct v4l2_subdev * sd)10759ac0038dSTim Harvey tda1997x_detect_tx_5v(struct v4l2_subdev *sd)
10769ac0038dSTim Harvey {
10779ac0038dSTim Harvey 	u8 reg = io_read(sd, REG_DETECT_5V);
10789ac0038dSTim Harvey 
10799ac0038dSTim Harvey 	return ((reg & DETECT_5V_SEL) ? 1 : 0);
10809ac0038dSTim Harvey }
10819ac0038dSTim Harvey 
10829ac0038dSTim Harvey static bool
tda1997x_detect_tx_hpd(struct v4l2_subdev * sd)10839ac0038dSTim Harvey tda1997x_detect_tx_hpd(struct v4l2_subdev *sd)
10849ac0038dSTim Harvey {
10859ac0038dSTim Harvey 	u8 reg = io_read(sd, REG_DETECT_5V);
10869ac0038dSTim Harvey 
10879ac0038dSTim Harvey 	return ((reg & DETECT_HPD) ? 1 : 0);
10889ac0038dSTim Harvey }
10899ac0038dSTim Harvey 
10909ac0038dSTim Harvey static int
tda1997x_detect_std(struct tda1997x_state * state,struct v4l2_dv_timings * timings)10919ac0038dSTim Harvey tda1997x_detect_std(struct tda1997x_state *state,
10929ac0038dSTim Harvey 		    struct v4l2_dv_timings *timings)
10939ac0038dSTim Harvey {
10949ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
10959ac0038dSTim Harvey 
10969ac0038dSTim Harvey 	/*
10979ac0038dSTim Harvey 	 * Read the FMT registers
1098d64a7709SKrzysztof Hałasa 	 *   REG_V_PER: Period of a frame (or field) in MCLK (27MHz) cycles
10999ac0038dSTim Harvey 	 *   REG_H_PER: Period of a line in MCLK (27MHz) cycles
11009ac0038dSTim Harvey 	 *   REG_HS_WIDTH: Period of horiz sync pulse in MCLK (27MHz) cycles
11019ac0038dSTim Harvey 	 */
1102d64a7709SKrzysztof Hałasa 	u32 vper, vsync_pos;
1103d64a7709SKrzysztof Hałasa 	u16 hper, hsync_pos, hsper, interlaced;
1104d64a7709SKrzysztof Hałasa 	u16 htot, hact, hfront, hsync, hback;
1105d64a7709SKrzysztof Hałasa 	u16 vtot, vact, vfront1, vfront2, vsync, vback1, vback2;
11065cdd19bbSKrzysztof Hałasa 
11075cdd19bbSKrzysztof Hałasa 	if (!state->input_detect[0] && !state->input_detect[1])
11089ac0038dSTim Harvey 		return -ENOLINK;
11099ac0038dSTim Harvey 
1110d64a7709SKrzysztof Hałasa 	vper = io_read24(sd, REG_V_PER);
1111d64a7709SKrzysztof Hałasa 	hper = io_read16(sd, REG_H_PER);
1112d64a7709SKrzysztof Hałasa 	hsper = io_read16(sd, REG_HS_WIDTH);
1113d64a7709SKrzysztof Hałasa 	vsync_pos = vper & MASK_VPER_SYNC_POS;
1114d64a7709SKrzysztof Hałasa 	hsync_pos = hper & MASK_HPER_SYNC_POS;
1115d64a7709SKrzysztof Hałasa 	interlaced = hsper & MASK_HSWIDTH_INTERLACED;
1116d64a7709SKrzysztof Hałasa 	vper &= MASK_VPER;
1117d64a7709SKrzysztof Hałasa 	hper &= MASK_HPER;
1118d64a7709SKrzysztof Hałasa 	hsper &= MASK_HSWIDTH;
1119d64a7709SKrzysztof Hałasa 	v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper);
11209ac0038dSTim Harvey 
1121d64a7709SKrzysztof Hałasa 	htot = io_read16(sd, REG_FMT_H_TOT);
1122d64a7709SKrzysztof Hałasa 	hact = io_read16(sd, REG_FMT_H_ACT);
1123d64a7709SKrzysztof Hałasa 	hfront = io_read16(sd, REG_FMT_H_FRONT);
1124d64a7709SKrzysztof Hałasa 	hsync = io_read16(sd, REG_FMT_H_SYNC);
1125d64a7709SKrzysztof Hałasa 	hback = io_read16(sd, REG_FMT_H_BACK);
11269ac0038dSTim Harvey 
1127d64a7709SKrzysztof Hałasa 	vtot = io_read16(sd, REG_FMT_V_TOT);
1128d64a7709SKrzysztof Hałasa 	vact = io_read16(sd, REG_FMT_V_ACT);
1129d64a7709SKrzysztof Hałasa 	vfront1 = io_read(sd, REG_FMT_V_FRONT_F1);
1130d64a7709SKrzysztof Hałasa 	vfront2 = io_read(sd, REG_FMT_V_FRONT_F2);
1131d64a7709SKrzysztof Hałasa 	vsync = io_read(sd, REG_FMT_V_SYNC);
1132d64a7709SKrzysztof Hałasa 	vback1 = io_read(sd, REG_FMT_V_BACK_F1);
1133d64a7709SKrzysztof Hałasa 	vback2 = io_read(sd, REG_FMT_V_BACK_F2);
1134d64a7709SKrzysztof Hałasa 
1135d64a7709SKrzysztof Hałasa 	v4l2_dbg(1, debug, sd, "Geometry: H %u %u %u %u %u Sync%c  V %u %u %u %u %u %u %u Sync%c\n",
1136d64a7709SKrzysztof Hałasa 		 htot, hact, hfront, hsync, hback, hsync_pos ? '+' : '-',
1137d64a7709SKrzysztof Hałasa 		 vtot, vact, vfront1, vfront2, vsync, vback1, vback2, vsync_pos ? '+' : '-');
1138d64a7709SKrzysztof Hałasa 
1139d64a7709SKrzysztof Hałasa 	if (!timings)
11409ac0038dSTim Harvey 		return 0;
11419ac0038dSTim Harvey 
1142d64a7709SKrzysztof Hałasa 	timings->type = V4L2_DV_BT_656_1120;
1143d64a7709SKrzysztof Hałasa 	timings->bt.width = hact;
1144d64a7709SKrzysztof Hałasa 	timings->bt.hfrontporch = hfront;
1145d64a7709SKrzysztof Hałasa 	timings->bt.hsync = hsync;
1146d64a7709SKrzysztof Hałasa 	timings->bt.hbackporch = hback;
1147d64a7709SKrzysztof Hałasa 	timings->bt.height = vact;
1148d64a7709SKrzysztof Hałasa 	timings->bt.vfrontporch = vfront1;
1149d64a7709SKrzysztof Hałasa 	timings->bt.vsync = vsync;
1150d64a7709SKrzysztof Hałasa 	timings->bt.vbackporch = vback1;
1151d64a7709SKrzysztof Hałasa 	timings->bt.interlaced = interlaced ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
1152d64a7709SKrzysztof Hałasa 	timings->bt.polarities = vsync_pos ? V4L2_DV_VSYNC_POS_POL : 0;
1153d64a7709SKrzysztof Hałasa 	timings->bt.polarities |= hsync_pos ? V4L2_DV_HSYNC_POS_POL : 0;
1154d64a7709SKrzysztof Hałasa 
1155d64a7709SKrzysztof Hałasa 	timings->bt.pixelclock = (u64)htot * vtot * 27000000;
1156d64a7709SKrzysztof Hałasa 	if (interlaced) {
1157d64a7709SKrzysztof Hałasa 		timings->bt.il_vfrontporch = vfront2;
1158d64a7709SKrzysztof Hałasa 		timings->bt.il_vsync = timings->bt.vsync;
1159d64a7709SKrzysztof Hałasa 		timings->bt.il_vbackporch = vback2;
1160d64a7709SKrzysztof Hałasa 		do_div(timings->bt.pixelclock, vper * 2 /* full frame */);
1161d64a7709SKrzysztof Hałasa 	} else {
1162d64a7709SKrzysztof Hałasa 		timings->bt.il_vfrontporch = 0;
1163d64a7709SKrzysztof Hałasa 		timings->bt.il_vsync = 0;
1164d64a7709SKrzysztof Hałasa 		timings->bt.il_vbackporch = 0;
1165d64a7709SKrzysztof Hałasa 		do_div(timings->bt.pixelclock, vper);
1166d64a7709SKrzysztof Hałasa 	}
1167d64a7709SKrzysztof Hałasa 	v4l2_find_dv_timings_cap(timings, &tda1997x_dv_timings_cap,
1168d64a7709SKrzysztof Hałasa 				 (u32)timings->bt.pixelclock / 500, NULL, NULL);
1169d64a7709SKrzysztof Hałasa 	v4l2_print_dv_timings(sd->name, "Detected format: ", timings, false);
1170d64a7709SKrzysztof Hałasa 	return 0;
11719ac0038dSTim Harvey }
11729ac0038dSTim Harvey 
11739ac0038dSTim Harvey /* some sort of errata workaround for chip revision 0 (N1) */
tda1997x_reset_n1(struct tda1997x_state * state)11749ac0038dSTim Harvey static void tda1997x_reset_n1(struct tda1997x_state *state)
11759ac0038dSTim Harvey {
11769ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
11779ac0038dSTim Harvey 	u8 reg;
11789ac0038dSTim Harvey 
11799ac0038dSTim Harvey 	/* clear HDMI mode flag in BCAPS */
11809ac0038dSTim Harvey 	io_write(sd, REG_CLK_CFG, CLK_CFG_SEL_ACLK_EN | CLK_CFG_SEL_ACLK);
11819ac0038dSTim Harvey 	io_write(sd, REG_PON_OVR_EN, PON_EN);
11829ac0038dSTim Harvey 	io_write(sd, REG_PON_CBIAS, PON_EN);
11839ac0038dSTim Harvey 	io_write(sd, REG_PON_PLL, PON_EN);
11849ac0038dSTim Harvey 
11859ac0038dSTim Harvey 	reg = io_read(sd, REG_MODE_REC_CFG1);
11869ac0038dSTim Harvey 	reg &= ~0x06;
11879ac0038dSTim Harvey 	reg |= 0x02;
11889ac0038dSTim Harvey 	io_write(sd, REG_MODE_REC_CFG1, reg);
11899ac0038dSTim Harvey 	io_write(sd, REG_CLK_CFG, CLK_CFG_DIS);
11909ac0038dSTim Harvey 	io_write(sd, REG_PON_OVR_EN, PON_DIS);
11919ac0038dSTim Harvey 	reg = io_read(sd, REG_MODE_REC_CFG1);
11929ac0038dSTim Harvey 	reg &= ~0x06;
11939ac0038dSTim Harvey 	io_write(sd, REG_MODE_REC_CFG1, reg);
11949ac0038dSTim Harvey }
11959ac0038dSTim Harvey 
11969ac0038dSTim Harvey /*
11979ac0038dSTim Harvey  * Activity detection must only be notified when stable_clk_x AND active_x
11989ac0038dSTim Harvey  * bits are set to 1. If only stable_clk_x bit is set to 1 but not
11999ac0038dSTim Harvey  * active_x, it means that the TMDS clock is not in the defined range
12009ac0038dSTim Harvey  * and activity detection must not be notified.
12019ac0038dSTim Harvey  */
12029ac0038dSTim Harvey static u8
tda1997x_read_activity_status_regs(struct v4l2_subdev * sd)12039ac0038dSTim Harvey tda1997x_read_activity_status_regs(struct v4l2_subdev *sd)
12049ac0038dSTim Harvey {
12059ac0038dSTim Harvey 	u8 reg, status = 0;
12069ac0038dSTim Harvey 
12079ac0038dSTim Harvey 	/* Read CLK_A_STATUS register */
12089ac0038dSTim Harvey 	reg = io_read(sd, REG_CLK_A_STATUS);
12099ac0038dSTim Harvey 	/* ignore if not active */
12109ac0038dSTim Harvey 	if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE))
12119ac0038dSTim Harvey 		reg &= ~MASK_CLK_STABLE;
12129ac0038dSTim Harvey 	status |= ((reg & MASK_CLK_STABLE) >> 2);
12139ac0038dSTim Harvey 
12149ac0038dSTim Harvey 	/* Read CLK_B_STATUS register */
12159ac0038dSTim Harvey 	reg = io_read(sd, REG_CLK_B_STATUS);
12169ac0038dSTim Harvey 	/* ignore if not active */
12179ac0038dSTim Harvey 	if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE))
12189ac0038dSTim Harvey 		reg &= ~MASK_CLK_STABLE;
12199ac0038dSTim Harvey 	status |= ((reg & MASK_CLK_STABLE) >> 1);
12209ac0038dSTim Harvey 
12219ac0038dSTim Harvey 	/* Read the SUS_STATUS register */
12229ac0038dSTim Harvey 	reg = io_read(sd, REG_SUS_STATUS);
12239ac0038dSTim Harvey 
12249ac0038dSTim Harvey 	/* If state = 5 => TMDS is locked */
12259ac0038dSTim Harvey 	if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED)
12269ac0038dSTim Harvey 		status |= MASK_SUS_STATE;
12279ac0038dSTim Harvey 	else
12289ac0038dSTim Harvey 		status &= ~MASK_SUS_STATE;
12299ac0038dSTim Harvey 
12309ac0038dSTim Harvey 	return status;
12319ac0038dSTim Harvey }
12329ac0038dSTim Harvey 
12339ac0038dSTim Harvey static void
set_rgb_quantization_range(struct tda1997x_state * state)12349ac0038dSTim Harvey set_rgb_quantization_range(struct tda1997x_state *state)
12359ac0038dSTim Harvey {
12369ac0038dSTim Harvey 	struct v4l2_hdmi_colorimetry *c = &state->colorimetry;
12379ac0038dSTim Harvey 
12389ac0038dSTim Harvey 	state->colorimetry = v4l2_hdmi_rx_colorimetry(&state->avi_infoframe,
12399ac0038dSTim Harvey 						      NULL,
12409ac0038dSTim Harvey 						      state->timings.bt.height);
12419ac0038dSTim Harvey 	/* If ycbcr_enc is V4L2_YCBCR_ENC_DEFAULT, we receive RGB */
12429ac0038dSTim Harvey 	if (c->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
12439ac0038dSTim Harvey 		switch (state->rgb_quantization_range) {
12449ac0038dSTim Harvey 		case V4L2_DV_RGB_RANGE_LIMITED:
12459ac0038dSTim Harvey 			c->quantization = V4L2_QUANTIZATION_FULL_RANGE;
12469ac0038dSTim Harvey 			break;
12479ac0038dSTim Harvey 		case V4L2_DV_RGB_RANGE_FULL:
12489ac0038dSTim Harvey 			c->quantization = V4L2_QUANTIZATION_LIM_RANGE;
12499ac0038dSTim Harvey 			break;
12509ac0038dSTim Harvey 		}
12519ac0038dSTim Harvey 	}
12529ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client,
12539ac0038dSTim Harvey 		"colorspace=%d/%d colorimetry=%d range=%s content=%d\n",
12549ac0038dSTim Harvey 		state->avi_infoframe.colorspace, c->colorspace,
12559ac0038dSTim Harvey 		state->avi_infoframe.colorimetry,
12569ac0038dSTim Harvey 		v4l2_quantization_names[c->quantization],
12579ac0038dSTim Harvey 		state->avi_infoframe.content_type);
12589ac0038dSTim Harvey }
12599ac0038dSTim Harvey 
12609ac0038dSTim Harvey /* parse an infoframe and do some sanity checks on it */
12619ac0038dSTim Harvey static unsigned int
tda1997x_parse_infoframe(struct tda1997x_state * state,u16 addr)12629ac0038dSTim Harvey tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
12639ac0038dSTim Harvey {
12649ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
12659ac0038dSTim Harvey 	union hdmi_infoframe frame;
126648d219f9STom Rix 	u8 buffer[40] = { 0 };
12679ac0038dSTim Harvey 	u8 reg;
12689ac0038dSTim Harvey 	int len, err;
12699ac0038dSTim Harvey 
12709ac0038dSTim Harvey 	/* read data */
12719ac0038dSTim Harvey 	len = io_readn(sd, addr, sizeof(buffer), buffer);
127248d219f9STom Rix 	err = hdmi_infoframe_unpack(&frame, buffer, len);
12739ac0038dSTim Harvey 	if (err) {
12749ac0038dSTim Harvey 		v4l_err(state->client,
12759ac0038dSTim Harvey 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
12769ac0038dSTim Harvey 			len, addr, buffer[0]);
12779ac0038dSTim Harvey 		return err;
12789ac0038dSTim Harvey 	}
12799ac0038dSTim Harvey 	hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame);
12809ac0038dSTim Harvey 	switch (frame.any.type) {
12819ac0038dSTim Harvey 	/* Audio InfoFrame: see HDMI spec 8.2.2 */
12829ac0038dSTim Harvey 	case HDMI_INFOFRAME_TYPE_AUDIO:
12839ac0038dSTim Harvey 		/* sample rate */
12849ac0038dSTim Harvey 		switch (frame.audio.sample_frequency) {
12859ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
12869ac0038dSTim Harvey 			state->audio_samplerate = 32000;
12879ac0038dSTim Harvey 			break;
12889ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
12899ac0038dSTim Harvey 			state->audio_samplerate = 44100;
12909ac0038dSTim Harvey 			break;
12919ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
12929ac0038dSTim Harvey 			state->audio_samplerate = 48000;
12939ac0038dSTim Harvey 			break;
12949ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
12959ac0038dSTim Harvey 			state->audio_samplerate = 88200;
12969ac0038dSTim Harvey 			break;
12979ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
12989ac0038dSTim Harvey 			state->audio_samplerate = 96000;
12999ac0038dSTim Harvey 			break;
13009ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
13019ac0038dSTim Harvey 			state->audio_samplerate = 176400;
13029ac0038dSTim Harvey 			break;
13039ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
13049ac0038dSTim Harvey 			state->audio_samplerate = 192000;
13059ac0038dSTim Harvey 			break;
13069ac0038dSTim Harvey 		default:
13079ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
13089ac0038dSTim Harvey 			break;
13099ac0038dSTim Harvey 		}
13109ac0038dSTim Harvey 
13119ac0038dSTim Harvey 		/* sample size */
13129ac0038dSTim Harvey 		switch (frame.audio.sample_size) {
13139ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_SIZE_16:
13149ac0038dSTim Harvey 			state->audio_samplesize = 16;
13159ac0038dSTim Harvey 			break;
13169ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_SIZE_20:
13179ac0038dSTim Harvey 			state->audio_samplesize = 20;
13189ac0038dSTim Harvey 			break;
13199ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_SIZE_24:
13209ac0038dSTim Harvey 			state->audio_samplesize = 24;
13219ac0038dSTim Harvey 			break;
13229ac0038dSTim Harvey 		case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
13239ac0038dSTim Harvey 		default:
13249ac0038dSTim Harvey 			break;
13259ac0038dSTim Harvey 		}
13269ac0038dSTim Harvey 
13279ac0038dSTim Harvey 		/* Channel Count */
13289ac0038dSTim Harvey 		state->audio_channels = frame.audio.channels;
13299ac0038dSTim Harvey 		if (frame.audio.channel_allocation &&
13309ac0038dSTim Harvey 		    frame.audio.channel_allocation != state->audio_ch_alloc) {
13319ac0038dSTim Harvey 			/* use the channel assignment from the infoframe */
13329ac0038dSTim Harvey 			state->audio_ch_alloc = frame.audio.channel_allocation;
13339ac0038dSTim Harvey 			tda1997x_configure_audout(sd, state->audio_ch_alloc);
13349ac0038dSTim Harvey 			/* reset the audio FIFO */
13359ac0038dSTim Harvey 			tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false);
13369ac0038dSTim Harvey 		}
13379ac0038dSTim Harvey 		break;
13389ac0038dSTim Harvey 
13399ac0038dSTim Harvey 	/* Auxiliary Video information (AVI) InfoFrame: see HDMI spec 8.2.1 */
13409ac0038dSTim Harvey 	case HDMI_INFOFRAME_TYPE_AVI:
13419ac0038dSTim Harvey 		state->avi_infoframe = frame.avi;
13429ac0038dSTim Harvey 		set_rgb_quantization_range(state);
13439ac0038dSTim Harvey 
13449ac0038dSTim Harvey 		/* configure upsampler: 0=bypass 1=repeatchroma 2=interpolate */
13459ac0038dSTim Harvey 		reg = io_read(sd, REG_PIX_REPEAT);
13469ac0038dSTim Harvey 		reg &= ~PIX_REPEAT_MASK_UP_SEL;
13479ac0038dSTim Harvey 		if (frame.avi.colorspace == HDMI_COLORSPACE_YUV422)
13489ac0038dSTim Harvey 			reg |= (PIX_REPEAT_CHROMA << PIX_REPEAT_SHIFT);
13499ac0038dSTim Harvey 		io_write(sd, REG_PIX_REPEAT, reg);
13509ac0038dSTim Harvey 
13519ac0038dSTim Harvey 		/* ConfigurePixelRepeater: repeat n-times each pixel */
13529ac0038dSTim Harvey 		reg = io_read(sd, REG_PIX_REPEAT);
13539ac0038dSTim Harvey 		reg &= ~PIX_REPEAT_MASK_REP;
13549ac0038dSTim Harvey 		reg |= frame.avi.pixel_repeat;
13559ac0038dSTim Harvey 		io_write(sd, REG_PIX_REPEAT, reg);
13569ac0038dSTim Harvey 
13579ac0038dSTim Harvey 		/* configure the receiver with the new colorspace */
13589ac0038dSTim Harvey 		tda1997x_configure_csc(sd);
13599ac0038dSTim Harvey 		break;
13609ac0038dSTim Harvey 	default:
13619ac0038dSTim Harvey 		break;
13629ac0038dSTim Harvey 	}
13639ac0038dSTim Harvey 	return 0;
13649ac0038dSTim Harvey }
13659ac0038dSTim Harvey 
tda1997x_irq_sus(struct tda1997x_state * state,u8 * flags)13669ac0038dSTim Harvey static void tda1997x_irq_sus(struct tda1997x_state *state, u8 *flags)
13679ac0038dSTim Harvey {
13689ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
13699ac0038dSTim Harvey 	u8 reg, source;
13709ac0038dSTim Harvey 
13719ac0038dSTim Harvey 	source = io_read(sd, REG_INT_FLG_CLR_SUS);
13729ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_SUS, source);
13739ac0038dSTim Harvey 
13749ac0038dSTim Harvey 	if (source & MASK_MPT) {
13759ac0038dSTim Harvey 		/* reset MTP in use flag if set */
13769ac0038dSTim Harvey 		if (state->mptrw_in_progress)
13779ac0038dSTim Harvey 			state->mptrw_in_progress = 0;
13789ac0038dSTim Harvey 	}
13799ac0038dSTim Harvey 
13809ac0038dSTim Harvey 	if (source & MASK_SUS_END) {
13819ac0038dSTim Harvey 		/* reset audio FIFO */
13829ac0038dSTim Harvey 		reg = io_read(sd, REG_HDMI_INFO_RST);
13839ac0038dSTim Harvey 		reg |= MASK_SR_FIFO_FIFO_CTRL;
13849ac0038dSTim Harvey 		io_write(sd, REG_HDMI_INFO_RST, reg);
13859ac0038dSTim Harvey 		reg &= ~MASK_SR_FIFO_FIFO_CTRL;
13869ac0038dSTim Harvey 		io_write(sd, REG_HDMI_INFO_RST, reg);
13879ac0038dSTim Harvey 
13889ac0038dSTim Harvey 		/* reset HDMI flags */
13899ac0038dSTim Harvey 		state->hdmi_status = 0;
13909ac0038dSTim Harvey 	}
13919ac0038dSTim Harvey 
13929ac0038dSTim Harvey 	/* filter FMT interrupt based on SUS state */
13939ac0038dSTim Harvey 	reg = io_read(sd, REG_SUS_STATUS);
13949ac0038dSTim Harvey 	if (((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED)
13959ac0038dSTim Harvey 	   || (source & MASK_MPT)) {
13969ac0038dSTim Harvey 		source &= ~MASK_FMT;
13979ac0038dSTim Harvey 	}
13989ac0038dSTim Harvey 
13999ac0038dSTim Harvey 	if (source & (MASK_FMT | MASK_SUS_END)) {
14009ac0038dSTim Harvey 		reg = io_read(sd, REG_SUS_STATUS);
14019ac0038dSTim Harvey 		if ((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED) {
14029ac0038dSTim Harvey 			v4l_err(state->client, "BAD SUS STATUS\n");
14039ac0038dSTim Harvey 			return;
14049ac0038dSTim Harvey 		}
14059ac0038dSTim Harvey 		if (debug)
14069ac0038dSTim Harvey 			tda1997x_detect_std(state, NULL);
14079ac0038dSTim Harvey 		/* notify user of change in resolution */
14089ac0038dSTim Harvey 		v4l2_subdev_notify_event(&state->sd, &tda1997x_ev_fmt);
14099ac0038dSTim Harvey 	}
14109ac0038dSTim Harvey }
14119ac0038dSTim Harvey 
tda1997x_irq_ddc(struct tda1997x_state * state,u8 * flags)14129ac0038dSTim Harvey static void tda1997x_irq_ddc(struct tda1997x_state *state, u8 *flags)
14139ac0038dSTim Harvey {
14149ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
14159ac0038dSTim Harvey 	u8 source;
14169ac0038dSTim Harvey 
14179ac0038dSTim Harvey 	source = io_read(sd, REG_INT_FLG_CLR_DDC);
14189ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_DDC, source);
14199ac0038dSTim Harvey 	if (source & MASK_EDID_MTP) {
14209ac0038dSTim Harvey 		/* reset MTP in use flag if set */
14219ac0038dSTim Harvey 		if (state->mptrw_in_progress)
14229ac0038dSTim Harvey 			state->mptrw_in_progress = 0;
14239ac0038dSTim Harvey 	}
14249ac0038dSTim Harvey 
14259ac0038dSTim Harvey 	/* Detection of +5V */
14269ac0038dSTim Harvey 	if (source & MASK_DET_5V) {
14279ac0038dSTim Harvey 		v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
14289ac0038dSTim Harvey 				 tda1997x_detect_tx_5v(sd));
14299ac0038dSTim Harvey 	}
14309ac0038dSTim Harvey }
14319ac0038dSTim Harvey 
tda1997x_irq_rate(struct tda1997x_state * state,u8 * flags)14329ac0038dSTim Harvey static void tda1997x_irq_rate(struct tda1997x_state *state, u8 *flags)
14339ac0038dSTim Harvey {
14349ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
14359ac0038dSTim Harvey 	u8 reg, source;
14369ac0038dSTim Harvey 
14374395fb47SMauro Carvalho Chehab 	u8 irq_status;
14389ac0038dSTim Harvey 
14399ac0038dSTim Harvey 	source = io_read(sd, REG_INT_FLG_CLR_RATE);
14409ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_RATE, source);
14419ac0038dSTim Harvey 
14429ac0038dSTim Harvey 	/* read status regs */
14434395fb47SMauro Carvalho Chehab 	irq_status = tda1997x_read_activity_status_regs(sd);
14449ac0038dSTim Harvey 
14459ac0038dSTim Harvey 	/*
14469ac0038dSTim Harvey 	 * read clock status reg until INT_FLG_CLR_RATE is still 0
14479ac0038dSTim Harvey 	 * after the read to make sure its the last one
14489ac0038dSTim Harvey 	 */
14499ac0038dSTim Harvey 	reg = source;
14509ac0038dSTim Harvey 	while (reg != 0) {
14519ac0038dSTim Harvey 		irq_status = tda1997x_read_activity_status_regs(sd);
14529ac0038dSTim Harvey 		reg = io_read(sd, REG_INT_FLG_CLR_RATE);
14539ac0038dSTim Harvey 		io_write(sd, REG_INT_FLG_CLR_RATE, reg);
14549ac0038dSTim Harvey 		source |= reg;
14559ac0038dSTim Harvey 	}
14569ac0038dSTim Harvey 
14579ac0038dSTim Harvey 	/* we only pay attention to stability change events */
14589ac0038dSTim Harvey 	if (source & (MASK_RATE_A_ST | MASK_RATE_B_ST)) {
14599ac0038dSTim Harvey 		int input = (source & MASK_RATE_A_ST)?0:1;
14609ac0038dSTim Harvey 		u8 mask = 1<<input;
14619ac0038dSTim Harvey 
14629ac0038dSTim Harvey 		/* state change */
14639ac0038dSTim Harvey 		if ((irq_status & mask) != (state->activity_status & mask)) {
14649ac0038dSTim Harvey 			/* activity lost */
14659ac0038dSTim Harvey 			if ((irq_status & mask) == 0) {
14669ac0038dSTim Harvey 				v4l_info(state->client,
14679ac0038dSTim Harvey 					 "HDMI-%c: Digital Activity Lost\n",
14689ac0038dSTim Harvey 					 input+'A');
14699ac0038dSTim Harvey 
14709ac0038dSTim Harvey 				/* bypass up/down sampler and pixel repeater */
14719ac0038dSTim Harvey 				reg = io_read(sd, REG_PIX_REPEAT);
14729ac0038dSTim Harvey 				reg &= ~PIX_REPEAT_MASK_UP_SEL;
14739ac0038dSTim Harvey 				reg &= ~PIX_REPEAT_MASK_REP;
14749ac0038dSTim Harvey 				io_write(sd, REG_PIX_REPEAT, reg);
14759ac0038dSTim Harvey 
14769ac0038dSTim Harvey 				if (state->chip_revision == 0)
14779ac0038dSTim Harvey 					tda1997x_reset_n1(state);
14789ac0038dSTim Harvey 
14799ac0038dSTim Harvey 				state->input_detect[input] = 0;
14809ac0038dSTim Harvey 				v4l2_subdev_notify_event(sd, &tda1997x_ev_fmt);
14819ac0038dSTim Harvey 			}
14829ac0038dSTim Harvey 
14839ac0038dSTim Harvey 			/* activity detected */
14849ac0038dSTim Harvey 			else {
14859ac0038dSTim Harvey 				v4l_info(state->client,
14869ac0038dSTim Harvey 					 "HDMI-%c: Digital Activity Detected\n",
14879ac0038dSTim Harvey 					 input+'A');
14889ac0038dSTim Harvey 				state->input_detect[input] = 1;
14899ac0038dSTim Harvey 			}
14909ac0038dSTim Harvey 
14919ac0038dSTim Harvey 			/* hold onto current state */
14929ac0038dSTim Harvey 			state->activity_status = (irq_status & mask);
14939ac0038dSTim Harvey 		}
14949ac0038dSTim Harvey 	}
14959ac0038dSTim Harvey }
14969ac0038dSTim Harvey 
tda1997x_irq_info(struct tda1997x_state * state,u8 * flags)14979ac0038dSTim Harvey static void tda1997x_irq_info(struct tda1997x_state *state, u8 *flags)
14989ac0038dSTim Harvey {
14999ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
15009ac0038dSTim Harvey 	u8 source;
15019ac0038dSTim Harvey 
15029ac0038dSTim Harvey 	source = io_read(sd, REG_INT_FLG_CLR_INFO);
15039ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_INFO, source);
15049ac0038dSTim Harvey 
15059ac0038dSTim Harvey 	/* Audio infoframe */
15069ac0038dSTim Harvey 	if (source & MASK_AUD_IF) {
15079ac0038dSTim Harvey 		tda1997x_parse_infoframe(state, AUD_IF);
15089ac0038dSTim Harvey 		source &= ~MASK_AUD_IF;
15099ac0038dSTim Harvey 	}
15109ac0038dSTim Harvey 
15119ac0038dSTim Harvey 	/* Source Product Descriptor infoframe change */
15129ac0038dSTim Harvey 	if (source & MASK_SPD_IF) {
15139ac0038dSTim Harvey 		tda1997x_parse_infoframe(state, SPD_IF);
15149ac0038dSTim Harvey 		source &= ~MASK_SPD_IF;
15159ac0038dSTim Harvey 	}
15169ac0038dSTim Harvey 
15179ac0038dSTim Harvey 	/* Auxiliary Video Information infoframe */
15189ac0038dSTim Harvey 	if (source & MASK_AVI_IF) {
15199ac0038dSTim Harvey 		tda1997x_parse_infoframe(state, AVI_IF);
15209ac0038dSTim Harvey 		source &= ~MASK_AVI_IF;
15219ac0038dSTim Harvey 	}
15229ac0038dSTim Harvey }
15239ac0038dSTim Harvey 
tda1997x_irq_audio(struct tda1997x_state * state,u8 * flags)15249ac0038dSTim Harvey static void tda1997x_irq_audio(struct tda1997x_state *state, u8 *flags)
15259ac0038dSTim Harvey {
15269ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
15279ac0038dSTim Harvey 	u8 reg, source;
15289ac0038dSTim Harvey 
15299ac0038dSTim Harvey 	source = io_read(sd, REG_INT_FLG_CLR_AUDIO);
15309ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_AUDIO, source);
15319ac0038dSTim Harvey 
15329ac0038dSTim Harvey 	/* reset audio FIFO on FIFO pointer error or audio mute */
15339ac0038dSTim Harvey 	if (source & MASK_ERROR_FIFO_PT ||
15349ac0038dSTim Harvey 	    source & MASK_MUTE_FLG) {
15359ac0038dSTim Harvey 		/* audio reset audio FIFO */
15369ac0038dSTim Harvey 		reg = io_read(sd, REG_SUS_STATUS);
15379ac0038dSTim Harvey 		if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED) {
15389ac0038dSTim Harvey 			reg = io_read(sd, REG_HDMI_INFO_RST);
15399ac0038dSTim Harvey 			reg |= MASK_SR_FIFO_FIFO_CTRL;
15409ac0038dSTim Harvey 			io_write(sd, REG_HDMI_INFO_RST, reg);
15419ac0038dSTim Harvey 			reg &= ~MASK_SR_FIFO_FIFO_CTRL;
15429ac0038dSTim Harvey 			io_write(sd, REG_HDMI_INFO_RST, reg);
15439ac0038dSTim Harvey 			/* reset channel status IT if present */
15449ac0038dSTim Harvey 			source &= ~(MASK_CH_STATE);
15459ac0038dSTim Harvey 		}
15469ac0038dSTim Harvey 	}
15479ac0038dSTim Harvey 	if (source & MASK_AUDIO_FREQ_FLG) {
15489ac0038dSTim Harvey 		static const int freq[] = {
15499ac0038dSTim Harvey 			0, 32000, 44100, 48000, 88200, 96000, 176400, 192000
15509ac0038dSTim Harvey 		};
15519ac0038dSTim Harvey 
15529ac0038dSTim Harvey 		reg = io_read(sd, REG_AUDIO_FREQ);
15539ac0038dSTim Harvey 		state->audio_samplerate = freq[reg & 7];
15549ac0038dSTim Harvey 		v4l_info(state->client, "Audio Frequency Change: %dHz\n",
15559ac0038dSTim Harvey 			 state->audio_samplerate);
15569ac0038dSTim Harvey 	}
15579ac0038dSTim Harvey 	if (source & MASK_AUDIO_FLG) {
15589ac0038dSTim Harvey 		reg = io_read(sd, REG_AUDIO_FLAGS);
15599ac0038dSTim Harvey 		if (reg & BIT(AUDCFG_TYPE_DST))
15609ac0038dSTim Harvey 			state->audio_type = AUDCFG_TYPE_DST;
15619ac0038dSTim Harvey 		if (reg & BIT(AUDCFG_TYPE_OBA))
15629ac0038dSTim Harvey 			state->audio_type = AUDCFG_TYPE_OBA;
15639ac0038dSTim Harvey 		if (reg & BIT(AUDCFG_TYPE_HBR))
15649ac0038dSTim Harvey 			state->audio_type = AUDCFG_TYPE_HBR;
15659ac0038dSTim Harvey 		if (reg & BIT(AUDCFG_TYPE_PCM))
15669ac0038dSTim Harvey 			state->audio_type = AUDCFG_TYPE_PCM;
15679ac0038dSTim Harvey 		v4l_info(state->client, "Audio Type: %s\n",
15689ac0038dSTim Harvey 			 audtype_names[state->audio_type]);
15699ac0038dSTim Harvey 	}
15709ac0038dSTim Harvey }
15719ac0038dSTim Harvey 
tda1997x_irq_hdcp(struct tda1997x_state * state,u8 * flags)15729ac0038dSTim Harvey static void tda1997x_irq_hdcp(struct tda1997x_state *state, u8 *flags)
15739ac0038dSTim Harvey {
15749ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
15759ac0038dSTim Harvey 	u8 reg, source;
15769ac0038dSTim Harvey 
15779ac0038dSTim Harvey 	source = io_read(sd, REG_INT_FLG_CLR_HDCP);
15789ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_HDCP, source);
15799ac0038dSTim Harvey 
15809ac0038dSTim Harvey 	/* reset MTP in use flag if set */
15819ac0038dSTim Harvey 	if (source & MASK_HDCP_MTP)
15829ac0038dSTim Harvey 		state->mptrw_in_progress = 0;
15839ac0038dSTim Harvey 	if (source & MASK_STATE_C5) {
15849ac0038dSTim Harvey 		/* REPEATER: mask AUDIO and IF irqs to avoid IF during auth */
15859ac0038dSTim Harvey 		reg = io_read(sd, REG_INT_MASK_TOP);
15869ac0038dSTim Harvey 		reg &= ~(INTERRUPT_AUDIO | INTERRUPT_INFO);
15879ac0038dSTim Harvey 		io_write(sd, REG_INT_MASK_TOP, reg);
15889ac0038dSTim Harvey 		*flags &= (INTERRUPT_AUDIO | INTERRUPT_INFO);
15899ac0038dSTim Harvey 	}
15909ac0038dSTim Harvey }
15919ac0038dSTim Harvey 
tda1997x_isr_thread(int irq,void * d)15929ac0038dSTim Harvey static irqreturn_t tda1997x_isr_thread(int irq, void *d)
15939ac0038dSTim Harvey {
15949ac0038dSTim Harvey 	struct tda1997x_state *state = d;
15959ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
15969ac0038dSTim Harvey 	u8 flags;
15979ac0038dSTim Harvey 
15989ac0038dSTim Harvey 	mutex_lock(&state->lock);
15999ac0038dSTim Harvey 	do {
16009ac0038dSTim Harvey 		/* read interrupt flags */
16019ac0038dSTim Harvey 		flags = io_read(sd, REG_INT_FLG_CLR_TOP);
16029ac0038dSTim Harvey 		if (flags == 0)
16039ac0038dSTim Harvey 			break;
16049ac0038dSTim Harvey 
16059ac0038dSTim Harvey 		/* SUS interrupt source (Input activity events) */
16069ac0038dSTim Harvey 		if (flags & INTERRUPT_SUS)
16079ac0038dSTim Harvey 			tda1997x_irq_sus(state, &flags);
16089ac0038dSTim Harvey 		/* DDC interrupt source (Display Data Channel) */
16099ac0038dSTim Harvey 		else if (flags & INTERRUPT_DDC)
16109ac0038dSTim Harvey 			tda1997x_irq_ddc(state, &flags);
16119ac0038dSTim Harvey 		/* RATE interrupt source (Digital Input activity) */
16129ac0038dSTim Harvey 		else if (flags & INTERRUPT_RATE)
16139ac0038dSTim Harvey 			tda1997x_irq_rate(state, &flags);
16149ac0038dSTim Harvey 		/* Infoframe change interrupt */
16159ac0038dSTim Harvey 		else if (flags & INTERRUPT_INFO)
16169ac0038dSTim Harvey 			tda1997x_irq_info(state, &flags);
16179ac0038dSTim Harvey 		/* Audio interrupt source:
16189ac0038dSTim Harvey 		 *   freq change, DST,OBA,HBR,ASP flags, mute, FIFO err
16199ac0038dSTim Harvey 		 */
16209ac0038dSTim Harvey 		else if (flags & INTERRUPT_AUDIO)
16219ac0038dSTim Harvey 			tda1997x_irq_audio(state, &flags);
16229ac0038dSTim Harvey 		/* HDCP interrupt source (content protection) */
16239ac0038dSTim Harvey 		if (flags & INTERRUPT_HDCP)
16249ac0038dSTim Harvey 			tda1997x_irq_hdcp(state, &flags);
16259ac0038dSTim Harvey 	} while (flags != 0);
16269ac0038dSTim Harvey 	mutex_unlock(&state->lock);
16279ac0038dSTim Harvey 
16289ac0038dSTim Harvey 	return IRQ_HANDLED;
16299ac0038dSTim Harvey }
16309ac0038dSTim Harvey 
16319ac0038dSTim Harvey /* -----------------------------------------------------------------------------
16329ac0038dSTim Harvey  * v4l2_subdev_video_ops
16339ac0038dSTim Harvey  */
16349ac0038dSTim Harvey 
16359ac0038dSTim Harvey static int
tda1997x_g_input_status(struct v4l2_subdev * sd,u32 * status)16369ac0038dSTim Harvey tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status)
16379ac0038dSTim Harvey {
16389ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
16399ac0038dSTim Harvey 	u32 vper;
16409ac0038dSTim Harvey 	u16 hper;
16419ac0038dSTim Harvey 	u16 hsper;
16429ac0038dSTim Harvey 
16439ac0038dSTim Harvey 	mutex_lock(&state->lock);
16449ac0038dSTim Harvey 	vper = io_read24(sd, REG_V_PER) & MASK_VPER;
16459ac0038dSTim Harvey 	hper = io_read16(sd, REG_H_PER) & MASK_HPER;
16469ac0038dSTim Harvey 	hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH;
16479ac0038dSTim Harvey 	/*
16489ac0038dSTim Harvey 	 * The tda1997x supports A/B inputs but only a single output.
16499ac0038dSTim Harvey 	 * The irq handler monitors for timing changes on both inputs and
16509ac0038dSTim Harvey 	 * sets the input_detect array to 0|1 depending on signal presence.
16519ac0038dSTim Harvey 	 * I believe selection of A vs B is automatic.
16529ac0038dSTim Harvey 	 *
16539ac0038dSTim Harvey 	 * The vper/hper/hsper registers provide the frame period, line period
16549ac0038dSTim Harvey 	 * and horiz sync period (units of MCLK clock cycles (27MHz)) and
16559ac0038dSTim Harvey 	 * testing shows these values to be random if no signal is present
16569ac0038dSTim Harvey 	 * or locked.
16579ac0038dSTim Harvey 	 */
16589ac0038dSTim Harvey 	v4l2_dbg(1, debug, sd, "inputs:%d/%d timings:%d/%d/%d\n",
16599ac0038dSTim Harvey 		 state->input_detect[0], state->input_detect[1],
16609ac0038dSTim Harvey 		 vper, hper, hsper);
16619ac0038dSTim Harvey 	if (!state->input_detect[0] && !state->input_detect[1])
16629ac0038dSTim Harvey 		*status = V4L2_IN_ST_NO_SIGNAL;
16639ac0038dSTim Harvey 	else if (!vper || !hper || !hsper)
16649ac0038dSTim Harvey 		*status = V4L2_IN_ST_NO_SYNC;
16659ac0038dSTim Harvey 	else
16669ac0038dSTim Harvey 		*status = 0;
16679ac0038dSTim Harvey 	mutex_unlock(&state->lock);
16689ac0038dSTim Harvey 
16699ac0038dSTim Harvey 	return 0;
16709ac0038dSTim Harvey };
16719ac0038dSTim Harvey 
tda1997x_s_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)16729ac0038dSTim Harvey static int tda1997x_s_dv_timings(struct v4l2_subdev *sd,
16739ac0038dSTim Harvey 				struct v4l2_dv_timings *timings)
16749ac0038dSTim Harvey {
16759ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
16769ac0038dSTim Harvey 
16779ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s\n", __func__);
16789ac0038dSTim Harvey 
16799ac0038dSTim Harvey 	if (v4l2_match_dv_timings(&state->timings, timings, 0, false))
16809ac0038dSTim Harvey 		return 0; /* no changes */
16819ac0038dSTim Harvey 
16829ac0038dSTim Harvey 	if (!v4l2_valid_dv_timings(timings, &tda1997x_dv_timings_cap,
16839ac0038dSTim Harvey 				   NULL, NULL))
16849ac0038dSTim Harvey 		return -ERANGE;
16859ac0038dSTim Harvey 
16869ac0038dSTim Harvey 	mutex_lock(&state->lock);
16879ac0038dSTim Harvey 	state->timings = *timings;
16889ac0038dSTim Harvey 	/* setup frame detection window and VHREF timing generator */
16899ac0038dSTim Harvey 	tda1997x_configure_vhref(sd);
16909ac0038dSTim Harvey 	/* configure colorspace conversion */
16919ac0038dSTim Harvey 	tda1997x_configure_csc(sd);
16929ac0038dSTim Harvey 	mutex_unlock(&state->lock);
16939ac0038dSTim Harvey 
16949ac0038dSTim Harvey 	return 0;
16959ac0038dSTim Harvey }
16969ac0038dSTim Harvey 
tda1997x_g_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)16979ac0038dSTim Harvey static int tda1997x_g_dv_timings(struct v4l2_subdev *sd,
16989ac0038dSTim Harvey 				 struct v4l2_dv_timings *timings)
16999ac0038dSTim Harvey {
17009ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
17019ac0038dSTim Harvey 
17029ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s\n", __func__);
17039ac0038dSTim Harvey 	mutex_lock(&state->lock);
17049ac0038dSTim Harvey 	*timings = state->timings;
17059ac0038dSTim Harvey 	mutex_unlock(&state->lock);
17069ac0038dSTim Harvey 
17079ac0038dSTim Harvey 	return 0;
17089ac0038dSTim Harvey }
17099ac0038dSTim Harvey 
tda1997x_query_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)17109ac0038dSTim Harvey static int tda1997x_query_dv_timings(struct v4l2_subdev *sd,
17119ac0038dSTim Harvey 				     struct v4l2_dv_timings *timings)
17129ac0038dSTim Harvey {
17139ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
17147dee1030SKrzysztof Hałasa 	int ret;
17159ac0038dSTim Harvey 
17169ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s\n", __func__);
17179ac0038dSTim Harvey 	memset(timings, 0, sizeof(struct v4l2_dv_timings));
17189ac0038dSTim Harvey 	mutex_lock(&state->lock);
17197dee1030SKrzysztof Hałasa 	ret = tda1997x_detect_std(state, timings);
17209ac0038dSTim Harvey 	mutex_unlock(&state->lock);
17219ac0038dSTim Harvey 
17227dee1030SKrzysztof Hałasa 	return ret;
17239ac0038dSTim Harvey }
17249ac0038dSTim Harvey 
17259ac0038dSTim Harvey static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
17269ac0038dSTim Harvey 	.g_input_status = tda1997x_g_input_status,
17279ac0038dSTim Harvey 	.s_dv_timings = tda1997x_s_dv_timings,
17289ac0038dSTim Harvey 	.g_dv_timings = tda1997x_g_dv_timings,
17299ac0038dSTim Harvey 	.query_dv_timings = tda1997x_query_dv_timings,
17309ac0038dSTim Harvey };
17319ac0038dSTim Harvey 
17329ac0038dSTim Harvey 
17339ac0038dSTim Harvey /* -----------------------------------------------------------------------------
17349ac0038dSTim Harvey  * v4l2_subdev_pad_ops
17359ac0038dSTim Harvey  */
17369ac0038dSTim Harvey 
tda1997x_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)17379ac0038dSTim Harvey static int tda1997x_init_cfg(struct v4l2_subdev *sd,
17380d346d2aSTomi Valkeinen 			     struct v4l2_subdev_state *sd_state)
17399ac0038dSTim Harvey {
17409ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
17419ac0038dSTim Harvey 	struct v4l2_mbus_framefmt *mf;
17429ac0038dSTim Harvey 
17430d346d2aSTomi Valkeinen 	mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
17449ac0038dSTim Harvey 	mf->code = state->mbus_codes[0];
17459ac0038dSTim Harvey 
17469ac0038dSTim Harvey 	return 0;
17479ac0038dSTim Harvey }
17489ac0038dSTim Harvey 
tda1997x_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)17499ac0038dSTim Harvey static int tda1997x_enum_mbus_code(struct v4l2_subdev *sd,
17500d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
17519ac0038dSTim Harvey 				  struct v4l2_subdev_mbus_code_enum *code)
17529ac0038dSTim Harvey {
17539ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
17549ac0038dSTim Harvey 
17559ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s %d\n", __func__, code->index);
17569ac0038dSTim Harvey 	if (code->index >= ARRAY_SIZE(state->mbus_codes))
17579ac0038dSTim Harvey 		return -EINVAL;
17589ac0038dSTim Harvey 
17599ac0038dSTim Harvey 	if (!state->mbus_codes[code->index])
17609ac0038dSTim Harvey 		return -EINVAL;
17619ac0038dSTim Harvey 
17629ac0038dSTim Harvey 	code->code = state->mbus_codes[code->index];
17639ac0038dSTim Harvey 
17649ac0038dSTim Harvey 	return 0;
17659ac0038dSTim Harvey }
17669ac0038dSTim Harvey 
tda1997x_fill_format(struct tda1997x_state * state,struct v4l2_mbus_framefmt * format)17679ac0038dSTim Harvey static void tda1997x_fill_format(struct tda1997x_state *state,
17689ac0038dSTim Harvey 				 struct v4l2_mbus_framefmt *format)
17699ac0038dSTim Harvey {
17709ac0038dSTim Harvey 	const struct v4l2_bt_timings *bt;
17719ac0038dSTim Harvey 
17729ac0038dSTim Harvey 	memset(format, 0, sizeof(*format));
17739ac0038dSTim Harvey 	bt = &state->timings.bt;
17749ac0038dSTim Harvey 	format->width = bt->width;
17759ac0038dSTim Harvey 	format->height = bt->height;
17769ac0038dSTim Harvey 	format->colorspace = state->colorimetry.colorspace;
17779ac0038dSTim Harvey 	format->field = (bt->interlaced) ?
17789ac0038dSTim Harvey 		V4L2_FIELD_SEQ_TB : V4L2_FIELD_NONE;
17799ac0038dSTim Harvey }
17809ac0038dSTim Harvey 
tda1997x_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)17819ac0038dSTim Harvey static int tda1997x_get_format(struct v4l2_subdev *sd,
17820d346d2aSTomi Valkeinen 			       struct v4l2_subdev_state *sd_state,
17839ac0038dSTim Harvey 			       struct v4l2_subdev_format *format)
17849ac0038dSTim Harvey {
17859ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
17869ac0038dSTim Harvey 
17879ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s pad=%d which=%d\n",
17889ac0038dSTim Harvey 		__func__, format->pad, format->which);
17899ac0038dSTim Harvey 
17909ac0038dSTim Harvey 	tda1997x_fill_format(state, &format->format);
17919ac0038dSTim Harvey 
17929ac0038dSTim Harvey 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
17939ac0038dSTim Harvey 		struct v4l2_mbus_framefmt *fmt;
17949ac0038dSTim Harvey 
17950d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
17969ac0038dSTim Harvey 		format->format.code = fmt->code;
17979ac0038dSTim Harvey 	} else
17989ac0038dSTim Harvey 		format->format.code = state->mbus_code;
17999ac0038dSTim Harvey 
18009ac0038dSTim Harvey 	return 0;
18019ac0038dSTim Harvey }
18029ac0038dSTim Harvey 
tda1997x_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)18039ac0038dSTim Harvey static int tda1997x_set_format(struct v4l2_subdev *sd,
18040d346d2aSTomi Valkeinen 			       struct v4l2_subdev_state *sd_state,
18059ac0038dSTim Harvey 			       struct v4l2_subdev_format *format)
18069ac0038dSTim Harvey {
18079ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
18089ac0038dSTim Harvey 	u32 code = 0;
18099ac0038dSTim Harvey 	int i;
18109ac0038dSTim Harvey 
18119ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s pad=%d which=%d fmt=0x%x\n",
18129ac0038dSTim Harvey 		__func__, format->pad, format->which, format->format.code);
18139ac0038dSTim Harvey 
18149ac0038dSTim Harvey 	for (i = 0; i < ARRAY_SIZE(state->mbus_codes); i++) {
18159ac0038dSTim Harvey 		if (format->format.code == state->mbus_codes[i]) {
18169ac0038dSTim Harvey 			code = state->mbus_codes[i];
18179ac0038dSTim Harvey 			break;
18189ac0038dSTim Harvey 		}
18199ac0038dSTim Harvey 	}
18209ac0038dSTim Harvey 	if (!code)
18219ac0038dSTim Harvey 		code = state->mbus_codes[0];
18229ac0038dSTim Harvey 
18239ac0038dSTim Harvey 	tda1997x_fill_format(state, &format->format);
18249ac0038dSTim Harvey 	format->format.code = code;
18259ac0038dSTim Harvey 
18269ac0038dSTim Harvey 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
18279ac0038dSTim Harvey 		struct v4l2_mbus_framefmt *fmt;
18289ac0038dSTim Harvey 
18290d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
18309ac0038dSTim Harvey 		*fmt = format->format;
18319ac0038dSTim Harvey 	} else {
18329ac0038dSTim Harvey 		int ret = tda1997x_setup_format(state, format->format.code);
18339ac0038dSTim Harvey 
18349ac0038dSTim Harvey 		if (ret)
18359ac0038dSTim Harvey 			return ret;
18369ac0038dSTim Harvey 		/* mbus_code has changed - re-configure csc/vidout */
18379ac0038dSTim Harvey 		tda1997x_configure_csc(sd);
18389ac0038dSTim Harvey 		tda1997x_configure_vidout(state);
18399ac0038dSTim Harvey 	}
18409ac0038dSTim Harvey 
18419ac0038dSTim Harvey 	return 0;
18429ac0038dSTim Harvey }
18439ac0038dSTim Harvey 
tda1997x_get_edid(struct v4l2_subdev * sd,struct v4l2_edid * edid)18449ac0038dSTim Harvey static int tda1997x_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
18459ac0038dSTim Harvey {
18469ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
18479ac0038dSTim Harvey 
18489ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad);
18499ac0038dSTim Harvey 	memset(edid->reserved, 0, sizeof(edid->reserved));
18509ac0038dSTim Harvey 
18519ac0038dSTim Harvey 	if (edid->start_block == 0 && edid->blocks == 0) {
18529ac0038dSTim Harvey 		edid->blocks = state->edid.blocks;
18539ac0038dSTim Harvey 		return 0;
18549ac0038dSTim Harvey 	}
18559ac0038dSTim Harvey 
18569ac0038dSTim Harvey 	if (!state->edid.present)
18579ac0038dSTim Harvey 		return -ENODATA;
18589ac0038dSTim Harvey 
18599ac0038dSTim Harvey 	if (edid->start_block >= state->edid.blocks)
18609ac0038dSTim Harvey 		return -EINVAL;
18619ac0038dSTim Harvey 
18629ac0038dSTim Harvey 	if (edid->start_block + edid->blocks > state->edid.blocks)
18639ac0038dSTim Harvey 		edid->blocks = state->edid.blocks - edid->start_block;
18649ac0038dSTim Harvey 
18659ac0038dSTim Harvey 	memcpy(edid->edid, state->edid.edid + edid->start_block * 128,
18669ac0038dSTim Harvey 	       edid->blocks * 128);
18679ac0038dSTim Harvey 
18689ac0038dSTim Harvey 	return 0;
18699ac0038dSTim Harvey }
18709ac0038dSTim Harvey 
tda1997x_set_edid(struct v4l2_subdev * sd,struct v4l2_edid * edid)18719ac0038dSTim Harvey static int tda1997x_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
18729ac0038dSTim Harvey {
18739ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
18749ac0038dSTim Harvey 	int i;
18759ac0038dSTim Harvey 
18769ac0038dSTim Harvey 	v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad);
18779ac0038dSTim Harvey 	memset(edid->reserved, 0, sizeof(edid->reserved));
18789ac0038dSTim Harvey 
18799ac0038dSTim Harvey 	if (edid->start_block != 0)
18809ac0038dSTim Harvey 		return -EINVAL;
18819ac0038dSTim Harvey 
18829ac0038dSTim Harvey 	if (edid->blocks == 0) {
18839ac0038dSTim Harvey 		state->edid.blocks = 0;
18849ac0038dSTim Harvey 		state->edid.present = 0;
18859ac0038dSTim Harvey 		tda1997x_disable_edid(sd);
18869ac0038dSTim Harvey 		return 0;
18879ac0038dSTim Harvey 	}
18889ac0038dSTim Harvey 
18899ac0038dSTim Harvey 	if (edid->blocks > 2) {
18909ac0038dSTim Harvey 		edid->blocks = 2;
18919ac0038dSTim Harvey 		return -E2BIG;
18929ac0038dSTim Harvey 	}
18939ac0038dSTim Harvey 
18949ac0038dSTim Harvey 	tda1997x_disable_edid(sd);
18959ac0038dSTim Harvey 
18969ac0038dSTim Harvey 	/* write base EDID */
18979ac0038dSTim Harvey 	for (i = 0; i < 128; i++)
18989ac0038dSTim Harvey 		io_write(sd, REG_EDID_IN_BYTE0 + i, edid->edid[i]);
18999ac0038dSTim Harvey 
19009ac0038dSTim Harvey 	/* write CEA Extension */
19019ac0038dSTim Harvey 	for (i = 0; i < 128; i++)
19029ac0038dSTim Harvey 		io_write(sd, REG_EDID_IN_BYTE128 + i, edid->edid[i+128]);
19039ac0038dSTim Harvey 
19040806bc0aSTim Harvey 	/* store state */
19050806bc0aSTim Harvey 	memcpy(state->edid.edid, edid->edid, 256);
19060806bc0aSTim Harvey 	state->edid.blocks = edid->blocks;
19070806bc0aSTim Harvey 
19089ac0038dSTim Harvey 	tda1997x_enable_edid(sd);
19099ac0038dSTim Harvey 
19109ac0038dSTim Harvey 	return 0;
19119ac0038dSTim Harvey }
19129ac0038dSTim Harvey 
tda1997x_get_dv_timings_cap(struct v4l2_subdev * sd,struct v4l2_dv_timings_cap * cap)19139ac0038dSTim Harvey static int tda1997x_get_dv_timings_cap(struct v4l2_subdev *sd,
19149ac0038dSTim Harvey 				       struct v4l2_dv_timings_cap *cap)
19159ac0038dSTim Harvey {
19169ac0038dSTim Harvey 	*cap = tda1997x_dv_timings_cap;
19179ac0038dSTim Harvey 	return 0;
19189ac0038dSTim Harvey }
19199ac0038dSTim Harvey 
tda1997x_enum_dv_timings(struct v4l2_subdev * sd,struct v4l2_enum_dv_timings * timings)19209ac0038dSTim Harvey static int tda1997x_enum_dv_timings(struct v4l2_subdev *sd,
19219ac0038dSTim Harvey 				    struct v4l2_enum_dv_timings *timings)
19229ac0038dSTim Harvey {
19239ac0038dSTim Harvey 	return v4l2_enum_dv_timings_cap(timings, &tda1997x_dv_timings_cap,
19249ac0038dSTim Harvey 					NULL, NULL);
19259ac0038dSTim Harvey }
19269ac0038dSTim Harvey 
19279ac0038dSTim Harvey static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = {
19289ac0038dSTim Harvey 	.init_cfg = tda1997x_init_cfg,
19299ac0038dSTim Harvey 	.enum_mbus_code = tda1997x_enum_mbus_code,
19309ac0038dSTim Harvey 	.get_fmt = tda1997x_get_format,
19319ac0038dSTim Harvey 	.set_fmt = tda1997x_set_format,
19329ac0038dSTim Harvey 	.get_edid = tda1997x_get_edid,
19339ac0038dSTim Harvey 	.set_edid = tda1997x_set_edid,
19349ac0038dSTim Harvey 	.dv_timings_cap = tda1997x_get_dv_timings_cap,
19359ac0038dSTim Harvey 	.enum_dv_timings = tda1997x_enum_dv_timings,
19369ac0038dSTim Harvey };
19379ac0038dSTim Harvey 
19389ac0038dSTim Harvey /* -----------------------------------------------------------------------------
19399ac0038dSTim Harvey  * v4l2_subdev_core_ops
19409ac0038dSTim Harvey  */
19419ac0038dSTim Harvey 
tda1997x_log_infoframe(struct v4l2_subdev * sd,int addr)19429ac0038dSTim Harvey static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
19439ac0038dSTim Harvey {
19449ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
19459ac0038dSTim Harvey 	union hdmi_infoframe frame;
194648d219f9STom Rix 	u8 buffer[40] = { 0 };
19479ac0038dSTim Harvey 	int len, err;
19489ac0038dSTim Harvey 
19499ac0038dSTim Harvey 	/* read data */
19509ac0038dSTim Harvey 	len = io_readn(sd, addr, sizeof(buffer), buffer);
19519ac0038dSTim Harvey 	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
195248d219f9STom Rix 	err = hdmi_infoframe_unpack(&frame, buffer, len);
19539ac0038dSTim Harvey 	if (err) {
19549ac0038dSTim Harvey 		v4l_err(state->client,
19559ac0038dSTim Harvey 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
19569ac0038dSTim Harvey 			len, addr, buffer[0]);
19579ac0038dSTim Harvey 		return err;
19589ac0038dSTim Harvey 	}
19599ac0038dSTim Harvey 	hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame);
19609ac0038dSTim Harvey 
19619ac0038dSTim Harvey 	return 0;
19629ac0038dSTim Harvey }
19639ac0038dSTim Harvey 
tda1997x_log_status(struct v4l2_subdev * sd)19649ac0038dSTim Harvey static int tda1997x_log_status(struct v4l2_subdev *sd)
19659ac0038dSTim Harvey {
19669ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
19679ac0038dSTim Harvey 	struct v4l2_dv_timings timings;
19689ac0038dSTim Harvey 	struct hdmi_avi_infoframe *avi = &state->avi_infoframe;
19699ac0038dSTim Harvey 
19709ac0038dSTim Harvey 	v4l2_info(sd, "-----Chip status-----\n");
19719ac0038dSTim Harvey 	v4l2_info(sd, "Chip: %s N%d\n", state->info->name,
19729ac0038dSTim Harvey 		  state->chip_revision + 1);
19739ac0038dSTim Harvey 	v4l2_info(sd, "EDID Enabled: %s\n", state->edid.present ? "yes" : "no");
19749ac0038dSTim Harvey 
19759ac0038dSTim Harvey 	v4l2_info(sd, "-----Signal status-----\n");
19769ac0038dSTim Harvey 	v4l2_info(sd, "Cable detected (+5V power): %s\n",
19779ac0038dSTim Harvey 		  tda1997x_detect_tx_5v(sd) ? "yes" : "no");
19789ac0038dSTim Harvey 	v4l2_info(sd, "HPD detected: %s\n",
19799ac0038dSTim Harvey 		  tda1997x_detect_tx_hpd(sd) ? "yes" : "no");
19809ac0038dSTim Harvey 
19819ac0038dSTim Harvey 	v4l2_info(sd, "-----Video Timings-----\n");
19829ac0038dSTim Harvey 	switch (tda1997x_detect_std(state, &timings)) {
19839ac0038dSTim Harvey 	case -ENOLINK:
19849ac0038dSTim Harvey 		v4l2_info(sd, "No video detected\n");
19859ac0038dSTim Harvey 		break;
19869ac0038dSTim Harvey 	case -ERANGE:
19879ac0038dSTim Harvey 		v4l2_info(sd, "Invalid signal detected\n");
19889ac0038dSTim Harvey 		break;
19899ac0038dSTim Harvey 	}
19909ac0038dSTim Harvey 	v4l2_print_dv_timings(sd->name, "Configured format: ",
19919ac0038dSTim Harvey 			      &state->timings, true);
19929ac0038dSTim Harvey 
19939ac0038dSTim Harvey 	v4l2_info(sd, "-----Color space-----\n");
19949ac0038dSTim Harvey 	v4l2_info(sd, "Input color space: %s %s %s",
19959ac0038dSTim Harvey 		  hdmi_colorspace_names[avi->colorspace],
19969ac0038dSTim Harvey 		  (avi->colorspace == HDMI_COLORSPACE_RGB) ? "" :
19979ac0038dSTim Harvey 			hdmi_colorimetry_names[avi->colorimetry],
19989ac0038dSTim Harvey 		  v4l2_quantization_names[state->colorimetry.quantization]);
19999ac0038dSTim Harvey 	v4l2_info(sd, "Output color space: %s",
20009ac0038dSTim Harvey 		  vidfmt_names[state->vid_fmt]);
20019ac0038dSTim Harvey 	v4l2_info(sd, "Color space conversion: %s", state->conv ?
20029ac0038dSTim Harvey 		  state->conv->name : "None");
20039ac0038dSTim Harvey 
20049ac0038dSTim Harvey 	v4l2_info(sd, "-----Audio-----\n");
20059ac0038dSTim Harvey 	if (state->audio_channels) {
20069ac0038dSTim Harvey 		v4l2_info(sd, "audio: %dch %dHz\n", state->audio_channels,
20079ac0038dSTim Harvey 			  state->audio_samplerate);
20089ac0038dSTim Harvey 	} else {
20099ac0038dSTim Harvey 		v4l2_info(sd, "audio: none\n");
20109ac0038dSTim Harvey 	}
20119ac0038dSTim Harvey 
20129ac0038dSTim Harvey 	v4l2_info(sd, "-----Infoframes-----\n");
20139ac0038dSTim Harvey 	tda1997x_log_infoframe(sd, AUD_IF);
20149ac0038dSTim Harvey 	tda1997x_log_infoframe(sd, SPD_IF);
20159ac0038dSTim Harvey 	tda1997x_log_infoframe(sd, AVI_IF);
20169ac0038dSTim Harvey 
20179ac0038dSTim Harvey 	return 0;
20189ac0038dSTim Harvey }
20199ac0038dSTim Harvey 
tda1997x_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)20209ac0038dSTim Harvey static int tda1997x_subscribe_event(struct v4l2_subdev *sd,
20219ac0038dSTim Harvey 				    struct v4l2_fh *fh,
20229ac0038dSTim Harvey 				    struct v4l2_event_subscription *sub)
20239ac0038dSTim Harvey {
20249ac0038dSTim Harvey 	switch (sub->type) {
20259ac0038dSTim Harvey 	case V4L2_EVENT_SOURCE_CHANGE:
20269ac0038dSTim Harvey 		return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
20279ac0038dSTim Harvey 	case V4L2_EVENT_CTRL:
20289ac0038dSTim Harvey 		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
20299ac0038dSTim Harvey 	default:
20309ac0038dSTim Harvey 		return -EINVAL;
20319ac0038dSTim Harvey 	}
20329ac0038dSTim Harvey }
20339ac0038dSTim Harvey 
20349ac0038dSTim Harvey static const struct v4l2_subdev_core_ops tda1997x_core_ops = {
20359ac0038dSTim Harvey 	.log_status = tda1997x_log_status,
20369ac0038dSTim Harvey 	.subscribe_event = tda1997x_subscribe_event,
20379ac0038dSTim Harvey 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
20389ac0038dSTim Harvey };
20399ac0038dSTim Harvey 
20409ac0038dSTim Harvey /* -----------------------------------------------------------------------------
20419ac0038dSTim Harvey  * v4l2_subdev_ops
20429ac0038dSTim Harvey  */
20439ac0038dSTim Harvey 
20449ac0038dSTim Harvey static const struct v4l2_subdev_ops tda1997x_subdev_ops = {
20459ac0038dSTim Harvey 	.core = &tda1997x_core_ops,
20469ac0038dSTim Harvey 	.video = &tda1997x_video_ops,
20479ac0038dSTim Harvey 	.pad = &tda1997x_pad_ops,
20489ac0038dSTim Harvey };
20499ac0038dSTim Harvey 
20509ac0038dSTim Harvey /* -----------------------------------------------------------------------------
20519ac0038dSTim Harvey  * v4l2_controls
20529ac0038dSTim Harvey  */
20539ac0038dSTim Harvey 
tda1997x_s_ctrl(struct v4l2_ctrl * ctrl)20549ac0038dSTim Harvey static int tda1997x_s_ctrl(struct v4l2_ctrl *ctrl)
20559ac0038dSTim Harvey {
20569ac0038dSTim Harvey 	struct v4l2_subdev *sd = to_sd(ctrl);
20579ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
20589ac0038dSTim Harvey 
20599ac0038dSTim Harvey 	switch (ctrl->id) {
20609ac0038dSTim Harvey 	/* allow overriding the default RGB quantization range */
20619ac0038dSTim Harvey 	case V4L2_CID_DV_RX_RGB_RANGE:
20629ac0038dSTim Harvey 		state->rgb_quantization_range = ctrl->val;
20639ac0038dSTim Harvey 		set_rgb_quantization_range(state);
20649ac0038dSTim Harvey 		tda1997x_configure_csc(sd);
20659ac0038dSTim Harvey 		return 0;
20669ac0038dSTim Harvey 	}
20679ac0038dSTim Harvey 
20689ac0038dSTim Harvey 	return -EINVAL;
20699ac0038dSTim Harvey };
20709ac0038dSTim Harvey 
tda1997x_g_volatile_ctrl(struct v4l2_ctrl * ctrl)20719ac0038dSTim Harvey static int tda1997x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
20729ac0038dSTim Harvey {
20739ac0038dSTim Harvey 	struct v4l2_subdev *sd = to_sd(ctrl);
20749ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
20759ac0038dSTim Harvey 
20769ac0038dSTim Harvey 	if (ctrl->id == V4L2_CID_DV_RX_IT_CONTENT_TYPE) {
20779ac0038dSTim Harvey 		ctrl->val = state->avi_infoframe.content_type;
20789ac0038dSTim Harvey 		return 0;
20799ac0038dSTim Harvey 	}
20809ac0038dSTim Harvey 	return -EINVAL;
20819ac0038dSTim Harvey };
20829ac0038dSTim Harvey 
20839ac0038dSTim Harvey static const struct v4l2_ctrl_ops tda1997x_ctrl_ops = {
20849ac0038dSTim Harvey 	.s_ctrl = tda1997x_s_ctrl,
20859ac0038dSTim Harvey 	.g_volatile_ctrl = tda1997x_g_volatile_ctrl,
20869ac0038dSTim Harvey };
20879ac0038dSTim Harvey 
tda1997x_core_init(struct v4l2_subdev * sd)20889ac0038dSTim Harvey static int tda1997x_core_init(struct v4l2_subdev *sd)
20899ac0038dSTim Harvey {
20909ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
20919ac0038dSTim Harvey 	struct tda1997x_platform_data *pdata = &state->pdata;
20929ac0038dSTim Harvey 	u8 reg;
20939ac0038dSTim Harvey 	int i;
20949ac0038dSTim Harvey 
20959ac0038dSTim Harvey 	/* disable HPD */
20969ac0038dSTim Harvey 	io_write(sd, REG_HPD_AUTO_CTRL, HPD_AUTO_HPD_UNSEL);
20979ac0038dSTim Harvey 	if (state->chip_revision == 0) {
20989ac0038dSTim Harvey 		io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_DIS_HDCP | MAN_RST_HDCP);
20999ac0038dSTim Harvey 		io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT);
21009ac0038dSTim Harvey 	}
21019ac0038dSTim Harvey 
21029ac0038dSTim Harvey 	/* reset infoframe at end of start-up-sequencer */
21039ac0038dSTim Harvey 	io_write(sd, REG_SUS_SET_RGB2, 0x06);
21049ac0038dSTim Harvey 	io_write(sd, REG_SUS_SET_RGB3, 0x06);
21059ac0038dSTim Harvey 
21069ac0038dSTim Harvey 	/* Enable TMDS pull-ups */
21079ac0038dSTim Harvey 	io_write(sd, REG_RT_MAN_CTRL, RT_MAN_CTRL_RT |
21089ac0038dSTim Harvey 		 RT_MAN_CTRL_RT_B | RT_MAN_CTRL_RT_A);
21099ac0038dSTim Harvey 
21109ac0038dSTim Harvey 	/* enable sync measurement timing */
21119ac0038dSTim Harvey 	tda1997x_cec_write(sd, REG_PWR_CONTROL & 0xff, 0x04);
21129ac0038dSTim Harvey 	/* adjust CEC clock divider */
21139ac0038dSTim Harvey 	tda1997x_cec_write(sd, REG_OSC_DIVIDER & 0xff, 0x03);
21149ac0038dSTim Harvey 	tda1997x_cec_write(sd, REG_EN_OSC_PERIOD_LSB & 0xff, 0xa0);
21159ac0038dSTim Harvey 	io_write(sd, REG_TIMER_D, 0x54);
21169ac0038dSTim Harvey 	/* enable power switch */
21179ac0038dSTim Harvey 	reg = tda1997x_cec_read(sd, REG_CONTROL & 0xff);
21189ac0038dSTim Harvey 	reg |= 0x20;
21199ac0038dSTim Harvey 	tda1997x_cec_write(sd, REG_CONTROL & 0xff, reg);
21209ac0038dSTim Harvey 	mdelay(50);
21219ac0038dSTim Harvey 
21229ac0038dSTim Harvey 	/* read the chip version */
21239ac0038dSTim Harvey 	reg = io_read(sd, REG_VERSION);
21249ac0038dSTim Harvey 	/* get the chip configuration */
21259ac0038dSTim Harvey 	reg = io_read(sd, REG_CMTP_REG10);
21269ac0038dSTim Harvey 
21279ac0038dSTim Harvey 	/* enable interrupts we care about */
21289ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_TOP,
21299ac0038dSTim Harvey 		 INTERRUPT_HDCP | INTERRUPT_AUDIO | INTERRUPT_INFO |
21309ac0038dSTim Harvey 		 INTERRUPT_RATE | INTERRUPT_SUS);
21319ac0038dSTim Harvey 	/* config_mtp,fmt,sus_end,sus_st */
21329ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_SUS, MASK_MPT | MASK_FMT | MASK_SUS_END);
21339ac0038dSTim Harvey 	/* rate stability change for inputs A/B */
21349ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_RATE, MASK_RATE_B_ST | MASK_RATE_A_ST);
21359ac0038dSTim Harvey 	/* aud,spd,avi*/
21369ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_INFO,
21379ac0038dSTim Harvey 		 MASK_AUD_IF | MASK_SPD_IF | MASK_AVI_IF);
21389ac0038dSTim Harvey 	/* audio_freq,audio_flg,mute_flg,fifo_err */
21399ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_AUDIO,
21409ac0038dSTim Harvey 		 MASK_AUDIO_FREQ_FLG | MASK_AUDIO_FLG | MASK_MUTE_FLG |
21419ac0038dSTim Harvey 		 MASK_ERROR_FIFO_PT);
21429ac0038dSTim Harvey 	/* HDCP C5 state reached */
21439ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_HDCP, MASK_STATE_C5);
21449ac0038dSTim Harvey 	/* 5V detect and HDP pulse end */
21459ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_DDC, MASK_DET_5V);
21469ac0038dSTim Harvey 	/* don't care about AFE/MODE */
21479ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_AFE, 0);
21489ac0038dSTim Harvey 	io_write(sd, REG_INT_MASK_MODE, 0);
21499ac0038dSTim Harvey 
21509ac0038dSTim Harvey 	/* clear all interrupts */
21519ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_TOP, 0xff);
21529ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_SUS, 0xff);
21539ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_DDC, 0xff);
21549ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_RATE, 0xff);
21559ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_MODE, 0xff);
21569ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_INFO, 0xff);
21579ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_AUDIO, 0xff);
21589ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_HDCP, 0xff);
21599ac0038dSTim Harvey 	io_write(sd, REG_INT_FLG_CLR_AFE, 0xff);
21609ac0038dSTim Harvey 
21619ac0038dSTim Harvey 	/* init TMDS equalizer */
21629ac0038dSTim Harvey 	if (state->chip_revision == 0)
21639ac0038dSTim Harvey 		io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT);
21649ac0038dSTim Harvey 	io_write24(sd, REG_CLK_MIN_RATE, CLK_MIN_RATE);
21659ac0038dSTim Harvey 	io_write24(sd, REG_CLK_MAX_RATE, CLK_MAX_RATE);
21669ac0038dSTim Harvey 	if (state->chip_revision == 0)
21679ac0038dSTim Harvey 		io_write(sd, REG_WDL_CFG, WDL_CFG_VAL);
21689ac0038dSTim Harvey 	/* DC filter */
21699ac0038dSTim Harvey 	io_write(sd, REG_DEEP_COLOR_CTRL, DC_FILTER_VAL);
21709ac0038dSTim Harvey 	/* disable test pattern */
21719ac0038dSTim Harvey 	io_write(sd, REG_SVC_MODE, 0x00);
21729ac0038dSTim Harvey 	/* update HDMI INFO CTRL */
21739ac0038dSTim Harvey 	io_write(sd, REG_INFO_CTRL, 0xff);
21749ac0038dSTim Harvey 	/* write HDMI INFO EXCEED value */
21759ac0038dSTim Harvey 	io_write(sd, REG_INFO_EXCEED, 3);
21769ac0038dSTim Harvey 
21779ac0038dSTim Harvey 	if (state->chip_revision == 0)
21789ac0038dSTim Harvey 		tda1997x_reset_n1(state);
21799ac0038dSTim Harvey 
21809ac0038dSTim Harvey 	/*
21819ac0038dSTim Harvey 	 * No HDCP acknowledge when HDCP is disabled
21829ac0038dSTim Harvey 	 * and reset SUS to force format detection
21839ac0038dSTim Harvey 	 */
21849ac0038dSTim Harvey 	tda1997x_hdmi_info_reset(sd, NACK_HDCP, true);
21859ac0038dSTim Harvey 
21869ac0038dSTim Harvey 	/* Set HPD low */
21879ac0038dSTim Harvey 	tda1997x_manual_hpd(sd, HPD_LOW_BP);
21889ac0038dSTim Harvey 
21899ac0038dSTim Harvey 	/* Configure receiver capabilities */
21909ac0038dSTim Harvey 	io_write(sd, REG_HDCP_BCAPS, HDCP_HDMI | HDCP_FAST_REAUTH);
21919ac0038dSTim Harvey 
21929ac0038dSTim Harvey 	/* Configure HDMI: Auto HDCP mode, packet controlled mute */
21939ac0038dSTim Harvey 	reg = HDMI_CTRL_MUTE_AUTO << HDMI_CTRL_MUTE_SHIFT;
21949ac0038dSTim Harvey 	reg |= HDMI_CTRL_HDCP_AUTO << HDMI_CTRL_HDCP_SHIFT;
21959ac0038dSTim Harvey 	io_write(sd, REG_HDMI_CTRL, reg);
21969ac0038dSTim Harvey 
21979ac0038dSTim Harvey 	/* reset start-up-sequencer to force format detection */
21989ac0038dSTim Harvey 	tda1997x_hdmi_info_reset(sd, 0, true);
21999ac0038dSTim Harvey 
22009ac0038dSTim Harvey 	/* disable matrix conversion */
22019ac0038dSTim Harvey 	reg = io_read(sd, REG_VDP_CTRL);
22029ac0038dSTim Harvey 	reg |= VDP_CTRL_MATRIX_BP;
22039ac0038dSTim Harvey 	io_write(sd, REG_VDP_CTRL, reg);
22049ac0038dSTim Harvey 
22059ac0038dSTim Harvey 	/* set video output mode */
22069ac0038dSTim Harvey 	tda1997x_configure_vidout(state);
22079ac0038dSTim Harvey 
22089ac0038dSTim Harvey 	/* configure video output port */
22099ac0038dSTim Harvey 	for (i = 0; i < 9; i++) {
22109ac0038dSTim Harvey 		v4l_dbg(1, debug, state->client, "vidout_cfg[%d]=0x%02x\n", i,
22119ac0038dSTim Harvey 			pdata->vidout_port_cfg[i]);
22129ac0038dSTim Harvey 		io_write(sd, REG_VP35_32_CTRL + i, pdata->vidout_port_cfg[i]);
22139ac0038dSTim Harvey 	}
22149ac0038dSTim Harvey 
22159ac0038dSTim Harvey 	/* configure audio output port */
22169ac0038dSTim Harvey 	tda1997x_configure_audout(sd, 0);
22179ac0038dSTim Harvey 
22189ac0038dSTim Harvey 	/* configure audio clock freq */
22199ac0038dSTim Harvey 	switch (pdata->audout_mclk_fs) {
22209ac0038dSTim Harvey 	case 512:
22219ac0038dSTim Harvey 		reg = AUDIO_CLOCK_SEL_512FS;
22229ac0038dSTim Harvey 		break;
22239ac0038dSTim Harvey 	case 256:
22249ac0038dSTim Harvey 		reg = AUDIO_CLOCK_SEL_256FS;
22259ac0038dSTim Harvey 		break;
22269ac0038dSTim Harvey 	case 128:
22279ac0038dSTim Harvey 		reg = AUDIO_CLOCK_SEL_128FS;
22289ac0038dSTim Harvey 		break;
22299ac0038dSTim Harvey 	case 64:
22309ac0038dSTim Harvey 		reg = AUDIO_CLOCK_SEL_64FS;
22319ac0038dSTim Harvey 		break;
22329ac0038dSTim Harvey 	case 32:
22339ac0038dSTim Harvey 		reg = AUDIO_CLOCK_SEL_32FS;
22349ac0038dSTim Harvey 		break;
22359ac0038dSTim Harvey 	default:
22369ac0038dSTim Harvey 		reg = AUDIO_CLOCK_SEL_16FS;
22379ac0038dSTim Harvey 		break;
22389ac0038dSTim Harvey 	}
22399ac0038dSTim Harvey 	io_write(sd, REG_AUDIO_CLOCK, reg);
22409ac0038dSTim Harvey 
22419ac0038dSTim Harvey 	/* reset advanced infoframes (ISRC1/ISRC2/ACP) */
22429ac0038dSTim Harvey 	tda1997x_hdmi_info_reset(sd, RESET_AI, false);
22439ac0038dSTim Harvey 	/* reset infoframe */
22449ac0038dSTim Harvey 	tda1997x_hdmi_info_reset(sd, RESET_IF, false);
22459ac0038dSTim Harvey 	/* reset audio infoframes */
22469ac0038dSTim Harvey 	tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false);
22479ac0038dSTim Harvey 	/* reset gamut */
22489ac0038dSTim Harvey 	tda1997x_hdmi_info_reset(sd, RESET_GAMUT, false);
22499ac0038dSTim Harvey 
22509ac0038dSTim Harvey 	/* get initial HDMI status */
22519ac0038dSTim Harvey 	state->hdmi_status = io_read(sd, REG_HDMI_FLAGS);
22529ac0038dSTim Harvey 
2253ea3e1c36SKrzysztof Hałasa 	io_write(sd, REG_EDID_ENABLE, EDID_ENABLE_A_EN | EDID_ENABLE_B_EN);
22549ac0038dSTim Harvey 	return 0;
22559ac0038dSTim Harvey }
22569ac0038dSTim Harvey 
tda1997x_set_power(struct tda1997x_state * state,bool on)22579ac0038dSTim Harvey static int tda1997x_set_power(struct tda1997x_state *state, bool on)
22589ac0038dSTim Harvey {
22599ac0038dSTim Harvey 	int ret = 0;
22609ac0038dSTim Harvey 
22619ac0038dSTim Harvey 	if (on) {
22629ac0038dSTim Harvey 		ret = regulator_bulk_enable(TDA1997X_NUM_SUPPLIES,
22639ac0038dSTim Harvey 					     state->supplies);
22649ac0038dSTim Harvey 		msleep(300);
22659ac0038dSTim Harvey 	} else {
22669ac0038dSTim Harvey 		ret = regulator_bulk_disable(TDA1997X_NUM_SUPPLIES,
22679ac0038dSTim Harvey 					     state->supplies);
22689ac0038dSTim Harvey 	}
22699ac0038dSTim Harvey 
22709ac0038dSTim Harvey 	return ret;
22719ac0038dSTim Harvey }
22729ac0038dSTim Harvey 
22739ac0038dSTim Harvey static const struct i2c_device_id tda1997x_i2c_id[] = {
22749ac0038dSTim Harvey 	{"tda19971", (kernel_ulong_t)&tda1997x_chip_info[TDA19971]},
22759ac0038dSTim Harvey 	{"tda19973", (kernel_ulong_t)&tda1997x_chip_info[TDA19973]},
22769ac0038dSTim Harvey 	{ },
22779ac0038dSTim Harvey };
22789ac0038dSTim Harvey MODULE_DEVICE_TABLE(i2c, tda1997x_i2c_id);
22799ac0038dSTim Harvey 
22809ac0038dSTim Harvey static const struct of_device_id tda1997x_of_id[] __maybe_unused = {
22819ac0038dSTim Harvey 	{ .compatible = "nxp,tda19971", .data = &tda1997x_chip_info[TDA19971] },
22829ac0038dSTim Harvey 	{ .compatible = "nxp,tda19973", .data = &tda1997x_chip_info[TDA19973] },
22839ac0038dSTim Harvey 	{ },
22849ac0038dSTim Harvey };
22859ac0038dSTim Harvey MODULE_DEVICE_TABLE(of, tda1997x_of_id);
22869ac0038dSTim Harvey 
tda1997x_parse_dt(struct tda1997x_state * state)22879ac0038dSTim Harvey static int tda1997x_parse_dt(struct tda1997x_state *state)
22889ac0038dSTim Harvey {
22899ac0038dSTim Harvey 	struct tda1997x_platform_data *pdata = &state->pdata;
229060359a28SSakari Ailus 	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
22919ac0038dSTim Harvey 	struct device_node *ep;
22929ac0038dSTim Harvey 	struct device_node *np;
22939ac0038dSTim Harvey 	unsigned int flags;
22949ac0038dSTim Harvey 	const char *str;
22959ac0038dSTim Harvey 	int ret;
22969ac0038dSTim Harvey 	u32 v;
22979ac0038dSTim Harvey 
22989ac0038dSTim Harvey 	/*
22999ac0038dSTim Harvey 	 * setup default values:
23009ac0038dSTim Harvey 	 * - HREF: active high from start to end of row
23019ac0038dSTim Harvey 	 * - VS: Vertical Sync active high at beginning of frame
23029ac0038dSTim Harvey 	 * - DE: Active high when data valid
23039ac0038dSTim Harvey 	 * - A_CLK: 128*Fs
23049ac0038dSTim Harvey 	 */
23059ac0038dSTim Harvey 	pdata->vidout_sel_hs = HS_HREF_SEL_HREF_VHREF;
23069ac0038dSTim Harvey 	pdata->vidout_sel_vs = VS_VREF_SEL_VREF_HDMI;
23079ac0038dSTim Harvey 	pdata->vidout_sel_de = DE_FREF_SEL_DE_VHREF;
23089ac0038dSTim Harvey 
23099ac0038dSTim Harvey 	np = state->client->dev.of_node;
23109ac0038dSTim Harvey 	ep = of_graph_get_next_endpoint(np, NULL);
23119ac0038dSTim Harvey 	if (!ep)
23129ac0038dSTim Harvey 		return -EINVAL;
23139ac0038dSTim Harvey 
23149ac0038dSTim Harvey 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
23159ac0038dSTim Harvey 	if (ret) {
23169ac0038dSTim Harvey 		of_node_put(ep);
23179ac0038dSTim Harvey 		return ret;
23189ac0038dSTim Harvey 	}
23199ac0038dSTim Harvey 	of_node_put(ep);
23209ac0038dSTim Harvey 	pdata->vidout_bus_type = bus_cfg.bus_type;
23219ac0038dSTim Harvey 
23229ac0038dSTim Harvey 	/* polarity of HS/VS/DE */
23239ac0038dSTim Harvey 	flags = bus_cfg.bus.parallel.flags;
23249ac0038dSTim Harvey 	if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
23259ac0038dSTim Harvey 		pdata->vidout_inv_hs = 1;
23269ac0038dSTim Harvey 	if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
23279ac0038dSTim Harvey 		pdata->vidout_inv_vs = 1;
23289ac0038dSTim Harvey 	if (flags & V4L2_MBUS_DATA_ACTIVE_LOW)
23299ac0038dSTim Harvey 		pdata->vidout_inv_de = 1;
23309ac0038dSTim Harvey 	pdata->vidout_bus_width = bus_cfg.bus.parallel.bus_width;
23319ac0038dSTim Harvey 
23329ac0038dSTim Harvey 	/* video output port config */
23339ac0038dSTim Harvey 	ret = of_property_count_u32_elems(np, "nxp,vidout-portcfg");
23349ac0038dSTim Harvey 	if (ret > 0) {
23359ac0038dSTim Harvey 		u32 reg, val, i;
23369ac0038dSTim Harvey 
23379ac0038dSTim Harvey 		for (i = 0; i < ret / 2 && i < 9; i++) {
23389ac0038dSTim Harvey 			of_property_read_u32_index(np, "nxp,vidout-portcfg",
23399ac0038dSTim Harvey 						   i * 2, &reg);
23409ac0038dSTim Harvey 			of_property_read_u32_index(np, "nxp,vidout-portcfg",
23419ac0038dSTim Harvey 						   i * 2 + 1, &val);
23429ac0038dSTim Harvey 			if (reg < 9)
23439ac0038dSTim Harvey 				pdata->vidout_port_cfg[reg] = val;
23449ac0038dSTim Harvey 		}
23459ac0038dSTim Harvey 	} else {
23469ac0038dSTim Harvey 		v4l_err(state->client, "nxp,vidout-portcfg missing\n");
23479ac0038dSTim Harvey 		return -EINVAL;
23489ac0038dSTim Harvey 	}
23499ac0038dSTim Harvey 
23509ac0038dSTim Harvey 	/* default to channel layout dictated by packet header */
23519ac0038dSTim Harvey 	pdata->audout_layoutauto = true;
23529ac0038dSTim Harvey 
23539ac0038dSTim Harvey 	pdata->audout_format = AUDFMT_TYPE_DISABLED;
23549ac0038dSTim Harvey 	if (!of_property_read_string(np, "nxp,audout-format", &str)) {
23559ac0038dSTim Harvey 		if (strcmp(str, "i2s") == 0)
23569ac0038dSTim Harvey 			pdata->audout_format = AUDFMT_TYPE_I2S;
23579ac0038dSTim Harvey 		else if (strcmp(str, "spdif") == 0)
23589ac0038dSTim Harvey 			pdata->audout_format = AUDFMT_TYPE_SPDIF;
23599ac0038dSTim Harvey 		else {
23609ac0038dSTim Harvey 			v4l_err(state->client, "nxp,audout-format invalid\n");
23619ac0038dSTim Harvey 			return -EINVAL;
23629ac0038dSTim Harvey 		}
23639ac0038dSTim Harvey 		if (!of_property_read_u32(np, "nxp,audout-layout", &v)) {
23649ac0038dSTim Harvey 			switch (v) {
23659ac0038dSTim Harvey 			case 0:
23669ac0038dSTim Harvey 			case 1:
23679ac0038dSTim Harvey 				break;
23689ac0038dSTim Harvey 			default:
23699ac0038dSTim Harvey 				v4l_err(state->client,
23709ac0038dSTim Harvey 					"nxp,audout-layout invalid\n");
23719ac0038dSTim Harvey 				return -EINVAL;
23729ac0038dSTim Harvey 			}
23739ac0038dSTim Harvey 			pdata->audout_layout = v;
23749ac0038dSTim Harvey 		}
23759ac0038dSTim Harvey 		if (!of_property_read_u32(np, "nxp,audout-width", &v)) {
23769ac0038dSTim Harvey 			switch (v) {
23779ac0038dSTim Harvey 			case 16:
23789ac0038dSTim Harvey 			case 32:
23799ac0038dSTim Harvey 				break;
23809ac0038dSTim Harvey 			default:
23819ac0038dSTim Harvey 				v4l_err(state->client,
23829ac0038dSTim Harvey 					"nxp,audout-width invalid\n");
23839ac0038dSTim Harvey 				return -EINVAL;
23849ac0038dSTim Harvey 			}
23859ac0038dSTim Harvey 			pdata->audout_width = v;
23869ac0038dSTim Harvey 		}
23879ac0038dSTim Harvey 		if (!of_property_read_u32(np, "nxp,audout-mclk-fs", &v)) {
23889ac0038dSTim Harvey 			switch (v) {
23899ac0038dSTim Harvey 			case 512:
23909ac0038dSTim Harvey 			case 256:
23919ac0038dSTim Harvey 			case 128:
23929ac0038dSTim Harvey 			case 64:
23939ac0038dSTim Harvey 			case 32:
23949ac0038dSTim Harvey 			case 16:
23959ac0038dSTim Harvey 				break;
23969ac0038dSTim Harvey 			default:
23979ac0038dSTim Harvey 				v4l_err(state->client,
23989ac0038dSTim Harvey 					"nxp,audout-mclk-fs invalid\n");
23999ac0038dSTim Harvey 				return -EINVAL;
24009ac0038dSTim Harvey 			}
24019ac0038dSTim Harvey 			pdata->audout_mclk_fs = v;
24029ac0038dSTim Harvey 		}
24039ac0038dSTim Harvey 	}
24049ac0038dSTim Harvey 
24059ac0038dSTim Harvey 	return 0;
24069ac0038dSTim Harvey }
24079ac0038dSTim Harvey 
tda1997x_get_regulators(struct tda1997x_state * state)24089ac0038dSTim Harvey static int tda1997x_get_regulators(struct tda1997x_state *state)
24099ac0038dSTim Harvey {
24109ac0038dSTim Harvey 	int i;
24119ac0038dSTim Harvey 
24129ac0038dSTim Harvey 	for (i = 0; i < TDA1997X_NUM_SUPPLIES; i++)
24139ac0038dSTim Harvey 		state->supplies[i].supply = tda1997x_supply_name[i];
24149ac0038dSTim Harvey 
24159ac0038dSTim Harvey 	return devm_regulator_bulk_get(&state->client->dev,
24169ac0038dSTim Harvey 				       TDA1997X_NUM_SUPPLIES,
24179ac0038dSTim Harvey 				       state->supplies);
24189ac0038dSTim Harvey }
24199ac0038dSTim Harvey 
tda1997x_identify_module(struct tda1997x_state * state)24209ac0038dSTim Harvey static int tda1997x_identify_module(struct tda1997x_state *state)
24219ac0038dSTim Harvey {
24229ac0038dSTim Harvey 	struct v4l2_subdev *sd = &state->sd;
24239ac0038dSTim Harvey 	enum tda1997x_type type;
24249ac0038dSTim Harvey 	u8 reg;
24259ac0038dSTim Harvey 
24269ac0038dSTim Harvey 	/* Read chip configuration*/
24279ac0038dSTim Harvey 	reg = io_read(sd, REG_CMTP_REG10);
24289ac0038dSTim Harvey 	state->tmdsb_clk = (reg >> 6) & 0x01; /* use tmds clock B_inv for B */
24299ac0038dSTim Harvey 	state->tmdsb_soc = (reg >> 5) & 0x01; /* tmds of input B */
24309ac0038dSTim Harvey 	state->port_30bit = (reg >> 2) & 0x03; /* 30bit vs 24bit */
24319ac0038dSTim Harvey 	state->output_2p5 = (reg >> 1) & 0x01; /* output supply 2.5v */
24329ac0038dSTim Harvey 	switch ((reg >> 4) & 0x03) {
24339ac0038dSTim Harvey 	case 0x00:
24349ac0038dSTim Harvey 		type = TDA19971;
24359ac0038dSTim Harvey 		break;
24369ac0038dSTim Harvey 	case 0x02:
24379ac0038dSTim Harvey 	case 0x03:
24389ac0038dSTim Harvey 		type = TDA19973;
24399ac0038dSTim Harvey 		break;
24409ac0038dSTim Harvey 	default:
24419ac0038dSTim Harvey 		dev_err(&state->client->dev, "unsupported chip ID\n");
24429ac0038dSTim Harvey 		return -EIO;
24439ac0038dSTim Harvey 	}
24449ac0038dSTim Harvey 	if (state->info->type != type) {
24459ac0038dSTim Harvey 		dev_err(&state->client->dev, "chip id mismatch\n");
24469ac0038dSTim Harvey 		return -EIO;
24479ac0038dSTim Harvey 	}
24489ac0038dSTim Harvey 
24499ac0038dSTim Harvey 	/* read chip revision */
24509ac0038dSTim Harvey 	state->chip_revision = io_read(sd, REG_CMTP_REG11);
24519ac0038dSTim Harvey 
24529ac0038dSTim Harvey 	return 0;
24539ac0038dSTim Harvey }
24549ac0038dSTim Harvey 
24559ac0038dSTim Harvey static const struct media_entity_operations tda1997x_media_ops = {
24569ac0038dSTim Harvey 	.link_validate = v4l2_subdev_link_validate,
24579ac0038dSTim Harvey };
24589ac0038dSTim Harvey 
24599ac0038dSTim Harvey 
24609ac0038dSTim Harvey /* -----------------------------------------------------------------------------
24619ac0038dSTim Harvey  * HDMI Audio Codec
24629ac0038dSTim Harvey  */
24639ac0038dSTim Harvey 
24649ac0038dSTim Harvey /* refine sample-rate based on HDMI source */
tda1997x_pcm_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)24659ac0038dSTim Harvey static int tda1997x_pcm_startup(struct snd_pcm_substream *substream,
24669ac0038dSTim Harvey 				struct snd_soc_dai *dai)
24679ac0038dSTim Harvey {
24688d246e29SKrzysztof Hałasa 	struct v4l2_subdev *sd = snd_soc_dai_get_drvdata(dai);
24698d246e29SKrzysztof Hałasa 	struct tda1997x_state *state = to_state(sd);
24702d8102ccSKuninori Morimoto 	struct snd_soc_component *component = dai->component;
24719ac0038dSTim Harvey 	struct snd_pcm_runtime *rtd = substream->runtime;
24729ac0038dSTim Harvey 	int rate, err;
24739ac0038dSTim Harvey 
24749ac0038dSTim Harvey 	rate = state->audio_samplerate;
24759ac0038dSTim Harvey 	err = snd_pcm_hw_constraint_minmax(rtd, SNDRV_PCM_HW_PARAM_RATE,
24769ac0038dSTim Harvey 					   rate, rate);
24779ac0038dSTim Harvey 	if (err < 0) {
24782d8102ccSKuninori Morimoto 		dev_err(component->dev, "failed to constrain samplerate to %dHz\n",
24799ac0038dSTim Harvey 			rate);
24809ac0038dSTim Harvey 		return err;
24819ac0038dSTim Harvey 	}
24822d8102ccSKuninori Morimoto 	dev_info(component->dev, "set samplerate constraint to %dHz\n", rate);
24839ac0038dSTim Harvey 
24849ac0038dSTim Harvey 	return 0;
24859ac0038dSTim Harvey }
24869ac0038dSTim Harvey 
24879ac0038dSTim Harvey static const struct snd_soc_dai_ops tda1997x_dai_ops = {
24889ac0038dSTim Harvey 	.startup = tda1997x_pcm_startup,
24899ac0038dSTim Harvey };
24909ac0038dSTim Harvey 
24919ac0038dSTim Harvey static struct snd_soc_dai_driver tda1997x_audio_dai = {
24929ac0038dSTim Harvey 	.name = "tda1997x",
24939ac0038dSTim Harvey 	.capture = {
24949ac0038dSTim Harvey 		.stream_name = "Capture",
24959ac0038dSTim Harvey 		.channels_min = 2,
24969ac0038dSTim Harvey 		.channels_max = 8,
24979ac0038dSTim Harvey 		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
24989ac0038dSTim Harvey 			 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
24999ac0038dSTim Harvey 			 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
25009ac0038dSTim Harvey 			 SNDRV_PCM_RATE_192000,
25019ac0038dSTim Harvey 	},
25029ac0038dSTim Harvey 	.ops = &tda1997x_dai_ops,
25039ac0038dSTim Harvey };
25049ac0038dSTim Harvey 
tda1997x_codec_probe(struct snd_soc_component * component)25052d8102ccSKuninori Morimoto static int tda1997x_codec_probe(struct snd_soc_component *component)
25069ac0038dSTim Harvey {
25079ac0038dSTim Harvey 	return 0;
25089ac0038dSTim Harvey }
25099ac0038dSTim Harvey 
tda1997x_codec_remove(struct snd_soc_component * component)25102d8102ccSKuninori Morimoto static void tda1997x_codec_remove(struct snd_soc_component *component)
25119ac0038dSTim Harvey {
25129ac0038dSTim Harvey }
25139ac0038dSTim Harvey 
25142d8102ccSKuninori Morimoto static struct snd_soc_component_driver tda1997x_codec_driver = {
25159ac0038dSTim Harvey 	.probe			= tda1997x_codec_probe,
25169ac0038dSTim Harvey 	.remove			= tda1997x_codec_remove,
25172d8102ccSKuninori Morimoto 	.idle_bias_on		= 1,
25182d8102ccSKuninori Morimoto 	.use_pmdown_time	= 1,
25192d8102ccSKuninori Morimoto 	.endianness		= 1,
25209ac0038dSTim Harvey };
25219ac0038dSTim Harvey 
tda1997x_probe(struct i2c_client * client)252276b6ae7dSUwe Kleine-König static int tda1997x_probe(struct i2c_client *client)
25239ac0038dSTim Harvey {
252476b6ae7dSUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
25259ac0038dSTim Harvey 	struct tda1997x_state *state;
25269ac0038dSTim Harvey 	struct tda1997x_platform_data *pdata;
25279ac0038dSTim Harvey 	struct v4l2_subdev *sd;
25289ac0038dSTim Harvey 	struct v4l2_ctrl_handler *hdl;
25299ac0038dSTim Harvey 	struct v4l2_ctrl *ctrl;
25309ac0038dSTim Harvey 	static const struct v4l2_dv_timings cea1920x1080 =
25319ac0038dSTim Harvey 		V4L2_DV_BT_CEA_1920X1080P60;
25329ac0038dSTim Harvey 	u32 *mbus_codes;
25339ac0038dSTim Harvey 	int i, ret;
25349ac0038dSTim Harvey 
25359ac0038dSTim Harvey 	/* Check if the adapter supports the needed features */
25369ac0038dSTim Harvey 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
25379ac0038dSTim Harvey 		return -EIO;
25389ac0038dSTim Harvey 
25399ac0038dSTim Harvey 	state = kzalloc(sizeof(struct tda1997x_state), GFP_KERNEL);
25409ac0038dSTim Harvey 	if (!state)
25419ac0038dSTim Harvey 		return -ENOMEM;
25429ac0038dSTim Harvey 
25439ac0038dSTim Harvey 	state->client = client;
25449ac0038dSTim Harvey 	pdata = &state->pdata;
25459ac0038dSTim Harvey 	if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) {
25469ac0038dSTim Harvey 		const struct of_device_id *oid;
25479ac0038dSTim Harvey 
25489ac0038dSTim Harvey 		oid = of_match_node(tda1997x_of_id, client->dev.of_node);
25499ac0038dSTim Harvey 		state->info = oid->data;
25509ac0038dSTim Harvey 
25519ac0038dSTim Harvey 		ret = tda1997x_parse_dt(state);
25529ac0038dSTim Harvey 		if (ret < 0) {
25539ac0038dSTim Harvey 			v4l_err(client, "DT parsing error\n");
25549ac0038dSTim Harvey 			goto err_free_state;
25559ac0038dSTim Harvey 		}
25569ac0038dSTim Harvey 	} else if (client->dev.platform_data) {
25579ac0038dSTim Harvey 		struct tda1997x_platform_data *pdata =
25589ac0038dSTim Harvey 			client->dev.platform_data;
25599ac0038dSTim Harvey 		state->info =
25609ac0038dSTim Harvey 			(const struct tda1997x_chip_info *)id->driver_data;
25619ac0038dSTim Harvey 		state->pdata = *pdata;
25629ac0038dSTim Harvey 	} else {
25639ac0038dSTim Harvey 		v4l_err(client, "No platform data\n");
25649ac0038dSTim Harvey 		ret = -ENODEV;
25659ac0038dSTim Harvey 		goto err_free_state;
25669ac0038dSTim Harvey 	}
25679ac0038dSTim Harvey 
25689ac0038dSTim Harvey 	ret = tda1997x_get_regulators(state);
25699ac0038dSTim Harvey 	if (ret)
25709ac0038dSTim Harvey 		goto err_free_state;
25719ac0038dSTim Harvey 
25729ac0038dSTim Harvey 	ret = tda1997x_set_power(state, 1);
25739ac0038dSTim Harvey 	if (ret)
25749ac0038dSTim Harvey 		goto err_free_state;
25759ac0038dSTim Harvey 
25769ac0038dSTim Harvey 	mutex_init(&state->page_lock);
25779ac0038dSTim Harvey 	mutex_init(&state->lock);
25789ac0038dSTim Harvey 	state->page = 0xff;
25799ac0038dSTim Harvey 
25809ac0038dSTim Harvey 	INIT_DELAYED_WORK(&state->delayed_work_enable_hpd,
25819ac0038dSTim Harvey 			  tda1997x_delayed_work_enable_hpd);
25829ac0038dSTim Harvey 
25839ac0038dSTim Harvey 	/* set video format based on chip and bus width */
25849ac0038dSTim Harvey 	ret = tda1997x_identify_module(state);
25859ac0038dSTim Harvey 	if (ret)
25869ac0038dSTim Harvey 		goto err_free_mutex;
25879ac0038dSTim Harvey 
25889ac0038dSTim Harvey 	/* initialize subdev */
25899ac0038dSTim Harvey 	sd = &state->sd;
25909ac0038dSTim Harvey 	v4l2_i2c_subdev_init(sd, client, &tda1997x_subdev_ops);
25919ac0038dSTim Harvey 	snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
25929ac0038dSTim Harvey 		 id->name, i2c_adapter_id(client->adapter),
25939ac0038dSTim Harvey 		 client->addr);
25945cd770f6SSakari Ailus 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
2595d272bc92SHans Verkuil 	sd->entity.function = MEDIA_ENT_F_DV_DECODER;
25969ac0038dSTim Harvey 	sd->entity.ops = &tda1997x_media_ops;
25979ac0038dSTim Harvey 
25989ac0038dSTim Harvey 	/* set allowed mbus modes based on chip, bus-type, and bus-width */
25999ac0038dSTim Harvey 	i = 0;
26009ac0038dSTim Harvey 	mbus_codes = state->mbus_codes;
26019ac0038dSTim Harvey 	switch (state->info->type) {
26029ac0038dSTim Harvey 	case TDA19973:
26039ac0038dSTim Harvey 		switch (pdata->vidout_bus_type) {
26049ac0038dSTim Harvey 		case V4L2_MBUS_PARALLEL:
26059ac0038dSTim Harvey 			switch (pdata->vidout_bus_width) {
26069ac0038dSTim Harvey 			case 36:
26079ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
26089ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_YUV12_1X36;
26091771e9fbSGustavo A. R. Silva 				fallthrough;
26109ac0038dSTim Harvey 			case 24:
26119ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
26129ac0038dSTim Harvey 				break;
26139ac0038dSTim Harvey 			}
26149ac0038dSTim Harvey 			break;
26159ac0038dSTim Harvey 		case V4L2_MBUS_BT656:
26169ac0038dSTim Harvey 			switch (pdata->vidout_bus_width) {
26179ac0038dSTim Harvey 			case 36:
26189ac0038dSTim Harvey 			case 24:
26199ac0038dSTim Harvey 			case 12:
26209ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12;
26219ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10;
26229ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8;
26239ac0038dSTim Harvey 				break;
26249ac0038dSTim Harvey 			}
26259ac0038dSTim Harvey 			break;
26269ac0038dSTim Harvey 		default:
26279ac0038dSTim Harvey 			break;
26289ac0038dSTim Harvey 		}
26299ac0038dSTim Harvey 		break;
26309ac0038dSTim Harvey 	case TDA19971:
26319ac0038dSTim Harvey 		switch (pdata->vidout_bus_type) {
26329ac0038dSTim Harvey 		case V4L2_MBUS_PARALLEL:
26339ac0038dSTim Harvey 			switch (pdata->vidout_bus_width) {
26349ac0038dSTim Harvey 			case 24:
26359ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_RGB888_1X24;
26369ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_YUV8_1X24;
26379ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
26381771e9fbSGustavo A. R. Silva 				fallthrough;
26399ac0038dSTim Harvey 			case 20:
26409ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
26411771e9fbSGustavo A. R. Silva 				fallthrough;
26429ac0038dSTim Harvey 			case 16:
26439ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
26449ac0038dSTim Harvey 				break;
26459ac0038dSTim Harvey 			}
26469ac0038dSTim Harvey 			break;
26479ac0038dSTim Harvey 		case V4L2_MBUS_BT656:
26489ac0038dSTim Harvey 			switch (pdata->vidout_bus_width) {
26499ac0038dSTim Harvey 			case 24:
26509ac0038dSTim Harvey 			case 20:
26519ac0038dSTim Harvey 			case 16:
26529ac0038dSTim Harvey 			case 12:
26539ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12;
26541771e9fbSGustavo A. R. Silva 				fallthrough;
26559ac0038dSTim Harvey 			case 10:
26569ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10;
26571771e9fbSGustavo A. R. Silva 				fallthrough;
26589ac0038dSTim Harvey 			case 8:
26599ac0038dSTim Harvey 				mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8;
26609ac0038dSTim Harvey 				break;
26619ac0038dSTim Harvey 			}
26629ac0038dSTim Harvey 			break;
26639ac0038dSTim Harvey 		default:
26649ac0038dSTim Harvey 			break;
26659ac0038dSTim Harvey 		}
26669ac0038dSTim Harvey 		break;
26679ac0038dSTim Harvey 	}
26689ac0038dSTim Harvey 	if (WARN_ON(i > ARRAY_SIZE(state->mbus_codes))) {
26699ac0038dSTim Harvey 		ret = -EINVAL;
26709ac0038dSTim Harvey 		goto err_free_mutex;
26719ac0038dSTim Harvey 	}
26729ac0038dSTim Harvey 
26739ac0038dSTim Harvey 	/* default format */
26749ac0038dSTim Harvey 	tda1997x_setup_format(state, state->mbus_codes[0]);
26759ac0038dSTim Harvey 	state->timings = cea1920x1080;
26769ac0038dSTim Harvey 
26779ac0038dSTim Harvey 	/*
26789ac0038dSTim Harvey 	 * default to SRGB full range quantization
26799ac0038dSTim Harvey 	 * (in case we don't get an infoframe such as DVI signal
26809ac0038dSTim Harvey 	 */
26819ac0038dSTim Harvey 	state->colorimetry.colorspace = V4L2_COLORSPACE_SRGB;
26829ac0038dSTim Harvey 	state->colorimetry.quantization = V4L2_QUANTIZATION_FULL_RANGE;
26839ac0038dSTim Harvey 
26849ac0038dSTim Harvey 	/* disable/reset HDCP to get correct I2C access to Rx HDMI */
26859ac0038dSTim Harvey 	io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_RST_HDCP | MAN_DIS_HDCP);
26869ac0038dSTim Harvey 
26879ac0038dSTim Harvey 	/*
26889ac0038dSTim Harvey 	 * if N2 version, reset compdel_bp as it may generate some small pixel
26899ac0038dSTim Harvey 	 * shifts in case of embedded sync/or delay lower than 4
26909ac0038dSTim Harvey 	 */
26919ac0038dSTim Harvey 	if (state->chip_revision != 0) {
26929ac0038dSTim Harvey 		io_write(sd, REG_MAN_SUS_HDMI_SEL, 0x00);
26939ac0038dSTim Harvey 		io_write(sd, REG_VDP_CTRL, 0x1f);
26949ac0038dSTim Harvey 	}
26959ac0038dSTim Harvey 
26969ac0038dSTim Harvey 	v4l_info(client, "NXP %s N%d detected\n", state->info->name,
26979ac0038dSTim Harvey 		 state->chip_revision + 1);
26989ac0038dSTim Harvey 	v4l_info(client, "video: %dbit %s %d formats available\n",
26999ac0038dSTim Harvey 		pdata->vidout_bus_width,
27009ac0038dSTim Harvey 		(pdata->vidout_bus_type == V4L2_MBUS_PARALLEL) ?
27019ac0038dSTim Harvey 			"parallel" : "BT656",
27029ac0038dSTim Harvey 		i);
27039ac0038dSTim Harvey 	if (pdata->audout_format) {
27049ac0038dSTim Harvey 		v4l_info(client, "audio: %dch %s layout%d sysclk=%d*fs\n",
27059ac0038dSTim Harvey 			 pdata->audout_layout ? 2 : 8,
27069ac0038dSTim Harvey 			 audfmt_names[pdata->audout_format],
27079ac0038dSTim Harvey 			 pdata->audout_layout,
27089ac0038dSTim Harvey 			 pdata->audout_mclk_fs);
27099ac0038dSTim Harvey 	}
27109ac0038dSTim Harvey 
27119ac0038dSTim Harvey 	ret = 0x34 + ((io_read(sd, REG_SLAVE_ADDR)>>4) & 0x03);
27122f822f1dSWolfram Sang 	state->client_cec = devm_i2c_new_dummy_device(&client->dev,
27132f822f1dSWolfram Sang 						      client->adapter, ret);
27142f822f1dSWolfram Sang 	if (IS_ERR(state->client_cec)) {
27152f822f1dSWolfram Sang 		ret = PTR_ERR(state->client_cec);
27162f822f1dSWolfram Sang 		goto err_free_mutex;
27172f822f1dSWolfram Sang 	}
27182f822f1dSWolfram Sang 
27199ac0038dSTim Harvey 	v4l_info(client, "CEC slave address 0x%02x\n", ret);
27209ac0038dSTim Harvey 
27219ac0038dSTim Harvey 	ret = tda1997x_core_init(sd);
27229ac0038dSTim Harvey 	if (ret)
27239ac0038dSTim Harvey 		goto err_free_mutex;
27249ac0038dSTim Harvey 
27259ac0038dSTim Harvey 	/* control handlers */
27269ac0038dSTim Harvey 	hdl = &state->hdl;
27279ac0038dSTim Harvey 	v4l2_ctrl_handler_init(hdl, 3);
27289ac0038dSTim Harvey 	ctrl = v4l2_ctrl_new_std_menu(hdl, &tda1997x_ctrl_ops,
27299ac0038dSTim Harvey 			V4L2_CID_DV_RX_IT_CONTENT_TYPE,
27309ac0038dSTim Harvey 			V4L2_DV_IT_CONTENT_TYPE_NO_ITC, 0,
27319ac0038dSTim Harvey 			V4L2_DV_IT_CONTENT_TYPE_NO_ITC);
27329ac0038dSTim Harvey 	if (ctrl)
27339ac0038dSTim Harvey 		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
27349ac0038dSTim Harvey 	/* custom controls */
27359ac0038dSTim Harvey 	state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
27369ac0038dSTim Harvey 			V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
27379ac0038dSTim Harvey 	state->rgb_quantization_range_ctrl = v4l2_ctrl_new_std_menu(hdl,
27389ac0038dSTim Harvey 			&tda1997x_ctrl_ops,
27399ac0038dSTim Harvey 			V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0,
27409ac0038dSTim Harvey 			V4L2_DV_RGB_RANGE_AUTO);
27419ac0038dSTim Harvey 	state->sd.ctrl_handler = hdl;
27429ac0038dSTim Harvey 	if (hdl->error) {
27439ac0038dSTim Harvey 		ret = hdl->error;
27449ac0038dSTim Harvey 		goto err_free_handler;
27459ac0038dSTim Harvey 	}
27469ac0038dSTim Harvey 	v4l2_ctrl_handler_setup(hdl);
27479ac0038dSTim Harvey 
27489ac0038dSTim Harvey 	/* initialize source pads */
27499ac0038dSTim Harvey 	state->pads[TDA1997X_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
27509ac0038dSTim Harvey 	ret = media_entity_pads_init(&sd->entity, TDA1997X_NUM_PADS,
27519ac0038dSTim Harvey 		state->pads);
27529ac0038dSTim Harvey 	if (ret) {
27539ac0038dSTim Harvey 		v4l_err(client, "failed entity_init: %d", ret);
275450a0efaeSChristophe JAILLET 		goto err_free_handler;
27559ac0038dSTim Harvey 	}
27569ac0038dSTim Harvey 
27579ac0038dSTim Harvey 	ret = v4l2_async_register_subdev(sd);
27589ac0038dSTim Harvey 	if (ret)
27599ac0038dSTim Harvey 		goto err_free_media;
27609ac0038dSTim Harvey 
27619ac0038dSTim Harvey 	/* register audio DAI */
27629ac0038dSTim Harvey 	if (pdata->audout_format) {
27639ac0038dSTim Harvey 		u64 formats;
27649ac0038dSTim Harvey 
27659ac0038dSTim Harvey 		if (pdata->audout_width == 32)
27669ac0038dSTim Harvey 			formats = SNDRV_PCM_FMTBIT_S32_LE;
27679ac0038dSTim Harvey 		else
27689ac0038dSTim Harvey 			formats = SNDRV_PCM_FMTBIT_S16_LE;
27699ac0038dSTim Harvey 		tda1997x_audio_dai.capture.formats = formats;
27702d8102ccSKuninori Morimoto 		ret = devm_snd_soc_register_component(&state->client->dev,
27719ac0038dSTim Harvey 					     &tda1997x_codec_driver,
27729ac0038dSTim Harvey 					     &tda1997x_audio_dai, 1);
27739ac0038dSTim Harvey 		if (ret) {
27749ac0038dSTim Harvey 			dev_err(&client->dev, "register audio codec failed\n");
27759ac0038dSTim Harvey 			goto err_free_media;
27769ac0038dSTim Harvey 		}
27779ac0038dSTim Harvey 		v4l_info(state->client, "registered audio codec\n");
27789ac0038dSTim Harvey 	}
27799ac0038dSTim Harvey 
27809ac0038dSTim Harvey 	/* request irq */
27819ac0038dSTim Harvey 	ret = devm_request_threaded_irq(&client->dev, client->irq,
27829ac0038dSTim Harvey 					NULL, tda1997x_isr_thread,
27839ac0038dSTim Harvey 					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
27849ac0038dSTim Harvey 					KBUILD_MODNAME, state);
27859ac0038dSTim Harvey 	if (ret) {
27869ac0038dSTim Harvey 		v4l_err(client, "irq%d reg failed: %d\n", client->irq, ret);
27879ac0038dSTim Harvey 		goto err_free_media;
27889ac0038dSTim Harvey 	}
27899ac0038dSTim Harvey 
27909ac0038dSTim Harvey 	return 0;
27919ac0038dSTim Harvey 
27929ac0038dSTim Harvey err_free_media:
27939ac0038dSTim Harvey 	media_entity_cleanup(&sd->entity);
27949ac0038dSTim Harvey err_free_handler:
27959ac0038dSTim Harvey 	v4l2_ctrl_handler_free(&state->hdl);
27969ac0038dSTim Harvey err_free_mutex:
27979ac0038dSTim Harvey 	cancel_delayed_work(&state->delayed_work_enable_hpd);
27989ac0038dSTim Harvey 	mutex_destroy(&state->page_lock);
27999ac0038dSTim Harvey 	mutex_destroy(&state->lock);
280031b980c0SZheyu Ma 	tda1997x_set_power(state, 0);
28019ac0038dSTim Harvey err_free_state:
28029ac0038dSTim Harvey 	kfree(state);
28039ac0038dSTim Harvey 	dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
28049ac0038dSTim Harvey 
28059ac0038dSTim Harvey 	return ret;
28069ac0038dSTim Harvey }
28079ac0038dSTim Harvey 
tda1997x_remove(struct i2c_client * client)2808ed5c2f5fSUwe Kleine-König static void tda1997x_remove(struct i2c_client *client)
28099ac0038dSTim Harvey {
28109ac0038dSTim Harvey 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
28119ac0038dSTim Harvey 	struct tda1997x_state *state = to_state(sd);
28129ac0038dSTim Harvey 	struct tda1997x_platform_data *pdata = &state->pdata;
28139ac0038dSTim Harvey 
28149ac0038dSTim Harvey 	if (pdata->audout_format) {
28159ac0038dSTim Harvey 		mutex_destroy(&state->audio_lock);
28169ac0038dSTim Harvey 	}
28179ac0038dSTim Harvey 
28189ac0038dSTim Harvey 	disable_irq(state->client->irq);
28199ac0038dSTim Harvey 	tda1997x_power_mode(state, 0);
28209ac0038dSTim Harvey 
28219ac0038dSTim Harvey 	v4l2_async_unregister_subdev(sd);
28229ac0038dSTim Harvey 	media_entity_cleanup(&sd->entity);
28239ac0038dSTim Harvey 	v4l2_ctrl_handler_free(&state->hdl);
28249ac0038dSTim Harvey 	regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies);
28257f820ab5SYang Yingliang 	cancel_delayed_work_sync(&state->delayed_work_enable_hpd);
28269ac0038dSTim Harvey 	mutex_destroy(&state->page_lock);
28279ac0038dSTim Harvey 	mutex_destroy(&state->lock);
28289ac0038dSTim Harvey 
28299ac0038dSTim Harvey 	kfree(state);
28309ac0038dSTim Harvey }
28319ac0038dSTim Harvey 
28329ac0038dSTim Harvey static struct i2c_driver tda1997x_i2c_driver = {
28339ac0038dSTim Harvey 	.driver = {
28349ac0038dSTim Harvey 		.name = "tda1997x",
28359ac0038dSTim Harvey 		.of_match_table = of_match_ptr(tda1997x_of_id),
28369ac0038dSTim Harvey 	},
2837*aaeb31c0SUwe Kleine-König 	.probe = tda1997x_probe,
28389ac0038dSTim Harvey 	.remove = tda1997x_remove,
28399ac0038dSTim Harvey 	.id_table = tda1997x_i2c_id,
28409ac0038dSTim Harvey };
28419ac0038dSTim Harvey 
28429ac0038dSTim Harvey module_i2c_driver(tda1997x_i2c_driver);
28439ac0038dSTim Harvey 
28449ac0038dSTim Harvey MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
28459ac0038dSTim Harvey MODULE_DESCRIPTION("TDA1997X HDMI Receiver driver");
28469ac0038dSTim Harvey MODULE_LICENSE("GPL v2");
2847