Skip to content

Commit

Permalink
Switch to imx290
Browse files Browse the repository at this point in the history
Copies exposure controls from raspberrypi/linux at
93fdf5e63517115bafb3fb3f32bdfbf56ce9202d

Signed-off-by: Ravago Jones <[email protected]>
  • Loading branch information
platipus25 committed Jan 4, 2023
1 parent 0a8f137 commit 0706faa
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 17 deletions.
6 changes: 4 additions & 2 deletions arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -509,18 +509,20 @@

camera2: camera-module@36 {
status = "okay";
compatible = "ovti,ov5647";
compatible = "sony,imx290";
reg = <0x36>;

clocks = <&cru SCLK_CIF_OUT>;
clock-names = "clk_cif_out";
clock-names = "xclk";
clock-frequency = <37125000>;
//pinctrl-names = "rockchip,camera_default";

port {
ucam_out1: endpoint {
remote-endpoint = <&mipi_in_ucam0>;
//remote-endpoint = <&isp0_mipi_in>;
data-lanes = <1 2>;
link-frequencies = /bits/ 64 <445500000 297000000>;
};
};
};
Expand Down
128 changes: 113 additions & 15 deletions drivers/media/i2c/imx290.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,15 @@
#define IMX290_BLKLEVEL_LOW 0x300a
#define IMX290_BLKLEVEL_HIGH 0x300b
#define IMX290_GAIN 0x3014
#define IMX290_VMAX_LOW 0x3018
#define IMX290_VMAX_MAX 0x3fff
#define IMX290_HMAX_LOW 0x301c
#define IMX290_HMAX_HIGH 0x301d
#define IMX290_HMAX_MAX 0xffff

#define IMX290_EXPOSURE_MIN 1
#define IMX290_EXPOSURE_STEP 1
#define IMX290_EXPOSURE_LOW 0x3020
#define IMX290_PGCTRL 0x308c
#define IMX290_PHY_LANE_NUM 0x3407
#define IMX290_CSI_LANE_MODE 0x3443
Expand All @@ -39,7 +46,7 @@
#define IMX290_PGCTRL_THRU BIT(1)
#define IMX290_PGCTRL_MODE(n) ((n) << 4)

