📄 omapcamera_sensor_if.c
字号:
};const static struct ov9640_reg * ov9640_reg_init[NUM_PIXEL_FORMATS][NUM_IMAGE_SIZES] ={ { qqcif_yuv, qqvga_yuv, qcif_yuv, qvga_yuv, cif_yuv, vga_yuv, sxga_yuv }, { qqcif_565, qqvga_565, qcif_565, qvga_565, cif_565, vga_565, sxga_565 }, { qqcif_555, qqvga_555, qcif_555, qvga_555, cif_555, vga_555, sxga_555 },};static int ov9640_read_reg(struct i2c_client *client, u8 reg, u8 *val){ int err; struct i2c_msg msg[1]; unsigned char data[1]; if (!client->adapter) return -ENODEV; msg->addr = client->addr; msg->flags = 0; msg->len = 1; msg->buf = data; *data = reg; err = i2c_transfer(client->adapter, msg, 1); if (err >= 0) { msg->flags = I2C_M_RD; err = i2c_transfer(client->adapter, msg, 1); } if (err >= 0) { *val = *data; return 0; } return err;}/* Write a value to a register in an OV9640 sensor device. * Returns zero if successful, or non-zero otherwise. */static int ov9640_write_reg(struct i2c_client *client, u8 reg, u8 val){ int err; struct i2c_msg msg[1]; unsigned char data[2]; if (!client->adapter) return -ENODEV; msg->addr = client->addr; msg->flags = 0; msg->len = 2; msg->buf = data; data[0] = reg; data[1] = val; err = i2c_transfer(client->adapter, msg, 1); if (err >= 0) return 0; return err;}/* Initialize a list of OV9640 registers. * The list of registers is terminated by the pair of values * { OV9640_REG_TERM, OV9640_VAL_TERM }. * Returns zero if successful, or non-zero otherwise. */static int ov9640_write_regs(struct i2c_client *client, const struct ov9640_reg reglist[]){ int err; const struct ov9640_reg *next = reglist; while (!((next->reg == OV9640_REG_TERM) && (next->val == OV9640_VAL_TERM))) { err = ov9640_write_reg(client, next->reg, next->val); udelay(100); if (err) return err; next++; } return 0;}/* Calculate the internal clock divisor (value of the CLKRC register) of the * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a * desired frame period (in seconds). The frame period 'fper' is expressed as * a fraction. The frame period is an input/output parameter. * Returns the value of the OV9640 CLKRC register that will yield the frame * period returned in 'fper' at the specified xclk frequency. The * returned period will be as close to the requested period as possible. */static unsigned charov9640_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper){ unsigned long fpm, fpm_max; /* frames per minute */ unsigned long divisor; const unsigned long divisor_max = 64; const static unsigned long clks_per_frame[] = { 200000, 400000, 200000, 400000, 400000, 800000, 3200000 }; /* QQCIF QQVGA QCIF QVGA CIF VGA SXGA *actually 199680,400000, 199680, 400000, 399360, 800000, 3200000 */ if (fper->numerator > 0) fpm = (fper->denominator*60)/fper->numerator; else fpm = 0xffffffff; fpm_max = (xclk*60)/clks_per_frame[isize]; if (fpm_max == 0) fpm_max = 1; if (fpm > fpm_max) fpm = fpm_max; if (fpm == 0) fpm = 1; divisor = fpm_max/fpm; if (divisor > divisor_max) divisor = divisor_max; fper->numerator = divisor*60; fper->denominator = fpm_max; /* try to reduce the fraction */ while (!(fper->denominator % 5) && !(fper->numerator % 5)) { fper->numerator /= 5; fper->denominator /= 5; } while (!(fper->denominator % 3) && !(fper->numerator % 3)) { fper->numerator /= 3; fper->denominator /= 3; } while (!(fper->denominator % 2) && !(fper->numerator % 2)) { fper->numerator /= 2; fper->denominator /= 2; } if (fper->numerator < fper->denominator) { if (!(fper->denominator % fper->numerator)) { fper->denominator /= fper->numerator; fper->numerator = 1; } } else { if (!(fper->numerator % fper->denominator)) { fper->numerator /= fper->denominator; fper->denominator = 1; } } /* we set bit 7 in CLKRC to enable the digital PLL */ return (0x80 | (divisor - 1));}/* Configure the OV9640 for a specified image size, pixel format, and frame * period. xclk is the frequency (in Hz) of the xclk input to the OV9640. * fper is the frame period (in seconds) expressed as a fraction. * Returns zero if successful, or non-zero otherwise. * The actual frame period is returned in fper. */static intov9640_configure(struct i2c_client *client, enum image_size isize, enum pixel_format pfmt, unsigned long xclk, struct v4l2_fract *fper){ int err; unsigned char clkrc; /* common register initialization */ err = ov9640_write_regs(client, ov9640_common); if (err) return err; /* configure image size and pixel format */ err = ov9640_write_regs(client, ov9640_reg_init[pfmt][isize]); if (err) return err; /* configure frame rate */ clkrc = ov9640_clkrc(isize, xclk, fper); err = ov9640_write_reg(client, OV9640_CLKRC, clkrc); if (err) return err; return 0;}/* Write to GPIO EXPA on the H4 board. * The GPIO expanders need an independent I2C client driver. */static intwrite_gpio_expa(u8 val, int add){ struct i2c_adapter *adap; int err; struct i2c_msg msg[1]; unsigned char data[1]; adap = i2c_get_adapter(0); if (!adap) return -ENODEV; msg->addr = add; /* I2C address of GPIO EXPA */ msg->flags = 0; msg->len = 1; msg->buf = data; data[0] = val; err = i2c_transfer(adap, msg, 1); if (err >= 0) return 0; return err;}/* Read from GPIO EXPA on the H4 board. * The GPIO expanders need an independent I2C client driver. */static intread_gpio_expa(u8 *val, int add){ struct i2c_adapter *adap; int err; struct i2c_msg msg[1]; unsigned char data[1]; adap = i2c_get_adapter(0); if (!adap) return -ENODEV; msg->addr = add; /* I2C address of GPIO EXPA */ msg->flags = I2C_M_RD; msg->len = 1; msg->buf = data; err = i2c_transfer(adap, msg, 1); *val = data[0]; if (err >= 0) return 0; return err;}/* Power-up the OV9640 sensor on the H4 board. * Returns 0 if successful, non-zero otherwise. */static intov9640_powerup(struct omap24xxcam_device *cam){ unsigned char expa; int err; /* read current state of GPIO EXPA outputs */ if ((err = read_gpio_expa(&expa, 0x20))) { printk(KERN_ERR "%s: Error reading GPIO EXPA\n", cam->vfd->name); return err; } /* Clear GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up sensor */ if ((err = write_gpio_expa(expa & ~0x08, 0x20))) { printk(KERN_ERR "%s: Error writing to GPIO EXPA\n", cam->vfd->name); return err; } /* read current state of GPIO EXPA outputs */ if ((err = read_gpio_expa(&expa, 0x22))) { printk(KERN_ERR "%s: Error reading GPIO EXPA\n", cam->vfd->name); return err; } /* Clear GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up sensor */ if ((err = write_gpio_expa(expa & ~0x80, 0x22))) { printk(KERN_ERR "%s: Error writing to GPIO EXPA\n", cam->vfd->name); return err; } return 0;}/* Power-down the OV9640 sensor on the H4 board. * Returns 0 if successful, non-zero otherwise. */static intov9640_powerdown(struct omap24xxcam_device *cam){ unsigned char expa; int err; /* read current state of GPIO EXPA outputs */ if ((err = read_gpio_expa(&expa, 0x20))) { printk(KERN_ERR "%s: Error reading GPIO EXPA\n", cam->vfd->name); return err; } /* Set GPIO EXPA P3 (CAMERA_MODULE_EN) to power-down sensor */ if ((err = write_gpio_expa(expa | 0x08, 0x20))) { printk(KERN_ERR "%s: Error writing to GPIO EXPA\n", cam->vfd->name); return err; } return 0;}/* Detect if an OV9640 is present, and if so which revision. * A device is considered to be detected if the manufacturer ID (MIDH and MIDL) * and the product ID (PID) registers match the expected values. * Any value of the version ID (VER) register is accepted. * Here are the version numbers we know about: * 0x48 --> OV9640 Revision 1 or OV9640 Revision 2 * 0x49 --> OV9640 Revision 3 * Returns a negative error number if no device is detected, or the * non-negative value of the version ID register if a device is detected. */static intov9640_detect(struct ov9640_sensor *sensor){ u8 midh, midl, pid, ver; struct i2c_client *client; if (!sensor) return -ENODEV; client = &sensor->client; if (ov9640_read_reg(client, OV9640_MIDH, &midh)) return -ENODEV; if (ov9640_read_reg(client, OV9640_MIDL, &midl)) return -ENODEV; if (ov9640_read_reg(client, OV9640_PID, &pid)) return -ENODEV; if (ov9640_read_reg(client, OV9640_VER, &ver)) return -ENODEV; if ((midh != OV9640_MIDH_MAGIC) || (midl != OV9640_MIDL_MAGIC) || (pid != OV9640_PID_MAGIC)) { /* We didn't read the values we expected, so * this must not be an OV9640. */ return -ENODEV; } sensor->ver = ver; return ver;}/* This function registers an I2C client via i2c_attach_client() for an OV9640 * sensor device. If 'probe' is non-zero, then the I2C client is only * registered if the device can be detected. If 'probe' is zero, then no * device detection is attempted and the I2C client is always registered. * Returns zero if an I2C client is successfully registered, or non-zero * otherwise. */static int ov9640_i2c_attach_client(struct i2c_adapter *adap, int addr, int probe){ struct ov9640_sensor *sensor = &ov9640; struct i2c_client *client = &sensor->client; int err; if (client->adapter) return -EBUSY; /* our client is already attached */ client->addr = addr; client->flags = I2C_CLIENT_ALLOW_USE; client->driver = &sensor->driver; client->adapter = adap; err = i2c_attach_client(client); if (err) { client->adapter = NULL; return err; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -