linux/drivers/media/i2c/ml86v7667.c
<<
>>
Prefs
   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
  85struct ml86v7667_priv {
  86        struct v4l2_subdev              sd;
  87        struct v4l2_ctrl_handler        hdl;
  88        v4l2_std_id                     std;
  89};
  90
  91static inline struct ml86v7667_priv *to_ml86v7667(struct v4l2_subdev *subdev)
  92{
  93        return container_of(subdev, struct ml86v7667_priv, sd);
  94}
  95
  96static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
  97{
  98        return &container_of(ctrl->handler, struct ml86v7667_priv, hdl)->sd;
  99}
 100
 101static 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
 112static 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
 159static 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
 176static 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
 190static 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
 202static 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
 222static 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
 232static 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
 241static 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
 260static 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
 276static 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
 285static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
 286        .s_ctrl = ml86v7667_s_ctrl,
 287};
 288
 289static 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
 297static 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
 303static 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
 310static 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
 316static 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
 360static 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
 408cleanup:
 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
 416static 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
 427static const struct i2c_device_id ml86v7667_id[] = {
 428        {DRV_NAME, 0},
 429        {},
 430};
 431MODULE_DEVICE_TABLE(i2c, ml86v7667_id);
 432
 433static 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
 442module_i2c_driver(ml86v7667_i2c_driver);
 443
 444MODULE_DESCRIPTION("OKI Semiconductor ML86V7667 video decoder driver");
 445MODULE_AUTHOR("Vladimir Barinov");
 446MODULE_LICENSE("GPL");
 447