📄 w9968cf.c
字号:
{ DBG(4, "i2c_write_byte() is an unsupported transfer mode") return -EINVAL;}/**************************************************************************** * I2C interface to kernel * ****************************************************************************/static intw9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data){ struct w9968cf_device* cam = i2c_get_adapdata(adapter); u8 i; int err = 0; switch (addr) { case OV6xx0_SID: case OV7xx0_SID: break; default: DBG(4, "Rejected slave ID 0x%04X", addr) return -EINVAL; } if (size == I2C_SMBUS_BYTE) { /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ addr <<= 1; if (read_write == I2C_SMBUS_WRITE) err = w9968cf_i2c_adap_write_byte(cam, addr, command); else if (read_write == I2C_SMBUS_READ) err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); } else if (size == I2C_SMBUS_BYTE_DATA) { addr <<= 1; if (read_write == I2C_SMBUS_WRITE) err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, command, data->byte); else if (read_write == I2C_SMBUS_READ) { for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { err = w9968cf_i2c_adap_read_byte_data(cam,addr, command, &data->byte); if (err) { if (w9968cf_smbus_refresh_bus(cam)) { err = -EIO; break; } } else break; } } else return -EINVAL; } else { DBG(4, "Unsupported I2C transfer mode (%d)", size) return -EINVAL; } return err;}static u32 w9968cf_i2c_func(struct i2c_adapter* adap){ return I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;}static int w9968cf_i2c_attach_inform(struct i2c_client* client){ struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); const char* clientname = i2c_clientname(client); int id = client->driver->id, err = 0; if (id == I2C_DRIVERID_OVCAMCHIP) { cam->sensor_client = client; err = w9968cf_sensor_init(cam); if (err) { cam->sensor_client = NULL; return err; } } else { DBG(4, "Rejected client [%s] with driver [%s]", clientname, client->driver->name) return -EINVAL; } DBG(5, "I2C attach client [%s] with driver [%s]", clientname, client->driver->name) return 0;}static int w9968cf_i2c_detach_inform(struct i2c_client* client){ struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); const char* clientname = i2c_clientname(client); if (cam->sensor_client == client) cam->sensor_client = NULL; DBG(5, "I2C detach client [%s]", clientname) return 0;}static int w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, unsigned long arg){ return 0;}static int w9968cf_i2c_init(struct w9968cf_device* cam){ int err = 0; static struct i2c_algorithm algo = { .name = "W996[87]CF algorithm", .id = I2C_ALGO_SMBUS, .smbus_xfer = w9968cf_i2c_smbus_xfer, .algo_control = w9968cf_i2c_control, .functionality = w9968cf_i2c_func, }; static struct i2c_adapter adap = { .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF, .class = I2C_CLASS_CAM_DIGITAL, .owner = THIS_MODULE, .client_register = w9968cf_i2c_attach_inform, .client_unregister = w9968cf_i2c_detach_inform, .algo = &algo, }; memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); strcpy(cam->i2c_adapter.name, "w9968cf"); i2c_set_adapdata(&cam->i2c_adapter, cam); DBG(6, "Registering I2C adapter with kernel...") err = i2c_add_adapter(&cam->i2c_adapter); if (err) DBG(1, "Failed to register the I2C adapter") else DBG(5, "I2C adapter registered") return err;}/**************************************************************************** * Helper functions * ****************************************************************************//*-------------------------------------------------------------------------- Turn on the LED on some webcams. A beep should be heard too. Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_turn_on_led(struct w9968cf_device* cam){ int err = 0; err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ if (err) DBG(2, "Couldn't turn on the LED") DBG(5, "LED turned on") return err;}/*-------------------------------------------------------------------------- Write some registers for the device initialization. This function is called once on open(). Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_init_chip(struct w9968cf_device* cam){ unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, y0 = 0x0000, u0 = y0 + hw_bufsize/2, v0 = u0 + hw_bufsize/4, y1 = v0 + hw_bufsize/4, u1 = y1 + hw_bufsize/2, v1 = u1 + hw_bufsize/4; int err = 0; err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ err += w9968cf_set_picture(cam, cam->picture); /* this before */ err += w9968cf_set_window(cam, cam->window); if (err) DBG(1, "Chip initialization failed") else DBG(5, "Chip successfully initialized") return err;}/*-------------------------------------------------------------------------- Return non-zero if the palette is supported, 0 otherwise. --------------------------------------------------------------------------*/static inline u16 w9968cf_valid_palette(u16 palette){ u8 i = 0; while (w9968cf_formatlist[i].palette != 0) { if (palette == w9968cf_formatlist[i].palette) return palette; i++; } return 0;}/*-------------------------------------------------------------------------- Return the depth corresponding to the given palette. Palette _must_ be supported ! --------------------------------------------------------------------------*/static inline u16 w9968cf_valid_depth(u16 palette){ u8 i=0; while (w9968cf_formatlist[i].palette != palette) i++; return w9968cf_formatlist[i].depth;}/*-------------------------------------------------------------------------- Return non-zero if the format requires decompression, 0 otherwise. --------------------------------------------------------------------------*/static inline u8 w9968cf_need_decompression(u16 palette){ u8 i = 0; while (w9968cf_formatlist[i].palette != 0) { if (palette == w9968cf_formatlist[i].palette) return w9968cf_formatlist[i].compression; i++; } return 0;}/*-------------------------------------------------------------------------- Change the picture settings of the camera. Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static intw9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict){ u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; int err = 0; /* Make sure we are using a valid depth */ pict.depth = w9968cf_valid_depth(pict.palette); fmt = pict.palette; hw_depth = pict.depth; /* depth used by the winbond chip */ hw_palette = pict.palette; /* palette used by the winbond chip */ /* VS & HS polarities */ reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); switch (fmt) { case VIDEO_PALETTE_UYVY: reg_v |= 0x0000; cam->vpp_flag = VPP_NONE; break; case VIDEO_PALETTE_YUV422P: reg_v |= 0x0002; cam->vpp_flag = VPP_DECOMPRESSION; break; case VIDEO_PALETTE_YUV420: case VIDEO_PALETTE_YUV420P: reg_v |= 0x0003; cam->vpp_flag = VPP_DECOMPRESSION; break; case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_YUV422: reg_v |= 0x0000; cam->vpp_flag = VPP_SWAP_YUV_BYTES; hw_palette = VIDEO_PALETTE_UYVY; break; /* Original video is used instead of RGBX palettes. Software conversion later. */ case VIDEO_PALETTE_GREY: case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_RGB32: reg_v |= 0x0000; /* UYVY 16 bit is used */ hw_depth = 16; hw_palette = VIDEO_PALETTE_UYVY; cam->vpp_flag = VPP_UYVY_TO_RGBX; break; } /* NOTE: due to memory issues, it is better to disable the hardware double buffering during compression */ if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) reg_v |= 0x0080; if (cam->clamping) reg_v |= 0x0020; if (cam->filter_type == 1) reg_v |= 0x0008; else if (cam->filter_type == 2) reg_v |= 0x000c; if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) goto
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -