18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * adv7343 - ADV7343 Video Encoder Driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * The encoder hardware does not support SECAM.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
98c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as
108c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This program is distributed .as is. WITHOUT ANY WARRANTY of any
138c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty
148c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
158c2ecf20Sopenharmony_ci * GNU General Public License for more details.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/init.h>
208c2ecf20Sopenharmony_ci#include <linux/ctype.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include <linux/i2c.h>
238c2ecf20Sopenharmony_ci#include <linux/device.h>
248c2ecf20Sopenharmony_ci#include <linux/delay.h>
258c2ecf20Sopenharmony_ci#include <linux/module.h>
268c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
278c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
288c2ecf20Sopenharmony_ci#include <linux/of.h>
298c2ecf20Sopenharmony_ci#include <linux/of_graph.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <media/i2c/adv7343.h>
328c2ecf20Sopenharmony_ci#include <media/v4l2-async.h>
338c2ecf20Sopenharmony_ci#include <media/v4l2-device.h>
348c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include "adv7343_regs.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ADV7343 video encoder driver");
398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic int debug;
428c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level 0-1");
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct adv7343_state {
468c2ecf20Sopenharmony_ci	struct v4l2_subdev sd;
478c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler hdl;
488c2ecf20Sopenharmony_ci	const struct adv7343_platform_data *pdata;
498c2ecf20Sopenharmony_ci	u8 reg00;
508c2ecf20Sopenharmony_ci	u8 reg01;
518c2ecf20Sopenharmony_ci	u8 reg02;
528c2ecf20Sopenharmony_ci	u8 reg35;
538c2ecf20Sopenharmony_ci	u8 reg80;
548c2ecf20Sopenharmony_ci	u8 reg82;
558c2ecf20Sopenharmony_ci	u32 output;
568c2ecf20Sopenharmony_ci	v4l2_std_id std;
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	return container_of(sd, struct adv7343_state, sd);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(sd);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(client, reg, value);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic const u8 adv7343_init_reg_val[] = {
778c2ecf20Sopenharmony_ci	ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,
788c2ecf20Sopenharmony_ci	ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,
818c2ecf20Sopenharmony_ci	ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,
828c2ecf20Sopenharmony_ci	ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,
838c2ecf20Sopenharmony_ci	ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,
848c2ecf20Sopenharmony_ci	ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,
858c2ecf20Sopenharmony_ci	ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,
868c2ecf20Sopenharmony_ci	ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,
898c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,
908c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,
918c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,
928c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,
938c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,
948c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,
958c2ecf20Sopenharmony_ci	ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,
988c2ecf20Sopenharmony_ci	ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,
998c2ecf20Sopenharmony_ci	ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/*
1038c2ecf20Sopenharmony_ci *			    2^32
1048c2ecf20Sopenharmony_ci * FSC(reg) =  FSC (HZ) * --------
1058c2ecf20Sopenharmony_ci *			  27000000
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_cistatic const struct adv7343_std_info stdinfo[] = {
1088c2ecf20Sopenharmony_ci	{
1098c2ecf20Sopenharmony_ci		/* FSC(Hz) = 3,579,545.45 Hz */
1108c2ecf20Sopenharmony_ci		SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
1118c2ecf20Sopenharmony_ci	}, {
1128c2ecf20Sopenharmony_ci		/* FSC(Hz) = 3,575,611.00 Hz */
1138c2ecf20Sopenharmony_ci		SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
1148c2ecf20Sopenharmony_ci	}, {
1158c2ecf20Sopenharmony_ci		/* FSC(Hz) = 3,582,056.00 */
1168c2ecf20Sopenharmony_ci		SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
1178c2ecf20Sopenharmony_ci	}, {
1188c2ecf20Sopenharmony_ci		/* FSC(Hz) = 4,433,618.75 Hz */
1198c2ecf20Sopenharmony_ci		SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
1208c2ecf20Sopenharmony_ci	}, {
1218c2ecf20Sopenharmony_ci		/* FSC(Hz) = 4,433,618.75 Hz */
1228c2ecf20Sopenharmony_ci		SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
1238c2ecf20Sopenharmony_ci	}, {
1248c2ecf20Sopenharmony_ci		/* FSC(Hz) = 4,433,618.75 Hz */
1258c2ecf20Sopenharmony_ci		SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
1268c2ecf20Sopenharmony_ci	}, {
1278c2ecf20Sopenharmony_ci		/* FSC(Hz) = 4,433,618.75 Hz */
1288c2ecf20Sopenharmony_ci		SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
1298c2ecf20Sopenharmony_ci	},
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct adv7343_state *state = to_state(sd);
1358c2ecf20Sopenharmony_ci	struct adv7343_std_info *std_info;
1368c2ecf20Sopenharmony_ci	int num_std;
1378c2ecf20Sopenharmony_ci	char *fsc_ptr;
1388c2ecf20Sopenharmony_ci	u8 reg, val;
1398c2ecf20Sopenharmony_ci	int err = 0;
1408c2ecf20Sopenharmony_ci	int i = 0;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	std_info = (struct adv7343_std_info *)stdinfo;
1438c2ecf20Sopenharmony_ci	num_std = ARRAY_SIZE(stdinfo);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	for (i = 0; i < num_std; i++) {
1468c2ecf20Sopenharmony_ci		if (std_info[i].stdid & std)
1478c2ecf20Sopenharmony_ci			break;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (i == num_std) {
1518c2ecf20Sopenharmony_ci		v4l2_dbg(1, debug, sd,
1528c2ecf20Sopenharmony_ci				"Invalid std or std is not supported: %llx\n",
1538c2ecf20Sopenharmony_ci						(unsigned long long)std);
1548c2ecf20Sopenharmony_ci		return -EINVAL;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* Set the standard */
1588c2ecf20Sopenharmony_ci	val = state->reg80 & (~(SD_STD_MASK));
1598c2ecf20Sopenharmony_ci	val |= std_info[i].standard_val3;
1608c2ecf20Sopenharmony_ci	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
1618c2ecf20Sopenharmony_ci	if (err < 0)
1628c2ecf20Sopenharmony_ci		goto setstd_exit;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	state->reg80 = val;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* Configure the input mode register */
1678c2ecf20Sopenharmony_ci	val = state->reg01 & (~((u8) INPUT_MODE_MASK));
1688c2ecf20Sopenharmony_ci	val |= SD_INPUT_MODE;
1698c2ecf20Sopenharmony_ci	err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);
1708c2ecf20Sopenharmony_ci	if (err < 0)
1718c2ecf20Sopenharmony_ci		goto setstd_exit;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	state->reg01 = val;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* Program the sub carrier frequency registers */
1768c2ecf20Sopenharmony_ci	fsc_ptr = (unsigned char *)&std_info[i].fsc_val;
1778c2ecf20Sopenharmony_ci	reg = ADV7343_FSC_REG0;
1788c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++, reg++, fsc_ptr++) {
1798c2ecf20Sopenharmony_ci		err = adv7343_write(sd, reg, *fsc_ptr);
1808c2ecf20Sopenharmony_ci		if (err < 0)
1818c2ecf20Sopenharmony_ci			goto setstd_exit;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	val = state->reg80;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Filter settings */
1878c2ecf20Sopenharmony_ci	if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
1888c2ecf20Sopenharmony_ci		val &= 0x03;
1898c2ecf20Sopenharmony_ci	else if (std & ~V4L2_STD_SECAM)
1908c2ecf20Sopenharmony_ci		val |= 0x04;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
1938c2ecf20Sopenharmony_ci	if (err < 0)
1948c2ecf20Sopenharmony_ci		goto setstd_exit;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	state->reg80 = val;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cisetstd_exit:
1998c2ecf20Sopenharmony_ci	if (err != 0)
2008c2ecf20Sopenharmony_ci		v4l2_err(sd, "Error setting std, write failed\n");
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return err;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct adv7343_state *state = to_state(sd);
2088c2ecf20Sopenharmony_ci	unsigned char val;
2098c2ecf20Sopenharmony_ci	int err = 0;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (output_type > ADV7343_SVIDEO_ID) {
2128c2ecf20Sopenharmony_ci		v4l2_dbg(1, debug, sd,
2138c2ecf20Sopenharmony_ci			"Invalid output type or output type not supported:%d\n",
2148c2ecf20Sopenharmony_ci								output_type);
2158c2ecf20Sopenharmony_ci		return -EINVAL;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Enable Appropriate DAC */
2198c2ecf20Sopenharmony_ci	val = state->reg00 & 0x03;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/* configure default configuration */
2228c2ecf20Sopenharmony_ci	if (!state->pdata)
2238c2ecf20Sopenharmony_ci		if (output_type == ADV7343_COMPOSITE_ID)
2248c2ecf20Sopenharmony_ci			val |= ADV7343_COMPOSITE_POWER_VALUE;
2258c2ecf20Sopenharmony_ci		else if (output_type == ADV7343_COMPONENT_ID)
2268c2ecf20Sopenharmony_ci			val |= ADV7343_COMPONENT_POWER_VALUE;
2278c2ecf20Sopenharmony_ci		else
2288c2ecf20Sopenharmony_ci			val |= ADV7343_SVIDEO_POWER_VALUE;
2298c2ecf20Sopenharmony_ci	else
2308c2ecf20Sopenharmony_ci		val = state->pdata->mode_config.sleep_mode << 0 |
2318c2ecf20Sopenharmony_ci		      state->pdata->mode_config.pll_control << 1 |
2328c2ecf20Sopenharmony_ci		      state->pdata->mode_config.dac[2] << 2 |
2338c2ecf20Sopenharmony_ci		      state->pdata->mode_config.dac[1] << 3 |
2348c2ecf20Sopenharmony_ci		      state->pdata->mode_config.dac[0] << 4 |
2358c2ecf20Sopenharmony_ci		      state->pdata->mode_config.dac[5] << 5 |
2368c2ecf20Sopenharmony_ci		      state->pdata->mode_config.dac[4] << 6 |
2378c2ecf20Sopenharmony_ci		      state->pdata->mode_config.dac[3] << 7;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
2408c2ecf20Sopenharmony_ci	if (err < 0)
2418c2ecf20Sopenharmony_ci		goto setoutput_exit;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	state->reg00 = val;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* Enable YUV output */
2468c2ecf20Sopenharmony_ci	val = state->reg02 | YUV_OUTPUT_SELECT;
2478c2ecf20Sopenharmony_ci	err = adv7343_write(sd, ADV7343_MODE_REG0, val);
2488c2ecf20Sopenharmony_ci	if (err < 0)
2498c2ecf20Sopenharmony_ci		goto setoutput_exit;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	state->reg02 = val;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
2548c2ecf20Sopenharmony_ci	val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (state->pdata && state->pdata->sd_config.sd_dac_out[0])
2578c2ecf20Sopenharmony_ci		val = val | (state->pdata->sd_config.sd_dac_out[0] << 1);
2588c2ecf20Sopenharmony_ci	else if (state->pdata && !state->pdata->sd_config.sd_dac_out[0])
2598c2ecf20Sopenharmony_ci		val = val & ~(state->pdata->sd_config.sd_dac_out[0] << 1);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (state->pdata && state->pdata->sd_config.sd_dac_out[1])
2628c2ecf20Sopenharmony_ci		val = val | (state->pdata->sd_config.sd_dac_out[1] << 2);
2638c2ecf20Sopenharmony_ci	else if (state->pdata && !state->pdata->sd_config.sd_dac_out[1])
2648c2ecf20Sopenharmony_ci		val = val & ~(state->pdata->sd_config.sd_dac_out[1] << 2);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
2678c2ecf20Sopenharmony_ci	if (err < 0)
2688c2ecf20Sopenharmony_ci		goto setoutput_exit;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	state->reg82 = val;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to
2738c2ecf20Sopenharmony_ci	 * zero */
2748c2ecf20Sopenharmony_ci	val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);
2758c2ecf20Sopenharmony_ci	err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);
2768c2ecf20Sopenharmony_ci	if (err < 0)
2778c2ecf20Sopenharmony_ci		goto setoutput_exit;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	state->reg35 = val;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cisetoutput_exit:
2828c2ecf20Sopenharmony_ci	if (err != 0)
2838c2ecf20Sopenharmony_ci		v4l2_err(sd, "Error setting output, write failed\n");
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return err;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic int adv7343_log_status(struct v4l2_subdev *sd)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct adv7343_state *state = to_state(sd);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
2938c2ecf20Sopenharmony_ci	v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
2948c2ecf20Sopenharmony_ci			((state->output == 1) ? "Component" : "S-Video"));
2958c2ecf20Sopenharmony_ci	return 0;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = to_sd(ctrl);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	switch (ctrl->id) {
3038c2ecf20Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
3048c2ecf20Sopenharmony_ci		return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
3058c2ecf20Sopenharmony_ci					ctrl->val);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	case V4L2_CID_HUE:
3088c2ecf20Sopenharmony_ci		return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	case V4L2_CID_GAIN:
3118c2ecf20Sopenharmony_ci		return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val);
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	return -EINVAL;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
3178c2ecf20Sopenharmony_ci	.s_ctrl = adv7343_s_ctrl,
3188c2ecf20Sopenharmony_ci};
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops adv7343_core_ops = {
3218c2ecf20Sopenharmony_ci	.log_status = adv7343_log_status,
3228c2ecf20Sopenharmony_ci};
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct adv7343_state *state = to_state(sd);
3278c2ecf20Sopenharmony_ci	int err = 0;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (state->std == std)
3308c2ecf20Sopenharmony_ci		return 0;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	err = adv7343_setstd(sd, std);
3338c2ecf20Sopenharmony_ci	if (!err)
3348c2ecf20Sopenharmony_ci		state->std = std;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return err;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int adv7343_s_routing(struct v4l2_subdev *sd,
3408c2ecf20Sopenharmony_ci		u32 input, u32 output, u32 config)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct adv7343_state *state = to_state(sd);
3438c2ecf20Sopenharmony_ci	int err = 0;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (state->output == output)
3468c2ecf20Sopenharmony_ci		return 0;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	err = adv7343_setoutput(sd, output);
3498c2ecf20Sopenharmony_ci	if (!err)
3508c2ecf20Sopenharmony_ci		state->output = output;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	return err;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops adv7343_video_ops = {
3568c2ecf20Sopenharmony_ci	.s_std_output	= adv7343_s_std_output,
3578c2ecf20Sopenharmony_ci	.s_routing	= adv7343_s_routing,
3588c2ecf20Sopenharmony_ci};
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops adv7343_ops = {
3618c2ecf20Sopenharmony_ci	.core	= &adv7343_core_ops,
3628c2ecf20Sopenharmony_ci	.video	= &adv7343_video_ops,
3638c2ecf20Sopenharmony_ci};
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int adv7343_initialize(struct v4l2_subdev *sd)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct adv7343_state *state = to_state(sd);
3688c2ecf20Sopenharmony_ci	int err = 0;
3698c2ecf20Sopenharmony_ci	int i;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		err = adv7343_write(sd, adv7343_init_reg_val[i],
3748c2ecf20Sopenharmony_ci					adv7343_init_reg_val[i+1]);
3758c2ecf20Sopenharmony_ci		if (err) {
3768c2ecf20Sopenharmony_ci			v4l2_err(sd, "Error initializing\n");
3778c2ecf20Sopenharmony_ci			return err;
3788c2ecf20Sopenharmony_ci		}
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* Configure for default video standard */
3828c2ecf20Sopenharmony_ci	err = adv7343_setoutput(sd, state->output);
3838c2ecf20Sopenharmony_ci	if (err < 0) {
3848c2ecf20Sopenharmony_ci		v4l2_err(sd, "Error setting output during init\n");
3858c2ecf20Sopenharmony_ci		return -EINVAL;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	err = adv7343_setstd(sd, state->std);
3898c2ecf20Sopenharmony_ci	if (err < 0) {
3908c2ecf20Sopenharmony_ci		v4l2_err(sd, "Error setting std during init\n");
3918c2ecf20Sopenharmony_ci		return -EINVAL;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return err;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic struct adv7343_platform_data *
3988c2ecf20Sopenharmony_ciadv7343_get_pdata(struct i2c_client *client)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct adv7343_platform_data *pdata;
4018c2ecf20Sopenharmony_ci	struct device_node *np;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
4048c2ecf20Sopenharmony_ci		return client->dev.platform_data;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
4078c2ecf20Sopenharmony_ci	if (!np)
4088c2ecf20Sopenharmony_ci		return NULL;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
4118c2ecf20Sopenharmony_ci	if (!pdata)
4128c2ecf20Sopenharmony_ci		goto done;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	pdata->mode_config.sleep_mode =
4158c2ecf20Sopenharmony_ci			of_property_read_bool(np, "adi,power-mode-sleep-mode");
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	pdata->mode_config.pll_control =
4188c2ecf20Sopenharmony_ci			of_property_read_bool(np, "adi,power-mode-pll-ctrl");
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	of_property_read_u32_array(np, "adi,dac-enable",
4218c2ecf20Sopenharmony_ci				   pdata->mode_config.dac, 6);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	of_property_read_u32_array(np, "adi,sd-dac-enable",
4248c2ecf20Sopenharmony_ci				   pdata->sd_config.sd_dac_out, 2);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cidone:
4278c2ecf20Sopenharmony_ci	of_node_put(np);
4288c2ecf20Sopenharmony_ci	return pdata;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic int adv7343_probe(struct i2c_client *client)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct adv7343_state *state;
4348c2ecf20Sopenharmony_ci	int err;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
4378c2ecf20Sopenharmony_ci		return -ENODEV;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	v4l_info(client, "chip found @ 0x%x (%s)\n",
4408c2ecf20Sopenharmony_ci			client->addr << 1, client->adapter->name);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	state = devm_kzalloc(&client->dev, sizeof(struct adv7343_state),
4438c2ecf20Sopenharmony_ci			     GFP_KERNEL);
4448c2ecf20Sopenharmony_ci	if (state == NULL)
4458c2ecf20Sopenharmony_ci		return -ENOMEM;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* Copy board specific information here */
4488c2ecf20Sopenharmony_ci	state->pdata = adv7343_get_pdata(client);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	state->reg00	= 0x80;
4518c2ecf20Sopenharmony_ci	state->reg01	= 0x00;
4528c2ecf20Sopenharmony_ci	state->reg02	= 0x20;
4538c2ecf20Sopenharmony_ci	state->reg35	= 0x00;
4548c2ecf20Sopenharmony_ci	state->reg80	= ADV7343_SD_MODE_REG1_DEFAULT;
4558c2ecf20Sopenharmony_ci	state->reg82	= ADV7343_SD_MODE_REG2_DEFAULT;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	state->output = ADV7343_COMPOSITE_ID;
4588c2ecf20Sopenharmony_ci	state->std = V4L2_STD_NTSC;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(&state->hdl, 2);
4638c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
4648c2ecf20Sopenharmony_ci			V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN,
4658c2ecf20Sopenharmony_ci					     ADV7343_BRIGHTNESS_MAX, 1,
4668c2ecf20Sopenharmony_ci					     ADV7343_BRIGHTNESS_DEF);
4678c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
4688c2ecf20Sopenharmony_ci			V4L2_CID_HUE, ADV7343_HUE_MIN,
4698c2ecf20Sopenharmony_ci				      ADV7343_HUE_MAX, 1,
4708c2ecf20Sopenharmony_ci				      ADV7343_HUE_DEF);
4718c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
4728c2ecf20Sopenharmony_ci			V4L2_CID_GAIN, ADV7343_GAIN_MIN,
4738c2ecf20Sopenharmony_ci				       ADV7343_GAIN_MAX, 1,
4748c2ecf20Sopenharmony_ci				       ADV7343_GAIN_DEF);
4758c2ecf20Sopenharmony_ci	state->sd.ctrl_handler = &state->hdl;
4768c2ecf20Sopenharmony_ci	if (state->hdl.error) {
4778c2ecf20Sopenharmony_ci		err = state->hdl.error;
4788c2ecf20Sopenharmony_ci		goto done;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_setup(&state->hdl);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	err = adv7343_initialize(&state->sd);
4838c2ecf20Sopenharmony_ci	if (err)
4848c2ecf20Sopenharmony_ci		goto done;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	err = v4l2_async_register_subdev(&state->sd);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cidone:
4898c2ecf20Sopenharmony_ci	if (err < 0)
4908c2ecf20Sopenharmony_ci		v4l2_ctrl_handler_free(&state->hdl);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	return err;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic int adv7343_remove(struct i2c_client *client)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
4988c2ecf20Sopenharmony_ci	struct adv7343_state *state = to_state(sd);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	v4l2_async_unregister_subdev(&state->sd);
5018c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&state->hdl);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	return 0;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic const struct i2c_device_id adv7343_id[] = {
5078c2ecf20Sopenharmony_ci	{"adv7343", 0},
5088c2ecf20Sopenharmony_ci	{},
5098c2ecf20Sopenharmony_ci};
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adv7343_id);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
5148c2ecf20Sopenharmony_cistatic const struct of_device_id adv7343_of_match[] = {
5158c2ecf20Sopenharmony_ci	{.compatible = "adi,adv7343", },
5168c2ecf20Sopenharmony_ci	{ /* sentinel */ },
5178c2ecf20Sopenharmony_ci};
5188c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, adv7343_of_match);
5198c2ecf20Sopenharmony_ci#endif
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic struct i2c_driver adv7343_driver = {
5228c2ecf20Sopenharmony_ci	.driver = {
5238c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(adv7343_of_match),
5248c2ecf20Sopenharmony_ci		.name	= "adv7343",
5258c2ecf20Sopenharmony_ci	},
5268c2ecf20Sopenharmony_ci	.probe_new	= adv7343_probe,
5278c2ecf20Sopenharmony_ci	.remove		= adv7343_remove,
5288c2ecf20Sopenharmony_ci	.id_table	= adv7343_id,
5298c2ecf20Sopenharmony_ci};
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cimodule_i2c_driver(adv7343_driver);
532