summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAndrei Andreyanau <a.andreyanau@sam-solutions.net>2013-02-20 17:40:00 +0300
committerJustin Waters <justin.waters@timesys.com>2013-11-07 12:19:24 -0500
commitd4a78cec2d15696274952cf81c447a7b2d11a61f (patch)
treec5b0e413a1a6a1611470b4ae77d8990de44aa3a6 /drivers
parenta266086cea49049b3896c9b8cbdef81e1d37c9ce (diff)
Fixed support for mt9v024 colour/monochrome camera sensor (uses mt9v022 kernel driver)
modified: drivers/media/video/mt9v022.c modified: include/media/v4l2-chip-ident.h Signed-off-by: Christian Hemp <c.hemp@phytec.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/mt9v022.c176
1 files changed, 76 insertions, 100 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index c7b9fe292f61..e95fb5f8a90f 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -1,5 +1,5 @@
/*
- * Driver for MT9V022 CMOS Image Sensor from Micron
+ * Driver for MT9V022/MT9V024 CMOS Image Sensor from Micron
*
* Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
*
@@ -19,7 +19,7 @@
#include <media/soc_camera.h>
/*
- * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
+ * MT9V022 and MT9V024 i2c address 0x48, 0x4c, 0x58, 0x5c
* The platform has to define ctruct i2c_board_info objects and link to them
* from struct soc_camera_link
*/
@@ -28,6 +28,8 @@ static char *sensor_type;
module_param(sensor_type, charp, S_IRUGO);
MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
+#define is_mt9v024() (mt9v022->model == V4L2_IDENT_MT9V024 ? 1 : 0)
+
/* mt9v022 selected register addresses */
#define MT9V022_CHIP_VERSION 0x00
#define MT9V022_COLUMN_START 0x01
@@ -47,17 +49,12 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
#define MT9V022_PIXEL_OPERATION_MODE 0x0f
#define MT9V022_LED_OUT_CONTROL 0x1b
#define MT9V022_ADC_MODE_CONTROL 0x1c
-#define MT9V022_REG32 0x20
#define MT9V022_ANALOG_GAIN 0x35
#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
-#define MT9V022_PIXCLK_FV_LV 0x74
+#define MT9V022_PIXCLK_FV_LV (is_mt9v024() ? 0x72 : 0x74)
#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
#define MT9V022_AEC_AGC_ENABLE 0xAF
-#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD
-
-/* mt9v024 partial list register addresses changes with respect to mt9v022 */
-#define MT9V024_PIXCLK_FV_LV 0x72
-#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH 0xAD
+#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH (is_mt9v024() ? 0xAD : 0xBD)
/* Progressive scan, master, defaults */
#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
@@ -69,9 +66,6 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
#define MT9V022_COLUMN_SKIP 1
#define MT9V022_ROW_SKIP 4
-#define is_mt9v022_rev3(id) (id == 0x1313)
-#define is_mt9v024(id) (id == 0x1324)
-
/* MT9V022 has only one fixed colorspace per pixelcode */
struct mt9v022_datafmt {
enum v4l2_mbus_pixelcode code;
@@ -106,31 +100,14 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
{V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
};
-struct mt9v02x_register {
- u8 max_total_shutter_width;
- u8 pixclk_fv_lv;
-};
-
-static const struct mt9v02x_register mt9v022_register = {
- .max_total_shutter_width = MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
- .pixclk_fv_lv = MT9V022_PIXCLK_FV_LV,
-};
-
-static const struct mt9v02x_register mt9v024_register = {
- .max_total_shutter_width = MT9V024_MAX_TOTAL_SHUTTER_WIDTH,
- .pixclk_fv_lv = MT9V024_PIXCLK_FV_LV,
-};
-
struct mt9v022 {
struct v4l2_subdev subdev;
struct v4l2_rect rect; /* Sensor window */
const struct mt9v022_datafmt *fmt;
const struct mt9v022_datafmt *fmts;
- const struct mt9v02x_register *reg;
int num_fmts;
- int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
+ int model; /* V4L2_IDENT_MT9V02x codes from v4l2-chip-ident.h */
u16 chip_control;
- u16 chip_version;
unsigned short y_skip_top; /* Lines to skip at the top */
};
@@ -212,32 +189,12 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
- if (enable) {
+ if (enable)
/* Switch to master "normal" mode */
mt9v022->chip_control &= ~0x10;
- if (is_mt9v022_rev3(mt9v022->chip_version) ||
- is_mt9v024(mt9v022->chip_version)) {
- /*
- * Unset snapshot mode specific settings: clear bit 9
- * and bit 2 in reg. 0x20 when in normal mode.
- */
- if (reg_clear(client, MT9V022_REG32, 0x204))
- return -EIO;
- }
- } else {
- /* Switch to snapshot mode */
- mt9v022->chip_control |= 0x10;
- if (is_mt9v022_rev3(mt9v022->chip_version) ||
- is_mt9v024(mt9v022->chip_version)) {
- /*
- * Required settings for snapshot mode: set bit 9
- * (RST enable) and bit 2 (CR enable) in reg. 0x20
- * See TechNote TN0960 or TN-09-225.
- */
- if (reg_set(client, MT9V022_REG32, 0x204))
- return -EIO;
- }
- }
+ else
+ /* Switch to snapshot mode */
+ mt9v022->chip_control |= 0x10;
if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
return -EIO;
@@ -321,7 +278,6 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_rect rect = a->c;
- int min_row, min_blank;
int ret;
/* Bayer format - even size lengths */
@@ -339,35 +295,25 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
/* Like in example app. Contradicts the datasheet though */
ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
- if (ret >= 0) {
- if (ret & 1) /* Autoexposure */
- ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
- rect.height + mt9v022->y_skip_top + 43);
- else
- ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
+ if (ret >= 0 && ret & 1) /* Autoexposure */
+ ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
rect.height + mt9v022->y_skip_top + 43);
- }
/* Setup frame format: defaults apart from width and height */
if (!ret)
ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
if (!ret)
ret = reg_write(client, MT9V022_ROW_START, rect.top);
-
- /*
- * mt9v022: min total row time is 660 columns, min blanking is 43
- * mt9v024: min total row time is 690 columns, min blanking is 61
- */
- if (is_mt9v024(mt9v022->chip_version)) {
- min_row = 690;
- min_blank = 61;
- } else {
- min_row = 660;
- min_blank = 43;
+ if (!ret) {
+ if (is_mt9v024()) {
+ ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
+ rect.width > 690 - 61 ? 61 :
+ 690 - rect.width);
+ } else {
+ ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
+ rect.width > 660 - 43 ? 43 :
+ 660 - rect.width);
+ }
}
- if (!ret)
- ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
- rect.width > min_row - min_blank ?
- min_blank : min_row - rect.width);
if (!ret)
ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
@@ -449,12 +395,14 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
switch (mf->code) {
case V4L2_MBUS_FMT_Y8_1X8:
case V4L2_MBUS_FMT_Y10_1X10:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM &&
+ mt9v022->model != V4L2_IDENT_MT9V024)
return -EINVAL;
break;
case V4L2_MBUS_FMT_SBGGR8_1X8:
case V4L2_MBUS_FMT_SBGGR10_1X10:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC &&
+ mt9v022->model != V4L2_IDENT_MT9V024)
return -EINVAL;
break;
default:
@@ -775,34 +723,45 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
* this wasn't our capture interface, so, we wait for the right one
*/
static int mt9v022_video_probe(struct soc_camera_device *icd,
- struct i2c_client *client)
+ struct i2c_client *client)
{
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct soc_camera_link *icl = to_soc_camera_link(icd);
s32 data;
int ret;
unsigned long flags;
+ int color = 0;
if (!icd->dev.parent ||
to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
return -ENODEV;
+ if (sensor_type && (!strcmp("colour", sensor_type) ||
+ !strcmp("color", sensor_type)))
+ color = 1;
+
/* Read out the chip version register */
data = reg_read(client, MT9V022_CHIP_VERSION);
- /* must be 0x1311 or 0x1313 */
- if (data != 0x1311 && data != 0x1313 && data != 0x1324) {
+ /* must be 0x1311, 0x1313 or 0x1324 */
+ switch (data) {
+ case 0x1324:
+ mt9v022->model = V4L2_IDENT_MT9V024;
+ break;
+ case 0x1311:
+ case 0x1313:
+ if (color)
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+ else
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+ break;
+ default:
ret = -ENODEV;
- dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
- data);
+ dev_info(&client->dev, "No MT9V02x found, ID register 0x%x\n",
+ data);
goto ei2c;
}
- mt9v022->chip_version = data;
-
- mt9v022->reg = is_mt9v024(data) ? &mt9v024_register :
- &mt9v022_register;
-
/* Soft reset */
ret = reg_write(client, MT9V022_RESET, 1);
if (ret < 0)
@@ -810,21 +769,38 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
/* 15 clock cycles */
udelay(200);
if (reg_read(client, MT9V022_RESET)) {
- dev_err(&client->dev, "Resetting MT9V022 failed!\n");
+ dev_err(&client->dev, "Resetting MT9V02x failed!\n");
if (ret > 0)
ret = -EIO;
goto ei2c;
}
/* Set monochrome or colour sensor type */
- if (sensor_type && (!strcmp("colour", sensor_type) ||
- !strcmp("color", sensor_type))) {
- ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
- mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+ if (color) {
+ switch (mt9v022->model) {
+ case V4L2_IDENT_MT9V022IX7ATC:
+ ret = reg_write(client,
+ MT9V022_PIXEL_OPERATION_MODE, 0x4 | 0x11);
+ break;
+ case V4L2_IDENT_MT9V024:
+ ret = reg_write(client,
+ MT9V022_PIXEL_OPERATION_MODE, 0x02 | 0x100);
+ break;
+ }
+
mt9v022->fmts = mt9v022_colour_fmts;
} else {
- ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
- mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+ switch (mt9v022->model) {
+ case V4L2_IDENT_MT9V022IX7ATM:
+ ret = reg_write(client,
+ MT9V022_PIXEL_OPERATION_MODE, 0x11);
+ break;
+ case V4L2_IDENT_MT9V024:
+ ret = reg_write(client,
+ MT9V022_PIXEL_OPERATION_MODE, 0x100);
+ break;
+ }
+
mt9v022->fmts = mt9v022_monochrome_fmts;
}
@@ -853,7 +829,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
mt9v022->fmt = &mt9v022->fmts[0];
- dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+ dev_info(&client->dev, "Detected a MT9V02x chip ID %x, %s sensor\n",
data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
"monochrome" : "colour");
@@ -939,13 +915,13 @@ static int mt9v022_probe(struct i2c_client *client,
int ret;
if (!icd) {
- dev_err(&client->dev, "MT9V022: missing soc-camera data!\n");
+ dev_err(&client->dev, "MT9V02x: missing soc-camera data!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl) {
- dev_err(&client->dev, "MT9V022 driver needs platform data\n");
+ dev_err(&client->dev, "MT9V02x driver needs platform data\n");
return -EINVAL;
}
@@ -1022,6 +998,6 @@ static void __exit mt9v022_mod_exit(void)
module_init(mt9v022_mod_init);
module_exit(mt9v022_mod_exit);
-MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
+MODULE_DESCRIPTION("Micron MT9V022/MT9V024 Camera driver");
MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
MODULE_LICENSE("GPL");