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