0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/i2c.h>
0013 #include <linux/slab.h>
0014 #include <linux/videodev2.h>
0015 #include <media/v4l2-subdev.h>
0016 #include <media/v4l2-device.h>
0017 #include <media/v4l2-ioctl.h>
0018 #include <media/v4l2-ctrls.h>
0019
0020 #define DRV_NAME "ml86v7667"
0021
0022
0023 #define MRA_REG 0x00
0024 #define MRC_REG 0x02
0025 #define LUMC_REG 0x0C
0026 #define CLC_REG 0x10
0027 #define SSEPL_REG 0x11
0028 #define CHRCA_REG 0x12
0029 #define ACCC_REG 0x14
0030 #define ACCRC_REG 0x15
0031 #define HUE_REG 0x16
0032 #define ADC2_REG 0x1F
0033 #define PLLR1_REG 0x20
0034 #define STATUS_REG 0x2C
0035
0036
0037 #define MRA_OUTPUT_MODE_MASK (3 << 6)
0038 #define MRA_ITUR_BT601 (1 << 6)
0039 #define MRA_ITUR_BT656 (0 << 6)
0040 #define MRA_INPUT_MODE_MASK (7 << 3)
0041 #define MRA_PAL_BT601 (4 << 3)
0042 #define MRA_NTSC_BT601 (0 << 3)
0043 #define MRA_REGISTER_MODE (1 << 0)
0044
0045
0046 #define MRC_AUTOSELECT (1 << 7)
0047
0048
0049 #define LUMC_ONOFF_SHIFT 7
0050 #define LUMC_ONOFF_MASK (1 << 7)
0051
0052
0053 #define CLC_CONTRAST_ONOFF (1 << 7)
0054 #define CLC_CONTRAST_MASK 0x0F
0055
0056
0057 #define SSEPL_LUMINANCE_ONOFF (1 << 7)
0058 #define SSEPL_LUMINANCE_MASK 0x7F
0059
0060
0061 #define CHRCA_MODE_SHIFT 6
0062 #define CHRCA_MODE_MASK (1 << 6)
0063
0064
0065 #define ACCC_CHROMA_CR_SHIFT 3
0066 #define ACCC_CHROMA_CR_MASK (7 << 3)
0067 #define ACCC_CHROMA_CB_SHIFT 0
0068 #define ACCC_CHROMA_CB_MASK (7 << 0)
0069
0070
0071 #define ACCRC_CHROMA_MASK 0xfc
0072 #define ACCRC_CHROMA_SHIFT 2
0073
0074
0075 #define ADC2_CLAMP_VOLTAGE_MASK (7 << 1)
0076 #define ADC2_CLAMP_VOLTAGE(n) ((n & 7) << 1)
0077
0078
0079 #define PLLR1_FIXED_CLOCK (1 << 7)
0080
0081
0082 #define STATUS_HLOCK_DETECT (1 << 3)
0083 #define STATUS_NTSCPAL (1 << 2)
0084
0085 struct ml86v7667_priv {
0086 struct v4l2_subdev sd;
0087 struct v4l2_ctrl_handler hdl;
0088 v4l2_std_id std;
0089 };
0090
0091 static inline struct ml86v7667_priv *to_ml86v7667(struct v4l2_subdev *subdev)
0092 {
0093 return container_of(subdev, struct ml86v7667_priv, sd);
0094 }
0095
0096 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
0097 {
0098 return &container_of(ctrl->handler, struct ml86v7667_priv, hdl)->sd;
0099 }
0100
0101 static int ml86v7667_mask_set(struct i2c_client *client, const u8 reg,
0102 const u8 mask, const u8 data)
0103 {
0104 int val = i2c_smbus_read_byte_data(client, reg);
0105 if (val < 0)
0106 return val;
0107
0108 val = (val & ~mask) | (data & mask);
0109 return i2c_smbus_write_byte_data(client, reg, val);
0110 }
0111
0112 static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
0113 {
0114 struct v4l2_subdev *sd = to_sd(ctrl);
0115 struct i2c_client *client = v4l2_get_subdevdata(sd);
0116 int ret = -EINVAL;
0117
0118 switch (ctrl->id) {
0119 case V4L2_CID_BRIGHTNESS:
0120 ret = ml86v7667_mask_set(client, SSEPL_REG,
0121 SSEPL_LUMINANCE_MASK, ctrl->val);
0122 break;
0123 case V4L2_CID_CONTRAST:
0124 ret = ml86v7667_mask_set(client, CLC_REG,
0125 CLC_CONTRAST_MASK, ctrl->val);
0126 break;
0127 case V4L2_CID_CHROMA_GAIN:
0128 ret = ml86v7667_mask_set(client, ACCRC_REG, ACCRC_CHROMA_MASK,
0129 ctrl->val << ACCRC_CHROMA_SHIFT);
0130 break;
0131 case V4L2_CID_HUE:
0132 ret = ml86v7667_mask_set(client, HUE_REG, ~0, ctrl->val);
0133 break;
0134 case V4L2_CID_RED_BALANCE:
0135 ret = ml86v7667_mask_set(client, ACCC_REG,
0136 ACCC_CHROMA_CR_MASK,
0137 ctrl->val << ACCC_CHROMA_CR_SHIFT);
0138 break;
0139 case V4L2_CID_BLUE_BALANCE:
0140 ret = ml86v7667_mask_set(client, ACCC_REG,
0141 ACCC_CHROMA_CB_MASK,
0142 ctrl->val << ACCC_CHROMA_CB_SHIFT);
0143 break;
0144 case V4L2_CID_SHARPNESS:
0145 ret = ml86v7667_mask_set(client, LUMC_REG,
0146 LUMC_ONOFF_MASK,
0147 ctrl->val << LUMC_ONOFF_SHIFT);
0148 break;
0149 case V4L2_CID_COLOR_KILLER:
0150 ret = ml86v7667_mask_set(client, CHRCA_REG,
0151 CHRCA_MODE_MASK,
0152 ctrl->val << CHRCA_MODE_SHIFT);
0153 break;
0154 }
0155
0156 return ret;
0157 }
0158
0159 static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
0160 {
0161 struct i2c_client *client = v4l2_get_subdevdata(sd);
0162 int status;
0163
0164 status = i2c_smbus_read_byte_data(client, STATUS_REG);
0165 if (status < 0)
0166 return status;
0167
0168 if (status & STATUS_HLOCK_DETECT)
0169 *std &= status & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;
0170 else
0171 *std = V4L2_STD_UNKNOWN;
0172
0173 return 0;
0174 }
0175
0176 static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status)
0177 {
0178 struct i2c_client *client = v4l2_get_subdevdata(sd);
0179 int status_reg;
0180
0181 status_reg = i2c_smbus_read_byte_data(client, STATUS_REG);
0182 if (status_reg < 0)
0183 return status_reg;
0184
0185 *status = status_reg & STATUS_HLOCK_DETECT ? 0 : V4L2_IN_ST_NO_SIGNAL;
0186
0187 return 0;
0188 }
0189
0190 static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd,
0191 struct v4l2_subdev_state *sd_state,
0192 struct v4l2_subdev_mbus_code_enum *code)
0193 {
0194 if (code->pad || code->index > 0)
0195 return -EINVAL;
0196
0197 code->code = MEDIA_BUS_FMT_YUYV8_2X8;
0198
0199 return 0;
0200 }
0201
0202 static int ml86v7667_fill_fmt(struct v4l2_subdev *sd,
0203 struct v4l2_subdev_state *sd_state,
0204 struct v4l2_subdev_format *format)
0205 {
0206 struct ml86v7667_priv *priv = to_ml86v7667(sd);
0207 struct v4l2_mbus_framefmt *fmt = &format->format;
0208
0209 if (format->pad)
0210 return -EINVAL;
0211
0212 fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
0213 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
0214
0215 fmt->field = V4L2_FIELD_INTERLACED_TB;
0216 fmt->width = 720;
0217 fmt->height = priv->std & V4L2_STD_525_60 ? 480 : 576;
0218
0219 return 0;
0220 }
0221
0222 static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd,
0223 unsigned int pad,
0224 struct v4l2_mbus_config *cfg)
0225 {
0226 cfg->type = V4L2_MBUS_BT656;
0227 cfg->bus.parallel.flags = V4L2_MBUS_MASTER |
0228 V4L2_MBUS_PCLK_SAMPLE_RISING |
0229 V4L2_MBUS_DATA_ACTIVE_HIGH;
0230
0231 return 0;
0232 }
0233
0234 static int ml86v7667_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
0235 {
0236 struct ml86v7667_priv *priv = to_ml86v7667(sd);
0237
0238 *std = priv->std;
0239
0240 return 0;
0241 }
0242
0243 static int ml86v7667_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
0244 {
0245 struct ml86v7667_priv *priv = to_ml86v7667(sd);
0246 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
0247 int ret;
0248 u8 mode;
0249
0250
0251 mode = std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
0252 ret = ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, mode);
0253 if (ret < 0)
0254 return ret;
0255
0256 priv->std = std;
0257
0258 return 0;
0259 }
0260
0261 #ifdef CONFIG_VIDEO_ADV_DEBUG
0262 static int ml86v7667_g_register(struct v4l2_subdev *sd,
0263 struct v4l2_dbg_register *reg)
0264 {
0265 struct i2c_client *client = v4l2_get_subdevdata(sd);
0266 int ret;
0267
0268 ret = i2c_smbus_read_byte_data(client, (u8)reg->reg);
0269 if (ret < 0)
0270 return ret;
0271
0272 reg->val = ret;
0273 reg->size = sizeof(u8);
0274
0275 return 0;
0276 }
0277
0278 static int ml86v7667_s_register(struct v4l2_subdev *sd,
0279 const struct v4l2_dbg_register *reg)
0280 {
0281 struct i2c_client *client = v4l2_get_subdevdata(sd);
0282
0283 return i2c_smbus_write_byte_data(client, (u8)reg->reg, (u8)reg->val);
0284 }
0285 #endif
0286
0287 static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
0288 .s_ctrl = ml86v7667_s_ctrl,
0289 };
0290
0291 static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
0292 .g_std = ml86v7667_g_std,
0293 .s_std = ml86v7667_s_std,
0294 .querystd = ml86v7667_querystd,
0295 .g_input_status = ml86v7667_g_input_status,
0296 };
0297
0298 static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = {
0299 .enum_mbus_code = ml86v7667_enum_mbus_code,
0300 .get_fmt = ml86v7667_fill_fmt,
0301 .set_fmt = ml86v7667_fill_fmt,
0302 .get_mbus_config = ml86v7667_get_mbus_config,
0303 };
0304
0305 static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
0306 #ifdef CONFIG_VIDEO_ADV_DEBUG
0307 .g_register = ml86v7667_g_register,
0308 .s_register = ml86v7667_s_register,
0309 #endif
0310 };
0311
0312 static const struct v4l2_subdev_ops ml86v7667_subdev_ops = {
0313 .core = &ml86v7667_subdev_core_ops,
0314 .video = &ml86v7667_subdev_video_ops,
0315 .pad = &ml86v7667_subdev_pad_ops,
0316 };
0317
0318 static int ml86v7667_init(struct ml86v7667_priv *priv)
0319 {
0320 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
0321 int val;
0322 int ret;
0323
0324
0325 ret = ml86v7667_mask_set(client, MRA_REG,
0326 MRA_OUTPUT_MODE_MASK | MRA_REGISTER_MODE,
0327 MRA_ITUR_BT656 | MRA_REGISTER_MODE);
0328
0329
0330 ret |= ml86v7667_mask_set(client, PLLR1_REG, PLLR1_FIXED_CLOCK,
0331 PLLR1_FIXED_CLOCK);
0332
0333
0334 ret |= ml86v7667_mask_set(client, ADC2_REG, ADC2_CLAMP_VOLTAGE_MASK,
0335 ADC2_CLAMP_VOLTAGE(7));
0336
0337
0338 ret |= ml86v7667_mask_set(client, SSEPL_REG, SSEPL_LUMINANCE_ONOFF,
0339 SSEPL_LUMINANCE_ONOFF);
0340
0341
0342 ret |= ml86v7667_mask_set(client, CLC_REG, CLC_CONTRAST_ONOFF, 0);
0343
0344
0345
0346
0347
0348
0349 val = i2c_smbus_read_byte_data(client, STATUS_REG);
0350 if (val < 0)
0351 return val;
0352
0353 priv->std = val & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;
0354 ret |= ml86v7667_mask_set(client, MRC_REG, MRC_AUTOSELECT, 0);
0355
0356 val = priv->std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
0357 ret |= ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, val);
0358
0359 return ret;
0360 }
0361
0362 static int ml86v7667_probe(struct i2c_client *client,
0363 const struct i2c_device_id *did)
0364 {
0365 struct ml86v7667_priv *priv;
0366 int ret;
0367
0368 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
0369 return -EIO;
0370
0371 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
0372 if (!priv)
0373 return -ENOMEM;
0374
0375 v4l2_i2c_subdev_init(&priv->sd, client, &ml86v7667_subdev_ops);
0376
0377 v4l2_ctrl_handler_init(&priv->hdl, 8);
0378 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0379 V4L2_CID_BRIGHTNESS, -64, 63, 1, 0);
0380 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0381 V4L2_CID_CONTRAST, -8, 7, 1, 0);
0382 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0383 V4L2_CID_CHROMA_GAIN, -32, 31, 1, 0);
0384 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0385 V4L2_CID_HUE, -128, 127, 1, 0);
0386 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0387 V4L2_CID_RED_BALANCE, -4, 3, 1, 0);
0388 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0389 V4L2_CID_BLUE_BALANCE, -4, 3, 1, 0);
0390 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0391 V4L2_CID_SHARPNESS, 0, 1, 1, 0);
0392 v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
0393 V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
0394 priv->sd.ctrl_handler = &priv->hdl;
0395
0396 ret = priv->hdl.error;
0397 if (ret)
0398 goto cleanup;
0399
0400 v4l2_ctrl_handler_setup(&priv->hdl);
0401
0402 ret = ml86v7667_init(priv);
0403 if (ret)
0404 goto cleanup;
0405
0406 v4l_info(client, "chip found @ 0x%02x (%s)\n",
0407 client->addr, client->adapter->name);
0408 return 0;
0409
0410 cleanup:
0411 v4l2_ctrl_handler_free(&priv->hdl);
0412 v4l2_device_unregister_subdev(&priv->sd);
0413 v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
0414 client->addr, client->adapter->name);
0415 return ret;
0416 }
0417
0418 static int ml86v7667_remove(struct i2c_client *client)
0419 {
0420 struct v4l2_subdev *sd = i2c_get_clientdata(client);
0421 struct ml86v7667_priv *priv = to_ml86v7667(sd);
0422
0423 v4l2_ctrl_handler_free(&priv->hdl);
0424 v4l2_device_unregister_subdev(&priv->sd);
0425
0426 return 0;
0427 }
0428
0429 static const struct i2c_device_id ml86v7667_id[] = {
0430 {DRV_NAME, 0},
0431 {},
0432 };
0433 MODULE_DEVICE_TABLE(i2c, ml86v7667_id);
0434
0435 static struct i2c_driver ml86v7667_i2c_driver = {
0436 .driver = {
0437 .name = DRV_NAME,
0438 },
0439 .probe = ml86v7667_probe,
0440 .remove = ml86v7667_remove,
0441 .id_table = ml86v7667_id,
0442 };
0443
0444 module_i2c_driver(ml86v7667_i2c_driver);
0445
0446 MODULE_DESCRIPTION("OKI Semiconductor ML86V7667 video decoder driver");
0447 MODULE_AUTHOR("Vladimir Barinov");
0448 MODULE_LICENSE("GPL");