brintos

brintos / linux-shallow public Read only

0
0
Text · 11.7 KiB · 57ba369 Raw
446 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * OKI Semiconductor ML86V7667 video decoder driver4 *5 * Author: Vladimir Barinov <source@cogentembedded.com>6 * Copyright (C) 2013 Cogent Embedded, Inc.7 * Copyright (C) 2013 Renesas Solutions Corp.8 */9 10#include <linux/init.h>11#include <linux/module.h>12#include <linux/i2c.h>13#include <linux/slab.h>14#include <linux/videodev2.h>15#include <media/v4l2-subdev.h>16#include <media/v4l2-device.h>17#include <media/v4l2-ioctl.h>18#include <media/v4l2-ctrls.h>19 20#define DRV_NAME "ml86v7667"21 22/* Subaddresses */23#define MRA_REG			0x00 /* Mode Register A */24#define MRC_REG			0x02 /* Mode Register C */25#define LUMC_REG		0x0C /* Luminance Control */26#define CLC_REG			0x10 /* Contrast level control */27#define SSEPL_REG		0x11 /* Sync separation level */28#define CHRCA_REG		0x12 /* Chrominance Control A */29#define ACCC_REG		0x14 /* ACC Loop filter & Chrominance control */30#define ACCRC_REG		0x15 /* ACC Reference level control */31#define HUE_REG			0x16 /* Hue control */32#define ADC2_REG		0x1F /* ADC Register 2 */33#define PLLR1_REG		0x20 /* PLL Register 1 */34#define STATUS_REG		0x2C /* STATUS Register */35 36/* Mode Register A register bits */37#define MRA_OUTPUT_MODE_MASK	(3 << 6)38#define MRA_ITUR_BT601		(1 << 6)39#define MRA_ITUR_BT656		(0 << 6)40#define MRA_INPUT_MODE_MASK	(7 << 3)41#define MRA_PAL_BT601		(4 << 3)42#define MRA_NTSC_BT601		(0 << 3)43#define MRA_REGISTER_MODE	(1 << 0)44 45/* Mode Register C register bits */46#define MRC_AUTOSELECT		(1 << 7)47 48/* Luminance Control register bits */49#define LUMC_ONOFF_SHIFT	750#define LUMC_ONOFF_MASK		(1 << 7)51 52/* Contrast level control register bits */53#define CLC_CONTRAST_ONOFF	(1 << 7)54#define CLC_CONTRAST_MASK	0x0F55 56/* Sync separation level register bits */57#define SSEPL_LUMINANCE_ONOFF	(1 << 7)58#define SSEPL_LUMINANCE_MASK	0x7F59 60/* Chrominance Control A register bits */61#define CHRCA_MODE_SHIFT	662#define CHRCA_MODE_MASK		(1 << 6)63 64/* ACC Loop filter & Chrominance control register bits */65#define ACCC_CHROMA_CR_SHIFT	366#define ACCC_CHROMA_CR_MASK	(7 << 3)67#define ACCC_CHROMA_CB_SHIFT	068#define ACCC_CHROMA_CB_MASK	(7 << 0)69 70/* ACC Reference level control register bits */71#define ACCRC_CHROMA_MASK	0xfc72#define ACCRC_CHROMA_SHIFT	273 74/* ADC Register 2 register bits */75#define ADC2_CLAMP_VOLTAGE_MASK	(7 << 1)76#define ADC2_CLAMP_VOLTAGE(n)	((n & 7) << 1)77 78/* PLL Register 1 register bits */79#define PLLR1_FIXED_CLOCK	(1 << 7)80 81/* STATUS Register register bits */82#define STATUS_HLOCK_DETECT	(1 << 3)83#define STATUS_NTSCPAL		(1 << 2)84 85struct ml86v7667_priv {86	struct v4l2_subdev		sd;87	struct v4l2_ctrl_handler	hdl;88	v4l2_std_id			std;89};90 91static inline struct ml86v7667_priv *to_ml86v7667(struct v4l2_subdev *subdev)92{93	return container_of(subdev, struct ml86v7667_priv, sd);94}95 96static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)97{98	return &container_of(ctrl->handler, struct ml86v7667_priv, hdl)->sd;99}100 101static int ml86v7667_mask_set(struct i2c_client *client, const u8 reg,102			      const u8 mask, const u8 data)103{104	int val = i2c_smbus_read_byte_data(client, reg);105	if (val < 0)106		return val;107 108	val = (val & ~mask) | (data & mask);109	return i2c_smbus_write_byte_data(client, reg, val);110}111 112static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)113{114	struct v4l2_subdev *sd = to_sd(ctrl);115	struct i2c_client *client = v4l2_get_subdevdata(sd);116	int ret = -EINVAL;117 118	switch (ctrl->id) {119	case V4L2_CID_BRIGHTNESS:120		ret = ml86v7667_mask_set(client, SSEPL_REG,121					 SSEPL_LUMINANCE_MASK, ctrl->val);122		break;123	case V4L2_CID_CONTRAST:124		ret = ml86v7667_mask_set(client, CLC_REG,125					 CLC_CONTRAST_MASK, ctrl->val);126		break;127	case V4L2_CID_CHROMA_GAIN:128		ret = ml86v7667_mask_set(client, ACCRC_REG, ACCRC_CHROMA_MASK,129					 ctrl->val << ACCRC_CHROMA_SHIFT);130		break;131	case V4L2_CID_HUE:132		ret = ml86v7667_mask_set(client, HUE_REG, ~0, ctrl->val);133		break;134	case V4L2_CID_RED_BALANCE:135		ret = ml86v7667_mask_set(client, ACCC_REG,136					 ACCC_CHROMA_CR_MASK,137					 ctrl->val << ACCC_CHROMA_CR_SHIFT);138		break;139	case V4L2_CID_BLUE_BALANCE:140		ret = ml86v7667_mask_set(client, ACCC_REG,141					 ACCC_CHROMA_CB_MASK,142					 ctrl->val << ACCC_CHROMA_CB_SHIFT);143		break;144	case V4L2_CID_SHARPNESS:145		ret = ml86v7667_mask_set(client, LUMC_REG,146					 LUMC_ONOFF_MASK,147					 ctrl->val << LUMC_ONOFF_SHIFT);148		break;149	case V4L2_CID_COLOR_KILLER:150		ret = ml86v7667_mask_set(client, CHRCA_REG,151					 CHRCA_MODE_MASK,152					 ctrl->val << CHRCA_MODE_SHIFT);153		break;154	}155 156	return ret;157}158 159static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)160{161	struct i2c_client *client = v4l2_get_subdevdata(sd);162	int status;163 164	status = i2c_smbus_read_byte_data(client, STATUS_REG);165	if (status < 0)166		return status;167 168	if (status & STATUS_HLOCK_DETECT)169		*std &= status & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;170	else171		*std = V4L2_STD_UNKNOWN;172 173	return 0;174}175 176static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status)177{178	struct i2c_client *client = v4l2_get_subdevdata(sd);179	int status_reg;180 181	status_reg = i2c_smbus_read_byte_data(client, STATUS_REG);182	if (status_reg < 0)183		return status_reg;184 185	*status = status_reg & STATUS_HLOCK_DETECT ? 0 : V4L2_IN_ST_NO_SIGNAL;186 187	return 0;188}189 190static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd,191		struct v4l2_subdev_state *sd_state,192		struct v4l2_subdev_mbus_code_enum *code)193{194	if (code->pad || code->index > 0)195		return -EINVAL;196 197	code->code = MEDIA_BUS_FMT_YUYV8_2X8;198 199	return 0;200}201 202static int ml86v7667_fill_fmt(struct v4l2_subdev *sd,203		struct v4l2_subdev_state *sd_state,204		struct v4l2_subdev_format *format)205{206	struct ml86v7667_priv *priv = to_ml86v7667(sd);207	struct v4l2_mbus_framefmt *fmt = &format->format;208 209	if (format->pad)210		return -EINVAL;211 212	fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;213	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;214	/* The top field is always transferred first by the chip */215	fmt->field = V4L2_FIELD_INTERLACED_TB;216	fmt->width = 720;217	fmt->height = priv->std & V4L2_STD_525_60 ? 480 : 576;218 219	return 0;220}221 222static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd,223				     unsigned int pad,224				     struct v4l2_mbus_config *cfg)225{226	cfg->type = V4L2_MBUS_BT656;227	cfg->bus.parallel.flags = V4L2_MBUS_MASTER |228				  V4L2_MBUS_PCLK_SAMPLE_RISING |229				  V4L2_MBUS_DATA_ACTIVE_HIGH;230 231	return 0;232}233 234static int ml86v7667_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)235{236	struct ml86v7667_priv *priv = to_ml86v7667(sd);237 238	*std = priv->std;239 240	return 0;241}242 243static int ml86v7667_s_std(struct v4l2_subdev *sd, v4l2_std_id std)244{245	struct ml86v7667_priv *priv = to_ml86v7667(sd);246	struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);247	int ret;248	u8 mode;249 250	/* PAL/NTSC ITU-R BT.601 input mode */251	mode = std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;252	ret = ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, mode);253	if (ret < 0)254		return ret;255 256	priv->std = std;257 258	return 0;259}260 261#ifdef CONFIG_VIDEO_ADV_DEBUG262static int ml86v7667_g_register(struct v4l2_subdev *sd,263				struct v4l2_dbg_register *reg)264{265	struct i2c_client *client = v4l2_get_subdevdata(sd);266	int ret;267 268	ret = i2c_smbus_read_byte_data(client, (u8)reg->reg);269	if (ret < 0)270		return ret;271 272	reg->val = ret;273	reg->size = sizeof(u8);274 275	return 0;276}277 278static int ml86v7667_s_register(struct v4l2_subdev *sd,279				const struct v4l2_dbg_register *reg)280{281	struct i2c_client *client = v4l2_get_subdevdata(sd);282 283	return i2c_smbus_write_byte_data(client, (u8)reg->reg, (u8)reg->val);284}285#endif286 287static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {288	.s_ctrl = ml86v7667_s_ctrl,289};290 291static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {292	.g_std = ml86v7667_g_std,293	.s_std = ml86v7667_s_std,294	.querystd = ml86v7667_querystd,295	.g_input_status = ml86v7667_g_input_status,296};297 298static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = {299	.enum_mbus_code = ml86v7667_enum_mbus_code,300	.get_fmt = ml86v7667_fill_fmt,301	.set_fmt = ml86v7667_fill_fmt,302	.get_mbus_config = ml86v7667_get_mbus_config,303};304 305static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {306#ifdef CONFIG_VIDEO_ADV_DEBUG307	.g_register = ml86v7667_g_register,308	.s_register = ml86v7667_s_register,309#endif310};311 312static const struct v4l2_subdev_ops ml86v7667_subdev_ops = {313	.core = &ml86v7667_subdev_core_ops,314	.video = &ml86v7667_subdev_video_ops,315	.pad = &ml86v7667_subdev_pad_ops,316};317 318static int ml86v7667_init(struct ml86v7667_priv *priv)319{320	struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);321	int val;322	int ret;323 324	/* BT.656-4 output mode, register mode */325	ret = ml86v7667_mask_set(client, MRA_REG,326				 MRA_OUTPUT_MODE_MASK | MRA_REGISTER_MODE,327				 MRA_ITUR_BT656 | MRA_REGISTER_MODE);328 329	/* PLL circuit fixed clock, 32MHz */330	ret |= ml86v7667_mask_set(client, PLLR1_REG, PLLR1_FIXED_CLOCK,331				  PLLR1_FIXED_CLOCK);332 333	/* ADC2 clamping voltage maximum  */334	ret |= ml86v7667_mask_set(client, ADC2_REG, ADC2_CLAMP_VOLTAGE_MASK,335				  ADC2_CLAMP_VOLTAGE(7));336 337	/* enable luminance function */338	ret |= ml86v7667_mask_set(client, SSEPL_REG, SSEPL_LUMINANCE_ONOFF,339				  SSEPL_LUMINANCE_ONOFF);340 341	/* enable contrast function */342	ret |= ml86v7667_mask_set(client, CLC_REG, CLC_CONTRAST_ONOFF, 0);343 344	/*345	 * PAL/NTSC autodetection is enabled after reset,346	 * set the autodetected std in manual std mode and347	 * disable autodetection348	 */349	val = i2c_smbus_read_byte_data(client, STATUS_REG);350	if (val < 0)351		return val;352 353	priv->std = val & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;354	ret |= ml86v7667_mask_set(client, MRC_REG, MRC_AUTOSELECT, 0);355 356	val = priv->std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;357	ret |= ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, val);358 359	return ret;360}361 362static int ml86v7667_probe(struct i2c_client *client)363{364	struct ml86v7667_priv *priv;365	int ret;366 367	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))368		return -EIO;369 370	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);371	if (!priv)372		return -ENOMEM;373 374	v4l2_i2c_subdev_init(&priv->sd, client, &ml86v7667_subdev_ops);375 376	v4l2_ctrl_handler_init(&priv->hdl, 8);377	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,378			  V4L2_CID_BRIGHTNESS, -64, 63, 1, 0);379	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,380			  V4L2_CID_CONTRAST, -8, 7, 1, 0);381	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,382			  V4L2_CID_CHROMA_GAIN, -32, 31, 1, 0);383	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,384			  V4L2_CID_HUE, -128, 127, 1, 0);385	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,386			  V4L2_CID_RED_BALANCE, -4, 3, 1, 0);387	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,388			  V4L2_CID_BLUE_BALANCE, -4, 3, 1, 0);389	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,390			  V4L2_CID_SHARPNESS, 0, 1, 1, 0);391	v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,392			  V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);393	priv->sd.ctrl_handler = &priv->hdl;394 395	ret = priv->hdl.error;396	if (ret)397		goto cleanup;398 399	v4l2_ctrl_handler_setup(&priv->hdl);400 401	ret = ml86v7667_init(priv);402	if (ret)403		goto cleanup;404 405	v4l_info(client, "chip found @ 0x%02x (%s)\n",406		 client->addr, client->adapter->name);407	return 0;408 409cleanup:410	v4l2_ctrl_handler_free(&priv->hdl);411	v4l2_device_unregister_subdev(&priv->sd);412	v4l_err(client, "failed to probe @ 0x%02x (%s)\n",413		client->addr, client->adapter->name);414	return ret;415}416 417static void ml86v7667_remove(struct i2c_client *client)418{419	struct v4l2_subdev *sd = i2c_get_clientdata(client);420	struct ml86v7667_priv *priv = to_ml86v7667(sd);421 422	v4l2_ctrl_handler_free(&priv->hdl);423	v4l2_device_unregister_subdev(&priv->sd);424}425 426static const struct i2c_device_id ml86v7667_id[] = {427	{ DRV_NAME },428	{}429};430MODULE_DEVICE_TABLE(i2c, ml86v7667_id);431 432static struct i2c_driver ml86v7667_i2c_driver = {433	.driver = {434		.name	= DRV_NAME,435	},436	.probe		= ml86v7667_probe,437	.remove		= ml86v7667_remove,438	.id_table	= ml86v7667_id,439};440 441module_i2c_driver(ml86v7667_i2c_driver);442 443MODULE_DESCRIPTION("OKI Semiconductor ML86V7667 video decoder driver");444MODULE_AUTHOR("Vladimir Barinov");445MODULE_LICENSE("GPL");446