0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include <linux/module.h>
0019 #include <linux/types.h>
0020 #include <linux/slab.h>
0021 #include <linux/ioctl.h>
0022 #include <linux/uaccess.h>
0023 #include <linux/i2c.h>
0024 #include <linux/videodev2.h>
0025 #include <media/v4l2-device.h>
0026
0027 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
0028 MODULE_AUTHOR("Maxim Yevtyushkin");
0029 MODULE_LICENSE("GPL");
0030
0031
0032 static int debug;
0033 module_param(debug, int, 0);
0034 MODULE_PARM_DESC(debug, "Debug level (0-1)");
0035
0036
0037
0038 struct adv7170 {
0039 struct v4l2_subdev sd;
0040 unsigned char reg[128];
0041
0042 v4l2_std_id norm;
0043 int input;
0044 };
0045
0046 static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
0047 {
0048 return container_of(sd, struct adv7170, sd);
0049 }
0050
0051 static char *inputs[] = { "pass_through", "play_back" };
0052
0053 static u32 adv7170_codes[] = {
0054 MEDIA_BUS_FMT_UYVY8_2X8,
0055 MEDIA_BUS_FMT_UYVY8_1X16,
0056 };
0057
0058
0059
0060 static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
0061 {
0062 struct i2c_client *client = v4l2_get_subdevdata(sd);
0063 struct adv7170 *encoder = to_adv7170(sd);
0064
0065 encoder->reg[reg] = value;
0066 return i2c_smbus_write_byte_data(client, reg, value);
0067 }
0068
0069 static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg)
0070 {
0071 struct i2c_client *client = v4l2_get_subdevdata(sd);
0072
0073 return i2c_smbus_read_byte_data(client, reg);
0074 }
0075
0076 static int adv7170_write_block(struct v4l2_subdev *sd,
0077 const u8 *data, unsigned int len)
0078 {
0079 struct i2c_client *client = v4l2_get_subdevdata(sd);
0080 struct adv7170 *encoder = to_adv7170(sd);
0081 int ret = -1;
0082 u8 reg;
0083
0084
0085
0086 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0087
0088 u8 block_data[32];
0089 int block_len;
0090
0091 while (len >= 2) {
0092 block_len = 0;
0093 block_data[block_len++] = reg = data[0];
0094 do {
0095 block_data[block_len++] =
0096 encoder->reg[reg++] = data[1];
0097 len -= 2;
0098 data += 2;
0099 } while (len >= 2 && data[0] == reg && block_len < 32);
0100 ret = i2c_master_send(client, block_data, block_len);
0101 if (ret < 0)
0102 break;
0103 }
0104 } else {
0105
0106 while (len >= 2) {
0107 reg = *data++;
0108 ret = adv7170_write(sd, reg, *data++);
0109 if (ret < 0)
0110 break;
0111 len -= 2;
0112 }
0113 }
0114 return ret;
0115 }
0116
0117
0118
0119 #define TR0MODE 0x4c
0120 #define TR0RST 0x80
0121
0122 #define TR1CAPT 0x00
0123 #define TR1PLAY 0x00
0124
0125 static const unsigned char init_NTSC[] = {
0126 0x00, 0x10,
0127 0x01, 0x20,
0128 0x02, 0x0e,
0129 0x03, 0x80,
0130 0x04, 0x30,
0131 0x05, 0x00,
0132 0x06, 0x00,
0133 0x07, TR0MODE,
0134 0x08, TR1CAPT,
0135 0x09, 0x16,
0136 0x0a, 0x7c,
0137 0x0b, 0xf0,
0138 0x0c, 0x21,
0139 0x0d, 0x00,
0140 0x0e, 0x00,
0141 0x0f, 0x00,
0142 0x10, 0x00,
0143 0x11, 0x00,
0144 0x12, 0x00,
0145 0x13, 0x00,
0146 0x14, 0x00,
0147 0x15, 0x00,
0148 0x16, 0x00,
0149 0x17, 0x00,
0150 0x18, 0x00,
0151 0x19, 0x00,
0152 };
0153
0154 static const unsigned char init_PAL[] = {
0155 0x00, 0x71,
0156 0x01, 0x20,
0157 0x02, 0x0e,
0158 0x03, 0x80,
0159 0x04, 0x30,
0160 0x05, 0x00,
0161 0x06, 0x00,
0162 0x07, TR0MODE,
0163 0x08, TR1CAPT,
0164 0x09, 0xcb,
0165 0x0a, 0x8a,
0166 0x0b, 0x09,
0167 0x0c, 0x2a,
0168 0x0d, 0x00,
0169 0x0e, 0x00,
0170 0x0f, 0x00,
0171 0x10, 0x00,
0172 0x11, 0x00,
0173 0x12, 0x00,
0174 0x13, 0x00,
0175 0x14, 0x00,
0176 0x15, 0x00,
0177 0x16, 0x00,
0178 0x17, 0x00,
0179 0x18, 0x00,
0180 0x19, 0x00,
0181 };
0182
0183
0184 static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
0185 {
0186 struct adv7170 *encoder = to_adv7170(sd);
0187
0188 v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
0189
0190 if (std & V4L2_STD_NTSC) {
0191 adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
0192 if (encoder->input == 0)
0193 adv7170_write(sd, 0x02, 0x0e);
0194 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
0195 adv7170_write(sd, 0x07, TR0MODE);
0196 } else if (std & V4L2_STD_PAL) {
0197 adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
0198 if (encoder->input == 0)
0199 adv7170_write(sd, 0x02, 0x0e);
0200 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
0201 adv7170_write(sd, 0x07, TR0MODE);
0202 } else {
0203 v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
0204 (unsigned long long)std);
0205 return -EINVAL;
0206 }
0207 v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
0208 encoder->norm = std;
0209 return 0;
0210 }
0211
0212 static int adv7170_s_routing(struct v4l2_subdev *sd,
0213 u32 input, u32 output, u32 config)
0214 {
0215 struct adv7170 *encoder = to_adv7170(sd);
0216
0217
0218
0219
0220
0221 v4l2_dbg(1, debug, sd, "set input from %s\n",
0222 input == 0 ? "decoder" : "ZR36060");
0223
0224 switch (input) {
0225 case 0:
0226 adv7170_write(sd, 0x01, 0x20);
0227 adv7170_write(sd, 0x08, TR1CAPT);
0228 adv7170_write(sd, 0x02, 0x0e);
0229 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
0230 adv7170_write(sd, 0x07, TR0MODE);
0231
0232 break;
0233
0234 case 1:
0235 adv7170_write(sd, 0x01, 0x00);
0236 adv7170_write(sd, 0x08, TR1PLAY);
0237 adv7170_write(sd, 0x02, 0x08);
0238 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
0239 adv7170_write(sd, 0x07, TR0MODE);
0240
0241 break;
0242
0243 default:
0244 v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
0245 return -EINVAL;
0246 }
0247 v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
0248 encoder->input = input;
0249 return 0;
0250 }
0251
0252 static int adv7170_enum_mbus_code(struct v4l2_subdev *sd,
0253 struct v4l2_subdev_state *sd_state,
0254 struct v4l2_subdev_mbus_code_enum *code)
0255 {
0256 if (code->pad || code->index >= ARRAY_SIZE(adv7170_codes))
0257 return -EINVAL;
0258
0259 code->code = adv7170_codes[code->index];
0260 return 0;
0261 }
0262
0263 static int adv7170_get_fmt(struct v4l2_subdev *sd,
0264 struct v4l2_subdev_state *sd_state,
0265 struct v4l2_subdev_format *format)
0266 {
0267 struct v4l2_mbus_framefmt *mf = &format->format;
0268 u8 val = adv7170_read(sd, 0x7);
0269
0270 if (format->pad)
0271 return -EINVAL;
0272
0273 if ((val & 0x40) == (1 << 6))
0274 mf->code = MEDIA_BUS_FMT_UYVY8_1X16;
0275 else
0276 mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
0277
0278 mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
0279 mf->width = 0;
0280 mf->height = 0;
0281 mf->field = V4L2_FIELD_ANY;
0282
0283 return 0;
0284 }
0285
0286 static int adv7170_set_fmt(struct v4l2_subdev *sd,
0287 struct v4l2_subdev_state *sd_state,
0288 struct v4l2_subdev_format *format)
0289 {
0290 struct v4l2_mbus_framefmt *mf = &format->format;
0291 u8 val = adv7170_read(sd, 0x7);
0292
0293 if (format->pad)
0294 return -EINVAL;
0295
0296 switch (mf->code) {
0297 case MEDIA_BUS_FMT_UYVY8_2X8:
0298 val &= ~0x40;
0299 break;
0300
0301 case MEDIA_BUS_FMT_UYVY8_1X16:
0302 val |= 0x40;
0303 break;
0304
0305 default:
0306 v4l2_dbg(1, debug, sd,
0307 "illegal v4l2_mbus_framefmt code: %d\n", mf->code);
0308 return -EINVAL;
0309 }
0310
0311 if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
0312 return adv7170_write(sd, 0x7, val);
0313
0314 return 0;
0315 }
0316
0317
0318
0319 static const struct v4l2_subdev_video_ops adv7170_video_ops = {
0320 .s_std_output = adv7170_s_std_output,
0321 .s_routing = adv7170_s_routing,
0322 };
0323
0324 static const struct v4l2_subdev_pad_ops adv7170_pad_ops = {
0325 .enum_mbus_code = adv7170_enum_mbus_code,
0326 .get_fmt = adv7170_get_fmt,
0327 .set_fmt = adv7170_set_fmt,
0328 };
0329
0330 static const struct v4l2_subdev_ops adv7170_ops = {
0331 .video = &adv7170_video_ops,
0332 .pad = &adv7170_pad_ops,
0333 };
0334
0335
0336
0337 static int adv7170_probe(struct i2c_client *client,
0338 const struct i2c_device_id *id)
0339 {
0340 struct adv7170 *encoder;
0341 struct v4l2_subdev *sd;
0342 int i;
0343
0344
0345 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
0346 return -ENODEV;
0347
0348 v4l_info(client, "chip found @ 0x%x (%s)\n",
0349 client->addr << 1, client->adapter->name);
0350
0351 encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
0352 if (encoder == NULL)
0353 return -ENOMEM;
0354 sd = &encoder->sd;
0355 v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
0356 encoder->norm = V4L2_STD_NTSC;
0357 encoder->input = 0;
0358
0359 i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
0360 if (i >= 0) {
0361 i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
0362 i = adv7170_write(sd, 0x07, TR0MODE);
0363 i = adv7170_read(sd, 0x12);
0364 v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
0365 }
0366 if (i < 0)
0367 v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
0368 return 0;
0369 }
0370
0371 static int adv7170_remove(struct i2c_client *client)
0372 {
0373 struct v4l2_subdev *sd = i2c_get_clientdata(client);
0374
0375 v4l2_device_unregister_subdev(sd);
0376 return 0;
0377 }
0378
0379
0380
0381 static const struct i2c_device_id adv7170_id[] = {
0382 { "adv7170", 0 },
0383 { "adv7171", 0 },
0384 { }
0385 };
0386 MODULE_DEVICE_TABLE(i2c, adv7170_id);
0387
0388 static struct i2c_driver adv7170_driver = {
0389 .driver = {
0390 .name = "adv7170",
0391 },
0392 .probe = adv7170_probe,
0393 .remove = adv7170_remove,
0394 .id_table = adv7170_id,
0395 };
0396
0397 module_i2c_driver(adv7170_driver);