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