saa7110.c (12660B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * saa7110 - Philips SAA7110(A) video decoder driver 4 * 5 * Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl> 6 * 7 * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> 8 * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> 9 * - some corrections for Pinnacle Systems Inc. DC10plus card. 10 * 11 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net> 12 * - moved over to linux>=2.4.x i2c protocol (1/1/2003) 13 */ 14 15#include <linux/module.h> 16#include <linux/init.h> 17#include <linux/types.h> 18#include <linux/delay.h> 19#include <linux/slab.h> 20#include <linux/wait.h> 21#include <linux/uaccess.h> 22#include <linux/i2c.h> 23#include <linux/videodev2.h> 24#include <media/v4l2-device.h> 25#include <media/v4l2-ctrls.h> 26 27MODULE_DESCRIPTION("Philips SAA7110 video decoder driver"); 28MODULE_AUTHOR("Pauline Middelink"); 29MODULE_LICENSE("GPL"); 30 31 32static int debug; 33module_param(debug, int, 0); 34MODULE_PARM_DESC(debug, "Debug level (0-1)"); 35 36#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ 37#define SAA7110_MAX_OUTPUT 1 /* 1 YUV */ 38 39#define SAA7110_NR_REG 0x35 40 41struct saa7110 { 42 struct v4l2_subdev sd; 43 struct v4l2_ctrl_handler hdl; 44 u8 reg[SAA7110_NR_REG]; 45 46 v4l2_std_id norm; 47 int input; 48 int enable; 49 50 wait_queue_head_t wq; 51}; 52 53static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd) 54{ 55 return container_of(sd, struct saa7110, sd); 56} 57 58static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 59{ 60 return &container_of(ctrl->handler, struct saa7110, hdl)->sd; 61} 62 63/* ----------------------------------------------------------------------- */ 64/* I2C support functions */ 65/* ----------------------------------------------------------------------- */ 66 67static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value) 68{ 69 struct i2c_client *client = v4l2_get_subdevdata(sd); 70 struct saa7110 *decoder = to_saa7110(sd); 71 72 decoder->reg[reg] = value; 73 return i2c_smbus_write_byte_data(client, reg, value); 74} 75 76static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len) 77{ 78 struct i2c_client *client = v4l2_get_subdevdata(sd); 79 struct saa7110 *decoder = to_saa7110(sd); 80 int ret = -1; 81 u8 reg = *data; /* first register to write to */ 82 83 /* Sanity check */ 84 if (reg + (len - 1) > SAA7110_NR_REG) 85 return ret; 86 87 /* the saa7110 has an autoincrement function, use it if 88 * the adapter understands raw I2C */ 89 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 90 ret = i2c_master_send(client, data, len); 91 92 /* Cache the written data */ 93 memcpy(decoder->reg + reg, data + 1, len - 1); 94 } else { 95 for (++data, --len; len; len--) { 96 ret = saa7110_write(sd, reg++, *data++); 97 if (ret < 0) 98 break; 99 } 100 } 101 102 return ret; 103} 104 105static inline int saa7110_read(struct v4l2_subdev *sd) 106{ 107 struct i2c_client *client = v4l2_get_subdevdata(sd); 108 109 return i2c_smbus_read_byte(client); 110} 111 112/* ----------------------------------------------------------------------- */ 113/* SAA7110 functions */ 114/* ----------------------------------------------------------------------- */ 115 116#define FRESP_06H_COMPST 0x03 /*0x13*/ 117#define FRESP_06H_SVIDEO 0x83 /*0xC0*/ 118 119 120static int saa7110_selmux(struct v4l2_subdev *sd, int chan) 121{ 122 static const unsigned char modes[9][8] = { 123 /* mode 0 */ 124 {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03, 125 0x44, 0x75, 0x16}, 126 /* mode 1 */ 127 {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03, 128 0x44, 0x75, 0x16}, 129 /* mode 2 */ 130 {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03, 131 0x60, 0xB5, 0x05}, 132 /* mode 3 */ 133 {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03, 134 0x60, 0xB5, 0x05}, 135 /* mode 4 */ 136 {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83, 137 0x60, 0xB5, 0x03}, 138 /* mode 5 */ 139 {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83, 140 0x60, 0xB5, 0x03}, 141 /* mode 6 */ 142 {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3, 143 0x44, 0x75, 0x12}, 144 /* mode 7 */ 145 {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13, 146 0x60, 0xB5, 0x14}, 147 /* mode 8 */ 148 {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23, 149 0x44, 0x75, 0x21} 150 }; 151 struct saa7110 *decoder = to_saa7110(sd); 152 const unsigned char *ptr = modes[chan]; 153 154 saa7110_write(sd, 0x06, ptr[0]); /* Luminance control */ 155 saa7110_write(sd, 0x20, ptr[1]); /* Analog Control #1 */ 156 saa7110_write(sd, 0x21, ptr[2]); /* Analog Control #2 */ 157 saa7110_write(sd, 0x22, ptr[3]); /* Mixer Control #1 */ 158 saa7110_write(sd, 0x2C, ptr[4]); /* Mixer Control #2 */ 159 saa7110_write(sd, 0x30, ptr[5]); /* ADCs gain control */ 160 saa7110_write(sd, 0x31, ptr[6]); /* Mixer Control #3 */ 161 saa7110_write(sd, 0x21, ptr[7]); /* Analog Control #2 */ 162 decoder->input = chan; 163 164 return 0; 165} 166 167static const unsigned char initseq[1 + SAA7110_NR_REG] = { 168 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00, 169 /* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90, 170 /* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA, 171 /* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 172 /* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, 173 /* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C, 174 /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02 175}; 176 177static v4l2_std_id determine_norm(struct v4l2_subdev *sd) 178{ 179 DEFINE_WAIT(wait); 180 struct saa7110 *decoder = to_saa7110(sd); 181 int status; 182 183 /* mode changed, start automatic detection */ 184 saa7110_write_block(sd, initseq, sizeof(initseq)); 185 saa7110_selmux(sd, decoder->input); 186 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); 187 schedule_timeout(msecs_to_jiffies(250)); 188 finish_wait(&decoder->wq, &wait); 189 status = saa7110_read(sd); 190 if (status & 0x40) { 191 v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status); 192 return V4L2_STD_UNKNOWN; 193 } 194 if ((status & 3) == 0) { 195 saa7110_write(sd, 0x06, 0x83); 196 if (status & 0x20) { 197 v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status); 198 /*saa7110_write(sd,0x2E,0x81);*/ 199 return V4L2_STD_NTSC; 200 } 201 v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status); 202 /*saa7110_write(sd,0x2E,0x9A);*/ 203 return V4L2_STD_PAL; 204 } 205 /*saa7110_write(sd,0x06,0x03);*/ 206 if (status & 0x20) { /* 60Hz */ 207 v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status); 208 saa7110_write(sd, 0x0D, 0x86); 209 saa7110_write(sd, 0x0F, 0x50); 210 saa7110_write(sd, 0x11, 0x2C); 211 /*saa7110_write(sd,0x2E,0x81);*/ 212 return V4L2_STD_NTSC; 213 } 214 215 /* 50Hz -> PAL/SECAM */ 216 saa7110_write(sd, 0x0D, 0x86); 217 saa7110_write(sd, 0x0F, 0x10); 218 saa7110_write(sd, 0x11, 0x59); 219 /*saa7110_write(sd,0x2E,0x9A);*/ 220 221 prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); 222 schedule_timeout(msecs_to_jiffies(250)); 223 finish_wait(&decoder->wq, &wait); 224 225 status = saa7110_read(sd); 226 if ((status & 0x03) == 0x01) { 227 v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status); 228 saa7110_write(sd, 0x0D, 0x87); 229 return V4L2_STD_SECAM; 230 } 231 v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status); 232 return V4L2_STD_PAL; 233} 234 235static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus) 236{ 237 struct saa7110 *decoder = to_saa7110(sd); 238 int res = V4L2_IN_ST_NO_SIGNAL; 239 int status = saa7110_read(sd); 240 241 v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n", 242 status, (unsigned long long)decoder->norm); 243 if (!(status & 0x40)) 244 res = 0; 245 if (!(status & 0x03)) 246 res |= V4L2_IN_ST_NO_COLOR; 247 248 *pstatus = res; 249 return 0; 250} 251 252static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 253{ 254 *std &= determine_norm(sd); 255 return 0; 256} 257 258static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 259{ 260 struct saa7110 *decoder = to_saa7110(sd); 261 262 if (decoder->norm != std) { 263 decoder->norm = std; 264 /*saa7110_write(sd, 0x06, 0x03);*/ 265 if (std & V4L2_STD_NTSC) { 266 saa7110_write(sd, 0x0D, 0x86); 267 saa7110_write(sd, 0x0F, 0x50); 268 saa7110_write(sd, 0x11, 0x2C); 269 /*saa7110_write(sd, 0x2E, 0x81);*/ 270 v4l2_dbg(1, debug, sd, "switched to NTSC\n"); 271 } else if (std & V4L2_STD_PAL) { 272 saa7110_write(sd, 0x0D, 0x86); 273 saa7110_write(sd, 0x0F, 0x10); 274 saa7110_write(sd, 0x11, 0x59); 275 /*saa7110_write(sd, 0x2E, 0x9A);*/ 276 v4l2_dbg(1, debug, sd, "switched to PAL\n"); 277 } else if (std & V4L2_STD_SECAM) { 278 saa7110_write(sd, 0x0D, 0x87); 279 saa7110_write(sd, 0x0F, 0x10); 280 saa7110_write(sd, 0x11, 0x59); 281 /*saa7110_write(sd, 0x2E, 0x9A);*/ 282 v4l2_dbg(1, debug, sd, "switched to SECAM\n"); 283 } else { 284 return -EINVAL; 285 } 286 } 287 return 0; 288} 289 290static int saa7110_s_routing(struct v4l2_subdev *sd, 291 u32 input, u32 output, u32 config) 292{ 293 struct saa7110 *decoder = to_saa7110(sd); 294 295 if (input >= SAA7110_MAX_INPUT) { 296 v4l2_dbg(1, debug, sd, "input=%d not available\n", input); 297 return -EINVAL; 298 } 299 if (decoder->input != input) { 300 saa7110_selmux(sd, input); 301 v4l2_dbg(1, debug, sd, "switched to input=%d\n", input); 302 } 303 return 0; 304} 305 306static int saa7110_s_stream(struct v4l2_subdev *sd, int enable) 307{ 308 struct saa7110 *decoder = to_saa7110(sd); 309 310 if (decoder->enable != enable) { 311 decoder->enable = enable; 312 saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80); 313 v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off"); 314 } 315 return 0; 316} 317 318static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl) 319{ 320 struct v4l2_subdev *sd = to_sd(ctrl); 321 322 switch (ctrl->id) { 323 case V4L2_CID_BRIGHTNESS: 324 saa7110_write(sd, 0x19, ctrl->val); 325 break; 326 case V4L2_CID_CONTRAST: 327 saa7110_write(sd, 0x13, ctrl->val); 328 break; 329 case V4L2_CID_SATURATION: 330 saa7110_write(sd, 0x12, ctrl->val); 331 break; 332 case V4L2_CID_HUE: 333 saa7110_write(sd, 0x07, ctrl->val); 334 break; 335 default: 336 return -EINVAL; 337 } 338 return 0; 339} 340 341/* ----------------------------------------------------------------------- */ 342 343static const struct v4l2_ctrl_ops saa7110_ctrl_ops = { 344 .s_ctrl = saa7110_s_ctrl, 345}; 346 347static const struct v4l2_subdev_video_ops saa7110_video_ops = { 348 .s_std = saa7110_s_std, 349 .s_routing = saa7110_s_routing, 350 .s_stream = saa7110_s_stream, 351 .querystd = saa7110_querystd, 352 .g_input_status = saa7110_g_input_status, 353}; 354 355static const struct v4l2_subdev_ops saa7110_ops = { 356 .video = &saa7110_video_ops, 357}; 358 359/* ----------------------------------------------------------------------- */ 360 361static int saa7110_probe(struct i2c_client *client, 362 const struct i2c_device_id *id) 363{ 364 struct saa7110 *decoder; 365 struct v4l2_subdev *sd; 366 int rv; 367 368 /* Check if the adapter supports the needed features */ 369 if (!i2c_check_functionality(client->adapter, 370 I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 371 return -ENODEV; 372 373 v4l_info(client, "chip found @ 0x%x (%s)\n", 374 client->addr << 1, client->adapter->name); 375 376 decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL); 377 if (!decoder) 378 return -ENOMEM; 379 sd = &decoder->sd; 380 v4l2_i2c_subdev_init(sd, client, &saa7110_ops); 381 decoder->norm = V4L2_STD_PAL; 382 decoder->input = 0; 383 decoder->enable = 1; 384 v4l2_ctrl_handler_init(&decoder->hdl, 2); 385 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, 386 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 387 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, 388 V4L2_CID_CONTRAST, 0, 127, 1, 64); 389 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, 390 V4L2_CID_SATURATION, 0, 127, 1, 64); 391 v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, 392 V4L2_CID_HUE, -128, 127, 1, 0); 393 sd->ctrl_handler = &decoder->hdl; 394 if (decoder->hdl.error) { 395 int err = decoder->hdl.error; 396 397 v4l2_ctrl_handler_free(&decoder->hdl); 398 return err; 399 } 400 v4l2_ctrl_handler_setup(&decoder->hdl); 401 402 init_waitqueue_head(&decoder->wq); 403 404 rv = saa7110_write_block(sd, initseq, sizeof(initseq)); 405 if (rv < 0) { 406 v4l2_dbg(1, debug, sd, "init status %d\n", rv); 407 } else { 408 int ver, status; 409 saa7110_write(sd, 0x21, 0x10); 410 saa7110_write(sd, 0x0e, 0x18); 411 saa7110_write(sd, 0x0D, 0x04); 412 ver = saa7110_read(sd); 413 saa7110_write(sd, 0x0D, 0x06); 414 /*mdelay(150);*/ 415 status = saa7110_read(sd); 416 v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n", 417 ver, status); 418 saa7110_write(sd, 0x0D, 0x86); 419 saa7110_write(sd, 0x0F, 0x10); 420 saa7110_write(sd, 0x11, 0x59); 421 /*saa7110_write(sd, 0x2E, 0x9A);*/ 422 } 423 424 /*saa7110_selmux(sd,0);*/ 425 /*determine_norm(sd);*/ 426 /* setup and implicit mode 0 select has been performed */ 427 428 return 0; 429} 430 431static int saa7110_remove(struct i2c_client *client) 432{ 433 struct v4l2_subdev *sd = i2c_get_clientdata(client); 434 struct saa7110 *decoder = to_saa7110(sd); 435 436 v4l2_device_unregister_subdev(sd); 437 v4l2_ctrl_handler_free(&decoder->hdl); 438 return 0; 439} 440 441/* ----------------------------------------------------------------------- */ 442 443static const struct i2c_device_id saa7110_id[] = { 444 { "saa7110", 0 }, 445 { } 446}; 447MODULE_DEVICE_TABLE(i2c, saa7110_id); 448 449static struct i2c_driver saa7110_driver = { 450 .driver = { 451 .name = "saa7110", 452 }, 453 .probe = saa7110_probe, 454 .remove = saa7110_remove, 455 .id_table = saa7110_id, 456}; 457 458module_i2c_driver(saa7110_driver);