From 239a368d5715d8f5b7733f9400339c2350c49369 Mon Sep 17 00:00:00 2001 From: Saul Wold Date: Fri, 24 Sep 2010 15:36:24 -0700 Subject: netbook: Correct netbook build by moving netbook configuration from moblin to meta Signed-off-by: Saul Wold --- ...-2.6.35-moorestown-camera-driver-10.0-3-3.patch | 8290 -------------------- 1 file changed, 8290 deletions(-) delete mode 100644 meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.35-moorestown-camera-driver-10.0-3-3.patch (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.35-moorestown-camera-driver-10.0-3-3.patch') diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.35-moorestown-camera-driver-10.0-3-3.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.35-moorestown-camera-driver-10.0-3-3.patch deleted file mode 100644 index cd4edb921..000000000 --- a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.35-moorestown-camera-driver-10.0-3-3.patch +++ /dev/null @@ -1,8290 +0,0 @@ -From 0d55b08388f12c7c22cae9c6c745995d051624ba Mon Sep 17 00:00:00 2001 -From: Zheng Ba -Date: Thu, 1 Apr 2010 16:29:43 +0800 -Subject: [PATCH 3/3] Moorestown Camera Imaging driver Beta 10.0 - -Patch-mainline: 2.6.35? - -Changes from Beta 9.0: -1. Fixed hsd sighting: - 3469638 3469639 3469710 3469822 (high) - 3469697 (medium) - -Changes from Beta 8.0: -1. Fixed hsd sighting - 3469056 3469058 (critical) - 3469705 3469696 3469709 3469510 (medium) - -Changes from Beta 7.0: -1. Fixed hsd sighting 3469681,3469682,3469683 (high) - -Changes from Beta 6.0: -1. Fixed hsd sighting 3469668 (high) -2. Fixed ov5630 v4l2 view-finding dark issue -3. Enabled support for popular v4l2 applications (cheese, skype, ffmpeg) - -Changes from Beta 5.1: -1. Fixed CRITICAL sighting 3469558 -- ciapp fails to launch with segment fault -2. Fixed HIGH sighting 3479513 -- ov5630 AWB unstable -3. Improved KMOT sensor 720p fps from 30 to 40 - -Changes from Beta 5.0: -Fixed a critical issue of camera driver not loading -- hsd 3469557 - -Main changes from Beta 4.0: -Fixed 4 HSD sightings: 3469392,3469099,3469470,3469500 - -Main changes from Beta 3.0: -Fixed 7 HSD sightings: 3469264,3469112,3469395,3469103,3469105,3469471,3469484 - -Main changes from Beta 2.0: -Fixed 6 HSD sightings: 3469047,3469315,3469317,3469101,3468409,3469391 - -Main changes from Beta 1.1: -1. Added interrupt mode for jpeg capture and KMOT viewfinding -2. Fixed HSD sighting 3469228 and 3469147 - -Main changes from Alpha2: -Enabled MIPI interface in ISP driver and KMOT sensor s5k4e1. -Enabled FIFO in ISP driver, which doubled the fps in view-finding mode. -Enabled Subdev Framework in CI kernel driver. -Enabled AF Continuous Mode. -Enabled AE scene evaluation. - -Enabled the camera drivers in kernel: -Device Drivers --> Multimedia support --> Video For Linux -Device Drivers --> Mulitmedia support --> Video capture adapters --> ---> Moorestown Langwell Camera Imaging Subsystem support. - -Kernel configs: -1. camera driver depends on GPIO library and I2C driver. -CONFIG_GENERIC_GPIO=y -CONFIG_I2C=y -CONFIG_GPIOLIB=y -2. camera driver depends on videobuf-core and videobuf-dma-contig. -VIDEOBUF_GEN=y -VIDEOBUF_DMA_CONTIG=y -3. enable multimedia support and video capture. -CONFIG_MEDIA_SUPPORT=y -CONFIG_VIDEO_DEV=y -CONFIG_VIDEO_V4L2_COMMON=y -CONFIG_VIDEO_MEDIA=y -CONFIG_VIDEO_V4L2=y -4. camera drivers incluing ISP, 5630, 5630-motor, s5k4e1, s5k4e1-motor, 2650, -9665, flash. -CONFIG_VIDEO_MRSTCI=y -CONFIG_VIDEO_MRST_ISP=y -CONFIG_VIDEO_MRST_OV5630=y -CONFIG_VIDEO_MRST_OV5630_MOTOR=y -CONFIG_VIDEO_MRST_S5K4E1=y -CONFIG_VIDEO_MRST_S5K4E1_MOTOR=y -CONFIG_VIDEO_MRST_FLASH=y -CONFIG_VIDEO_MRST_OV2650=y -CONFIG_VIDEO_MRST_OV9665=y -Signed-off-by: Zheng Ba ---- - drivers/media/video/mrstci/mrstflash/Kconfig | 9 + - drivers/media/video/mrstci/mrstflash/Makefile | 3 + - drivers/media/video/mrstci/mrstflash/mrstflash.c | 150 +++ - drivers/media/video/mrstci/mrstov2650/Kconfig | 9 + - drivers/media/video/mrstci/mrstov2650/Makefile | 3 + - drivers/media/video/mrstci/mrstov2650/mrstov2650.c | 1190 ++++++++++++++++++++ - drivers/media/video/mrstci/mrstov2650/ov2650.h | 766 +++++++++++++ - drivers/media/video/mrstci/mrstov5630/Kconfig | 9 + - drivers/media/video/mrstci/mrstov5630/Makefile | 4 + - drivers/media/video/mrstci/mrstov5630/ov5630.c | 1153 +++++++++++++++++++ - drivers/media/video/mrstci/mrstov5630/ov5630.h | 672 +++++++++++ - .../media/video/mrstci/mrstov5630_motor/Kconfig | 9 + - .../media/video/mrstci/mrstov5630_motor/Makefile | 3 + - .../mrstci/mrstov5630_motor/mrstov5630_motor.c | 428 +++++++ - .../video/mrstci/mrstov5630_motor/ov5630_motor.h | 86 ++ - drivers/media/video/mrstci/mrstov9665/Kconfig | 9 + - drivers/media/video/mrstci/mrstov9665/Makefile | 3 + - drivers/media/video/mrstci/mrstov9665/mrstov9665.c | 972 ++++++++++++++++ - drivers/media/video/mrstci/mrstov9665/ov9665.h | 263 +++++ - drivers/media/video/mrstci/mrsts5k4e1/Kconfig | 9 + - drivers/media/video/mrstci/mrsts5k4e1/Makefile | 3 + - drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c | 1024 +++++++++++++++++ - drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h | 662 +++++++++++ - .../media/video/mrstci/mrsts5k4e1_motor/Kconfig | 9 + - .../media/video/mrstci/mrsts5k4e1_motor/Makefile | 3 + - .../mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.c | 430 +++++++ - .../mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.h | 102 ++ - 27 files changed, 7983 insertions(+), 0 deletions(-) - create mode 100644 drivers/media/video/mrstci/mrstflash/Kconfig - create mode 100644 drivers/media/video/mrstci/mrstflash/Makefile - create mode 100644 drivers/media/video/mrstci/mrstflash/mrstflash.c - create mode 100644 drivers/media/video/mrstci/mrstov2650/Kconfig - create mode 100644 drivers/media/video/mrstci/mrstov2650/Makefile - create mode 100644 drivers/media/video/mrstci/mrstov2650/mrstov2650.c - create mode 100644 drivers/media/video/mrstci/mrstov2650/ov2650.h - create mode 100644 drivers/media/video/mrstci/mrstov5630/Kconfig - create mode 100644 drivers/media/video/mrstci/mrstov5630/Makefile - create mode 100644 drivers/media/video/mrstci/mrstov5630/ov5630.c - create mode 100644 drivers/media/video/mrstci/mrstov5630/ov5630.h - create mode 100644 drivers/media/video/mrstci/mrstov5630_motor/Kconfig - create mode 100644 drivers/media/video/mrstci/mrstov5630_motor/Makefile - create mode 100644 drivers/media/video/mrstci/mrstov5630_motor/mrstov5630_motor.c - create mode 100644 drivers/media/video/mrstci/mrstov5630_motor/ov5630_motor.h - create mode 100644 drivers/media/video/mrstci/mrstov9665/Kconfig - create mode 100644 drivers/media/video/mrstci/mrstov9665/Makefile - create mode 100644 drivers/media/video/mrstci/mrstov9665/mrstov9665.c - create mode 100644 drivers/media/video/mrstci/mrstov9665/ov9665.h - create mode 100755 drivers/media/video/mrstci/mrsts5k4e1/Kconfig - create mode 100644 drivers/media/video/mrstci/mrsts5k4e1/Makefile - create mode 100755 drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c - create mode 100755 drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h - create mode 100755 drivers/media/video/mrstci/mrsts5k4e1_motor/Kconfig - create mode 100644 drivers/media/video/mrstci/mrsts5k4e1_motor/Makefile - create mode 100644 drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.c - create mode 100644 drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.h - -diff --git a/drivers/media/video/mrstci/mrstflash/Kconfig b/drivers/media/video/mrstci/mrstflash/Kconfig -new file mode 100644 -index 0000000..72099c5 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstflash/Kconfig -@@ -0,0 +1,9 @@ -+config VIDEO_MRST_FLASH -+ tristate "Moorestown flash" -+ depends on I2C && VIDEO_MRST_ISP -+ -+ ---help--- -+ Say Y here if your platform support moorestown flash. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mrstov2650.ko. -diff --git a/drivers/media/video/mrstci/mrstflash/Makefile b/drivers/media/video/mrstci/mrstflash/Makefile -new file mode 100644 -index 0000000..068f638 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstflash/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_VIDEO_MRST_FLASH) += mrstflash.o -+ -+EXTRA_CFLAGS += -I$(src)/../include -diff --git a/drivers/media/video/mrstci/mrstflash/mrstflash.c b/drivers/media/video/mrstci/mrstflash/mrstflash.c -new file mode 100644 -index 0000000..5611e6b ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstflash/mrstflash.c -@@ -0,0 +1,150 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging camera flash. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int debug; -+module_param(debug, bool, 0644); -+MODULE_PARM_DESC(debug, "Debug level (0-1)"); -+ -+MODULE_AUTHOR("Xiaolin Zhang "); -+MODULE_DESCRIPTION("A low-level driver for mrst flash"); -+MODULE_LICENSE("GPL"); -+ -+static int flash_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+#define V4L2_IDENT_MRST_FLASH 8248 -+ return v4l2_chip_ident_i2c_client(client, chip, -+ V4L2_IDENT_MRST_FLASH, 0); -+} -+ -+static const struct v4l2_subdev_core_ops flash_core_ops = { -+ .g_chip_ident = flash_g_chip_ident, -+}; -+static const struct v4l2_subdev_ops flash_ops = { -+ .core = &flash_core_ops, -+}; -+ -+static int flash_detect(struct i2c_client *client) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ u8 pid; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) -+ return -ENODEV; -+ -+ if (adapter->nr != 0) -+ return -ENODEV; -+ -+ pid = i2c_smbus_read_byte_data(client, 0x10); -+ if (pid == 0x18) { -+ printk(KERN_ERR "camera flash device found\n"); -+ v4l_dbg(1, debug, client, "found camera flash device"); -+ } else { -+ printk(KERN_ERR "no camera flash device found\n"); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static int flash_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ u8 pid, ver; -+ int ret = -1; -+ struct v4l2_subdev *sd; -+ -+ v4l_info(client, "chip found @ 0x%x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ -+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); -+ ret = flash_detect(client); -+ if (ret) -+ return -ENODEV; -+ -+ v4l2_i2c_subdev_init(sd, client, &flash_ops); -+ -+ ver = i2c_smbus_read_byte_data(client, 0x50); -+ v4l_dbg(1, debug, client, "detect:CST from device is 0x%x", ver); -+ pid = i2c_smbus_read_byte_data(client, 0x20); -+ v4l_dbg(1, debug, client, "detect:MFPC from device is 0x%x", pid); -+ pid = i2c_smbus_read_byte_data(client, 0xA0); -+ v4l_dbg(1, debug, client, "detect:TCC from device is 0x%x", pid); -+ pid = i2c_smbus_read_byte_data(client, 0xB0); -+ v4l_dbg(1, debug, client, "detect:FCC from device is 0x%x", pid); -+ pid = i2c_smbus_read_byte_data(client, 0xC0); -+ v4l_dbg(1, debug, client, "detect:FDC from device is 0x%x", pid); -+ i2c_smbus_write_byte_data(client, 0xc0, 0xff); /*set FST to 1000us*/ -+ pid = i2c_smbus_read_byte_data(client, 0xc0); -+ v4l_dbg(1, debug, client, "FDC from device is 0x%x", pid); -+ -+ v4l_dbg(1, debug, client, -+ "successfully load camera flash device driver"); -+ return 0; -+} -+ -+static int flash_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ v4l2_device_unregister_subdev(sd); -+ -+ return 0; -+} -+ -+static const struct i2c_device_id flash_id[] = { -+ {"mrst_camera_flash", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, flash_id); -+ -+static struct v4l2_i2c_driver_data v4l2_i2c_data = { -+ .name = "mrst_camera_flash", -+ .probe = flash_probe, -+ .remove = flash_remove, -+ .id_table = flash_id, -+}; -diff --git a/drivers/media/video/mrstci/mrstov2650/Kconfig b/drivers/media/video/mrstci/mrstov2650/Kconfig -new file mode 100644 -index 0000000..d39d894 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov2650/Kconfig -@@ -0,0 +1,9 @@ -+config VIDEO_MRST_OV2650 -+ tristate "Moorestown OV2650 SoC Sensor" -+ depends on I2C && VIDEO_MRST_ISP -+ -+ ---help--- -+ Say Y here if your platform support OV2650 SoC Sensor. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mrstov2650.ko. -diff --git a/drivers/media/video/mrstci/mrstov2650/Makefile b/drivers/media/video/mrstci/mrstov2650/Makefile -new file mode 100644 -index 0000000..fb16d57 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov2650/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_VIDEO_MRST_OV2650) += mrstov2650.o -+ -+EXTRA_CFLAGS += -I$(src)/../include -\ No newline at end of file -diff --git a/drivers/media/video/mrstci/mrstov2650/mrstov2650.c b/drivers/media/video/mrstci/mrstov2650/mrstov2650.c -new file mode 100644 -index 0000000..7f0d478 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov2650/mrstov2650.c -@@ -0,0 +1,1190 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ci_sensor_common.h" -+#include "ov2650.h" -+ -+static int mrstov2650_debug; -+module_param(mrstov2650_debug, int, 0644); -+MODULE_PARM_DESC(mrstov2650_debug, "Debug level (0-1)"); -+ -+#define dprintk(level, fmt, arg...) do { \ -+ if (mrstov2650_debug >= level) \ -+ printk(KERN_DEBUG "mrstisp@%s: " fmt "\n", \ -+ __func__, ## arg); } \ -+ while (0) -+ -+#define eprintk(fmt, arg...) \ -+ printk(KERN_ERR "mrstisp@%s: line %d: " fmt "\n", \ -+ __func__, __LINE__, ## arg); -+ -+#define DBG_entering dprintk(2, "entering"); -+#define DBG_leaving dprintk(2, "leaving"); -+#define DBG_line dprintk(2, " line: %d", __LINE__); -+ -+static inline struct ci_sensor_config *to_sensor_config(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct ci_sensor_config, sd); -+} -+ -+static struct ov2650_format_struct { -+ __u8 *desc; -+ __u32 pixelformat; -+ struct regval_list *regs; -+} ov2650_formats[] = { -+ { -+ .desc = "YUYV 4:2:2", -+ .pixelformat = SENSOR_MODE_BT601, -+ .regs = NULL, -+ }, -+}; -+#define N_OV2650_FMTS ARRAY_SIZE(ov2650_formats) -+ -+static struct ov2650_res_struct { -+ __u8 *desc; -+ int res; -+ int width; -+ int height; -+ /* FIXME: correct the fps values.. */ -+ int fps; -+ bool used; -+ struct regval_list *regs; -+} ov2650_res[] = { -+ { -+ .desc = "UXGA", -+ .res = SENSOR_RES_UXGA, -+ .width = 1600, -+ .height = 1200, -+ .fps = 15, -+ .used = 0, -+ .regs = ov2650_res_uxga, -+ }, -+ { -+ .desc = "SXGA", -+ .res = SENSOR_RES_SXGA, -+ .width = 1280, -+ .height = 1024, -+ .fps = 15, -+ .used = 0, -+ .regs = ov2650_res_sxga, -+ }, -+ { -+ .desc = "SVGA", -+ .res = SENSOR_RES_SVGA, -+ .width = 800, -+ .height = 600, -+ .fps = 15, -+ .used = 0, -+ .regs = ov2650_res_svga, -+ }, -+ { -+ .desc = "VGA", -+ .res = SENSOR_RES_VGA, -+ .width = 640, -+ .height = 480, -+ .fps = 15, -+ .used = 0, -+ .regs = ov2650_res_vga_vario, -+ }, -+ { -+ .desc = "QVGA", -+ .res = SENSOR_RES_QVGA, -+ .width = 320, -+ .height = 240, -+ .fps = 15, -+ .used = 0, -+ .regs = ov2650_res_qvga, -+ }, -+}; -+ -+#define N_RES (ARRAY_SIZE(ov2650_res)) -+ -+/* -+ * I2C Read & Write stuff -+ */ -+static int ov2650_read(struct i2c_client *c, u16 reg, u8 *value) -+{ -+ int ret; -+ int i; -+ struct i2c_msg msg[2]; -+ u8 msgbuf[2]; -+ u8 ret_val = 0; -+ *value = 0; -+ /* Read needs two message to go */ -+ memset(&msg, 0, sizeof(msg)); -+ msgbuf[0] = 0; -+ msgbuf[1] = 0; -+ i = 0; -+ msgbuf[i++] = reg >> 8; -+ msgbuf[i++] = reg; -+ msg[0].addr = c->addr; -+ msg[0].buf = msgbuf; -+ msg[0].len = i; -+ -+ msg[1].addr = c->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].buf = &ret_val; -+ msg[1].len = 1; -+ -+ ret = i2c_transfer(c->adapter, &msg[0], 2); -+ *value = ret_val; -+ -+ ret = (ret == 2) ? 0 : -1; -+ return ret; -+} -+ -+static int ov2650_write(struct i2c_client *c, u16 reg, u8 value) -+{ -+ int ret, i; -+ struct i2c_msg msg; -+ u8 msgbuf[3]; -+ -+ /* Writing only needs one message */ -+ memset(&msg, 0, sizeof(msg)); -+ i = 0; -+ msgbuf[i++] = reg >> 8; -+ msgbuf[i++] = reg; -+ msgbuf[i++] = value; -+ -+ msg.addr = c->addr; -+ msg.flags = 0; -+ msg.buf = msgbuf; -+ msg.len = i; -+ -+ ret = i2c_transfer(c->adapter, &msg, 1); -+ -+ /* If this is a reset register, wait for 1ms */ -+ if (reg == OV2650_SYS && (value & 0x80)) -+ msleep(3); -+ -+ ret = (ret == 1) ? 0 : -1; -+ return ret; -+} -+ -+static int ov2650_write_array(struct i2c_client *c, struct regval_list *vals) -+{ -+ struct regval_list *p; -+ u8 read_val = 0; -+ int err_num = 0; -+ int i = 0; -+ p = vals; -+ while (p->reg_num != 0xffff) { -+ ov2650_write(c, p->reg_num, p->value); -+ ov2650_read(c, p->reg_num, &read_val); -+ if (read_val != p->value) -+ err_num++; -+ p++; -+ i++; -+ } -+ return 0; -+} -+ -+static int ov2650_set_data_pin_in(struct i2c_client *client) -+{ -+ int ret = 0; -+ u8 reg; -+ -+ ret += ov2650_write(client, 0x30b0, 0x00); -+ -+ ret += ov2650_read(client, 0x30b1, ®); -+ reg &= 0xfc; -+ ret += ov2650_write(client, 0x30b1, reg); -+ -+ return ret; -+} -+ -+static int ov2650_set_data_pin_out(struct i2c_client *client) -+{ -+ int ret = 0; -+ u8 reg; -+ -+ ret += ov2650_write(client, 0x30b0, 0xff); -+ -+ ret += ov2650_read(client, 0x30b1, ®); -+ reg &= 0xfc; -+ reg |= 0x03; -+ ret += ov2650_write(client, 0x30b1, reg); -+ -+ return ret; -+} -+/* -+ * Sensor specific helper function -+ */ -+static int ov2650_standby(void) -+{ -+ gpio_set_value(GPIO_STDBY_PIN, 1); -+ dprintk(1, "PM: standby called\n"); -+ return 0; -+} -+ -+static int ov2650_wakeup(void) -+{ -+ gpio_set_value(GPIO_STDBY_PIN, 0); -+ dprintk(1, "PM: wakeup called\n"); -+ return 0; -+} -+ -+static int ov2650_s_power(struct v4l2_subdev *sd, u32 val) -+{ -+ if (val == 1) -+ ov2650_standby(); -+ if (val == 0) -+ ov2650_wakeup(); -+ return 0; -+} -+ -+static int ov2650_init(struct i2c_client *c) -+{ -+ int ret; -+ struct v4l2_subdev *sd = i2c_get_clientdata(c); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ -+ /* Fill the configuration structure */ -+ /* Note this default configuration value */ -+ info->mode = ov2650_formats[0].pixelformat; -+ info->res = ov2650_res[0].res; -+ info->type = SENSOR_TYPE_SOC; -+ info->bls = SENSOR_BLS_OFF; -+ info->gamma = SENSOR_GAMMA_ON; -+ info->cconv = SENSOR_CCONV_ON; -+ info->blc = SENSOR_BLC_AUTO; -+ info->agc = SENSOR_AGC_AUTO; -+ info->awb = SENSOR_AWB_AUTO; -+ info->aec = SENSOR_AEC_AUTO; -+ info->bus_width = SENSOR_BUSWIDTH_8BIT_ZZ; -+ info->ycseq = SENSOR_YCSEQ_YCBYCR; -+ info->conv422 = SENSOR_CONV422_COSITED; -+ info->bpat = SENSOR_BPAT_BGBGGRGR;/* GRGRBGBG; */ -+ info->field_inv = SENSOR_FIELDINV_NOSWAP; -+ info->field_sel = SENSOR_FIELDSEL_BOTH; -+ info->hpol = SENSOR_HPOL_REFPOS; -+ info->vpol = SENSOR_VPOL_POS; -+ info->edge = SENSOR_EDGE_RISING; -+ info->flicker_freq = SENSOR_FLICKER_100; -+ info->cie_profile = 0; -+ memcpy(info->name, "ov2650", 7); -+ -+ ret = ov2650_write(c, OV2650_SYS, 0x80); -+ /* Set registers into default config value */ -+ ret += ov2650_write_array(c, ov2650_def_reg); -+ -+ /* added by wen to stop sensor from streaming */ -+ ov2650_write(c, 0x3086, 0x0f); -+ ov2650_set_data_pin_in(c); -+ ssleep(1); -+ -+ return ret; -+} -+ -+static int distance(struct ov2650_res_struct *res, u32 w, u32 h) -+{ -+ int ret; -+ if (res->width < w || res->height < h) -+ return -1; -+ -+ ret = ((res->width - w) + (res->height - h)); -+ return ret; -+} -+ -+static int ov2650_try_res(u32 *w, u32 *h) -+{ -+ struct ov2650_res_struct *res_index, *p = NULL; -+ int dis, last_dis = ov2650_res->width + ov2650_res->height; -+ -+ dprintk(1, "&&&&& before %dx%d", *w, *h); -+ for (res_index = ov2650_res; -+ res_index < ov2650_res + N_RES; -+ res_index++) { -+ if ((res_index->width <= *w) && (res_index->height <= *h)) -+ break; -+ dis = distance(res_index, *w, *h); -+ if (dis < last_dis) { -+ last_dis = dis; -+ p = res_index; -+ } -+ } -+ if ((res_index->width < *w) || (res_index->height < *h)) { -+ if (res_index != ov2650_res) -+ res_index--; -+ } -+ -+ /* -+ if (p == NULL) { -+ p = ov2650_res; -+ } -+ -+ if ((w != NULL) && (h != NULL)) { -+ *w = p->width; -+ *h = p->height; -+ } -+ */ -+ if (res_index == ov2650_res + N_RES) -+ res_index = ov2650_res + N_RES - 1; -+ -+ *w = res_index->width; -+ *h = res_index->height; -+ -+ dprintk(1, "&&&&& after %dx%d", *w, *h); -+ return 0; -+} -+ -+static struct ov2650_res_struct *ov2650_to_res(u32 w, u32 h) -+{ -+ struct ov2650_res_struct *res_index; -+ -+ for (res_index = ov2650_res; -+ res_index < ov2650_res + N_RES; -+ res_index++) -+ if ((res_index->width == w) && (res_index->height == h)) -+ break; -+ -+ if (res_index >= ov2650_res + N_RES) -+ res_index--; /* Take the bigger one */ -+ -+ return res_index; -+} -+ -+static int ov2650_try_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ DBG_entering; -+ dprintk(1, "&&&&& before %dx%d", fmt->fmt.pix.width, -+ fmt->fmt.pix.height); -+ return ov2650_try_res(&fmt->fmt.pix.width, &fmt->fmt.pix.height); -+ dprintk(1, "&&&&& after %dx%d", fmt->fmt.pix.width, -+ fmt->fmt.pix.height); -+ DBG_leaving; -+} -+ -+static int ov2650_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ unsigned short width, height; -+ int index; -+ -+ ci_sensor_res2size(info->res, &width, &height); -+ -+ /* Marked the current sensor res as being "used" */ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == ov2650_res[index].width) && -+ (height == ov2650_res[index].height)) { -+ ov2650_res[index].used = 1; -+ continue; -+ } -+ ov2650_res[index].used = 0; -+ } -+ -+ fmt->fmt.pix.width = width; -+ fmt->fmt.pix.height = height; -+ return 0; -+} -+ -+static int ov2650_set_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ int ret = 0; -+ struct ov2650_res_struct *res_index; -+ u32 width, height; -+ int index; -+ -+ DBG_entering; -+ -+ width = fmt->fmt.pix.width; -+ height = fmt->fmt.pix.height; -+ -+ ret = ov2650_try_res(&width, &height); -+ res_index = ov2650_to_res(width, height); -+ -+ ov2650_wakeup(); -+ -+ /* if ((info->res != res_index->res) && (res_index->regs)) { */ -+ if (res_index->regs) { -+ -+ dprintk(2, "changing res from to %dx%d", width, height); -+ ret = ov2650_write(client, OV2650_SYS, 0x80); -+ ret += ov2650_write_array(client, ov2650_def_reg); -+ ret += ov2650_write_array(client, res_index->regs); -+ -+ /* add to debug -+ if(res_index->res == SENSOR_RES_VGA) { -+ ret += ov2650_write_array(c, ov2650_def_reg); -+ ret += ov2650_write_array(c, res_index->regs); -+ } else { -+ ret += ov2650_write_array(c, ov2650_res_vga_reverse); -+ ret += ov2650_write_array(c, res_index->regs); -+ } -+ */ -+ -+ /* Add delay here to get better image */ -+ /* -+ if (res_index->res == SENSOR_RES_SXGA || -+ res_index->res == SENSOR_RES_UXGA) -+ msleep(2000); -+ else -+ msleep(900); -+ */ -+ -+ /* Marked current sensor res as being "used" */ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == ov2650_res[index].width) && -+ (height == ov2650_res[index].height)) { -+ ov2650_res[index].used = 1; -+ continue; -+ } -+ ov2650_res[index].used = 0; -+ } -+ -+ for (index = 0; index < N_RES; index++) -+ dprintk(2, "index = %d, used = %d\n", index, -+ ov2650_res[index].used); -+ -+ } -+ -+ info->res = res_index->res; -+ -+ /* -+ int i; -+ unsigned char value; -+ printk(KERN_WARNING "2650 reg dumping start:\n"); -+ for(i = 0x3000; i <= 0x360B; i ++) { -+ ov2650_read(c, i, &value); -+ printk(KERN_WARNING "reg at offset %4x = %x\n", i, value); -+ } -+ printk(KERN_WARNING "2650 reg dumping finished:\n"); -+ */ -+ -+ DBG_leaving; -+ -+ return ret; -+} -+ -+static int ov2650_q_hflip(struct v4l2_subdev *sd, __s32 *value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int err; -+ unsigned char v; -+ -+ err = ov2650_read(client, OV2650_TMC_6, &v); -+ *value = (v & 0x02) == 0x02; -+ return err; -+} -+ -+static int ov2650_t_hflip(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ unsigned char v, v1 = 0; -+ int err; -+ -+ value = value >= 1 ? 1 : 0; -+ err = ov2650_read(client, OV2650_TMC_6, &v); -+ if (value) { -+ v |= 0x02; -+ v1 |= 0x08; -+ info->bpat = SENSOR_BPAT_GRGRBGBG;/*BGBGGRGR;*/ -+ } else { -+ v &= ~0x02; -+ v1 &= ~0x08; -+ info->bpat = SENSOR_BPAT_BGBGGRGR; -+ } -+ err += ov2650_write(client, OV2650_TMC_6, v); -+ err += ov2650_write(client, 0x3090, v1); -+ msleep(10); /* FIXME */ -+ -+ return err; -+} -+ -+static int ov2650_q_vflip(struct v4l2_subdev *sd, __s32 *value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int err; -+ unsigned char v; -+ -+ err = ov2650_read(client, OV2650_TMC_6, &v); -+ *value = (v & 0x01) == 0x01; -+ return err; -+} -+ -+ -+static int ov2650_t_vflip(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int err = 0; -+ unsigned char v; -+ -+ value = value >= 1 ? 1 : 0; -+ err = ov2650_read(client, OV2650_TMC_6, &v); -+ if (value) -+ v |= 0x01; -+ else -+ v &= ~0x01; -+ err += ov2650_write(client, OV2650_TMC_6, v); -+ msleep(10); /* FIXME */ -+ -+ return err; -+} -+ -+#if 0 -+static int ov2650_t_awb(struct i2c_client *c, int value) -+{ -+ unsigned char v; -+ int ret; -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ -+ value = value >= 1 ? 1 : 0; -+ ret = ov2650_read(c, OV2650_ISP_CTL_0, &v); -+ if (value & 0x01) { -+ v |= 0x30; -+ info->awb = SENSOR_AWB_AUTO; -+ } else { -+ v &= ~0x30; -+ info->awb = SENSOR_AWB_OFF; -+ } -+ ret += ov2650_write(c, OV2650_ISP_CTL_0, v); -+ msleep(10); /* FIXME */ -+ -+ return ret; -+} -+ -+static int ov2650_q_awb(struct i2c_client *c, int *value) -+{ -+ int ret; -+ unsigned char v; -+ -+ ret = ov2650_read(c, OV2650_ISP_CTL_0, &v); -+ *value = (v & 0x30) == 0x30; -+ return ret; -+} -+ -+static int ov2650_t_agc(struct i2c_client *c, int value) -+{ -+ unsigned char v; -+ int ret; -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ -+ value = value >= 1 ? 1 : 0; -+ ret = ov2650_read(c, OV2650_ISP_CTL_0, &v); -+ if (value & 0x01) { -+ v |= 0x10; -+ info->agc = SENSOR_AGC_AUTO; -+ } else { -+ v &= ~0x10; -+ info->agc = SENSOR_AGC_OFF; -+ } -+ ret += ov2650_write(c, OV2650_ISP_CTL_0, v); -+ msleep(10); /* FIXME */ -+ -+ return ret; -+} -+ -+static int ov2650_q_agc(struct i2c_client *c, int *value) -+{ -+ int ret; -+ unsigned char v; -+ -+ ret = ov2650_read(c, OV2650_ISP_CTL_0, &v); -+ *value = (v & 0x10) == 0x10; -+ return ret; -+} -+ -+static int ov2650_t_blc(struct i2c_client *c, int value) -+{ -+ unsigned char v; -+ int ret; -+ -+ value = value >= 1 ? 1 : 0; -+ -+ ret = ov2650_read(c, OV2650_BLCC, &v); -+ if (value & 0x01) -+ v |= 0x10; -+ else -+ v &= ~0x10; -+ ret += ov2650_write(c, OV2650_BLCC, v); -+ msleep(10); /* FIXME */ -+ -+ return ret; -+} -+ -+static int ov2650_q_blc(struct i2c_client *c, int *value) -+{ -+ int ret; -+ unsigned char v; -+ -+ ret = ov2650_read(c, OV2650_BLCC, &v); -+ *value = (v & 0x10) == 0x10; -+ return ret; -+} -+#endif -+ -+static struct ov2650_control { -+ struct v4l2_queryctrl qc; -+ int (*query)(struct v4l2_subdev *sd, __s32 *value); -+ int (*tweak)(struct v4l2_subdev *sd, int value); -+} ov2650_controls[] = { -+ { -+ .qc = { -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .name = "Vertical flip", -+ .minimum = 0, -+ .maximum = 1, -+ .step = 1, -+ .default_value = 0, -+ }, -+ .tweak = ov2650_t_vflip, -+ .query = ov2650_q_vflip, -+ }, -+ { -+ .qc = { -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .name = "Horizontal mirror", -+ .minimum = 0, -+ .maximum = 1, -+ .step = 1, -+ .default_value = 0, -+ }, -+ .tweak = ov2650_t_hflip, -+ .query = ov2650_q_hflip, -+ }, -+#if 0 -+ { -+ .parm = { -+ .index = V4L2_CID_AUTO_WHITE_BALANCE, -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .name = "Auto White Balance", -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def_value = 1, -+ }, -+ .tweak = ov2650_t_awb, -+ .query = ov2650_q_awb, -+ }, -+ { -+ .parm = { -+ .index = V4L2_CID_AUTOGAIN, -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .name = "Auto Gain Control", -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def_value = 1, -+ }, -+ .tweak = ov2650_t_agc, -+ .query = ov2650_q_agc, -+ -+ }, -+ { -+ .parm = { -+ .index = V4L2_CID_BLACK_LEVEL, -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .name = "Black Level Control", -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def_value = 1, -+ }, -+ .tweak = ov2650_t_blc, -+ .query = ov2650_q_blc, -+ -+ }, -+#endif -+}; -+#define N_CONTROLS (ARRAY_SIZE(ov2650_controls)) -+ -+static struct ov2650_control *ov2650_find_control(__u32 id) -+{ -+ int i; -+ -+ for (i = 0; i < N_CONTROLS; i++) -+ if (ov2650_controls[i].qc.id == id) -+ return ov2650_controls + i; -+ return NULL; -+} -+ -+static int ov2650_queryctrl(struct v4l2_subdev *sd, -+ struct v4l2_queryctrl *qc) -+{ -+ struct ov2650_control *octrl; -+ octrl = ov2650_find_control(qc->id); -+ if (NULL == octrl) -+ return -EINVAL; -+ *qc = octrl->qc; -+ return 0; -+} -+ -+static int ov2650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ struct ov2650_control *octrl = ov2650_find_control(ctrl->id); -+ int ret; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->query(sd, &ctrl->value); -+ if (ret >= 0) -+ return 0; -+ return ret; -+} -+ -+static int ov2650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ struct ov2650_control *octrl = ov2650_find_control(ctrl->id); -+ int ret; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->tweak(sd, ctrl->value); -+ if (ret >= 0) -+ return 0; -+ return ret; -+} -+#if 0 -+static int ov2650_get_caps(struct i2c_client *c, struct ci_sensor_caps *caps) -+{ -+ if (caps == NULL) -+ return -EIO; -+ -+ caps->bus_width = SENSOR_BUSWIDTH_8BIT_ZZ; -+ caps->mode = SENSOR_MODE_BT601; -+ caps->field_inv = SENSOR_FIELDINV_NOSWAP; -+ caps->field_sel = SENSOR_FIELDSEL_BOTH; -+ caps->ycseq = SENSOR_YCSEQ_YCBYCR; -+ caps->conv422 = SENSOR_CONV422_COSITED; -+ caps->bpat = SENSOR_BPAT_BGBGGRGR; -+ caps->hpol = SENSOR_HPOL_REFPOS; -+ caps->vpol = SENSOR_VPOL_POS; -+ caps->edge = SENSOR_EDGE_RISING; -+ caps->bls = SENSOR_BLS_OFF; -+ caps->gamma = SENSOR_GAMMA_ON; -+ caps->cconv = SENSOR_CCONV_ON; -+ caps->res = SENSOR_RES_UXGA | SENSOR_RES_SXGA | SENSOR_RES_SVGA -+ | SENSOR_RES_VGA | SENSOR_RES_QVGA; -+ caps->blc = SENSOR_BLC_AUTO; -+ caps->agc = SENSOR_AGC_AUTO; -+ caps->awb = SENSOR_AWB_AUTO; -+ caps->aec = SENSOR_AEC_AUTO; -+ caps->cie_profile = 0; -+ caps->flicker_freq = SENSOR_FLICKER_100 | SENSOR_FLICKER_120; -+ caps->type = SENSOR_TYPE_SOC; -+ /* caps->name = "ov2650"; */ -+ strcpy(caps->name, "ov2650"); -+ -+ return 0; -+} -+ -+static int ov2650_get_config(struct i2c_client *c, -+ struct ci_sensor_config *config) -+{ -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ -+ if (config == NULL) { -+ printk(KERN_WARNING "sensor_get_config: NULL pointer\n"); -+ return -EIO; -+ } -+ -+ memcpy(config, info, sizeof(struct ci_sensor_config)); -+ -+ return 0; -+} -+ -+static int ov2650_setup(struct i2c_client *c, -+ const struct ci_sensor_config *config) -+{ -+ int ret; -+ struct ov2650_res_struct *res_index; -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ u16 width, high; -+ -+ /* Soft reset camera first*/ -+ ret = ov2650_write(c, OV2650_SYS, 0x80); -+ -+ /* Set registers into default config value */ -+ ret += ov2650_write_array(c, ov2650_def_reg); -+ -+ /* set image resolution */ -+ ci_sensor_res2size(config->res, &width, &high); -+ ret += ov2650_try_res(c, &width, &high); -+ res_index = ov2650_find_res(width, high); -+ if (res_index->regs) -+ ret += ov2650_write_array(c, res_index->regs); -+ if (!ret) -+ info->res = res_index->res; -+ -+ -+ if (config->blc != info->blc) { -+ ret += ov2650_t_blc(c, config->blc); -+ info->blc = config->blc; -+ } -+ -+ if (config->agc != info->agc) { -+ ret += ov2650_t_agc(c, config->agc); -+ info->agc = config->agc; -+ } -+ -+ if (config->awb != info->awb) { -+ ret += ov2650_t_awb(c, config->awb); -+ info->awb = config->awb; -+ } -+ /* Add some delay here to get a better image*/ -+ if (res_index->res == SENSOR_RES_SXGA || -+ res_index->res == SENSOR_RES_UXGA) -+ msleep(2000); -+ else -+ msleep(900); -+ -+ return ret; -+} -+ -+/* -+ * File operation functions -+ */ -+ -+ -+ -+static int ov2650_open(struct i2c_setting *c, void *priv) -+{ -+ struct i2c_client *client = c->sensor_client; -+ /* Just wake up sensor */ -+ if (ov2650_wakeup()) -+ return -EIO; -+ ov2650_init(client); -+ /*Sleep sensor now*/ -+ ov2650_write(client, 0x3086, 0x0f); -+ -+ /* set data pin to input */ -+ if (ov2650_set_data_pin_in(client)) -+ return -EIO; -+ -+ return 0; -+} -+ -+static int ov2650_release(struct i2c_setting *c, void *priv) -+{ -+ /* Just suspend the sensor */ -+ ov2650_standby(); -+ return 0; -+} -+ -+static int ov2650_on(struct i2c_setting *c) -+{ -+ int ret; -+ -+ /* Software wake up sensor */ -+ ret = ov2650_write(c->sensor_client, 0x3086, 0x00); -+ -+ /* set data pin to output */ -+ return ret + ov2650_set_data_pin_out(c->sensor_client); -+} -+ -+static int ov2650_off(struct i2c_setting *c) -+{ -+ int ret; -+ -+ /* Software standby sensor */ -+ ret = ov2650_write(c->sensor_client, 0x3086, 0x0f); -+ -+ /* set data pin to input */ -+ return ret + ov2650_set_data_pin_in(c->sensor_client); -+} -+ -+static struct sensor_device ov2650 = { -+ .name = "OV2650", -+ .type = SENSOR_TYPE_SOC, -+ .minor = -1, -+ .open = ov2650_open, -+ .release = ov2650_release, -+ .on = ov2650_on, -+ .off = ov2650_off, -+ .querycap = ov2650_get_caps, -+ .get_config = ov2650_get_config, -+ .set_config = ov2650_setup, -+ .enum_parm = ov2650_queryctrl, -+ .get_parm = ov2650_g_ctrl, -+ .set_parm = ov2650_s_ctrl, -+ .try_res = ov2650_try_res, -+ .set_res = ov2650_set_res, -+ .suspend = ov2650_standby, -+ .resume = ov2650_wakeup, -+ .get_ls_corr_config = NULL, -+ .set_awb = NULL, -+ .set_aec = NULL, -+ .set_blc = NULL, -+ /* TBC */ -+}; -+#endif -+ -+static int ov2650_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ DBG_entering; -+ -+ -+ if (enable) { -+ ov2650_write(client, 0x3086, 0x00); -+ ov2650_set_data_pin_out(client); -+ msleep(2000); -+ } else { -+ ov2650_write(client, 0x3086, 0x0f); -+ ov2650_set_data_pin_in(client); -+ } -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int ov2650_enum_framesizes(struct v4l2_subdev *sd, -+ struct v4l2_frmsizeenum *fsize) -+{ -+ unsigned int index = fsize->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; -+ fsize->discrete.width = ov2650_res[index].width; -+ fsize->discrete.height = ov2650_res[index].height; -+ fsize->reserved[0] = ov2650_res[index].used; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+ -+static int ov2650_enum_frameintervals(struct v4l2_subdev *sd, -+ struct v4l2_frmivalenum *fival) -+{ -+ unsigned int index = fival->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; -+ fival->discrete.numerator = 1; -+ fival->discrete.denominator = ov2650_res[index].fps; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+static int ov2650_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+#define V4L2_IDENT_OV2650 8244 -+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV2650, 0); -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ov2650_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ unsigned char val = 0; -+ int ret; -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ ret = ov2650_read(client, reg->reg & 0xffff, &val); -+ reg->val = val; -+ reg->size = 1; -+ return ret; -+} -+ -+static int ov2650_s_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ ov2650_write(client, reg->reg & 0xffff, reg->val & 0xff); -+ return 0; -+} -+#endif -+ -+static const struct v4l2_subdev_video_ops ov2650_video_ops = { -+ .try_fmt = ov2650_try_fmt, -+ .s_fmt = ov2650_set_fmt, -+ .g_fmt = ov2650_get_fmt, -+ .s_stream = ov2650_s_stream, -+ .enum_framesizes = ov2650_enum_framesizes, -+ .enum_frameintervals = ov2650_enum_frameintervals, -+}; -+ -+static const struct v4l2_subdev_core_ops ov2650_core_ops = { -+ .g_chip_ident = ov2650_g_chip_ident, -+ .queryctrl = ov2650_queryctrl, -+ .g_ctrl = ov2650_g_ctrl, -+ .s_ctrl = ov2650_s_ctrl, -+ .s_gpio = ov2650_s_power, -+ /*.g_ext_ctrls = ov2650_g_ext_ctrls,*/ -+ /*.s_ext_ctrls = ov2650_s_ext_ctrls,*/ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ov2650_g_register, -+ .s_register = ov2650_s_register, -+#endif -+}; -+ -+static const struct v4l2_subdev_ops ov2650_ops = { -+ .core = &ov2650_core_ops, -+ .video = &ov2650_video_ops, -+}; -+ -+/* -+ * Basic i2c stuff -+ */ -+#if 0 -+static unsigned short normal_i2c[] = {I2C_OV2650 >> 1, I2C_CLIENT_END}; -+I2C_CLIENT_INSMOD; -+ -+static struct i2c_driver ov2650_driver; -+#endif -+static int ov2650_detect(struct i2c_client *client) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ int adap_id = i2c_adapter_id(adapter); -+ u8 value; -+ -+ printk(KERN_WARNING "Now start ov2650 detect\n"); -+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) -+ return -ENODEV; -+ -+ if (adap_id != 1) -+ return -ENODEV; -+ -+ /* if (ov2650_wakeup()) */ -+ /* return -ENODEV; */ -+ ov2650_wakeup(); -+ -+ ov2650_read(client, OV2650_PID_L, &value); -+ if (value != 0x52) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static int ov2650_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct ci_sensor_config *info; -+ struct v4l2_subdev *sd; -+ int ret = -1; -+ -+ DBG_entering; -+ -+ printk(KERN_INFO "Init ov2650 sensor \n"); -+ -+ v4l_info(client, "chip found @ 0x%x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ /* -+ * Setup sensor configuration structure -+ */ -+ info = kzalloc(sizeof(struct ci_sensor_config), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ ret = ov2650_detect(client); -+ if (ret) { -+ kfree(info); -+ return -ENODEV; -+ } -+ -+ sd = &info->sd; -+ v4l2_i2c_subdev_init(sd, client, &ov2650_ops); -+ -+ /* -+ * TODO: Need to check if this can be here. -+ * Turn into standby mode -+ */ -+ /* ov2650_standby(); */ -+ ret += ov2650_init(client); -+ ov2650_standby(); -+ -+ printk(KERN_INFO "Init ov2650 sensor success, ret = %d\n", ret); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int ov2650_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ v4l2_device_unregister_subdev(sd); -+ kfree(to_sensor_config(sd)); -+ return 0; -+} -+ -+static const struct i2c_device_id ov2650_id[] = { -+ {"ov2650", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, ov2650_id); -+ -+static struct v4l2_i2c_driver_data v4l2_i2c_data = { -+ .name = "ov2650", -+ .probe = ov2650_probe, -+ .remove = ov2650_remove, -+ /* .suspend = ov2650_suspend, -+ * .resume = ov2650_resume, */ -+ .id_table = ov2650_id, -+}; -+ -+MODULE_AUTHOR("Xiaolin Zhang "); -+MODULE_DESCRIPTION("A low-level driver for OmniVision 2650 sensors"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/video/mrstci/mrstov2650/ov2650.h b/drivers/media/video/mrstci/mrstov2650/ov2650.h -new file mode 100644 -index 0000000..f5c0418 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov2650/ov2650.h -@@ -0,0 +1,766 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#define I2C_OV2650 0x60 -+/* Should add to kernel source */ -+#define I2C_DRIVERID_OV2650 1047 -+/* GPIO pin on Moorestown */ -+#define GPIO_SCLK_25 44 -+#define GPIO_STB_PIN 47 -+#define GPIO_STDBY_PIN 48 -+#define GPIO_RESET_PIN 50 -+ -+/* System control register */ -+#define OV2650_AGC 0x3000 -+#define OV2650_AGCS 0x3001 -+#define OV2650_AEC_H 0x3002 -+#define OV2650_AEC_L 0x3003 -+#define OV2650_AECL 0x3004 -+#define OV2650_AECS_H 0x3008 -+#define OV2650_AECS_L 0x3009 -+#define OV2650_PID_H 0x300A -+#define OV2650_PID_L 0x300B -+#define OV2650_SCCB 0x300C -+#define OV2650_PCLK 0x300D -+#define OV2650_PLL_1 0x300E -+#define OV2650_PLL_2 0x300F -+#define OV2650_PLL_3 0x3010 -+#define OV2650_CLK 0x3011 -+#define OV2650_SYS 0x3012 -+#define OV2650_AUTO_1 0x3013 -+#define OV2650_AUTO_2 0x3014 -+#define OV2650_AUTO_3 0x3015 -+#define OV2650_AUTO_4 0x3016 -+#define OV2650_AUTO_5 0x3017 -+#define OV2650_WPT 0x3018 -+#define OV2650_BPT 0x3019 -+#define OV2650_VPT 0x301A -+#define OV2650_YAVG 0x301B -+#define OV2650_AECG_50 0x301C -+#define OV2650_AECG_60 0x301D -+#define OV2650_RZM_H 0x301E -+#define OV2650_RZM_L 0x301F -+#define OV2650_HS_H 0x3020 -+#define OV2650_HS_L 0x3021 -+#define OV2650_VS_H 0x3022 -+#define OV2650_VS_L 0x3023 -+#define OV2650_HW_H 0x3024 -+#define OV2650_HW_L 0x3025 -+#define OV2650_VH_H 0x3026 -+#define OV2650_VH_L 0x3027 -+#define OV2650_HTS_H 0x3028 -+#define OV2650_HTS_L 0x3029 -+#define OV2650_VTS_H 0x302A -+#define OV2650_VTS_L 0x302B -+#define OV2650_EXHTS 0x302C -+#define OV2650_EXVTS_H 0x302D -+#define OV2650_EXVTS_L 0x302E -+#define OV2650_WET_0 0x3030 -+#define OV2650_WET_1 0x3031 -+#define OV2650_WET_2 0x3032 -+#define OV2650_WET_3 0x3033 -+#define OV2650_AHS_H 0x3038 -+#define OV2650_AHS_L 0x3039 -+#define OV2650_AVS_H 0x303A -+#define OV2650_AVS_L 0x303B -+#define OV2650_AHW_H 0x303C -+#define OV2650_AHW_L 0x303D -+#define OV2650_AVH_H 0x303E -+#define OV2650_AVH_L 0x303F -+#define OV2650_HISTO_0 0x3040 -+#define OV2650_HISTO_1 0x3041 -+#define OV2650_HISTO_2 0x3042 -+#define OV2650_HISTO_3 0x3043 -+#define OV2650_HISTO_4 0x3044 -+#define OV2650_BLC9A 0x3069 -+#define OV2650_BLCC 0x306C -+#define OV2650_BLCD 0x306D -+#define OV2650_BLCF 0x306F -+#define OV2650_BD50_L 0x3070 -+#define OV2650_BD50_H 0x3071 -+#define OV2650_BD60_L 0x3072 -+#define OV2650_BD60_H 0x3073 -+#define OV2650_TMC_0 0x3076 -+#define OV2650_TMC_1 0x3077 -+#define OV2650_TMC_2 0x3078 -+#define OV2650_TMC_4 0x307A -+#define OV2650_TMC_6 0x307C -+#define OV2650_TMC_8 0x307E -+#define OV2650_TMC_I2C 0x3084 -+#define OV2650_TMC_10 0x3086 -+#define OV2650_TMC_11 0x3087 -+#define OV2650_ISP_XO_H 0x3088 -+#define OV2650_ISP_XO_L 0x3089 -+#define OV2650_ISP_YO_H 0x308A -+#define OV2650_ISP_YO_L 0x308B -+#define OV2650_TMC_12 0x308C -+#define OV2650_TMC_13 0x308D -+#define OV2650_EFUSE 0x308F -+#define OV2650_IO_CTL_0 0x30B0 -+#define OV2650_IO_CRL_1 0x30B1 -+#define OV2650_IO_CTL_2 0x30B2 -+#define OV2650_LAEC 0x30F0 -+#define OV2650_GRP_EOP 0x30FF -+ -+/* SC registers */ -+#define OV2650_SC_CTL_0 0x3100 -+#define OV2650_SC_SYN_CTL_0 0x3104 -+#define OV2650_SC_SYN_CTL_1 0x3105 -+#define OV2650_SC_SYN_CTL_3 0x3107 -+#define OV2650_SC_SYN_CTL_4 0x3108 -+ -+/* DSP control register */ -+#define OV2650_ISP_CTL_0 0x3300 -+#define OV2650_ISP_CTL_1 0x3301 -+#define OV2650_ISP_CTL_2 0x3302 -+#define OV2650_ISP_CTL_3 0x3303 -+#define OV2650_ISP_CTL_4 0x3304 -+#define OV2650_ISP_CTL_5 0x3305 -+#define OV2650_ISP_CTL_6 0x3306 -+#define OV2650_ISP_CTL_7 0x3307 -+#define OV2650_ISP_CTL_8 0x3308 -+#define OV2650_ISP_CTL_9 0x3309 -+#define OV2650_ISP_CTL_A 0x330A -+#define OV2650_ISP_CTL_B 0x330B -+#define OV2650_ISP_CTL_10 0x3310 -+#define OV2650_ISP_CTL_11 0x3311 -+#define OV2650_ISP_CTL_12 0x3312 -+#define OV2650_ISP_CTL_13 0x3313 -+#define OV2650_ISP_CTL_14 0x3314 -+#define OV2650_ISP_CTL_15 0x3315 -+#define OV2650_ISP_CTL_16 0x3316 -+#define OV2650_ISP_CTL_17 0x3317 -+#define OV2650_ISP_CTL_18 0x3318 -+#define OV2650_ISP_CTL_19 0x3319 -+#define OV2650_ISP_CTL_1A 0x331A -+#define OV2650_ISP_CTL_1B 0x331B -+#define OV2650_ISP_CTL_1C 0x331C -+#define OV2650_ISP_CTL_1D 0x331D -+#define OV2650_ISP_CTL_1E 0x331E -+#define OV2650_ISP_CTL_20 0x3320 -+#define OV2650_ISP_CTL_21 0x3321 -+#define OV2650_ISP_CTL_22 0x3322 -+#define OV2650_ISP_CTL_23 0x3323 -+#define OV2650_ISP_CTL_24 0x3324 -+#define OV2650_ISP_CTL_27 0x3327 -+#define OV2650_ISP_CTL_28 0x3328 -+#define OV2650_ISP_CTL_29 0x3329 -+#define OV2650_ISP_CTL_2A 0x332A -+#define OV2650_ISP_CTL_2B 0x332B -+#define OV2650_ISP_CTL_2C 0x332C -+#define OV2650_ISP_CTL_2D 0x332D -+#define OV2650_ISP_CTL_2E 0x332E -+#define OV2650_ISP_CTL_2F 0x332F -+#define OV2650_ISP_CTL_30 0x3330 -+#define OV2650_ISP_CTL_31 0x3331 -+#define OV2650_ISP_CTL_32 0x3332 -+#define OV2650_ISP_CTL_33 0x3333 -+#define OV2650_ISP_CTL_34 0x3334 -+#define OV2650_ISP_CTL_35 0x3335 -+#define OV2650_ISP_CTL_36 0x3336 -+#define OV2650_ISP_CTL_40 0x3340 -+#define OV2650_ISP_CTL_41 0x3341 -+#define OV2650_ISP_CTL_42 0x3342 -+#define OV2650_ISP_CTL_43 0x3343 -+#define OV2650_ISP_CTL_44 0x3344 -+#define OV2650_ISP_CTL_45 0x3345 -+#define OV2650_ISP_CTL_46 0x3346 -+#define OV2650_ISP_CTL_47 0x3347 -+#define OV2650_ISP_CTL_48 0x3348 -+#define OV2650_ISP_CTL_49 0x3349 -+#define OV2650_ISP_CTL_4A 0x334A -+#define OV2650_ISP_CTL_4B 0x334B -+#define OV2650_ISP_CTL_4C 0x334C -+#define OV2650_ISP_CTL_4D 0x334D -+#define OV2650_ISP_CTL_4E 0x334E -+#define OV2650_ISP_CTL_4F 0x334F -+#define OV2650_ISP_CTL_50 0x3350 -+#define OV2650_ISP_CTL_51 0x3351 -+#define OV2650_ISP_CTL_52 0x3352 -+#define OV2650_ISP_CTL_53 0x3353 -+#define OV2650_ISP_CTL_54 0x3354 -+#define OV2650_ISP_CTL_55 0x3355 -+#define OV2650_ISP_CTL_56 0x3356 -+#define OV2650_ISP_CTL_57 0x3357 -+#define OV2650_ISP_CTL_58 0x3358 -+#define OV2650_ISP_CTL_59 0x3359 -+#define OV2650_ISP_CTL_5A 0x335A -+#define OV2650_ISP_CTL_5B 0x335B -+#define OV2650_ISP_CTL_5C 0x335C -+#define OV2650_ISP_CTL_5D 0x335D -+#define OV2650_ISP_CTL_5E 0x335E -+#define OV2650_ISP_CTL_5F 0x335F -+#define OV2650_ISP_CTL_60 0x3360 -+#define OV2650_ISP_CTL_61 0x3361 -+#define OV2650_ISP_CTL_62 0x3362 -+#define OV2650_ISP_CTL_63 0x3363 -+#define OV2650_ISP_CTL_64 0x3364 -+#define OV2650_ISP_CTL_65 0x3365 -+#define OV2650_ISP_CTL_6A 0x336A -+#define OV2650_ISP_CTL_6B 0x336B -+#define OV2650_ISP_CTL_6C 0x336C -+#define OV2650_ISP_CTL_6E 0x336E -+#define OV2650_ISP_CTL_71 0x3371 -+#define OV2650_ISP_CTL_72 0x3372 -+#define OV2650_ISP_CTL_73 0x3373 -+#define OV2650_ISP_CTL_74 0x3374 -+#define OV2650_ISP_CTL_75 0x3375 -+#define OV2650_ISP_CTL_76 0x3376 -+#define OV2650_ISP_CTL_77 0x3377 -+#define OV2650_ISP_CTL_78 0x3378 -+#define OV2650_ISP_CTL_79 0x3379 -+#define OV2650_ISP_CTL_7A 0x337A -+#define OV2650_ISP_CTL_7B 0x337B -+#define OV2650_ISP_CTL_7C 0x337C -+#define OV2650_ISP_CTL_80 0x3380 -+#define OV2650_ISP_CTL_81 0x3381 -+#define OV2650_ISP_CTL_82 0x3382 -+#define OV2650_ISP_CTL_83 0x3383 -+#define OV2650_ISP_CTL_84 0x3384 -+#define OV2650_ISP_CTL_85 0x3385 -+#define OV2650_ISP_CTL_86 0x3386 -+#define OV2650_ISP_CTL_87 0x3387 -+#define OV2650_ISP_CTL_88 0x3388 -+#define OV2650_ISP_CTL_89 0x3389 -+#define OV2650_ISP_CTL_8A 0x338A -+#define OV2650_ISP_CTL_8B 0x338B -+#define OV2650_ISP_CTL_8C 0x338C -+#define OV2650_ISP_CTL_8D 0x338D -+#define OV2650_ISP_CTL_8E 0x338E -+#define OV2650_ISP_CTL_90 0x3390 -+#define OV2650_ISP_CTL_91 0x3391 -+#define OV2650_ISP_CTL_92 0x3392 -+#define OV2650_ISP_CTL_93 0x3393 -+#define OV2650_ISP_CTL_94 0x3394 -+#define OV2650_ISP_CTL_95 0x3395 -+#define OV2650_ISP_CTL_96 0x3396 -+#define OV2650_ISP_CTL_97 0x3397 -+#define OV2650_ISP_CTL_98 0x3398 -+#define OV2650_ISP_CTL_99 0x3399 -+#define OV2650_ISP_CTL_9A 0x339A -+#define OV2650_ISP_CTL_A0 0x33A0 -+#define OV2650_ISP_CTL_A1 0x33A1 -+#define OV2650_ISP_CTL_A2 0x33A2 -+#define OV2650_ISP_CTL_A3 0x33A3 -+#define OV2650_ISP_CTL_A4 0x33A4 -+#define OV2650_ISP_CTL_A5 0x33A5 -+#define OV2650_ISP_CTL_A6 0x33A6 -+#define OV2650_ISP_CTL_A7 0x33A7 -+#define OV2650_ISP_CTL_A8 0x33A8 -+#define OV2650_ISP_CTL_AA 0x33AA -+#define OV2650_ISP_CTL_AB 0x33AB -+#define OV2650_ISP_CTL_AC 0x33AC -+#define OV2650_ISP_CTL_AD 0x33AD -+#define OV2650_ISP_CTL_AE 0x33AE -+#define OV2650_ISP_CTL_AF 0x33AF -+#define OV2650_ISP_CTL_B0 0x33B0 -+#define OV2650_ISP_CTL_B1 0x33B1 -+#define OV2650_ISP_CTL_B2 0x33B2 -+#define OV2650_ISP_CTL_B3 0x33B3 -+#define OV2650_ISP_CTL_B4 0x33B4 -+#define OV2650_ISP_CTL_B5 0x33B5 -+#define OV2650_ISP_CTL_B6 0x33B6 -+#define OV2650_ISP_CTL_B7 0x33B7 -+#define OV2650_ISP_CTL_B8 0x33B8 -+#define OV2650_ISP_CTL_B9 0x33B9 -+ -+/* Format register */ -+#define OV2650_FMT_CTL_0 0x3400 -+#define OV2650_FMT_CTL_1 0x3401 -+#define OV2650_FMT_CTL_2 0x3402 -+#define OV2650_FMT_CTL_3 0x3403 -+#define OV2650_FMT_CTL_4 0x3404 -+#define OV2650_FMT_CTL_5 0x3405 -+#define OV2650_FMT_CTL_6 0x3406 -+#define OV2650_FMT_CTL_7 0x3407 -+#define OV2650_FMT_CTL_8 0x3408 -+#define OV2650_DITHER_CTL 0x3409 -+#define OV2650_DVP_CTL_0 0x3600 -+#define OV2650_DVP_CTL_1 0x3601 -+#define OV2650_DVP_CTL_6 0x3606 -+#define OV2650_DVP_CTL_7 0x3607 -+#define OV2650_DVP_CTL_9 0x3609 -+#define OV2650_DVP_CTL_B 0x360B -+ -+/* General definition for ov2650 */ -+#define OV2650_OUTWND_MAX_H UXGA_SIZE_H -+#define OV2650_OUTWND_MAX_V UXGA_SIZE_V -+ -+struct regval_list { -+ u16 reg_num; -+ u8 value; -+}; -+ -+/* -+ * Default register value -+ * 1600x1200 YUV -+ */ -+static struct regval_list ov2650_def_reg[] = { -+ {0x3012, 0x80}, -+ {0x308c, 0x80}, -+ {0x308d, 0x0e}, -+ {0x360b, 0x00}, -+ {0x30b0, 0xff}, -+ {0x30b1, 0xff}, -+ {0x30b2, 0x27}, -+ -+ {0x300e, 0x34}, -+ {0x300f, 0xa6}, -+ {0x3010, 0x81}, -+ {0x3082, 0x01}, -+ {0x30f4, 0x01}, -+ {0x3090, 0x33}, -+ {0x3091, 0xc0}, -+ {0x30ac, 0x42}, -+ -+ {0x30d1, 0x08}, -+ {0x30a8, 0x56}, -+ {0x3015, 0x03}, -+ {0x3093, 0x00}, -+ {0x307e, 0xe5}, -+ {0x3079, 0x00}, -+ {0x30aa, 0x42}, -+ {0x3017, 0x40}, -+ {0x30f3, 0x82}, -+ {0x306a, 0x0c}, -+ {0x306d, 0x00}, -+ {0x336a, 0x3c}, -+ {0x3076, 0x6a}, -+ {0x30d9, 0x8c}, -+ {0x3016, 0x82}, -+ {0x3601, 0x30}, -+ {0x304e, 0x88}, -+ {0x30f1, 0x82}, -+ {0x3011, 0x02}, -+ -+ {0x3013, 0xf7}, -+ {0x301c, 0x13}, -+ {0x301d, 0x17}, -+ {0x3070, 0x3e}, -+ {0x3072, 0x34}, -+ -+ {0x30af, 0x00}, -+ {0x3048, 0x1f}, -+ {0x3049, 0x4e}, -+ {0x304a, 0x20}, -+ {0x304f, 0x20}, -+ {0x304b, 0x02}, -+ {0x304c, 0x00}, -+ {0x304d, 0x02}, -+ {0x304f, 0x20}, -+ {0x30a3, 0x10}, -+ {0x3013, 0xf7}, -+ {0x3014, 0x44}, -+ {0x3071, 0x00}, -+ {0x3070, 0x3e}, -+ {0x3073, 0x00}, -+ {0x3072, 0x34}, -+ {0x301c, 0x12}, -+ {0x301d, 0x16}, -+ {0x304d, 0x42}, -+ {0x304a, 0x40}, -+ {0x304f, 0x40}, -+ {0x3095, 0x07}, -+ {0x3096, 0x16}, -+ {0x3097, 0x1d}, -+ -+ {0x3020, 0x01}, -+ {0x3021, 0x18}, -+ {0x3022, 0x00}, -+ {0x3023, 0x0a}, -+ {0x3024, 0x06}, -+ {0x3025, 0x58}, -+ {0x3026, 0x04}, -+ {0x3027, 0xbc}, -+ {0x3088, 0x06}, -+ {0x3089, 0x40}, -+ {0x308a, 0x04}, -+ {0x308b, 0xb0}, -+ {0x3316, 0x64}, -+ {0x3317, 0x4b}, -+ {0x3318, 0x00}, -+ {0x331a, 0x64}, -+ {0x331b, 0x4b}, -+ {0x331c, 0x00}, -+ {0x3100, 0x00}, -+ -+ {0x3320, 0xfa}, -+ {0x3321, 0x11}, -+ {0x3322, 0x92}, -+ {0x3323, 0x01}, -+ {0x3324, 0x97}, -+ {0x3325, 0x02}, -+ {0x3326, 0xff}, -+ {0x3327, 0x0c}, -+ {0x3328, 0x10}, -+ {0x3329, 0x10}, -+ {0x332a, 0x58}, -+ {0x332b, 0x50}, -+ {0x332c, 0xbe}, -+ {0x332d, 0xe1}, -+ {0x332e, 0x43}, -+ {0x332f, 0x36}, -+ {0x3330, 0x4d}, -+ {0x3331, 0x44}, -+ {0x3332, 0xf8}, -+ {0x3333, 0x0a}, -+ {0x3334, 0xf0}, -+ {0x3335, 0xf0}, -+ {0x3336, 0xf0}, -+ {0x3337, 0x40}, -+ {0x3338, 0x40}, -+ {0x3339, 0x40}, -+ {0x333a, 0x00}, -+ {0x333b, 0x00}, -+ -+ {0x3380, 0x28}, -+ {0x3381, 0x48}, -+ {0x3382, 0x10}, -+ {0x3383, 0x23}, -+ {0x3384, 0xc0}, -+ {0x3385, 0xe5}, -+ {0x3386, 0xc2}, -+ {0x3387, 0xb3}, -+ {0x3388, 0x0e}, -+ {0x3389, 0x98}, -+ {0x338a, 0x01}, -+ -+ {0x3340, 0x0e}, -+ {0x3341, 0x1a}, -+ {0x3342, 0x31}, -+ {0x3343, 0x45}, -+ {0x3344, 0x5a}, -+ {0x3345, 0x69}, -+ {0x3346, 0x75}, -+ {0x3347, 0x7e}, -+ {0x3348, 0x88}, -+ {0x3349, 0x96}, -+ {0x334a, 0xa3}, -+ {0x334b, 0xaf}, -+ {0x334c, 0xc4}, -+ {0x334d, 0xd7}, -+ {0x334e, 0xe8}, -+ {0x334f, 0x20}, -+ -+ {0x3350, 0x32}, -+ {0x3351, 0x25}, -+ {0x3352, 0x80}, -+ {0x3353, 0x1e}, -+ {0x3354, 0x00}, -+ {0x3355, 0x85}, -+ {0x3356, 0x32}, -+ {0x3357, 0x25}, -+ {0x3358, 0x80}, -+ {0x3359, 0x1b}, -+ {0x335a, 0x00}, -+ {0x335b, 0x85}, -+ {0x335c, 0x32}, -+ {0x335d, 0x25}, -+ {0x335e, 0x80}, -+ {0x335f, 0x1b}, -+ {0x3360, 0x00}, -+ {0x3361, 0x85}, -+ {0x3363, 0x70}, -+ {0x3364, 0x7f}, -+ {0x3365, 0x00}, -+ {0x3366, 0x00}, -+ -+ {0x3301, 0xff}, -+ {0x338B, 0x11}, -+ {0x338c, 0x10}, -+ {0x338d, 0x40}, -+ -+ {0x3370, 0xd0}, -+ {0x3371, 0x00}, -+ {0x3372, 0x00}, -+ {0x3373, 0x40}, -+ {0x3374, 0x10}, -+ {0x3375, 0x10}, -+ {0x3376, 0x04}, -+ {0x3377, 0x00}, -+ {0x3378, 0x04}, -+ {0x3379, 0x80}, -+ -+ {0x3069, 0x84}, -+ {0x307c, 0x10}, -+ {0x3087, 0x02}, -+ -+ {0x3300, 0xfc}, -+ {0x3302, 0x01}, -+ {0x3400, 0x00}, -+ {0x3606, 0x20}, -+ {0x3601, 0x30}, -+ {0x30f3, 0x83}, -+ {0x304e, 0x88}, -+ -+ {0x3086, 0x0f}, -+ {0x3086, 0x00}, -+ -+ {0xffff, 0xff}, -+}; -+ -+/* 800x600 */ -+static struct regval_list ov2650_res_svga[] = { -+ -+ {0x306f, 0x14}, -+ {0x302a, 0x02}, -+ {0x302b, 0x84}, -+ {0x3012, 0x10}, -+ {0x3011, 0x01}, -+ -+ {0x3070, 0x5d}, -+ {0x3072, 0x4d}, -+ -+ {0x3014, 0x84}, -+ {0x301c, 0x07}, -+ {0x301d, 0x09}, -+ {0x3070, 0x50}, -+ {0x3071, 0x00}, -+ {0x3072, 0x42}, -+ {0x3073, 0x00}, -+ -+ {0x3020, 0x01}, -+ {0x3021, 0x18}, -+ {0x3022, 0x00}, -+ {0x3023, 0x06}, -+ {0x3024, 0x06}, -+ {0x3025, 0x58}, -+ {0x3026, 0x02}, -+ {0x3027, 0x5e}, -+ {0x3088, 0x03}, -+ {0x3089, 0x20}, -+ {0x308a, 0x02}, -+ {0x308b, 0x58}, -+ {0x3316, 0x64}, -+ {0x3317, 0x25}, -+ {0x3318, 0x80}, -+ {0x3319, 0x08}, -+ {0x331a, 0x64}, -+ {0x331b, 0x4b}, -+ {0x331c, 0x00}, -+ {0x331d, 0x38}, -+ {0x3100, 0x00}, -+ -+ {0x3302, 0x11}, -+ -+ {0x3011, 0x01}, -+ {0x300f, 0xa6}, -+ {0x300e, 0x36}, -+ {0x3010, 0x81}, -+ {0x302e, 0x00}, -+ {0x302d, 0x00}, -+ {0x302c, 0x00}, -+ {0x302b, 0x84}, -+ {0x3014, 0x84}, -+ {0x301c, 0x07}, -+ {0x301d, 0x09}, -+ {0x3070, 0x50}, -+ {0x3071, 0x00}, -+ {0x3072, 0x42}, -+ {0x3073, 0x00}, -+ -+ {0x3086, 0x0f}, -+ {0x3086, 0x00}, -+ {0xffff, 0xff}, -+}; -+ -+/* 640x480 */ -+static struct regval_list ov2650_res_vga_vario[] = { -+ {0x306f, 0x14}, -+ {0x302a, 0x02}, -+ {0x302b, 0x6a}, -+ {0x3012, 0x10}, -+ {0x3011, 0x01}, -+ -+ {0x3070, 0x5d}, -+ {0x3072, 0x4d}, -+ -+ {0x301c, 0x05}, -+ {0x301d, 0x06}, -+ -+ {0x3020, 0x01}, -+ {0x3021, 0x18}, -+ {0x3022, 0x00}, -+ {0x3023, 0x06}, -+ {0x3024, 0x06}, -+ {0x3025, 0x58}, -+ {0x3026, 0x02}, -+ {0x3027, 0x61}, -+ {0x3088, 0x02}, -+ {0x3089, 0x80}, -+ {0x308a, 0x01}, -+ {0x308b, 0xe0}, -+ {0x3316, 0x64}, -+ {0x3317, 0x25}, -+ {0x3318, 0x80}, -+ {0x3319, 0x08}, -+ {0x331a, 0x28}, -+ {0x331b, 0x1e}, -+ {0x331c, 0x00}, -+ {0x331d, 0x38}, -+ {0x3100, 0x00}, -+ -+ {0x3302, 0x11}, -+ {0x3011, 0x00}, -+ -+ {0x3014, 0x84}, /* note this */ -+ {0x3086, 0x0f}, -+ {0x3086, 0x00}, -+ {0xffff, 0xff}, -+}; -+ -+/* 640x480 reverse */ -+/* -+static struct regval_list ov2650_res_vga_reverse[] = { -+ {0x306f, 0x10}, -+ {0x302a, 0x04}, -+ {0x302b, 0xd4}, -+ {0x3012, 0x00}, -+ {0x3011, 0x02}, -+ -+ {0x3070, 0x3e}, -+ {0x3072, 0x34}, -+ -+ {0x301c, 0x12}, -+ {0x301d, 0x16}, -+ -+ {0x3020, 0x01}, -+ {0x3021, 0x18}, -+ {0x3022, 0x00}, -+ {0x3023, 0x0a}, -+ {0x3024, 0x06}, -+ {0x3025, 0x58}, -+ {0x3026, 0x04}, -+ {0x3027, 0xbc}, -+ {0x3088, 0x06}, -+ {0x3089, 0x40}, -+ {0x308a, 0x04}, -+ {0x308b, 0xb0}, -+ {0x3316, 0x64}, -+ {0x3317, 0xb4}, -+ {0x3318, 0x00}, -+ {0x3319, 0x6c}, -+ {0x331a, 0x64}, -+ {0x331b, 0x4b}, -+ {0x331c, 0x00}, -+ {0x331d, 0x6c}, -+ {0x3100, 0x00}, -+ -+ {0x3302, 0x01}, -+ {0x3011, 0x02}, -+ -+ {0x3014, 0x44}, -+ {0x3086, 0x0f}, -+ {0x3086, 0x00}, -+ {0xffff, 0xff}, -+}; -+ -+*/ -+/* 320x240 */ -+static struct regval_list ov2650_res_qvga[] = { -+ {0x306f, 0x14}, -+ {0x302a, 0x02}, -+ {0x302b, 0x6a}, -+ -+ {0x3012, 0x10}, -+ {0x3011, 0x01}, -+ -+ {0x3070, 0x5d}, -+ {0x3072, 0x4d}, -+ {0x301c, 0x05}, -+ {0x301d, 0x06}, -+ -+ {0x3023, 0x06}, -+ {0x3026, 0x02}, -+ {0x3027, 0x61}, -+ {0x3088, 0x01}, -+ {0x3089, 0x40}, -+ {0x308a, 0x00}, -+ {0x308b, 0xf0}, -+ {0x3316, 0x64}, -+ {0x3317, 0x25}, -+ {0x3318, 0x80}, -+ {0x3319, 0x08}, -+ {0x331a, 0x14}, -+ {0x331b, 0x0f}, -+ {0x331c, 0x00}, -+ {0x331d, 0x38}, -+ {0x3100, 0x00}, -+ -+ {0x3015, 0x02}, /* note this */ -+ {0x3014, 0x84}, -+ {0x3302, 0x11}, -+ {0x3086, 0x0f}, -+ {0x3086, 0x00}, -+ {0xffff, 0xff}, -+}; -+ -+static struct regval_list ov2650_res_uxga[] = { -+ /* Note this added by debug */ -+ {0x3014, 0x84}, -+ {0x301c, 0x13}, -+ {0x301d, 0x17}, -+ {0x3070, 0x40}, -+ {0x3071, 0x00}, -+ {0x3072, 0x36}, -+ {0x3073, 0x00}, -+ -+ {0xffff, 0xff}, -+}; -+ -+static struct regval_list ov2650_res_sxga[] = { -+ {0x3011, 0x02}, -+ -+ {0x3020, 0x01}, -+ {0x3021, 0x18}, -+ {0x3022, 0x00}, -+ {0x3023, 0x0a}, -+ {0x3024, 0x06}, -+ {0x3025, 0x58}, -+ {0x3026, 0x04}, -+ {0x3027, 0xbc}, -+ {0x3088, 0x05}, -+ {0x3089, 0x00}, -+ {0x308a, 0x04}, -+ {0x308b, 0x00}, -+ {0x3316, 0x64}, -+ {0x3317, 0x4b}, -+ {0x3318, 0x00}, -+ {0x331a, 0x50}, -+ {0x331b, 0x40}, -+ {0x331c, 0x00}, -+ -+ {0x3302, 0x11}, -+ -+ {0x3014, 0x84}, -+ {0x301c, 0x13}, -+ {0x301d, 0x17}, -+ {0x3070, 0x40}, -+ {0x3071, 0x00}, -+ {0x3072, 0x36}, -+ {0x3073, 0x00}, -+ -+ {0x3086, 0x0f}, -+ {0x3086, 0x00}, -+ {0xffff, 0xff}, -+}; -diff --git a/drivers/media/video/mrstci/mrstov5630/Kconfig b/drivers/media/video/mrstci/mrstov5630/Kconfig -new file mode 100644 -index 0000000..a28ddc2 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630/Kconfig -@@ -0,0 +1,9 @@ -+config VIDEO_MRST_OV5630 -+ tristate "Moorestown OV5630 RAW Sensor" -+ depends on I2C && VIDEO_MRST_ISP -+ -+ ---help--- -+ Say Y here if your platform support OV5630 RAW Sensor. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mrstov2650.ko. -diff --git a/drivers/media/video/mrstci/mrstov5630/Makefile b/drivers/media/video/mrstci/mrstov5630/Makefile -new file mode 100644 -index 0000000..c67abff ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630/Makefile -@@ -0,0 +1,4 @@ -+mrstov5630-objs = ov5630.o -+obj-$(CONFIG_VIDEO_MRST_OV5630) += mrstov5630.o -+ -+EXTRA_CFLAGS += -I$(src)/../include -diff --git a/drivers/media/video/mrstci/mrstov5630/ov5630.c b/drivers/media/video/mrstci/mrstov5630/ov5630.c -new file mode 100644 -index 0000000..6498153 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630/ov5630.c -@@ -0,0 +1,1153 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ci_sensor_common.h" -+#include "ov5630.h" -+ -+static int mrstov5630_debug; -+module_param(mrstov5630_debug, int, 0644); -+MODULE_PARM_DESC(mrstov5630_debug, "Debug level (0-1)"); -+ -+#define dprintk(level, fmt, arg...) do { \ -+ if (mrstov5630_debug >= level) \ -+ printk(KERN_DEBUG "mrstisp@%s: " fmt "\n", \ -+ __func__, ## arg); } \ -+ while (0) -+ -+#define eprintk(fmt, arg...) \ -+ printk(KERN_ERR "mrstisp@%s: line %d: " fmt "\n", \ -+ __func__, __LINE__, ## arg); -+ -+#define DBG_entering dprintk(2, "entering"); -+#define DBG_leaving dprintk(2, "leaving"); -+#define DBG_line dprintk(2, " line: %d", __LINE__); -+ -+static inline struct ci_sensor_config *to_sensor_config(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct ci_sensor_config, sd); -+} -+ -+/* static int ov5630_set_res(struct i2c_client *c, const int w, const int h); -+ */ -+static struct ov5630_format_struct { -+ __u8 *desc; -+ __u32 pixelformat; -+ struct regval_list *regs; -+} ov5630_formats[] = { -+ { -+ .desc = "Raw RGB Bayer", -+ .pixelformat = SENSOR_MODE_BAYER, -+ .regs = NULL, -+ }, -+}; -+#define N_OV5630_FMTS ARRAY_SIZE(ov5630_formats) -+ -+static struct ov5630_res_struct { -+ __u8 *desc; -+ int res; -+ int width; -+ int height; -+ /* FIXME: correct the fps values.. */ -+ int fps; -+ bool used; -+ struct regval_list *regs; -+} ov5630_res[] = { -+ { -+ .desc = "QSXGA_PLUS4", -+ .res = SENSOR_RES_QXGA_PLUS, -+ .width = 2592, -+ .height = 1944, -+ .fps = 15, -+ .used = 0, -+ .regs = ov5630_res_qsxga_plus4, -+ }, -+ { -+ .desc = "1080P", -+ .res = SENSOR_RES_1080P, -+ .width = 1920, -+ .height = 1080, -+ .fps = 25, -+ .used = 0, -+ .regs = ov5630_res_1080p, -+ }, -+ { -+ .desc = "XGA_PLUS", -+ .res = SENSOR_RES_XGA_PLUS, -+ .width = 1280, -+ .height = 960, -+ .fps = 30, -+ .used = 0, -+ .regs = ov5630_res_xga_plus, -+ }, -+ { -+ .desc = "720p", -+ .res = SENSOR_RES_720P, -+ .width = 1280, -+ .height = 720, -+ .fps = 34, -+ .used = 0, -+ .regs = ov5630_res_720p, -+ }, -+ { -+ .desc = "VGA", -+ .res = SENSOR_RES_VGA, -+ .width = 640, -+ .height = 480, -+ .fps = 39, -+ .used = 0, -+ .regs = ov5630_res_vga_ac04_bill, -+ }, -+}; -+ -+#define N_RES (ARRAY_SIZE(ov5630_res)) -+ -+/* -+ * I2C Read & Write stuff -+ */ -+static int ov5630_read(struct i2c_client *c, u32 reg, u32 *value) -+{ -+ int ret; -+ int i; -+ struct i2c_msg msg[2]; -+ u8 msgbuf[2]; -+ u8 ret_val = 0; -+ *value = 0; -+ /* Read needs two message to go */ -+ memset(&msg, 0, sizeof(msg)); -+ msgbuf[0] = 0; -+ msgbuf[1] = 0; -+ i = 0; -+ -+ msgbuf[i++] = ((u16)reg) >> 8; -+ msgbuf[i++] = ((u16)reg) & 0xff; -+ msg[0].addr = c->addr; -+ msg[0].buf = msgbuf; -+ msg[0].len = i; -+ -+ msg[1].addr = c->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].buf = &ret_val; -+ msg[1].len = 1; -+ -+ ret = i2c_transfer(c->adapter, &msg[0], 2); -+ *value = ret_val; -+ -+ ret = (ret == 2) ? 0 : -1; -+ return ret; -+} -+ -+static int ov5630_write(struct i2c_client *c, u32 reg, u32 value) -+{ -+ int ret, i; -+ struct i2c_msg msg; -+ u8 msgbuf[3]; -+ -+ /* Writing only needs one message */ -+ memset(&msg, 0, sizeof(msg)); -+ i = 0; -+ msgbuf[i++] = ((u16)reg) >> 8; -+ msgbuf[i++] = (u16)reg & 0xff; -+ msgbuf[i++] = (u8)value; -+ -+ msg.addr = c->addr; -+ msg.flags = 0; -+ msg.buf = msgbuf; -+ msg.len = i; -+ -+ ret = i2c_transfer(c->adapter, &msg, 1); -+ -+ /* If this is a reset register, wait for 1ms */ -+ if (reg == OV5630_SYS && (value & 0x80)) -+ msleep(3); -+ -+ ret = (ret == 1) ? 0 : -1; -+ return ret; -+} -+ -+static int ov5630_write_array(struct i2c_client *c, struct regval_list *vals) -+{ -+ struct regval_list *p; -+ u32 read_val = 0; -+ int err_num = 0; -+ int i = 0; -+ p = vals; -+ while (p->reg_num != 0xffff) { -+ ov5630_write(c, (u32)p->reg_num, (u32)p->value); -+ ov5630_read(c, (u32)p->reg_num, &read_val); -+ if (read_val != p->value) -+ err_num++; -+ p++; -+ i++; -+ } -+ return 0; -+} -+ -+/* -+ * Sensor specific helper function -+ */ -+static int ov5630_standby(void) -+{ -+ gpio_set_value(GPIO_STDBY_PIN, 1); -+ /* ov5630_motor_standby(); */ -+ dprintk(1, "PM: standby called\n"); -+ return 0; -+} -+ -+static int ov5630_wakeup(void) -+{ -+ gpio_set_value(GPIO_STDBY_PIN, 0); -+ /* ov5630_motor_wakeup(); */ -+ dprintk(1, "PM: wakeup called\n"); -+ return 0; -+} -+ -+static int ov5630_s_power(struct v4l2_subdev *sd, u32 val) -+{ -+ if (val == 1) -+ ov5630_standby(); -+ if (val == 0) -+ ov5630_wakeup(); -+ return 0; -+} -+ -+static int ov5630_set_img_ctrl(struct i2c_client *c, -+ const struct ci_sensor_config *config) -+{ -+ int err = 0; -+ u32 reg_val = 0; -+ /* struct ci_sensor_config *info = i2c_get_clientdata(c); */ -+ -+ switch (config->blc) { -+ case SENSOR_BLC_OFF: -+ err |= ov5630_read(c, OV5630_ISP_CTL00, ®_val); -+ err |= ov5630_write(c, OV5630_ISP_CTL00, reg_val & 0xFE); -+ break; -+ case SENSOR_BLC_AUTO: -+ err |= ov5630_read(c, OV5630_ISP_CTL00, ®_val); -+ err |= ov5630_write(c, OV5630_ISP_CTL00, reg_val | 0x01); -+ break; -+ } -+ -+ switch (config->agc) { -+ case SENSOR_AGC_AUTO: -+ err |= ov5630_read(c, OV5630_AUTO_1, ®_val); -+ err |= ov5630_write(c, OV5630_AUTO_1, reg_val | 0x04); -+ break; -+ case SENSOR_AGC_OFF: -+ err |= ov5630_read(c, OV5630_AUTO_1, ®_val); -+ err |= ov5630_write(c, OV5630_AUTO_1, reg_val & ~0x04); -+ break; -+ } -+ -+ switch (config->awb) { -+ case SENSOR_AWB_AUTO: -+ err |= ov5630_read(c, OV5630_ISP_CTL00, ®_val); -+ err |= ov5630_write(c, OV5630_ISP_CTL00, reg_val | 0x30); -+ break; -+ case SENSOR_AWB_OFF: -+ err |= ov5630_read(c, OV5630_ISP_CTL00, ®_val); -+ err |= ov5630_write(c, OV5630_ISP_CTL00, reg_val & ~0x30); -+ break; -+ } -+ -+ switch (config->aec) { -+ case SENSOR_AEC_AUTO: -+ err |= ov5630_read(c, OV5630_AUTO_1, ®_val); -+ err |= ov5630_write(c, OV5630_AUTO_1, reg_val | 0xFB); -+ break; -+ case SENSOR_AEC_OFF: -+ err |= ov5630_read(c, OV5630_AUTO_1, ®_val); -+ err |= ov5630_write(c, OV5630_AUTO_1, reg_val & 0xF6); -+ break; -+ } -+ -+ return err; -+} -+ -+static int ov5630_init(struct i2c_client *c) -+{ -+ int ret; -+ struct v4l2_subdev *sd = i2c_get_clientdata(c); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ char *name = ""; -+ -+ /* Fill the configuration structure */ -+ /* Note this default configuration value */ -+ info->mode = ov5630_formats[0].pixelformat; -+ info->res = ov5630_res[0].res; -+ info->type = SENSOR_TYPE_RAW; -+ info->bls = SENSOR_BLS_OFF; -+ info->gamma = SENSOR_GAMMA_OFF; -+ info->cconv = SENSOR_CCONV_OFF; -+ info->blc = SENSOR_BLC_AUTO; -+ info->agc = SENSOR_AGC_AUTO; -+ info->awb = SENSOR_AWB_AUTO; -+ info->aec = SENSOR_AEC_AUTO; -+ /* info->bus_width = SENSOR_BUSWIDTH_10BIT; */ -+ info->bus_width = SENSOR_BUSWIDTH_10BIT_ZZ; -+ info->ycseq = SENSOR_YCSEQ_YCBYCR; -+ /* info->conv422 = SENSOR_CONV422_NOCOSITED; */ -+ info->conv422 = SENSOR_CONV422_COSITED; -+ info->bpat = SENSOR_BPAT_BGBGGRGR; -+ info->field_inv = SENSOR_FIELDINV_NOSWAP; -+ info->field_sel = SENSOR_FIELDSEL_BOTH; -+ info->hpol = SENSOR_HPOL_REFPOS; -+ info->vpol = SENSOR_VPOL_NEG; -+ info->edge = SENSOR_EDGE_RISING; -+ info->flicker_freq = SENSOR_FLICKER_100; -+ info->cie_profile = SENSOR_CIEPROF_F11; -+ name = "ov5630"; -+ memcpy(info->name, name, 7); -+ -+ /* Reset sensor hardware, and implement the setting*/ -+ ret = ov5630_write(c, (u32)OV5630_SYS, (u32)0x80); -+ ret += ov5630_write(c, (u32)OV5630_IMAGE_SYSTEM, (u32)0x00); -+ -+ /* Set registers into default config value */ -+ ret += ov5630_write_array(c, ov5630_def_reg); -+ -+ /* Set MIPI interface */ -+#ifdef OV5630_MIPI -+ ret += ov5630_write_array(c, ov5630_mipi); -+#endif -+ -+ /* turn off AE AEB AGC */ -+ ret += ov5630_set_img_ctrl(c, info); -+ -+ /* streaming */ -+ /* ret += ov5630_write(c, (u32)OV5630_IMAGE_SYSTEM, (u32)0x01); */ -+ /* ret += ov5630_write(c, (u32)0x3096, (u32)0x50); */ -+ /* /ssleep(1); */ -+ -+ /* Added by wen to stop sensor from streaming */ -+ ov5630_write(c, (u32)OV5630_IMAGE_SYSTEM, (u32)0x00); -+ ov5630_write(c, 0x30b0, 0x00); -+ ov5630_write(c, 0x30b1, 0x00); -+ return ret; -+} -+ -+static int distance(struct ov5630_res_struct *res, u32 w, u32 h) -+{ -+ int ret; -+ if (res->width < w || res->height < h) -+ return -1; -+ -+ ret = ((res->width - w) + (res->height - h)); -+ return ret; -+} -+static int ov5630_try_res(u32 *w, u32 *h) -+{ -+ struct ov5630_res_struct *res_index, *p = NULL; -+ int dis, last_dis = ov5630_res->width + ov5630_res->height; -+ -+ DBG_entering; -+ -+ for (res_index = ov5630_res; -+ res_index < ov5630_res + N_RES; -+ res_index++) { -+ if ((res_index->width < *w) || (res_index->height < *h)) -+ break; -+ dis = distance(res_index, *w, *h); -+ if (dis < last_dis) { -+ last_dis = dis; -+ p = res_index; -+ } -+ } -+ -+ if (p == NULL) -+ p = ov5630_res; -+ else if ((p->width < *w) || (p->height < *h)) { -+ if (p != ov5630_res) -+ p--; -+ } -+ -+ if ((w != NULL) && (h != NULL)) { -+ *w = p->width; -+ *h = p->height; -+ } -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static struct ov5630_res_struct *ov5630_to_res(u32 w, u32 h) -+{ -+ struct ov5630_res_struct *res_index; -+ -+ for (res_index = ov5630_res; -+ res_index < ov5630_res + N_RES; -+ res_index++) -+ if ((res_index->width == w) && (res_index->height == h)) -+ break; -+ -+ if (res_index >= ov5630_res + N_RES) -+ res_index--; /* Take the bigger one */ -+ -+ return res_index; -+} -+ -+static int ov5630_try_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ DBG_entering; -+ return ov5630_try_res(&fmt->fmt.pix.width, &fmt->fmt.pix.height); -+ DBG_leaving; -+} -+ -+static int ov5630_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ unsigned short width, height; -+ int index; -+ -+ ci_sensor_res2size(info->res, &width, &height); -+ -+ /* Marked the current sensor res as being "used" */ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == ov5630_res[index].width) && -+ (height == ov5630_res[index].height)) { -+ ov5630_res[index].used = 1; -+ continue; -+ } -+ ov5630_res[index].used = 0; -+ } -+ -+ fmt->fmt.pix.width = width; -+ fmt->fmt.pix.height = height; -+ return 0; -+} -+ -+static int ov5630_set_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -+{ -+ struct i2c_client *c = v4l2_get_subdevdata(sd); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ int ret = 0; -+ struct ov5630_res_struct *res_index; -+ u32 width, height; -+ int index; -+ -+ DBG_entering; -+ -+ width = fmt->fmt.pix.width; -+ height = fmt->fmt.pix.height; -+ -+ dprintk(1, "was told to set fmt (%d x %d) ", width, height); -+ -+ ret = ov5630_try_res(&width, &height); -+ -+ dprintk(1, "setting fmt (%d x %d) ", width, height); -+ -+ res_index = ov5630_to_res(width, height); -+ -+ ov5630_wakeup(); -+ -+ if (res_index->regs) { -+ /* Soft reset camera first*/ -+ ret = ov5630_write(c, (u32)OV5630_SYS, (u32)0x80); -+ -+ /* software sleep/standby */ -+ ret += ov5630_write(c, (u32)OV5630_IMAGE_SYSTEM, (u32)0x00); -+ -+ /* Set registers into default config value */ -+ ret += ov5630_write_array(c, ov5630_def_reg); -+ -+ /* set image resolution */ -+ ret += ov5630_write_array(c, res_index->regs); -+ -+ /* turn off AE AEB AGC */ -+ ret += ov5630_set_img_ctrl(c, info); -+ -+ /* Set MIPI interface */ -+#ifdef OV5630_MIPI -+ ret += ov5630_write_array(c, ov5630_mipi); -+#endif -+ -+ if (res_index->res == SENSOR_RES_VGA) -+ ret += ov5630_write(c, (u32)0x3015, (u32)0x03); -+ -+ /* streaming */ -+ ret = ov5630_write(c, (u32)OV5630_IMAGE_SYSTEM, (u32)0x01); -+ ret = ov5630_write(c, (u32)0x3096, (u32)0x50); -+ -+ info->res = res_index->res; -+ -+ /* Marked current sensor res as being "used" */ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == ov5630_res[index].width) && -+ (height == ov5630_res[index].height)) { -+ ov5630_res[index].used = 1; -+ continue; -+ } -+ ov5630_res[index].used = 0; -+ } -+ -+ for (index = 0; index < N_RES; index++) -+ dprintk(2, "index = %d, used = %d\n", index, -+ ov5630_res[index].used); -+ } else { -+ eprintk("no res for (%d x %d)", width, height); -+ } -+ -+ DBG_leaving; -+ return ret; -+} -+ -+static int ov5630_t_gain(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ u32 v; -+ -+ DBG_entering; -+ -+ dprintk(2, "writing gain %x to 0x3000", value); -+ -+ ov5630_read(client, 0x3000, &v); -+ v = (v & 0x80) + value; -+ ov5630_write(client, 0x3000, v); -+ -+ dprintk(2, "gain %x was writen to 0x3000", v); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int ov5630_t_exposure(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ u32 v; -+ u32 reg_val; -+ -+ DBG_entering; -+ -+ ov5630_read(client, 0x3013, &v); -+ dprintk(2, "0x3013 = %x", v); -+ if (v & 0x05) { -+ /* turn off agc/aec */ -+ v = v & 0xfa; -+ ov5630_write(client, 0x3013, v); -+ /* turn off awb */ -+ ov5630_read(client, OV5630_ISP_CTL00, ®_val); -+ ov5630_write(client, OV5630_ISP_CTL00, reg_val & ~0x30); -+ } -+ ov5630_read(client, 0x3014, &v); -+ dprintk(2, "0x3014 = %x", v); -+ ov5630_read(client, 0x3002, &v); -+ dprintk(2, "0x3002 = %x", v); -+ ov5630_read(client, 0x3003, &v); -+ dprintk(2, "0x3003 = %x", v); -+ -+ dprintk(2, "writing exposure %x to 0x3002/3", value); -+ -+ v = value >> 8; -+ ov5630_write(client, 0x3002, v); -+ dprintk(2, "exposure %x was writen to 0x3002", v); -+ -+ v = value & 0xff; -+ ov5630_write(client, 0x3003, v); -+ dprintk(2, "exposure %x was writen to 0x3003", v); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static struct ov5630_control { -+ struct v4l2_queryctrl qc; -+ int (*query)(struct v4l2_subdev *sd, __s32 *value); -+ int (*tweak)(struct v4l2_subdev *sd, int value); -+} ov5630_controls[] = { -+ { -+ .qc = { -+ .id = V4L2_CID_GAIN, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "global gain", -+ .minimum = 0x0, -+ .maximum = 0xFF, -+ .step = 0x01, -+ .default_value = 0x00, -+ .flags = 0, -+ }, -+ .tweak = ov5630_t_gain, -+/* .query = ov5630_q_gain, */ -+ }, -+ { -+ .qc = { -+ .id = V4L2_CID_EXPOSURE, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "exposure", -+ .minimum = 0x0, -+ .maximum = 0xFFFF, -+ .step = 0x01, -+ .default_value = 0x00, -+ .flags = 0, -+ }, -+ .tweak = ov5630_t_exposure, -+/* .query = ov5630_q_exposure; */ -+ }, -+}; -+#define N_CONTROLS (ARRAY_SIZE(ov5630_controls)) -+ -+/* -+static int ov5630_g_gain(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ unsigned char v; -+ -+ DBG_entering; -+ -+ ov5630_write(client, 0x3000, &v); -+ dprintk(2, "writing gain %x to 0x3000", value); -+ -+ value -+ DBG_leaving; -+ return 0 -+} -+*/ -+ -+static struct ov5630_control *ov5630_find_control(__u32 id) -+{ -+ int i; -+ -+ for (i = 0; i < N_CONTROLS; i++) -+ if (ov5630_controls[i].qc.id == id) -+ return ov5630_controls + i; -+ return NULL; -+} -+ -+static int ov5630_queryctrl(struct v4l2_subdev *sd, -+ struct v4l2_queryctrl *qc) -+{ -+ struct ov5630_control *ctrl = ov5630_find_control(qc->id); -+ -+ if (ctrl == NULL) -+ return -EINVAL; -+ *qc = ctrl->qc; -+ return 0; -+} -+ -+static int ov5630_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ /* -+ struct ov5630_control *octrl = ov5630_find_control(ctrl->id); -+ -+ int ret; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->query(sd, &ctrl->value); -+ if (ret >= 0) -+ return 0; -+ return ret; -+ */ -+ return 0; -+} -+ -+static int ov5630_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ struct ov5630_control *octrl = ov5630_find_control(ctrl->id); -+ int ret; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->tweak(sd, ctrl->value); -+ if (ret >= 0) -+ return 0; -+ return ret; -+} -+ -+#if 0 -+static int ov5630_get_caps(struct i2c_client *c, struct ci_sensor_caps *caps) -+{ -+ if (caps == NULL) -+ return -EIO; -+ -+ caps->bus_width = SENSOR_BUSWIDTH_10BIT; -+ caps->mode = SENSOR_MODE_BAYER; -+ caps->field_inv = SENSOR_FIELDINV_NOSWAP; -+ caps->field_sel = SENSOR_FIELDSEL_BOTH; -+ caps->ycseq = SENSOR_YCSEQ_YCBYCR; -+ caps->conv422 = SENSOR_CONV422_NOCOSITED; -+ caps->bpat = SENSOR_BPAT_BGBGGRGR; -+ caps->hpol = SENSOR_HPOL_REFPOS; -+ caps->vpol = SENSOR_VPOL_NEG; -+ caps->edge = SENSOR_EDGE_RISING; -+ caps->bls = SENSOR_BLS_OFF; -+ caps->gamma = SENSOR_GAMMA_OFF; -+ caps->cconv = SENSOR_CCONV_OFF; -+ caps->res = SENSOR_RES_QXGA_PLUS | SENSOR_RES_1080P | -+ SENSOR_RES_XGA_PLUS | SENSOR_RES_720P | SENSOR_RES_VGA; -+ caps->blc = SENSOR_BLC_OFF; -+ caps->agc = SENSOR_AGC_OFF; -+ caps->awb = SENSOR_AWB_OFF; -+ caps->aec = SENSOR_AEC_OFF; -+ caps->cie_profile = SENSOR_CIEPROF_D65 | SENSOR_CIEPROF_D75 | -+ SENSOR_CIEPROF_F11 | SENSOR_CIEPROF_F12 | SENSOR_CIEPROF_A | -+ SENSOR_CIEPROF_F2; -+ caps->flicker_freq = SENSOR_FLICKER_100 | SENSOR_FLICKER_120; -+ caps->type = SENSOR_TYPE_RAW; -+ /* caps->name = "ov5630"; */ -+ strcpy(caps->name, "ov5630"); -+ -+ return 0; -+} -+ -+static int ov5630_get_config(struct i2c_client *c, -+ struct ci_sensor_config *config) -+{ -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ -+ if (config == NULL) { -+ printk(KERN_WARNING "sensor_get_config: NULL pointer\n"); -+ return -EIO; -+ } -+ -+ memcpy(config, info, sizeof(struct ci_sensor_config)); -+ -+ return 0; -+} -+ -+static int ov5630_setup(struct i2c_client *c, -+ const struct ci_sensor_config *config) -+{ -+ int ret; -+ u16 width, high; -+ struct ov5630_res_struct *res_index; -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ -+ /* Soft reset camera first*/ -+ ret = ov5630_write(c, (u32)OV5630_SYS, (u32)0x80); -+ -+ /* software sleep/standby */ -+ ret = ov5630_write(c, (u32)OV5630_IMAGE_SYSTEM, (u32)0x00); -+ -+ /* Set registers into default config value */ -+ ret = ov5630_write_array(c, ov5630_def_reg); -+ -+ /* set image resolution */ -+ ci_sensor_res2size(config->res, &width, &high); -+ ret += ov5630_try_res(&width, &high); -+ res_index = ov5630_find_res(width, high); -+ if (res_index->regs) -+ ret += ov5630_write_array(c, res_index->regs); -+ if (!ret) -+ info->res = res_index->res; -+ -+ ret += ov5630_set_img_ctrl(c, config); -+ -+ /* Set MIPI interface */ -+#ifdef OV5630_MIPI -+ ret += ov5630_write_array(c, ov5630_mipi); -+#endif -+ -+ /* streaming */ -+ ret += ov5630_write(c, (u32)OV5630_IMAGE_SYSTEM, (u32)0x01); -+ ret += ov5630_write(c, (u32)0x3096, (u32)0x50); -+ -+ /*Note here for the time delay */ -+ /* ssleep(1); */ -+ msleep(500); -+ return ret; -+} -+ -+/* -+ * File operation functions -+ */ -+static int ov5630_dvp_enable(struct i2c_client *client) -+{ -+ int ret; -+ -+ u8 reg; -+ -+ ret = ov5630_read(client, 0x3506, ®); -+ reg &= 0xdf; -+ reg |= 0x20; -+ ret += ov5630_write(client, 0x3506, reg); -+ -+ return ret; -+} -+ -+static int ov5630_dvp_disable(struct i2c_client *client) -+{ -+ int ret; -+ -+ u8 reg; -+ -+ ret = ov5630_read(client, 0x3506, ®); -+ reg &= 0xdf; -+ ret += ov5630_write(client, 0x3506, reg); -+ -+ return ret; -+} -+ -+static int ov5630_open(struct i2c_setting *c, void *priv) -+{ -+ /* Just wake up sensor */ -+ if (ov5630_wakeup()) -+ return -EIO; -+ ov5630_init(c->sensor_client); -+ /* ov5630_motor_init(c->motor_client); */ -+ ov5630_write(c->sensor_client, (u32)OV5630_IMAGE_SYSTEM, (u32)0x00); -+ -+ /* disable dvp_en */ -+ ov5630_dvp_disable(c->sensor_client); -+ -+ return 0; -+} -+ -+static int ov5630_release(struct i2c_setting *c, void *priv) -+{ -+ /* Just suspend the sensor */ -+ if (ov5630_standby()) -+ return -EIO; -+ return 0; -+} -+ -+static int ov5630_on(struct i2c_setting *c) -+{ -+ int ret; -+ -+ /* Software wake up sensor */ -+ ret = ov5630_write(c->sensor_client, -+ (u32)OV5630_IMAGE_SYSTEM, (u32)0x01); -+ -+ /* enable dvp_en */ -+ return ret + ov5630_dvp_enable(c->sensor_client); -+} -+ -+static int ov5630_off(struct i2c_setting *c) -+{ -+ int ret; -+ -+ /* Software standby sensor */ -+ ret = ov5630_write(c->sensor_client, -+ (u32)OV5630_IMAGE_SYSTEM, (u32)0x00); -+ /* disable dvp_en */ -+ return ret + ov5630_dvp_disable(c->sensor_client); -+} -+ -+static struct sensor_device ov5630 = { -+ .name = "ov5630", -+ .type = SENSOR_TYPE_RAW, -+ .minor = -1, -+ .open = ov5630_open, -+ .release = ov5630_release, -+ .on = ov5630_on, -+ .off = ov5630_off, -+ .querycap = ov5630_get_caps, -+ .get_config = ov5630_get_config, -+ .set_config = ov5630_setup, -+ .enum_parm = ov5630_queryctrl, -+ .get_parm = ov5630_g_ctrl, -+ .set_parm = ov5630_s_ctrl, -+ .try_res = ov5630_try_res, -+ .set_res = ov5630_set_res, -+ .get_ls_corr_config = NULL, -+ .mdi_get_focus = ov5630_motor_get_focus, -+ .mdi_set_focus = ov5630_motor_set_focus, -+ .mdi_max_step = ov5630_motor_max_step, -+ .mdi_calibrate = NULL, -+ .read = ov5630_read, -+ .write = ov5630_write, -+ .suspend = ov5630_standby, -+ .resume = ov5630_wakeup, -+ /* TBC */ -+}; -+#endif -+ -+static int ov5630_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ DBG_entering; -+ -+ if (enable) { -+ ov5630_write(client, (u32)OV5630_IMAGE_SYSTEM, (u32)0x01); -+ ov5630_write(client, 0x30b0, 0xff); -+ ov5630_write(client, 0x30b1, 0xff); -+ msleep(500); -+ } else { -+ ov5630_write(client, (u32)OV5630_IMAGE_SYSTEM, (u32)0x00); -+ ov5630_write(client, 0x30b0, 0x00); -+ ov5630_write(client, 0x30b1, 0x00); -+ } -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int ov5630_enum_framesizes(struct v4l2_subdev *sd, -+ struct v4l2_frmsizeenum *fsize) -+{ -+ unsigned int index = fsize->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; -+ fsize->discrete.width = ov5630_res[index].width; -+ fsize->discrete.height = ov5630_res[index].height; -+ fsize->reserved[0] = ov5630_res[index].used; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+ -+static int ov5630_enum_frameintervals(struct v4l2_subdev *sd, -+ struct v4l2_frmivalenum *fival) -+{ -+ unsigned int index = fival->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; -+ fival->discrete.numerator = 1; -+ fival->discrete.denominator = ov5630_res[index].fps; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+ -+static int ov5630_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+#define V4L2_IDENT_OV5630 8245 -+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV5630, 0); -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ov5630_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ unsigned char val = 0; -+ int ret; -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ ret = ov5630_read(client, reg->reg & 0xffff, &val); -+ reg->val = val; -+ reg->size = 1; -+ return ret; -+} -+ -+static int ov5630_s_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ ov5630_write(client, reg->reg & 0xffff, reg->val & 0xff); -+ return 0; -+} -+#endif -+ -+static const struct v4l2_subdev_video_ops ov5630_video_ops = { -+ .try_fmt = ov5630_try_fmt, -+ .s_fmt = ov5630_set_fmt, -+ .g_fmt = ov5630_get_fmt, -+ .s_stream = ov5630_s_stream, -+ .enum_framesizes = ov5630_enum_framesizes, -+ .enum_frameintervals = ov5630_enum_frameintervals, -+}; -+ -+static const struct v4l2_subdev_core_ops ov5630_core_ops = { -+ .g_chip_ident = ov5630_g_chip_ident, -+ .queryctrl = ov5630_queryctrl, -+ .g_ctrl = ov5630_g_ctrl, -+ .s_ctrl = ov5630_s_ctrl, -+ .s_gpio = ov5630_s_power, -+ /*.g_ext_ctrls = ov5630_g_ext_ctrls,*/ -+ /*.s_ext_ctrls = ov5630_s_ext_ctrls,*/ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ov5630_g_register, -+ .s_register = ov5630_s_register, -+#endif -+}; -+ -+static const struct v4l2_subdev_ops ov5630_ops = { -+ .core = &ov5630_core_ops, -+ .video = &ov5630_video_ops, -+}; -+ -+/* -+ * Basic i2c stuff -+ */ -+/* -+static unsigned short normal_i2c[] = {I2C_OV5630 >> 1, -+ I2C_CLIENT_END}; -+I2C_CLIENT_INSMOD; -+ -+static struct i2c_driver ov5630_driver; -+*/ -+static int ov5630_detect(struct i2c_client *client) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ int adap_id = i2c_adapter_id(adapter); -+ u32 value; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { -+ eprintk("error i2c check func"); -+ return -ENODEV; -+ } -+ -+ if (adap_id != 1) { -+ eprintk("adap_id != 1"); -+ return -ENODEV; -+ } -+ -+ /* if (ov5630_wakeup()) */ -+ /* return -ENODEV; */ -+ ov5630_wakeup(); -+ -+ ov5630_read(client, (u32)OV5630_PID_H, &value); -+ if ((u8)value != 0x56) { -+ dprintk(1, "PID != 0x56, but %x", value); -+ dprintk(2, "client->addr = %x", client->addr); -+ return -ENODEV; -+ } -+ -+ printk(KERN_INFO "Init ov5630 sensor success\n"); -+ return 0; -+} -+ -+static int ov5630_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct ci_sensor_config *info; -+ struct v4l2_subdev *sd; -+ int ret = -1; -+/* struct i2c_client *motor; */ -+ -+ DBG_entering; -+ v4l_info(client, "chip found @ 0x%x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ /* -+ * Setup sensor configuration structure -+ */ -+ info = kzalloc(sizeof(struct ci_sensor_config), GFP_KERNEL); -+ if (!info) { -+ eprintk("fail to malloc for ci_sensor_config"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ret = ov5630_detect(client); -+ if (ret) { -+ dprintk(1, "error ov5630_detect"); -+ goto out_free; -+ } -+ -+ sd = &info->sd; -+ v4l2_i2c_subdev_init(sd, client, &ov5630_ops); -+ -+ /* -+ * Initialization OV5630 -+ * then turn into standby mode -+ */ -+ /* ret = ov5630_standby(); */ -+ ret = ov5630_init(client); -+ if (ret) { -+ eprintk("error calling ov5630_init"); -+ goto out_free; -+ } -+ ov5630_standby(); -+ -+ ret = 0; -+ goto out; -+ -+out_free: -+ kfree(info); -+ DBG_leaving; -+out: -+ return ret; -+} -+ -+/* -+ * XXX: Need to be checked -+ */ -+static int ov5630_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ DBG_entering; -+ -+ v4l2_device_unregister_subdev(sd); -+ kfree(to_sensor_config(sd)); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static const struct i2c_device_id ov5630_id[] = { -+ {"ov5630", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, ov5630_id); -+ -+static struct v4l2_i2c_driver_data v4l2_i2c_data = { -+ .name = "ov5630", -+ .probe = ov5630_probe, -+ .remove = ov5630_remove, -+ /* .suspend = ov5630_suspend, -+ * .resume = ov5630_resume, */ -+ .id_table = ov5630_id, -+}; -+ -+MODULE_AUTHOR("Xiaolin Zhang "); -+MODULE_DESCRIPTION("A low-level driver for OmniVision 5630 sensors"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/video/mrstci/mrstov5630/ov5630.h b/drivers/media/video/mrstci/mrstov5630/ov5630.h -new file mode 100644 -index 0000000..3da0ecd ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630/ov5630.h -@@ -0,0 +1,672 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#define I2C_OV5630 0x6C -+/* Should add to kernel source */ -+#define I2C_DRIVERID_OV5630 1046 -+/* GPIO pin on Moorestown */ -+#define GPIO_SCLK_25 44 -+#define GPIO_STB_PIN 47 -+#define GPIO_STDBY_PIN 49 -+#define GPIO_RESET_PIN 50 -+ -+/* System control register */ -+#define OV5630_AGC 0x3000 -+#define OV5630_AGCS 0x3001 -+#define OV5630_AEC_H 0x3002 -+#define OV5630_AEC_L 0x3003 -+#define OV5630_LAEC_H 0x3004 -+#define OV5630_LAEC_L 0x3005 -+#define OV5630_AECS_H 0x3008 -+#define OV5630_AECS_L 0x3009 -+#define OV5630_PID_H 0x300A -+#define OV5630_PID_L 0x300B -+#define OV5630_SCCB_ID 0x300C -+#define OV5630_PLL_1 0x300E -+#define OV5630_PLL_2 0x300F -+#define OV5630_PLL_3 0x3010 -+#define OV5630_PLL_4 0x3011 -+#define OV5630_SYS 0x3012 -+#define OV5630_AUTO_1 0x3013 -+#define OV5630_AUTO_2 0x3014 -+#define OV5630_AUTO_3 0x3015 -+#define OV5630_AUTO_4 0x3016 -+#define OV5630_AUTO_5 0x3017 -+#define OV5630_WPT 0x3018 -+#define OV5630_BPT 0x3019 -+#define OV5630_VPT 0x301A -+#define OV5630_YAVG 0x301B -+#define OV5630_AECG_50 0x301C -+#define OV5630_AECG_60 0x301D -+#define OV5630_ADDVS_H 0x301E -+#define OV5630_ADDVS_L 0x301F -+#define OV5630_FRAME_LENGTH_LINES_H 0x3020 -+#define OV5630_FRAME_LENGTH_LINES_L 0x3021 -+#define OV5630_LINE_LENGTH_PCK_H 0x3022 -+#define OV5630_LINE_LENGTH_PCK_L 0x3023 -+#define OV5630_X_ADDR_START_H 0x3024 -+#define OV5630_X_ADDR_START_L 0x3025 -+#define OV5630_Y_ADDR_START_H 0x3026 -+#define OV5630_Y_ADDR_START_L 0x3027 -+#define OV5630_X_ADDR_END_H 0x3028 -+#define OV5630_X_ADDR_END_L 0x3029 -+#define OV5630_Y_ADDR_END_H 0x302A -+#define OV5630_Y_ADDR_END_L 0x302B -+#define OV5630_X_OUTPUT_SIZE_H 0x302C -+#define OV5630_X_OUTPUT_SIZE_L 0x302D -+#define OV5630_Y_OUTPUT_SIZE_H 0x302E -+#define OV5630_Y_OUTPUT_SIZE_L 0x302F -+#define OV5630_FRAME_CNT 0x3030 -+#define OV5630_DATR_LMO_0 0x3038 -+#define OV5630_DATR_LMO_1 0x3039 -+#define OV5630_DATR_LMO_2 0x303A -+#define OV5630_DATR_D56 0x303D -+#define OV5630_DATR_EF 0x303E -+#define OV5630_R_SIGMA_0 0x3048 -+#define OV5630_R_SIGMA_1 0x3049 -+#define OV5630_R_SIGMA_2 0x304A -+#define OV5630_R_SIGMA_3 0x304B -+#define OV5630_R_SIGMA_4 0x304C -+#define OV5630_R_SIGMA_5 0x304D -+#define OV5630_D56COM 0x304E -+#define OV5630_5060TH 0x3050 -+#define OV5630_LMO_TH1 0x3058 -+#define OV5630_LMO_TH2 0x3059 -+#define OV5630_LMO_K 0x305A -+#define OV5630_BD50ST_H 0x305C -+#define OV5630_BD50ST_L 0x305D -+#define OV5630_BD60ST_H 0x305E -+#define OV5630_BD60ST_L 0x305F -+#define OV5630_HSYNST 0x306D -+#define OV5630_HSYNED 0x306E -+#define OV5630_HSYNED_HSYNST 0x306F -+#define OV5630_TMC_RWIN0 0x3070 -+#define OV5630_IO_CTRL0 0x30B0 -+#define OV5630_IO_CTRL1 0x30B1 -+#define OV5630_IO_CTRL2 0x30B2 -+#define OV5630_DSIO_0 0x30B3 -+#define OV5630_DSIO_1 0x30B4 -+#define OV5630_DSIO_2 0x30B5 -+#define OV5630_TMC_10 0x30B6 -+#define OV5630_TMC_12 0x30B7 -+#define OV5630_TMC_14 0x30B9 -+#define OV5630_TMC_COM4 0x30BA -+#define OV5630_TMC_REG6C 0x30BB -+#define OV5630_TMC_REG6E 0x30BC -+#define OV5630_R_CLK_S 0x30BD -+#define OV5630_R_CLK_A 0x30BE -+#define OV5630_R_CLK_A1 0x30BF -+#define OV5630_FRS_0 0x30E0 -+#define OV5630_FRS_1 0x30E1 -+#define OV5630_FRS_2 0x30E2 -+#define OV5630_FRS_3 0x30E3 -+#define OV5630_FRS_FECNT 0x30E4 -+#define OV5630_FRS_FECNT_0 0x30E5 -+#define OV5630_FRS_FECNT_1 0x30E6 -+#define OV5630_FRS_RFRM 0x30E7 -+#define OV5630_FRS_RSTRB 0x30E8 -+#define OV5630_SA1TMC 0x30E9 -+#define OV5630_TMC_MISC0 0x30EA -+#define OV5630_TMC_MISC1 0x30EB -+#define OV5630_FLEX_TXP 0x30F0 -+#define OV5630_FLEX_FLT 0x30F1 -+#define OV5630_FLEX_TXT 0x30F2 -+#define OV5630_FLEX_HBK 0x30F3 -+#define OV5630_FLEX_HSG 0x30F4 -+#define OV5630_FLEX_SA1SFT 0x30F5 -+#define OV5630_RVSOPT 0x30F6 -+#define OV5630_AUTO 0x30F7 -+#define OV5630_IMAGE_TRANSFORM 0x30F8 -+#define OV5630_IMAGE_LUM 0x30F9 -+#define OV5630_IMAGE_SYSTEM 0x30FA -+#define OV5630_GROUP_WR 0x30FF -+ -+/* CIF control register */ -+#define OV5630_CIF_CTRL2 0x3202 -+ -+/* ISP control register */ -+#define OV5630_ISP_CTL00 0x3300 -+#define OV5630_ISP_CTL01 0x3301 -+#define OV5630_ISP_CTL02 0x3302 -+#define OV5630_ISP_03 0x3303 -+#define OV5630_ISP_DIG_GAIN_MAN 0x3304 -+#define OV5630_ISP_BIAS_MAN 0x3305 -+#define OV5630_ISP_06 0x3306 -+#define OV5630_ISP_STABLE_RANGE 0x3307 -+#define OV5630_ISP_R_GAIN_MAN_1 0x3308 -+#define OV5630_ISP_R_GAIN_MAN_0 0x3309 -+#define OV5630_ISP_G_GAIN_MAN_1 0x330A -+#define OV5630_ISP_G_GAIN_MAN_0 0x330B -+#define OV5630_ISP_B_GAIN_MAN_1 0x330C -+#define OV5630_ISP_B_GAIN_MAN_0 0x330D -+#define OV5630_ISP_STABLE_RANGEW 0x330E -+#define OV5630_ISP_AWB_FRAME_CNT 0x330F -+#define OV5630_ISP_11 0x3311 -+#define OV5630_ISP_12 0x3312 -+#define OV5630_ISP_13 0x3313 -+#define OV5630_ISP_HSIZE_IN_1 0x3314 -+#define OV5630_ISP_HSIZE_IN_0 0x3315 -+#define OV5630_ISP_VSIZE_IN_1 0x3316 -+#define OV5630_ISP_VSIZE_IN_0 0x3317 -+#define OV5630_ISP_18 0x3318 -+#define OV5630_ISP_19 0x3319 -+#define OV5630_ISP_EVEN_MAN0 0x331A -+#define OV5630_ISP_EVEN_MAN1 0x331B -+#define OV5630_ISP_EVEN_MAN2 0x331C -+#define OV5630_ISP_EVEN_MAN3 0x331D -+#define OV5630_ISP_1E 0x331E -+#define OV5630_ISP_1F 0x331F -+#define OV5630_ISP_BLC_LMT_OPTION 0x3320 -+#define OV5630_ISP_BLC_THRE 0x3321 -+#define OV5630_ISP_22 0x3322 -+#define OV5630_ISP_23 0x3323 -+#define OV5630_ISP_BLC_MAN0_1 0x3324 -+#define OV5630_ISP_BLC_MAN0_0 0x3325 -+#define OV5630_ISP_BLC_MAN1_1 0x3326 -+#define OV5630_ISP_BLC_MAN1_0 0x3327 -+#define OV5630_ISP_BLC_MAN2_1 0x3328 -+#define OV5630_ISP_BLC_MAN2_0 0x3329 -+#define OV5630_ISP_BLC_MAN3_1 0x332A -+#define OV5630_ISP_BLC_MAN3_0 0x332B -+#define OV5630_ISP_BLC_MAN4_1 0x332C -+#define OV5630_ISP_BLC_MAN4_0 0x332D -+#define OV5630_ISP_BLC_MAN5_1 0x332E -+#define OV5630_ISP_BLC_MAN5_0 0x332F -+#define OV5630_ISP_BLC_MAN6_1 0x3330 -+#define OV5630_ISP_BLC_MAN6_0 0x3331 -+#define OV5630_ISP_BLC_MAN7_1 0x3332 -+#define OV5630_ISP_BLC_MAN7_0 0x3333 -+#define OV5630_ISP_CD 0x33CD -+#define OV5630_ISP_FF 0x33FF -+ -+/* clipping control register */ -+#define OV5630_CLIP_CTRL0 0x3400 -+#define OV5630_CLIP_CTRL1 0x3401 -+#define OV5630_CLIP_CTRL2 0x3402 -+#define OV5630_CLIP_CTRL3 0x3403 -+#define OV5630_CLIP_CTRL4 0x3404 -+#define OV5630_CLIP_CTRL5 0x3405 -+#define OV5630_CLIP_CTRL6 0x3406 -+#define OV5630_CLIP_CTRL7 0x3407 -+ -+/* DVP control register */ -+#define OV5630_DVP_CTRL00 0x3500 -+#define OV5630_DVP_CTRL01 0x3501 -+#define OV5630_DVP_CTRL02 0x3502 -+#define OV5630_DVP_CTRL03 0x3503 -+#define OV5630_DVP_CTRL04 0x3504 -+#define OV5630_DVP_CTRL05 0x3505 -+#define OV5630_DVP_CTRL06 0x3506 -+#define OV5630_DVP_CTRL07 0x3507 -+#define OV5630_DVP_CTRL08 0x3508 -+#define OV5630_DVP_CTRL09 0x3509 -+#define OV5630_DVP_CTRL0A 0x350A -+#define OV5630_DVP_CTRL0B 0x350B -+#define OV5630_DVP_CTRL0C 0x350C -+#define OV5630_DVP_CTRL0D 0x350D -+#define OV5630_DVP_CTRL0E 0x350E -+#define OV5630_DVP_CTRL0F 0x350F -+#define OV5630_DVP_CTRL10 0x3510 -+#define OV5630_DVP_CTRL11 0x3511 -+#define OV5630_DVP_CTRL12 0x3512 -+#define OV5630_DVP_CTRL13 0x3513 -+#define OV5630_DVP_CTRL14 0x3514 -+#define OV5630_DVP_CTRL15 0x3515 -+#define OV5630_DVP_CTRL16 0x3516 -+#define OV5630_DVP_CTRL17 0x3517 -+#define OV5630_DVP_CTRL18 0x3518 -+#define OV5630_DVP_CTRL19 0x3519 -+#define OV5630_DVP_CTRL1A 0x351A -+#define OV5630_DVP_CTRL1B 0x351B -+#define OV5630_DVP_CTRL1C 0x351C -+#define OV5630_DVP_CTRL1D 0x351D -+#define OV5630_DVP_CTRL1E 0x351E -+#define OV5630_DVP_CTRL1F 0x351F -+ -+/* MIPI control register */ -+#define OV5630_MIPI_CTRL00 0x3600 -+#define OV5630_MIPI_CTRL01 0x3601 -+#define OV5630_MIPI_CTRL02 0x3602 -+#define OV5630_MIPI_CTRL03 0x3603 -+#define OV5630_MIPI_CTRL04 0x3604 -+#define OV5630_MIPI_CTRL05 0x3605 -+#define OV5630_MIPI_CTRL06 0x3606 -+#define OV5630_MIPI_CTRL07 0x3607 -+#define OV5630_MIPI_CTRL08 0x3608 -+#define OV5630_MIPI_CTRL09 0x3609 -+#define OV5630_MIPI_CTRL0A 0x360A -+#define OV5630_MIPI_CTRL0B 0x360B -+#define OV5630_MIPI_CTRL0C 0x360C -+#define OV5630_MIPI_CTRL0D 0x360D -+#define OV5630_MIPI_CTRL0E 0x360E -+#define OV5630_MIPI_CTRL0F 0x360F -+#define OV5630_MIPI_CTRL10 0x3610 -+#define OV5630_MIPI_CTRL11 0x3611 -+#define OV5630_MIPI_CTRL12 0x3612 -+#define OV5630_MIPI_CTRL13 0x3613 -+#define OV5630_MIPI_CTRL14 0x3614 -+#define OV5630_MIPI_CTRL15 0x3615 -+#define OV5630_MIPI_CTRL16 0x3616 -+#define OV5630_MIPI_CTRL17 0x3617 -+#define OV5630_MIPI_CTRL18 0x3618 -+#define OV5630_MIPI_CTRL19 0x3619 -+#define OV5630_MIPI_CTRL1A 0x361A -+#define OV5630_MIPI_CTRL1B 0x361B -+#define OV5630_MIPI_CTRL1C 0x361C -+#define OV5630_MIPI_CTRL1D 0x361D -+#define OV5630_MIPI_CTRL1E 0x361E -+#define OV5630_MIPI_CTRL1F 0x361F -+#define OV5630_MIPI_CTRL20 0x3620 -+#define OV5630_MIPI_CTRL21 0x3621 -+#define OV5630_MIPI_CTRL22 0x3622 -+#define OV5630_MIPI_CTRL23 0x3623 -+#define OV5630_MIPI_CTRL24 0x3624 -+#define OV5630_MIPI_CTRL25 0x3625 -+#define OV5630_MIPI_CTRL26 0x3626 -+#define OV5630_MIPI_CTRL27 0x3627 -+#define OV5630_MIPI_CTRL28 0x3628 -+#define OV5630_MIPI_CTRL29 0x3629 -+#define OV5630_MIPI_CTRL2A 0x362A -+#define OV5630_MIPI_CTRL2B 0x362B -+#define OV5630_MIPI_CTRL2C 0x362C -+#define OV5630_MIPI_CTRL2D 0x362D -+#define OV5630_MIPI_CTRL2E 0x362E -+#define OV5630_MIPI_CTRL2F 0x362F -+#define OV5630_MIPI_CTRL30 0x3630 -+#define OV5630_MIPI_CTRL31 0x3631 -+#define OV5630_MIPI_CTRL32 0x3632 -+#define OV5630_MIPI_CTRL33 0x3633 -+#define OV5630_MIPI_CTRL34 0x3634 -+#define OV5630_MIPI_CTRL35 0x3635 -+#define OV5630_MIPI_CTRL36 0x3636 -+#define OV5630_MIPI_CTRL37 0x3637 -+#define OV5630_MIPI_CTRL38 0x3638 -+#define OV5630_MIPI_CTRL39 0x3639 -+#define OV5630_MIPI_CTRL3A 0x363A -+#define OV5630_MIPI_CTRL3B 0x363B -+#define OV5630_MIPI_CTRL3C 0x363C -+#define OV5630_MIPI_CTRL3D 0x363D -+#define OV5630_MIPI_CTRL3E 0x363E -+#define OV5630_MIPI_CTRL3F 0x363F -+#define OV5630_MIPI_RO61 0x3661 -+#define OV5630_MIPI_RO62 0x3662 -+#define OV5630_MIPI_RO63 0x3663 -+#define OV5630_MIPI_RO64 0x3664 -+#define OV5630_MIPI_RO65 0x3665 -+#define OV5630_MIPI_RO66 0x3666 -+ -+/* General definition for ov5630 */ -+#define OV5630_OUTWND_MAX_H QSXXGA_PLUS4_SIZE_H -+#define OV5630_OUTWND_MAX_V QSXGA_PLUS4_SIZE_V -+ -+struct regval_list { -+ u16 reg_num; -+ u8 value; -+}; -+ -+/* -+ * Default register value -+ * 5Mega Pixel, 2592x1944 -+ */ -+static struct regval_list ov5630_def_reg[] = { -+ {0x300f, 0x00}, /*00*/ -+ {0x30b2, 0x32}, -+ {0x3084, 0x44}, -+ {0x3016, 0x01}, -+ {0x308a, 0x25}, -+ -+ {0x3013, 0xff}, -+ {0x3015, 0x03}, -+ {0x30bf, 0x02}, -+ -+ {0x3065, 0x50}, -+ {0x3068, 0x08}, -+ {0x30ac, 0x05}, -+ {0x309e, 0x24}, -+ {0x3091, 0x04}, -+ -+ {0x3075, 0x22}, -+ {0x3076, 0x23}, -+ {0x3077, 0x24}, -+ {0x3078, 0x25}, -+ -+ {0x30b5, 0x0c}, -+ {0x3090, 0x67}, -+ -+ {0x30f9, 0x11}, -+ {0x3311, 0x80}, -+ {0x3312, 0x1f}, -+ -+ {0x3103, 0x10}, -+ {0x305c, 0x01}, -+ {0x305d, 0x29}, -+ {0x305e, 0x00}, -+ {0x305f, 0xf7}, -+ {0x308d, 0x0b}, -+ {0x30ad, 0x20}, -+ {0x3072, 0x0d}, -+ {0x308b, 0x82}, -+ {0x3317, 0x9c}, -+ {0x3318, 0x22}, -+ {0x3025, 0x20}, -+ {0x3027, 0x08}, -+ {0x3029, 0x3f}, -+ {0x302b, 0xa3}, -+ {0x3319, 0x22}, -+ {0x30a1, 0xc4}, -+ {0x306a, 0x05}, -+ {0x3315, 0x22}, -+ {0x30ae, 0x25}, -+ {0x3304, 0x40}, -+ {0x3099, 0x49}, -+ -+ {0x300e, 0xb1/*b0*/}, /* Note this PLL setting*/ -+ {0x300f, 0x10}, /*00*/ -+ {0x3010, 0x07}, /*change from 0f according to SV */ -+ {0x3011, 0x40}, -+ {0x30af, 0x10}, -+ {0x304a, 0x00}, -+ {0x304d, 0x00}, -+ -+ {0x304e, 0x22}, -+ {0x304d, 0xa0}, -+ {0x3058, 0x00}, -+ {0x3059, 0xff}, -+ {0x305a, 0x00}, -+ -+ {0x30e9, 0x04}, -+ {0x3084, 0x44}, -+ {0x3090, 0x67}, -+ {0x30e9, 0x04}, -+ -+ {0x30b5, 0x1c}, -+ {0x331f, 0x22}, -+ {0x30ae, 0x15}, -+ {0x3304, 0x4c}, -+ -+ {0x3300, 0xfb}, -+ {0x3071, 0x34}, -+ {0x30e7, 0x01}, -+ {0x3302, 0x60}, -+ {0x331e, 0x05}, -+ {0x3321, 0x04}, -+ -+ /* Mark end */ -+ {0xffff, 0xff}, -+ -+}; -+ -+/* MIPI register are removed by Wen */ -+ -+/* 2592x1944 */ -+static struct regval_list ov5630_res_qsxga_plus4[] = { -+ {0x3020, 0x07}, -+ {0x3021, 0xbc}, -+ {0x3022, 0x0c/*0a*/}, -+ {0x3023, 0xa0/*00*/}, -+ {0x305c, 0x01}, -+ {0x305d, 0x29}, -+ {0x305e, 0x00}, -+ {0x305f, 0xf7}, -+ -+ /* 30fps , 96 MHZ*/ -+ /* {0x300f, 0x10}, */ -+ {0x300f, 0x10}, -+ {0x300e, 0xb1}, -+ /* mipi */ -+#ifdef MIPI -+ {0x30b0, 0x00}, -+ {0x30b1, 0xfc}, -+ {0x3603, 0x50}, -+ {0x3601, 0x0F}, -+ /* lan2 bit 10*/ -+ {0x3010, 0x07}, -+ {0x30fa, 0x01}, -+ /* {0x 30f8 09 */ -+ {0x3096, 0x50}, -+ /* end mipi*/ -+#else -+ /* parrral */ -+ {0x30fa, 0x01}, -+#endif -+ /* end post*/ -+ {0xffff, 0xff}, -+}; -+ -+/* 1920x1080 */ -+static struct regval_list ov5630_res_1080p[] = { -+ /*res start*/ -+ {0x3020, 0x04}, -+ {0x3021, 0x5c}, -+ {0x3022, 0x0b/*0a*/}, -+ {0x3023, 0x32/*00*/}, -+ {0x305c, 0x01}, -+ {0x305d, 0x2c}, -+ {0x3024, 0x01}, -+ {0x3025, 0x6e/*70*/}, -+ {0x3026, 0x01}, -+ {0x3027, 0xb8}, -+ {0x3028, 0x08}, -+ {0x3029, 0xef}, -+ {0x302a, 0x05}, -+ {0x302b, 0xf3}, -+ {0x302c, 0x07}, -+ {0x302d, 0x80}, -+ {0x302e, 0x04}, -+ {0x302f, 0x38}, -+ {0x3314, 0x07}, -+ {0x3315, 0x82/*80*/}, -+ {0x3316, 0x04}, -+ {0x3317, 0x3c}, -+ -+ /* 30fps , 96 MHZ*/ -+ {0x300f, 0x10}, /* 00 */ -+ {0x300e, 0xb1}, -+ -+ /* mipi */ -+#ifdef MIPI -+ {0x30b0, 0x00}, -+ {0x30b1, 0xfc}, -+ {0x3603, 0x50}, -+ {0x3601, 0x0F}, -+ /* lan2 bit 10*/ -+ {0x3010, 0x07}, -+ {0x30fa, 0x01}, -+ /* {0x 30f8 09 */ -+ {0x3096, 0x50}, -+ /* end mipi*/ -+#else -+ /* parrral */ -+ {0x30fa, 0x01}, -+#endif -+ /* end post*/ -+ {0xffff, 0xff}, -+}; -+ -+/* 1280x960 V1F2_H1F2 */ -+static struct regval_list ov5630_res_xga_plus[] = { -+ {0x3020, 0x03}, -+ {0x3021, 0xe4}, -+ {0x3022, 0x0c/*07*/}, -+ {0x3023, 0x8c/*76*/}, -+ {0x305c, 0x00}, -+ {0x305d, 0xb1}, -+ {0x3024, 0x00}, -+ {0x3025, 0x30}, -+ {0x3026, 0x00}, -+ {0x3027, 0x10/*14*/}, -+ {0x3028, 0x0a}, -+ {0x3029, 0x2f}, -+ {0x302a, 0x07}, -+ {0x302b, 0xa7/*a7*/}, -+ {0x302c, 0x05}, -+ {0x302d, 0x00}, -+ {0x302e, 0x03}, -+ {0x302f, 0xc0}, -+ -+ {0x30f8, 0x05}, -+ {0x30f9, 0x13}, -+ {0x3314, 0x05}, -+ {0x3315, 0x02/*00*/}, -+ {0x3316, 0x03}, -+ {0x3317, 0xc4}, -+ -+ {0x300f, 0x10}, /* 00 */ -+ {0x300e, 0xb1}, -+ -+#ifdef MIPI -+ {0x30b0, 0x00}, -+ {0x30b1, 0xfc}, -+ {0x3603, 0x50}, -+ {0x3601, 0x0F}, -+ /* lan2 bit 10*/ -+ {0x3010, 0x07}, -+ {0x30fa, 0x01}, -+ /* {0x 30f8 09 */ -+ {0x3096, 0x50}, -+ /* end mipi*/ -+#else -+ /* parrral */ -+ {0x30fa, 0x01}, -+#endif -+ -+ {0xffff, 0xff}, -+}; -+ -+/* 1280x720, V1F2 & H1F2 */ -+static struct regval_list ov5630_res_720p[] = { -+ {0x3020, 0x02}, -+ {0x3021, 0xf4}, -+ {0x3022, 0x07}, -+ {0x3023, 0x80}, -+ {0x305c, 0x00}, -+ {0x305d, 0xff}, -+ {0x305e, 0x00}, -+ {0x305f, 0xd4}, -+ -+ /* Crop then downscale */ -+ {0x3024, 0x00}, -+ {0x3025, 0x2c}, -+ {0x3026, 0x00}, -+ {0x3027, 0xf0}, -+ {0x3028, 0x0a}, -+ {0x3029, 0x2f}, -+ {0x302a, 0x08}, -+ {0x302b, 0x97}, -+ -+ {0x30f8, 0x05}, -+ -+ {0x302c, 0x05}, -+ {0x302d, 0x00}, -+ {0x302e, 0x02}, -+ {0x302f, 0xd0}, -+ -+ {0x30f9, 0x13}, -+ {0x3314, 0x05}, -+ {0x3315, 0x04}, -+ {0x3316, 0x02}, -+ {0x3317, 0xd4}, -+ -+ /* Add this to test setting from OVT */ -+ {0x300f, 0x10}, /*00*/ -+ {0x300e, 0xb0}, -+ -+#ifdef MIPI -+ {0x30b0, 0x00}, -+ {0x30b1, 0xfc}, -+ {0x3603, 0x50}, -+ {0x3601, 0x0F}, -+ /* lan2 bit 10*/ -+ {0x3010, 0x07}, -+ {0x30fa, 0x01}, -+ /* {0x 30f8 09 */ -+ {0x3096, 0x50}, -+ /* end mipi*/ -+#else -+ /* parrral */ -+ {0x30fa, 0x01}, -+#endif -+ -+ {0xffff, 0xff}, -+}; -+ -+/*VGA 40fps now*/ -+static struct regval_list ov5630_res_vga_ac04_bill[] = { -+ /* res setting*/ -+ {0x3020, 0x02}, -+ {0x3021, 0x04}, -+ {0x3022, 0x08}, -+ {0x3023, 0x48}, -+ {0x305c, 0x00}, -+ {0x305d, 0x5e}, -+ {0x3024, 0x00}, -+ {0x3025, 0x2c},/*2c*/ -+ {0x3026, 0x00}, -+ {0x3027, 0x14}, -+ {0x3028, 0x0a}, -+ {0x3029, 0x2f}, -+ {0x302a, 0x07}, -+ {0x302b, 0xa3}, -+ {0x302c, 0x02}, -+ {0x302d, 0x80}, -+ {0x302e, 0x01}, -+ {0x302f, 0xe0}, -+ -+ {0x30b3, 0x09}, -+ {0x3301, 0xc1}, -+ {0x3313, 0xf1}, -+ {0x3314, 0x05}, -+ {0x3315, 0x04},/*04*/ -+ {0x3316, 0x01}, -+ {0x3317, 0xe4}, -+ {0x3318, 0x20}, -+ -+ {0x300f, 0x10/*00*/}, -+ {0x30f8, 0x09}, -+ -+ {0x300f, 0x11}, -+ {0x300e, 0xb2}, -+ -+ {0x3015, 0x02}, -+ /* mipi */ -+#ifdef MIPI -+ {0x30b0, 0x00}, -+ {0x30b1, 0xfc}, -+ {0x3603, 0x50}, -+ {0x3601, 0x0F}, -+ /* lan2 bit 10*/ -+ {0x3010, 0x07}, -+ {0x30fa, 0x01}, -+ /* {0x 30f8 09 */ -+ {0x3096, 0x50}, -+ /* end mipi*/ -+#else -+ -+ /* parrral */ -+ {0x30fa, 0x01}, -+ {0x30f8, 0x09}, -+ {0x3096, 0x50}, -+#endif -+ -+ {0xffff, 0xff}, -+}; -diff --git a/drivers/media/video/mrstci/mrstov5630_motor/Kconfig b/drivers/media/video/mrstci/mrstov5630_motor/Kconfig -new file mode 100644 -index 0000000..b6dcf62 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630_motor/Kconfig -@@ -0,0 +1,9 @@ -+config VIDEO_MRST_OV5630_MOTOR -+ tristate "Moorestown OV5630 motor" -+ depends on I2C && VIDEO_MRST_ISP && VIDEO_MRST_OV5630 -+ -+ ---help--- -+ Say Y here if your platform support OV5630 motor -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mrstov2650.ko. -diff --git a/drivers/media/video/mrstci/mrstov5630_motor/Makefile b/drivers/media/video/mrstci/mrstov5630_motor/Makefile -new file mode 100644 -index 0000000..056b2a6 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630_motor/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_VIDEO_MRST_OV2650) += mrstov5630_motor.o -+ -+EXTRA_CFLAGS += -I$(src)/../include -diff --git a/drivers/media/video/mrstci/mrstov5630_motor/mrstov5630_motor.c b/drivers/media/video/mrstci/mrstov5630_motor/mrstov5630_motor.c -new file mode 100644 -index 0000000..1bb7274 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630_motor/mrstov5630_motor.c -@@ -0,0 +1,428 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ov5630_motor.h" -+ -+/* #define OSPM */ -+#include -+#define PMIC_WRITE1(ipcbuf, reg1, val1) \ -+ do { \ -+ memset(&ipcbuf, 0, sizeof(struct ipc_pmic_reg_data)); \ -+ ipcbuf.ioc = 0; \ -+ ipcbuf.num_entries = 1; \ -+ ipcbuf.pmic_reg_data[0].register_address = reg1; \ -+ ipcbuf.pmic_reg_data[0].value = val1; \ -+ if (ipc_pmic_register_write(&ipcbuf, 1) != 0) { \ -+ return -1; \ -+ } \ -+ } while (0); -+ -+static int mrstov5630_motor_debug; -+module_param(mrstov5630_motor_debug, int, 0644); -+MODULE_PARM_DESC(mrstov5630_motor_debug, "Debug level (0-1)"); -+ -+#define dprintk(level, fmt, arg...) do { \ -+ if (mrstov5630_motor_debug >= level) \ -+ printk(KERN_DEBUG "mrstisp@%s: " fmt "\n", \ -+ __func__, ## arg); } \ -+ while (0) -+ -+#define eprintk(fmt, arg...) \ -+ printk(KERN_ERR "mrstisp@%s: line %d: " fmt "\n", \ -+ __func__, __LINE__, ## arg); -+ -+#define DBG_entering dprintk(2, "entering"); -+#define DBG_leaving dprintk(2, "leaving"); -+#define DBG_line dprintk(2, " line: %d", __LINE__); -+ -+static inline struct ov5630_motor *to_motor_config(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct ov5630_motor, sd); -+} -+ -+static int motor_read(struct i2c_client *c, u16 *reg) -+{ -+ int ret; -+ struct i2c_msg msg; -+ u8 msgbuf[2]; -+ -+ /* Read needs two message to go */ -+ msgbuf[0] = 0; -+ msgbuf[1] = 0; -+ -+ memset(&msg, 0, sizeof(msg)); -+ msg.addr = c->addr; -+ msg.buf = msgbuf; -+ msg.len = 2; -+ msg.flags = I2C_M_RD; -+ -+ ret = i2c_transfer(c->adapter, &msg, 1); -+ -+ *reg = (msgbuf[0] << 8 | msgbuf[1]); -+ -+ ret = (ret == 1) ? 0 : -1; -+ return ret; -+} -+ -+static int motor_write(struct i2c_client *c, u16 reg) -+{ -+ int ret; -+ struct i2c_msg msg; -+ u8 msgbuf[2]; -+ -+ /* Writing only needs one message */ -+ memset(&msg, 0, sizeof(msg)); -+ msgbuf[0] = reg >> 8; -+ msgbuf[1] = reg; -+ -+ msg.addr = c->addr; -+ msg.flags = 0; -+ msg.buf = msgbuf; -+ msg.len = 2; -+ -+ ret = i2c_transfer(c->adapter, &msg, 1); -+ -+ ret = (ret == 1) ? 0 : -1; -+ return ret; -+} -+ -+static int ov5630_motor_goto_position(struct i2c_client *c, -+ unsigned short code, -+ struct ov5630_motor *config) -+{ -+ int max_code, min_code; -+ u8 cmdh, cmdl; -+ u16 cmd, val = 0; -+ -+ max_code = config->macro_code; -+ min_code = config->infin_code; -+ -+ if (code > max_code) -+ code = max_code; -+ if (code < min_code) -+ code = min_code; -+ -+ cmdh = (MOTOR_DAC_CODE_H(code)); -+ cmdl = (MOTOR_DAC_CODE_L(code) | MOTOR_DAC_CTRL_MODE_2(SUB_MODE_4)); -+ cmd = cmdh << 8 | cmdl; -+ -+ motor_write(c, cmd); -+ /*Delay more than full-scale transition time 8.8ms*/ -+ msleep(8); -+ motor_read(c, &val); -+ -+ return (cmd == val ? 0 : -1); -+} -+ -+int ov5630_motor_wakeup(void) -+{ -+ return gpio_direction_output(GPIO_AF_PD, 1); -+} -+ -+int ov5630_motor_standby(void) -+{ -+ return gpio_direction_output(GPIO_AF_PD, 0); -+} -+ -+int ov5630_motor_init(struct i2c_client *client, struct ov5630_motor *config) -+{ -+ int ret; -+ int infin_cur, macro_cur; -+#ifdef OSPM -+ /* Power on motor */ -+ struct ipc_pmic_reg_data ipcbuf; -+ -+ PMIC_WRITE1(ipcbuf, 0x50, 0x27); -+ printk(KERN_WARNING "Power on Vcc33 for motor\n"); -+#endif -+ -+ infin_cur = MAX(MOTOR_INFIN_CUR, MOTOR_DAC_MIN_CUR); -+ macro_cur = MIN(MOTOR_MACRO_CUR, MOTOR_DAC_MAX_CUR); -+ -+ config->infin_cur = infin_cur; -+ config->macro_cur = macro_cur; -+ -+ config->infin_code = (int)((infin_cur * MOTOR_DAC_MAX_CODE) -+ / MOTOR_DAC_MAX_CUR); -+ config->macro_code = (int)((macro_cur * MOTOR_DAC_MAX_CODE) -+ / MOTOR_DAC_MAX_CUR); -+ -+ config->max_step = ((config->macro_code - config->infin_code) -+ >> MOTOR_STEP_SHIFT) + 1; -+ /* Note here, maybe macro_code */ -+ ret = ov5630_motor_goto_position(client, config->infin_code, config); -+ if (!ret) -+ config->cur_code = config->infin_code; -+ else -+ printk(KERN_ERR "Error while initializing motor\n"); -+ -+ return ret; -+} -+ -+int ov5630_motor_set_focus(struct i2c_client *c, int step, -+ struct ov5630_motor *config) -+{ -+ int s_code, ret; -+ int max_step = config->max_step; -+ unsigned int val = step; -+ -+ DBG_entering; -+ dprintk(1, "setting setp %d", step); -+ if (val > max_step) -+ val = max_step; -+ -+ s_code = (val << MOTOR_STEP_SHIFT); -+ s_code += config->infin_code; -+ -+ ret = ov5630_motor_goto_position(c, s_code, config); -+ if (!ret) -+ config->cur_code = s_code; -+ -+ DBG_leaving; -+ return ret; -+} -+ -+static int ov5630_motor_s_ctrl(struct v4l2_subdev *sd, -+ struct v4l2_control *ctrl) -+{ -+ struct i2c_client *c = v4l2_get_subdevdata(sd); -+ struct ov5630_motor *config = to_motor_config(sd); -+ int ret; -+ -+ DBG_entering; -+ ret = ov5630_motor_set_focus(c, ctrl->value, config); -+ if (ret) { -+ eprintk("error call ov5630_motor_set_focue"); -+ return ret; -+ } -+ DBG_leaving; -+ return 0; -+} -+int ov5630_motor_get_focus(struct i2c_client *c, unsigned int *step, -+ struct ov5630_motor *config) -+{ -+ int ret_step; -+ -+ ret_step = ((config->cur_code - config->infin_code) -+ >> MOTOR_STEP_SHIFT); -+ -+ if (ret_step <= config->max_step) -+ *step = ret_step; -+ else -+ *step = config->max_step; -+ -+ return 0; -+} -+ -+static int ov5630_motor_g_ctrl(struct v4l2_subdev *sd, -+ struct v4l2_control *ctrl) -+{ -+ struct i2c_client *c = v4l2_get_subdevdata(sd); -+ struct ov5630_motor *config = to_motor_config(sd); -+ int ret; -+ -+ DBG_entering; -+ dprintk(2, "c = %p, config = %p, ctrl = %p", c, config, ctrl); -+ ret = ov5630_motor_get_focus(c, &ctrl->value, config); -+ if (ret) { -+ eprintk("error call ov5630_motor_get_focue"); -+ return ret; -+ } -+ DBG_leaving; -+ return 0; -+} -+int ov5630_motor_max_step(struct i2c_client *c, unsigned int *max_code, -+ struct ov5630_motor *config) -+{ -+ if (config->max_step != 0) -+ *max_code = config->max_step; -+ return 0; -+} -+ -+static int ov5630_motor_queryctrl(struct v4l2_subdev *sd, -+ struct v4l2_queryctrl *qc) -+{ -+ struct ov5630_motor *config = to_motor_config(sd); -+ -+ DBG_entering; -+ -+ if (qc->id != V4L2_CID_FOCUS_ABSOLUTE) -+ return -EINVAL; -+ -+ dprintk(1, "got focus range of %d", config->max_step); -+ if (config->max_step != 0) -+ qc->maximum = config->max_step; -+ DBG_leaving; -+ return 0; -+} -+static const struct v4l2_subdev_core_ops ov5630_motor_core_ops = { -+ /* -+ .queryctrl = ov5630_queryctrl, -+ .g_ctrl = ov5630_g_ctrl, -+ */ -+ .g_ctrl = ov5630_motor_g_ctrl, -+ .s_ctrl = ov5630_motor_s_ctrl, -+ .queryctrl = ov5630_motor_queryctrl, -+}; -+ -+static const struct v4l2_subdev_ops ov5630_motor_ops = { -+ .core = &ov5630_motor_core_ops, -+}; -+ -+static int ov5630_motor_detect(struct i2c_client *client) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ int adap_id = i2c_adapter_id(adapter); -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { -+ eprintk("error i2c check func"); -+ return -ENODEV; -+ } -+ -+ if (adap_id != 1) { -+ eprintk("adap_id != 1"); -+ return -ENODEV; -+ } -+ -+ /* if (ov5630_motor_wakeup()) */ -+ /* return -ENODEV; */ -+ ov5630_motor_wakeup(); -+ ssleep(1); -+ -+ /* -+ ov5630_motor_read(client, (u32)OV5630_PID_H, &value); -+ if ((u8)value != 0x56) { -+ eprintk("PID != 0x56, but %x", value); -+ dprintk(2, "client->addr = %x", client->addr); -+ return -ENODEV; -+ } -+ */ -+ -+ return 0; -+} -+ -+static int ov5630_motor_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct ov5630_motor *info; -+ struct v4l2_subdev *sd; -+ int ret = -1; -+/* struct i2c_client *motor; */ -+ -+ DBG_entering; -+ v4l_info(client, "chip found @ 0x%x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ /* -+ * Setup sensor configuration structure -+ */ -+ info = kzalloc(sizeof(struct ov5630_motor), GFP_KERNEL); -+ if (!info) { -+ eprintk("fail to malloc for ci_motor"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ret = ov5630_motor_detect(client); -+ if (ret) { -+ eprintk("error ov5630_motor_detect"); -+ goto out_free; -+ } -+ -+ sd = &info->sd; -+ v4l2_i2c_subdev_init(sd, client, &ov5630_motor_ops); -+ -+ /* -+ * Initialization OV5630 -+ * then turn into standby mode -+ */ -+ /* ret = ov5630_motor_standby(); */ -+ ret = ov5630_motor_init(client, info); -+ if (ret) { -+ eprintk("error calling ov5630_motor_init"); -+ goto out_free; -+ } -+ -+ ret = 0; -+ goto out; -+ -+out_free: -+ kfree(info); -+ DBG_leaving; -+out: -+ return ret; -+} -+ -+/* -+ * XXX: Need to be checked -+ */ -+static int ov5630_motor_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ DBG_entering; -+ -+ v4l2_device_unregister_subdev(sd); -+ kfree(to_motor_config(sd)); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static const struct i2c_device_id ov5630_motor_id[] = { -+ {"ov5630_motor", 0}, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, ov5630_motor_id); -+ -+static struct v4l2_i2c_driver_data v4l2_i2c_data = { -+ .name = "ov5630_motor", -+ .probe = ov5630_motor_probe, -+ .remove = ov5630_motor_remove, -+ /* .suspend = ov5630_suspend, -+ * .resume = ov5630_resume, */ -+ .id_table = ov5630_motor_id, -+}; -+MODULE_AUTHOR("Xiaolin Zhang "); -+MODULE_DESCRIPTION("A low-level driver for OmniVision 5630 sensors"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/video/mrstci/mrstov5630_motor/ov5630_motor.h b/drivers/media/video/mrstci/mrstov5630_motor/ov5630_motor.h -new file mode 100644 -index 0000000..302c218 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov5630_motor/ov5630_motor.h -@@ -0,0 +1,86 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+ -+/* VCM start current (mA) */ -+#define MOTOR_INFIN_CUR 15 -+/* VCM max current for Macro (mA) */ -+#define MOTOR_MACRO_CUR 90 -+/* DAC output max current (mA) */ -+#define MOTOR_DAC_MAX_CUR 100 -+/* DAC output min current (mA) */ -+#define MOTOR_DAC_MIN_CUR 3 -+ -+#define MOTOR_DAC_BIT_RES 10 -+#define MOTOR_DAC_MAX_CODE ((1 << MOTOR_DAC_BIT_RES) - 1) -+ -+#define MOTOR_STEP_SHIFT 4 -+ -+#define MAX(x, y) ((x) > (y) ? (x) : (y)) -+#define MIN(x, y) ((x) < (y) ? (x) : (y)) -+ -+/* DAC register related define */ -+#define MOTOR_POWER_DOWN (1 << 7) -+#define PD_ENABLE (1 << 7) -+#define PD_DISABLE (0) -+ -+#define MOTOR_DAC_CODE_H(x) ((x >> 4) & 0x3f) -+#define MOTOR_DAC_CODE_L(x) ((x << 4) & 0xf0) -+ -+#define MOTOR_DAC_CTRL_MODE_0 0x00 -+#define MOTOR_DAC_CTRL_MODE_1(x) (x & 0x07) -+#define MOTOR_DAC_CTRL_MODE_2(x) ((x & 0x07) | 0x08) -+ -+#define SUB_MODE_1 0x01 -+#define SUB_MODE_2 0x02 -+#define SUB_MODE_3 0x03 -+#define SUB_MODE_4 0x04 -+#define SUB_MODE_5 0x05 -+#define SUB_MODE_6 0x06 -+#define SUB_MODE_7 0x07 -+ -+#define OV5630_MOTOR_ADDR (0x18 >> 1) -+#define POWER_EN_PIN 7 -+#define GPIO_AF_PD 95 -+ -+struct ov5630_motor{ -+ unsigned int infin_cur; -+ unsigned int infin_code; -+ unsigned int macro_cur; -+ unsigned int macro_code; -+ unsigned int max_step; -+ unsigned int cur_code; -+ struct v4l2_subdev sd; -+}; -+ -+extern int ov5630_motor_init(struct i2c_client *client, struct ov5630_motor -+ *config); -+extern int ov5630_motor_standby(void); -+extern int ov5630_motor_wakeup(void); -+extern int ov5630_motor_set_focus(struct i2c_client *c, int step, -+ struct ov5630_motor *config); -+extern int ov5630_motor_get_focus(struct i2c_client *c, unsigned int *step, -+ struct ov5630_motor *config); -+extern int ov5630_motor_max_step(struct i2c_client *c, unsigned int *max_code, -+ struct ov5630_motor *config); -diff --git a/drivers/media/video/mrstci/mrstov9665/Kconfig b/drivers/media/video/mrstci/mrstov9665/Kconfig -new file mode 100644 -index 0000000..ba9b692 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov9665/Kconfig -@@ -0,0 +1,9 @@ -+config VIDEO_MRST_OV9665 -+ tristate "Moorestown OV9665 SoC Sensor" -+ depends on I2C && VIDEO_MRST_ISP -+ -+ ---help--- -+ Say Y here if your platform support OV9665 SoC Sensor. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mrstov9665.ko. -diff --git a/drivers/media/video/mrstci/mrstov9665/Makefile b/drivers/media/video/mrstci/mrstov9665/Makefile -new file mode 100644 -index 0000000..871b6bf ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov9665/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_VIDEO_MRST_OV9665) += mrstov9665.o -+ -+EXTRA_CFLAGS += -I$(src)/../include -diff --git a/drivers/media/video/mrstci/mrstov9665/mrstov9665.c b/drivers/media/video/mrstci/mrstov9665/mrstov9665.c -new file mode 100644 -index 0000000..04e553a ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov9665/mrstov9665.c -@@ -0,0 +1,972 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ci_sensor_common.h" -+#include "ov9665.h" -+ -+static int mrstov9665_debug; -+module_param(mrstov9665_debug, int, 0644); -+MODULE_PARM_DESC(mrstov9665_debug, "Debug level (0-1)"); -+ -+#define dprintk(level, fmt, arg...) do { \ -+ if (mrstov9665_debug >= level) \ -+ printk(KERN_DEBUG "mrstisp@%s: " fmt "\n", \ -+ __func__, ## arg); } \ -+ while (0) -+ -+#define eprintk(fmt, arg...) \ -+ printk(KERN_ERR "mrstisp@%s: line %d: " fmt "\n", \ -+ __func__, __LINE__, ## arg); -+ -+#define DBG_entering dprintk(2, "entering"); -+#define DBG_leaving dprintk(2, "leaving"); -+#define DBG_line dprintk(2, " line: %d", __LINE__); -+ -+static inline struct ci_sensor_config *to_sensor_config(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct ci_sensor_config, sd); -+} -+ -+static struct ov9665_format_struct { -+ __u8 *desc; -+ __u32 pixelformat; -+ struct regval_list *regs; -+} ov9665_formats[] = { -+ { -+ .desc = "YUYV 4:2:2", -+ .pixelformat = SENSOR_MODE_BT601, -+ .regs = NULL, -+ }, -+}; -+#define N_OV9665_FMTS ARRAY_SIZE(ov9665_formats) -+ -+static struct ov9665_res_struct { -+ __u8 *desc; -+ int res; -+ int width; -+ int height; -+ /* FIXME: correct the fps values.. */ -+ int fps; -+ bool used; -+ struct regval_list *regs; -+} ov9665_res[] = { -+ { -+ .desc = "SXGA", -+ .res = SENSOR_RES_SXGA, -+ .width = 1280, -+ .height = 1024, -+ .fps = 15, -+ .used = 0, -+ .regs = ov9665_res_sxga, -+ }, -+ { -+ .desc = "VGA", -+ .res = SENSOR_RES_VGA, -+ .width = 640, -+ .height = 480, -+ .fps = 15, -+ .used = 0, -+ .regs = ov9665_res_vga, -+ }, -+}; -+#define N_RES (ARRAY_SIZE(ov9665_res)) -+ -+/* -+ * I2C Read & Write stuff -+ */ -+static int ov9665_read(struct i2c_client *c, unsigned char reg, -+ unsigned char *value) -+{ -+ int ret; -+ -+ ret = i2c_smbus_read_byte_data(c, reg); -+ if (ret >= 0) { -+ *value = (unsigned char) ret; -+ ret = 0; -+ } -+ return ret; -+} -+ -+static int ov9665_write(struct i2c_client *c, unsigned char reg, -+ unsigned char value) -+{ -+ int ret = i2c_smbus_write_byte_data(c, reg, value); -+ if (reg == 0x12 && (value & 0x80)) -+ msleep(2); /* Wait for reset to run */ -+ return ret; -+} -+ -+/* -+ * Write a list of register settings; ff/ff stops the process. -+ */ -+static int ov9665_write_array(struct i2c_client *c, struct regval_list *vals) -+{ -+ struct regval_list *p; -+ u8 read_val = 0; -+ int err_num = 0; -+ int i = 0; -+ p = vals; -+ while (p->reg_num != 0xff) { -+ ov9665_write(c, p->reg_num, p->value); -+ ov9665_read(c, p->reg_num, &read_val); -+ if (read_val != p->value) -+ err_num++; -+ p++; -+ i++; -+ } -+ -+ return 0; -+} -+ -+static int ov9665_set_data_pin_in(struct i2c_client *client) -+{ -+ int ret = 0; -+ -+ ret += ov9665_write(client, 0xd5, 0x00); -+ ret += ov9665_write(client, 0xd6, 0x00); -+ -+ return ret; -+} -+ -+static int ov9665_set_data_pin_out(struct i2c_client *client) -+{ -+ int ret = 0; -+ -+ ret += ov9665_write(client, 0xd5, 0xff); -+ ret += ov9665_write(client, 0xd6, 0xff); -+ -+ return ret; -+} -+/* -+ * Sensor specific helper function -+ */ -+static int ov9665_standby(void) -+{ -+ /* Pull the pin to high to hardware standby */ -+ gpio_set_value(GPIO_STDBY_PIN, 1); -+ dprintk(1, "PM: standby called\n"); -+ return 0; -+} -+ -+static int ov9665_wakeup(void) -+{ -+ /* Pull the pin to low*/ -+ gpio_set_value(GPIO_STDBY_PIN, 0); -+ dprintk(1, "PM: wakeup called\n"); -+ msleep(10); -+ return 0; -+} -+ -+static int ov9665_s_power(struct v4l2_subdev *sd, u32 val) -+{ -+ if (val == 1) -+ ov9665_standby(); -+ if (val == 0) -+ ov9665_wakeup(); -+ return 0; -+} -+ -+static int ov9665_init(struct i2c_client *c) -+{ -+ int ret; -+ struct v4l2_subdev *sd = i2c_get_clientdata(c); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ u8 reg = 0; -+ -+ /* Fill the configuration structure */ -+ /* Note this default configuration value */ -+ info->mode = ov9665_formats[0].pixelformat; -+ info->res = ov9665_res[0].res; -+ info->type = SENSOR_TYPE_SOC; -+ info->bls = SENSOR_BLS_OFF; -+ info->gamma = SENSOR_GAMMA_ON; -+ info->cconv = SENSOR_CCONV_ON; -+ info->blc = SENSOR_BLC_AUTO; -+ info->agc = SENSOR_AGC_AUTO; -+ info->awb = SENSOR_AWB_AUTO; -+ info->aec = SENSOR_AEC_AUTO; -+ info->bus_width = SENSOR_BUSWIDTH_8BIT_ZZ; -+ info->ycseq = SENSOR_YCSEQ_YCBYCR; -+ info->conv422 = SENSOR_CONV422_COSITED; -+ info->bpat = SENSOR_BPAT_GRGRBGBG; -+ info->field_inv = SENSOR_FIELDINV_NOSWAP; -+ info->field_sel = SENSOR_FIELDSEL_BOTH; -+ info->hpol = SENSOR_HPOL_REFPOS; -+ info->vpol = SENSOR_VPOL_POS; -+ info->edge = SENSOR_EDGE_FALLING; -+ info->flicker_freq = SENSOR_FLICKER_100; -+ info->cie_profile = 0; -+ memcpy(info->name, "ov9665", 7); -+ -+ ret = ov9665_write(c, 0x12, 0x80); -+ /* Set registers into default config value */ -+ ret += ov9665_write_array(c, ov9665_def_reg); -+ -+ ov9665_read(c, 0x09, ®); -+ reg = reg | 0x10; -+ ov9665_write(c, 0x09, reg); -+ ov9665_set_data_pin_in(c); -+ ssleep(1); -+ -+ return ret; -+} -+ -+static int distance(struct ov9665_res_struct *res, u32 w, u32 h) -+{ -+ int ret; -+ if (res->width < w || res->height < h) -+ return -1; -+ -+ ret = ((res->width - w) + (res->height - h)); -+ return ret; -+} -+static int ov9665_try_res(u32 *w, u32 *h) -+{ -+ struct ov9665_res_struct *res_index, *p = NULL; -+ int dis, last_dis = ov9665_res->width + ov9665_res->height; -+ -+ dprintk(1, "&&&&& before %dx%d", *w, *h); -+ for (res_index = ov9665_res; -+ res_index < ov9665_res + N_RES; -+ res_index++) { -+ if ((res_index->width <= *w) && (res_index->height <= *h)) -+ break; -+ dis = distance(res_index, *w, *h); -+ if (dis < last_dis) { -+ last_dis = dis; -+ p = res_index; -+ } -+ } -+ if ((res_index->width < *w) || (res_index->height < *h)) { -+ if (res_index != ov9665_res) -+ res_index--; -+ } -+ -+ /* -+ if (p == NULL) { -+ p = ov2650_res; -+ } -+ -+ if ((w != NULL) && (h != NULL)) { -+ *w = p->width; -+ *h = p->height; -+ } -+ */ -+ if (res_index == ov9665_res + N_RES) -+ res_index = ov9665_res + N_RES - 1; -+ -+ *w = res_index->width; -+ *h = res_index->height; -+ -+ dprintk(1, "&&&&& after %dx%d", *w, *h); -+ return 0; -+} -+ -+static struct ov9665_res_struct *ov9665_to_res(u32 w, u32 h) -+{ -+ struct ov9665_res_struct *res_index; -+ -+ for (res_index = ov9665_res; -+ res_index < ov9665_res + N_RES; -+ res_index++) -+ if ((res_index->width == w) && (res_index->height == h)) -+ break; -+ -+ if (res_index >= ov9665_res + N_RES) -+ res_index--; /* Take the bigger one */ -+ -+ return res_index; -+} -+ -+static int ov9665_try_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ DBG_entering; -+ return ov9665_try_res(&fmt->fmt.pix.width, &fmt->fmt.pix.height); -+ DBG_leaving; -+} -+ -+static int ov9665_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ unsigned short width, height; -+ int index; -+ -+ ci_sensor_res2size(info->res, &width, &height); -+ -+ /* Marked the current sensor res as being "used" */ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == ov9665_res[index].width) && -+ (height == ov9665_res[index].height)) { -+ ov9665_res[index].used = 1; -+ continue; -+ } -+ ov9665_res[index].used = 0; -+ } -+ -+ fmt->fmt.pix.width = width; -+ fmt->fmt.pix.height = height; -+ return 0; -+} -+ -+static int ov9665_set_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -+{ -+ struct i2c_client *c = v4l2_get_subdevdata(sd); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ int ret = 0; -+ struct ov9665_res_struct *res_index; -+ u32 width, height; -+ int index; -+ -+ DBG_entering; -+ -+ width = fmt->fmt.pix.width; -+ height = fmt->fmt.pix.height; -+ -+ ret = ov9665_try_res(&width, &height); -+ res_index = ov9665_to_res(width, height); -+ -+ ov9665_wakeup(); -+ /* if ((info->res != res_index->res) && (res_index->regs)) { */ -+ if ( res_index->regs) { -+ ret = ov9665_write(c, 0x12, 0x80); -+ ret += ov9665_write_array(c, ov9665_def_reg); -+ ret += ov9665_write_array(c, res_index->regs); -+ /* Add delay here to get better image */ -+ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == ov9665_res[index].width) && -+ (height == ov9665_res[index].height)) { -+ ov9665_res[index].used = 1; -+ continue; -+ } -+ ov9665_res[index].used = 0; -+ } -+ -+ for (index = 0; index < N_RES; index++) -+ dprintk(2, "index = %d, used = %d\n", index, -+ ov9665_res[index].used); -+ -+ } -+ info->res = res_index->res; -+ -+ DBG_leaving; -+ return ret; -+} -+ -+static int ov9665_q_hflip(struct v4l2_subdev *sd, __s32 *value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int ret; -+ unsigned char v = 0; -+ -+ ret = ov9665_read(client, 0x04, &v); -+ *value = ((v & 0x80) == 0x80); -+ return ret; -+} -+ -+static int ov9665_t_hflip(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ unsigned char v = 0; -+ int ret; -+ -+ value = value >= 1 ? 1 : 0; -+ ret = ov9665_read(client, 0x33, &v); -+ if (value) -+ v |= 0x08; -+ else -+ v &= ~0x08; -+ ret += ov9665_write(client, 0x33, v); -+ -+ ret += ov9665_read(client, 0x04, &v); -+ if (value) -+ v |= 0x80; -+ else -+ v &= ~0x80; -+ ret += ov9665_write(client, 0x04, v); -+ msleep(10); /* FIXME */ -+ return ret; -+} -+ -+static int ov9665_q_vflip(struct v4l2_subdev *sd, __s32 *value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int ret; -+ unsigned char v = 0; -+ -+ ret = ov9665_read(client, 0x04, &v); -+ *value = ((v & 0x40) == 0x40); -+ return ret; -+} -+ -+static int ov9665_t_vflip(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ unsigned char v = 0; -+ int ret; -+ -+ value = value >= 1 ? 1 : 0; -+ ret = ov9665_read(client, 0x04, &v); -+ if (value) -+ v |= 0x40; -+ else -+ v &= ~0x40; -+ ret += ov9665_write(client, 0x04, v); -+ msleep(10); /* FIXME */ -+ return ret; -+} -+ -+static struct ov9665_control { -+ struct v4l2_queryctrl qc; -+ int (*query)(struct v4l2_subdev *sd, __s32 *value); -+ int (*tweak)(struct v4l2_subdev *sd, int value); -+} ov9665_controls[] = { -+ { -+ .qc = { -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .name = "Vertical flip", -+ .minimum = 0, -+ .maximum = 1, -+ .step = 1, -+ .default_value = 0, -+ }, -+ .tweak = ov9665_t_vflip, -+ .query = ov9665_q_vflip, -+ }, -+ { -+ .qc = { -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .name = "Horizontal mirror", -+ .minimum = 0, -+ .maximum = 1, -+ .step = 1, -+ .default_value = 0, -+ }, -+ .tweak = ov9665_t_hflip, -+ .query = ov9665_q_hflip, -+ }, -+}; -+#define N_CONTROLS (ARRAY_SIZE(ov9665_controls)) -+ -+static struct ov9665_control *ov9665_find_control(__u32 id) -+{ -+ int i; -+ -+ for (i = 0; i < N_CONTROLS; i++) -+ if (ov9665_controls[i].qc.id == id) -+ return ov9665_controls + i; -+ return NULL; -+} -+ -+static int ov9665_queryctrl(struct v4l2_subdev *sd, -+ struct v4l2_queryctrl *qc) -+{ -+ struct ov9665_control *ctrl = ov9665_find_control(qc->id); -+ -+ if (ctrl == NULL) -+ return -EINVAL; -+ *qc = ctrl->qc; -+ return 0; -+} -+ -+static int ov9665_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ struct ov9665_control *octrl = ov9665_find_control(ctrl->id); -+ int ret; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->query(sd, &ctrl->value); -+ if (ret >= 0) -+ return 0; -+ return ret; -+} -+ -+static int ov9665_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ struct ov9665_control *octrl = ov9665_find_control(ctrl->id); -+ int ret; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->tweak(sd, ctrl->value); -+ if (ret >= 0) -+ return 0; -+ return ret; -+} -+ -+#if 0 -+static int ov9665_get_caps(struct i2c_client *c, struct ci_sensor_caps *caps) -+{ -+ if (caps == NULL) -+ return -EIO; -+ -+ caps->bus_width = SENSOR_BUSWIDTH_8BIT_ZZ; -+ caps->mode = SENSOR_MODE_BT601; -+ caps->field_inv = SENSOR_FIELDINV_NOSWAP; -+ caps->field_sel = SENSOR_FIELDSEL_BOTH; -+ caps->ycseq = SENSOR_YCSEQ_YCBYCR; -+ caps->conv422 = SENSOR_CONV422_COSITED; -+ caps->bpat = SENSOR_BPAT_GRGRBGBG; -+ caps->hpol = SENSOR_HPOL_REFPOS; -+ caps->vpol = SENSOR_VPOL_POS; -+ caps->edge = SENSOR_EDGE_FALLING; -+ caps->bls = SENSOR_BLS_OFF; -+ caps->gamma = SENSOR_GAMMA_ON; -+ caps->cconv = SENSOR_CCONV_ON; -+ caps->res = SENSOR_RES_SXGA | SENSOR_RES_VGA; -+ caps->blc = SENSOR_BLC_AUTO; -+ caps->agc = SENSOR_AGC_AUTO; -+ caps->awb = SENSOR_AWB_AUTO; -+ caps->aec = SENSOR_AEC_AUTO; -+ caps->cie_profile = 0; -+ caps->flicker_freq = SENSOR_FLICKER_100 | SENSOR_FLICKER_120; -+ caps->type = SENSOR_TYPE_SOC; -+ /* caps->name = "ov9665"; */ -+ strcpy(caps->name, "ov9665"); -+ -+ return 0; -+} -+ -+static int ov9665_get_config(struct i2c_client *c, -+ struct ci_sensor_config *config) -+{ -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ -+ if (config == NULL) { -+ printk(KERN_WARNING "sensor_get_config: NULL pointer\n"); -+ return -EIO; -+ } -+ -+ memset(config, 0, sizeof(struct ci_sensor_config *)); -+ memcpy(config, info, sizeof(struct ci_sensor_config)); -+ -+ return 0; -+} -+ -+static int ov9665_setup(struct i2c_client *c, -+ const struct ci_sensor_config *config) -+{ -+ int ret; -+ struct ov9665_res_struct *res_index; -+ struct ci_sensor_config *info = i2c_get_clientdata(c); -+ u16 width, high; -+ -+ /* Soft reset camera first*/ -+ ret = ov9665_write(c, 0x12, 0x80); -+ -+ /* Set registers into default config value */ -+ ret += ov9665_write_array(c, ov9665_def_reg); -+ -+ /* set image resolution */ -+ ci_sensor_res2size(config->res, &width, &high); -+ ret += ov9665_try_res(c, &width, &high); -+ res_index = ov9665_find_res(width, high); -+ if (res_index->regs) -+ ret += ov9665_write_array(c, res_index->regs); -+ if (!ret) -+ info->res = res_index->res; -+ -+ /* Add some delay here to get a better image*/ -+ ssleep(1); -+ -+ return ret; -+} -+ -+static int ov9665_set_data_pin_in(struct i2c_client *client) -+{ -+ int ret = 0; -+ -+ ret += ov9665_write(client, 0xd5, 0x00); -+ ret += ov9665_write(client, 0xd6, 0x00); -+ -+ return ret; -+} -+ -+static int ov9665_set_data_pin_out(struct i2c_client *client) -+{ -+ int ret = 0; -+ -+ ret += ov9665_write(client, 0xd5, 0xff); -+ ret += ov9665_write(client, 0xd6, 0xff); -+ -+ return ret; -+} -+/* -+ * File operation functions -+ */ -+static int ov9665_open(struct i2c_setting *c, void *priv) -+{ -+ struct i2c_client *client = c->sensor_client; -+ int ret = 0; -+ u8 reg = 0; -+ /* Just wake up sensor */ -+ if (ov9665_wakeup()) -+ return -EIO; -+ -+ ov9665_init(client); -+ ret = ov9665_read(client, 0x09, ®); -+ reg = reg | 0x10; -+ ret += ov9665_write(client, 0x09, reg); -+ -+ if (ov9665_set_data_pin_in(client)) -+ return EIO; -+/* -+ if (ov9665_standby()) -+ return EIO; -+*/ -+ return ret; -+} -+ -+static int ov9665_release(struct i2c_setting *c, void *priv) -+{ -+ /* Just suspend the sensor */ -+ if (ov9665_standby()) -+ return EIO; -+ return 0; -+} -+ -+static int ov9665_on(struct i2c_setting *c) -+{ -+ struct i2c_client *client = c->sensor_client; -+ int ret = 0; -+ u8 reg = 0; -+ -+ ret = ov9665_read(client, 0x09, ®); -+ reg = reg & ~0x10; -+ ret = ov9665_write(client, 0x09, reg); -+ -+ if (ov9665_set_data_pin_out(client)) -+ return EIO; -+ -+ return ret; -+} -+ -+static int ov9665_off(struct i2c_setting *c) -+{ -+ struct i2c_client *client = c->sensor_client; -+ int ret = 0; -+ u8 reg = 0; -+/* -+ ret = ov9665_read(client, 0x09, ®); -+ reg = reg | 0x10; -+ ret += ov9665_write(client, 0x09, reg); -+*/ -+ if (ov9665_set_data_pin_in(client)) -+ return EIO; -+ -+ return ret; -+} -+ -+static struct sensor_device ov9665 = { -+ .name = "OV9665", -+ .type = SENSOR_TYPE_SOC, -+ .minor = -1, -+ .open = ov9665_open, -+ .release = ov9665_release, -+ .on = ov9665_on, -+ .off = ov9665_off, -+ .querycap = ov9665_get_caps, -+ .get_config = ov9665_get_config, -+ .set_config = ov9665_setup, -+ .enum_parm = ov9665_queryctrl, -+ .get_parm = ov9665_g_ctrl, -+ .set_parm = ov9665_s_ctrl, -+ .try_res = ov9665_try_res, -+ .set_res = ov9665_set_res, -+ .suspend = ov9665_standby, -+ .resume = ov9665_wakeup, -+ .get_ls_corr_config = NULL, -+ .set_awb = NULL, -+ .set_aec = NULL, -+ .set_blc = NULL, -+ /* TBC */ -+}; -+#endif -+ -+static int ov9665_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ u8 reg = 0; -+ -+ DBG_entering; -+ if (enable) { -+ ov9665_read(client, 0x09, ®); -+ reg = reg & ~0x10; -+ ov9665_write(client, 0x09, reg); -+ ov9665_set_data_pin_out(client); -+ ssleep(1); -+ -+ } else { -+ ov9665_read(client, 0x09, ®); -+ reg = reg | 0x10; -+ ov9665_write(client, 0x09, reg); -+ ov9665_set_data_pin_in(client); -+ } -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int ov9665_enum_framesizes(struct v4l2_subdev *sd, -+ struct v4l2_frmsizeenum *fsize) -+{ -+ unsigned int index = fsize->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; -+ fsize->discrete.width = ov9665_res[index].width; -+ fsize->discrete.height = ov9665_res[index].height; -+ fsize->reserved[0] = ov9665_res[index].used; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+ -+static int ov9665_enum_frameintervals(struct v4l2_subdev *sd, -+ struct v4l2_frmivalenum *fival) -+{ -+ unsigned int index = fival->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; -+ fival->discrete.numerator = 1; -+ fival->discrete.denominator = ov9665_res[index].fps; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+ -+static int ov9665_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+#define V4L2_IDENT_OV9665 8246 -+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV9665, 0); -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ov9665_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ unsigned char val = 0; -+ int ret; -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ ret = ov9665_read(client, reg->reg & 0xffff, &val); -+ reg->val = val; -+ reg->size = 1; -+ return ret; -+} -+ -+static int ov9665_s_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ ov9665_write(client, reg->reg & 0xffff, reg->val & 0xff); -+ return 0; -+} -+#endif -+ -+static const struct v4l2_subdev_video_ops ov9665_video_ops = { -+ .try_fmt = ov9665_try_fmt, -+ .s_fmt = ov9665_set_fmt, -+ .g_fmt = ov9665_get_fmt, -+ .s_stream = ov9665_s_stream, -+ .enum_framesizes = ov9665_enum_framesizes, -+ .enum_frameintervals = ov9665_enum_frameintervals, -+}; -+ -+static const struct v4l2_subdev_core_ops ov9665_core_ops = { -+ .g_chip_ident = ov9665_g_chip_ident, -+ .queryctrl = ov9665_queryctrl, -+ .g_ctrl = ov9665_g_ctrl, -+ .s_ctrl = ov9665_s_ctrl, -+ .s_gpio = ov9665_s_power, -+ /*.g_ext_ctrls = ov9665_g_ext_ctrls,*/ -+ /*.s_ext_ctrls = ov9665_s_ext_ctrls,*/ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ov9665_g_register, -+ .s_register = ov9665_s_register, -+#endif -+}; -+ -+static const struct v4l2_subdev_ops ov9665_ops = { -+ .core = &ov9665_core_ops, -+ .video = &ov9665_video_ops, -+}; -+/* -+ * Basic i2c stuff -+ */ -+/* -+static unsigned short normal_i2c[] = {0x30, I2C_CLIENT_END}; -+I2C_CLIENT_INSMOD; -+ -+static struct i2c_driver ov9665_driver; -+*/ -+static int ov9665_detect(struct i2c_client *client) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ int adap_id = i2c_adapter_id(adapter); -+ u8 config = 0; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) -+ return -ENODEV; -+ -+ if (adap_id != 1) -+ return -ENODEV; -+ -+ ov9665_wakeup(); -+ -+ ov9665_read(client, 0x0a, &config); -+ if (config != 0x96) -+ return -ENODEV; -+ -+ ov9665_read(client, 0x0b, &config); -+ if (config != 0x63) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static int ov9665_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct ci_sensor_config *info; -+ struct v4l2_subdev *sd; -+ int ret = -1; -+ -+ DBG_entering; -+ /* -+ * Setup sensor configuration structure -+ */ -+ info = kzalloc(sizeof(struct ci_sensor_config), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ ret = ov9665_detect(client); -+ if (ret) { -+ kfree(info); -+ return -ENODEV; -+ } -+ -+ sd = &info->sd; -+ v4l2_i2c_subdev_init(sd, client, &ov9665_ops); -+ -+ /* -+ * Initialization OV9665 -+ * then turn into standby mode -+ */ -+ /* ret = ov9665_standby(); */ -+ ret = ov9665_init(client); -+ if (ret) { -+ eprintk("error init ov9665"); -+ goto err_1; -+ } -+ -+ ov9665_standby(); -+ printk(KERN_INFO "Init ov9665 sensor success\n"); -+ DBG_leaving; -+ return 0; -+ -+err_1: -+ kfree(info); -+ return ret; -+} -+ -+/* -+ * XXX: Need to be checked -+ */ -+static int ov9665_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ v4l2_device_unregister_subdev(sd); -+ kfree(to_sensor_config(sd)); -+ -+ return 0; -+} -+ -+static const struct i2c_device_id ov9665_id[] = { -+ {"ov9665", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, ov9665_id); -+ -+static struct v4l2_i2c_driver_data v4l2_i2c_data = { -+ .name = "ov9665", -+ .probe = ov9665_probe, -+ .remove = ov9665_remove, -+ .id_table = ov9665_id, -+}; -+ -+MODULE_AUTHOR("Xiaolin Zhang "); -+MODULE_DESCRIPTION("A low-level driver for OmniVision 9665 sensors"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/video/mrstci/mrstov9665/ov9665.h b/drivers/media/video/mrstci/mrstov9665/ov9665.h -new file mode 100644 -index 0000000..6fc9d12 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrstov9665/ov9665.h -@@ -0,0 +1,263 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#define I2C_OV9665 0x60 -+/* Should add to kernel source */ -+#define I2C_DRIVERID_OV9665 1047 -+/* GPIO pin on Moorestown */ -+#define GPIO_SCLK_25 44 -+#define GPIO_STB_PIN 47 -+#define GPIO_STDBY_PIN 48 -+#define GPIO_RESET_PIN 50 -+ -+struct regval_list { -+ u8 reg_num; -+ u8 value; -+}; -+ -+/* -+ * Default register value -+ * 1280x1024 YUV -+ */ -+static struct regval_list ov9665_def_reg[] = { -+ {0x3E, 0x80}, -+ {0x12, 0x80}, -+ -+ {0xd5, 0xff}, -+ {0xd6, 0x3f}, -+ -+ {0x3d, 0x3c}, -+ {0x11, 0x81}, -+ {0x2a, 0x00}, -+ {0x2b, 0x00}, -+ -+ {0x3a, 0xf1}, -+ {0x3b, 0x00}, -+ {0x3c, 0x58}, -+ {0x3e, 0x50}, -+ {0x71, 0x00}, -+ -+ {0x15, 0x00}, -+ {0x6a, 0x24}, -+ {0x85, 0xe7}, -+ -+ {0x63, 0x01}, -+ -+ {0x17, 0x0c}, -+ {0x18, 0x5c}, -+ {0x19, 0x01}, -+ {0x1a, 0x82}, -+ {0x03, 0x03}, -+ {0x2b, 0x00}, -+ -+ {0x36, 0xb4}, -+ {0x65, 0x10}, -+ {0x70, 0x02}, -+ {0x71, 0x9f}, -+ {0x64, 0x24}, -+ -+ {0x43, 0x00}, -+ {0x5D, 0x55}, -+ {0x5E, 0x57}, -+ {0x5F, 0x21}, -+ -+ {0x24, 0x3e}, -+ {0x25, 0x38}, -+ {0x26, 0x72}, -+ -+ {0x14, 0x68}, -+ {0x0C, 0x3a}, /* Auto detect for 50/60 */ -+ {0x4F, 0x9E}, -+ {0x50, 0x84}, -+ {0x5A, 0x67}, -+ -+ {0x7d, 0x30}, -+ {0x7e, 0x00}, -+ {0x82, 0x03}, -+ {0x7f, 0x00}, -+ {0x83, 0x07}, -+ {0x80, 0x03}, -+ {0x81, 0x04}, -+ -+ {0x96, 0xf0}, -+ {0x97, 0x00}, -+ {0x92, 0x33}, -+ {0x94, 0x5a}, -+ {0x93, 0x3a}, -+ {0x95, 0x48}, -+ {0x91, 0xfc}, -+ {0x90, 0xff}, -+ {0x8e, 0x4e}, -+ {0x8f, 0x4e}, -+ {0x8d, 0x13}, -+ {0x8c, 0x0c}, -+ {0x8b, 0x0c}, -+ {0x86, 0x9e}, -+ {0x87, 0x11}, -+ {0x88, 0x22}, -+ {0x89, 0x05}, -+ {0x8a, 0x03}, -+ -+ {0x9b, 0x0e}, -+ {0x9c, 0x1c}, -+ {0x9d, 0x34}, -+ {0x9e, 0x5a}, -+ {0x9f, 0x68}, -+ {0xa0, 0x76}, -+ {0xa1, 0x82}, -+ {0xa2, 0x8e}, -+ {0xa3, 0x98}, -+ {0xa4, 0xa0}, -+ {0xa5, 0xb0}, -+ {0xa6, 0xbe}, -+ {0xa7, 0xd2}, -+ {0xa8, 0xe2}, -+ {0xa9, 0xee}, -+ {0xaa, 0x18}, -+ -+ {0xAB, 0xe7}, -+ {0xb0, 0x43}, -+ {0xac, 0x04}, -+ {0x84, 0x40}, -+ -+ {0xad, 0x84}, -+ {0xd9, 0x24}, -+ {0xda, 0x00}, -+ {0xae, 0x10}, -+ -+ {0xab, 0xe7}, -+ {0xb9, 0xa0}, -+ {0xba, 0x80}, -+ {0xbb, 0xa0}, -+ {0xbc, 0x80}, -+ -+ {0xbd, 0x08}, -+ {0xbe, 0x19}, -+ {0xbf, 0x02}, -+ {0xc0, 0x08}, -+ {0xc1, 0x2a}, -+ {0xc2, 0x34}, -+ {0xc3, 0x2d}, -+ {0xc4, 0x2d}, -+ {0xc5, 0x00}, -+ {0xc6, 0x98}, -+ {0xc7, 0x18}, -+ {0x69, 0x48}, -+ -+ {0x74, 0xc0}, -+ -+ {0x7c, 0x18}, -+ {0x65, 0x11}, -+ {0x66, 0x00}, -+ {0x41, 0xa0}, -+ {0x5b, 0x28}, -+ {0x60, 0x84}, -+ {0x05, 0x07}, -+ {0x03, 0x03}, -+ {0xd2, 0x8c}, -+ -+ {0xc7, 0x90}, -+ {0xc8, 0x06}, -+ {0xcb, 0x40}, -+ {0xcc, 0x40}, -+ {0xcf, 0x00}, -+ {0xd0, 0x20}, -+ {0xd1, 0x00}, -+ {0xc7, 0x18}, -+ -+ {0x0d, 0x82}, -+ {0x0d, 0x80}, -+ -+ {0x09, 0x01}, -+ -+ {0xff, 0xff}, -+}; -+ -+/* 1280x1024 */ -+static struct regval_list ov9665_res_sxga[] = { -+ {0x0c, 0xbc}, /* note this */ -+ {0xff, 0xff}, -+}; -+ -+/* 640x480 */ -+static struct regval_list ov9665_res_vga[] = { -+ /* Fclk/4 */ -+ {0x11, 0x80}, -+ {0x63, 0x00}, -+ -+ {0x12, 0x40}, /*VGA format*/ -+ {0x14, 0x30}, /*4x*/ -+ {0x0c, 0xbc}, -+ {0x4d, 0x09}, -+ {0x5c, 0x80}, /* Full average AEC */ -+ -+ /* Windows setting */ -+ {0x17, 0x0c}, -+ {0x18, 0x5c}, -+ {0x19, 0x02}, -+ {0x1a, 0x3f}, -+ {0x03, 0x03}, -+ {0x32, 0xad}, -+ -+ /* 50/60Hz AEC */ -+ {0x5a, 0x23}, -+ {0x2b, 0x00}, -+ -+ {0x64, 0xa4}, -+ /* -+ {0x4F, 0x4f}, -+ {0x50, 0x42}, -+ */ -+ {0x4F, 0x9e}, -+ {0x50, 0x84}, -+ {0x97, 0x0a}, -+ {0xad, 0x82}, -+ {0xd9, 0x11}, -+ -+ /* Scale window */ -+ {0xb9, 0x50}, -+ {0xba, 0x3c}, -+ {0xbb, 0x50}, -+ {0xbc, 0x3c}, -+ -+ {0xad, 0x80}, -+ {0xd9, 0x00}, -+ {0xac, 0x0f}, -+ {0x84, 0x86}, -+ -+ /*This is for Color Matrix*/ -+ {0xbd, 0x05}, -+ {0xbe, 0x16}, -+ {0xbf, 0x05}, -+ {0xc0, 0x07}, -+ {0xc1, 0x18}, -+ {0xc2, 0x1f}, -+ {0xc3, 0x2b}, -+ {0xc4, 0x2b}, -+ {0xc5, 0x00}, -+ -+ {0x0d, 0x92}, -+ {0x0d, 0x90}, -+ -+ {0xff, 0xff}, -+}; -diff --git a/drivers/media/video/mrstci/mrsts5k4e1/Kconfig b/drivers/media/video/mrstci/mrsts5k4e1/Kconfig -new file mode 100755 -index 0000000..7dee787 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1/Kconfig -@@ -0,0 +1,9 @@ -+config VIDEO_MRST_S5K4E1 -+ tristate "Moorestown s5k4e1 RAW Sensor" -+ depends on I2C && VIDEO_MRST_ISP -+ -+ ---help--- -+ Say Y here if your platform support s5k4e1 RAW Sensor. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mrstov2650.ko. -diff --git a/drivers/media/video/mrstci/mrsts5k4e1/Makefile b/drivers/media/video/mrstci/mrsts5k4e1/Makefile -new file mode 100644 -index 0000000..8733fa8 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_VIDEO_MRST_S5K4E1) += mrsts5k4e1.o -+ -+EXTRA_CFLAGS += -I$(src)/../include -diff --git a/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c -new file mode 100755 -index 0000000..f644531 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c -@@ -0,0 +1,1024 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ci_sensor_common.h" -+#include "mrsts5k4e1.h" -+/* #include "priv.h" */ -+/* extern const struct DumpRegs regs_d[]; */ -+ -+static int s5k4e1_debug; -+module_param(s5k4e1_debug, int, 0644); -+MODULE_PARM_DESC(s5k4e1_debug, "Debug level (0-1)"); -+ -+#define dprintk(level, fmt, arg...) \ -+ do { \ -+ if (s5k4e1_debug >= level) \ -+ printk(KERN_DEBUG "mrstisp@%s: " fmt "\n", \ -+ __func__, ## arg);\ -+ } while (0) -+ -+#define eprintk(fmt, arg...) \ -+ printk(KERN_ERR "mrstisp@%s:" fmt "\n", \ -+ __func__, ## arg); -+ -+#define DBG_entering dprintk(1, "entering"); -+#define DBG_leaving dprintk(1, "leaving"); -+#define DBG_line dprintk(1, " line: %d", __LINE__); -+ -+static inline struct ci_sensor_config *to_sensor_config(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct ci_sensor_config, sd); -+} -+ -+static struct s5k4e1_format_struct { -+ __u8 *desc; -+ __u32 pixelformat; -+ struct regval_list *regs; -+} s5k4e1_formats[] = { -+ { -+ .desc = "Raw RGB Bayer", -+ .pixelformat = SENSOR_MODE_MIPI, -+ .regs = NULL, -+ }, -+}; -+#define N_S5K4E1_FMTS ARRAY_SIZE(s5k4e1_formats) -+ -+static struct s5k4e1_res_struct { -+ __u8 *desc; -+ int res; -+ int width; -+ int height; -+ /* FIXME: correct the fps values.. */ -+ int fps; -+ bool used; -+ struct regval_list *regs; -+} s5k4e1_res[] = { -+ { -+ .desc = "QSXGA_PLUS4", -+ .res = SENSOR_RES_QXGA_PLUS, -+ .width = 2592, -+ .height = 1944, -+ .fps = 15, -+ .used = 0, -+ .regs = s5k4e1_res_qsxga_plus4, -+ }, -+ { -+ .desc = "1080P", -+ .res = SENSOR_RES_1080P, -+ .width = 1920, -+ .height = 1080, -+ .fps = 25, -+ .used = 0, -+ .regs = s5k4e1_res_1080p, -+ }, -+ { -+ .desc = "VGA_PLUS", -+ .res = SENSOR_RES_VGA_PLUS, -+ .width = 1304, -+ .height = 980, -+ .fps = 30, -+ .used = 0, -+ .regs = s5k4e1_res_vga_ac04_bill, -+ }, -+ { -+ .desc = "720p", -+ .res = SENSOR_RES_720P, -+ .width = 1280, -+ .height = 720, -+ .fps = 30, -+ .used = 0, -+ .regs = s5k4e1_res_720p, -+ }, -+ { -+ .desc = "VGA", -+ .res = SENSOR_RES_VGA, -+ .width = 640, -+ .height = 480, -+ .used = 0, -+ .fps = 40, -+ .regs = s5k4e1_res_vga_ac04_bill, -+ }, -+}; -+ -+#define N_RES (ARRAY_SIZE(s5k4e1_res)) -+ -+/* -+ * I2C Read & Write stuff -+ */ -+static int s5k4e1_read(struct i2c_client *c, u32 reg, u32 *value) -+{ -+ int ret; -+ int i; -+ struct i2c_msg msg[2]; -+ u8 msgbuf[2]; -+ u8 ret_val = 0; -+ *value = 0; -+ /* Read needs two message to go */ -+ memset(&msg, 0, sizeof(msg)); -+ msgbuf[0] = 0; -+ msgbuf[1] = 0; -+ i = 0; -+ -+ msgbuf[i++] = ((u16)reg) >> 8; -+ msgbuf[i++] = ((u16)reg) & 0xff; -+ msg[0].addr = c->addr; -+ msg[0].buf = msgbuf; -+ msg[0].len = i; -+ -+ msg[1].addr = c->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].buf = &ret_val; -+ msg[1].len = 1; -+ -+ ret = i2c_transfer(c->adapter, &msg[0], 2); -+ *value = ret_val; -+ -+ ret = (ret == 2) ? 0 : -1; -+ dprintk(2, "reg:0x%8x, value:0x%8x - %s", reg, *value, -+ (ret ? "failed" : "succesfully")); -+ return ret; -+} -+ -+static int s5k4e1_write(struct i2c_client *c, u32 reg, u32 value) -+{ -+ int ret, i; -+ struct i2c_msg msg; -+ u8 msgbuf[3]; -+ -+ /* Writing only needs one message */ -+ memset(&msg, 0, sizeof(msg)); -+ i = 0; -+ msgbuf[i++] = ((u16)reg) >> 8; -+ msgbuf[i++] = (u16)reg & 0xff; -+ msgbuf[i++] = (u8)value; -+ -+ msg.addr = c->addr; -+ msg.flags = 0; -+ msg.buf = msgbuf; -+ msg.len = i; -+ -+ ret = i2c_transfer(c->adapter, &msg, 1); -+ -+ /* If this is a reset register, wait for 1ms */ -+ if (reg == 0x0103 && (value & 0x01)) -+ /*Note here, check if this is needed */ -+ msleep(4); -+ -+ ret = (ret == 1) ? 0 : -1; -+ dprintk(2, "reg:0x%8x, value:0x%8x - %s", reg, value, -+ (ret ? "failed" : "successfully")); -+ return ret; -+} -+ -+static int s5k4e1_write_array(struct i2c_client *c, struct regval_list *vals) -+{ -+ struct regval_list *p; -+ u32 read_val = 0; -+ int err_num = 0; -+ int i = 0; -+ -+ DBG_entering; -+ -+ p = vals; -+ while (p->reg_num != 0xffff) { -+ s5k4e1_write(c, (u32)p->reg_num, (u32)p->value); -+ s5k4e1_read(c, (u32)p->reg_num, &read_val); -+ /* msleep(100);*/ -+ if (read_val != p->value) { -+ eprintk("0x%x write error:should be 0x%x, but 0x%x", -+ p->reg_num, p->value, read_val); -+ err_num++; -+ } -+ p++; -+ i++; -+ } -+ dprintk(1, "sucessfully wrote %d registers, err is %d", i, -+ err_num); -+ return 0; -+} -+ -+/* -+ * Sensor specific helper function -+ */ -+static int s5k4e1_standby(void) -+{ -+ gpio_set_value(GPIO_STDBY_PIN, 1); -+ dprintk(1, "PM: standby called\n"); -+ return 0; -+} -+ -+static int s5k4e1_wakeup(void) -+{ -+ gpio_set_value(GPIO_STDBY_PIN, 0); -+ dprintk(1, "PM: wakeup called\n"); -+ return 0; -+} -+ -+static int s5k4e1_s_power(struct v4l2_subdev *sd, u32 val) -+{ -+ if (val == 1) -+ s5k4e1_standby(); -+ if (val == 0) -+ s5k4e1_wakeup(); -+ return 0; -+} -+ -+static int s5k4e1_set_img_ctrl(struct i2c_client *c, -+ const struct ci_sensor_config *config) -+{ -+ int err = 0; -+ -+ DBG_entering; -+ -+ switch (config->blc) { -+ /* only SENSOR_BLC_AUTO supported */ -+ case SENSOR_BLC_AUTO: -+ break; -+ default: -+ dprintk(1, "BLC not supported,\ -+ set to BLC_AUTO by default."); -+ } -+ -+ switch (config->bls) { -+ /* only SENSOR_BLS_OFF supported */ -+ case SENSOR_BLS_OFF: -+ break; -+ default: -+ dprintk(1, "Black level not supported,\ -+ set to BLS_OFF by default."); -+ } -+ -+ switch (config->agc) { -+ /* only SENSOR_AGC_OFF supported */ -+ case SENSOR_AGC_OFF: -+ break; -+ default: -+ dprintk(1, "AGC not supported,\ -+ set to AGC_OFF by default."); -+ } -+ -+ switch (config->awb) { -+ /* only SENSOR_AWB_OFF supported */ -+ case SENSOR_AWB_OFF: -+ break; -+ default: -+ dprintk(1, "AWB not supported,\ -+ set to AWB_OFF by default."); -+ } -+ -+ switch (config->aec) { -+ /* only SENSOR_AEC_OFF supported */ -+ case SENSOR_AEC_OFF: -+ break; -+ default: -+ dprintk(1, "AEC not supported,\ -+ set to AEC_OFF by default."); -+ } -+ -+ DBG_leaving; -+ -+ return err; -+} -+static int s5k4e1_init(struct i2c_client *c) -+{ -+ int ret = 0; -+ struct v4l2_subdev *sd = i2c_get_clientdata(c); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ char *name = ""; -+ -+ DBG_entering; -+ -+ /* Fill the configuration structure */ -+ /* Note this default configuration value */ -+ info->mode = s5k4e1_formats[0].pixelformat; -+ info->res = s5k4e1_res[0].res; -+ info->type = SENSOR_TYPE_RAW; -+ info->bls = SENSOR_BLS_OFF; -+ info->gamma = SENSOR_GAMMA_OFF; -+ info->cconv = SENSOR_CCONV_OFF; -+ info->blc = SENSOR_BLC_AUTO; -+ info->agc = SENSOR_AGC_OFF; -+ info->awb = SENSOR_AWB_OFF; -+ info->aec = SENSOR_AEC_OFF; -+ /*info->bus_width = SENSOR_BUSWIDTH_10BIT_ZZ;*/ -+ info->bus_width = SENSOR_BUSWIDTH_12BIT; -+ info->ycseq = SENSOR_YCSEQ_YCBYCR; -+ info->conv422 = SENSOR_CONV422_COSITED; -+ /*info->conv422 = SENSOR_CONV422_NOCOSITED;*/ -+ info->bpat = SENSOR_BPAT_GRGRBGBG; -+ info->field_inv = SENSOR_FIELDINV_NOSWAP; -+ info->field_sel = SENSOR_FIELDSEL_BOTH; -+ info->hpol = SENSOR_HPOL_REFPOS; -+ info->vpol = SENSOR_VPOL_NEG; -+ info->edge = SENSOR_EDGE_RISING; -+ info->flicker_freq = SENSOR_FLICKER_100; -+ info->cie_profile = SENSOR_CIEPROF_F11; -+ info->mipi_mode = SENSOR_MIPI_MODE_RAW_10; -+ name = "s5k4e1"; -+ memcpy(info->name, name, 7); -+ -+ /* Reset sensor hardware, and implement the setting*/ -+ ret += s5k4e1_write(c, 0x0100, (u32)0x00); -+ /*TODO: See if we can ignore this*/ -+ ret = s5k4e1_write(c, 0x0103, (u32)0x01); -+ -+ /* sw reset -- delay 3.1ms */ -+ msleep(4); -+ -+ /* Set registers into default config value */ -+ /* ret += s5k4e1_write_array(c, s5k4e1_def_reg); */ -+ -+ /* Set MIPI interface */ -+#ifdef S5K4E1_MIPI -+ ret += s5k4e1_write_array(c, s5k4e1_mipi); -+#endif -+ -+ ret += s5k4e1_set_img_ctrl(c, info); /*FIXME*/ -+ -+ /* streaming */ -+ /* ret += s5k4e1_write(c, 0x0100, (u32)0x01); */ -+ ret += s5k4e1_write(c, 0x0100, (u32)0x00); -+ -+ msleep(1); -+ -+ DBG_leaving; -+ -+ return ret; -+} -+ -+static int distance(struct s5k4e1_res_struct *res, u32 w, u32 h) -+{ -+ int ret; -+ -+ DBG_entering; -+ -+ if (res->width < w || res->height < h) -+ return -1; -+ -+ ret = ((res->width - w) + (res->height - h)); -+ -+ DBG_leaving; -+ -+ return ret; -+} -+ -+static int s5k4e1_try_res(u32 *w, u32 *h) -+{ -+ struct s5k4e1_res_struct *res_index, *p = NULL; -+ int dis, last_dis = s5k4e1_res->width + s5k4e1_res->height; -+ -+ DBG_entering; -+ -+ for (res_index = s5k4e1_res; -+ res_index < s5k4e1_res + N_RES; -+ res_index++) { -+ if ((res_index->width < *w) || (res_index->height < *h)) -+ break; -+ dis = distance(res_index, *w, *h); -+ if (dis < last_dis) { -+ last_dis = dis; -+ p = res_index; -+ } -+ } -+ -+ if (p == NULL) -+ p = s5k4e1_res; -+ else if ((p->width < *w) || (p->height < *h)) { -+ if (p != s5k4e1_res) -+ p--; -+ } -+ -+ if ((w != NULL) && (h != NULL)) { -+ *w = p->width; -+ *h = p->height; -+ } -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static struct s5k4e1_res_struct *s5k4e1_to_res(u32 w, u32 h) -+{ -+ struct s5k4e1_res_struct *res_index; -+ -+ DBG_entering; -+ -+ for (res_index = s5k4e1_res; -+ res_index < s5k4e1_res + N_RES; -+ res_index++) -+ if ((res_index->width == w) && (res_index->height == h)) -+ break; -+ -+ if (res_index >= s5k4e1_res + N_RES) -+ res_index--; /* Take the bigger one */ -+ -+ DBG_leaving; -+ -+ return res_index; -+} -+ -+static int s5k4e1_try_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ DBG_entering; -+ return s5k4e1_try_res(&fmt->fmt.pix.width, &fmt->fmt.pix.height); -+ DBG_leaving; -+} -+ -+static int s5k4e1_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_format *fmt) -+{ -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ unsigned short width, height; -+ int index; -+ -+ ci_sensor_res2size(info->res, &width, &height); -+ -+ /* Marked the current sensor res as being "used" */ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == s5k4e1_res[index].width) && -+ (height == s5k4e1_res[index].height)) { -+ s5k4e1_res[index].used = 1; -+ continue; -+ } -+ s5k4e1_res[index].used = 0; -+ } -+ -+ fmt->fmt.pix.width = width; -+ fmt->fmt.pix.height = height; -+ return 0; -+ -+} -+ -+#if 0 -+/* chuanxiao add, to dump regs */ -+static int s5k4e1_dump_regs(struct i2c_client *c) -+{ -+ /*struct i2c_client *c = v4l2_get_subdevdata(sd);*/ -+ const struct DumpRegs *p = regs_d; -+ u32 value; -+ u32 value1, value2, value3, value4; -+ while (p->ulFlags != eTableEnd) { -+ if (p->ulFlags & eFourBytes) { -+ s5k4e1_read(c, (u32)p->ulAddr, &value1); -+ s5k4e1_read(c, (u32)p->ulAddr+1, &value2); -+ s5k4e1_read(c, (u32)p->ulAddr+2, &value3); -+ s5k4e1_read(c, (u32)p->ulAddr+3, &value4); -+ value = value1<<24 | value2<<16 | value3<<8 | value4; -+ } else if (p->ulFlags & eTwoBytes) { -+ s5k4e1_read(c, (u32)p->ulAddr, &value1); -+ s5k4e1_read(c, (u32)p->ulAddr+1, &value2); -+ value = value1<<8 | value2; -+ } else -+ s5k4e1_read(c, (u32)p->ulAddr, &value); -+ /* -+ if (value == p->ulDefaultValue) -+ dprintk(0, "%s\t @ 0x%x = 0x%lx (= default value)\n", -+ p->pszName, p->ulAddr, value); -+ else -+ dprintk(0, "%s\t @ 0x%x = 0x%lx (default was 0x%lx)\n", -+ p->pszName, p->ulAddr, value, p->ulDefaultValue); -+ */ -+ dprintk(0, "%-30s @ 0x%04X = 0x%08X", p->pszName, -+ p->ulAddr, value); -+ p++; -+ } -+ return 0; -+} -+#endif -+ -+static int s5k4e1_set_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -+{ -+ struct i2c_client *c = v4l2_get_subdevdata(sd); -+ struct ci_sensor_config *info = to_sensor_config(sd); -+ int ret = 0; -+ struct s5k4e1_res_struct *res_index; -+ u32 width, height; -+ int index; -+ -+ DBG_entering; -+ -+ width = fmt->fmt.pix.width; -+ height = fmt->fmt.pix.height; -+ -+ dprintk(1, "was told to set fmt (%d x %d) ", width, height); -+ ret = s5k4e1_try_res(&width, &height); -+ -+ res_index = s5k4e1_to_res(width, height); -+ -+ s5k4e1_wakeup(); -+ DBG_line; -+ if (res_index->regs) { -+ /* software sleep/standby */ -+ ret += s5k4e1_write(c, 0x0100, (u32)0x00); -+ -+ /* Soft reset camera first*/ -+ /*TODO: See if we can ignore this*/ -+ ret = s5k4e1_write(c, 0x0103, (u32)0xff); -+ -+ /* Set registers into default config value */ -+ /* ret += s5k4e1_write_array(c, s5k4e1_def_reg);*/ -+ -+ /* set image resolution */ -+ ret += s5k4e1_write_array(c, res_index->regs); -+ -+ ret += s5k4e1_set_img_ctrl(c, info); -+ -+ /* XXX setup with unknow meaning ... */ -+ /* ret += s5k4e1_write(c, 0x30b0, 0xfe); */ -+ -+ /* Set MIPI interface */ -+#ifdef S5K4E1_MIPI -+ ret += s5k4e1_write_array(c, s5k4e1_mipi); -+#endif -+ -+ /* streaming */ -+ ret = s5k4e1_write(c, 0x0100, (u32)0x01); -+ msleep(1); -+ -+ info->res = res_index->res; -+ -+ /* Marked current sensor res as being "used" */ -+ for (index = 0; index < N_RES; index++) { -+ if ((width == s5k4e1_res[index].width) && -+ (height == s5k4e1_res[index].height)) { -+ s5k4e1_res[index].used = 1; -+ continue; -+ } -+ s5k4e1_res[index].used = 0; -+ } -+ -+ for (index = 0; index < N_RES; index++) -+ dprintk(2, "index = %d, used = %d\n", index, -+ s5k4e1_res[index].used); -+ -+ DBG_line; -+ } else { -+ eprintk("no res for (%d x %d)", width, height); -+ } -+ -+ DBG_leaving; -+ return ret; -+} -+ -+static int s5k4e1_t_gain(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ DBG_entering; -+ -+ s5k4e1_write(client, 0x0104, 1); /*hold*/ -+ -+ /* analog gain */ -+ s5k4e1_write(client, 0x0204, value >> 8); -+ -+ s5k4e1_write(client, 0x0205, value & 0xff); -+ -+ s5k4e1_write(client, 0x0104, 0); /*unhold*/ -+ -+ dprintk(1, "gain %x was writen to 0x0204/5", value); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int s5k4e1_t_exposure(struct v4l2_subdev *sd, int value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ DBG_entering; -+ -+ s5k4e1_write(client, 0x0104, 1); /*hold*/ -+ -+ /* fine integration time */ -+ s5k4e1_write(client, 0x0200, value >> 24); -+ -+ s5k4e1_write(client, 0x0201, (value >> 16) & 0xff); -+ -+ /* coarse integration time */ -+ s5k4e1_write(client, 0x0202, (value & 0xff00) >> 8); -+ -+ s5k4e1_write(client, 0x0203, value & 0xff); -+ -+ s5k4e1_write(client, 0x0104, 0); /*unhold*/ -+ -+ dprintk(1, "exposure %x was writen to 0x0200/1/2/3", value); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static struct s5k4e1_control { -+ struct v4l2_queryctrl qc; -+ int (*query)(struct v4l2_subdev *sd, __s32 *value); -+ int (*tweak)(struct v4l2_subdev *sd, int value); -+} s5k4e1_controls[] = { -+ { -+ .qc = { -+ .id = V4L2_CID_GAIN, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "global gain", -+ .minimum = 0x0, -+ .maximum = 0xFFFF, -+ .step = 0x01, -+ .default_value = 0x00, -+ .flags = 0, -+ }, -+ .tweak = s5k4e1_t_gain, -+ }, -+ { -+ .qc = { -+ .id = V4L2_CID_EXPOSURE, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "exposure", -+ .minimum = 0x0, -+ .maximum = 0xFFFF, -+ .step = 0x01, -+ .default_value = 0x00, -+ .flags = 0, -+ }, -+ .tweak = s5k4e1_t_exposure, -+ }, -+}; -+#define N_CONTROLS (ARRAY_SIZE(s5k4e1_controls)) -+ -+static struct s5k4e1_control *s5k4e1_find_control(__u32 id) -+{ -+ int i; -+ -+ DBG_entering; -+ for (i = 0; i < N_CONTROLS; i++) -+ if (s5k4e1_controls[i].qc.id == id) -+ return s5k4e1_controls + i; -+ DBG_leaving; -+ return NULL; -+} -+ -+static int s5k4e1_queryctrl(struct v4l2_subdev *sd, -+ struct v4l2_queryctrl *qc) -+{ -+ struct s5k4e1_control *ctrl = s5k4e1_find_control(qc->id); -+ -+ DBG_entering; -+ if (ctrl == NULL) -+ return -EINVAL; -+ *qc = ctrl->qc; -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int s5k4e1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+/* -+ struct s5k4e1_control *octrl = s5k4e1_find_control(parm->index); -+ int ret; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->query(client, &parm->value); -+ if (ret >= 0) -+ return 0; -+*/ -+ return 0; -+} -+ -+static int s5k4e1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ struct s5k4e1_control *octrl = s5k4e1_find_control(ctrl->id); -+ int ret; -+ -+ DBG_entering; -+ -+ if (octrl == NULL) -+ return -EINVAL; -+ ret = octrl->tweak(sd, ctrl->value); -+ if (ret >= 0) -+ return 0; -+ -+ DBG_leaving; -+ return ret; -+} -+ -+static int s5k4e1_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ DBG_entering; -+ -+ if (enable) { -+ s5k4e1_write(client, (u32)0x0100, 0x01); -+ /*chuanxiao add, dump s5k4e1 regs*/ -+ /* s5k4e1_dump_regs(client); */ -+ } else -+ s5k4e1_write(client, (u32)0x0100, 0x00); -+ -+ /*msleep(1);*/ -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int s5k4e1_enum_framesizes(struct v4l2_subdev *sd, -+ struct v4l2_frmsizeenum *fsize) -+{ -+ unsigned int index = fsize->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; -+ fsize->discrete.width = s5k4e1_res[index].width; -+ fsize->discrete.height = s5k4e1_res[index].height; -+ fsize->reserved[0] = s5k4e1_res[index].used; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+ -+static int s5k4e1_enum_frameintervals(struct v4l2_subdev *sd, -+ struct v4l2_frmivalenum *fival) -+{ -+ unsigned int index = fival->index; -+ -+ DBG_entering; -+ -+ if (index >= N_RES) -+ return -EINVAL; -+ -+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; -+ fival->discrete.numerator = 1; -+ fival->discrete.denominator = s5k4e1_res[index].fps; -+ -+ DBG_leaving; -+ -+ return 0; -+} -+ -+static int s5k4e1_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ DBG_entering; -+ -+#define V4L2_IDENT_S5K4E1 8250 -+ DBG_leaving; -+ -+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_S5K4E1, 0); -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int s5k4e1_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ unsigned char val = 0; -+ int ret; -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ ret = s5k4e1_read(client, reg->reg & 0xffff, &val); -+ reg->val = val; -+ reg->size = 1; -+ return ret; -+} -+ -+static int s5k4e1_s_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ s5k4e1_write(client, reg->reg & 0xffff, reg->val & 0xff); -+ return 0; -+} -+#endif -+ -+static const struct v4l2_subdev_video_ops s5k4e1_video_ops = { -+ .try_fmt = s5k4e1_try_fmt, -+ .s_fmt = s5k4e1_set_fmt, -+ .g_fmt = s5k4e1_get_fmt, -+ .s_stream = s5k4e1_s_stream, -+ .enum_framesizes = s5k4e1_enum_framesizes, -+ .enum_frameintervals = s5k4e1_enum_frameintervals, -+}; -+ -+static const struct v4l2_subdev_core_ops s5k4e1_core_ops = { -+ .g_chip_ident = s5k4e1_g_chip_ident, -+ .queryctrl = s5k4e1_queryctrl, -+ .g_ctrl = s5k4e1_g_ctrl, -+ .s_ctrl = s5k4e1_s_ctrl, -+ .s_gpio = s5k4e1_s_power, -+ /*.g_ext_ctrls = s5k4e1_g_ext_ctrls,*/ -+ /*.s_ext_ctrls = s5k4e1_s_ext_ctrls,*/ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = s5k4e1_g_register, -+ .s_register = s5k4e1_s_register, -+#endif -+}; -+ -+static const struct v4l2_subdev_ops s5k4e1_ops = { -+ .core = &s5k4e1_core_ops, -+ .video = &s5k4e1_video_ops, -+}; -+ -+/* -+ * Basic i2c stuff -+ */ -+/* -+static unsigned short normal_i2c[] = {0x36, I2C_CLIENT_END}; -+I2C_CLIENT_INSMOD; -+ -+static struct i2c_driver i2c_driver_s5k4e1_sensor; -+*/ -+static int s5k4e1_detect(struct i2c_client *client) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ int adap_id = i2c_adapter_id(adapter); -+ u32 value; -+ -+ DBG_entering; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { -+ eprintk("error i2c check func"); -+ return -ENODEV; -+ } -+ -+ if (adap_id != 1) { -+ eprintk("adap_id != 1"); -+ return -ENODEV; -+ } -+ -+ if (s5k4e1_wakeup()) { -+ eprintk("sensor wakeup failed"); -+ return -EIO; -+ } -+ -+ s5k4e1_read(client, 0x0003, &value); -+ dprintk(1, "Read from 0x0003: %x", value); -+ if ((value != 0x09)) -+ return -ENODEV; -+ -+ s5k4e1_read(client, 0x0000, &value); -+ dprintk(1, "Read from 0x0000: %x", value); -+ if ((value != 0x4e) && (value != 0x10)) -+ return -ENODEV; -+ -+ s5k4e1_read(client, 0x0001, &value); -+ dprintk(1, "Read from 0x0001: %x", value); -+ if ((value != 0x4e) && (value != 0x10)) -+ return -ENODEV; -+ -+ /*TODO EVT3 detect*/ -+ s5k4e1_read(client, 0x0002, &value); -+ dprintk(1, "Read from 0x0002: %x", value); -+ if (value == 0x0010) { -+ dprintk(1, "EVT3 module not supported!"); -+ return -ENODEV; -+ } -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static int s5k4e1_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct ci_sensor_config *info; -+ struct v4l2_subdev *sd; -+ int ret = -1; -+ -+ DBG_entering; -+ -+ v4l_info(client, "chip found @ 0x%x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ -+ /* -+ * Setup sensor configuration structure -+ */ -+ info = kzalloc(sizeof(struct ci_sensor_config), GFP_KERNEL); -+ if (!info) { -+ dprintk(0, "fail to malloc for ci_sensor_config"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ret = s5k4e1_detect(client); -+ if (ret) { -+ dprintk(0, "error s5k4e1_detect"); -+ goto out_free; -+ } -+ -+ sd = &info->sd; -+ v4l2_i2c_subdev_init(sd, client, &s5k4e1_ops); -+ -+ /* -+ * Initialization S5K4E1 -+ * then turn into standby mode -+ */ -+ ret = s5k4e1_init(client); -+ if (ret) { -+ dprintk(0, "error calling s5k4e1_init"); -+ goto out_free; -+ } -+ -+ s5k4e1_standby(); -+ dprintk(0, "Init s5k4e1 sensor successfully"); -+ -+ ret = 0; -+ goto out; -+ -+out_free: -+ kfree(info); -+ DBG_leaving; -+out: -+ -+ DBG_leaving; -+ return ret; -+} -+ -+ -+static int s5k4e1_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ DBG_entering; -+ -+ v4l2_device_unregister_subdev(sd); -+ kfree(to_sensor_config(sd)); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+/** -+ * i2c_driver for s5k4e1_sensor -+ */ -+static const struct i2c_device_id s5k4e1_id[] = { -+ {"s5k4e1", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, s5k4e1_id); -+ -+static struct v4l2_i2c_driver_data v4l2_i2c_data = { -+ .name = "s5k4e1", -+ .probe = s5k4e1_probe, -+ .remove = s5k4e1_remove, -+ /* .suspend = s5k4e1_suspend, -+ * .resume = s5k4e1_resume, */ -+ .id_table = s5k4e1_id, -+}; -+ -+MODULE_AUTHOR("Xiaolin Zhang "); -+MODULE_DESCRIPTION("A low-level driver for Samsung S5K4E1 sensors"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h -new file mode 100755 -index 0000000..d722035 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h -@@ -0,0 +1,662 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#define I2C_S5K4E1 0x6C -+/* Should add to kernel source */ -+#define I2C_DRIVERID_S5K4E1 1046 -+/* GPIO pin on Moorestown */ -+#define GPIO_SCLK_25 44 -+#define GPIO_STB_PIN 47 -+#define GPIO_STDBY_PIN 49 -+#define GPIO_RESET_PIN 50 -+ -+struct regval_list { -+ u16 reg_num; -+ u8 value; -+}; -+ -+/* -+ * Default register value -+ * 5Mega Pixel, 2592x1944 -+ */ -+/* MIPI register are removed by Wen */ -+ -+/* 2592x1944 */ -+static struct regval_list s5k4e1_res_qsxga_plus4[] = { -+ /* Reset for operation */ -+ {0x0100, 0x00}, /* stream off */ -+ {0x0103, 0x01}, /* software reset */ -+ -+/* -+ * Analog Setting -+ * This register is for FACTORY ONLY. -+ * If you change it without prior notification, -+ * You are RESPONSIBLE for the FAILURE that will happen in the future. -+ */ -+ -+/* CDS timing setting ... */ -+ {0x3000, 0x04}, /* ct_ld_start (default = 07h) */ -+ {0x3001, 0x02}, /* ct_sl_start (default = 05h) */ -+ {0x3002, 0x0C}, /* ct_rx_start (default = 21h) */ -+ {0x3003, 0x0E}, /* ct_cds_start (default = 23h) */ -+ {0x3004, 0x2C}, /* ct_smp_width (default = 60h) */ -+ {0x3005, 0x0D}, /* ct_az_width (default = 28h) */ -+ {0x3006, 0x39}, /* ct_s1r_width (default = 88h) */ -+ {0x3007, 0x02}, /* ct_tx_start (default = 06h) */ -+ {0x3008, 0x3C}, /* ct_tx_width 1.5us (default = 7Ch) */ -+ {0x3009, 0x3C}, /* ct_stx_width 1.5us (default = 7Ch) */ -+ {0x300A, 0x28}, /* ct_dtx_width 1us (default = 3Eh) */ -+ {0x300B, 0x15}, /* ct_rmp_rst_start (default = 44h) */ -+ {0x300C, 0x15}, /* ct_rmp_sig_start (default = 48h) */ -+ {0x300D, 0x02}, /* ct_rmp_lat (default = 02h) */ -+ {0x300E, 0xA9}, /* D-Shut en[7], CLP On[5], LD high[4] */ -+ -+/* CDS option setting ... */ -+ {0x3010, 0x00}, /* smp_en[2]=0(00) 1(04) row_id[1:0] = 00 */ -+ {0x3011, 0x7A}, /* RST_MX (288), SIG_MX (1024+352) */ -+ {0x3012, 0x30}, /* SIG offset1 48 code */ -+ {0x3013, 0xA0}, /* RST offset1 160 code */ -+ {0x3014, 0x00}, /* SIG offset2 */ -+ {0x3015, 0x00}, /* RST offset2 */ -+ {0x3016, 0x02}, /* ADC_SAT (510mV) */ -+ {0x3017, 0x94}, /* RMP_INIT[3:0](RMP_REG) 1.8V MS[6:4]=1 */ -+ {0x3018, 0x78}, /* rmp option - ramp connect[MSB] +RMP INIT DAC MIN */ -+ {0x301D, 0xD4}, /* CLP level (default = 0Fh) */ -+ -+ {0x3021, 0x02}, /* inrush ctrl[1] off */ -+ {0x3022, 0x44}, /* pump ring oscillator set [7:4]=CP, [3:0]=NCP */ -+ {0x3024, 0x40}, /* pix voltage 2.8V (default = 88h) */ -+ {0x3027, 0x08}, /* ntg voltage (default = 04h) */ -+ -+/* Pixel option setting ... */ -+ {0x301C, 0x05}, /* Pixel Bias [3:0] (default = 03h) */ -+ {0x30D8, 0x3F}, /* All tx off 2f, on 3f */ -+ -+/* ADLC setting ... */ -+ {0x3070, 0x5F}, /* [6]L-ADLC BPR, [4]ch sel, [3]L-ADLC, [2]F-ADLC */ -+ {0x3071, 0x00}, /* F&L-adlc max 127 (default = 11h, max 255) */ -+ {0x3080, 0x04}, /* F-ADLC filter A (default = 10h) */ -+ {0x3081, 0x38}, /* F-ADLC filter B (default = 20h) */ -+ -+/* Integration setting ... */ -+ {0x0202, 0x03}, /* coarse integration time */ -+ {0x0203, 0xCF}, -+ {0x0204, 0x00}, /* analog gain[msb] 0100 x8 0080 x4 */ -+ {0x0205, 0x80}, /* analog gain[lsb] 0040 x2 0020 x1 */ -+ -+/* Frame Length */ -+ {0x0340, 0x07}, /* Capture 07B4(1960[# of row]+12[V-blank]) */ -+ {0x0341, 0xA4}, /* Preview 03E0(980[# of row]+12[V-blank]) */ -+ -+/* Line Length */ -+ {0x0342, 0x0A}, /* 2738 */ -+ {0x0343, 0xB2}, /* (Same as sensor default) */ -+ -+/* embedded 2-line OFF setting ... */ -+/* 2608 x 1960 */ -+ {0x3084, 0x15}, /* SYNC Mode */ -+ -+/* (3) MIPI 2-lane Serial(TST = 0000b or TST = 0010b), 30 fps */ -+ -+ {0x30A9, 0x01}, -+ {0x0387, 0x01}, -+ -+ {0x30BD, 0x00}, /* SEL_CCP[0] */ -+ {0x30B2, 0x08}, /* PLL P = 8 */ -+ {0x30B3, 0x00}, /* PLL M[8] = 0 */ -+ {0x30B5, 0x01}, /* PLL S = 0 */ -+ {0x30BE, 0x1A}, /* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */ -+ -+ {0x30BF, 0xAB}, -+ {0x30C0, 0x00}, /* video_offset[7:4] 3240%12 */ -+ {0x30C1, 0x01}, /* pack video enable [0] */ -+ {0x30C8, 0x0C}, /* video_data_length 3260 = 2608 * 1.25 */ -+ {0x30C9, 0xA8}, -+ {0x30E2, 0x02}, /* num lanes[1:0] = 2 */ -+ {0x30EE, 0x02}, /* DPHY enable [1] */ -+ {0x30F1, 0x70}, /* DPHY BANDCTRL 800MHz=80.6MHz */ -+ {0x3111, 0x86}, /* Embedded data off [5] */ -+ -+ {0x034C, 0x0A}, -+ {0x034D, 0x20}, -+ {0x044E, 0x07}, -+ {0x034F, 0x98}, -+ -+ {0x0344, 0x00}, -+ {0x0345, 0x08}, -+ {0x0346, 0x00}, -+ {0x0347, 0x08}, -+ {0x0348, 0x0A}, -+ {0x0349, 0x27}, -+ {0x034A, 0x07}, -+ {0x034B, 0x9F}, -+ -+ /* This is to set FRAME_NUM > 0 */ -+ {0x30d9, 0x00}, -+ -+ /* Add this setting according to Bill's test */ -+ {0x0305, 0x05}, -+ {0x0306, 0x00}, -+ {0x0307, 0x3c}, -+ {0x30b5, 0x02}, -+ -+ {0x020E, 0x01}, /* Gr Digital Gain */ -+ {0x020F, 0x00}, -+ {0x0210, 0x01}, /* Red Digital Gain */ -+ {0x0211, 0x00}, -+ {0x0212, 0x01}, /* Blue Digital Gain */ -+ {0x0213, 0x00}, -+ {0x0214, 0x01}, /* Gb Digital Gain */ -+ {0x0215, 0x00}, -+ {0x0204, 0x00}, -+ {0x0205, 0x80}, -+ -+#if 1 -+ /*Apply Bill's setting*/ -+ {0x30E2, 0x02}, -+ {0x0305, 0x05}, -+ {0x0306, 0x00}, -+ {0x0307, 0x50}, /* vcc_out = 80 */ -+ {0x30B5, 0x01}, /* pll_s = 1 */ -+ {0x30B4, 0x50}, -+ -+ {0x30B2, 0x05}, -+ -+ {0x30BE, 0x1A}, /* DIV_M_PCLK = 5 */ -+ -+ {0x0100, 0x01}, /* stream on */ -+ {0xffff, 0xff}, -+#endif -+}; -+ -+/* 1920x1080 */ -+static struct regval_list s5k4e1_res_1080p[] = { -+/* Reset for operation ... */ -+ {0x0100, 0x00}, /* stream off */ -+ {0x0103, 0x01}, /* software reset */ -+ -+/* -+ * Analog Setting -+ * This register is for FACTORY ONLY. -+ * If you change it without prior notification, -+ * You are RESPONSIBLE for the FAILURE that will happen in the future. -+ */ -+ -+/* CDS timing setting ... */ -+ {0x3000, 0x04}, /* ct_ld_start (default = 07h) */ -+ {0x3001, 0x02}, /* ct_sl_start (default = 05h) */ -+ {0x3002, 0x0C}, /* ct_rx_start (default = 21h) */ -+ {0x3003, 0x0E}, /* ct_cds_start (default = 23h) */ -+ {0x3004, 0x2C}, /* ct_smp_width (default = 60h) */ -+ {0x3005, 0x0D}, /* ct_az_width (default = 28h) */ -+ {0x3006, 0x39}, /* ct_s1r_width (default = 88h) */ -+ {0x3007, 0x02}, /* ct_tx_start (default = 06h) */ -+ {0x3008, 0x3C}, /* ct_tx_width 1.5us (default = 7Ch) */ -+ {0x300A, 0x28}, /* ct_dtx_width 1us (default = 3Eh) */ -+ {0x300B, 0x15}, /* ct_rmp_rst_start (default = 44h) */ -+ {0x300C, 0x15}, /* ct_rmp_sig_start (default = 48h) */ -+ {0x300D, 0x02}, /* ct_rmp_lat (default = 02h) */ -+ {0x300E, 0xA9}, /* D-Shut en[7], CLP On[5], LD high[4] */ -+ -+/* CDS option setting ... */ -+ {0x3010, 0x00}, /* smp_en[2]=0(00) 1(04) row_id[1:0] = 00 */ -+ {0x3011, 0x7A}, /* RST_MX (288), SIG_MX (1024+352) */ -+ {0x3012, 0x30}, /* SIG offset1 48 code */ -+ {0x3013, 0xA0}, /* RST offset1 160 code */ -+ {0x3014, 0x00}, /* SIG offset2 */ -+ {0x3015, 0x00}, /* RST offset2 */ -+ {0x3016, 0x0A}, /* ADC_SAT (510mV) */ -+ {0x3017, 0x94}, /* RMP_INIT[3:0](RMP_REG) 1.8V MS[6:4]=1 */ -+ {0x3018, 0x78}, /* rmp option - ramp connect[MSB] +RMP INIT DAC MIN */ -+ -+ {0x301D, 0xD4}, /* CLP level (default = 0Fh) */ -+ -+ {0x3021, 0x02}, /* inrush ctrl[1] off */ -+ {0x3022, 0x41}, /* pump ring oscillator set [7:4]=CP, [3:0]=NCP */ -+ {0x3024, 0x08}, /* pix voltage 2.8V (default = 88h) */ -+ {0x3027, 0x08}, /* ntg voltage (default = 04h) */ -+ -+/* Pixel option setting ... */ -+ {0x301C, 0x05}, /* Pixel Bias [3:0] (default = 03h) */ -+ {0x30D8, 0x3F}, /* All tx off 2f, on 3f */ -+ -+/* ADLC setting ... */ -+ {0x3070, 0x5F}, /* [6]L-ADLC BPR, [4]ch sel, [3]L-ADLC, [2]F-ADLC */ -+ {0x3071, 0x00}, /* F&L-adlc max 127 (default = 11h, max 255) */ -+ {0x3080, 0x04}, /* F-ADLC filter A (default = 10h) */ -+ {0x3081, 0x38}, /* F-ADLC filter B (default = 20h) */ -+ -+/* Integration setting ... */ -+ {0x0202, 0x03}, /* coarse integration time */ -+ {0x0203, 0xCD}, -+ {0x0204, 0x00}, /* analog gain[msb] 0100 x8 0080 x4 */ -+ {0x0205, 0x80}, /* analog gain[lsb] 0040 x2 0020 x1 */ -+ -+/* Frame Length */ -+ {0x0340, 0x04}, /*Capture 07B4(1960[# of row]+12[V-blank]) */ -+ {0x0341, 0x44}, /*Preview 03E0(980[# of row]+12[V-blank]) */ -+ -+/* Line Length */ -+ {0x0342, 0x0A}, /* 2738 */ -+ {0x0343, 0xB2}, /*(Same as sensor default) */ -+ -+/* embedded 2-line OFF setting ... */ -+/* 1920 x 1080 */ -+ {0x3084, 0x15}, /* SYNC Mode */ -+ -+/* PLL & MIPI setting ... */ -+/* input clock 25MHz */ -+ -+/* (3) MIPI 2-lane Serial(TST = 0000b or TST = 0010b), 30 fps */ -+ {0x30BD, 0x00}, /* SEL_CCP[0] */ -+ {0x30B2, 0x08}, /* PLL P = 8 */ -+ {0x30B3, 0x00}, /* PLL M[8] = 0 */ -+ {0x30B4, 0x78}, /* PLL M = 129 */ -+ {0x30B5, 0x00}, /* PLL S = 0 */ -+ {0x30BE, 0x1A}, /* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */ -+ -+ {0x30BF, 0xAB}, -+ {0x30C0, 0x00}, /* video_offset[7:4] 2400%12 */ -+ {0x30C1, 0x01}, /* pack video enable [0] */ -+ {0x30C8, 0x09}, /* video_data_length 2400 = 1920 * 1.25 */ -+ {0x30C9, 0x60}, -+ {0x30E2, 0x02}, /* num lanes[1:0] = 2 */ -+ {0x30EE, 0x02}, /* DPHY enable [1] */ -+ {0x30F1, 0x70}, /* DPHY BANDCTRL 800MHz=80.6MHz */ -+ {0x3111, 0x86}, /* Embedded data off [5] */ -+ -+ {0x30b4, 0x20}, -+ {0x30b5, 0x01}, -+ -+ {0x30A9, 0x01}, -+ {0x0387, 0x01}, -+ {0x0344, 0x01}, /*x_addr_start 344 */ -+ {0x0345, 0x58}, -+ {0x0348, 0x08}, /*x_addr_end 2263 */ -+ {0x0349, 0xD7}, -+ {0x0346, 0x01}, /*y_addr_start 440 */ -+ {0x0347, 0xB8}, -+ {0x034A, 0x05}, /*y_addr_end 1519 */ -+ {0x034B, 0xEF}, -+ -+ {0x034C, 0x07}, /*x_output_size 1920 */ -+ {0x034D, 0x80}, -+ {0x034E, 0x04}, /*y_output_size 1080 */ -+ {0x034F, 0x38}, -+ -+ {0x30d9, 0x00}, -+ -+ {0x020E, 0x01}, /*Gr Digital Gain */ -+ {0x020F, 0x00}, -+ {0x0210, 0x01}, /*Red Digital Gain */ -+ {0x0211, 0x00}, -+ {0x0212, 0x01}, /*Blue Digital Gain */ -+ {0x0213, 0x00}, -+ {0x0214, 0x01}, /*Gb Digital Gain */ -+ {0x0215, 0x00}, -+ {0x0204, 0x00}, -+ {0x0205, 0x80}, -+ -+ -+ /*Apply Bill's setting*/ -+ {0x30E2, 0x02}, -+ {0x0305, 0x05}, -+ {0x0306, 0x00}, -+ {0x0307, 0x50}, /*vcc_out = 80 */ -+ {0x30B5, 0x01}, /*pll_s = 1 */ -+ {0x30B4, 0x50}, -+ -+ {0x30B2, 0x05}, -+ -+ {0x30BE, 0x1A}, /*DIV_M_PCLK = 5 */ -+ -+ {0x0383, 0x01}, -+ -+ {0x0100, 0x01}, /* stream on */ -+ {0xffff, 0xff}, -+ -+}; -+ -+/* 1280x720, V1F2 & H1F2 */ -+static struct regval_list s5k4e1_res_720p[] = { -+ {0x0100, 0x00}, /* stream off */ -+ {0x0103, 0x01}, /* software reset */ -+ -+/* CDS timing setting ... */ -+ {0x3000, 0x04}, -+ {0x3001, 0x02}, -+ {0x3002, 0x0C}, -+ {0x3003, 0x0E}, -+ {0x3004, 0x2C}, -+ {0x3005, 0x0D}, -+ {0x3006, 0x39}, -+ {0x3007, 0x02}, -+ {0x3008, 0x3C}, -+ {0x3009, 0x3C}, -+ {0x300A, 0x28}, -+ {0x300B, 0x15}, -+ {0x300C, 0x15}, -+ {0x300D, 0x02}, -+ {0x300E, 0xAB}, -+ -+/* CDS option setting ... */ -+ {0x3010, 0x00}, -+ {0x3011, 0x7A}, -+ {0x3012, 0x30}, -+ {0x3013, 0x90}, -+ {0x3014, 0x00}, -+ {0x3015, 0x00}, -+ {0x3016, 0x0A}, -+ {0x3017, 0x84}, -+ {0x3018, 0x78}, -+ {0x301D, 0xD4}, -+ -+ {0x3021, 0x02}, -+ {0x3022, 0x41}, -+ {0x3024, 0x08}, -+ {0x3027, 0x08}, -+ -+/* Pixel option setting ... */ -+ {0x301C, 0x05}, /* Pixel Bias [3:0] (default = 03h) */ -+ {0x30D8, 0x3F}, /* All tx off 2f, on 3f */ -+ -+/* ADLC setting ... */ -+ {0x3070, 0x5F}, -+ {0x3071, 0x00}, -+ {0x3080, 0x04}, -+ {0x3081, 0x38}, -+ -+/* Integration setting ... */ -+ {0x0202, 0x03}, -+ {0x0203, 0xD8}, -+ {0x0204, 0x00}, -+ {0x0205, 0x80}, -+ -+/*Frame Length*/ -+ {0x0340, 0x02}, -+ {0x0341, 0xDC}, -+ -+/* Line Length */ -+ {0x0342, 0x0A}, /*2738 */ -+ {0x0343, 0xB2}, -+ -+/* Average Sub-sampling */ -+ {0x0387, 0x03}, -+ {0x30a9, 0x02}, -+ -+/* embedded 2-line OFF setting ... */ -+/* 1280 x 720 */ -+ {0x3084, 0x15}, -+ -+/* PLL & MIPI setting ... */ -+ -+/* (3) MIPI 2-lane Serial(TST = 0000b or TST = 0010b), 60 fps */ -+ {0x30BD, 0x00}, -+ {0x30B2, 0x08}, -+ {0x30B3, 0x00}, -+ {0x30B4, 0x78}, -+ {0x30B5, 0x00}, -+ {0x30BE, 0x1A}, -+ -+ {0x30BF, 0xAB}, -+ {0x30C0, 0x40}, -+ {0x30C1, 0x01}, -+ {0x30C8, 0x06}, -+ {0x30C9, 0x40}, -+ -+ {0x30E2, 0x02}, -+ -+ {0x30b4, 0x20}, -+ {0x30b5, 0x01}, -+ -+ {0x30EE, 0x02}, -+ {0x30F1, 0x70}, -+ {0x3111, 0x86}, -+ -+/* MIPI Size Setting ... */ -+/* 1304 x 980 */ -+ {0x0344, 0x00}, -+ {0x0345, 0x18}, -+ {0x0348, 0x0A}, -+ {0x0349, 0x17}, -+ {0x0346, 0x01}, -+ {0x0347, 0x04}, -+ {0x034A, 0x06}, -+ {0x034B, 0xA3}, -+ -+ {0x0380, 0x00}, -+ {0x0381, 0x01}, -+ {0x0382, 0x00}, -+ {0x0383, 0x01}, -+ {0x0384, 0x00}, -+ {0x0385, 0x01}, -+ {0x0386, 0x00}, -+ {0x0387, 0x03}, -+ -+ {0x034C, 0x05}, /* x_output_size = 1280 */ -+ {0x034D, 0x00}, -+ {0x034E, 0x02}, /* y_output_size = 720 */ -+ {0x034F, 0xD0}, -+ -+ {0x30d9, 0x00}, -+ -+ {0x020E, 0x01}, -+ {0x020F, 0x00}, -+ {0x0210, 0x01}, -+ {0x0211, 0x00}, -+ {0x0212, 0x01}, -+ {0x0213, 0x00}, -+ {0x0214, 0x01}, -+ {0x0215, 0x00}, -+ {0x0204, 0x01}, -+ {0x0205, 0x00}, -+ -+ /*Apply Bill's setting*/ -+ {0x30E2, 0x02}, -+ {0x0305, 0x05}, -+ {0x0306, 0x00}, -+ {0x0307, 0x50}, /*vcc_out = 80 */ -+ {0x30B5, 0x01}, /*pll_s = 1 */ -+ {0x30B4, 0x50}, -+ -+ {0x30B2, 0x05}, -+ -+ {0x30BE, 0x15}, /*DIV_M_PCLK = 5 */ -+ -+ {0x0100, 0x01}, /* stream on */ -+ {0xffff, 0xff}, -+}; -+ -+/*VGA*/ -+static struct regval_list s5k4e1_res_vga_ac04_bill[] = { -+ {0x0100, 0x00}, /* stream off */ -+ {0x0103, 0x01}, /* software reset */ -+ -+ {0x3000, 0x04}, -+ {0x3001, 0x02}, -+ {0x3002, 0x0C}, -+ {0x3003, 0x0E}, -+ {0x3004, 0x2C}, -+ {0x3005, 0x0D}, -+ {0x3006, 0x39}, -+ {0x3007, 0x02}, -+ {0x3008, 0x3C}, -+ {0x3009, 0x3C}, -+ {0x300A, 0x28}, -+ {0x300B, 0x15}, -+ {0x300C, 0x15}, -+ {0x300D, 0x02}, -+ {0x300E, 0xA8}, -+ -+ {0x3010, 0x00}, -+ {0x3011, 0x7A}, -+ {0x3012, 0x30}, -+ {0x3013, 0xA0}, -+ {0x3014, 0x00}, -+ {0x3015, 0x00}, -+ {0x3016, 0x0A}, -+ {0x3017, 0x94}, -+ {0x3018, 0x78}, -+ -+ {0x301D, 0xD4}, -+ -+ {0x3021, 0x02}, -+ {0x3022, 0x41}, -+ {0x3024, 0x08}, -+ {0x3027, 0x08}, -+ -+ {0x301C, 0x05}, -+ {0x30D8, 0x3F}, -+ -+ {0x3070, 0x5F}, -+ {0x3071, 0x00}, -+ {0x3080, 0x04}, -+ {0x3081, 0x38}, -+ -+ {0x0202, 0x03}, -+ {0x0203, 0xD4}, -+ {0x0204, 0x00}, -+ {0x0205, 0x20}, -+ -+ {0x0340, 0x03}, -+ {0x0341, 0xE0}, -+ -+ {0x0342, 0x0A}, -+ {0x0343, 0xB2}, -+ -+ {0x0344, 0x00}, -+ {0x0345, 0x18}, -+ {0x0348, 0x0A}, -+ {0x0349, 0x17}, -+ {0x0346, 0x00}, -+ {0x0347, 0x14}, -+ {0x034A, 0x07}, -+ {0x034B, 0x93}, -+ -+ {0x034C, 0x02}, -+ {0x034D, 0x80}, -+ {0x034E, 0x01}, -+ {0x034F, 0xE0}, -+ -+ {0x0380, 0x00}, -+ {0x0381, 0x01}, -+ {0x0382, 0x00}, -+ {0x0383, 0x07}, -+ {0x0384, 0x00}, -+ {0x0385, 0x01}, -+ {0x0386, 0x00}, -+ {0x0387, 0x07}, -+ -+ {0x3084, 0x15}, -+ -+ {0x30BD, 0x00}, -+ -+ -+ {0x30b3, 0x00}, -+ {0x30b4, 0x57}, -+ {0x30b5, 0x01}, -+ {0x30f1, 0x70}, -+ -+ {0x30BE, 0x1A}, -+ -+ {0x30BF, 0xAB}, -+ {0x30C0, 0x80}, -+ {0x30C1, 0x01}, -+ {0x30C8, 0x03}, -+ {0x30C9, 0x20}, -+ -+ {0x30b2, 0x06}, -+ {0x30E2, 0x02}, -+ -+ {0x30EE, 0x02}, -+ -+ {0x3111, 0x86}, -+ -+ {0x30d9, 0x00}, -+ -+ {0x020E, 0x01}, -+ {0x020F, 0x00}, -+ {0x0210, 0x01}, -+ {0x0211, 0x00}, -+ {0x0212, 0x01}, -+ {0x0213, 0x00}, -+ {0x0214, 0x01}, -+ {0x0215, 0x00}, -+ {0x0204, 0x01}, -+ {0x0205, 0x00}, -+ -+#if 1 -+ /* Apply Bill's setting */ -+ {0x30E2, 0x02}, -+ {0x0305, 0x05}, -+ {0x0306, 0x00}, -+ {0x0307, 0x50}, -+ {0x30B5, 0x01}, -+ {0x30B4, 0x50}, -+ -+ {0x30B2, 0x05}, -+ -+ {0x30BE, 0x15}, -+ -+ /* {0x0100, 0x01}, */ -+ /* {0xffff, 0xff}, */ -+#endif -+ -+#if 1 -+ /* 1304x980 */ -+ {0x3013, 0x90}, -+ {0x3017, 0x84}, -+ {0x30A9, 0x02}, -+ {0x300E, 0xAB}, -+ -+ {0x0387, 0x03}, -+ {0x0344, 0x00}, /* x_addr_start = 0 */ -+ {0x0345, 0x00}, -+ {0x0348, 0x0A}, /* x_addr_end = 2607 */ -+ {0x0349, 0x2F}, -+ {0x0346, 0x00}, /* y_addr_start = 0 */ -+ {0x0347, 0x00}, -+ {0x034A, 0x07}, /* y_addr_end = 1959 */ -+ {0x034B, 0xA7}, -+ {0x0380, 0x00}, -+ {0x0381, 0x01}, -+ {0x0382, 0x00}, -+ {0x0383, 0x01}, -+ {0x0384, 0x00}, -+ {0x0385, 0x01}, -+ {0x0386, 0x00}, -+ {0x0387, 0x03}, -+ {0x034c, 0x05}, /* x_output_size = 1304 */ -+ {0x034d, 0x18}, -+ {0x034e, 0x03}, /* y_output_size = 980 */ -+ {0x034f, 0xd4}, -+ {0x30BF, 0xAB}, -+ {0x30c0, 0xa0}, -+ {0x30C8, 0x06}, /* x_output_size * 1.25 */ -+ {0x30c9, 0x5e}, -+ -+ {0x0100, 0x01}, -+ {0xffff, 0xff}, -+ -+#endif -+}; -diff --git a/drivers/media/video/mrstci/mrsts5k4e1_motor/Kconfig b/drivers/media/video/mrstci/mrsts5k4e1_motor/Kconfig -new file mode 100755 -index 0000000..27cb730 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1_motor/Kconfig -@@ -0,0 +1,9 @@ -+config VIDEO_MRST_S5K4E1_MOTOR -+ tristate "Moorestown s5k4e1 motor" -+ depends on I2C && VIDEO_MRST_ISP && VIDEO_MRST_S5K4E1 -+ -+ ---help--- -+ Say Y here if your platform support s5k4e1 motor. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mrstov2650.ko. -diff --git a/drivers/media/video/mrstci/mrsts5k4e1_motor/Makefile b/drivers/media/video/mrstci/mrsts5k4e1_motor/Makefile -new file mode 100644 -index 0000000..68c9fbc ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1_motor/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_VIDEO_MRST_S5K4E1_MOTOR) += mrsts5k4e1_motor.o -+ -+EXTRA_CFLAGS += -I$(src)/../include -diff --git a/drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.c b/drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.c -new file mode 100644 -index 0000000..cd2813b ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.c -@@ -0,0 +1,430 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "mrsts5k4e1_motor.h" -+ -+static int s5k4e1_motor_debug; -+module_param(s5k4e1_motor_debug, int, 0644); -+MODULE_PARM_DESC(s5k4e1_motor_debug, "Debug level (0-1)"); -+ -+#define dprintk(level, fmt, arg...) \ -+ do { \ -+ if (s5k4e1_motor_debug >= level) \ -+ printk(KERN_DEBUG "mrstisp@%s: " fmt "\n", __func__, ## arg); \ -+ } while (0) -+ -+#define eprintk(fmt, arg...) \ -+ printk(KERN_ERR "mrstisp@%s: line %d: " fmt "\n", \ -+ __func__, __LINE__, ## arg); -+ -+#define DBG_entering dprintk(1, "entering"); -+#define DBG_leaving dprintk(1, "leaving"); -+#define DBG_line dprintk(1, " line: %d", __LINE__); -+ -+static inline struct s5k4e1_motor *to_motor_config(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct s5k4e1_motor, sd); -+} -+ -+/*static struct s5k4e1_motor *config; */ -+static int motor_read(struct i2c_client *c, u32 *reg) -+{ -+ int ret; -+ struct i2c_msg msg; -+ u8 msgbuf[3]; -+ -+ msgbuf[0] = 0; -+ msgbuf[1] = 0; -+ msgbuf[2] = 0; -+ -+ memset(&msg, 0, sizeof(msg)); -+ msg.addr = c->addr; -+ msg.buf = msgbuf; -+ msg.len = 3; -+ msg.flags = I2C_M_RD; -+ -+ ret = i2c_transfer(c->adapter, &msg, 1); -+ -+ *reg = (msgbuf[0] << 16 | msgbuf[1] << 8 | msgbuf[2]); -+ -+ ret = (ret == 1) ? 0 : -1; -+ return ret; -+} -+ -+static int motor_write(struct i2c_client *c, u32 reg) -+{ -+ int ret; -+ struct i2c_msg msg; -+ u8 msgbuf[3]; -+ -+ memset(&msg, 0, sizeof(msg)); -+ msgbuf[0] = (reg & 0x00FFFFFFFF) >> 16; -+ msgbuf[1] = (reg & 0x0000FFFF) >> 8 ; -+ msgbuf[2] = reg; -+ -+ msg.addr = c->addr; -+ msg.flags = 0; -+ msg.buf = msgbuf; -+ msg.len = 3; -+ -+ ret = i2c_transfer(c->adapter, &msg, 1); -+ -+ ret = (ret == 1) ? 0 : -1; -+ return ret; -+} -+ -+static int s5k4e1_motor_goto_position(struct i2c_client *c, -+ unsigned short code, -+ struct s5k4e1_motor *config, -+ unsigned int step) -+{ -+ int max_code, min_code; -+ int timeout = 25; /*TODO: check the timeout time */ -+ u8 cmdh, cmdl, finished; -+ u32 cmd = 0, val = 0; -+ -+ max_code = config->macro_code; -+ min_code = config->infin_code; -+ -+ if (code > max_code) -+ code = max_code; -+ if (code < min_code) -+ code = min_code; -+ -+ cmdh = MOTOR_DAC_CTRL_MODE_1 | (code >> 8); /* PS EN x x M W TD9 TD8*/ -+ cmdl = code; /* TD7 ~ TD0 */ -+ cmd |= (cmdh << 16) | (cmdl << 8); -+ -+ dprintk(1, "cmdh: %x, cmdl: %x, cmd: %x", cmdh, cmdl, cmd); -+ dprintk(1, "DAC code: %x", code); -+ -+ motor_write(c, cmd); -+ finished = 0; -+ while ((!finished) && timeout--) { -+ msleep(1); -+ motor_read(c, &val); -+ cmdh = val >> 16; -+ cmdl = val >> 8; -+ -+ dprintk(1, "cmdh & MOTOR_F = %x", cmdh & MOTOR_F); -+ finished = cmdh & MOTOR_F; -+ finished = (finished) ? 0 : 1; -+ }; -+ -+ if (finished) { -+ dprintk(1, "Moving from code %x to code %x takes %d ms.", -+ config->cur_code, code, 25-timeout); -+ return 0; -+ } else { -+ eprintk("Unable to move motor to step %d, TIMEOUT!!", step); -+ return -1; -+ } -+ -+} -+ -+int s5k4e1_motor_wakeup(struct i2c_client *client) -+{ -+ /* hardware wakeup: set PS = 1 */ -+ return motor_write(client, 0xC00000); -+} -+ -+int s5k4e1_motor_standby(struct i2c_client *client) -+{ -+ /* hardware standby: set PS = 0 */ -+ return motor_write(client, 0x400000); -+} -+ -+int s5k4e1_motor_init(struct i2c_client *client, struct s5k4e1_motor *config) -+{ -+ -+ int ret; -+ int infin_cur, macro_cur; -+ int step_res, step_time; -+ int val; -+ -+ DBG_entering; -+ infin_cur = MAX(MOTOR_INFIN_CUR, MOTOR_DAC_MIN_CUR); -+ macro_cur = MIN(MOTOR_MACRO_CUR, MOTOR_DAC_MAX_CUR); -+ step_res = 1 << MOTOR_STEP_SHIFT; -+ step_time = MOTOR_STEP_TIME; -+ -+ /*config->motor = client;*/ -+ config->infin_cur = infin_cur; -+ config->macro_cur = macro_cur; -+ -+ config->infin_code = MOTOR_INFIN_CODE; -+ config->macro_code = MOTOR_MACRO_CODE; -+ -+ config->max_step = ((config->macro_code - config->infin_code) -+ >> MOTOR_STEP_SHIFT) + 1; -+ config->step_res = step_res; -+ config->step_time = step_time; -+ -+ dprintk(1, "max_step: %d, step_res: %d, step_time: %d", -+ config->max_step, step_res, step_time); -+ -+ /* Set motor step time and resolution */ -+ val = (MOTOR_DAC_CTRL_MODE_0 << 16) | (step_res << 8) | step_time; -+ ret = motor_write(client, val); -+ -+ /* Note here, maybe macro_code */ -+ ret |= s5k4e1_motor_goto_position(client, config->infin_code, -+ config, 0); -+ if (!ret) { -+ config->cur_code = config->infin_code; -+ dprintk(1, "Motor initialization success!"); -+ } else -+ eprintk("Error while initializing motor!!!"); -+ -+ return ret; -+} -+ -+int s5k4e1_motor_set_focus(struct i2c_client *c, -+ unsigned int step, -+ struct s5k4e1_motor *config) -+{ -+ int s_code, ret; -+ int max_step = config->max_step; -+ unsigned int val = step; -+ -+ if (val > max_step) -+ val = max_step; -+ -+ s_code = (val << MOTOR_STEP_SHIFT); -+ s_code += config->infin_code; -+ -+ ret = s5k4e1_motor_goto_position(c, s_code, config, step); -+ if (!ret) -+ config->cur_code = s_code; -+ -+ return ret; -+} -+ -+static int s5k4e1_motor_g_ctrl(struct v4l2_subdev *sd, -+ struct v4l2_control *ctrl) -+{ -+ struct i2c_client *c = v4l2_get_subdevdata(sd); -+ struct s5k4e1_motor *config = to_motor_config(sd); -+ int ret; -+ -+ DBG_entering; -+ ret = s5k4e1_motor_get_focus(c, &ctrl->value, config); -+ if (ret) { -+ eprintk("error call s5k4e1_motor_get_focue"); -+ return ret; -+ } -+ DBG_leaving; -+ return 0; -+} -+ -+static int s5k4e1_motor_s_ctrl(struct v4l2_subdev *sd, -+ struct v4l2_control *ctrl) -+{ -+ struct i2c_client *c = v4l2_get_subdevdata(sd); -+ struct s5k4e1_motor *config = to_motor_config(sd); -+ int ret; -+ -+ DBG_entering; -+ ret = s5k4e1_motor_set_focus(c, ctrl->value, config); -+ if (ret) { -+ eprintk("error call s5k4e1_motor_set_focue"); -+ return ret; -+ } -+ DBG_leaving; -+ return 0; -+} -+ -+int s5k4e1_motor_get_focus(struct i2c_client *c, -+ unsigned int *step, -+ struct s5k4e1_motor *config) -+{ -+ int ret_step; -+ -+ ret_step = ((config->cur_code - config->infin_code) -+ >> MOTOR_STEP_SHIFT); -+ -+ if (ret_step <= config->max_step) -+ *step = ret_step; -+ else -+ *step = config->max_step; -+ -+ return 0; -+} -+ -+int s5k4e1_motor_max_step(struct i2c_client *c, -+ unsigned int *max_code, -+ struct s5k4e1_motor *config) -+{ -+ if (config->max_step != 0) -+ *max_code = config->max_step; -+ return 0; -+ -+} -+ -+static int s5k4e1_motor_queryctrl(struct v4l2_subdev *sd, -+ struct v4l2_queryctrl *qc) -+{ -+ struct s5k4e1_motor *config = to_motor_config(sd); -+ -+ DBG_entering; -+ dprintk(1, "got focus range of %d", config->max_step); -+ if (config->max_step != 0) -+ qc->maximum = config->max_step; -+ DBG_leaving; -+ return 0; -+} -+ -+static const struct v4l2_subdev_core_ops s5k4e1_motor_core_ops = { -+ .g_ctrl = s5k4e1_motor_g_ctrl, -+ .s_ctrl = s5k4e1_motor_s_ctrl, -+ .queryctrl = s5k4e1_motor_queryctrl, -+}; -+ -+static const struct v4l2_subdev_ops s5k4e1_motor_ops = { -+ .core = &s5k4e1_motor_core_ops, -+}; -+ -+static int s5k4e1_motor_detect(struct i2c_client *client) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ int adap_id = i2c_adapter_id(adapter); -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { -+ eprintk("error i2c check func"); -+ return -ENODEV; -+ } -+ -+ if (adap_id != 1) { -+ eprintk("adap_id != 1"); -+ return -ENODEV; -+ } -+ -+ if (s5k4e1_motor_wakeup(client)) -+ eprintk("unable to wakeup s5k4e1 motor."); -+ -+ return 0; -+} -+ -+static int s5k4e1_motor_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct s5k4e1_motor *info; -+ struct v4l2_subdev *sd; -+ int ret = -1; -+/* struct i2c_client *motor; */ -+ -+ DBG_entering; -+ v4l_info(client, "chip found @ 0x%x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ /* -+ * Setup sensor configuration structure -+ */ -+ info = kzalloc(sizeof(struct s5k4e1_motor), GFP_KERNEL); -+ if (!info) { -+ eprintk("fail to malloc for ci_motor"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ret = s5k4e1_motor_detect(client); -+ if (ret) { -+ eprintk("error s5k4e1_motor_detect"); -+ goto out_free; -+ } -+ -+ sd = &info->sd; -+ v4l2_i2c_subdev_init(sd, client, &s5k4e1_motor_ops); -+ -+ /* -+ * Initialization S5K4E1 -+ * then turn into standby mode -+ */ -+ ret = s5k4e1_motor_init(client, info); -+ if (ret) { -+ eprintk("error calling s5k4e1_motor_init"); -+ goto out_free; -+ } -+ -+ ret = 0; -+ goto out; -+ -+out_free: -+ kfree(info); -+ DBG_leaving; -+out: -+ return ret; -+} -+ -+/* -+ * XXX: Need to be checked -+ */ -+static int s5k4e1_motor_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ DBG_entering; -+ -+ v4l2_device_unregister_subdev(sd); -+ kfree(to_motor_config(sd)); -+ -+ DBG_leaving; -+ return 0; -+} -+ -+static const struct i2c_device_id s5k4e1_motor_id[] = { -+ {"s5k4e1_motor", 0}, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, s5k4e1_motor_id); -+ -+static struct v4l2_i2c_driver_data v4l2_i2c_data = { -+ .name = "s5k4e1_motor", -+ .probe = s5k4e1_motor_probe, -+ .remove = s5k4e1_motor_remove, -+ /* .suspend = ov5630_suspend, -+ * .resume = ov5630_resume, */ -+ .id_table = s5k4e1_motor_id, -+}; -+MODULE_AUTHOR("Xiaolin Zhang "); -+MODULE_DESCRIPTION("A low-level driver for Samsung S5K4E1 sensor motor"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.h b/drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.h -new file mode 100644 -index 0000000..04f9436 ---- /dev/null -+++ b/drivers/media/video/mrstci/mrsts5k4e1_motor/mrsts5k4e1_motor.h -@@ -0,0 +1,102 @@ -+/* -+ * Support for Moorestown Langwell Camera Imaging ISP subsystem. -+ * -+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301, USA. -+ * -+ * -+ * Xiaolin Zhang -+ */ -+ -+#include -+ -+/* DAC output max current (mA) */ -+#define MOTOR_DAC_MAX_CUR 125 -+/* DAC output min current (mA) */ -+#define MOTOR_DAC_MIN_CUR 1 -+/* DAC max code (Hex) */ -+#define MOTOR_DAC_CODE_MAX 0x3FF -+/* DAC min code (Hex) */ -+#define MOTOR_DAC_CODE_MIN 0x0 -+ -+/* VCM start code (Hex) */ -+#define MOTOR_INFIN_CODE 0x120 -+/* VCM stop code (Hex) */ -+#define MOTOR_MACRO_CODE 0x205 -+ -+#define MOTOR_STEP_SHIFT 4 /* Step res = 2^4 = 10H */ -+#define MOTOR_STEP_TIME 20 /* Step time = 50us x 20d = 1ms */ -+ -+/* VCM start current (mA) */ -+#define MOTOR_INFIN_CUR ((MOTOR_DAC_MAX_CUR / MOTOR_DAC_CODE_MAX) \ -+ * MOTOR_INFIN_CODE + 1) -+/* VCM max current for Macro (mA) */ -+#define MOTOR_MACRO_CUR ((MOTOR_DAC_MAX_CUR / MOTOR_DAC_CODE_MAX) \ -+ * MOTOR_MACRO_CODE + 1) -+ -+ -+#define MOTOR_DAC_BIT_RES 10 -+#define MOTOR_DAC_MAX_CODE ((1 << MOTOR_DAC_BIT_RES) - 1) -+ -+#define MOTOR_STEP_SHIFT 4 -+ -+#define MAX(x, y) ((x) > (y) ? (x) : (y)) -+#define MIN(x, y) ((x) < (y) ? (x) : (y)) -+ -+/* DAC register related define */ -+#define MOTOR_PS (1 << 7) /* power save */ -+#define MOTOR_EN (1 << 6) /* out pin status*/ -+#define MOTOR_M (1 << 3) /* mode select */ -+#define MOTOR_W (1 << 2) /* register address */ -+#define MOTOR_F (1 << 4) /* finish flag */ -+ -+#define MOTOR_DAC_CODE_L(x) (x & 0xff) -+#define MOTOR_DAC_CODE_H(x) ((x >> 8) & 0xf3) -+ -+/* Step mode setting */ -+#define MOTOR_DAC_CTRL_MODE_0 0xCC -+/* DAC code setting */ -+#define MOTOR_DAC_CTRL_MODE_1 0xC8 -+ -+#define S5K4E1_MOTOR_ADDR (0x18 >> 1) -+/*#define POWER_EN_PIN 7*/ -+#define GPIO_AF_PD 95 -+ -+#define DEBUG 0 -+ -+struct s5k4e1_motor{ -+ /*struct i2c_client *motor;*/ -+ unsigned int infin_cur; -+ unsigned int infin_code; -+ unsigned int macro_cur; -+ unsigned int macro_code; -+ unsigned int max_step; -+ unsigned int cur_code; -+ unsigned int step_res; -+ unsigned int step_time; -+ struct v4l2_subdev sd; -+}; -+ -+extern int s5k4e1_motor_init(struct i2c_client *client, -+ struct s5k4e1_motor *config); -+extern int s5k4e1_motor_standby(struct i2c_client *client); -+extern int s5k4e1_motor_wakeup(struct i2c_client *client); -+extern int s5k4e1_motor_set_focus(struct i2c_client *c, unsigned int step, -+ struct s5k4e1_motor *config); -+extern int s5k4e1_motor_get_focus(struct i2c_client *c, unsigned int *step, -+ struct s5k4e1_motor *config); -+extern int s5k4e1_motor_max_step(struct i2c_client *c, unsigned int *max_code, -+ struct s5k4e1_motor *config); --- -1.6.0.6 - -- cgit v1.2.3