static const char * const imx290_supply_name[] = {
static const char *const imx290_supply_name[] = {
"vdda",
"vddd",
"vdddo",
Expand All @@ -56,6 +63,7 @@ struct imx290_mode {
u32 width;
u32 height;
u32 hmax;
u32 vmax;
u8 link_freq_index;

const struct imx290_regval *data;
Expand All @@ -80,6 +88,9 @@ struct imx290 {
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *exposure;

struct mutex lock;
};
Expand All @@ -100,7 +111,7 @@ static const struct regmap_config imx290_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};

static const char * const imx290_test_pattern_menu[] = {
static const char *const imx290_test_pattern_menu[] = {
"Disabled",
"Sequence Pattern 1",
"Horizontal Color-bar Chart",
Expand Down Expand Up @@ -308,15 +319,17 @@ static const struct imx290_mode imx290_modes_2lanes[] = {
{
.width = 1920,
.height = 1080,
.hmax = 0x1130,
.hmax = 0x0898,
.vmax = 0x0465,
.link_freq_index = FREQ_INDEX_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
},
{
.width = 1280,
.height = 720,
.hmax = 0x19c8,
.hmax = 0x0ce4,
.vmax = 0x02ee,
.link_freq_index = FREQ_INDEX_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
Expand All @@ -328,6 +341,7 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
.width = 1920,
.height = 1080,
.hmax = 0x0898,
.vmax = 0x0465,
.link_freq_index = FREQ_INDEX_1080P,
.data = imx290_1080p_settings,
.data_size = ARRAY_SIZE(imx290_1080p_settings),
Expand All @@ -336,6 +350,7 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
.width = 1280,
.height = 720,
.hmax = 0x0ce4,
.vmax = 0x02ee,
.link_freq_index = FREQ_INDEX_720P,
.data = imx290_720p_settings,
.data_size = ARRAY_SIZE(imx290_720p_settings),
Expand Down Expand Up @@ -452,6 +467,51 @@ static int imx290_set_gain(struct imx290 *imx290, u32 value)
return ret;
}

static int imx290_set_exposure(struct imx290 *imx290, u32 value)
{
u32 exposure = (imx290->current_mode->height + imx290->vblank->val) -
value - 1;
int ret;

ret = imx290_write_buffered_reg(imx290, IMX290_EXPOSURE_LOW, 3,
exposure);
if (ret)
dev_err(imx290->dev, "Unable to write exposure\n");

return ret;
}

static int imx290_set_hmax(struct imx290 *imx290, u32 val)
{
u32 hmax = val + imx290->current_mode->width;
int ret;

ret = imx290_write_buffered_reg(imx290, IMX290_HMAX_LOW, 2, hmax);
if (ret)
dev_err(imx290->dev, "Error setting HMAX register\n");

return ret;
}

static int imx290_set_vmax(struct imx290 *imx290, u32 val)
{
u32 vmax = val + imx290->current_mode->height;
int ret;

ret = imx290_write_buffered_reg(imx290, IMX290_VMAX_LOW, 3, vmax);
if (ret)
dev_err(imx290->dev, "Unable to write vmax\n");

/*
* * Becuse of the way exposure works for this sensor, updating
* * vblank causes the effective exposure to change, so we must
* * set it back to the "new" correct value.
* */
imx290_set_exposure(imx290, imx290->exposure->val);

return ret;
}

/* Stop streaming */
static int imx290_stop_streaming(struct imx290 *imx290)
{
Expand All @@ -472,6 +532,19 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
struct imx290, ctrls);
int ret = 0;

if (ctrl->id == V4L2_CID_VBLANK) {
u32 vmax = ctrl->val + imx290->current_mode->height;

/*
* * Changing vblank changes the allowed range for exposure.
* * We don't supply the current exposure as default here as it
* * may lie outside the new range. We will reset it just below.
* */
__v4l2_ctrl_modify_range(imx290->exposure, IMX290_EXPOSURE_MIN,
vmax - 2, IMX290_EXPOSURE_STEP,
vmax - 2);
}

/* V4L2 controls values will be applied only when power is already up */
if (!pm_runtime_get_if_in_use(imx290->dev))
return 0;
Expand All @@ -480,6 +553,15 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_GAIN:
ret = imx290_set_gain(imx290, ctrl->val);
break;
case V4L2_CID_EXPOSURE:
ret = imx290_set_exposure(imx290, ctrl->val);
break;
case V4L2_CID_HBLANK:
ret = imx290_set_hmax(imx290, ctrl->val);
break;
case V4L2_CID_VBLANK:
ret = imx290_set_vmax(imx290, ctrl->val);
break;
case V4L2_CID_TEST_PATTERN:
if (ctrl->val) {
imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00);
Expand Down Expand Up @@ -931,9 +1013,8 @@ static int imx290_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct fwnode_handle *endpoint;
/* Only CSI2 is supported for now: */
struct v4l2_fwnode_endpoint ep = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
const struct imx290_mode *mode;
struct imx290 *imx290;
u32 xclk_freq;
s64 fq;
Expand Down Expand Up @@ -1044,14 +1125,31 @@ static int imx290_probe(struct i2c_client *client)

v4l2_ctrl_handler_init(&imx290->ctrls, 4);

v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_GAIN, 0, 72, 1, 0);

imx290->link_freq =
v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_LINK_FREQ,
imx290_link_freqs_num(imx290) - 1, 0,
imx290_link_freqs_ptr(imx290));
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_GAIN, 0,
72, 1, 0);

mode = imx290->current_mode;
imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_HBLANK,
mode->hmax - mode->width,
IMX290_HMAX_MAX - mode->width, 1,
mode->hmax - mode->width);

imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_VBLANK,
mode->vmax - mode->height,
IMX290_VMAX_MAX - mode->height, 1,
mode->vmax - mode->height);

imx290->exposure = v4l2_ctrl_new_std(
&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_EXPOSURE,
IMX290_EXPOSURE_MIN, mode->vmax - 2, IMX290_EXPOSURE_STEP,
mode->vmax - 2);

imx290->link_freq = v4l2_ctrl_new_int_menu(
&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_LINK_FREQ,
imx290_link_freqs_num(imx290) - 1, 0,
imx290_link_freqs_ptr(imx290));
if (imx290->link_freq)
imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;

Expand Down

0 comments on commit 0706faa

Please sign in to comment.