aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c/soc_camera/mt9v022.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/soc_camera/mt9v022.c')
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c88
1 files changed, 78 insertions, 10 deletions
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index 333ef178d6fb..d40a8858be01 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -15,6 +15,7 @@
15#include <linux/log2.h> 15#include <linux/log2.h>
16#include <linux/module.h> 16#include <linux/module.h>
17 17
18#include <media/mt9v022.h>
18#include <media/soc_camera.h> 19#include <media/soc_camera.h>
19#include <media/soc_mediabus.h> 20#include <media/soc_mediabus.h>
20#include <media/v4l2-subdev.h> 21#include <media/v4l2-subdev.h>
@@ -50,6 +51,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
50#define MT9V022_PIXEL_OPERATION_MODE 0x0f 51#define MT9V022_PIXEL_OPERATION_MODE 0x0f
51#define MT9V022_LED_OUT_CONTROL 0x1b 52#define MT9V022_LED_OUT_CONTROL 0x1b
52#define MT9V022_ADC_MODE_CONTROL 0x1c 53#define MT9V022_ADC_MODE_CONTROL 0x1c
54#define MT9V022_REG32 0x20
53#define MT9V022_ANALOG_GAIN 0x35 55#define MT9V022_ANALOG_GAIN 0x35
54#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 56#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
55#define MT9V022_PIXCLK_FV_LV 0x74 57#define MT9V022_PIXCLK_FV_LV 0x74
@@ -71,7 +73,15 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
71#define MT9V022_COLUMN_SKIP 1 73#define MT9V022_COLUMN_SKIP 1
72#define MT9V022_ROW_SKIP 4 74#define MT9V022_ROW_SKIP 4
73 75
74#define is_mt9v024(id) (id == 0x1324) 76#define MT9V022_HORIZONTAL_BLANKING_MIN 43
77#define MT9V022_HORIZONTAL_BLANKING_MAX 1023
78#define MT9V022_HORIZONTAL_BLANKING_DEF 94
79#define MT9V022_VERTICAL_BLANKING_MIN 2
80#define MT9V022_VERTICAL_BLANKING_MAX 3000
81#define MT9V022_VERTICAL_BLANKING_DEF 45
82
83#define is_mt9v022_rev3(id) (id == 0x1313)
84#define is_mt9v024(id) (id == 0x1324)
75 85
76/* MT9V022 has only one fixed colorspace per pixelcode */ 86/* MT9V022 has only one fixed colorspace per pixelcode */
77struct mt9v022_datafmt { 87struct mt9v022_datafmt {
@@ -136,6 +146,8 @@ struct mt9v022 {
136 struct v4l2_ctrl *autogain; 146 struct v4l2_ctrl *autogain;
137 struct v4l2_ctrl *gain; 147 struct v4l2_ctrl *gain;
138 }; 148 };
149 struct v4l2_ctrl *hblank;
150 struct v4l2_ctrl *vblank;
139 struct v4l2_rect rect; /* Sensor window */ 151 struct v4l2_rect rect; /* Sensor window */
140 const struct mt9v022_datafmt *fmt; 152 const struct mt9v022_datafmt *fmt;
141 const struct mt9v022_datafmt *fmts; 153 const struct mt9v022_datafmt *fmts;
@@ -143,6 +155,7 @@ struct mt9v022 {
143 int num_fmts; 155 int num_fmts;
144 int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ 156 int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
145 u16 chip_control; 157 u16 chip_control;
158 u16 chip_version;
146 unsigned short y_skip_top; /* Lines to skip at the top */ 159 unsigned short y_skip_top; /* Lines to skip at the top */
147}; 160};
148 161
@@ -225,12 +238,32 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
225 struct i2c_client *client = v4l2_get_subdevdata(sd); 238 struct i2c_client *client = v4l2_get_subdevdata(sd);
226 struct mt9v022 *mt9v022 = to_mt9v022(client); 239 struct mt9v022 *mt9v022 = to_mt9v022(client);
227 240
228 if (enable) 241 if (enable) {
229 /* Switch to master "normal" mode */ 242 /* Switch to master "normal" mode */
230 mt9v022->chip_control &= ~0x10; 243 mt9v022->chip_control &= ~0x10;
231 else 244 if (is_mt9v022_rev3(mt9v022->chip_version) ||
245 is_mt9v024(mt9v022->chip_version)) {
246 /*
247 * Unset snapshot mode specific settings: clear bit 9
248 * and bit 2 in reg. 0x20 when in normal mode.
249 */
250 if (reg_clear(client, MT9V022_REG32, 0x204))
251 return -EIO;
252 }
253 } else {
232 /* Switch to snapshot mode */ 254 /* Switch to snapshot mode */
233 mt9v022->chip_control |= 0x10; 255 mt9v022->chip_control |= 0x10;
256 if (is_mt9v022_rev3(mt9v022->chip_version) ||
257 is_mt9v024(mt9v022->chip_version)) {
258 /*
259 * Required settings for snapshot mode: set bit 9
260 * (RST enable) and bit 2 (CR enable) in reg. 0x20
261 * See TechNote TN0960 or TN-09-225.
262 */
263 if (reg_set(client, MT9V022_REG32, 0x204))
264 return -EIO;
265 }
266 }
234 267
235 if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) 268 if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
236 return -EIO; 269 return -EIO;
@@ -282,11 +315,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
282 * Default 94, Phytec driver says: 315 * Default 94, Phytec driver says:
283 * "width + horizontal blank >= 660" 316 * "width + horizontal blank >= 660"
284 */ 317 */
285 ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, 318 ret = v4l2_ctrl_s_ctrl(mt9v022->hblank,
286 rect.width > 660 - 43 ? 43 : 319 rect.width > 660 - 43 ? 43 : 660 - rect.width);
287 660 - rect.width);
288 if (!ret) 320 if (!ret)
289 ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); 321 ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45);
290 if (!ret) 322 if (!ret)
291 ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); 323 ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
292 if (!ret) 324 if (!ret)
@@ -509,6 +541,18 @@ static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
509 range = exp->maximum - exp->minimum; 541 range = exp->maximum - exp->minimum;
510 exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; 542 exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
511 return 0; 543 return 0;
544 case V4L2_CID_HBLANK:
545 data = reg_read(client, MT9V022_HORIZONTAL_BLANKING);
546 if (data < 0)
547 return -EIO;
548 ctrl->val = data;
549 return 0;
550 case V4L2_CID_VBLANK:
551 data = reg_read(client, MT9V022_VERTICAL_BLANKING);
552 if (data < 0)
553 return -EIO;
554 ctrl->val = data;
555 return 0;
512 } 556 }
513 return -EINVAL; 557 return -EINVAL;
514} 558}
@@ -590,6 +634,16 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
590 return -EIO; 634 return -EIO;
591 } 635 }
592 return 0; 636 return 0;
637 case V4L2_CID_HBLANK:
638 if (reg_write(client, MT9V022_HORIZONTAL_BLANKING,
639 ctrl->val) < 0)
640 return -EIO;
641 return 0;
642 case V4L2_CID_VBLANK:
643 if (reg_write(client, MT9V022_VERTICAL_BLANKING,
644 ctrl->val) < 0)
645 return -EIO;
646 return 0;
593 } 647 }
594 return -EINVAL; 648 return -EINVAL;
595} 649}
@@ -621,6 +675,8 @@ static int mt9v022_video_probe(struct i2c_client *client)
621 goto ei2c; 675 goto ei2c;
622 } 676 }
623 677
678 mt9v022->chip_version = data;
679
624 mt9v022->reg = is_mt9v024(data) ? &mt9v024_register : 680 mt9v022->reg = is_mt9v024(data) ? &mt9v024_register :
625 &mt9v022_register; 681 &mt9v022_register;
626 682
@@ -819,6 +875,7 @@ static int mt9v022_probe(struct i2c_client *client,
819 struct mt9v022 *mt9v022; 875 struct mt9v022 *mt9v022;
820 struct soc_camera_link *icl = soc_camera_i2c_to_link(client); 876 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
821 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 877 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
878 struct mt9v022_platform_data *pdata = icl->priv;
822 int ret; 879 int ret;
823 880
824 if (!icl) { 881 if (!icl) {
@@ -857,10 +914,21 @@ static int mt9v022_probe(struct i2c_client *client,
857 mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, 914 mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
858 V4L2_CID_EXPOSURE, 1, 255, 1, 255); 915 V4L2_CID_EXPOSURE, 1, 255, 1, 255);
859 916
917 mt9v022->hblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
918 V4L2_CID_HBLANK, MT9V022_HORIZONTAL_BLANKING_MIN,
919 MT9V022_HORIZONTAL_BLANKING_MAX, 1,
920 MT9V022_HORIZONTAL_BLANKING_DEF);
921
922 mt9v022->vblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
923 V4L2_CID_VBLANK, MT9V022_VERTICAL_BLANKING_MIN,
924 MT9V022_VERTICAL_BLANKING_MAX, 1,
925 MT9V022_VERTICAL_BLANKING_DEF);
926
860 mt9v022->subdev.ctrl_handler = &mt9v022->hdl; 927 mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
861 if (mt9v022->hdl.error) { 928 if (mt9v022->hdl.error) {
862 int err = mt9v022->hdl.error; 929 int err = mt9v022->hdl.error;
863 930
931 dev_err(&client->dev, "control initialisation err %d\n", err);
864 kfree(mt9v022); 932 kfree(mt9v022);
865 return err; 933 return err;
866 } 934 }
@@ -871,10 +939,10 @@ static int mt9v022_probe(struct i2c_client *client,
871 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; 939 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
872 940
873 /* 941 /*
874 * MT9V022 _really_ corrupts the first read out line. 942 * On some platforms the first read out line is corrupted.
875 * TODO: verify on i.MX31 943 * Workaround it by skipping if indicated by platform data.
876 */ 944 */
877 mt9v022->y_skip_top = 1; 945 mt9v022->y_skip_top = pdata ? pdata->y_skip_top : 0;
878 mt9v022->rect.left = MT9V022_COLUMN_SKIP; 946 mt9v022->rect.left = MT9V022_COLUMN_SKIP;
879 mt9v022->rect.top = MT9V022_ROW_SKIP; 947 mt9v022->rect.top = MT9V022_ROW_SKIP;
880 mt9v022->rect.width = MT9V022_MAX_WIDTH; 948 mt9v022->rect.width = MT9V022_MAX_WIDTH;