📄 omapcamera_sensor_if.c
字号:
if (probe) { err = ov9640_detect(sensor); if (err < 0) { i2c_detach_client(client); client->adapter = NULL; return 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;}/* Convert a Video for Linux fourcc pixelformat to an enum pixel_format value. */static enum pixel_formatov9640_find_format(unsigned long pixelformat){ switch (pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: default: return YUV; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: return RGB565; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB555X: return RGB555; }}/* 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 voidov9640_try_fmt(struct v4l2_pix_format *pix){ 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; }}/* Given the image capture format in cam->pix, the nominal frame period in * cam->nominal_timeperframe, and the frequency of the camera interface * functional clock (cam->mclk), calculate the required xclk frequency * (cam->xclk) and the actual frame period (cam->cparm.timeperframe). * xclk is obtained by dividing mclk with a divisor in the range 1 to 30. * The nominal xclk input frequency of the OV9640 is 24MHz, maximum * frequency is 48MHz, and minimum frequency is 10MHz. */static voidomap24xxcam_sensor_timeperframe(struct omap24xxcam_device *cam){ unsigned long tgt_xclk; /* target xclk */ unsigned long tgt_fpm; /* target frames per minute */ unsigned long divisor; 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 ((cam->nominal_timeperframe.numerator == 0) || (cam->nominal_timeperframe.denominator == 0)) { /* supply a default nominal_timeperframe of 15 fps */ cam->nominal_timeperframe.numerator = 1; cam->nominal_timeperframe.denominator = 15; } tgt_fpm = (cam->nominal_timeperframe.denominator*60) / cam->nominal_timeperframe.numerator; tgt_xclk = 24000000; isize = ov9640_find_size(cam->pix.width, cam->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; } if (tgt_xclk > cam->mclk) tgt_xclk = cam->mclk; divisor = cam->mclk/tgt_xclk; if (tgt_xclk*divisor < cam->mclk) divisor += 1; if (divisor > 30) divisor = 30; cam->xclk = cam->mclk/divisor; cam->cparm.timeperframe = cam->nominal_timeperframe; ov9640_clkrc(isize, cam->xclk, &cam->cparm.timeperframe);}/* Given a capture format in cam->pix, the frame period in * cam->cparm.timeperframe, and the xclk frequency in cam->xclk, set the * capture format of the OV9640 sensor. The actual frame period will be * returned in cam->cparm.timeperframe. */static intcamera_sensor_configure(struct omap24xxcam_device *cam){ struct ov9640_sensor *sensor = (struct ov9640_sensor *) cam->sensor; struct i2c_client *client = &sensor->client; enum image_size isize; enum pixel_format pfmt; int err; isize = ov9640_find_size(cam->pix.width, cam->pix.height); pfmt = ov9640_find_format(cam->pix.pixelformat); err = ov9640_configure(client, isize, pfmt, cam->xclk, &cam->cparm.timeperframe); return err;}/* Implement sensor-specific ioctls. For any ioctls we don't handle here we * return -ENOIOCTLCMD, which indicates that the generic camera interface ioctl * routine should provide a default handler. */static intomap24xxcam_sensor_ioctl(struct omap24xxcam_fh *fh, unsigned long cmd, void *arg){ switch (cmd) { case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) arg; 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; } case VIDIOC_TRY_FMT: { struct v4l2_format *f = (struct v4l2_format *) arg; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: ov9640_try_fmt(&f->fmt.pix); break; default: /* Let the camera interface ioctl * handler deal with all other cases. */ return -ENOIOCTLCMD; } return 0; } default: return -ENOIOCTLCMD; }}/* Prepare for the driver to exit. * Balances omap24xxcam_sensor_init(). * This function must set cam->sensor to NULL to indicate that the sensor * and its associated data structures have been de-initialized. */static voidomap24xxcam_sensor_exit(struct omap24xxcam_device *cam){ struct ov9640_sensor *sensor = (struct ov9640_sensor *) cam->sensor; if (sensor) {#ifndef CONFIG_OMAP24XX_VIRTIO ov9640_powerdown(cam);#endif cam->sensor = NULL; }}/* 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 cam->pix. The capture format is not actually programmed * into the OV9640 sensor by this routine. * This function must set cam->sensor to a non-NULL value to indicate that * initialization is successful. cam->sensor must be set to NULL to indicate * failure. */static voidcamera_sensor_init(struct omap24xxcam_device *cam){ struct ov9640_sensor *sensor = &ov9640; struct i2c_driver *driver = &sensor->driver; struct v4l2_pix_format *pix = &cam->pix; int err; memset(sensor, 0, sizeof(*sensor)); /* power-up the sensor */#ifndef CONFIG_OMAP24XX_VIRTIO ov9640_powerup(cam);#endif 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 "%s: Failed to register OV9640 I2C client.\n", cam->vfd->name); return; } if (!sensor->client.adapter) { printk(KERN_WARNING "%s: Failed to detect OV9640 sensor chip.\n", cam->vfd->name); } else { printk(KERN_INFO "%s: OV9640 sensor chip version 0x%02x detected\n", cam->vfd->name, 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; ov9640_try_fmt(pix); cam->sensor = sensor;}struct camera_sensor camera_sensor_if = { version : 0x01, init: camera_sensor_init, timeperframe: omap24xxcam_sensor_timeperframe, configure: camera_sensor_configure, exit : omap24xxcam_sensor_exit, try_format: ov9640_try_fmt, ioctl: omap24xxcam_sensor_ioctl, power_on: ov9640_powerup, power_off: ov9640_powerdown, };#endif /* ifdef CAMERA_OV9640 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -