📄 saa7121.c
字号:
static struct miscdevice saa7121_MiscDev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVNAME, .fops = &saa7121_fops};static inline intsaa7121_read (struct i2c_client *client,u8 reg){ return i2c_smbus_read_byte_data(client,reg);}static intsaa7121_write (struct i2c_client *client, u8 reg, u8 value){ struct saa7121 *encoder = i2c_get_clientdata(client); //dprintk(1, KERN_DEBUG "SAA7121: %02x set to %02x\n", reg, value); encoder->reg[reg] = value; return i2c_smbus_write_byte_data(client, reg, value);}static intsaa7121_write_block (struct i2c_client *client, const u8 *data, unsigned int len){ int ret = -1; u8 reg; /*测试是否支持I2C_FUNC_I2C*/ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { /* do raw I2C, not smbus compatible */ struct saa7121 *encoder = i2c_get_clientdata(client); struct i2c_msg msg; u8 block_data[32]; msg.addr = client->addr; msg.flags = 0; while (len >= 2) { msg.buf = (char *) block_data; msg.len = 0; block_data[msg.len++] = reg = data[0]; do { block_data[msg.len++] = encoder->reg[reg++] = data[1]; len -= 2; data += 2; } while (len >= 2 && data[0] == reg && msg.len < 32); if ((ret = i2c_transfer(client->adapter, &msg, 1)) < 0) break; } } else { /* do some slow I2C emulation kind of thing */ while (len >= 2) { reg = *data++; if ((ret = saa7121_write(client, reg, *data++)) < 0) break; len -= 2; //printk("Writing Reg[%02x], wait 1/4 second...\n",reg); //mdelay(250); } } return ret;}/* ----------------------------------------------------------------------- */static intsaa7121_command (struct i2c_client *client, unsigned int cmd, void *arg){ struct saa7121 *encoder = i2c_get_clientdata(client); switch (cmd) { case 0: saa7121_write_block(client, init_common, sizeof(init_common)); switch (encoder->norm) { case VIDEO_MODE_NTSC: saa7121_write_block(client, init_ntsc, sizeof(init_ntsc)); printk("saa7121 set output mode : NTSC\n"); break; case VIDEO_MODE_PAL: saa7121_write_block(client, init_pal, sizeof(init_pal)); printk("saa7121 set output mode : PAL\n"); break; } break; default: return -EINVAL; } return 0;}/* ----------------------------------------------------------------------- *//* * Generic i2c probe * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */static unsigned short normal_i2c[] = { I2C_SAA7121 >> 1, I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .normal_i2c_range = normal_i2c_range, .probe = probe, .probe_range = probe_range, .ignore = ignore, .ignore_range = ignore_range, .force = force};static int saa7121_i2c_id = 0;static struct i2c_driver i2c_driver_saa7121;static intsaa7121_detect_client (struct i2c_adapter *adapter, int address, int kind){ int i = 0; //int j = 0; //struct i2c_client *client; struct saa7121 *encoder; //saa7121_client = client; dprintk(1, KERN_INFO "saa7121.c: detecting saa7121 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; saa7121_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (saa7121_client == 0) return -ENOMEM; memset(saa7121_client, 0, sizeof(struct i2c_client)); saa7121_client->addr = address; saa7121_client->adapter = adapter; saa7121_client->driver = &i2c_driver_saa7121; saa7121_client->flags = I2C_CLIENT_ALLOW_USE; saa7121_client->id = saa7121_i2c_id++; snprintf(I2C_NAME(saa7121_client), sizeof(I2C_NAME(saa7121_client)) - 1, "saa7121[%d]", saa7121_client->id); encoder = kmalloc(sizeof(struct saa7121), GFP_KERNEL); if (encoder == NULL) { kfree(saa7121_client); return -ENOMEM; } memset(encoder, 0, sizeof(struct saa7121)); encoder->norm = VIDEO_MODE_PAL; encoder->enable = 1; i2c_set_clientdata(saa7121_client, encoder); i = i2c_attach_client(saa7121_client); if (i) { kfree(saa7121_client); kfree(encoder); return i; } /*测试寄存器的数据*/ /* for (i=0; i<64; i++){ for (j=0; j<4; j++) { dprintk(1, "B_REG[%02x] = 0x%02x", i*4+j, saa7121_read(saa7121_client,i*4+j) ); } dprintk(1,"\n"); } */ i = saa7121_write_block(saa7121_client, init_common, sizeof(init_common)); if (i >= 0) { if(strcmp(mode_option,"pal")==0) { printk("output format is : pal\n"); i = saa7121_write_block(saa7121_client, init_pal,sizeof(init_pal)); } else { printk("output format is : ntsc\n"); i = saa7121_write_block(saa7121_client, init_ntsc,sizeof(init_ntsc)); } } if (i < 0) { dprintk(1, KERN_ERR "%s_attach: init error %d\n", I2C_NAME(saa7121_client), i); } else { dprintk(1, KERN_INFO "%s_attach: chip version %d at address 0x%x\n", I2C_NAME(saa7121_client), saa7121_read(saa7121_client,0) >> 5, saa7121_client->addr << 1); } /* Register a misc device called "saa7121". */ i = misc_register( &saa7121_MiscDev ); if (i < 0) { dprintk(1, KERN_INFO "can't register misc device (minor %d)!\n", saa7121_MiscDev.minor ); return i; } return 0;}static intsaa7121_attach_adapter (struct i2c_adapter *adapter){ dprintk(1, KERN_INFO "saa7121.c: starting probe for adapter %s (0x%x)\n", I2C_NAME(adapter), adapter->id); return i2c_probe(adapter, &addr_data, &saa7121_detect_client);}static intsaa7121_detach_client (struct i2c_client *client){ struct saa7121 *encoder = i2c_get_clientdata(client); int err; err = i2c_detach_client(client); if (err) { return err; } saa7121_write(client, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */ //saa7121_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */ kfree(encoder); kfree(client); return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver i2c_driver_saa7121 = { .owner = THIS_MODULE, .name = "saa7121", .id = I2C_DRIVERID_SAA7121, .flags = I2C_DF_NOTIFY, .attach_adapter = saa7121_attach_adapter, .detach_client = saa7121_detach_client, .command = saa7121_command,};static int __initsaa7121_init (void){ /*设置QVCP 5L的输出格式*/// QVCP5L的输出格式是双D1模式,8bit。// out_ctrl_value = inl(QVCP5L_ONSH_CTRL);// printk("QVCP 5L onsh control register(0x10e070) value= 0x%X\n",out_ctrl_value);// out_ctrl_value = inl(QVCP5L_OUT_CTRL);// printk("Old QVCP 5L control register(0x10e03C) value= 0x%X\n",out_ctrl_value); // out_ctrl_value &= QVCP5L_OUT_CTRL_MSK;// out_ctrl_value |= QVCP5L_OUT_CTRL_SET;// printk("New QVCP 5L control register value= 0x%X\n",out_ctrl_value);// outl(out_ctrl_value,QVCP5L_OUT_CTRL); return i2c_add_driver(&i2c_driver_saa7121);}static void __exitsaa7121_exit (void){ if (misc_deregister(&saa7121_MiscDev)!=0) { dprintk(1, KERN_INFO "saa7121: could not misc_deregister the device\n"); } i2c_del_driver(&i2c_driver_saa7121);}module_init(saa7121_init);module_exit(saa7121_exit);MODULE_DESCRIPTION("Philips SAA7121 Video Encoder Driver");MODULE_AUTHOR("Wu WenBin");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -