* [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface
@ 2007-08-18 8:36 Trilok Soni
2007-08-20 9:07 ` Sakari Ailus
0 siblings, 1 reply; 11+ messages in thread
From: Trilok Soni @ 2007-08-18 8:36 UTC (permalink / raw)
To: Linux OMAP; +Cc: Sakari Ailus
[-- Attachment #1: Type: text/plain, Size: 552 bytes --]
Hi All,
I have attached two patches which converts the ov9640 driver to use
the new v4l2 sensor interface. Sensor detection is working with H4 but
the output is not anywhere near to correct, so someone with H4 please
check and give inputs.
Patches are implemented and tested against mainline kernel and OMAP2
camera driver posted by Sakari to v4l mailing list [1].
--
--Trilok Soni
[1]
http://marc.info/?l=linux-video&m=118484999529003&w=2
http://marc.info/?l=linux-video&m=118477003808023&w=2
http://marc.info/?l=linux-video&m=118476992703092&w=2
[-- Attachment #2: 0001-ov9640-Add-OmniVision-ov9640-driver-new-interface.patch --]
[-- Type: text/x-diff, Size: 45256 bytes --]
From 90bae15a999faddbb17936f61b673a650453d854 Mon Sep 17 00:00:00 2001
From: Trilok Soni <soni.trilok@gmail.com>
Date: Fri, 17 Aug 2007 21:27:26 +0530
Subject: [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface
- Add Omnivision OV9640 driver with new v4l2 sensor
interface.
- Not quite working yet, with OMAP2 camera driver
on H4. Not ready for upstream.
Signed-off-by: Trilok Soni <soni.trilok@gmail.com>
---
drivers/media/video/Kconfig | 8 +
drivers/media/video/Makefile | 5 +-
drivers/media/video/ov9640.c | 1313 ++++++++++++++++++++++++++++++++++++++++++
drivers/media/video/ov9640.h | 185 ++++++
4 files changed, 1510 insertions(+), 1 deletions(-)
create mode 100644 drivers/media/video/ov9640.c
create mode 100644 drivers/media/video/ov9640.h
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index bd04ca6..a28325e 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -197,6 +197,14 @@ config VIDEO_OV7670
OV7670 VGA camera. It currently only works with the M88ALP01
controller.
+config VIDEO_OV9640
+ tristate "OmniVision OV9640 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV9640 camera. It currently works with the TI OMAP2
+ controller.
+
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L1 && I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index f476836..7fdc820 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -96,9 +96,12 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
-obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OMAP2) += omap24xxcam.o omap24xxcam-dma.o
+obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
+
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
new file mode 100644
index 0000000..9a7b039
--- /dev/null
+++ b/drivers/media/video/ov9640.c
@@ -0,0 +1,1313 @@
+/*
+ * drivers/media/video/ov9640.c
+ *
+ * OV9640 sensor driver
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ * Contact: Trilok Soni <soni.trilok@gmail.com>
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-int-device.h>
+
+#include "ov9640.h"
+
+#define DRIVER_NAME "ov9640"
+
+struct ov9640_sensor {
+ const struct ov9640_platform_data *pdata;
+ struct v4l2_int_device *v4l2_int_device;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ struct v4l2_fract timeperframe;
+ int ver; /*ov9640 chip version*/
+};
+
+static struct ov9640_sensor ov9640;
+static struct i2c_driver ov9640sensor_i2c_driver;
+
+/* list of image formats supported by OV9640 sensor */
+const static struct v4l2_fmtdesc ov9640_formats[] = {
+ {
+ /* Note: V4L2 defines RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
+ *
+ * We interpret RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
+ */
+ .description = "RGB565, le",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ /* Note: V4L2 defines RGB565X as:
+ *
+ * Byte 0 Byte 1
+ * b4 b3 b2 b1 b0 g5 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
+ *
+ * We interpret RGB565X as:
+ *
+ * Byte 0 Byte 1
+ * r4 r3 r2 r1 r0 g5 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
+ */
+ .description = "RGB565, be",
+ .pixelformat = V4L2_PIX_FMT_RGB565X,
+ },
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .description = "UYVY, packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ /* Note: V4L2 defines RGB555 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 x b4 b3 b2 b1 b0 g4 g3
+ *
+ * We interpret RGB555 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 x r4 r3 r2 r1 r0 g4 g3
+ */
+ .description = "RGB555, le",
+ .pixelformat = V4L2_PIX_FMT_RGB555,
+ },
+ {
+ /* Note: V4L2 defines RGB555X as:
+ *
+ * Byte 0 Byte 1
+ * x b4 b3 b2 b1 b0 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
+ *
+ * We interpret RGB555X as:
+ *
+ * Byte 0 Byte 1
+ * x r4 r3 r2 r1 r0 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
+ */
+ .description = "RGB555, be",
+ .pixelformat = V4L2_PIX_FMT_RGB555X,
+ },
+};
+
+#define NUM_CAPTURE_FORMATS ARRAY_SIZE(ov9640_formats)
+
+/*
+ * OV9640 register configuration for all combinations of pixel format and
+ * image size
+ */
+ /* YUV (YCbCr) QQCIF */
+const static struct ov9640_reg qqcif_yuv[] = {
+ { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x0F }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* YUV (YCbCr) QQVGA */
+const static struct ov9640_reg qqvga_yuv[] = {
+ { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x0F }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* YUV (YCbCr) QCIF */
+const static struct ov9640_reg qcif_yuv[] = {
+ { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x0F }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* YUV (YCbCr) QVGA */
+const static struct ov9640_reg qvga_yuv[] = {
+ { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x0F }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* YUV (YCbCr) CIF */
+const static struct ov9640_reg cif_yuv[] = {
+ { 0x12, 0x20 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x0F }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* YUV (YCbCr) VGA */
+const static struct ov9640_reg vga_yuv[] = {
+ { 0x12, 0x40 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x0F }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* YUV (YCbCr) SXGA */
+const static struct ov9640_reg sxga_yuv[] = {
+ { 0x12, 0x00 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x0F }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB565 QQCIF */
+const static struct ov9640_reg qqcif_565[] = {
+ { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB565 QQVGA */
+const static struct ov9640_reg qqvga_565[] = {
+ { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB565 QCIF */
+const static struct ov9640_reg qcif_565[] = {
+ { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB565 QVGA */
+const static struct ov9640_reg qvga_565[] = {
+ { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB565 CIF */
+const static struct ov9640_reg cif_565[] = {
+ { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB565 VGA */
+const static struct ov9640_reg vga_565[] = {
+ { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB565 SXGA */
+const static struct ov9640_reg sxga_565[] = {
+ { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB555 QQCIF */
+const static struct ov9640_reg qqcif_555[] = {
+ { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB555 QQVGA */
+const static struct ov9640_reg qqvga_555[] = {
+ { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB555 QCIF */
+const static struct ov9640_reg qcif_555[] = {
+ { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB555 QVGA */
+const static struct ov9640_reg qvga_555[] = {
+ { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB555 CIF */
+const static struct ov9640_reg cif_555[] = {
+ { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB555 VGA */
+const static struct ov9640_reg vga_555[] = {
+ { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+ /* RGB555 SXGA */
+const static struct ov9640_reg sxga_555[] = {
+ { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+ { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+ { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+ { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+ { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+ { 0x58, 0x65 }, /* MTXS */
+ { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+
+#define DEF_GAIN 31
+#define DEF_AUTOGAIN 1
+#define DEF_EXPOSURE 154
+#define DEF_AEC 1
+#define DEF_FREEZE_AGCAEC 0
+#define DEF_BLUE 153
+#define DEF_RED (255 - DEF_BLUE)
+#define DEF_AWB 1
+#define DEF_HFLIP 0
+#define DEF_VFLIP 0
+
+/* Our own specific controls */
+#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_AUTOEXPOSURE V4L2_CID_PRIVATE_BASE + 1
+#define V4L2_CID_LAST_PRIV V4L2_CID_AUTOEXPOSURE
+
+/* Video controls */
+static struct vcontrol {
+ struct v4l2_queryctrl qc;
+ int current_value;
+ u8 reg;
+ u8 mask;
+ u8 start_bit;
+} video_control[] = {
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = DEF_GAIN,
+ },
+ .current_value = 0,
+ .reg = OV9640_GAIN,
+ .mask = 0x3f,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_AUTOGAIN,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM8,
+ .mask = 0x04,
+ .start_bit = 2,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEF_EXPOSURE,
+ },
+ .current_value = 0,
+ .reg = OV9640_AECH,
+ .mask = 0xff,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOEXPOSURE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_AEC,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM8,
+ .mask = 0x01,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_FREEZE_AGCAEC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Freeze AGC/AEC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_FREEZE_AGCAEC,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM9,
+ .mask = 0x01,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEF_RED,
+ },
+ .current_value = 0,
+ .reg = OV9640_RED,
+ .mask = 0xff,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEF_BLUE,
+ },
+ .current_value = 0,
+ .reg = OV9640_BLUE,
+ .mask = 0xff,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_AWB,
+ },
+ .current_value = 0,
+ .reg = OV9640_COM8,
+ .mask = 0x02,
+ .start_bit = 1,
+ },
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_HFLIP,
+ },
+ .current_value = 0,
+ .reg = OV9640_MVFP,
+ .mask = 0x20,
+ .start_bit = 5,
+ },
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ .default_value = DEF_VFLIP,
+ },
+ .current_value = 0,
+ .reg = OV9640_MVFP,
+ .mask = 0x10,
+ .start_bit = 4,
+ },
+};
+
+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 },
+};
+
+
+/*
+ * Read a value from a register in an OV9640 sensor device.
+ * The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+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;
+}
+
+static int
+ov9640_write_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+ u8 oldval, newval;
+ int rc;
+
+ if (mask == 0xff)
+ newval = *val;
+ else {
+ /* need to do read - modify - write */
+ rc = ov9640_read_reg(client, reg, &oldval);
+ if (rc)
+ return rc;
+ oldval &= (~mask); /* Clear the masked bits */
+ *val &= mask; /* Enforce mask on value */
+ newval = oldval | *val; /* Set the desired bits */
+ }
+
+ /* write the new value to the register */
+ rc = ov9640_write_reg(client, reg, newval);
+ if (rc)
+ return rc;
+
+ rc = ov9640_read_reg(client, reg, &newval);
+ if (rc)
+ return rc;
+
+ *val = newval & mask;
+ return 0;
+}
+
+static int
+ov9640_read_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+ int rc;
+
+ rc = ov9640_read_reg(client, reg, val);
+ if (rc)
+ return rc;
+ (*val) &= mask;
+
+ return 0;
+}
+
+/*
+ * 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;
+}
+
+/* Returns the index of the requested ID from the control structure array */
+static int
+find_vctrl(int id)
+{
+ int i;
+
+ if (id < V4L2_CID_BASE)
+ return -EDOM;
+
+ for (i = (ARRAY_SIZE(video_control) - 1); i >= 0; i--)
+ if (video_control[i].qc.id == id)
+ break;
+ if (i < 0)
+ i = -EINVAL;
+ return i;
+}
+
+/* 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 char
+ov9640_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;
+ /* FIXME
+ * clks_per_frame should come from platform data
+ */
+#ifdef CONFIG_ARCH_OMAP24XX
+ const static unsigned long clks_per_frame[] =
+ { 200000, 400000, 200000, 400000, 400000, 800000, 3200000 };
+ /* QQCIF QQVGA QCIF QVGA CIF VGA SXGA
+ * 199680,400000, 199680, 400000, 399360, 800000, 3200000
+ */
+#else
+ const static unsigned long clks_per_frame[] =
+ { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
+#endif
+
+ 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));
+}
+
+/*
+ * 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_size
+ov9640_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;
+}
+
+/*
+ * The nominal xclk input frequency of the OV9640 is 24MHz, maximum
+ * frequency is 48MHz, and minimum frequency is 10MHz.
+ */
+#define XCLK_MIN 10000000
+#define XCLK_MAX 48000000
+#define XCLK_NOM 24000000
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency
+ */
+static unsigned long
+ov9640sensor_calc_xclk(struct i2c_client *c)
+{
+ struct ov9640_sensor *sensor = i2c_get_clientdata(c);
+ struct v4l2_fract *timeperframe = &sensor->timeperframe;
+ struct v4l2_pix_format *pix = &sensor->pix;
+
+ 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 = XCLK_NOM;
+ isize = ov9640_find_size(pix->width, pix->height);
+ switch (isize) {
+ case SXGA:
+ if (tgt_fpm > 450)
+ tgt_xclk = XCLK_MAX;
+ break;
+ case VGA:
+ if (tgt_fpm > 900)
+ tgt_xclk = XCLK_MAX;
+ break;
+ default:
+ break;
+ }
+ return tgt_xclk;
+}
+
+/*
+ * 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 int ov9640_configure(struct v4l2_int_device *s)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &sensor->pix;
+ struct v4l2_fract *fper = &sensor->timeperframe;
+ struct i2c_client *client = sensor->i2c_client;
+ enum image_size isize;
+ unsigned long xclk;
+
+ int err;
+ unsigned char clkrc;
+ 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;
+ }
+
+ xclk = ov9640sensor_calc_xclk(client);
+
+ isize = ov9640_find_size(pix->width, pix->height);
+
+ /* common register initialization */
+ err = ov9640_write_regs(client, sensor->pdata->default_regs);
+ 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;
+}
+
+/*
+ * 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 int
+ov9640_detect(struct i2c_client *client)
+{
+ u8 midh, midl, pid, ver;
+
+ if (!client)
+ return -ENODEV;
+
+ 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;
+
+ return ver;
+}
+
+static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ unsigned long tgt_xclk;
+
+ tgt_xclk = ov9640sensor_calc_xclk(client);
+
+ *xclk = tgt_xclk;
+
+ return 0;
+}
+
+static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk)
+{
+ if (xclk > XCLK_MAX || xclk < XCLK_MIN)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*
+ * following are sensor interface functions implemented by
+ * OV9640 sensor driver.
+ */
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ i = find_vctrl(qc->id);
+ if (i == -EINVAL) {
+ qc->flags = V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+ }
+ if (i < 0)
+ return -EINVAL;
+
+ *qc = video_control[i].qc;
+ return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ int i, val;
+ struct vcontrol *lvc;
+
+ i = find_vctrl(vc->id);
+ if (i < 0)
+ return -EINVAL;
+
+ lvc = &video_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 int ioctl_s_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ struct vcontrol *lvc;
+ int val = vc->value;
+ int i;
+
+ i = find_vctrl(vc->id);
+ if (i < 0)
+ return -EINVAL;
+
+ lvc = &video_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 int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ 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;
+ 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 int ioctl_try_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ enum image_size isize;
+ int ifmt;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ 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;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int rval;
+
+ rval = ioctl_try_fmt_cap(s, f);
+ if (rval)
+ return rval;
+
+ rval = ov9640_configure(s);
+
+ if (!rval)
+ sensor->pix = *pix;
+
+ return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct ov9640_sensor *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe = sensor->timeperframe;
+
+ return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ struct v4l2_fract timeperframe_old;
+ int rval;
+
+ timeperframe_old = sensor->timeperframe;
+ sensor->timeperframe = *timeperframe;
+
+ rval = ov9640_configure(s);
+
+ if (rval)
+ sensor->timeperframe = timeperframe_old;
+ else
+ *timeperframe = sensor->timeperframe;
+
+ return rval;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct ov9640_sensor *sensor = s->priv;
+
+ return sensor->pdata->power_set(on);
+}
+
+/* FIXME - g_needs_reset will be removed once camera driver
+ * implments fix for it e.g -ENOIOCTLCMD.
+ */
+static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
+{
+ return 0;
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ return ov9640_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct ov9640_sensor *sensor = s->priv;
+ struct i2c_client *c = sensor->i2c_client;
+ int err;
+
+ err = ov9640_detect(c);
+ if (err < 0) {
+ dev_err(&c->dev, "Unable to detect " DRIVER_NAME " sensor\n");
+ return err;
+ }
+
+ sensor->ver = err;
+ pr_info(DRIVER_NAME " chip version 0x%02x detected\n", sensor->ver);
+
+ return 0;
+}
+
+#define NUM_IOCTLS 16
+
+static struct v4l2_int_ioctl_desc ov9640_ioctl_desc[NUM_IOCTLS] = {
+ { vidioc_int_dev_init_num,
+ (v4l2_int_ioctl_func *)&ioctl_dev_init },
+ { vidioc_int_dev_exit_num,
+ (v4l2_int_ioctl_func *)&ioctl_dev_exit },
+ { vidioc_int_s_power_num,
+ (v4l2_int_ioctl_func *)&ioctl_s_power },
+ { vidioc_int_g_ext_clk_num,
+ (v4l2_int_ioctl_func *)&ioctl_g_ext_clk },
+ { vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)&ioctl_g_needs_reset },
+ { vidioc_int_s_ext_clk_num,
+ (v4l2_int_ioctl_func *)&ioctl_s_ext_clk },
+ { vidioc_int_init_num,
+ (v4l2_int_ioctl_func *)&ioctl_init },
+ { vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap },
+ { vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap },
+ { vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap },
+ { vidioc_int_s_fmt_cap_num,
+ (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap },
+ { vidioc_int_g_parm_num,
+ (v4l2_int_ioctl_func *)&ioctl_g_parm },
+ { vidioc_int_s_parm_num,
+ (v4l2_int_ioctl_func *)&ioctl_s_parm },
+ { vidioc_int_queryctrl_num,
+ (v4l2_int_ioctl_func *)&ioctl_queryctrl },
+ { vidioc_int_g_ctrl_num,
+ (v4l2_int_ioctl_func *)&ioctl_g_ctrl },
+ { vidioc_int_s_ctrl_num,
+ (v4l2_int_ioctl_func *)&ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave ov9640_slave = {
+ .ioctls = ov9640_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(ov9640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov9640_int_device = {
+ .module = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .priv = &ov9640,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &ov9640_slave,
+ },
+};
+
+static int __init
+ov9640_probe(struct i2c_client *client)
+{
+ struct ov9640_sensor *sensor = &ov9640;
+ int err;
+
+ if (i2c_get_clientdata(client))
+ return -EBUSY;
+
+ sensor->pdata = client->dev.platform_data;
+
+ if (!sensor->pdata || !sensor->pdata->default_regs) {
+ dev_err(&client->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ sensor->v4l2_int_device = &ov9640_int_device;
+ sensor->i2c_client = client;
+
+ i2c_set_clientdata(client, sensor);
+
+ /* Make the default capture format QCIF RGB565 */
+ sensor->pix.width = ov9640_sizes[QCIF].width;
+ sensor->pix.height = ov9640_sizes[QCIF].height;
+ sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+ err = v4l2_int_device_register(sensor->v4l2_int_device);
+ if (err)
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static int __exit
+ov9640_remove(struct i2c_client *client)
+{
+ struct ov9640_sensor *sensor = i2c_get_clientdata(client);
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ v4l2_int_device_unregister(sensor->v4l2_int_device);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static struct i2c_driver ov9640sensor_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = ov9640_probe,
+ .remove = __exit_p(ov9640_remove),
+};
+
+static struct ov9640_sensor ov9640 = {
+ .timeperframe = {
+ .numerator = 1,
+ .denominator = 15,
+ },
+};
+
+static int ov9640sensor_init(void)
+{
+ int err;
+ int i = 0;
+
+ /* Just an experiment --- don't use *_cb functions yet. */
+ ov9640_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init);
+ BUG_ON(i >= NUM_IOCTLS);
+
+ err = i2c_add_driver(&ov9640sensor_i2c_driver);
+ if (err) {
+ printk(KERN_ERR "Failed to register" DRIVER_NAME ".\n");
+ return err;
+ }
+ return 0;
+}
+module_init(ov9640sensor_init);
+
+static void __exit ov9640sensor_cleanup(void)
+{
+ i2c_del_driver(&ov9640sensor_i2c_driver);
+}
+module_exit(ov9640sensor_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OV9640 camera sensor driver");
diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h
new file mode 100644
index 0000000..b6858b4
--- /dev/null
+++ b/drivers/media/video/ov9640.h
@@ -0,0 +1,185 @@
+/*
+ * drivers/media/video/ov9640.h
+ *
+ * Register definitions for the OmniVision OV9640 CameraChip.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef OV9640_H
+#define OV9640_H
+
+#define OV9640_I2C_ADDR 0x30
+
+/* define register offsets for the OV9640 sensor chip */
+#define OV9640_GAIN 0x00
+#define OV9640_BLUE 0x01
+#define OV9640_RED 0x02
+#define OV9640_VREF 0x03
+#define OV9640_COM1 0x04
+#define OV9640_BAVE 0x05
+#define OV9640_GEAVE 0x06
+#define OV9640_RAVE 0x08
+#define OV9640_COM2 0x09
+#define OV9640_PID 0x0A
+#define OV9640_VER 0x0B
+#define OV9640_COM3 0x0C
+#define OV9640_COM4 0x0D
+#define OV9640_COM5 0x0E
+#define OV9640_COM6 0x0F
+#define OV9640_AECH 0x10
+#define OV9640_CLKRC 0x11
+#define OV9640_COM7 0x12
+#define OV9640_COM8 0x13
+#define OV9640_COM9 0x14
+#define OV9640_COM10 0x15
+#define OV9640_HSTRT 0x17
+#define OV9640_HSTOP 0x18
+#define OV9640_VSTRT 0x19
+#define OV9640_VSTOP 0x1A
+#define OV9640_PSHFT 0x1B
+#define OV9640_MIDH 0x1C
+#define OV9640_MIDL 0x1D
+#define OV9640_MVFP 0x1E
+#define OV9640_LAEC 0x1F
+#define OV9640_BOS 0x20
+#define OV9640_GBOS 0x21
+#define OV9640_GROS 0x22
+#define OV9640_ROS 0x23
+#define OV9640_AEW 0x24
+#define OV9640_AEB 0x25
+#define OV9640_VPT 0x26
+#define OV9640_BBIAS 0x27
+#define OV9640_GBBIAS 0x28
+#define OV9640_EXHCH 0x2A
+#define OV9640_EXHCL 0x2B
+#define OV9640_RBIAS 0x2C
+#define OV9640_ADVFL 0x2D
+#define OV9640_ADVFH 0x2E
+#define OV9640_YAVE 0x2F
+#define OV9640_HSYST 0x30
+#define OV9640_HSYEN 0x31
+#define OV9640_HREF 0x32
+#define OV9640_CHLF 0x33
+#define OV9640_ARBLM 0x34
+#define OV9640_ADC 0x37
+#define OV9640_ACOM 0x38
+#define OV9640_OFON 0x39
+#define OV9640_TSLB 0x3A
+#define OV9640_COM11 0x3B
+#define OV9640_COM12 0x3C
+#define OV9640_COM13 0x3D
+#define OV9640_COM14 0x3E
+#define OV9640_EDGE 0x3F
+#define OV9640_COM15 0x40
+#define OV9640_COM16 0x41
+#define OV9640_COM17 0x42
+#define OV9640_MTX1 0x4F
+#define OV9640_MTX2 0x50
+#define OV9640_MTX3 0x51
+#define OV9640_MTX4 0x52
+#define OV9640_MTX5 0x53
+#define OV9640_MTX6 0x54
+#define OV9640_MTX7 0x55
+#define OV9640_MTX8 0x56
+#define OV9640_MTX9 0x57
+#define OV9640_MTXS 0x58
+#define OV9640_LCC1 0x62
+#define OV9640_LCC2 0x63
+#define OV9640_LCC3 0x64
+#define OV9640_LCC4 0x65
+#define OV9640_LCC5 0x66
+#define OV9640_MANU 0x67
+#define OV9640_MANV 0x68
+#define OV9640_HV 0x69
+#define OV9640_MBD 0x6A
+#define OV9640_DBLV 0x6B
+#define OV9640_GSP1 0x6C
+#define OV9640_GSP2 0x6D
+#define OV9640_GSP3 0x6E
+#define OV9640_GSP4 0x6F
+#define OV9640_GSP5 0x70
+#define OV9640_GSP6 0x71
+#define OV9640_GSP7 0x72
+#define OV9640_GSP8 0x73
+#define OV9640_GSP9 0x74
+#define OV9640_GSP10 0x75
+#define OV9640_GSP11 0x76
+#define OV9640_GSP12 0x77
+#define OV9640_GSP13 0x78
+#define OV9640_GSP14 0x79
+#define OV9640_GSP15 0x7A
+#define OV9640_GSP16 0x7B
+#define OV9640_GST1 0x7C
+#define OV9640_GST2 0x7D
+#define OV9640_GST3 0x7E
+#define OV9640_GST4 0x7F
+#define OV9640_GST5 0x80
+#define OV9640_GST6 0x81
+#define OV9640_GST7 0x82
+#define OV9640_GST8 0x83
+#define OV9640_GST9 0x84
+#define OV9640_GST10 0x85
+#define OV9640_GST11 0x86
+#define OV9640_GST12 0x87
+#define OV9640_GST13 0x88
+#define OV9640_GST14 0x89
+#define OV9640_GST15 0x8A
+
+#define OV9640_NUM_REGS (OV9640_GST15 + 1)
+
+#define OV9640_PID_MAGIC 0x96 /* high byte of product ID number */
+#define OV9640_VER_REV2 0x48 /* low byte of product ID number */
+#define OV9640_VER_REV3 0x49 /* low byte of product ID number */
+#define OV9640_MIDH_MAGIC 0x7F /* high byte of mfg ID */
+#define OV9640_MIDL_MAGIC 0xA2 /* low byte of mfg ID */
+
+#define OV9640_REG_TERM 0xFF /* terminating list entry for reg */
+#define OV9640_VAL_TERM 0xFF /* terminating list entry for val */
+
+/* define a structure for ov9640 register initialization values */
+struct ov9640_reg {
+ unsigned char reg;
+ unsigned char val;
+};
+
+enum image_size { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+enum pixel_format { YUV, RGB565, RGB555 };
+
+#define NUM_IMAGE_SIZES 7
+#define NUM_PIXEL_FORMATS 3
+
+struct capture_size {
+ unsigned long width;
+ unsigned long height;
+};
+
+struct ov9640_platform_data {
+ /* Set power state, zero is off, non-zero is on. */
+ int (*power_set)(int power);
+ /* Default registers written after power-on or reset. */
+ const struct ov9640_reg *default_regs;
+};
+
+/*
+ * Array of image sizes supported by OV9640. These must be ordered from
+ * smallest image size to largest.
+ */
+const static struct capture_size ov9640_sizes[] = {
+ { 88, 72 }, /* QQCIF */
+ { 160, 120 }, /* QQVGA */
+ { 176, 144 }, /* QCIF */
+ { 320, 240 }, /* QVGA */
+ { 352, 288 }, /* CIF */
+ { 640, 480 }, /* VGA */
+ { 1280, 960 }, /* SXGA */
+};
+
+#endif /* ifndef OV9640_H */
--
1.5.0
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface
2007-08-18 8:36 [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface Trilok Soni
@ 2007-08-20 9:07 ` Sakari Ailus
2007-08-20 10:21 ` Trilok Soni
0 siblings, 1 reply; 11+ messages in thread
From: Sakari Ailus @ 2007-08-20 9:07 UTC (permalink / raw)
To: ext Trilok Soni; +Cc: Linux OMAP
ext Trilok Soni wrote:
> Hi All,
Hi, Trilok!
> I have attached two patches which converts the ov9640 driver to use
> the new v4l2 sensor interface. Sensor detection is working with H4 but
> the output is not anywhere near to correct, so someone with H4 please
> check and give inputs.
>
> Patches are implemented and tested against mainline kernel and OMAP2
> camera driver posted by Sakari to v4l mailing list [1].
> +#define NUM_IOCTLS 16
...
> + /* Just an experiment --- don't use *_cb functions yet. */
> + ov9640_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init);
> + BUG_ON(i >= NUM_IOCTLS);
These are leftovers from the check-slave-interface-types experiment
which probably should be removed. This applies to TCM825x as well.
--
Sakari Ailus
sakari.ailus@nokia.com
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface
2007-08-20 9:07 ` Sakari Ailus
@ 2007-08-20 10:21 ` Trilok Soni
2007-08-23 12:29 ` Trilok Soni
0 siblings, 1 reply; 11+ messages in thread
From: Trilok Soni @ 2007-08-20 10:21 UTC (permalink / raw)
To: Sakari Ailus; +Cc: Linux OMAP
Hi Sakari,
On 8/20/07, Sakari Ailus <sakari.ailus@nokia.com> wrote:
> ext Trilok Soni wrote:
> > Hi All,
>
> Hi, Trilok!
>
> > I have attached two patches which converts the ov9640 driver to use
> > the new v4l2 sensor interface. Sensor detection is working with H4 but
> > the output is not anywhere near to correct, so someone with H4 please
> > check and give inputs.
> >
> > Patches are implemented and tested against mainline kernel and OMAP2
> > camera driver posted by Sakari to v4l mailing list [1].
>
> > +#define NUM_IOCTLS 16
> ...
> > + /* Just an experiment --- don't use *_cb functions yet. */
> > + ov9640_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init);
> > + BUG_ON(i >= NUM_IOCTLS);
>
> These are leftovers from the check-slave-interface-types experiment
> which probably should be removed. This applies to TCM825x as well.
>
I will remove that and update the patch once camera output is correct.
--
--Trilok Soni
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface
2007-08-20 10:21 ` Trilok Soni
@ 2007-08-23 12:29 ` Trilok Soni
2007-08-27 18:39 ` OSK5912 Boot from CF? Hingkwan Huen
2007-08-31 20:27 ` [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface Tony Lindgren
0 siblings, 2 replies; 11+ messages in thread
From: Trilok Soni @ 2007-08-23 12:29 UTC (permalink / raw)
To: Sakari Ailus; +Cc: Linux OMAP
[-- Attachment #1: Type: text/plain, Size: 1459 bytes --]
Hi,
--- Trilok Soni <soni.trilok@gmail.com> wrote:
> Hi Sakari,
>
> On 8/20/07, Sakari Ailus <sakari.ailus@nokia.com>
> wrote:
> > ext Trilok Soni wrote:
> > > Hi All,
> >
> > Hi, Trilok!
> >
> > > I have attached two patches which converts the
> ov9640 driver to use
> > > the new v4l2 sensor interface. Sensor detection
> is working with H4 but
> > > the output is not anywhere near to correct, so
> someone with H4 please
> > > check and give inputs.
> > >
> > > Patches are implemented and tested against
> mainline kernel and OMAP2
> > > camera driver posted by Sakari to v4l mailing
> list [1].
> >
> > > +#define NUM_IOCTLS 16
> > ...
> > > + /* Just an experiment --- don't use *_cb
> functions yet. */
> > > + ov9640_ioctl_desc[i++] =
> vidioc_int_dev_init_cb(&ioctl_dev_init);
> > > + BUG_ON(i >= NUM_IOCTLS);
> >
> > These are leftovers from the
> check-slave-interface-types experiment
> > which probably should be removed. This applies to
> TCM825x as well.
> >
>
> I will remove that and update the patch once camera
> output is correct.
>
I have attached the updated ov9640 patch with
v4l2_ifparm addition and some cosmetic changes, sensor
still not working except detection.
---Trilok Soni
____________________________________________________________________________________
Take the Internet to Go: Yahoo!Go puts the Internet in your pocket: mail, news, photos & more.
http://mobile.yahoo.com/go?refer=1GNXIC
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 3395908420-0001-ov9640-Update-sensor-driver-with-v4l2_ifparm.patch --]
[-- Type: text/x-patch; name="0001-ov9640-Update-sensor-driver-with-v4l2_ifparm.patch", Size: 4483 bytes --]
>From 9cceb274ab423ce74db6c8c97062dc31d56cfefb Mon Sep 17 00:00:00 2001
From: Trilok Soni <soni.trilok@gmail.com>
Date: Wed, 22 Aug 2007 17:04:40 +0530
Subject: [PATCH] ov9640: Update sensor driver with v4l2_ifparm.
- Update driver with new v4l2_ifparm structure.
- Remove un-necessary '&' and some test code.
Signed-off-by: Trilok Soni <soni.trilok@gmail.com>
---
drivers/media/video/ov9640.c | 56 ++++++++++++++++++------------------------
drivers/media/video/ov9640.h | 1 +
2 files changed, 25 insertions(+), 32 deletions(-)
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 9a7b039..8caa240 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -1128,19 +1128,18 @@ static int ioctl_s_parm(struct v4l2_int_device *s,
return rval;
}
-static int ioctl_s_power(struct v4l2_int_device *s, int on)
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
{
struct ov9640_sensor *sensor = s->priv;
- return sensor->pdata->power_set(on);
+ return sensor->pdata->ifparm(p);
}
-/* FIXME - g_needs_reset will be removed once camera driver
- * implments fix for it e.g -ENOIOCTLCMD.
- */
-static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
{
- return 0;
+ struct ov9640_sensor *sensor = s->priv;
+
+ return sensor->pdata->power_set(on);
}
static int ioctl_init(struct v4l2_int_device *s)
@@ -1171,41 +1170,39 @@ static int ioctl_dev_init(struct v4l2_int_device *s)
return 0;
}
-#define NUM_IOCTLS 16
-
-static struct v4l2_int_ioctl_desc ov9640_ioctl_desc[NUM_IOCTLS] = {
+static struct v4l2_int_ioctl_desc ov9640_ioctl_desc[] = {
{ vidioc_int_dev_init_num,
- (v4l2_int_ioctl_func *)&ioctl_dev_init },
+ (v4l2_int_ioctl_func *)ioctl_dev_init },
{ vidioc_int_dev_exit_num,
- (v4l2_int_ioctl_func *)&ioctl_dev_exit },
+ (v4l2_int_ioctl_func *)ioctl_dev_exit },
{ vidioc_int_s_power_num,
- (v4l2_int_ioctl_func *)&ioctl_s_power },
+ (v4l2_int_ioctl_func *)ioctl_s_power },
{ vidioc_int_g_ext_clk_num,
- (v4l2_int_ioctl_func *)&ioctl_g_ext_clk },
- { vidioc_int_g_needs_reset_num,
- (v4l2_int_ioctl_func *)&ioctl_g_needs_reset },
+ (v4l2_int_ioctl_func *)ioctl_g_ext_clk },
+ { vidioc_int_g_ifparm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ifparm },
{ vidioc_int_s_ext_clk_num,
- (v4l2_int_ioctl_func *)&ioctl_s_ext_clk },
+ (v4l2_int_ioctl_func *)ioctl_s_ext_clk },
{ vidioc_int_init_num,
- (v4l2_int_ioctl_func *)&ioctl_init },
+ (v4l2_int_ioctl_func *)ioctl_init },
{ vidioc_int_enum_fmt_cap_num,
- (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap },
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
{ vidioc_int_try_fmt_cap_num,
- (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap },
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
{ vidioc_int_g_fmt_cap_num,
- (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap },
+ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
{ vidioc_int_s_fmt_cap_num,
- (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap },
+ (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
{ vidioc_int_g_parm_num,
- (v4l2_int_ioctl_func *)&ioctl_g_parm },
+ (v4l2_int_ioctl_func *)ioctl_g_parm },
{ vidioc_int_s_parm_num,
- (v4l2_int_ioctl_func *)&ioctl_s_parm },
+ (v4l2_int_ioctl_func *)ioctl_s_parm },
{ vidioc_int_queryctrl_num,
- (v4l2_int_ioctl_func *)&ioctl_queryctrl },
+ (v4l2_int_ioctl_func *)ioctl_queryctrl },
{ vidioc_int_g_ctrl_num,
- (v4l2_int_ioctl_func *)&ioctl_g_ctrl },
+ (v4l2_int_ioctl_func *)ioctl_g_ctrl },
{ vidioc_int_s_ctrl_num,
- (v4l2_int_ioctl_func *)&ioctl_s_ctrl },
+ (v4l2_int_ioctl_func *)ioctl_s_ctrl },
};
static struct v4l2_int_slave ov9640_slave = {
@@ -1288,11 +1285,6 @@ static struct ov9640_sensor ov9640 = {
static int ov9640sensor_init(void)
{
int err;
- int i = 0;
-
- /* Just an experiment --- don't use *_cb functions yet. */
- ov9640_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init);
- BUG_ON(i >= NUM_IOCTLS);
err = i2c_add_driver(&ov9640sensor_i2c_driver);
if (err) {
diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h
index b6858b4..6de3fef 100644
--- a/drivers/media/video/ov9640.h
+++ b/drivers/media/video/ov9640.h
@@ -166,6 +166,7 @@ struct ov9640_platform_data {
int (*power_set)(int power);
/* Default registers written after power-on or reset. */
const struct ov9640_reg *default_regs;
+ int (*ifparm)(struct v4l2_ifparm *p);
};
/*
--
1.5.0
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply related [flat|nested] 11+ messages in thread* OSK5912 Boot from CF?
2007-08-23 12:29 ` Trilok Soni
@ 2007-08-27 18:39 ` Hingkwan Huen
2007-08-27 19:04 ` Dirk Behme
2007-08-31 20:27 ` [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface Tony Lindgren
1 sibling, 1 reply; 11+ messages in thread
From: Hingkwan Huen @ 2007-08-27 18:39 UTC (permalink / raw)
To: Linux OMAP
Dear All,
Can OSK5912 boot from CF? What is the right procedure to that?
Thanks,
kwan
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: OSK5912 Boot from CF?
2007-08-27 18:39 ` OSK5912 Boot from CF? Hingkwan Huen
@ 2007-08-27 19:04 ` Dirk Behme
2007-08-27 19:12 ` Hingkwan Huen
0 siblings, 1 reply; 11+ messages in thread
From: Dirk Behme @ 2007-08-27 19:04 UTC (permalink / raw)
To: hkh; +Cc: Linux OMAP
Hingkwan Huen wrote:
> Dear All,
> Can OSK5912 boot from CF?
No, I don't think so. Some time ago booting was described in "OMAP5912
Multimedia Processor Initialization Reference Guide (spru752)", but
looks like this changed. Check [1] if you can find anything there
about booting.
Regards
Dirk
[1]
http://focus.ti.com/docs/prod/folders/print/omap5912.html#technicaldocuments
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: OSK5912 Boot from CF?
2007-08-27 19:04 ` Dirk Behme
@ 2007-08-27 19:12 ` Hingkwan Huen
2007-08-27 19:22 ` Dirk Behme
2007-08-27 19:37 ` David Brownell
0 siblings, 2 replies; 11+ messages in thread
From: Hingkwan Huen @ 2007-08-27 19:12 UTC (permalink / raw)
To: Dirk Behme; +Cc: Linux OMAP
Thanks for the comment Dirk!
How about having the root file system on the CF, and kernel on the NOR
flash?
Regards,
kwan
On Mon, 2007-08-27 at 21:04 +0200, Dirk Behme wrote:
> Hingkwan Huen wrote:
> > Dear All,
> > Can OSK5912 boot from CF?
>
> No, I don't think so. Some time ago booting was described in "OMAP5912
> Multimedia Processor Initialization Reference Guide (spru752)", but
> looks like this changed. Check [1] if you can find anything there
> about booting.
>
> Regards
>
> Dirk
>
> [1]
> http://focus.ti.com/docs/prod/folders/print/omap5912.html#technicaldocuments
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: OSK5912 Boot from CF?
2007-08-27 19:12 ` Hingkwan Huen
@ 2007-08-27 19:22 ` Dirk Behme
2007-08-27 19:37 ` David Brownell
1 sibling, 0 replies; 11+ messages in thread
From: Dirk Behme @ 2007-08-27 19:22 UTC (permalink / raw)
To: hkh; +Cc: Linux OMAP
Hingkwan Huen wrote:
> Thanks for the comment Dirk!
> How about having the root file system on the CF, and kernel on the NOR
> flash?
This should work. If you have a bootloader (e.g. uboot) with CF &
filesystem support in NOR, you should even be able to put the kernel
on CF as well.
> Regards,
> kwan
>
> On Mon, 2007-08-27 at 21:04 +0200, Dirk Behme wrote:
>
>>Hingkwan Huen wrote:
>>
>>>Dear All,
>>>Can OSK5912 boot from CF?
>>
>>No, I don't think so. Some time ago booting was described in "OMAP5912
>>Multimedia Processor Initialization Reference Guide (spru752)", but
>>looks like this changed. Check [1] if you can find anything there
>>about booting.
>>
>>Regards
>>
>>Dirk
>>
>>[1]
>>http://focus.ti.com/docs/prod/folders/print/omap5912.html#technicaldocuments
>>
>>
>
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: OSK5912 Boot from CF?
2007-08-27 19:12 ` Hingkwan Huen
2007-08-27 19:22 ` Dirk Behme
@ 2007-08-27 19:37 ` David Brownell
1 sibling, 0 replies; 11+ messages in thread
From: David Brownell @ 2007-08-27 19:37 UTC (permalink / raw)
To: hkh, dirk.behme; +Cc: linux-omap-open-source
> How about having the root file system on the CF, and kernel on the NOR
> flash?
That should be easy.
You could even modify U-Boot to understand about that CF controller...
The OMAP would still boot the usual way (from NOR), but current versions
of U-Boot can be told to get the kernel from more places than just NOR
and NET. That assumes you're willing to hack U-Boot and install/debug
new versions; that's probably not a good new-developer project.
- Dave
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface
2007-08-23 12:29 ` Trilok Soni
2007-08-27 18:39 ` OSK5912 Boot from CF? Hingkwan Huen
@ 2007-08-31 20:27 ` Tony Lindgren
2007-09-02 9:59 ` Trilok Soni
1 sibling, 1 reply; 11+ messages in thread
From: Tony Lindgren @ 2007-08-31 20:27 UTC (permalink / raw)
To: Trilok Soni; +Cc: Sakari Ailus, Linux OMAP
* Trilok Soni <trilok_soni@yahoo.co.in> [070823 05:29]:
> Hi,
>
> --- Trilok Soni <soni.trilok@gmail.com> wrote:
>
> > Hi Sakari,
> >
> > On 8/20/07, Sakari Ailus <sakari.ailus@nokia.com>
> > wrote:
> > > ext Trilok Soni wrote:
> > > > Hi All,
> > >
> > > Hi, Trilok!
> > >
> > > > I have attached two patches which converts the
> > ov9640 driver to use
> > > > the new v4l2 sensor interface. Sensor detection
> > is working with H4 but
> > > > the output is not anywhere near to correct, so
> > someone with H4 please
> > > > check and give inputs.
> > > >
> > > > Patches are implemented and tested against
> > mainline kernel and OMAP2
> > > > camera driver posted by Sakari to v4l mailing
> > list [1].
> > >
> > > > +#define NUM_IOCTLS 16
> > > ...
> > > > + /* Just an experiment --- don't use *_cb
> > functions yet. */
> > > > + ov9640_ioctl_desc[i++] =
> > vidioc_int_dev_init_cb(&ioctl_dev_init);
> > > > + BUG_ON(i >= NUM_IOCTLS);
> > >
> > > These are leftovers from the
> > check-slave-interface-types experiment
> > > which probably should be removed. This applies to
> > TCM825x as well.
> > >
> >
> > I will remove that and update the patch once camera
> > output is correct.
> >
>
> I have attached the updated ov9640 patch with
> v4l2_ifparm addition and some cosmetic changes, sensor
> still not working except detection.
Trilok, can you please refresh this patch?
Tony
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface
2007-08-31 20:27 ` [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface Tony Lindgren
@ 2007-09-02 9:59 ` Trilok Soni
0 siblings, 0 replies; 11+ messages in thread
From: Trilok Soni @ 2007-09-02 9:59 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Sakari Ailus, Linux OMAP
Hi Tony,
On 9/1/07, Tony Lindgren <tony@atomide.com> wrote:
> * Trilok Soni <trilok_soni@yahoo.co.in> [070823 05:29]:
> > Hi,
> >
> > --- Trilok Soni <soni.trilok@gmail.com> wrote:
> >
> > > Hi Sakari,
> > >
> > > On 8/20/07, Sakari Ailus <sakari.ailus@nokia.com>
> > > wrote:
> > > > ext Trilok Soni wrote:
> > > > > Hi All,
> > > >
> > > > Hi, Trilok!
> > > >
> > > > > I have attached two patches which converts the
> > > ov9640 driver to use
> > > > > the new v4l2 sensor interface. Sensor detection
> > > is working with H4 but
> > > > > the output is not anywhere near to correct, so
> > > someone with H4 please
> > > > > check and give inputs.
> > > > >
> > > > > Patches are implemented and tested against
> > > mainline kernel and OMAP2
> > > > > camera driver posted by Sakari to v4l mailing
> > > list [1].
> > > >
> > > > > +#define NUM_IOCTLS 16
> > > > ...
> > > > > + /* Just an experiment --- don't use *_cb
> > > functions yet. */
> > > > > + ov9640_ioctl_desc[i++] =
> > > vidioc_int_dev_init_cb(&ioctl_dev_init);
> > > > > + BUG_ON(i >= NUM_IOCTLS);
> > > >
> > > > These are leftovers from the
> > > check-slave-interface-types experiment
> > > > which probably should be removed. This applies to
> > > TCM825x as well.
> > > >
> > >
> > > I will remove that and update the patch once camera
> > > output is correct.
> > >
> >
> > I have attached the updated ov9640 patch with
> > v4l2_ifparm addition and some cosmetic changes, sensor
> > still not working except detection.
>
> Trilok, can you please refresh this patch?
>
I will do this. But please note that new ov9640.[ch] is now outside
"omap" directory as compared to linux-omap git tree.
--
--Trilok Soni
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2007-09-02 9:59 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-18 8:36 [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface Trilok Soni
2007-08-20 9:07 ` Sakari Ailus
2007-08-20 10:21 ` Trilok Soni
2007-08-23 12:29 ` Trilok Soni
2007-08-27 18:39 ` OSK5912 Boot from CF? Hingkwan Huen
2007-08-27 19:04 ` Dirk Behme
2007-08-27 19:12 ` Hingkwan Huen
2007-08-27 19:22 ` Dirk Behme
2007-08-27 19:37 ` David Brownell
2007-08-31 20:27 ` [PATCH 1/2] ov9640: Add OmniVision ov9640 driver - new interface Tony Lindgren
2007-09-02 9:59 ` Trilok Soni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox