linux/drivers/media/i2c/ak881x.c
<<
>>
Prefs
   1/*
   2 * Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
   3 *
   4 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/i2c.h>
  12#include <linux/init.h>
  13#include <linux/platform_device.h>
  14#include <linux/slab.h>
  15#include <linux/videodev2.h>
  16#include <linux/module.h>
  17
  18#include <media/ak881x.h>
  19#include <media/v4l2-common.h>
  20#include <media/v4l2-device.h>
  21
  22#define AK881X_INTERFACE_MODE   0
  23#define AK881X_VIDEO_PROCESS1   1
  24#define AK881X_VIDEO_PROCESS2   2
  25#define AK881X_VIDEO_PROCESS3   3
  26#define AK881X_DAC_MODE         5
  27#define AK881X_STATUS           0x24
  28#define AK881X_DEVICE_ID        0x25
  29#define AK881X_DEVICE_REVISION  0x26
  30
  31struct ak881x {
  32        struct v4l2_subdev subdev;
  33        struct ak881x_pdata *pdata;
  34        unsigned int lines;
  35        char revision;  /* DEVICE_REVISION content */
  36};
  37
  38static int reg_read(struct i2c_client *client, const u8 reg)
  39{
  40        return i2c_smbus_read_byte_data(client, reg);
  41}
  42
  43static int reg_write(struct i2c_client *client, const u8 reg,
  44                     const u8 data)
  45{
  46        return i2c_smbus_write_byte_data(client, reg, data);
  47}
  48
  49static int reg_set(struct i2c_client *client, const u8 reg,
  50                   const u8 data, u8 mask)
  51{
  52        int ret = reg_read(client, reg);
  53        if (ret < 0)
  54                return ret;
  55        return reg_write(client, reg, (ret & ~mask) | (data & mask));
  56}
  57
  58static struct ak881x *to_ak881x(const struct i2c_client *client)
  59{
  60        return container_of(i2c_get_clientdata(client), struct ak881x, subdev);
  61}
  62
  63#ifdef CONFIG_VIDEO_ADV_DEBUG
  64static int ak881x_g_register(struct v4l2_subdev *sd,
  65                             struct v4l2_dbg_register *reg)
  66{
  67        struct i2c_client *client = v4l2_get_subdevdata(sd);
  68
  69        if (reg->reg > 0x26)
  70                return -EINVAL;
  71
  72        reg->size = 1;
  73        reg->val = reg_read(client, reg->reg);
  74
  75        if (reg->val > 0xffff)
  76                return -EIO;
  77
  78        return 0;
  79}
  80
  81static int ak881x_s_register(struct v4l2_subdev *sd,
  82                             const struct v4l2_dbg_register *reg)
  83{
  84        struct i2c_client *client = v4l2_get_subdevdata(sd);
  85
  86        if (reg->reg > 0x26)
  87                return -EINVAL;
  88
  89        if (reg_write(client, reg->reg, reg->val) < 0)
  90                return -EIO;
  91
  92        return 0;
  93}
  94#endif
  95
  96static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
  97                                 struct v4l2_mbus_framefmt *mf)
  98{
  99        struct i2c_client *client = v4l2_get_subdevdata(sd);
 100        struct ak881x *ak881x = to_ak881x(client);
 101
 102        v4l_bound_align_image(&mf->width, 0, 720, 2,
 103                              &mf->height, 0, ak881x->lines, 1, 0);
 104        mf->field       = V4L2_FIELD_INTERLACED;
 105        mf->code        = V4L2_MBUS_FMT_YUYV8_2X8;
 106        mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
 107
 108        return 0;
 109}
 110
 111static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
 112                             struct v4l2_mbus_framefmt *mf)
 113{
 114        if (mf->field != V4L2_FIELD_INTERLACED ||
 115            mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
 116                return -EINVAL;
 117
 118        return ak881x_try_g_mbus_fmt(sd, mf);
 119}
 120
 121static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
 122                                enum v4l2_mbus_pixelcode *code)
 123{
 124        if (index)
 125                return -EINVAL;
 126
 127        *code = V4L2_MBUS_FMT_YUYV8_2X8;
 128        return 0;
 129}
 130
 131static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 132{
 133        struct i2c_client *client = v4l2_get_subdevdata(sd);
 134        struct ak881x *ak881x = to_ak881x(client);
 135
 136        a->bounds.left                  = 0;
 137        a->bounds.top                   = 0;
 138        a->bounds.width                 = 720;
 139        a->bounds.height                = ak881x->lines;
 140        a->defrect                      = a->bounds;
 141        a->type                         = V4L2_BUF_TYPE_VIDEO_OUTPUT;
 142        a->pixelaspect.numerator        = 1;
 143        a->pixelaspect.denominator      = 1;
 144
 145        return 0;
 146}
 147
 148static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
 149{
 150        struct i2c_client *client = v4l2_get_subdevdata(sd);
 151        struct ak881x *ak881x = to_ak881x(client);
 152        u8 vp1;
 153
 154        if (std == V4L2_STD_NTSC_443) {
 155                vp1 = 3;
 156                ak881x->lines = 480;
 157        } else if (std == V4L2_STD_PAL_M) {
 158                vp1 = 5;
 159                ak881x->lines = 480;
 160        } else if (std == V4L2_STD_PAL_60) {
 161                vp1 = 7;
 162                ak881x->lines = 480;
 163        } else if (std && !(std & ~V4L2_STD_PAL)) {
 164                vp1 = 0xf;
 165                ak881x->lines = 576;
 166        } else if (std && !(std & ~V4L2_STD_NTSC)) {
 167                vp1 = 0;
 168                ak881x->lines = 480;
 169        } else {
 170                /* No SECAM or PAL_N/Nc supported */
 171                return -EINVAL;
 172        }
 173
 174        reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf);
 175
 176        return 0;
 177}
 178
 179static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
 180{
 181        struct i2c_client *client = v4l2_get_subdevdata(sd);
 182        struct ak881x *ak881x = to_ak881x(client);
 183
 184        if (enable) {
 185                u8 dac;
 186                /* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */
 187                /* Default: composite output */
 188                if (ak881x->pdata->flags & AK881X_COMPONENT)
 189                        dac = 3;
 190                else
 191                        dac = 4;
 192                /* Turn on the DAC(s) */
 193                reg_write(client, AK881X_DAC_MODE, dac);
 194                dev_dbg(&client->dev, "chip status 0x%x\n",
 195                        reg_read(client, AK881X_STATUS));
 196        } else {
 197                /* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */
 198                reg_write(client, AK881X_DAC_MODE, 0);
 199                dev_dbg(&client->dev, "chip status 0x%x\n",
 200                        reg_read(client, AK881X_STATUS));
 201        }
 202
 203        return 0;
 204}
 205
 206static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
 207#ifdef CONFIG_VIDEO_ADV_DEBUG
 208        .g_register     = ak881x_g_register,
 209        .s_register     = ak881x_s_register,
 210#endif
 211};
 212
 213static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = {
 214        .s_mbus_fmt     = ak881x_s_mbus_fmt,
 215        .g_mbus_fmt     = ak881x_try_g_mbus_fmt,
 216        .try_mbus_fmt   = ak881x_try_g_mbus_fmt,
 217        .cropcap        = ak881x_cropcap,
 218        .enum_mbus_fmt  = ak881x_enum_mbus_fmt,
 219        .s_std_output   = ak881x_s_std_output,
 220        .s_stream       = ak881x_s_stream,
 221};
 222
 223static struct v4l2_subdev_ops ak881x_subdev_ops = {
 224        .core   = &ak881x_subdev_core_ops,
 225        .video  = &ak881x_subdev_video_ops,
 226};
 227
 228static int ak881x_probe(struct i2c_client *client,
 229                        const struct i2c_device_id *did)
 230{
 231        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 232        struct ak881x *ak881x;
 233        u8 ifmode, data;
 234
 235        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 236                dev_warn(&adapter->dev,
 237                         "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
 238                return -EIO;
 239        }
 240
 241        ak881x = devm_kzalloc(&client->dev, sizeof(*ak881x), GFP_KERNEL);
 242        if (!ak881x)
 243                return -ENOMEM;
 244
 245        v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops);
 246
 247        data = reg_read(client, AK881X_DEVICE_ID);
 248
 249        switch (data) {
 250        case 0x13:
 251        case 0x14:
 252                break;
 253        default:
 254                dev_err(&client->dev,
 255                        "No ak881x chip detected, register read %x\n", data);
 256                return -ENODEV;
 257        }
 258
 259        ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION);
 260        ak881x->pdata = client->dev.platform_data;
 261
 262        if (ak881x->pdata) {
 263                if (ak881x->pdata->flags & AK881X_FIELD)
 264                        ifmode = 4;
 265                else
 266                        ifmode = 0;
 267
 268                switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) {
 269                case AK881X_IF_MODE_BT656:
 270                        ifmode |= 1;
 271                        break;
 272                case AK881X_IF_MODE_MASTER:
 273                        ifmode |= 2;
 274                        break;
 275                case AK881X_IF_MODE_SLAVE:
 276                default:
 277                        break;
 278                }
 279
 280                dev_dbg(&client->dev, "IF mode %x\n", ifmode);
 281
 282                /*
 283                 * "Line Blanking No." seems to be the same as the number of
 284                 * "black" lines on, e.g., SuperH VOU, whose default value of 20
 285                 * "incidentally" matches ak881x' default
 286                 */
 287                reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3));
 288        }
 289
 290        /* Hardware default: NTSC-M */
 291        ak881x->lines = 480;
 292
 293        dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n",
 294                 data, ak881x->revision);
 295
 296        return 0;
 297}
 298
 299static int ak881x_remove(struct i2c_client *client)
 300{
 301        struct ak881x *ak881x = to_ak881x(client);
 302
 303        v4l2_device_unregister_subdev(&ak881x->subdev);
 304
 305        return 0;
 306}
 307
 308static const struct i2c_device_id ak881x_id[] = {
 309        { "ak8813", 0 },
 310        { "ak8814", 0 },
 311        { }
 312};
 313MODULE_DEVICE_TABLE(i2c, ak881x_id);
 314
 315static struct i2c_driver ak881x_i2c_driver = {
 316        .driver = {
 317                .name = "ak881x",
 318        },
 319        .probe          = ak881x_probe,
 320        .remove         = ak881x_remove,
 321        .id_table       = ak881x_id,
 322};
 323
 324module_i2c_driver(ak881x_i2c_driver);
 325
 326MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
 327MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 328MODULE_LICENSE("GPL v2");
 329