brintos

brintos / linux-shallow public Read only

0
0
Text · 13.1 KiB · b964434 Raw
530 lines · c
1/*2 * adv7343 - ADV7343 Video Encoder Driver3 *4 * The encoder hardware does not support SECAM.5 *6 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/7 *8 * This program is free software; you can redistribute it and/or9 * modify it under the terms of the GNU General Public License as10 * published by the Free Software Foundation version 2.11 *12 * This program is distributed .as is. WITHOUT ANY WARRANTY of any13 * kind, whether express or implied; without even the implied warranty14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the15 * GNU General Public License for more details.16 */17 18#include <linux/kernel.h>19#include <linux/init.h>20#include <linux/ctype.h>21#include <linux/slab.h>22#include <linux/i2c.h>23#include <linux/device.h>24#include <linux/delay.h>25#include <linux/module.h>26#include <linux/videodev2.h>27#include <linux/uaccess.h>28#include <linux/of.h>29#include <linux/of_graph.h>30 31#include <media/i2c/adv7343.h>32#include <media/v4l2-async.h>33#include <media/v4l2-device.h>34#include <media/v4l2-ctrls.h>35 36#include "adv7343_regs.h"37 38MODULE_DESCRIPTION("ADV7343 video encoder driver");39MODULE_LICENSE("GPL");40 41static int debug;42module_param(debug, int, 0644);43MODULE_PARM_DESC(debug, "Debug level 0-1");44 45struct adv7343_state {46	struct v4l2_subdev sd;47	struct v4l2_ctrl_handler hdl;48	const struct adv7343_platform_data *pdata;49	u8 reg00;50	u8 reg01;51	u8 reg02;52	u8 reg35;53	u8 reg80;54	u8 reg82;55	u32 output;56	v4l2_std_id std;57};58 59static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)60{61	return container_of(sd, struct adv7343_state, sd);62}63 64static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)65{66	return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd;67}68 69static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)70{71	struct i2c_client *client = v4l2_get_subdevdata(sd);72 73	return i2c_smbus_write_byte_data(client, reg, value);74}75 76static const u8 adv7343_init_reg_val[] = {77	ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,78	ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,79 80	ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,81	ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,82	ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,83	ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,84	ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,85	ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,86	ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,87 88	ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,89	ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,90	ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,91	ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,92	ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,93	ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,94	ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,95	ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,96 97	ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,98	ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,99	ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,100};101 102/*103 *			    2^32104 * FSC(reg) =  FSC (HZ) * --------105 *			  27000000106 */107static const struct adv7343_std_info stdinfo[] = {108	{109		/* FSC(Hz) = 3,579,545.45 Hz */110		SD_STD_NTSC, 569408542, V4L2_STD_NTSC,111	}, {112		/* FSC(Hz) = 3,575,611.00 Hz */113		SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,114	}, {115		/* FSC(Hz) = 3,582,056.00 */116		SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,117	}, {118		/* FSC(Hz) = 4,433,618.75 Hz */119		SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,120	}, {121		/* FSC(Hz) = 4,433,618.75 Hz */122		SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,123	}, {124		/* FSC(Hz) = 4,433,618.75 Hz */125		SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,126	}, {127		/* FSC(Hz) = 4,433,618.75 Hz */128		SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,129	},130};131 132static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)133{134	struct adv7343_state *state = to_state(sd);135	struct adv7343_std_info *std_info;136	int num_std;137	char *fsc_ptr;138	u8 reg, val;139	int err = 0;140	int i = 0;141 142	std_info = (struct adv7343_std_info *)stdinfo;143	num_std = ARRAY_SIZE(stdinfo);144 145	for (i = 0; i < num_std; i++) {146		if (std_info[i].stdid & std)147			break;148	}149 150	if (i == num_std) {151		v4l2_dbg(1, debug, sd,152				"Invalid std or std is not supported: %llx\n",153						(unsigned long long)std);154		return -EINVAL;155	}156 157	/* Set the standard */158	val = state->reg80 & (~(SD_STD_MASK));159	val |= std_info[i].standard_val3;160	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);161	if (err < 0)162		goto setstd_exit;163 164	state->reg80 = val;165 166	/* Configure the input mode register */167	val = state->reg01 & (~((u8) INPUT_MODE_MASK));168	val |= SD_INPUT_MODE;169	err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);170	if (err < 0)171		goto setstd_exit;172 173	state->reg01 = val;174 175	/* Program the sub carrier frequency registers */176	fsc_ptr = (unsigned char *)&std_info[i].fsc_val;177	reg = ADV7343_FSC_REG0;178	for (i = 0; i < 4; i++, reg++, fsc_ptr++) {179		err = adv7343_write(sd, reg, *fsc_ptr);180		if (err < 0)181			goto setstd_exit;182	}183 184	val = state->reg80;185 186	/* Filter settings */187	if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))188		val &= 0x03;189	else if (std & ~V4L2_STD_SECAM)190		val |= 0x04;191 192	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);193	if (err < 0)194		goto setstd_exit;195 196	state->reg80 = val;197 198setstd_exit:199	if (err != 0)200		v4l2_err(sd, "Error setting std, write failed\n");201 202	return err;203}204 205static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)206{207	struct adv7343_state *state = to_state(sd);208	unsigned char val;209	int err = 0;210 211	if (output_type > ADV7343_SVIDEO_ID) {212		v4l2_dbg(1, debug, sd,213			"Invalid output type or output type not supported:%d\n",214								output_type);215		return -EINVAL;216	}217 218	/* Enable Appropriate DAC */219	val = state->reg00 & 0x03;220 221	/* configure default configuration */222	if (!state->pdata)223		if (output_type == ADV7343_COMPOSITE_ID)224			val |= ADV7343_COMPOSITE_POWER_VALUE;225		else if (output_type == ADV7343_COMPONENT_ID)226			val |= ADV7343_COMPONENT_POWER_VALUE;227		else228			val |= ADV7343_SVIDEO_POWER_VALUE;229	else230		val = state->pdata->mode_config.sleep_mode << 0 |231		      state->pdata->mode_config.pll_control << 1 |232		      state->pdata->mode_config.dac[2] << 2 |233		      state->pdata->mode_config.dac[1] << 3 |234		      state->pdata->mode_config.dac[0] << 4 |235		      state->pdata->mode_config.dac[5] << 5 |236		      state->pdata->mode_config.dac[4] << 6 |237		      state->pdata->mode_config.dac[3] << 7;238 239	err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);240	if (err < 0)241		goto setoutput_exit;242 243	state->reg00 = val;244 245	/* Enable YUV output */246	val = state->reg02 | YUV_OUTPUT_SELECT;247	err = adv7343_write(sd, ADV7343_MODE_REG0, val);248	if (err < 0)249		goto setoutput_exit;250 251	state->reg02 = val;252 253	/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */254	val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);255 256	if (state->pdata && state->pdata->sd_config.sd_dac_out[0])257		val = val | (state->pdata->sd_config.sd_dac_out[0] << 1);258	else if (state->pdata && !state->pdata->sd_config.sd_dac_out[0])259		val = val & ~(state->pdata->sd_config.sd_dac_out[0] << 1);260 261	if (state->pdata && state->pdata->sd_config.sd_dac_out[1])262		val = val | (state->pdata->sd_config.sd_dac_out[1] << 2);263	else if (state->pdata && !state->pdata->sd_config.sd_dac_out[1])264		val = val & ~(state->pdata->sd_config.sd_dac_out[1] << 2);265 266	err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);267	if (err < 0)268		goto setoutput_exit;269 270	state->reg82 = val;271 272	/* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to273	 * zero */274	val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);275	err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);276	if (err < 0)277		goto setoutput_exit;278 279	state->reg35 = val;280 281setoutput_exit:282	if (err != 0)283		v4l2_err(sd, "Error setting output, write failed\n");284 285	return err;286}287 288static int adv7343_log_status(struct v4l2_subdev *sd)289{290	struct adv7343_state *state = to_state(sd);291 292	v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);293	v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :294			((state->output == 1) ? "Component" : "S-Video"));295	return 0;296}297 298static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)299{300	struct v4l2_subdev *sd = to_sd(ctrl);301 302	switch (ctrl->id) {303	case V4L2_CID_BRIGHTNESS:304		return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,305					ctrl->val);306 307	case V4L2_CID_HUE:308		return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val);309 310	case V4L2_CID_GAIN:311		return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val);312	}313	return -EINVAL;314}315 316static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {317	.s_ctrl = adv7343_s_ctrl,318};319 320static const struct v4l2_subdev_core_ops adv7343_core_ops = {321	.log_status = adv7343_log_status,322};323 324static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)325{326	struct adv7343_state *state = to_state(sd);327	int err = 0;328 329	if (state->std == std)330		return 0;331 332	err = adv7343_setstd(sd, std);333	if (!err)334		state->std = std;335 336	return err;337}338 339static int adv7343_s_routing(struct v4l2_subdev *sd,340		u32 input, u32 output, u32 config)341{342	struct adv7343_state *state = to_state(sd);343	int err = 0;344 345	if (state->output == output)346		return 0;347 348	err = adv7343_setoutput(sd, output);349	if (!err)350		state->output = output;351 352	return err;353}354 355static const struct v4l2_subdev_video_ops adv7343_video_ops = {356	.s_std_output	= adv7343_s_std_output,357	.s_routing	= adv7343_s_routing,358};359 360static const struct v4l2_subdev_ops adv7343_ops = {361	.core	= &adv7343_core_ops,362	.video	= &adv7343_video_ops,363};364 365static int adv7343_initialize(struct v4l2_subdev *sd)366{367	struct adv7343_state *state = to_state(sd);368	int err = 0;369	int i;370 371	for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {372 373		err = adv7343_write(sd, adv7343_init_reg_val[i],374					adv7343_init_reg_val[i+1]);375		if (err) {376			v4l2_err(sd, "Error initializing\n");377			return err;378		}379	}380 381	/* Configure for default video standard */382	err = adv7343_setoutput(sd, state->output);383	if (err < 0) {384		v4l2_err(sd, "Error setting output during init\n");385		return -EINVAL;386	}387 388	err = adv7343_setstd(sd, state->std);389	if (err < 0) {390		v4l2_err(sd, "Error setting std during init\n");391		return -EINVAL;392	}393 394	return err;395}396 397static struct adv7343_platform_data *398adv7343_get_pdata(struct i2c_client *client)399{400	struct adv7343_platform_data *pdata;401	struct device_node *np;402 403	if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)404		return client->dev.platform_data;405 406	np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1);407	if (!np)408		return NULL;409 410	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);411	if (!pdata)412		goto done;413 414	pdata->mode_config.sleep_mode =415			of_property_read_bool(np, "adi,power-mode-sleep-mode");416 417	pdata->mode_config.pll_control =418			of_property_read_bool(np, "adi,power-mode-pll-ctrl");419 420	of_property_read_u32_array(np, "adi,dac-enable",421				   pdata->mode_config.dac, 6);422 423	of_property_read_u32_array(np, "adi,sd-dac-enable",424				   pdata->sd_config.sd_dac_out, 2);425 426done:427	of_node_put(np);428	return pdata;429}430 431static int adv7343_probe(struct i2c_client *client)432{433	struct adv7343_state *state;434	int err;435 436	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))437		return -ENODEV;438 439	v4l_info(client, "chip found @ 0x%x (%s)\n",440			client->addr << 1, client->adapter->name);441 442	state = devm_kzalloc(&client->dev, sizeof(struct adv7343_state),443			     GFP_KERNEL);444	if (state == NULL)445		return -ENOMEM;446 447	/* Copy board specific information here */448	state->pdata = adv7343_get_pdata(client);449 450	state->reg00	= 0x80;451	state->reg01	= 0x00;452	state->reg02	= 0x20;453	state->reg35	= 0x00;454	state->reg80	= ADV7343_SD_MODE_REG1_DEFAULT;455	state->reg82	= ADV7343_SD_MODE_REG2_DEFAULT;456 457	state->output = ADV7343_COMPOSITE_ID;458	state->std = V4L2_STD_NTSC;459 460	v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);461 462	v4l2_ctrl_handler_init(&state->hdl, 2);463	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,464			V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN,465					     ADV7343_BRIGHTNESS_MAX, 1,466					     ADV7343_BRIGHTNESS_DEF);467	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,468			V4L2_CID_HUE, ADV7343_HUE_MIN,469				      ADV7343_HUE_MAX, 1,470				      ADV7343_HUE_DEF);471	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,472			V4L2_CID_GAIN, ADV7343_GAIN_MIN,473				       ADV7343_GAIN_MAX, 1,474				       ADV7343_GAIN_DEF);475	state->sd.ctrl_handler = &state->hdl;476	if (state->hdl.error) {477		err = state->hdl.error;478		goto done;479	}480	v4l2_ctrl_handler_setup(&state->hdl);481 482	err = adv7343_initialize(&state->sd);483	if (err)484		goto done;485 486	err = v4l2_async_register_subdev(&state->sd);487 488done:489	if (err < 0)490		v4l2_ctrl_handler_free(&state->hdl);491 492	return err;493}494 495static void adv7343_remove(struct i2c_client *client)496{497	struct v4l2_subdev *sd = i2c_get_clientdata(client);498	struct adv7343_state *state = to_state(sd);499 500	v4l2_async_unregister_subdev(&state->sd);501	v4l2_ctrl_handler_free(&state->hdl);502}503 504static const struct i2c_device_id adv7343_id[] = {505	{ "adv7343" },506	{}507};508 509MODULE_DEVICE_TABLE(i2c, adv7343_id);510 511#if IS_ENABLED(CONFIG_OF)512static const struct of_device_id adv7343_of_match[] = {513	{.compatible = "adi,adv7343", },514	{ /* sentinel */ },515};516MODULE_DEVICE_TABLE(of, adv7343_of_match);517#endif518 519static struct i2c_driver adv7343_driver = {520	.driver = {521		.of_match_table = of_match_ptr(adv7343_of_match),522		.name	= "adv7343",523	},524	.probe		= adv7343_probe,525	.remove		= adv7343_remove,526	.id_table	= adv7343_id,527};528 529module_i2c_driver(adv7343_driver);530