📄 saa7114.c
字号:
static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore,};static struct i2c_driver i2c_driver_saa7114;static intsaa7114_detect_client (struct i2c_adapter *adapter, int address, int kind){ int i, err[30]; short int hoff = SAA_7114_NTSC_HOFFSET; short int voff = SAA_7114_NTSC_VOFFSET; short int w = SAA_7114_NTSC_WIDTH; short int h = SAA_7114_NTSC_HEIGHT; struct i2c_client *client; struct saa7114 *decoder; dprintk(1, KERN_INFO "saa7114.c: detecting saa7114 client on address 0x%x\n", address << 1); /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (client == 0) return -ENOMEM; memset(client, 0, sizeof(struct i2c_client)); client->addr = address; client->adapter = adapter; client->driver = &i2c_driver_saa7114; client->flags = I2C_CLIENT_ALLOW_USE; strlcpy(I2C_NAME(client), "saa7114", sizeof(I2C_NAME(client))); decoder = kmalloc(sizeof(struct saa7114), GFP_KERNEL); if (decoder == NULL) { kfree(client); return -ENOMEM; } memset(decoder, 0, sizeof(struct saa7114)); decoder->norm = VIDEO_MODE_NTSC; decoder->input = -1; decoder->enable = 1; decoder->bright = 32768; decoder->contrast = 32768; decoder->hue = 32768; decoder->sat = 32768; decoder->playback = 0; // initially capture mode useda i2c_set_clientdata(client, decoder); memcpy(decoder->reg, init, sizeof(init)); decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff); // hoffset low decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f; // hoffset high decoder->reg[REG_ADDR(0x96)] = LOBYTE(w); // width low decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f; // width high decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff); // voffset low decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f; // voffset high decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2); // height low decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f; // height high decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w); // out width low decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f; // out width high decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h); // out height low decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f; // out height high decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff); // hoffset low decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f; // hoffset high decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w); // width low decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f; // width high decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff); // voffset low decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f; // voffset high decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2); // height low decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f; // height high decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w); // out width low decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f; // out width high decoder->reg[REG_ADDR(0xce)] = LOBYTE(h); // out height low decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f; // out height high decoder->reg[REG_ADDR(0xb8)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xb9)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xba)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xbb)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xbc)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xbd)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xbe)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xbf)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xe8)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xe9)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xea)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xeb)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xec)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xed)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xee)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xef)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0x13)] = 0x80; // RTC0 on decoder->reg[REG_ADDR(0x87)] = 0x01; // I-Port decoder->reg[REG_ADDR(0x12)] = 0xc9; // RTS0 decoder->reg[REG_ADDR(0x02)] = 0xc0; // set composite1 input, aveasy decoder->reg[REG_ADDR(0x09)] = 0x00; // chrominance trap decoder->reg[REG_ADDR(0x0e)] |= 1; // combfilter on dprintk(1, KERN_DEBUG "%s_attach: starting decoder init\n", I2C_NAME(client)); err[0] = saa7114_write_block(client, decoder->reg + (0x20 << 1), 0x10 << 1); err[1] = saa7114_write_block(client, decoder->reg + (0x30 << 1), 0x10 << 1); err[2] = saa7114_write_block(client, decoder->reg + (0x63 << 1), (0x7f + 1 - 0x63) << 1); err[3] = saa7114_write_block(client, decoder->reg + (0x89 << 1), 6 << 1); err[4] = saa7114_write_block(client, decoder->reg + (0xb8 << 1), 8 << 1); err[5] = saa7114_write_block(client, decoder->reg + (0xe8 << 1), 8 << 1); for (i = 0; i <= 5; i++) { if (err[i] < 0) { dprintk(1, KERN_ERR "%s_attach: init error %d at stage %d, leaving attach.\n", I2C_NAME(client), i, err[i]); kfree(decoder); kfree(client); return 0; } } for (i = 6; i < 8; i++) { dprintk(1, KERN_DEBUG "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n", I2C_NAME(client), i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } dprintk(1, KERN_DEBUG "%s_attach: performing decoder reset sequence\n", I2C_NAME(client)); err[6] = saa7114_write(client, 0x80, 0x06); // i-port and scaler backend clock selection, task A&B off err[7] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler err[8] = saa7114_write(client, 0x88, 0xf8); // sw reset scaler release for (i = 6; i <= 8; i++) { if (err[i] < 0) { dprintk(1, KERN_ERR "%s_attach: init error %d at stage %d, leaving attach.\n", I2C_NAME(client), i, err[i]); kfree(decoder); kfree(client); return 0; } } dprintk(1, KERN_INFO "%s_attach: performing the rest of init\n", I2C_NAME(client)); err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]); err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1); // big seq err[11] = saa7114_write_block(client, decoder->reg + (0x40 << 1), (0x5f + 1 - 0x40) << 1); // slicer err[12] = saa7114_write_block(client, decoder->reg + (0x81 << 1), 2 << 1); // ? err[13] = saa7114_write_block(client, decoder->reg + (0x83 << 1), 5 << 1); // ? err[14] = saa7114_write_block(client, decoder->reg + (0x90 << 1), 4 << 1); // Task A err[15] = saa7114_write_block(client, decoder->reg + (0x94 << 1), 12 << 1); err[16] = saa7114_write_block(client, decoder->reg + (0xa0 << 1), 8 << 1); err[17] = saa7114_write_block(client, decoder->reg + (0xa8 << 1), 8 << 1); err[18] = saa7114_write_block(client, decoder->reg + (0xb0 << 1), 8 << 1); err[19] = saa7114_write_block(client, decoder->reg + (0xc0 << 1), 4 << 1); // Task B err[15] = saa7114_write_block(client, decoder->reg + (0xc4 << 1), 12 << 1); err[16] = saa7114_write_block(client, decoder->reg + (0xd0 << 1), 8 << 1); err[17] = saa7114_write_block(client, decoder->reg + (0xd8 << 1), 8 << 1); err[18] = saa7114_write_block(client, decoder->reg + (0xe0 << 1), 8 << 1); for (i = 9; i <= 18; i++) { if (err[i] < 0) { dprintk(1, KERN_ERR "%s_attach: init error %d at stage %d, leaving attach.\n", I2C_NAME(client), i, err[i]); kfree(decoder); kfree(client); return 0; } } for (i = 6; i < 8; i++) { dprintk(1, KERN_DEBUG "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n", I2C_NAME(client), i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } for (i = 0x11; i <= 0x13; i++) { dprintk(1, KERN_DEBUG "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n", I2C_NAME(client), i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } dprintk(1, KERN_DEBUG "%s_attach: setting video input\n", I2C_NAME(client)); err[19] = saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]); err[20] = saa7114_write(client, 0x09, decoder->reg[REG_ADDR(0x09)]); err[21] = saa7114_write(client, 0x0e, decoder->reg[REG_ADDR(0x0e)]); for (i = 19; i <= 21; i++) { if (err[i] < 0) { dprintk(1, KERN_ERR "%s_attach: init error %d at stage %d, leaving attach.\n", I2C_NAME(client), i, err[i]); kfree(decoder); kfree(client); return 0; } } dprintk(1, KERN_DEBUG "%s_attach: performing decoder reset sequence\n", I2C_NAME(client)); err[22] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler err[23] = saa7114_write(client, 0x88, 0xf8); // sw reset scaler release err[24] = saa7114_write(client, 0x80, 0x36); // i-port and scaler backend clock selection, task A&B off for (i = 22; i <= 24; i++) { if (err[i] < 0) { dprintk(1, KERN_ERR "%s_attach: init error %d at stage %d, leaving attach.\n", I2C_NAME(client), i, err[i]); kfree(decoder); kfree(client); return 0; } } err[25] = saa7114_write(client, 0x06, init[REG_ADDR(0x06)]); err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]); err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]); dprintk(1, KERN_INFO "%s_attach: chip version %x, decoder status 0x%02x\n", I2C_NAME(client), saa7114_read(client, 0x00) >> 4, saa7114_read(client, 0x1f)); dprintk(1, KERN_DEBUG "%s_attach: power save control: 0x%02x, scaler status: 0x%02x\n", I2C_NAME(client), saa7114_read(client, 0x88), saa7114_read(client, 0x8f)); for (i = 0x94; i < 0x96; i++) { dprintk(1, KERN_DEBUG "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n", I2C_NAME(client), i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } i = i2c_attach_client(client); if (i) { kfree(client); kfree(decoder); return i; } //i = saa7114_write_block(client, init, sizeof(init)); i = 0; if (i < 0) { dprintk(1, KERN_ERR "%s_attach error: init status %d\n", I2C_NAME(client), i); } else { dprintk(1, KERN_INFO "%s_attach: chip version %x at address 0x%x\n", I2C_NAME(client), saa7114_read(client, 0x00) >> 4, client->addr << 1); } return 0;}static intsaa7114_attach_adapter (struct i2c_adapter *adapter){ dprintk(1, KERN_INFO "saa7114.c: starting probe for adapter %s (0x%x)\n", I2C_NAME(adapter), adapter->id); return i2c_probe(adapter, &addr_data, &saa7114_detect_client);}static intsaa7114_detach_client (struct i2c_client *client){ struct saa7114 *decoder = i2c_get_clientdata(client); int err; err = i2c_detach_client(client); if (err) { return err; } kfree(decoder); kfree(client); return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver i2c_driver_saa7114 = { .owner = THIS_MODULE, .name = "saa7114", .id = I2C_DRIVERID_SAA7114, .flags = I2C_DF_NOTIFY, .attach_adapter = saa7114_attach_adapter, .detach_client = saa7114_detach_client, .command = saa7114_command,};static int __initsaa7114_init (void){ return i2c_add_driver(&i2c_driver_saa7114);}static void __exitsaa7114_exit (void){ i2c_del_driver(&i2c_driver_saa7114);}module_init(saa7114_init);module_exit(saa7114_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -