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