root/drivers/media/i2c/ml86v7667.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_ml86v7667
  2. to_sd
  3. ml86v7667_mask_set
  4. ml86v7667_s_ctrl
  5. ml86v7667_querystd
  6. ml86v7667_g_input_status
  7. ml86v7667_enum_mbus_code
  8. ml86v7667_fill_fmt
  9. ml86v7667_g_mbus_config
  10. ml86v7667_g_std
  11. ml86v7667_s_std
  12. ml86v7667_g_register
  13. ml86v7667_s_register
  14. ml86v7667_init
  15. ml86v7667_probe
  16. ml86v7667_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * OKI Semiconductor ML86V7667 video decoder driver
   4  *
   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        7
  50 #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       0x0F
  55 
  56 /* Sync separation level register bits */
  57 #define SSEPL_LUMINANCE_ONOFF   (1 << 7)
  58 #define SSEPL_LUMINANCE_MASK    0x7F
  59 
  60 /* Chrominance Control A register bits */
  61 #define CHRCA_MODE_SHIFT        6
  62 #define CHRCA_MODE_MASK         (1 << 6)
  63 
  64 /* ACC Loop filter & Chrominance control register bits */
  65 #define ACCC_CHROMA_CR_SHIFT    3
  66 #define ACCC_CHROMA_CR_MASK     (7 << 3)
  67 #define ACCC_CHROMA_CB_SHIFT    0
  68 #define ACCC_CHROMA_CB_MASK     (7 << 0)
  69 
  70 /* ACC Reference level control register bits */
  71 #define ACCRC_CHROMA_MASK       0xfc
  72 #define ACCRC_CHROMA_SHIFT      2
  73 
  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 
  85 struct ml86v7667_priv {
  86         struct v4l2_subdev              sd;
  87         struct v4l2_ctrl_handler        hdl;
  88         v4l2_std_id                     std;
  89 };
  90 
  91 static inline struct ml86v7667_priv *to_ml86v7667(struct v4l2_subdev *subdev)
  92 {
  93         return container_of(subdev, struct ml86v7667_priv, sd);
  94 }
  95 
  96 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
  97 {
  98         return &container_of(ctrl->handler, struct ml86v7667_priv, hdl)->sd;
  99 }
 100 
 101 static 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 
 112 static 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 
 159 static 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         else
 171                 *std = V4L2_STD_UNKNOWN;
 172 
 173         return 0;
 174 }
 175 
 176 static 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 
 190 static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd,
 191                 struct v4l2_subdev_pad_config *cfg,
 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 
 202 static int ml86v7667_fill_fmt(struct v4l2_subdev *sd,
 203                 struct v4l2_subdev_pad_config *cfg,
 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 
 222 static int ml86v7667_g_mbus_config(struct v4l2_subdev *sd,
 223                                    struct v4l2_mbus_config *cfg)
 224 {
 225         cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
 226                      V4L2_MBUS_DATA_ACTIVE_HIGH;
 227         cfg->type = V4L2_MBUS_BT656;
 228 
 229         return 0;
 230 }
 231 
 232 static int ml86v7667_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
 233 {
 234         struct ml86v7667_priv *priv = to_ml86v7667(sd);
 235 
 236         *std = priv->std;
 237 
 238         return 0;
 239 }
 240 
 241 static int ml86v7667_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 242 {
 243         struct ml86v7667_priv *priv = to_ml86v7667(sd);
 244         struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
 245         int ret;
 246         u8 mode;
 247 
 248         /* PAL/NTSC ITU-R BT.601 input mode */
 249         mode = std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
 250         ret = ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, mode);
 251         if (ret < 0)
 252                 return ret;
 253 
 254         priv->std = std;
 255 
 256         return 0;
 257 }
 258 
 259 #ifdef CONFIG_VIDEO_ADV_DEBUG
 260 static int ml86v7667_g_register(struct v4l2_subdev *sd,
 261                                 struct v4l2_dbg_register *reg)
 262 {
 263         struct i2c_client *client = v4l2_get_subdevdata(sd);
 264         int ret;
 265 
 266         ret = i2c_smbus_read_byte_data(client, (u8)reg->reg);
 267         if (ret < 0)
 268                 return ret;
 269 
 270         reg->val = ret;
 271         reg->size = sizeof(u8);
 272 
 273         return 0;
 274 }
 275 
 276 static int ml86v7667_s_register(struct v4l2_subdev *sd,
 277                                 const struct v4l2_dbg_register *reg)
 278 {
 279         struct i2c_client *client = v4l2_get_subdevdata(sd);
 280 
 281         return i2c_smbus_write_byte_data(client, (u8)reg->reg, (u8)reg->val);
 282 }
 283 #endif
 284 
 285 static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
 286         .s_ctrl = ml86v7667_s_ctrl,
 287 };
 288 
 289 static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
 290         .g_std = ml86v7667_g_std,
 291         .s_std = ml86v7667_s_std,
 292         .querystd = ml86v7667_querystd,
 293         .g_input_status = ml86v7667_g_input_status,
 294         .g_mbus_config = ml86v7667_g_mbus_config,
 295 };
 296 
 297 static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = {
 298         .enum_mbus_code = ml86v7667_enum_mbus_code,
 299         .get_fmt = ml86v7667_fill_fmt,
 300         .set_fmt = ml86v7667_fill_fmt,
 301 };
 302 
 303 static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
 304 #ifdef CONFIG_VIDEO_ADV_DEBUG
 305         .g_register = ml86v7667_g_register,
 306         .s_register = ml86v7667_s_register,
 307 #endif
 308 };
 309 
 310 static const struct v4l2_subdev_ops ml86v7667_subdev_ops = {
 311         .core = &ml86v7667_subdev_core_ops,
 312         .video = &ml86v7667_subdev_video_ops,
 313         .pad = &ml86v7667_subdev_pad_ops,
 314 };
 315 
 316 static int ml86v7667_init(struct ml86v7667_priv *priv)
 317 {
 318         struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
 319         int val;
 320         int ret;
 321 
 322         /* BT.656-4 output mode, register mode */
 323         ret = ml86v7667_mask_set(client, MRA_REG,
 324                                  MRA_OUTPUT_MODE_MASK | MRA_REGISTER_MODE,
 325                                  MRA_ITUR_BT656 | MRA_REGISTER_MODE);
 326 
 327         /* PLL circuit fixed clock, 32MHz */
 328         ret |= ml86v7667_mask_set(client, PLLR1_REG, PLLR1_FIXED_CLOCK,
 329                                   PLLR1_FIXED_CLOCK);
 330 
 331         /* ADC2 clamping voltage maximum  */
 332         ret |= ml86v7667_mask_set(client, ADC2_REG, ADC2_CLAMP_VOLTAGE_MASK,
 333                                   ADC2_CLAMP_VOLTAGE(7));
 334 
 335         /* enable luminance function */
 336         ret |= ml86v7667_mask_set(client, SSEPL_REG, SSEPL_LUMINANCE_ONOFF,
 337                                   SSEPL_LUMINANCE_ONOFF);
 338 
 339         /* enable contrast function */
 340         ret |= ml86v7667_mask_set(client, CLC_REG, CLC_CONTRAST_ONOFF, 0);
 341 
 342         /*
 343          * PAL/NTSC autodetection is enabled after reset,
 344          * set the autodetected std in manual std mode and
 345          * disable autodetection
 346          */
 347         val = i2c_smbus_read_byte_data(client, STATUS_REG);
 348         if (val < 0)
 349                 return val;
 350 
 351         priv->std = val & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;
 352         ret |= ml86v7667_mask_set(client, MRC_REG, MRC_AUTOSELECT, 0);
 353 
 354         val = priv->std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
 355         ret |= ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, val);
 356 
 357         return ret;
 358 }
 359 
 360 static int ml86v7667_probe(struct i2c_client *client,
 361                            const struct i2c_device_id *did)
 362 {
 363         struct ml86v7667_priv *priv;
 364         int ret;
 365 
 366         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 367                 return -EIO;
 368 
 369         priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
 370         if (!priv)
 371                 return -ENOMEM;
 372 
 373         v4l2_i2c_subdev_init(&priv->sd, client, &ml86v7667_subdev_ops);
 374 
 375         v4l2_ctrl_handler_init(&priv->hdl, 8);
 376         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 377                           V4L2_CID_BRIGHTNESS, -64, 63, 1, 0);
 378         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 379                           V4L2_CID_CONTRAST, -8, 7, 1, 0);
 380         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 381                           V4L2_CID_CHROMA_GAIN, -32, 31, 1, 0);
 382         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 383                           V4L2_CID_HUE, -128, 127, 1, 0);
 384         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 385                           V4L2_CID_RED_BALANCE, -4, 3, 1, 0);
 386         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 387                           V4L2_CID_BLUE_BALANCE, -4, 3, 1, 0);
 388         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 389                           V4L2_CID_SHARPNESS, 0, 1, 1, 0);
 390         v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
 391                           V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
 392         priv->sd.ctrl_handler = &priv->hdl;
 393 
 394         ret = priv->hdl.error;
 395         if (ret)
 396                 goto cleanup;
 397 
 398         v4l2_ctrl_handler_setup(&priv->hdl);
 399 
 400         ret = ml86v7667_init(priv);
 401         if (ret)
 402                 goto cleanup;
 403 
 404         v4l_info(client, "chip found @ 0x%02x (%s)\n",
 405                  client->addr, client->adapter->name);
 406         return 0;
 407 
 408 cleanup:
 409         v4l2_ctrl_handler_free(&priv->hdl);
 410         v4l2_device_unregister_subdev(&priv->sd);
 411         v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
 412                 client->addr, client->adapter->name);
 413         return ret;
 414 }
 415 
 416 static int ml86v7667_remove(struct i2c_client *client)
 417 {
 418         struct v4l2_subdev *sd = i2c_get_clientdata(client);
 419         struct ml86v7667_priv *priv = to_ml86v7667(sd);
 420 
 421         v4l2_ctrl_handler_free(&priv->hdl);
 422         v4l2_device_unregister_subdev(&priv->sd);
 423 
 424         return 0;
 425 }
 426 
 427 static const struct i2c_device_id ml86v7667_id[] = {
 428         {DRV_NAME, 0},
 429         {},
 430 };
 431 MODULE_DEVICE_TABLE(i2c, ml86v7667_id);
 432 
 433 static struct i2c_driver ml86v7667_i2c_driver = {
 434         .driver = {
 435                 .name   = DRV_NAME,
 436         },
 437         .probe          = ml86v7667_probe,
 438         .remove         = ml86v7667_remove,
 439         .id_table       = ml86v7667_id,
 440 };
 441 
 442 module_i2c_driver(ml86v7667_i2c_driver);
 443 
 444 MODULE_DESCRIPTION("OKI Semiconductor ML86V7667 video decoder driver");
 445 MODULE_AUTHOR("Vladimir Barinov");
 446 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */