summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorQuinn Jensen <quinn.jensen@freescale.com>2007-10-24 21:21:12 -0600
committerQuinn Jensen <quinn.jensen@freescale.com>2007-10-24 21:21:12 -0600
commitf04a23eb983a5994005a7aa2c09ef7d7fb9158dc (patch)
tree1b902818db333034cb3ff7808fc228523b8f1cdd /drivers
parent66eb60fd9fa5d0112a01b250637d0737dc9046d3 (diff)
CR 34439732: Camera and V4L2 improvements
Patch for CR 34439732: Camera and V4L2 improvements. Add flicker control, white balance, automatic exposure support, and tear prevention to the iMagic camera driver on the linux 2.6.22 kernel for MX platforms. Ported to 2.6.22 by Ross Wille http://www.bitshrine.org/gpp/linux-2.6.22-mx-CR-34439732-Camera-and-V4L2-improvements.patch
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/mxc/capture/mt9v111.c181
-rw-r--r--drivers/media/video/mxc/capture/mt9v111.h19
-rw-r--r--drivers/media/video/mxc/capture/mx27_v4l2_capture.c43
-rw-r--r--drivers/media/video/mxc/capture/mxc_v4l2_capture.h7
-rw-r--r--drivers/media/video/mxc/output/mx27_v4l2_output.c54
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.h11
6 files changed, 283 insertions, 32 deletions
diff --git a/drivers/media/video/mxc/capture/mt9v111.c b/drivers/media/video/mxc/capture/mt9v111.c
index 049615ff7315..4538ca29a0fa 100644
--- a/drivers/media/video/mxc/capture/mt9v111.c
+++ b/drivers/media/video/mxc/capture/mt9v111.c
@@ -166,6 +166,11 @@ static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg)
data = ifpReg->formatControl; // Set bit 12
mt9v111_write_reg(reg, data);
+ // Flicker Control
+ reg = MT9V111I_FLICKER_CONTROL;
+ data = ifpReg->flickerCtrl;
+ mt9v111_write_reg(reg, data);
+
// AE limit 4
reg = MT9V111I_SHUTTER_WIDTH_LIMIT_AE;
data = ifpReg->gainLimitAE;
@@ -361,6 +366,7 @@ sensor_interface *mt9v111_config(int *frame_rate, int high_quality)
mt9v111_device.ifpReg->formatControl = 0xc800;
mt9v111_device.ifpReg->modeControl = 0x708e;
mt9v111_device.ifpReg->awbSpeed = 0x4514;
+ mt9v111_device.ifpReg->flickerCtrl = 0x02;
mt9v111_device.coreReg->shutterWidth = 0xf8;
out_width = 640;
@@ -511,6 +517,149 @@ static void mt9v111_get_ae_mode(int *ae_mode)
}
/*!
+ * mt9v111 sensor enable/disable AE
+ *
+ * @param active int
+ * @return None
+ */
+static void mt9v111_set_ae(int active)
+{
+ u8 reg;
+ u16 data;
+
+ mt9v111_device.ifpReg->modeControl &= 0xfff3;
+ mt9v111_device.ifpReg->modeControl |= (active & 0x01) << 14;
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(reg, data);
+
+ reg = MT9V111I_MODE_CONTROL;
+ data = mt9v111_device.ifpReg->modeControl;
+ mt9v111_write_reg(reg, data);
+}
+
+/*!
+ * mt9v111 sensor enable/disable auto white balance
+ *
+ * @param active int
+ * @return None
+ */
+static void mt9v111_set_awb(int active)
+{
+ u8 reg;
+ u16 data;
+
+ mt9v111_device.ifpReg->modeControl &= 0xfff3;
+ mt9v111_device.ifpReg->modeControl |= (active & 0x01) << 1;
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(reg, data);
+
+ reg = MT9V111I_MODE_CONTROL;
+ data = mt9v111_device.ifpReg->modeControl;
+ mt9v111_write_reg(reg, data);
+}
+
+/*!
+ * mt9v111 sensor set the flicker control
+ *
+ * @param control int
+ * @return None
+ */
+static void mt9v111_flicker_control(int control)
+{
+ u8 reg;
+ u16 data;
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(reg, data);
+
+ switch (control) {
+ case MT9V111_FLICKER_DISABLE:
+ mt9v111_device.ifpReg->formatControl &= ~(0x01 << 11);
+
+ reg = MT9V111I_FORMAT_CONTROL;
+ data = mt9v111_device.ifpReg->formatControl;
+ mt9v111_write_reg(reg, data);
+ break;
+
+ case MT9V111_FLICKER_MANUAL_50:
+ if (!(mt9v111_device.ifpReg->formatControl & (0x01 << 11))) {
+ mt9v111_device.ifpReg->formatControl |= (0x01 << 11);
+ reg = MT9V111I_FORMAT_CONTROL;
+ data = mt9v111_device.ifpReg->formatControl;
+ mt9v111_write_reg(reg, data);
+ }
+ mt9v111_device.ifpReg->flickerCtrl = 0x01;
+ reg = MT9V111I_FLICKER_CONTROL;
+ data = mt9v111_device.ifpReg->flickerCtrl;
+ mt9v111_write_reg(reg, data);
+ break;
+
+ case MT9V111_FLICKER_MANUAL_60:
+ if (!(mt9v111_device.ifpReg->formatControl & (0x01 << 11))) {
+ mt9v111_device.ifpReg->formatControl |= (0x01 << 11);
+ reg = MT9V111I_FORMAT_CONTROL;
+ data = mt9v111_device.ifpReg->formatControl;
+ mt9v111_write_reg(reg, data);
+ }
+ mt9v111_device.ifpReg->flickerCtrl = 0x03;
+ reg = MT9V111I_FLICKER_CONTROL;
+ data = mt9v111_device.ifpReg->flickerCtrl;
+ mt9v111_write_reg(reg, data);
+ break;
+
+ case MT9V111_FLICKER_AUTO_DETECTION:
+ if (!(mt9v111_device.ifpReg->formatControl & (0x01 << 11))) {
+ mt9v111_device.ifpReg->formatControl |= (0x01 << 11);
+ reg = MT9V111I_FORMAT_CONTROL;
+ data = mt9v111_device.ifpReg->formatControl;
+ mt9v111_write_reg(reg, data);
+ }
+ mt9v111_device.ifpReg->flickerCtrl = 0x10;
+ reg = MT9V111I_FLICKER_CONTROL;
+ data = mt9v111_device.ifpReg->flickerCtrl;
+ mt9v111_write_reg(reg, data);
+ break;
+ }
+ return;
+
+}
+
+/*!
+ * mt9v111 Get mode&flicker control parameters
+ *
+ * @return None
+ */
+static void mt9v111_get_control_params(int *ae, int *awb, int *flicker)
+{
+ if ((ae != NULL) && (awb != NULL) && (flicker != NULL)) {
+ *ae = (mt9v111_device.ifpReg->modeControl & 0x4000) >> 14;
+ *awb = (mt9v111_device.ifpReg->modeControl & 0x02) >> 1;
+ *flicker = (mt9v111_device.ifpReg->formatControl & 0x800) >> 9;
+ if (*flicker) {
+ *flicker = (mt9v111_device.ifpReg->flickerCtrl & 0x03);
+ switch (*flicker) {
+ case 1:
+ *flicker = MT9V111_FLICKER_MANUAL_50;
+ break;
+ case 3:
+ *flicker = MT9V111_FLICKER_MANUAL_60;
+ break;
+ default:
+ *flicker = MT9V111_FLICKER_AUTO_DETECTION;
+ break;
+ }
+ } else
+ *flicker = MT9V111_FLICKER_DISABLE;
+ }
+ return;
+}
+
+/*!
* mt9v111 Reset function
*
* @return None
@@ -527,24 +676,24 @@ static sensor_interface *mt9v111_reset(void)
*/
static int mt9v111_get_status(void)
{
- int retval=0;
- u8 reg;
- u16 data=0;
+ int retval = 0;
+ u8 reg;
+ u16 data = 0;
if (!interface_param)
- return -ENODEV;
+ return -ENODEV;
- reg = MT9V111I_ADDR_SPACE_SEL;
- data = MT9V111I_SEL_SCA;
- retval = mt9v111_write_reg(reg, data);
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = MT9V111I_SEL_SCA;
+ retval = mt9v111_write_reg(reg, data);
- reg = MT9V111S_SENSOR_CORE_VERSION;
- retval = mt9v111_read_reg(&reg, &data);
- data = mt9v111_endian_swap16(data);
- if (MT9V111_CHIP_VERSION != data)
- retval = -ENODEV;
+ reg = MT9V111S_SENSOR_CORE_VERSION;
+ retval = mt9v111_read_reg(&reg, &data);
+ data = mt9v111_endian_swap16(data);
+ if (MT9V111_CHIP_VERSION != data)
+ retval = -ENODEV;
- return retval;
+ return retval;
}
struct camera_sensor camera_sensor_if = {
@@ -552,6 +701,10 @@ struct camera_sensor camera_sensor_if = {
.get_color = mt9v111_get_color,
.set_ae_mode = mt9v111_set_ae_mode,
.get_ae_mode = mt9v111_get_ae_mode,
+ .set_ae = mt9v111_set_ae,
+ .set_awb = mt9v111_set_awb,
+ .flicker_control = mt9v111_flicker_control,
+ .get_control_params = mt9v111_get_control_params,
.config = mt9v111_config,
.reset = mt9v111_reset,
.get_status = mt9v111_get_status,
@@ -656,7 +809,7 @@ static int mt9v111_attach(struct i2c_adapter *adap)
clk = clk_get(NULL, "csi_clk");
clk_enable(clk);
set_mclk_rate(&mclk);
-
+
err = i2c_probe(adap, &addr_data, &mt9v111_detect_client);
clk_disable(clk);
clk_put(clk);
diff --git a/drivers/media/video/mxc/capture/mt9v111.h b/drivers/media/video/mxc/capture/mt9v111.h
index f244ffd80ab0..be1493f2f7af 100644
--- a/drivers/media/video/mxc/capture/mt9v111.h
+++ b/drivers/media/video/mxc/capture/mt9v111.h
@@ -106,6 +106,7 @@
#define MT9V111I_GAMMA_KNEE_Y90 0x57
#define MT9V111I_GAMMA_VALUE_Y0 0x58
#define MT9V111I_SHUTTER_60 0x59
+#define MT9V111I_FLICKER_CONTROL 0x5B
#define MT9V111I_SEARCH_FLICK_60 0x5c
#define MT9V111I_RATIO_IMAGE_GAIN_BASE 0x5e
#define MT9V111I_RATIO_IMAGE_GAIN_DELTA 0x5f
@@ -227,6 +228,16 @@ typedef enum {
MT9V111_OutputResolution_SXGA /*!< SXGA size */
} MT9V111_OutputResolution;
+/*!
+ * The flicker control setting
+ */
+enum {
+ MT9V111_FLICKER_DISABLE = 0,
+ MT9V111_FLICKER_MANUAL_50,
+ MT9V111_FLICKER_MANUAL_60,
+ MT9V111_FLICKER_AUTO_DETECTION
+};
+
enum {
MT9V111_WINWIDTH = 0x287,
MT9V111_WINWIDTH_DEFAULT = 0x287,
@@ -370,6 +381,7 @@ typedef struct {
u32 gammaKneeY90; /*!< Gamma knee points Y9 and Y10 */
u32 gammaKneeY0; /*!< Gamma knee point Y0 */
u32 shutter_width_60;
+ u32 flickerCtrl;
u32 search_flicker_60;
u32 ratioImageGainBase;
u32 ratioImageGainDelta;
@@ -423,4 +435,11 @@ typedef struct {
u16 height;
} mt9v111_image_format;
+typedef struct {
+ u16 ae;
+ u16 awb;
+ u16 flicker;
+ u16 reserved;
+} mt9v111_ctrl_params;
+
#endif // MT9V111_H_
diff --git a/drivers/media/video/mxc/capture/mx27_v4l2_capture.c b/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
index c776bc38d375..0ebc9644050b 100644
--- a/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
@@ -468,6 +468,15 @@ static int mxc_get_v42l_control(cam_data * cam, struct v4l2_control *c)
case V4L2_CID_BLACK_LEVEL:
c->value = cam->ae_mode;
break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ c->value = cam->awb_enable;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ c->value = cam->ae_enable;
+ break;
+ case V4L2_CID_MXC_FLICKER:
+ c->value = cam->flicker_ctrl;
+ break;
default:
status = -EINVAL;
}
@@ -559,6 +568,27 @@ static int mxc_set_v42l_control(cam_data * cam, struct v4l2_control *c)
break;
case V4L2_CID_MXC_FLASH:
break;
+ case V4L2_CID_AUTOGAIN:
+ cam->ae_enable = c->value;
+ csi_enable_mclk(CSI_MCLK_I2C, true, true);
+ if (cam->cam_sensor->set_ae)
+ cam->cam_sensor->set_ae(cam->ae_enable);
+ csi_enable_mclk(CSI_MCLK_I2C, false, false);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ cam->awb_enable = c->value;
+ csi_enable_mclk(CSI_MCLK_I2C, true, true);
+ if (cam->cam_sensor->set_awb)
+ cam->cam_sensor->set_awb(cam->awb_enable);
+ csi_enable_mclk(CSI_MCLK_I2C, false, false);
+ break;
+ case V4L2_CID_MXC_FLICKER:
+ cam->flicker_ctrl = c->value;
+ csi_enable_mclk(CSI_MCLK_I2C, true, true);
+ if (cam->cam_sensor->flicker_control)
+ cam->cam_sensor->flicker_control(cam->flicker_ctrl);
+ csi_enable_mclk(CSI_MCLK_I2C, false, false);
+ break;
default:
return -EINVAL;
}
@@ -747,7 +777,7 @@ static int mxc_v4l_dqueue(cam_data * cam, struct v4l2_buffer *buf)
static int mxc_get_video_input(cam_data * cam)
{
int retval = 0;
- csi_enable_mclk(CSI_MCLK_I2C, true, true);
+ csi_enable_mclk(CSI_MCLK_I2C, true, true);
retval = cam->cam_sensor->get_status();
csi_enable_mclk(CSI_MCLK_I2C, false, false);
return retval;
@@ -779,8 +809,8 @@ static int mxc_v4l_open(struct inode *inode, struct file *file)
}
err = mxc_get_video_input(cam);
- if (0 != err)
- return -ENODEV;
+ if (0 != err)
+ return -ENODEV;
if (down_interruptible(&cam->busy_lock))
return -EINTR;
@@ -822,6 +852,9 @@ static int mxc_v4l_open(struct inode *inode, struct file *file)
&cam->red, &cam->green, &cam->blue);
if (cam->cam_sensor->get_ae_mode)
cam->cam_sensor->get_ae_mode(&cam->ae_mode);
+ cam->cam_sensor->get_control_params(&cam->ae_enable,
+ &cam->awb_enable,
+ &cam->flicker_ctrl);
csi_enable_mclk(CSI_MCLK_I2C, false, false);
prp_init(cam);
@@ -1718,7 +1751,7 @@ mxc_v4l_do_ioctl(struct inode *inode, struct file *file,
cam->output = *p_output_num;
break;
}
-
+
case VIDIOC_G_INPUT:
{
int *p_input_index = arg;
@@ -1731,7 +1764,7 @@ mxc_v4l_do_ioctl(struct inode *inode, struct file *file,
break;
}
-
+
case VIDIOC_ENUM_FMT:
case VIDIOC_TRY_FMT:
case VIDIOC_QUERYCTRL:
diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
index 543a8db4bef6..69cc5189fd16 100644
--- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
+++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
@@ -74,6 +74,10 @@ struct camera_sensor {
int *blue);
void (*set_ae_mode) (int ae_mode);
void (*get_ae_mode) (int *ae_mode);
+ void (*set_ae) (int active);
+ void (*set_awb) (int active);
+ void (*flicker_control) (int control);
+ void (*get_control_params) (int *ae, int *awb, int *flicker);
sensor_interface *(*config) (int *frame_rate, int high_quality);
sensor_interface *(*reset) (void);
int (*get_status) (void);
@@ -142,6 +146,9 @@ typedef struct _cam_data {
int green;
int blue;
int ae_mode;
+ int ae_enable;
+ int awb_enable;
+ int flicker_ctrl;
/* standart */
struct v4l2_streamparm streamparm;
diff --git a/drivers/media/video/mxc/output/mx27_v4l2_output.c b/drivers/media/video/mxc/output/mx27_v4l2_output.c
index 7ac39663e2d7..9e26bfb85af7 100644
--- a/drivers/media/video/mxc/output/mx27_v4l2_output.c
+++ b/drivers/media/video/mxc/output/mx27_v4l2_output.c
@@ -290,9 +290,15 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
goto exit0;
}
#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
- if (g_fb_enabled && (vout->v4l2_fb.flags != V4L2_FBUF_FLAG_OVERLAY))
- g_pp_ready = 1;
- else if (pp_enable(1)) {
+ if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) {
+ if (g_fb_enabled
+ && (vout->v4l2_fb.flags != V4L2_FBUF_FLAG_OVERLAY))
+ g_pp_ready = 1;
+ else if (pp_enable(1)) {
+ pr_debug("unable to enable PP\n");
+ goto exit0;
+ }
+ } else if (pp_enable(1)) {
pr_debug("unable to enable PP\n");
goto exit0;
}
@@ -457,11 +463,13 @@ static int mxc_v4l2out_streamon(vout_data * vout)
return -EINVAL;
}
#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
- g_output_fb = vout->output_fb_num[vout->cur_disp_output];
- g_fb_enabled = 0;
- g_pp_ready = 0;
- fb_register_client(&fb_event_notifier);
- mx2fb_register_client(&mx2fb_event_notifier);
+ if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) {
+ g_output_fb = vout->output_fb_num[vout->cur_disp_output];
+ g_fb_enabled = 0;
+ g_pp_ready = 0;
+ fb_register_client(&fb_event_notifier);
+ mx2fb_register_client(&mx2fb_event_notifier);
+ }
#endif
vout->frame_count = 0;
vout->state = STATE_STREAM_ON;
@@ -534,11 +542,13 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
mx2_gw_set(&gwinfo);
}
#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
- g_output_fb = -1;
- g_fb_enabled = 0;
- g_pp_ready = 0;
- fb_unregister_client(&fb_event_notifier);
- mx2fb_unregister_client(&mx2fb_event_notifier);
+ if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) {
+ g_output_fb = -1;
+ g_fb_enabled = 0;
+ g_pp_ready = 0;
+ fb_unregister_client(&fb_event_notifier);
+ mx2fb_unregister_client(&mx2fb_event_notifier);
+ }
#endif
mxc_free_buffers(vout->display_bufs, vout->display_bufs_vaddr,
@@ -686,6 +696,9 @@ static int mxc_get_v42lout_control(vout_data * vout, struct v4l2_control *c)
return (vout->rotate & IPU_ROTATE_VERT_FLIP) ? 1 : 0;
case (V4L2_CID_PRIVATE_BASE + 1):
return vout->rotate;
+ case V4L2_CID_MXC_TEAR_PROTECT:
+ c->value = vout->tear_protection;
+ return 0;
default:
return -EINVAL;
}
@@ -707,6 +720,16 @@ static int mxc_set_v42lout_control(vout_data * vout, struct v4l2_control *c)
case V4L2_CID_VFLIP:
case V4L2_CID_MXC_ROT:
return 0;
+ case V4L2_CID_MXC_TEAR_PROTECT:
+#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
+ if (c->value == TEARING_PROTECTION_ACTIVE)
+ vout->tear_protection = TEARING_PROTECTION_ACTIVE;
+ else
+ vout->tear_protection = TEARING_PROTECTION_INACTIVE;;
+#else
+ vout->tear_protection = TEARING_PROTECTION_UNSUPPORTED;
+#endif
+ return 0;
default:
return -EINVAL;
}
@@ -754,6 +777,11 @@ static int mxc_v4l2out_open(struct inode *inode, struct file *file)
g_irq_cnt = g_buf_output_cnt = g_buf_q_cnt = g_buf_dq_cnt = 0;
}
+#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
+ vout->tear_protection = TEARING_PROTECTION_ACTIVE;
+#else
+ vout->tear_protection = TEARING_PROTECTION_UNSUPPORTED;
+#endif
file->private_data = dev;
up(&vout->busy_lock);
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.h b/drivers/media/video/mxc/output/mxc_v4l2_output.h
index 6fb6f5a667bb..857526b9222e 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.h
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.h
@@ -57,6 +57,15 @@ typedef enum {
} v4lout_state;
/*!
+ * States for tearing protection
+ */
+typedef enum {
+ TEARING_PROTECTION_INACTIVE,
+ TEARING_PROTECTION_ACTIVE,
+ TEARING_PROTECTION_UNSUPPORTED
+} v4l_tear_protect;
+
+/*!
* common v4l2 driver structure.
*/
typedef struct _vout_data {
@@ -71,6 +80,8 @@ typedef struct _vout_data {
*/
int open_count;
+ v4l_tear_protect tear_protection;
+
/*!
* params lock for this camera
*/