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