root/drivers/media/i2c/ak881x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. reg_read
  2. reg_write
  3. reg_set
  4. to_ak881x
  5. ak881x_g_register
  6. ak881x_s_register
  7. ak881x_fill_fmt
  8. ak881x_enum_mbus_code
  9. ak881x_get_selection
  10. ak881x_s_std_output
  11. ak881x_s_stream
  12. ak881x_probe
  13. ak881x_remove

   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 
  28 struct ak881x {
  29         struct v4l2_subdev subdev;
  30         struct ak881x_pdata *pdata;
  31         unsigned int lines;
  32         char revision;  /* DEVICE_REVISION content */
  33 };
  34 
  35 static int reg_read(struct i2c_client *client, const u8 reg)
  36 {
  37         return i2c_smbus_read_byte_data(client, reg);
  38 }
  39 
  40 static 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 
  46 static 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 
  55 static 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
  61 static 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 
  78 static 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 
  93 static 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 
 113 static 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 
 124 static 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 
 146 static 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 
 177 static 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 
 204 static 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 
 211 static 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 
 216 static 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 
 223 static 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 
 229 static 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 
 300 static 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 
 309 static const struct i2c_device_id ak881x_id[] = {
 310         { "ak8813", 0 },
 311         { "ak8814", 0 },
 312         { }
 313 };
 314 MODULE_DEVICE_TABLE(i2c, ak881x_id);
 315 
 316 static 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 
 325 module_i2c_driver(ak881x_i2c_driver);
 326 
 327 MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
 328 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 329 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */