summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/imx219.c
diff options
context:
space:
mode:
authorJacob Chen <jacob2.chen@rock-chips.com>2017-11-20 09:51:13 +0800
committerTao Huang <huangtao@rock-chips.com>2017-11-28 14:30:07 +0800
commitc10f2c465a24693068286cb8f67f4ec453d58527 (patch)
treec8e1ebabeaae86829356b3a5a483760c5f1f9972 /drivers/media/i2c/imx219.c
parent76a28bb1b9cb0566e1523a79daa69b0a7f574796 (diff)
media: i2c: imx219: add some controls for 3A
Change-Id: I2157b98f9c00e303dd50470247ca794381db727e Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
Diffstat (limited to 'drivers/media/i2c/imx219.c')
-rw-r--r--drivers/media/i2c/imx219.c106
1 files changed, 52 insertions, 54 deletions
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 4990efc148d5..d03b086dbe34 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -21,19 +21,32 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-mediabus.h>
-#include <media/v4l2-of.h>
/* IMX219 supported geometry */
-#define IMX219_WIDTH 3280 //3280
+#define IMX219_WIDTH 3280
#define IMX219_HEIGHT 2464
+#define IMX219_HTS 3448
+#define IMX219_VTS 2500
+
#define IMX219_TABLE_END 0xffff
#define IMX219_ANALOGUE_GAIN_MULTIPLIER 256
#define IMX219_ANALOGUE_GAIN_MIN (1 * IMX219_ANALOGUE_GAIN_MULTIPLIER)
#define IMX219_ANALOGUE_GAIN_MAX (8 * IMX219_ANALOGUE_GAIN_MULTIPLIER)
+
/* In dB*256 */
#define IMX219_DIGITAL_GAIN_MIN 256
#define IMX219_DIGITAL_GAIN_MAX 4095
+#define IMX219_DIGITAL_EXPOSURE_MIN 0
+#define IMX219_DIGITAL_EXPOSURE_MAX 4095
+
+#define IMX219_LANES 2
+#define IMX219_BITS_PER_SAMPLE 10
+
+static const s64 link_freq_menu_items[] = {
+ 456000000,
+};
+
struct imx219_reg {
u16 addr;
u8 val;
@@ -143,6 +156,7 @@ struct imx219 {
int vflip;
u8 analogue_gain;
u16 digital_gain; /* bits 11:0 */
+ u16 exposure_time;
u16 test_pattern;
u16 test_pattern_solid_color_r;
u16 test_pattern_solid_color_gr;
@@ -287,6 +301,12 @@ static int imx219_s_stream(struct v4l2_subdev *sd, int enable)
if (ret)
return ret;
+ /* Handle exposure time */
+ ret = reg_write(client, 0x015a, priv->exposure_time >> 8);
+ ret |= reg_write(client, 0x015b, priv->exposure_time & 0xff);
+ if (ret)
+ return ret;
+
/* Handle test pattern */
if (priv->test_pattern) {
ret = reg_write(client, 0x0600, priv->test_pattern >> 8);
@@ -326,54 +346,6 @@ static int imx219_s_stream(struct v4l2_subdev *sd, int enable)
return reg_write_table(client, start);
}
-static int imx219_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *crop)
-{
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- crop->bounds.left = 0;
- crop->bounds.top = 0;
- crop->bounds.width = IMX219_WIDTH;
- crop->bounds.height = IMX219_HEIGHT;
- crop->defrect = crop->bounds;
- crop->pixelaspect.numerator = 1;
- crop->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int imx219_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct imx219 *priv = to_imx219(client);
-
- crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- crop->c = priv->crop_rect;
-
- return 0;
-}
-
-static int imx219_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *crop)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct imx219 *priv = to_imx219(client);
- struct v4l2_rect rect = crop->c;
- u8 reg;
-
- rect.left = ALIGN(rect.left, 2);
- rect.width = ALIGN(rect.width, 2);
- rect.top = ALIGN(rect.top, 2);
- rect.height = ALIGN(rect.height, 2);
- priv->crop_rect = rect;
-
- /* If enabled, apply settings immediately */
- reg = reg_read(client, 0x0100);
- if ((reg & 0x1f) == 0x01)
- imx219_s_stream(sd, 1);
-
- return 0;
-}
-
static int imx219_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
u32 *code)
{
@@ -558,6 +530,9 @@ static int imx219_s_ctrl(struct v4l2_ctrl *ctrl)
*/
priv->digital_gain = ctrl->val;
break;
+ case V4L2_CID_EXPOSURE:
+ priv->exposure_time = ctrl->val;
+ break;
case V4L2_CID_TEST_PATTERN:
return imx219_s_ctrl_test_pattern(ctrl);
default:
@@ -598,9 +573,6 @@ static int imx219_get_fmt(struct v4l2_subdev *sd,
/* Various V4L2 operations tables */
static struct v4l2_subdev_video_ops imx219_subdev_video_ops = {
.s_stream = imx219_s_stream,
- .cropcap = imx219_cropcap,
- .g_crop = imx219_g_crop,
- .s_crop = imx219_s_crop,
};
static struct v4l2_subdev_core_ops imx219_subdev_core_ops = {
@@ -703,6 +675,7 @@ static int imx219_ctrls_init(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct imx219 *priv = to_imx219(client);
+ u32 pixel_rate, h_blank, v_blank;
int ret;
v4l2_ctrl_handler_init(&priv->ctrl_handler, 10);
@@ -710,6 +683,8 @@ static int imx219_ctrls_init(struct v4l2_subdev *sd)
V4L2_CID_HFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&priv->ctrl_handler, &imx219_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ /* exposure */
v4l2_ctrl_new_std(&priv->ctrl_handler, &imx219_ctrl_ops,
V4L2_CID_ANALOGUE_GAIN,
IMX219_ANALOGUE_GAIN_MIN,
@@ -718,7 +693,30 @@ static int imx219_ctrls_init(struct v4l2_subdev *sd)
v4l2_ctrl_new_std(&priv->ctrl_handler, &imx219_ctrl_ops,
V4L2_CID_GAIN,
IMX219_DIGITAL_GAIN_MIN,
- IMX219_DIGITAL_GAIN_MAX, 1, IMX219_DIGITAL_GAIN_MIN);
+ IMX219_DIGITAL_GAIN_MAX, 1,
+ IMX219_DIGITAL_GAIN_MIN);
+ v4l2_ctrl_new_std(&priv->ctrl_handler, &imx219_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX219_DIGITAL_EXPOSURE_MIN,
+ IMX219_DIGITAL_EXPOSURE_MAX, 1,
+ IMX219_DIGITAL_EXPOSURE_MIN);
+
+ /* blank */
+ h_blank = IMX219_HTS - IMX219_WIDTH;
+ v4l2_ctrl_new_std(&priv->ctrl_handler, NULL, V4L2_CID_HBLANK,
+ h_blank, h_blank, 1, h_blank);
+ v_blank = IMX219_VTS - IMX219_HEIGHT;
+ v4l2_ctrl_new_std(&priv->ctrl_handler, NULL, V4L2_CID_VBLANK,
+ v_blank, v_blank, 1, v_blank);
+
+ /* freq */
+ v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, link_freq_menu_items);
+ pixel_rate = (link_freq_menu_items[0] * 2 * IMX219_LANES) /
+ IMX219_BITS_PER_SAMPLE;
+ v4l2_ctrl_new_std(&priv->ctrl_handler, NULL, V4L2_CID_PIXEL_RATE,
+ 0, pixel_rate, 1, pixel_rate);
+
v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, &imx219_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(tp_qmenu) - 1, 0, 0, tp_qmenu);