📄 sensor_ov9640.c
字号:
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; } 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; } if (probe) { err = ov9640_detect(client); if (err < 0) { i2c_detach_client(client); client->adapter = NULL; return err; } sensor->ver = err; } return 0;}/* This function is called by i2c_del_adapter() and i2c_del_driver() * if the adapter or driver with which this I2C client is associated is * removed. This function unregisters the client via i2c_detach_client(). * Returns zero if the client is successfully detached, or non-zero * otherwise. */static int ov9640_i2c_detach_client(struct i2c_client *client){ int err; if (!client->adapter) return -ENODEV; /* our client isn't attached */ err = i2c_detach_client(client); client->adapter = NULL; return err;}/* This function will be called for each registered I2C bus adapter when our * I2C driver is registered via i2c_add_driver(). It will also be called * whenever a new I2C adapter is registered after our I2C driver is registered. * This function probes the specified I2C bus adapter to determine if an * OV9640 sensor device is present. If a device is detected, an I2C client * is registered for it via ov9640_i2c_attach_client(). Note that we can't use * the standard i2c_probe() function to look for the sensor because the OMAP * I2C controller doesn't support probing. * Returns zero if an OV9640 device is detected and an I2C client successfully * registered for it, or non-zero otherwise. */static int ov9640_i2c_probe_adapter(struct i2c_adapter *adap){ return ov9640_i2c_attach_client(adap, OV9640_I2C_ADDR, 1);}/* Find the best match for a requested image capture size. The best match * is chosen as the nearest match that has the same number or fewer pixels * as the requested size, or the smallest image size if the requested size * has fewer pixels than the smallest image. */static enum image_sizeov9640_find_size(unsigned int width, unsigned int height){ enum image_size isize; unsigned long pixels = width*height; for (isize = QQCIF; isize < SXGA; isize++) { if (ov9640_sizes[isize + 1].height* ov9640_sizes[isize + 1].width > pixels) { return isize; } } return SXGA;}/* --------------------------------------------------------------------- * Following are sensor interface functions implemented by * OV9640 sensor driver. They are nanmed ov9640sensor_<name> */static intov9640sensor_power_on(void *priv){ return ov9640_powerup();}static intov9640sensor_power_off(void *priv){ return ov9640_powerdown();}static intov9640sensor_query_control(struct v4l2_queryctrl *qc, void *priv){ int i; i = find_vctrl (qc->id); if (i == -EINVAL) { qc->flags = V4L2_CTRL_FLAG_DISABLED; return 0; } if (i < 0) return -EINVAL; *qc = control[i].qc; return 0;}static intov9640sensor_get_control(struct v4l2_control *vc, void *priv){ struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; struct i2c_client *client = &sensor->client; int i, val; struct vcontrol * lvc; i = find_vctrl(vc->id); if (i < 0) return -EINVAL; lvc = &control[i]; if (ov9640_read_reg_mask(client, lvc->reg, (u8 *)&val, lvc->mask)) return -EIO; val = val >> lvc->start_bit; if (val >= 0) { vc->value = lvc->current_value = val; return 0; } else return val;}static intov9640sensor_set_control(struct v4l2_control *vc, void *priv){ struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; struct i2c_client *client = &sensor->client; struct vcontrol *lvc; int val = vc->value; int i; i = find_vctrl(vc->id); if (i < 0) return -EINVAL; lvc = &control[i]; val = val << lvc->start_bit; if (ov9640_write_reg_mask(client, lvc->reg, (u8 *)&val, (u8)lvc->mask)) return -EIO; val = val>> lvc->start_bit; if (val >= 0) { lvc->current_value = val; return 0; } else return val;}/* Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type. */static intov9640sensor_enum_pixformat(struct v4l2_fmtdesc *fmt, void *priv){ int index = fmt->index; enum v4l2_buf_type type = fmt->type; memset(fmt, 0, sizeof(*fmt)); fmt->index = index; fmt->type = type; switch (fmt->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (index >= NUM_CAPTURE_FORMATS) return -EINVAL; break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (index >= NUM_OVERLAY_FORMATS) return -EINVAL; break; default: return -EINVAL; } fmt->flags = ov9640_formats[index].flags; strlcpy(fmt->description, ov9640_formats[index].description, sizeof(fmt->description)); fmt->pixelformat = ov9640_formats[index].pixelformat; return 0;}/* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This * ioctl is used to negotiate the image capture size and pixel format * without actually making it take effect. */static intov9640sensor_try_format(struct v4l2_pix_format *pix, void *priv){ enum image_size isize; int ifmt; isize = ov9640_find_size(pix->width, pix->height); pix->width = ov9640_sizes[isize].width; pix->height = ov9640_sizes[isize].height; for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) { if (pix->pixelformat == ov9640_formats[ifmt].pixelformat) break; } if (ifmt == NUM_CAPTURE_FORMATS) ifmt = 0; pix->pixelformat = ov9640_formats[ifmt].pixelformat; pix->field = V4L2_FIELD_NONE; pix->bytesperline = pix->width*2; pix->sizeimage = pix->bytesperline*pix->height; pix->priv = 0; switch (pix->pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: default: pix->colorspace = V4L2_COLORSPACE_JPEG; break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB555X: pix->colorspace = V4L2_COLORSPACE_SRGB; break; } return 0;}/* Given the image capture format in pix, the nominal frame period in * timeperframe, calculate the required xclk frequency * The nominal xclk input frequency of the OV9640 is 24MHz, maximum * frequency is 48MHz, and minimum frequency is 10MHz. */static unsigned longov9640sensor_calc_xclk(struct v4l2_pix_format *pix, struct v4l2_fract *timeperframe, void *priv){ unsigned long tgt_xclk; /* target xclk */ unsigned long tgt_fpm; /* target frames per minute */ enum image_size isize; /* We use arbitrary rules to select the xclk frequency. If the * capture size is VGA and the frame rate is greater than 900 * frames per minute, or if the capture size is SXGA and the * frame rate is greater than 450 frames per minutes, then the * xclk frequency will be set to 48MHz. Otherwise, the xclk * frequency will be set to 24MHz. If the mclk frequency is such that * the target xclk frequency is not achievable, then xclk will be set * as close as to the target as possible. */ if ((timeperframe->numerator == 0) || (timeperframe->denominator == 0)) { /* supply a default nominal_timeperframe of 15 fps */ timeperframe->numerator = 1; timeperframe->denominator = 15; } tgt_fpm = (timeperframe->denominator*60) / timeperframe->numerator; tgt_xclk = 24000000; isize = ov9640_find_size(pix->width, pix->height); switch (isize) { case SXGA: if (tgt_fpm > 450) tgt_xclk = 48000000; break; case VGA: if (tgt_fpm > 900) tgt_xclk = 48000000; break; default: break; } return tgt_xclk;}/* Given a capture format in pix, the frame period in timeperframe, and * the xclk frequency, set the capture format of the OV9640 sensor. * The actual frame period will be returned in timeperframe. */static intov9640sensor_configure(struct v4l2_pix_format *pix, unsigned long xclk, struct v4l2_fract *timeperframe, void *priv){ struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; enum pixel_format pfmt = YUV; switch (pix->pixelformat) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: pfmt = RGB565; break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB555X: pfmt = RGB555; break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: default: pfmt = YUV; } return ov9640_configure(&sensor->client, ov9640_find_size(pix->width, pix->height), pfmt, xclk, timeperframe);}/* Prepare for the driver to exit. * Balances ov9640sensor_init(). * This function must de-initialize the sensor and its associated data * structures. */static intov9640sensor_cleanup(void *priv){ struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; if (sensor) { i2c_del_driver(&sensor->driver); ov9640_powerdown(); } return 0;}/* Initialize the OV9640 sensor. * This routine allocates and initializes the data structure for the sensor, * powers up the sensor, registers the I2C driver, and sets a default image * capture format in pix. The capture format is not actually programmed * into the OV9640 sensor by this routine. * This function must return a non-NULL value to indicate that * initialization is successful. */static void *ov9640sensor_init(struct v4l2_pix_format *pix){ struct ov9640_sensor *sensor = &ov9640; struct i2c_driver *driver = &sensor->driver; int err; memset(sensor, 0, sizeof(*sensor)); /* power-up the sensor */ if (ov9640_powerup()) return NULL; driver->owner = THIS_MODULE; strlcpy(driver->name, "OV9640 I2C driver", sizeof(driver->name)); driver->id = I2C_DRIVERID_EXP0; driver->flags = I2C_DF_NOTIFY; driver->attach_adapter = ov9640_i2c_probe_adapter; driver->detach_client = ov9640_i2c_detach_client; err = i2c_add_driver(driver); if (err) { printk(KERN_ERR "Failed to register OV9640 I2C client.\n"); return NULL; } if (!sensor->client.adapter) { printk(KERN_WARNING "Failed to detect OV9640 sensor chip.\n"); return NULL; } else { printk(KERN_INFO "OV9640 sensor chip version 0x%02x detected\n", sensor->ver); } /* Make the default capture format QCIF RGB565 */ pix->width = ov9640_sizes[QCIF].width; pix->height = ov9640_sizes[QCIF].height; pix->pixelformat = V4L2_PIX_FMT_RGB565; ov9640sensor_try_format(pix, NULL); return (void *)sensor;}struct camera_sensor camera_sensor_if = { version: 0x01, name: "OV9640", init: ov9640sensor_init, cleanup: ov9640sensor_cleanup, power_on: ov9640sensor_power_on, power_off: ov9640sensor_power_off, enum_pixformat: ov9640sensor_enum_pixformat, try_format: ov9640sensor_try_format, calc_xclk: ov9640sensor_calc_xclk, configure: ov9640sensor_configure, query_control: ov9640sensor_query_control, get_control: ov9640sensor_get_control, set_control: ov9640sensor_set_control,};void print_ov9640_regs(void *priv){ struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; u8 reg, val; for (reg=0x00; reg <=0x8A; reg++) if (ov9640_read_reg(&sensor->client,reg,&val)) printk("error reading %x\n", reg); else printk("reg %x = %x\n", reg, val); }#endif /* ifdef CAMERA_OV9640 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -