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_fill_fmt(struct v4l2_subdev *sd,
  97                struct v4l2_subdev_pad_config *cfg,
  98                struct v4l2_subdev_format *format)
  99{
 100        struct v4l2_mbus_framefmt *mf = &format->format;
 101        struct i2c_client *client = v4l2_get_subdevdata(sd);
 102        struct ak881x *ak881x = to_ak881x(client);
 103
 104        if (format->pad)
 105                return -EINVAL;
 106
 107        v4l_bound_align_image(&mf->width, 0, 720, 2,
 108                              &mf->height, 0, ak881x->lines, 1, 0);
 109        mf->field       = V4L2_FIELD_INTERLACED;
 110        mf->code        = MEDIA_BUS_FMT_YUYV8_2X8;
 111        mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
 112
 113        return 0;
 114}
 115
 116static int ak881x_enum_mbus_code(struct v4l2_subdev *sd,
 117                struct v4l2_subdev_pad_config *cfg,
 118                struct v4l2_subdev_mbus_code_enum *code)
 119{
 120        if (code->pad || code->index)
 121                return -EINVAL;
 122
 123        code->code = MEDIA_BUS_FMT_YUYV8_2X8;
 124        return 0;
 125}
 126
 127static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 128{
 129        struct i2c_client *client = v4l2_get_subdevdata(sd);
 130        struct ak881x *ak881x = to_ak881x(client);
 131
 132        a->bounds.left                  = 0;
 133        a->bounds.top                   = 0;
 134        a->bounds.width                 = 720;
 135        a->bounds.height                = ak881x->lines;
 136        a->defrect                      = a->bounds;
 137        a->type                         = V4L2_BUF_TYPE_VIDEO_OUTPUT;
 138        a->pixelaspect.numerator        = 1;
 139        a->pixelaspect.denominator      = 1;
 140
 141        return 0;
 142}
 143
 144static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
 145{
 146        struct i2c_client *client = v4l2_get_subdevdata(sd);
 147        struct ak881x *ak881x = to_ak881x(client);
 148        u8 vp1;
 149
 150        if (std == V4L2_STD_NTSC_443) {
 151                vp1 = 3;
 152                ak881x->lines = 480;
 153        } else if (std == V4L2_STD_PAL_M) {
 154                vp1 = 5;
 155                ak881x->lines = 480;
 156        } else if (std == V4L2_STD_PAL_60) {
 157                vp1 = 7;
 158                ak881x->lines = 480;
 159        } else if (std & V4L2_STD_NTSC) {
 160                vp1 = 0;
 161                ak881x->lines = 480;
 162        } else if (std & V4L2_STD_PAL) {
 163                vp1 = 0xf;
 164                ak881x->lines = 576;
 165        } else {
 166                /* No SECAM or PAL_N/Nc supported */
 167                return -EINVAL;
 168        }
 169
 170        reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf);
 171
 172        return 0;
 173}
 174
 175static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
 176{
 177        struct i2c_client *client = v4l2_get_subdevdata(sd);
 178        struct ak881x *ak881x = to_ak881x(client);
 179
 180        if (enable) {
 181                u8 dac;
 182                /* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */
 183                /* Default: composite output */
 184                if (ak881x->pdata->flags & AK881X_COMPONENT)
 185                        dac = 3;
 186                else
 187                        dac = 4;
 188                /* Turn on the DAC(s) */
 189                reg_write(client, AK881X_DAC_MODE, dac);
 190                dev_dbg(&client->dev, "chip status 0x%x\n",
 191                        reg_read(client, AK881X_STATUS));
 192        } else {
 193                /* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */
 194                reg_write(client, AK881X_DAC_MODE, 0);
 195                dev_dbg(&client->dev, "chip status 0x%x\n",
 196                        reg_read(client, AK881X_STATUS));
 197        }
 198
 199        return 0;
 200}
 201
 202static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
 203#ifdef CONFIG_VIDEO_ADV_DEBUG
 204        .g_register     = ak881x_g_register,
 205        .s_register     = ak881x_s_register,
 206#endif
 207};
 208
 209static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = {
 210        .cropcap        = ak881x_cropcap,
 211        .s_std_output   = ak881x_s_std_output,
 212        .s_stream       = ak881x_s_stream,
 213};
 214
 215static const struct v4l2_subdev_pad_ops ak881x_subdev_pad_ops = {
 216        .enum_mbus_code = ak881x_enum_mbus_code,
 217        .set_fmt        = ak881x_fill_fmt,
 218        .get_fmt        = ak881x_fill_fmt,
 219};
 220
 221static struct v4l2_subdev_ops ak881x_subdev_ops = {
 222        .core   = &ak881x_subdev_core_ops,
 223        .video  = &ak881x_subdev_video_ops,
 224        .pad    = &ak881x_subdev_pad_ops,
 225};
 226
 227static int ak881x_probe(struct i2c_client *client,
 228                        const struct i2c_device_id *did)
 229{
 230        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 231        struct ak881x *ak881x;
 232        u8 ifmode, data;
 233
 234        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 235                dev_warn(&adapter->dev,
 236                         "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
 237                return -EIO;
 238        }
 239
 240        ak881x = devm_kzalloc(&client->dev, sizeof(*ak881x), GFP_KERNEL);
 241        if (!ak881x)
 242                return -ENOMEM;
 243
 244        v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops);
 245
 246        data = reg_read(client, AK881X_DEVICE_ID);
 247
 248        switch (data) {
 249        case 0x13:
 250        case 0x14:
 251                break;
 252        default:
 253                dev_err(&client->dev,
 254                        "No ak881x chip detected, register read %x\n", data);
 255                return -ENODEV;
 256        }
 257
 258        ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION);
 259        ak881x->pdata = client->dev.platform_data;
 260
 261        if (ak881x->pdata) {
 262                if (ak881x->pdata->flags & AK881X_FIELD)
 263                        ifmode = 4;
 264                else
 265                        ifmode = 0;
 266
 267                switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) {
 268                case AK881X_IF_MODE_BT656:
 269                        ifmode |= 1;
 270                        break;
 271                case AK881X_IF_MODE_MASTER:
 272                        ifmode |= 2;
 273                        break;
 274                case AK881X_IF_MODE_SLAVE:
 275                default:
 276                        break;
 277                }
 278
 279                dev_dbg(&client->dev, "IF mode %x\n", ifmode);
 280
 281                /*
 282                 * "Line Blanking No." seems to be the same as the number of
 283                 * "black" lines on, e.g., SuperH VOU, whose default value of 20
 284                 * "incidentally" matches ak881x' default
 285                 */
 286                reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3));
 287        }
 288
 289        /* Hardware default: NTSC-M */
 290        ak881x->lines = 480;
 291
 292        dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n",
 293                 data, ak881x->revision);
 294
 295        return 0;
 296}
 297
 298static int ak881x_remove(struct i2c_client *client)
 299{
 300        struct ak881x *ak881x = to_ak881x(client);
 301
 302        v4l2_device_unregister_subdev(&ak881x->subdev);
 303
 304        return 0;
 305}
 306
 307static const struct i2c_device_id ak881x_id[] = {
 308        { "ak8813", 0 },
 309        { "ak8814", 0 },
 310        { }
 311};
 312MODULE_DEVICE_TABLE(i2c, ak881x_id);
 313
 314static struct i2c_driver ak881x_i2c_driver = {
 315        .driver = {
 316                .name = "ak881x",
 317        },
 318        .probe          = ak881x_probe,
 319        .remove         = ak881x_remove,
 320        .id_table       = ak881x_id,
 321};
 322
 323module_i2c_driver(ak881x_i2c_driver);
 324
 325MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
 326MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 327MODULE_LICENSE("GPL v2");
 328