mirror of
https://git.yoctoproject.org/meta-ti
synced 2026-07-23 04:17:00 +00:00
07e8c30da9
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
1548 lines
45 KiB
Diff
1548 lines
45 KiB
Diff
From eefcf5de4689fbd00119d7a7df75244ca6ca1187 Mon Sep 17 00:00:00 2001
|
|
From: Koen Kooi <koen@dominion.thruhere.net>
|
|
Date: Sun, 1 May 2011 16:40:54 +0200
|
|
Subject: [PATCH 1/2] mt9p031: import driver from https://github.com/Aptina/BeagleBoard-xM/tree/master/Angstrom/MT9P031
|
|
|
|
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
|
|
---
|
|
drivers/media/video/Kconfig | 6 +
|
|
drivers/media/video/Makefile | 1 +
|
|
drivers/media/video/mt9p031.c | 1445 +++++++++++++++++++++++++++++++++++++++
|
|
include/media/mt9p031.h | 30 +
|
|
include/media/v4l2-chip-ident.h | 1 +
|
|
5 files changed, 1483 insertions(+), 0 deletions(-)
|
|
create mode 100644 drivers/media/video/mt9p031.c
|
|
create mode 100644 include/media/mt9p031.h
|
|
|
|
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
|
|
index 4c1fb0f..59f1133 100644
|
|
--- a/drivers/media/video/Kconfig
|
|
+++ b/drivers/media/video/Kconfig
|
|
@@ -832,6 +832,12 @@ config SOC_CAMERA_MT9M111
|
|
help
|
|
This driver supports MT9M111 and MT9M112 cameras from Micron
|
|
|
|
+config SOC_CAMERA_MT9P031
|
|
+ tristate "mt9p031 support"
|
|
+ depends on SOC_CAMERA && I2C
|
|
+ help
|
|
+ This driver supports MT9P031 cameras from Micron.
|
|
+
|
|
config SOC_CAMERA_MT9T031
|
|
tristate "mt9t031 support"
|
|
depends on SOC_CAMERA && I2C
|
|
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
|
|
index fb7e46c..f3110e7 100644
|
|
--- a/drivers/media/video/Makefile
|
|
+++ b/drivers/media/video/Makefile
|
|
@@ -79,6 +79,7 @@ obj-$(CONFIG_VIDEO_MT9V113) += mt9v113.o
|
|
|
|
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
|
|
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
|
|
+obj-$(CONFIG_SOC_CAMERA_MT9P031) += mt9p031.o
|
|
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
|
|
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
|
|
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
|
|
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
|
|
new file mode 100644
|
|
index 0000000..3047e43
|
|
--- /dev/null
|
|
+++ b/drivers/media/video/mt9p031.c
|
|
@@ -0,0 +1,1445 @@
|
|
+/*
|
|
+ * drivers/media/video/mt9p031.c
|
|
+ *
|
|
+ * Aptina mt9p031 sensor driver
|
|
+ *
|
|
+ *
|
|
+ * Copyright (C) 2010 Aptina Imaging
|
|
+ *
|
|
+ *
|
|
+ * Leverage mt9p012.c
|
|
+ *
|
|
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
+ *
|
|
+ */
|
|
+
|
|
+
|
|
+#include <linux/delay.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/videodev2.h>
|
|
+#include <linux/sysfs.h>
|
|
+
|
|
+#include <media/mt9p031.h>
|
|
+#include <media/v4l2-int-device.h>
|
|
+#include <media/v4l2-chip-ident.h>
|
|
+
|
|
+#define MT9P031_DEBUG
|
|
+
|
|
+#ifdef MT9P031_DEBUG
|
|
+#define DPRINTK_DRIVER(format, ...) \
|
|
+ printk(KERN_INFO "_MT9P031_DRIVER: " format, ## __VA_ARGS__)
|
|
+#else
|
|
+#define DPRINTK_DRIVER(format, ...)
|
|
+#endif
|
|
+/************************************************************************
|
|
+ macro
|
|
+************************************************************************/
|
|
+// Macro to configure I2c level shifter. Use only for MT9P031 Headboards from Aptina; not required for Leopard Imaging or elsewise.
|
|
+#define MT9P031_HEADBOARD
|
|
+
|
|
+#define MT9P031_CHIP_ID 0x1801
|
|
+#define MT9P031_MAX_HEIGHT 1944
|
|
+#define MT9P031_MAX_WIDTH 2592
|
|
+#define MT9P031_MIN_HEIGHT 2
|
|
+#define MT9P031_MIN_WIDTH 2
|
|
+
|
|
+#define VGA_HEIGHT 480
|
|
+#define VGA_WIDTH 640
|
|
+
|
|
+#define MT9P031_NORMAL_OPERATION_MODE (0x1F82) //write
|
|
+#define MT9P031_OUTPUT_CTRL_CHIP_UNSELECT (0x1F80)
|
|
+#define MT9P031_OUTPUT_CTRL_HALT (0x1F83)
|
|
+
|
|
+/* FPS Capabilities */
|
|
+#define MT9P031_MIN_FPS 10
|
|
+#define MT9P031_DEF_FPS 30
|
|
+#define MT9P031_MAX_FPS 50
|
|
+
|
|
+#define MT9P031_XCLK_NOM_1 12000000
|
|
+#define MT9P031_XCLK_NOM_2 24000000
|
|
+
|
|
+/* Analog gain values */
|
|
+#define MT9P031_EV_MIN_GAIN 0
|
|
+#define MT9P031_EV_MAX_GAIN 47
|
|
+#define MT9P031_EV_DEF_GAIN 24
|
|
+#define MT9P031_EV_GAIN_STEP 1
|
|
+
|
|
+/* Exposure time values */
|
|
+#define MT9P031_MIN_EXPOSURE 15000
|
|
+#define MT9P031_MAX_EXPOSURE 128000
|
|
+#define MT9P031_DEF_EXPOSURE 33000
|
|
+#define MT9P031_EXPOSURE_STEP 100
|
|
+#define Q12 4096
|
|
+/************************************************************************
|
|
+ Register Address
|
|
+************************************************************************/
|
|
+
|
|
+#define REG_MT9P031_CHIP_VERSION 0x00
|
|
+#define REG_MT9P031_ROWSTART 0x01
|
|
+#define REG_MT9P031_COLSTART 0x02
|
|
+#define REG_MT9P031_HEIGHT 0x03
|
|
+#define REG_MT9P031_WIDTH 0x04
|
|
+#define REG_MT9P031_HBLANK 0x05
|
|
+#define REG_MT9P031_VBLANK 0x06
|
|
+#define REG_MT9P031_OUT_CTRL 0x07
|
|
+#define REG_MT9P031_SHUTTER_WIDTH_U 0x08
|
|
+#define REG_MT9P031_SHUTTER_WIDTH_L 0x09
|
|
+#define REG_MT9P031_PCLK_CTRL 0x0a
|
|
+#define REG_MT9P031_RESTART 0x0b
|
|
+#define REG_MT9P031_SHUTTER_DELAY 0x0c
|
|
+#define REG_MT9P031_RESET 0x0d
|
|
+
|
|
+#define REG_MT9P031_PLL_CTRL 0x10
|
|
+#define REG_MT9P031_PLL_CONF1 0x11
|
|
+#define REG_MT9P031_PLL_CONF2 0x12
|
|
+
|
|
+#define REG_MT9P031_READ_MODE1 0x1e
|
|
+#define REG_MT9P031_READ_MODE2 0x20
|
|
+#define REG_MT9P031_ROW_ADDR_MODE 0x22
|
|
+#define REG_MT9P031_COL_ADDR_MODE 0x23
|
|
+#define REG_MT9P031_GREEN_1_GAIN 0x2b
|
|
+#define REG_MT9P031_BLUE_GAIN 0x2c
|
|
+#define REG_MT9P031_RED_GAIN 0x2d
|
|
+#define REG_MT9P031_GREEN_2_GAIN 0x2e
|
|
+#define REG_MT9P031_GLOBAL_GAIN 0x35
|
|
+#define REG_MT9P031_CHIP_VERSION_ALT 0x0FF
|
|
+
|
|
+/************************************************************************
|
|
+ struct
|
|
+************************************************************************/
|
|
+struct mt9p031_frame_size {
|
|
+ u16 width;
|
|
+ u16 height;
|
|
+};
|
|
+
|
|
+struct mt9p031_priv {
|
|
+ struct mt9p031_platform_data *pdata;
|
|
+ struct v4l2_int_device *v4l2_int_device;
|
|
+ struct i2c_client *client;
|
|
+ struct v4l2_pix_format pix;
|
|
+ struct v4l2_fract timeperframe;
|
|
+ unsigned long xclk_current;
|
|
+ int fps;
|
|
+ int scaler;
|
|
+ int ver;
|
|
+ int model;
|
|
+ u32 flags;
|
|
+/* for flags */
|
|
+#define INIT_DONE (1<<0)
|
|
+};
|
|
+
|
|
+struct mt9p031_priv sysPriv;
|
|
+
|
|
+static const struct v4l2_fmtdesc mt9p031_formats[] = {
|
|
+ {
|
|
+ .description = "Bayer (sRGB) 10 bit",
|
|
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
|
|
+ },
|
|
+};
|
|
+
|
|
+static const unsigned int mt9p031_num_formats = ARRAY_SIZE(mt9p031_formats);
|
|
+
|
|
+/***********************Minimum Horizontal blanking*********************/
|
|
+int hb_min[4][4] = {
|
|
+ { 450, 430, 0, 420 },
|
|
+ { 796, 776, 0, 766 },
|
|
+ { 0, 0, 0, 0 },
|
|
+ { 1488, 1468, 0, 1458 },
|
|
+};
|
|
+
|
|
+/**************************supported sizes******************************/
|
|
+const static struct mt9p031_frame_size mt9p031_sizes[] = {
|
|
+ { 640, 480 },
|
|
+ { 1280, 720 },
|
|
+ { 1920, 1080 },
|
|
+ { 2048, 1536 }, //3MP
|
|
+ { 2592, 1944 }, //5MP
|
|
+};
|
|
+
|
|
+
|
|
+struct mt9p031_format_params {
|
|
+ int width;
|
|
+ int height;
|
|
+ int row_start;
|
|
+ int col_start;
|
|
+ int row_size;
|
|
+ int col_size;
|
|
+ int hblank;
|
|
+ int vblank;
|
|
+ int integ_time;
|
|
+ int row_addr_mode;
|
|
+ int col_addr_mode;
|
|
+ int read_mode_2_config;
|
|
+ int shutter_width_hi;
|
|
+ int shutter_delay;
|
|
+ int row_bin;
|
|
+ int col_bin;
|
|
+};
|
|
+
|
|
+enum mt9p031_image_size {
|
|
+ VGA_BIN_30FPS,
|
|
+ HDV_720P_30FPS,
|
|
+ //HDV_720P_60FPS,
|
|
+ //HDV_720P_60FPS_LVB,
|
|
+ HDV_1080P_30FPS,
|
|
+ MT9P031_THREE_MP,
|
|
+ MT9P031_FIVE_MP,
|
|
+};
|
|
+
|
|
+enum mt9p031_image_size mt9p031_current_format;
|
|
+
|
|
+const struct mt9p031_format_params mt9p031_supported_formats[] = {
|
|
+ { 640, 480, 64, 24, 1919, 2559, 0, 0, 0x0296, 0x0033, 0x0033, 0x0060, 0, 0, 3, 3 }, // VGA_BIN_30FPS
|
|
+ { 1280, 720, 64, 24, 1439, 2559, 0, 0, 0x0296, 0x0011, 0x0011, 0x0060, 0, 0, 1, 1 }, // 720P_HD_30FPS
|
|
+ //{ 1280, 720, 0x0040, 0x0018, 0x059F, 0x09FF, 0, 0, 0x0296, 0x0011, 0x0011, 0x0060, 0, 0, 1, 1 }, // 720P_HD_60FPS
|
|
+ //{ 1280, 720, 0x0040, 0x0018, 0x059F, 0x09FF, 0, 0x02D0, 0x0296, 0x0011, 0x0011, 0x0060, 0, 0, 1, 1 }, // 720P_HD_60FPS_LVB
|
|
+ { 1920, 1080, 431, 335, 1079, 1919, 0, 0x0037, 0x01AC, 0, 0, 0x0040, 0, 0, 0, 0 }, // 1080P_30FPS
|
|
+ { 2048, 1536, 431, 335, 1535, 2047, 0, 0x0037, 0x01AC, 0, 0, 0x0040, 0, 0, 0, 0 }, // 3MP CAPTURE
|
|
+ { 2592, 1944, 431, 335, 1943, 2591, 0, 0x0037, 0x01AC, 0, 0, 0x0040, 0, 0, 0, 0 }, // 5MP CAPTURE
|
|
+};
|
|
+
|
|
+
|
|
+const struct v4l2_fract mt9p031_frameintervals[] = {
|
|
+ { .numerator = 1, .denominator = 10 },
|
|
+ { .numerator = 1, .denominator = 20 },
|
|
+ { .numerator = 1, .denominator = 30 },
|
|
+ { .numerator = 1, .denominator = 40 },
|
|
+ { .numerator = 1, .denominator = 50 },
|
|
+};
|
|
+
|
|
+
|
|
+const u16 MT9P031_EV_GAIN_TBL[48] = {
|
|
+ /* Gain x1 */
|
|
+ 8, 9, 10, 11, 12, 13, 14, 15,
|
|
+ /* Gain x2 */
|
|
+ 16, 17, 18, 19, 20, 21, 22, 23,
|
|
+ /* Gain x3 */
|
|
+ 24, 25, 26, 27, 28, 29, 30, 31,
|
|
+ /* Gain x4 */
|
|
+ 32, 33, 34, 35,
|
|
+ /* Gain x5 */
|
|
+ 81, 82, 83,
|
|
+ /* Gain x6 */
|
|
+ 84, 85, 86, 87, 88, 89, 90, 91,
|
|
+ /* Gain x7 */
|
|
+ 92, 93, 94, 95, 96, 97, 98, 99,
|
|
+ /* Gain x8 */
|
|
+ 100,
|
|
+};
|
|
+
|
|
+#ifdef MT9P031_HEADBOARD
|
|
+/**
|
|
+ * mt9p031_config_PCA9543A - configure on-board I2c level-shifter PCA9543A of MT9P031 Headboards from Aptina
|
|
+ * @client: pointer to i2c client
|
|
+ * Configures the level shifter to enable channel 0
|
|
+ */
|
|
+static int mt9p031_config_PCA9543A(const struct i2c_client *client)
|
|
+{
|
|
+ struct i2c_msg msg;
|
|
+ int ret;
|
|
+ u8 buf;
|
|
+ buf = 0x21;
|
|
+
|
|
+ msg.addr = (0xE6 >> 1); //slave address of PCA9543A
|
|
+ msg.flags = 0;
|
|
+ msg.len = 1;
|
|
+ msg.buf = &buf;
|
|
+
|
|
+ ret = i2c_transfer(client->adapter, &msg, 1);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+#endif //MT9P031_HEADBOARD
|
|
+
|
|
+/**
|
|
+ * mt9p031_reg_read - read resgiter value
|
|
+ * @client: pointer to i2c client
|
|
+ * @command: register address
|
|
+ */
|
|
+static int mt9p031_reg_read(const struct i2c_client *client, u16 command, u16 *val)
|
|
+{
|
|
+ struct i2c_msg msg[2];
|
|
+ u8 buf[2];
|
|
+ int ret;
|
|
+
|
|
+ // 8-bit/ byte addressable register
|
|
+ buf[0] = command & 0xff;
|
|
+
|
|
+ msg[0].addr = client->addr;
|
|
+ msg[0].flags = 0;
|
|
+ msg[0].len = 1;
|
|
+ msg[0].buf = buf ;
|
|
+ ret = i2c_transfer(client->adapter, &msg[0], 1);
|
|
+
|
|
+ if(ret >= 0) {
|
|
+ msg[1].addr = client->addr;
|
|
+ msg[1].flags = I2C_M_RD; //1
|
|
+ msg[1].len = 2;
|
|
+ msg[1].buf = buf;
|
|
+ ret = i2c_transfer(client->adapter, &msg[1], 1);
|
|
+ }
|
|
+ /*
|
|
+ * if return value of this function is < 0,
|
|
+ * it mean error.
|
|
+ * else, under 16bit is valid data.
|
|
+ */
|
|
+ if(ret >= 0) {
|
|
+ *val = 0;
|
|
+ *val = buf[1] + (buf[0] << 8);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ v4l_err(client, "read from offset 0x%x error %d", command, ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_reg_write - read resgiter value
|
|
+ * @client: pointer to i2c client
|
|
+ * @command: register address
|
|
+ * @data: value to be written
|
|
+ */
|
|
+static int mt9p031_reg_write(const struct i2c_client *client,
|
|
+ u16 command, u16 data)
|
|
+{
|
|
+ struct i2c_msg msg;
|
|
+ u8 buf[3];
|
|
+ int ret;
|
|
+
|
|
+ // 8-bit/ byte addressable register
|
|
+
|
|
+ buf[0] = command & 0xff;
|
|
+ data = swab16(data);
|
|
+ memcpy(buf + 1, &data, 2);
|
|
+
|
|
+ msg.addr = client->addr;
|
|
+ msg.flags = 0;
|
|
+ msg.len = 3;
|
|
+ msg.buf = buf;
|
|
+
|
|
+ /*
|
|
+ * i2c_transfer return message length,
|
|
+ * but this function should return 0 if correct case
|
|
+ */
|
|
+ ret = i2c_transfer(client->adapter, &msg, 1);
|
|
+ if (ret >= 0)
|
|
+ ret = 0;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * struct vcontrol - Video controls
|
|
+ * @v4l2_queryctrl: V4L2 VIDIOC_QUERYCTRL ioctl structure
|
|
+ * @current_value: current value of this control
|
|
+ */
|
|
+static struct vcontrol {
|
|
+ struct v4l2_queryctrl qc;
|
|
+ int current_value;
|
|
+} mt9p031_video_control[] = {
|
|
+ {
|
|
+ {
|
|
+ .id = V4L2_CID_EXPOSURE,
|
|
+ .type = V4L2_CTRL_TYPE_INTEGER,
|
|
+ .name = "Exposure",
|
|
+ .minimum = MT9P031_MIN_EXPOSURE,
|
|
+ .maximum = MT9P031_MAX_EXPOSURE,
|
|
+ .step = MT9P031_EXPOSURE_STEP,
|
|
+ .default_value = MT9P031_DEF_EXPOSURE,
|
|
+ },
|
|
+ .current_value = MT9P031_DEF_EXPOSURE,
|
|
+ },
|
|
+ {
|
|
+ {
|
|
+ .id = V4L2_CID_GAIN,
|
|
+ .type = V4L2_CTRL_TYPE_INTEGER,
|
|
+ .name = "Analog Gain",
|
|
+ .minimum = MT9P031_EV_MIN_GAIN,
|
|
+ .maximum = MT9P031_EV_MAX_GAIN,
|
|
+ .step = MT9P031_EV_GAIN_STEP,
|
|
+ .default_value = MT9P031_EV_DEF_GAIN,
|
|
+ },
|
|
+ .current_value = MT9P031_EV_DEF_GAIN,
|
|
+ },
|
|
+};
|
|
+
|
|
+/**
|
|
+ * find_vctrl - Finds the requested ID in the video control structure array
|
|
+ * @id: ID of control to search the video control array for
|
|
+ *
|
|
+ * Returns the index of the requested ID from the control structure array
|
|
+ */
|
|
+static int
|
|
+find_vctrl(int id)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (id < V4L2_CID_BASE)
|
|
+ return -EDOM;
|
|
+
|
|
+ for (i = (ARRAY_SIZE(mt9p031_video_control) - 1); i >= 0; i--)
|
|
+ if (mt9p031_video_control[i].qc.id == id)
|
|
+ break;
|
|
+ if (i < 0)
|
|
+ i = -EINVAL;
|
|
+ return i;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_calc_size - Find the best match for a requested image capture size
|
|
+ * @width: requested image width in pixels
|
|
+ * @height: requested image height in pixels
|
|
+ *
|
|
+ * Find the best match for a requested image capture size. The best match
|
|
+ * is chosen as the nearest match that has the same number or fewer pixels
|
|
+ * as the requested size, or the smallest image size if the requested size
|
|
+ * has fewer pixels than the smallest image.
|
|
+ */
|
|
+static enum mt9p031_image_size mt9p031_calc_size(unsigned int width,
|
|
+ unsigned int height)
|
|
+{
|
|
+ enum mt9p031_image_size isize;
|
|
+ unsigned long pixels = width * height;
|
|
+
|
|
+ for (isize = VGA_BIN_30FPS; isize <= MT9P031_FIVE_MP; isize++) {
|
|
+ if (mt9p031_sizes[isize].height *
|
|
+ mt9p031_sizes[isize].width >= pixels) {
|
|
+
|
|
+ return isize;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return MT9P031_FIVE_MP;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_find_isize - Find the best match for a requested image capture size
|
|
+ * @width: requested image width in pixels
|
|
+ * @height: requested image height in pixels
|
|
+ *
|
|
+ * Find the best match for a requested image capture size. The best match
|
|
+ * is chosen as the nearest match that has the same number or fewer pixels
|
|
+ * as the requested size, or the smallest image size if the requested size
|
|
+ * has fewer pixels than the smallest image.
|
|
+ */
|
|
+static enum mt9p031_image_size mt9p031_find_isize(unsigned int width)
|
|
+{
|
|
+ enum mt9p031_image_size isize;
|
|
+
|
|
+ for (isize = VGA_BIN_30FPS; isize <= MT9P031_FIVE_MP; isize++) {
|
|
+ if (mt9p031_sizes[isize].width >= width)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return isize;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_calc_xclk - Calculate the required xclk frequency
|
|
+ * @c: i2c client driver structure
|
|
+ *
|
|
+ * Given the image capture format in pix, the nominal frame period in
|
|
+ * timeperframe, calculate and return the required xclk frequency
|
|
+ */
|
|
+static unsigned long mt9p031_calc_xclk(struct i2c_client *c)
|
|
+{
|
|
+ struct mt9p031_priv *priv = i2c_get_clientdata(c);
|
|
+ struct v4l2_fract *timeperframe = &priv->timeperframe;
|
|
+
|
|
+ if (timeperframe->numerator == 0 ||
|
|
+ timeperframe->denominator == 0) {
|
|
+ /* supply a default nominal_timeperframe */
|
|
+ timeperframe->numerator = 1;
|
|
+ timeperframe->denominator = MT9P031_DEF_FPS;
|
|
+ }
|
|
+
|
|
+ priv->fps = timeperframe->denominator / timeperframe->numerator;
|
|
+ if (priv->fps < MT9P031_MIN_FPS)
|
|
+ priv->fps = MT9P031_MIN_FPS;
|
|
+ else if (priv->fps > MT9P031_MAX_FPS)
|
|
+ priv->fps = MT9P031_MAX_FPS;
|
|
+
|
|
+ timeperframe->numerator = 1;
|
|
+ timeperframe->denominator = priv->fps;
|
|
+
|
|
+ return MT9P031_XCLK_NOM_1;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_set_params - sets register settings according to resolution
|
|
+ * @client: pointer to standard i2c client
|
|
+ * @width: width as queried by ioctl
|
|
+ * @height: height as queried by ioctl
|
|
+ */
|
|
+static int mt9p031_set_params(struct i2c_client *client, u32 width, u32 height)
|
|
+{
|
|
+ struct mt9p031_priv *priv = i2c_get_clientdata(client);
|
|
+ struct v4l2_pix_format *pix = &priv->pix;
|
|
+ int ret;
|
|
+ enum mt9p031_image_size i;
|
|
+
|
|
+ i = mt9p031_find_isize(pix->width);
|
|
+ priv->pix.width = mt9p031_supported_formats[i].width;
|
|
+ priv->pix.height = mt9p031_supported_formats[i].height;
|
|
+
|
|
+ ret = mt9p031_reg_write(client, REG_MT9P031_ROWSTART, mt9p031_supported_formats[i].row_start); //ROW_WINDOW_START_REG
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_COLSTART, mt9p031_supported_formats[i].col_start); //COL_WINDOW_START_REG
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_HEIGHT, mt9p031_supported_formats[i].row_size); //ROW_WINDOW_SIZE_REG=1439
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_WIDTH, mt9p031_supported_formats[i].col_size); //COL_WINDOW_SIZE_REG=2559
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_HBLANK, mt9p031_supported_formats[i].hblank); //HORZ_BLANK=0
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_VBLANK, mt9p031_supported_formats[i].vblank); //VERT_BLANK_REG=720
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_L, 0x0400); //SHUTTER_WIDTH_LOW (INTEG_TIME_REG = 1024)
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_ROW_ADDR_MODE, mt9p031_supported_formats[i].row_addr_mode); //ROW_MODE, ROW_SKIP=1, ROW_BIN=1
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_COL_ADDR_MODE, mt9p031_supported_formats[i].col_addr_mode); //COL_MODE, COL_SKIP=1, COL_BIN=1
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_READ_MODE2, mt9p031_supported_formats[i].read_mode_2_config); //READ_MODE_2, COL_SUM
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_U, mt9p031_supported_formats[i].shutter_width_hi); //SHUTTER_WIDTH_HI
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_L, mt9p031_supported_formats[i].integ_time); //SHUTTER_WIDTH_LOW (INTEG_TIME_REG)
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_DELAY, mt9p031_supported_formats[i].shutter_delay); //SHUTTER_DELAY_REG
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_init_camera - initialize camera settings
|
|
+ * @client: pointer to i2c client
|
|
+ * Initialize camera settings
|
|
+ */
|
|
+static int mt9p031_init_camera(const struct i2c_client *client)
|
|
+{
|
|
+ int ret;
|
|
+ struct mt9p031_priv *priv = i2c_get_clientdata(client);
|
|
+ struct v4l2_pix_format *pix = &priv->pix;
|
|
+
|
|
+ ret = mt9p031_reg_write(client, REG_MT9P031_PLL_CTRL, 0x0051); //PLL_CTRL; power up pll
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_PLL_CONF1, 0x1801); //PLL_CONFIG_1: m=24, n=1
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_PLL_CONF2, 0x0002); //PLL_CONFIG_2: p1=2, p2=0
|
|
+ mdelay(10); //wait 10 ms for VCO to lock
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_PLL_CTRL, 0x0053); //PLL_CONTROL; use PLL
|
|
+ mdelay(200);
|
|
+
|
|
+ ret |= mt9p031_set_params(priv->client, pix->width, pix->height);
|
|
+
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_RESET, 0x0001); //High
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_RESET, 0x0000); //Low
|
|
+ mdelay(100);
|
|
+
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_1_GAIN, 0x0051); //Green1_gain_reg
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_BLUE_GAIN, 0x0051); //Blue_gain_reg
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_RED_GAIN, 0x0051); //Red_gain_reg
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_2_GAIN, 0x0051); //Green2_gain_reg
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_GLOBAL_GAIN, 0x0008); //Analog Gain
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_READ_MODE1, 0x0006); //Read_mode_1 //disable AB
|
|
+ ret |= mt9p031_reg_write(client, REG_MT9P031_OUT_CTRL, 0x1F8E); //Enable parll fifo data
|
|
+
|
|
+ return ret>= 0 ? 0 : -EIO;
|
|
+}
|
|
+
|
|
+/************************************************************************
|
|
+ i2c driver
|
|
+************************************************************************/
|
|
+/**
|
|
+ * mt9p031_detect - Detect if an mt9p031 is present, and if so which revision
|
|
+ * @client: pointer to the i2c client driver structure
|
|
+ *
|
|
+ * Returns a negative error number if no device is detected
|
|
+ */
|
|
+static int mt9p031_detect(struct i2c_client *client)
|
|
+{
|
|
+ struct mt9p031_priv *priv = i2c_get_clientdata(client);
|
|
+ const char *devname;
|
|
+ u16 chipid;
|
|
+
|
|
+ if (!client)
|
|
+ return -ENODEV;
|
|
+ /*
|
|
+ * Set Normal Mode
|
|
+ */
|
|
+ if(mt9p031_reg_write(client, REG_MT9P031_OUT_CTRL, MT9P031_NORMAL_OPERATION_MODE))
|
|
+ return -ENODEV;
|
|
+ /*
|
|
+ * check and show chip ID
|
|
+ */
|
|
+ if(mt9p031_reg_read(client, REG_MT9P031_CHIP_VERSION, &chipid))
|
|
+ return -ENODEV;
|
|
+
|
|
+ if(chipid == MT9P031_CHIP_ID) {
|
|
+ devname = "mt9p031";
|
|
+ priv->model = V4L2_IDENT_MT9P031;
|
|
+ dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ dev_err(&client->dev, "Product ID error %04x\n", chipid);
|
|
+ return -ENODEV;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_set_exposure_time - sets exposure time per input value
|
|
+ * @exp_time: exposure time to be set on device
|
|
+ * @client: pointer to standard i2c client
|
|
+ * @lvc: pointer to V4L2 exposure entry in video_controls array
|
|
+ *
|
|
+ * If the requested exposure time is within the allowed limits, the HW
|
|
+ * is configured to use the new exposure time, and the video_controls
|
|
+ * array is updated with the new current value.
|
|
+ * The function returns 0 upon success. Otherwise an error code is
|
|
+ * returned.
|
|
+ */
|
|
+static int mt9p031_set_exposure_time(u32 exp_time, struct i2c_client *client,
|
|
+ struct vcontrol *lvc)
|
|
+{
|
|
+ int ret = 0, i, shutter_width, so_p, t_pix_clk, sd_p, shutter_delay;
|
|
+ int sw_l ,sw_u ,W ,h_blanking, t_row;
|
|
+
|
|
+ if(exp_time < MT9P031_MIN_EXPOSURE)
|
|
+ exp_time = MT9P031_MIN_EXPOSURE;
|
|
+ else if(exp_time > MT9P031_MAX_EXPOSURE)
|
|
+ exp_time = MT9P031_MAX_EXPOSURE;
|
|
+
|
|
+ shutter_delay = mt9p031_supported_formats[mt9p031_current_format].shutter_delay;
|
|
+ sd_p = min(shutter_delay + 1, 1504);
|
|
+ so_p = 208 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1) + 98 + sd_p - 94;
|
|
+ t_pix_clk = (Q12/96 );
|
|
+ h_blanking = mt9p031_supported_formats[mt9p031_current_format].hblank + 1;
|
|
+ W = 2 * (int)((mt9p031_supported_formats[mt9p031_current_format].row_size + 1) / (2 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1)) + 1);
|
|
+ t_row = 2 * t_pix_clk * max(W/2 + max(h_blanking, hb_min[mt9p031_supported_formats[mt9p031_current_format].row_bin][mt9p031_supported_formats[mt9p031_current_format].col_bin]),
|
|
+ (41 + 346 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1) + 99))/Q12;
|
|
+
|
|
+ shutter_width = (exp_time + 2*so_p*t_pix_clk) / t_row;
|
|
+
|
|
+ if (shutter_width< 3) {
|
|
+ sd_p = 1232 > shutter_delay ? 1232 : shutter_delay;
|
|
+ so_p = 208 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1) + 98 + sd_p - 94;
|
|
+ shutter_width = ((exp_time*Q12 + 2*so_p*t_pix_clk) / (t_row * Q12));
|
|
+ }
|
|
+
|
|
+ if (shutter_width < 1)
|
|
+ shutter_width = 1;
|
|
+ sw_l = shutter_width& 0xffff;
|
|
+ sw_u = (shutter_width)>> 16;
|
|
+ ret = mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_L,sw_l);
|
|
+ mdelay(1);
|
|
+ ret = mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_U,sw_u);
|
|
+
|
|
+ if (ret)
|
|
+ dev_err(&client->dev, "Error setting exposure time %d\n",
|
|
+ ret);
|
|
+ else{
|
|
+ i = find_vctrl(V4L2_CID_EXPOSURE);
|
|
+ if (i >= 0) {
|
|
+ lvc = &mt9p031_video_control[i];
|
|
+ lvc->current_value = exp_time;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_set_gain - sets sensor analog gain per input value
|
|
+ * @lineargain: analog gain value index to be set on device
|
|
+ * @client: pointer to standard i2c client
|
|
+ * @lvc: pointer to V4L2 analog gain entry in video_controls array
|
|
+ *
|
|
+ * If the requested analog gain is within the allowed limits, the HW
|
|
+ * is configured to use the new gain value, and the video_controls
|
|
+ * array is updated with the new current value.
|
|
+ * The function returns 0 upon success. Otherwise an error code is
|
|
+ * returned.
|
|
+ */
|
|
+int mt9p031_set_gain(u16 lineargain, struct i2c_client *client,
|
|
+ struct vcontrol *lvc)
|
|
+{
|
|
+ int ret= 0, i;
|
|
+ u16 reg_gain = 0;
|
|
+
|
|
+ if (lineargain < MT9P031_EV_MIN_GAIN) {
|
|
+ lineargain = MT9P031_EV_MIN_GAIN;
|
|
+ v4l_err(client, "Gain out of legal range.");
|
|
+ }
|
|
+ if (lineargain > MT9P031_EV_MAX_GAIN) {
|
|
+ lineargain = MT9P031_EV_MAX_GAIN;
|
|
+ v4l_err(client, "Gain out of legal range.");
|
|
+ }
|
|
+
|
|
+ reg_gain = MT9P031_EV_GAIN_TBL[lineargain];
|
|
+ ret = mt9p031_reg_write(client, REG_MT9P031_GLOBAL_GAIN,
|
|
+ reg_gain);
|
|
+
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "Error setting gain.%d", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ else {
|
|
+ i = find_vctrl(V4L2_CID_GAIN);
|
|
+ if (i >= 0) {
|
|
+ lvc = &mt9p031_video_control[i];
|
|
+ lvc->current_value = lineargain;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/************************************************************************
|
|
+ v4l2_ioctls
|
|
+************************************************************************/
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @on: power state to which device is to be set
|
|
+ *
|
|
+ * Sets devices power state to requrested state, if possible.
|
|
+ */
|
|
+static int mt9p031_v4l2_int_s_power(struct v4l2_int_device *s,
|
|
+ enum v4l2_power power)
|
|
+{
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+ struct i2c_client *client = priv->client;
|
|
+
|
|
+ int ret;
|
|
+
|
|
+ switch (power) {
|
|
+ case V4L2_POWER_STANDBY:
|
|
+ /* FALLTHROUGH */
|
|
+ case V4L2_POWER_OFF:
|
|
+ ret = priv->pdata->power_set(s, power);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&client->dev, "Unable to set target board power "
|
|
+ "state (OFF/STANDBY)\n");
|
|
+ return ret;
|
|
+ }
|
|
+ break;
|
|
+ case V4L2_POWER_ON:
|
|
+ ret = priv->pdata->power_set(s, power);
|
|
+
|
|
+ if (ret < 0) {
|
|
+ dev_err(&client->dev, "Unable to set target board power "
|
|
+ "state (ON)\n");
|
|
+ return ret;
|
|
+ }
|
|
+ if (!(priv->flags & INIT_DONE)) {
|
|
+ ret = mt9p031_detect(client);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&client->dev, "Unable to detect sensor\n");
|
|
+ return ret;
|
|
+ }
|
|
+ priv->flags |= INIT_DONE;
|
|
+ }
|
|
+
|
|
+ ret = mt9p031_init_camera(client);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&client->dev, "Unable to initialize sensor\n");
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
|
|
+ *
|
|
+ * If the requested control is supported, sets the control's current
|
|
+ * value in HW (and updates the video_control[] array). Otherwise,
|
|
+ * returns -EINVAL if the control is not supported.
|
|
+ */
|
|
+static int mt9p031_v4l2_s_ctrl(struct v4l2_int_device *s,
|
|
+ struct v4l2_control *vc)
|
|
+{
|
|
+ int retval = -EINVAL;
|
|
+ int i;
|
|
+ struct vcontrol *lvc;
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+ struct i2c_client *client = priv->client;
|
|
+
|
|
+ i = find_vctrl(vc->id);
|
|
+ if (i < 0)
|
|
+ return -EINVAL;
|
|
+ lvc = &mt9p031_video_control[i];
|
|
+
|
|
+ switch (vc->id) {
|
|
+ case V4L2_CID_EXPOSURE:
|
|
+ retval = mt9p031_set_exposure_time(vc->value, client, lvc);
|
|
+ break;
|
|
+ case V4L2_CID_GAIN:
|
|
+ retval = mt9p031_set_gain(vc->value, client, lvc);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
|
|
+ *
|
|
+ * If the requested control is supported, returns the control's current
|
|
+ * value from the video_control[] array. Otherwise, returns -EINVAL
|
|
+ * if the control is not supported.
|
|
+ */
|
|
+static int mt9p031_v4l2_g_ctrl(struct v4l2_int_device *s,
|
|
+ struct v4l2_control *vc)
|
|
+{
|
|
+ struct vcontrol *lvc;
|
|
+ int i;
|
|
+
|
|
+ i = find_vctrl(vc->id);
|
|
+ if (i < 0)
|
|
+ return -EINVAL;
|
|
+ lvc = &mt9p031_video_control[i];
|
|
+
|
|
+ switch (vc->id) {
|
|
+ case V4L2_CID_EXPOSURE:
|
|
+ vc->value = lvc->current_value;
|
|
+ break;
|
|
+ case V4L2_CID_GAIN:
|
|
+ vc->value = lvc->current_value;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
|
|
+ *
|
|
+ * If the requested control is supported, returns the control information
|
|
+ * from the video_control[] array. Otherwise, returns -EINVAL if the
|
|
+ * control is not supported.
|
|
+ */
|
|
+static int mt9p031_v4l2_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ i = find_vctrl(qc->id);
|
|
+ if (i == -EINVAL)
|
|
+ qc->flags = V4L2_CTRL_FLAG_DISABLED;
|
|
+
|
|
+ if (i < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ *qc = mt9p031_video_control[i].qc;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
|
|
+ *
|
|
+ * Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
|
|
+ */
|
|
+static int mt9p031_v4l2_int_enum_fmt_cap(struct v4l2_int_device *s,
|
|
+ struct v4l2_fmtdesc *fmt)
|
|
+{
|
|
+ int index = fmt->index;
|
|
+ enum v4l2_buf_type type = fmt->type;
|
|
+
|
|
+ memset(fmt, 0, sizeof(*fmt));
|
|
+ fmt->index = index;
|
|
+ fmt->type = type;
|
|
+
|
|
+ switch (fmt->type) {
|
|
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
+ if (index >= ARRAY_SIZE(mt9p031_formats))
|
|
+ return -EINVAL;
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ strlcpy(fmt->description, mt9p031_formats[index].description,
|
|
+ sizeof(fmt->description));
|
|
+ fmt->pixelformat = mt9p031_formats[index].pixelformat;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
|
|
+ *
|
|
+ * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
|
|
+ * ioctl is used to negotiate the image capture size and pixel format
|
|
+ * without actually making it take effect.
|
|
+ */
|
|
+static int mt9p031_v4l2_int_try_fmt_cap(struct v4l2_int_device *s,
|
|
+ struct v4l2_format *f)
|
|
+{
|
|
+ enum mt9p031_image_size isize;
|
|
+ int ifmt;
|
|
+ struct v4l2_pix_format *pix = &f->fmt.pix;
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+ struct v4l2_pix_format *pix2 = &priv->pix;
|
|
+
|
|
+ isize = mt9p031_calc_size(pix->width, pix->height);
|
|
+ mt9p031_current_format = isize;
|
|
+
|
|
+ pix->width = mt9p031_sizes[isize].width;
|
|
+ pix->height = mt9p031_sizes[isize].height;
|
|
+ for (ifmt = 0; ifmt < mt9p031_num_formats; ifmt++) {
|
|
+ if (pix->pixelformat == mt9p031_formats[ifmt].pixelformat)
|
|
+ break;
|
|
+ }
|
|
+ if (ifmt == mt9p031_num_formats)
|
|
+ ifmt = 0;
|
|
+ pix->pixelformat = mt9p031_formats[ifmt].pixelformat;
|
|
+ pix->field = V4L2_FIELD_NONE;
|
|
+ pix->bytesperline = pix->width * 2;
|
|
+ pix->sizeimage = pix->bytesperline * pix->height;
|
|
+ pix->priv = 0;
|
|
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
|
|
+
|
|
+ *pix2 = *pix;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_s_fmt_cap - V4L2 sensor interface handler for VIDIOC_S_FMT ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
|
|
+ *
|
|
+ * If the requested format is supported, configures the HW to use that
|
|
+ * format, returns error code if format not supported or HW can't be
|
|
+ * correctly configured.
|
|
+ */
|
|
+static int mt9p031_v4l2_int_s_fmt_cap(struct v4l2_int_device *s,
|
|
+ struct v4l2_format *f)
|
|
+{
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+ struct v4l2_pix_format *pix = &f->fmt.pix;
|
|
+ int rval;
|
|
+
|
|
+ rval = mt9p031_v4l2_int_try_fmt_cap(s, f);
|
|
+ if (!rval)
|
|
+ priv->pix = *pix;
|
|
+
|
|
+ return rval;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @f: pointer to standard V4L2 v4l2_format structure
|
|
+ *
|
|
+ * Returns the sensor's current pixel format in the v4l2_format
|
|
+ * parameter.
|
|
+ */
|
|
+static int mt9p031_v4l2_int_g_fmt_cap(struct v4l2_int_device *s,
|
|
+ struct v4l2_format *f)
|
|
+{
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+
|
|
+ f->fmt.pix.width = priv->pix.width;
|
|
+ f->fmt.pix.height = priv->pix.height;
|
|
+ f->fmt.pix.pixelformat = V4L2_COLORSPACE_SRGB;
|
|
+ f->fmt.pix.pixelformat = priv->pix.pixelformat;
|
|
+ f->fmt.pix.field = V4L2_FIELD_NONE;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
|
|
+ *
|
|
+ * Configures the sensor to use the input parameters, if possible. If
|
|
+ * not possible, reverts to the old parameters and returns the
|
|
+ * appropriate error code.
|
|
+ */
|
|
+
|
|
+
|
|
+static int mt9p031_v4l2_int_s_parm(struct v4l2_int_device *s,
|
|
+ struct v4l2_streamparm *a)
|
|
+{
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+ struct i2c_client *client = priv->client;
|
|
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
|
|
+
|
|
+ priv->timeperframe = *timeperframe;
|
|
+ priv->xclk_current = mt9p031_calc_xclk(client);
|
|
+ *timeperframe = priv->timeperframe;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
|
|
+ *
|
|
+ * Returns the sensor's video CAPTURE parameters.
|
|
+ */
|
|
+static int mt9p031_v4l2_int_g_parm(struct v4l2_int_device *s,
|
|
+ struct v4l2_streamparm *a)
|
|
+{
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+ struct v4l2_captureparm *cparm = &a->parm.capture;
|
|
+
|
|
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
+ return -EINVAL;
|
|
+
|
|
+ memset(a, 0, sizeof(*a));
|
|
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
+
|
|
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
|
|
+ cparm->timeperframe.numerator = 1;
|
|
+ cparm->timeperframe = priv->timeperframe;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_g_priv - V4L2 sensor interface handler for vidioc_int_g_priv_num
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @p: void pointer to hold sensor's private data address
|
|
+ *
|
|
+ * Returns device's (sensor's) private data area address in p parameter
|
|
+ */
|
|
+static int mt9p031_v4l2_int_g_priv(struct v4l2_int_device *s, void *p)
|
|
+{
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+
|
|
+ return priv->pdata->priv_data_set(p);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_priv_num
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @p: void pointer to hold sensor's ifparm
|
|
+ *
|
|
+ * Returns device's (sensor's) ifparm in p parameter
|
|
+ */
|
|
+static int mt9p031_v4l2_int_g_ifparm(struct v4l2_int_device *s,
|
|
+ struct v4l2_ifparm *p)
|
|
+{
|
|
+ struct mt9p031_priv *priv = s->priv;
|
|
+ int rval;
|
|
+
|
|
+ if (p == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!priv->pdata->ifparm)
|
|
+ return -EINVAL;
|
|
+
|
|
+ rval = priv->pdata->ifparm(p);
|
|
+ if (rval) {
|
|
+ v4l_err(priv->client, "g_ifparm.Err[%d]\n", rval);
|
|
+ return rval;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * mt9p031_v4l2_int_enum_framesizes - V4L2 sensor if handler for vidioc_int_enum_framesizes
|
|
+ * @s: pointer to standard V4L2 device structure
|
|
+ * @frms: pointer to standard V4L2 framesizes enumeration structure
|
|
+ *
|
|
+ * Returns possible framesizes depending on choosen pixel format
|
|
+ */
|
|
+static int mt9p031_v4l2_int_enum_framesizes(struct v4l2_int_device *s,
|
|
+ struct v4l2_frmsizeenum *frms)
|
|
+{
|
|
+ int ifmt;
|
|
+
|
|
+ for (ifmt = 0; ifmt < ARRAY_SIZE(mt9p031_formats); ifmt++)
|
|
+ if (mt9p031_formats[ifmt].pixelformat == frms->pixel_format)
|
|
+ break;
|
|
+
|
|
+ if (ifmt == ARRAY_SIZE(mt9p031_formats))
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Do we already reached all discrete framesizes? */
|
|
+ if (frms->index >= ARRAY_SIZE(mt9p031_sizes))
|
|
+ return -EINVAL;
|
|
+
|
|
+ frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
+ frms->discrete.width = mt9p031_sizes[frms->index].width;
|
|
+ frms->discrete.height = mt9p031_sizes[frms->index].height;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mt9p031_v4l2_int_enum_frameintervals(struct v4l2_int_device *s,
|
|
+ struct v4l2_frmivalenum *frmi)
|
|
+{
|
|
+ int ifmt;
|
|
+ int max_size;
|
|
+
|
|
+ for (ifmt = 0; ifmt < ARRAY_SIZE(mt9p031_formats); ifmt++)
|
|
+ if (mt9p031_formats[ifmt].pixelformat == frmi->pixel_format)
|
|
+ break;
|
|
+
|
|
+ if (ifmt == ARRAY_SIZE(mt9p031_formats))
|
|
+ return -EINVAL;
|
|
+
|
|
+ max_size = ARRAY_SIZE(mt9p031_sizes);
|
|
+
|
|
+ for(ifmt = 0; ifmt < max_size; ifmt++) {
|
|
+ if(frmi->width <= mt9p031_sizes[ifmt].width) {
|
|
+ frmi->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
+ frmi->discrete.numerator =
|
|
+ mt9p031_frameintervals[frmi->index].numerator;
|
|
+ frmi->discrete.denominator =
|
|
+ mt9p031_frameintervals[frmi->index].denominator;
|
|
+
|
|
+ if(frmi->discrete.denominator <= mt9p031_frameintervals[max_size - ifmt - 1].denominator)
|
|
+ return 0;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct v4l2_int_ioctl_desc mt9p031_ioctl_desc[] = {
|
|
+ { .num = vidioc_int_enum_framesizes_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_enum_framesizes },
|
|
+ { .num = vidioc_int_enum_frameintervals_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_enum_frameintervals },
|
|
+ { .num = vidioc_int_s_power_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_s_power },
|
|
+ { .num = vidioc_int_g_priv_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_priv },
|
|
+ { .num = vidioc_int_g_ifparm_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_ifparm },
|
|
+ { .num = vidioc_int_enum_fmt_cap_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_enum_fmt_cap },
|
|
+ { .num = vidioc_int_try_fmt_cap_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_try_fmt_cap },
|
|
+ { .num = vidioc_int_g_fmt_cap_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_fmt_cap },
|
|
+ { .num = vidioc_int_s_fmt_cap_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_s_fmt_cap },
|
|
+ { .num = vidioc_int_g_parm_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_parm },
|
|
+ { .num = vidioc_int_s_parm_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_s_parm },
|
|
+ { .num = vidioc_int_g_ctrl_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_g_ctrl },
|
|
+ { .num = vidioc_int_s_ctrl_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_s_ctrl },
|
|
+ { .num = vidioc_int_queryctrl_num,
|
|
+ .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_queryctrl },
|
|
+};
|
|
+
|
|
+#ifdef MT9P031_DEBUG
|
|
+/**
|
|
+ * ---------------------------------------------------------------------------------
|
|
+ * Sysfs
|
|
+ * ---------------------------------------------------------------------------------
|
|
+ */
|
|
+
|
|
+/* Basic register read write support */
|
|
+static u16 mt9p031_attr_basic_addr = 0x0000;
|
|
+
|
|
+static ssize_t
|
|
+mt9p031_basic_reg_addr_show( struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ return sprintf(buf, "0x%x\n", mt9p031_attr_basic_addr);
|
|
+}
|
|
+
|
|
+static ssize_t
|
|
+mt9p031_basic_reg_addr_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
|
|
+{
|
|
+ u16 val;
|
|
+ sscanf(buf, "%hx", &val);
|
|
+ mt9p031_attr_basic_addr = (u16) val;
|
|
+ return n;
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR( basic_reg_addr, S_IRUGO|S_IWUSR, mt9p031_basic_reg_addr_show, mt9p031_basic_reg_addr_store);
|
|
+
|
|
+
|
|
+static ssize_t
|
|
+mt9p031_basic_reg_val_show( struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ u16 val;
|
|
+ int ret;
|
|
+ ret = mt9p031_reg_read(sysPriv.client, mt9p031_attr_basic_addr, &val);
|
|
+ if(ret < 0){
|
|
+ printk(KERN_INFO "mt9p031: Basic register read failed");
|
|
+ return 1; // nothing processed
|
|
+ } else {
|
|
+ return sprintf(buf, "0x%x\n", val);
|
|
+ }
|
|
+}
|
|
+
|
|
+static ssize_t
|
|
+mt9p031_basic_reg_val_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
|
|
+{
|
|
+ u32 val;
|
|
+ sscanf(buf, "%x", &val);
|
|
+
|
|
+ if (mt9p031_reg_write(sysPriv.client, mt9p031_attr_basic_addr, (u16)val)) {
|
|
+ printk(KERN_INFO "mt9p031: Basic regiser write failed");
|
|
+ return n; // nothing processed
|
|
+ } else {
|
|
+ return n;
|
|
+ }
|
|
+}
|
|
+static DEVICE_ATTR( basic_reg_val, S_IRUGO|S_IWUSR, mt9p031_basic_reg_val_show, mt9p031_basic_reg_val_store);
|
|
+
|
|
+
|
|
+/* Exposure time access support */
|
|
+static ssize_t
|
|
+mt9p031_exposure_val_show( struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ u32 val;
|
|
+ struct vcontrol *lvc;
|
|
+ int i = find_vctrl(V4L2_CID_EXPOSURE);
|
|
+ if (i < 0)
|
|
+ return -EINVAL;
|
|
+ lvc = &mt9p031_video_control[i];
|
|
+ val = lvc->current_value;
|
|
+
|
|
+ if(val < 0){
|
|
+ printk(KERN_INFO "mt9p031: Exposure value read failed");
|
|
+ return 1; // nothing processed
|
|
+ } else {
|
|
+ return sprintf(buf, "%d\n", val);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static ssize_t
|
|
+mt9p031_exposure_val_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
|
|
+{
|
|
+ u32 val;
|
|
+ struct i2c_client *client;
|
|
+ struct vcontrol *lvc;
|
|
+
|
|
+ sscanf(buf, "%d", &val);
|
|
+ client = sysPriv.client;
|
|
+
|
|
+ lvc = &mt9p031_video_control[V4L2_CID_EXPOSURE];
|
|
+
|
|
+ if (mt9p031_set_exposure_time((u32)val, client, lvc)) {
|
|
+ printk(KERN_INFO "mt9p031: Exposure write failed");
|
|
+ return n; // nothing processed
|
|
+ } else {
|
|
+ return n;
|
|
+ }
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR( exposure_val, S_IRUGO|S_IWUSR, mt9p031_exposure_val_show, mt9p031_exposure_val_store);
|
|
+
|
|
+
|
|
+/* Global Gain access support */
|
|
+static ssize_t
|
|
+mt9p031_gain_val_show( struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ u16 val;
|
|
+ struct vcontrol *lvc;
|
|
+
|
|
+ int i = find_vctrl(V4L2_CID_GAIN);
|
|
+ if (i < 0)
|
|
+ return -EINVAL;
|
|
+ lvc = &mt9p031_video_control[i];
|
|
+ val = lvc->current_value;
|
|
+
|
|
+ if(val < 0){
|
|
+ printk(KERN_INFO "mt9p031: Global Gain value read failed");
|
|
+ return 1; // nothing processed
|
|
+ } else {
|
|
+ return sprintf(buf, "%d\n", val);
|
|
+ }
|
|
+}
|
|
+
|
|
+static ssize_t
|
|
+mt9p031_gain_val_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
|
|
+{
|
|
+ u16 val;
|
|
+ struct i2c_client *client;
|
|
+ struct vcontrol *lvc;
|
|
+
|
|
+ sscanf(buf, "%hd", &val);
|
|
+ client = sysPriv.client;
|
|
+
|
|
+ lvc = &mt9p031_video_control[V4L2_CID_GAIN];
|
|
+
|
|
+ if (mt9p031_set_gain(val, client, lvc)) {
|
|
+ printk(KERN_INFO "mt9p031: Global gain write failed");
|
|
+ return n; // nothing processed
|
|
+ } else {
|
|
+ return n;
|
|
+ }
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR( gain_val, S_IRUGO|S_IWUSR, mt9p031_gain_val_show, mt9p031_gain_val_store);
|
|
+
|
|
+
|
|
+static struct attribute *mt9p031_sysfs_attr[] = {
|
|
+ &dev_attr_basic_reg_addr.attr,
|
|
+ &dev_attr_basic_reg_val.attr,
|
|
+ &dev_attr_exposure_val.attr,
|
|
+ &dev_attr_gain_val.attr,
|
|
+};
|
|
+
|
|
+static int mt9p031_sysfs_add(struct kobject *kobj)
|
|
+{
|
|
+ int i = ARRAY_SIZE(mt9p031_sysfs_attr);
|
|
+ int rval = 0;
|
|
+
|
|
+ do {
|
|
+ rval = sysfs_create_file(kobj, mt9p031_sysfs_attr[--i]);
|
|
+ } while((i > 0) && (rval == 0));
|
|
+ return rval;
|
|
+}
|
|
+
|
|
+static int mt9p031_sysfs_rm(struct kobject *kobj)
|
|
+{
|
|
+ int i = ARRAY_SIZE(mt9p031_sysfs_attr);
|
|
+ int rval = 0;
|
|
+
|
|
+ do {
|
|
+ sysfs_remove_file(kobj, mt9p031_sysfs_attr[--i]);
|
|
+ } while(i > 0);
|
|
+ return rval;
|
|
+}
|
|
+#endif //MT9P031_DEBUG
|
|
+
|
|
+static struct v4l2_int_slave mt9p031_slave = {
|
|
+ .ioctls = mt9p031_ioctl_desc,
|
|
+ .num_ioctls = ARRAY_SIZE(mt9p031_ioctl_desc),
|
|
+};
|
|
+
|
|
+static int mt9p031_probe(struct i2c_client *client,
|
|
+ const struct i2c_device_id *did)
|
|
+{
|
|
+ struct mt9p031_priv *priv;
|
|
+ struct v4l2_int_device *v4l2_int_device;
|
|
+ int ret;
|
|
+ if (!client->dev.platform_data) {
|
|
+ dev_err(&client->dev, "no platform data?\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ v4l2_int_device = kzalloc(sizeof(*v4l2_int_device), GFP_KERNEL);
|
|
+ if (!v4l2_int_device) {
|
|
+ kfree(priv);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+#ifdef MT9P031_HEADBOARD
|
|
+ mt9p031_config_PCA9543A(client); //configure i2c level shifter on mt9p031 head-board, no need for Leopard module
|
|
+ mdelay(10);
|
|
+#endif //MT9P031_HEADBOARD
|
|
+
|
|
+ v4l2_int_device->module = THIS_MODULE;
|
|
+ strncpy(v4l2_int_device->name, "mt9p031", sizeof(v4l2_int_device->name));
|
|
+
|
|
+ v4l2_int_device->type = v4l2_int_type_slave;
|
|
+ v4l2_int_device->u.slave = &mt9p031_slave;
|
|
+
|
|
+ v4l2_int_device->priv = priv;
|
|
+
|
|
+ priv->v4l2_int_device = v4l2_int_device;
|
|
+ priv->client = client;
|
|
+ priv->pdata = client->dev.platform_data;
|
|
+
|
|
+ priv->pdata->flags = MT9P031_FLAG_PCLK_RISING_EDGE;
|
|
+
|
|
+ /* Setting Pixel Values */
|
|
+ priv->pix.width = mt9p031_sizes[0].width;
|
|
+ priv->pix.height = mt9p031_sizes[0].height;
|
|
+ priv->pix.pixelformat = mt9p031_formats[0].pixelformat;
|
|
+
|
|
+ i2c_set_clientdata(client, priv);
|
|
+
|
|
+ sysPriv.client = priv->client;
|
|
+
|
|
+ ret = v4l2_int_device_register(priv->v4l2_int_device);
|
|
+ if (ret) {
|
|
+ i2c_set_clientdata(client, NULL);
|
|
+ kfree(v4l2_int_device);
|
|
+ kfree(priv);
|
|
+ }
|
|
+
|
|
+#ifdef MT9P031_DEBUG
|
|
+ mt9p031_sysfs_add(&client->dev.kobj);
|
|
+#endif //MT9P031_DEBUG
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int mt9p031_remove(struct i2c_client *client)
|
|
+{
|
|
+ struct mt9p031_priv *priv = i2c_get_clientdata(client);
|
|
+
|
|
+ v4l2_int_device_unregister(priv->v4l2_int_device);
|
|
+ i2c_set_clientdata(client, NULL);
|
|
+ mt9p031_sysfs_rm(&client->dev.kobj);
|
|
+
|
|
+ kfree(priv->v4l2_int_device);
|
|
+ kfree(priv);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct i2c_device_id mt9p031_id[] = {
|
|
+ { "mt9p031", 0 },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(i2c, mt9p031_id);
|
|
+
|
|
+static struct i2c_driver mt9p031_i2c_driver = {
|
|
+ .driver = {
|
|
+ .name = "mt9p031",
|
|
+ },
|
|
+ .probe = mt9p031_probe,
|
|
+ .remove = mt9p031_remove,
|
|
+ .id_table = mt9p031_id,
|
|
+};
|
|
+
|
|
+/************************************************************************
|
|
+ module function
|
|
+************************************************************************/
|
|
+static int __init mt9p031_module_init(void)
|
|
+{
|
|
+ return i2c_add_driver(&mt9p031_i2c_driver);
|
|
+}
|
|
+
|
|
+static void __exit mt9p031_module_exit(void)
|
|
+{
|
|
+ i2c_del_driver(&mt9p031_i2c_driver);
|
|
+}
|
|
+
|
|
+module_init(mt9p031_module_init);
|
|
+module_exit(mt9p031_module_exit);
|
|
+
|
|
+MODULE_DESCRIPTION("mt9p031 sensor driver");
|
|
+MODULE_AUTHOR("Aptina");
|
|
+MODULE_LICENSE("GPL v2");
|
|
+
|
|
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
|
|
new file mode 100644
|
|
index 0000000..d119589
|
|
--- /dev/null
|
|
+++ b/include/media/mt9p031.h
|
|
@@ -0,0 +1,30 @@
|
|
+/* mt9p031 Camera
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#ifndef __MT9P031_H__
|
|
+#define __MT9P031_H__
|
|
+
|
|
+#include <media/v4l2-int-device.h>
|
|
+
|
|
+#define MT9P031_I2C_ADDR 0x48 //(0x90 >> 1)
|
|
+
|
|
+#define MT9P031_CLK_MAX (27000000) /* 27MHz */
|
|
+#define MT9P031_CLK_MIN (6000000) /* 6Mhz */
|
|
+
|
|
+#define MT9P031_FLAG_PCLK_RISING_EDGE (1 << 0)
|
|
+#define MT9P031_FLAG_DATAWIDTH_8 (1 << 1) /* default width is 10 */
|
|
+
|
|
+struct mt9p031_platform_data {
|
|
+ char *master;
|
|
+ int (*power_set) (struct v4l2_int_device *s, enum v4l2_power on);
|
|
+ int (*ifparm) (struct v4l2_ifparm *p);
|
|
+ int (*priv_data_set) (void *);
|
|
+ u32 (*set_xclk) (struct v4l2_int_device *s, u32 xclkfreq);
|
|
+ u32 flags;
|
|
+};
|
|
+
|
|
+#endif /* __MT9P031_H__ */
|
|
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
|
|
index 6cc107d..7599bf1 100644
|
|
--- a/include/media/v4l2-chip-ident.h
|
|
+++ b/include/media/v4l2-chip-ident.h
|
|
@@ -271,6 +271,7 @@ enum {
|
|
V4L2_IDENT_MT9T112 = 45022,
|
|
V4L2_IDENT_MT9V111 = 45031,
|
|
V4L2_IDENT_MT9V112 = 45032,
|
|
+ V4L2_IDENT_MT9P031 = 6145,
|
|
|
|
/* HV7131R CMOS sensor: just ident 46000 */
|
|
V4L2_IDENT_HV7131R = 46000,
|
|
--
|
|
1.6.6.1
|
|
|