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