Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB: V4L: v4l2-subdev driver for AK8813 and AK8814 TV-encoders from AKM

AK8814 only differs from AK8813 by included Macrovision Copy Protection
function. This patch adds a driver for AK8813 and AK8814 I2C PAL/NTSC TV
encoders.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Guennadi Liakhovetski and committed by
Mauro Carvalho Chehab
aec11e5d a81fb9b2

+405
+6
drivers/media/video/Kconfig
··· 480 480 To compile this driver as a module, choose M here: the 481 481 module will be called adv7343. 482 482 483 + config VIDEO_AK881X 484 + tristate "AK8813/AK8814 video encoders" 485 + depends on I2C 486 + help 487 + Video output driver for AKM AK8813 and AK8814 TV encoders 488 + 483 489 comment "Video improvement chips" 484 490 485 491 config VIDEO_UPD64031A
+2
drivers/media/video/Makefile
··· 151 151 obj-$(CONFIG_VIDEO_VIVI) += vivi.o 152 152 obj-$(CONFIG_VIDEO_CX23885) += cx23885/ 153 153 154 + obj-$(CONFIG_VIDEO_AK881X) += ak881x.o 155 + 154 156 obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o 155 157 obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o 156 158 obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
+368
drivers/media/video/ak881x.c
··· 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/videodev2.h> 15 + 16 + #include <media/ak881x.h> 17 + #include <media/v4l2-chip-ident.h> 18 + #include <media/v4l2-common.h> 19 + #include <media/v4l2-device.h> 20 + 21 + #define AK881X_INTERFACE_MODE 0 22 + #define AK881X_VIDEO_PROCESS1 1 23 + #define AK881X_VIDEO_PROCESS2 2 24 + #define AK881X_VIDEO_PROCESS3 3 25 + #define AK881X_DAC_MODE 5 26 + #define AK881X_STATUS 0x24 27 + #define AK881X_DEVICE_ID 0x25 28 + #define AK881X_DEVICE_REVISION 0x26 29 + 30 + struct ak881x { 31 + struct v4l2_subdev subdev; 32 + struct ak881x_pdata *pdata; 33 + unsigned int lines; 34 + int id; /* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */ 35 + char revision; /* DEVICE_REVISION content */ 36 + }; 37 + 38 + static int reg_read(struct i2c_client *client, const u8 reg) 39 + { 40 + return i2c_smbus_read_byte_data(client, reg); 41 + } 42 + 43 + static 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 + 49 + static 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 + 58 + static struct ak881x *to_ak881x(const struct i2c_client *client) 59 + { 60 + return container_of(i2c_get_clientdata(client), struct ak881x, subdev); 61 + } 62 + 63 + static int ak881x_g_chip_ident(struct v4l2_subdev *sd, 64 + struct v4l2_dbg_chip_ident *id) 65 + { 66 + struct i2c_client *client = v4l2_get_subdevdata(sd); 67 + struct ak881x *ak881x = to_ak881x(client); 68 + 69 + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) 70 + return -EINVAL; 71 + 72 + if (id->match.addr != client->addr) 73 + return -ENODEV; 74 + 75 + id->ident = ak881x->id; 76 + id->revision = ak881x->revision; 77 + 78 + return 0; 79 + } 80 + 81 + #ifdef CONFIG_VIDEO_ADV_DEBUG 82 + static int ak881x_g_register(struct v4l2_subdev *sd, 83 + struct v4l2_dbg_register *reg) 84 + { 85 + struct i2c_client *client = v4l2_get_subdevdata(sd); 86 + 87 + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26) 88 + return -EINVAL; 89 + 90 + if (reg->match.addr != client->addr) 91 + return -ENODEV; 92 + 93 + reg->val = reg_read(client, reg->reg); 94 + 95 + if (reg->val > 0xffff) 96 + return -EIO; 97 + 98 + return 0; 99 + } 100 + 101 + static int ak881x_s_register(struct v4l2_subdev *sd, 102 + struct v4l2_dbg_register *reg) 103 + { 104 + struct i2c_client *client = v4l2_get_subdevdata(sd); 105 + 106 + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26) 107 + return -EINVAL; 108 + 109 + if (reg->match.addr != client->addr) 110 + return -ENODEV; 111 + 112 + if (reg_write(client, reg->reg, reg->val) < 0) 113 + return -EIO; 114 + 115 + return 0; 116 + } 117 + #endif 118 + 119 + static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd, 120 + struct v4l2_mbus_framefmt *mf) 121 + { 122 + struct i2c_client *client = v4l2_get_subdevdata(sd); 123 + struct ak881x *ak881x = to_ak881x(client); 124 + 125 + v4l_bound_align_image(&mf->width, 0, 720, 2, 126 + &mf->height, 0, ak881x->lines, 1, 0); 127 + mf->field = V4L2_FIELD_INTERLACED; 128 + mf->code = V4L2_MBUS_FMT_YUYV8_2X8_LE; 129 + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; 130 + 131 + return 0; 132 + } 133 + 134 + static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, 135 + struct v4l2_mbus_framefmt *mf) 136 + { 137 + if (mf->field != V4L2_FIELD_INTERLACED || 138 + mf->code != V4L2_MBUS_FMT_YUYV8_2X8_LE) 139 + return -EINVAL; 140 + 141 + return ak881x_try_g_mbus_fmt(sd, mf); 142 + } 143 + 144 + static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, int index, 145 + enum v4l2_mbus_pixelcode *code) 146 + { 147 + if (index) 148 + return -EINVAL; 149 + 150 + *code = V4L2_MBUS_FMT_YUYV8_2X8_LE; 151 + return 0; 152 + } 153 + 154 + static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) 155 + { 156 + struct i2c_client *client = v4l2_get_subdevdata(sd); 157 + struct ak881x *ak881x = to_ak881x(client); 158 + 159 + a->bounds.left = 0; 160 + a->bounds.top = 0; 161 + a->bounds.width = 720; 162 + a->bounds.height = ak881x->lines; 163 + a->defrect = a->bounds; 164 + a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 165 + a->pixelaspect.numerator = 1; 166 + a->pixelaspect.denominator = 1; 167 + 168 + return 0; 169 + } 170 + 171 + static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 172 + { 173 + struct i2c_client *client = v4l2_get_subdevdata(sd); 174 + struct ak881x *ak881x = to_ak881x(client); 175 + u8 vp1; 176 + 177 + if (std == V4L2_STD_NTSC_443) { 178 + vp1 = 3; 179 + ak881x->lines = 480; 180 + } else if (std == V4L2_STD_PAL_M) { 181 + vp1 = 5; 182 + ak881x->lines = 480; 183 + } else if (std == V4L2_STD_PAL_60) { 184 + vp1 = 7; 185 + ak881x->lines = 480; 186 + } else if (std && !(std & ~V4L2_STD_PAL)) { 187 + vp1 = 0xf; 188 + ak881x->lines = 576; 189 + } else if (std && !(std & ~V4L2_STD_NTSC)) { 190 + vp1 = 0; 191 + ak881x->lines = 480; 192 + } else { 193 + /* No SECAM or PAL_N/Nc supported */ 194 + return -EINVAL; 195 + } 196 + 197 + reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf); 198 + 199 + return 0; 200 + } 201 + 202 + static int ak881x_s_stream(struct v4l2_subdev *sd, int enable) 203 + { 204 + struct i2c_client *client = v4l2_get_subdevdata(sd); 205 + struct ak881x *ak881x = to_ak881x(client); 206 + 207 + if (enable) { 208 + u8 dac; 209 + /* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */ 210 + /* Default: composite output */ 211 + if (ak881x->pdata->flags & AK881X_COMPONENT) 212 + dac = 3; 213 + else 214 + dac = 4; 215 + /* Turn on the DAC(s) */ 216 + reg_write(client, AK881X_DAC_MODE, dac); 217 + dev_dbg(&client->dev, "chip status 0x%x\n", 218 + reg_read(client, AK881X_STATUS)); 219 + } else { 220 + /* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */ 221 + reg_write(client, AK881X_DAC_MODE, 0); 222 + dev_dbg(&client->dev, "chip status 0x%x\n", 223 + reg_read(client, AK881X_STATUS)); 224 + } 225 + 226 + return 0; 227 + } 228 + 229 + static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = { 230 + .g_chip_ident = ak881x_g_chip_ident, 231 + #ifdef CONFIG_VIDEO_ADV_DEBUG 232 + .g_register = ak881x_g_register, 233 + .s_register = ak881x_s_register, 234 + #endif 235 + }; 236 + 237 + static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { 238 + .s_mbus_fmt = ak881x_s_mbus_fmt, 239 + .g_mbus_fmt = ak881x_try_g_mbus_fmt, 240 + .try_mbus_fmt = ak881x_try_g_mbus_fmt, 241 + .cropcap = ak881x_cropcap, 242 + .enum_mbus_fmt = ak881x_enum_mbus_fmt, 243 + .s_std_output = ak881x_s_std_output, 244 + .s_stream = ak881x_s_stream, 245 + }; 246 + 247 + static struct v4l2_subdev_ops ak881x_subdev_ops = { 248 + .core = &ak881x_subdev_core_ops, 249 + .video = &ak881x_subdev_video_ops, 250 + }; 251 + 252 + static int ak881x_probe(struct i2c_client *client, 253 + const struct i2c_device_id *did) 254 + { 255 + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 256 + struct ak881x *ak881x; 257 + u8 ifmode, data; 258 + 259 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 260 + dev_warn(&adapter->dev, 261 + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); 262 + return -EIO; 263 + } 264 + 265 + ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL); 266 + if (!ak881x) 267 + return -ENOMEM; 268 + 269 + v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops); 270 + 271 + data = reg_read(client, AK881X_DEVICE_ID); 272 + 273 + switch (data) { 274 + case 0x13: 275 + ak881x->id = V4L2_IDENT_AK8813; 276 + break; 277 + case 0x14: 278 + ak881x->id = V4L2_IDENT_AK8814; 279 + break; 280 + default: 281 + dev_err(&client->dev, 282 + "No ak881x chip detected, register read %x\n", data); 283 + kfree(ak881x); 284 + return -ENODEV; 285 + } 286 + 287 + ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION); 288 + ak881x->pdata = client->dev.platform_data; 289 + 290 + if (ak881x->pdata) { 291 + if (ak881x->pdata->flags & AK881X_FIELD) 292 + ifmode = 4; 293 + else 294 + ifmode = 0; 295 + 296 + switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) { 297 + case AK881X_IF_MODE_BT656: 298 + ifmode |= 1; 299 + break; 300 + case AK881X_IF_MODE_MASTER: 301 + ifmode |= 2; 302 + break; 303 + case AK881X_IF_MODE_SLAVE: 304 + default: 305 + break; 306 + } 307 + 308 + dev_dbg(&client->dev, "IF mode %x\n", ifmode); 309 + 310 + /* 311 + * "Line Blanking No." seems to be the same as the number of 312 + * "black" lines on, e.g., SuperH VOU, whose default value of 20 313 + * "incidentally" matches ak881x' default 314 + */ 315 + reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3)); 316 + } 317 + 318 + /* Hardware default: NTSC-M */ 319 + ak881x->lines = 480; 320 + 321 + dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n", 322 + data, ak881x->revision); 323 + 324 + return 0; 325 + } 326 + 327 + static int ak881x_remove(struct i2c_client *client) 328 + { 329 + struct ak881x *ak881x = to_ak881x(client); 330 + 331 + v4l2_device_unregister_subdev(&ak881x->subdev); 332 + kfree(ak881x); 333 + 334 + return 0; 335 + } 336 + 337 + static const struct i2c_device_id ak881x_id[] = { 338 + { "ak8813", 0 }, 339 + { "ak8814", 0 }, 340 + { } 341 + }; 342 + MODULE_DEVICE_TABLE(i2c, ak881x_id); 343 + 344 + static struct i2c_driver ak881x_i2c_driver = { 345 + .driver = { 346 + .name = "ak881x", 347 + }, 348 + .probe = ak881x_probe, 349 + .remove = ak881x_remove, 350 + .id_table = ak881x_id, 351 + }; 352 + 353 + static int __init ak881x_module_init(void) 354 + { 355 + return i2c_add_driver(&ak881x_i2c_driver); 356 + } 357 + 358 + static void __exit ak881x_module_exit(void) 359 + { 360 + i2c_del_driver(&ak881x_i2c_driver); 361 + } 362 + 363 + module_init(ak881x_module_init); 364 + module_exit(ak881x_module_exit); 365 + 366 + MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814"); 367 + MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); 368 + MODULE_LICENSE("GPL v2");
+25
include/media/ak881x.h
··· 1 + /* 2 + * Header 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 + #ifndef AK881X_H 12 + #define AK881X_H 13 + 14 + #define AK881X_IF_MODE_MASK (3 << 0) 15 + #define AK881X_IF_MODE_BT656 (0 << 0) 16 + #define AK881X_IF_MODE_MASTER (1 << 0) 17 + #define AK881X_IF_MODE_SLAVE (2 << 0) 18 + #define AK881X_FIELD (1 << 2) 19 + #define AK881X_COMPONENT (1 << 3) 20 + 21 + struct ak881x_pdata { 22 + unsigned long flags; 23 + }; 24 + 25 + #endif
+4
include/media/v4l2-chip-ident.h
··· 178 178 /* module cafe_ccic, just ident 8801 */ 179 179 V4L2_IDENT_CAFE = 8801, 180 180 181 + /* AKM AK8813/AK8814 */ 182 + V4L2_IDENT_AK8813 = 8813, 183 + V4L2_IDENT_AK8814 = 8814, 184 + 181 185 /* module cx23885 and cx25840 */ 182 186 V4L2_IDENT_CX23885 = 8850, 183 187 V4L2_IDENT_CX23885_AV = 8851, /* Integrated A/V decoder */