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