Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * OKI Semiconductor ML86V7667 video decoder driver
0004  *
0005  * Author: Vladimir Barinov <source@cogentembedded.com>
0006  * Copyright (C) 2013 Cogent Embedded, Inc.
0007  * Copyright (C) 2013 Renesas Solutions Corp.
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 /* Subaddresses */
0023 #define MRA_REG         0x00 /* Mode Register A */
0024 #define MRC_REG         0x02 /* Mode Register C */
0025 #define LUMC_REG        0x0C /* Luminance Control */
0026 #define CLC_REG         0x10 /* Contrast level control */
0027 #define SSEPL_REG       0x11 /* Sync separation level */
0028 #define CHRCA_REG       0x12 /* Chrominance Control A */
0029 #define ACCC_REG        0x14 /* ACC Loop filter & Chrominance control */
0030 #define ACCRC_REG       0x15 /* ACC Reference level control */
0031 #define HUE_REG         0x16 /* Hue control */
0032 #define ADC2_REG        0x1F /* ADC Register 2 */
0033 #define PLLR1_REG       0x20 /* PLL Register 1 */
0034 #define STATUS_REG      0x2C /* STATUS Register */
0035 
0036 /* Mode Register A register bits */
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 /* Mode Register C register bits */
0046 #define MRC_AUTOSELECT      (1 << 7)
0047 
0048 /* Luminance Control register bits */
0049 #define LUMC_ONOFF_SHIFT    7
0050 #define LUMC_ONOFF_MASK     (1 << 7)
0051 
0052 /* Contrast level control register bits */
0053 #define CLC_CONTRAST_ONOFF  (1 << 7)
0054 #define CLC_CONTRAST_MASK   0x0F
0055 
0056 /* Sync separation level register bits */
0057 #define SSEPL_LUMINANCE_ONOFF   (1 << 7)
0058 #define SSEPL_LUMINANCE_MASK    0x7F
0059 
0060 /* Chrominance Control A register bits */
0061 #define CHRCA_MODE_SHIFT    6
0062 #define CHRCA_MODE_MASK     (1 << 6)
0063 
0064 /* ACC Loop filter & Chrominance control register bits */
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 /* ACC Reference level control register bits */
0071 #define ACCRC_CHROMA_MASK   0xfc
0072 #define ACCRC_CHROMA_SHIFT  2
0073 
0074 /* ADC Register 2 register bits */
0075 #define ADC2_CLAMP_VOLTAGE_MASK (7 << 1)
0076 #define ADC2_CLAMP_VOLTAGE(n)   ((n & 7) << 1)
0077 
0078 /* PLL Register 1 register bits */
0079 #define PLLR1_FIXED_CLOCK   (1 << 7)
0080 
0081 /* STATUS Register register bits */
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     /* The top field is always transferred first by the chip */
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     /* PAL/NTSC ITU-R BT.601 input mode */
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     /* BT.656-4 output mode, register mode */
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     /* PLL circuit fixed clock, 32MHz */
0330     ret |= ml86v7667_mask_set(client, PLLR1_REG, PLLR1_FIXED_CLOCK,
0331                   PLLR1_FIXED_CLOCK);
0332 
0333     /* ADC2 clamping voltage maximum  */
0334     ret |= ml86v7667_mask_set(client, ADC2_REG, ADC2_CLAMP_VOLTAGE_MASK,
0335                   ADC2_CLAMP_VOLTAGE(7));
0336 
0337     /* enable luminance function */
0338     ret |= ml86v7667_mask_set(client, SSEPL_REG, SSEPL_LUMINANCE_ONOFF,
0339                   SSEPL_LUMINANCE_ONOFF);
0340 
0341     /* enable contrast function */
0342     ret |= ml86v7667_mask_set(client, CLC_REG, CLC_CONTRAST_ONOFF, 0);
0343 
0344     /*
0345      * PAL/NTSC autodetection is enabled after reset,
0346      * set the autodetected std in manual std mode and
0347      * disable autodetection
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");