📄 vpx3220.c
字号:
return status; if ((status & 0x20) == 0) { res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR; switch (status & 0x18) { case 0x00: case 0x10: case 0x14: case 0x18: res |= DECODER_STATUS_PAL; break; case 0x08: res |= DECODER_STATUS_SECAM; break; case 0x04: case 0x0c: case 0x1c: res |= DECODER_STATUS_NTSC; break; } } *(int *) arg = res; } break; case DECODER_SET_NORM: { int *iarg = arg, data; int temp_input; /* Here we back up the input selection because it gets overwritten when we fill the registers with the choosen video norm */ temp_input = vpx3220_fp_read(client, 0xf2); dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n", I2C_NAME(client), *iarg); switch (*iarg) { case VIDEO_MODE_NTSC: vpx3220_write_fp_block(client, init_ntsc, sizeof(init_ntsc) >> 1); dprintk(1, KERN_INFO "%s: norm switched to NTSC\n", I2C_NAME(client)); break; case VIDEO_MODE_PAL: vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1); dprintk(1, KERN_INFO "%s: norm switched to PAL\n", I2C_NAME(client)); break; case VIDEO_MODE_SECAM: vpx3220_write_fp_block(client, init_secam, sizeof(init_secam) >> 1); dprintk(1, KERN_INFO "%s: norm switched to SECAM\n", I2C_NAME(client)); break; case VIDEO_MODE_AUTO: /* FIXME This is only preliminary support */ data = vpx3220_fp_read(client, 0xf2) & 0x20; vpx3220_fp_write(client, 0xf2, 0x00c0 | data); dprintk(1, KERN_INFO "%s: norm switched to Auto\n", I2C_NAME(client)); break; default: return -EINVAL; } decoder->norm = *iarg; /* And here we set the backed up video input again */ vpx3220_fp_write(client, 0xf2, temp_input | 0x0010); udelay(10); } break; case DECODER_SET_INPUT: { int *iarg = arg, data; /* RJ: *iarg = 0: ST8 (PCTV) input *iarg = 1: COMPOSITE input *iarg = 2: SVHS input */ const int input[3][2] = { {0x0c, 0}, {0x0d, 0}, {0x0e, 1} }; if (*iarg < 0 || *iarg > 2) return -EINVAL; dprintk(1, KERN_INFO "%s: input switched to %s\n", I2C_NAME(client), inputs[*iarg]); vpx3220_write(client, 0x33, input[*iarg][0]); data = vpx3220_fp_read(client, 0xf2) & ~(0x0020); if (data < 0) return data; /* 0x0010 is required to latch the setting */ vpx3220_fp_write(client, 0xf2, data | (input[*iarg][1] << 5) | 0x0010); udelay(10); } break; case DECODER_SET_OUTPUT: { int *iarg = arg; /* not much choice of outputs */ if (*iarg != 0) { return -EINVAL; } } break; case DECODER_ENABLE_OUTPUT: { int *iarg = arg; dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n", I2C_NAME(client), *iarg); vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00)); } break; case DECODER_SET_PICTURE: { struct video_picture *pic = arg; if (decoder->bright != pic->brightness) { /* We want -128 to 128 we get 0-65535 */ decoder->bright = pic->brightness; vpx3220_write(client, 0xe6, (decoder->bright - 32768) >> 8); } if (decoder->contrast != pic->contrast) { /* We want 0 to 64 we get 0-65535 */ /* Bit 7 and 8 is for noise shaping */ decoder->contrast = pic->contrast; vpx3220_write(client, 0xe7, (decoder->contrast >> 10) + 192); } if (decoder->sat != pic->colour) { /* We want 0 to 4096 we get 0-65535 */ decoder->sat = pic->colour; vpx3220_fp_write(client, 0xa0, decoder->sat >> 4); } if (decoder->hue != pic->hue) { /* We want -512 to 512 we get 0-65535 */ decoder->hue = pic->hue; vpx3220_fp_write(client, 0x1c, ((decoder->hue - 32768) >> 6) & 0xFFF); } } break; default: return -EINVAL; } return 0;}static intvpx3220_init_client (struct i2c_client *client){ vpx3220_write_block(client, init_common, sizeof(init_common)); vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1); /* Default to PAL */ vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1); return 0;}/* ----------------------------------------------------------------------- * Client managment code *//* * Generic i2c probe * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */static unsigned short normal_i2c[] = { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, I2C_CLIENT_END};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 vpx3220_i2c_driver;static intvpx3220_detach_client (struct i2c_client *client){ struct vpx3220 *decoder = i2c_get_clientdata(client); int err; err = i2c_detach_client(client); if (err) { return err; } kfree(decoder); kfree(client); return 0;}static intvpx3220_detect_client (struct i2c_adapter *adapter, int address, int kind){ int err; struct i2c_client *client; struct vpx3220 *decoder; dprintk(1, VPX3220_DEBUG "%s\n", __func__); /* Check if the adapter supports the needed features */ if (!i2c_check_functionality (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return 0; client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (client == NULL) { return -ENOMEM; } memset(client, 0, sizeof(struct i2c_client)); client->addr = address; client->adapter = adapter; client->driver = &vpx3220_i2c_driver; client->flags = I2C_CLIENT_ALLOW_USE; /* Check for manufacture ID and part number */ if (kind < 0) { u8 id; u16 pn; id = vpx3220_read(client, 0x00); if (id != 0xec) { dprintk(1, KERN_INFO "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n", id); kfree(client); return 0; } pn = (vpx3220_read(client, 0x02) << 8) + vpx3220_read(client, 0x01); switch (pn) { case 0x4680: strlcpy(I2C_NAME(client), "vpx3220a", sizeof(I2C_NAME(client))); break; case 0x4260: strlcpy(I2C_NAME(client), "vpx3216b", sizeof(I2C_NAME(client))); break; case 0x4280: strlcpy(I2C_NAME(client), "vpx3214c", sizeof(I2C_NAME(client))); break; default: dprintk(1, KERN_INFO "%s: Wrong part number (0x%04x)\n", __func__, pn); kfree(client); return 0; } } else { strlcpy(I2C_NAME(client), "forced vpx32xx", sizeof(I2C_NAME(client))); } decoder = kmalloc(sizeof(struct vpx3220), GFP_KERNEL); if (decoder == NULL) { kfree(client); return -ENOMEM; } memset(decoder, 0, sizeof(struct vpx3220)); decoder->norm = VIDEO_MODE_PAL; decoder->input = 0; decoder->enable = 1; decoder->bright = 32768; decoder->contrast = 32768; decoder->hue = 32768; decoder->sat = 32768; i2c_set_clientdata(client, decoder); err = i2c_attach_client(client); if (err) { kfree(client); kfree(decoder); return err; } dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n", I2C_NAME(client), client->addr << 1); vpx3220_init_client(client); return 0;}static intvpx3220_attach_adapter (struct i2c_adapter *adapter){ int ret; ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client); dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n", __func__, ret); return ret;}/* ----------------------------------------------------------------------- * Driver initialization and cleanup code */static struct i2c_driver vpx3220_i2c_driver = { .owner = THIS_MODULE, .name = "vpx3220", .id = I2C_DRIVERID_VPX3220, .flags = I2C_DF_NOTIFY, .attach_adapter = vpx3220_attach_adapter, .detach_client = vpx3220_detach_client, .command = vpx3220_command,};static int __initvpx3220_init (void){ return i2c_add_driver(&vpx3220_i2c_driver);}static void __exitvpx3220_cleanup (void){ i2c_del_driver(&vpx3220_i2c_driver);}module_init(vpx3220_init);module_exit(vpx3220_cleanup);MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video encoder driver");MODULE_AUTHOR("Laurent Pinchart");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -