Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imx290 HCG and analogue gain updates #5859

Open
wants to merge 5 commits into
base: rpi-6.6.y
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ properties:
- sony,imx290lqr # Colour
- sony,imx290llr # Monochrome
- sony,imx327lqr # Colour
- sony,imx462lqr # Colour
- sony,imx462llr # Monochrome
- const: sony,imx290
deprecated: true

Expand Down
10 changes: 3 additions & 7 deletions arch/arm/boot/dts/overlays/imx462-overlay.dts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Definitions for IMX462 camera module on VC I2C bus

// IMX462 is the successor to IMX290. The drivers currently don't support
// any additional feature of IMX462, so use the IMX290 compatible strings
// for now.
// IMX462 is the successor to IMX290.

/dts-v1/;
/plugin/;
Expand All @@ -17,19 +15,17 @@
// Fragment numbers deliberately high to avoid conflicts with the
// included imx290_327 overlay file.

//IMX462 is not defined in the bindings, so use IMX290 for now.

fragment@101 {
target = <&cam_node>;
__overlay__ {
compatible = "sony,imx290lqr";
compatible = "sony,imx462lqr";
};
};

fragment@102 {
target = <&cam_node>;
__dormant__ {
compatible = "sony,imx290llr";
compatible = "sony,imx462llr";
};
};

Expand Down
89 changes: 82 additions & 7 deletions drivers/media/i2c/imx290.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
Expand Down Expand Up @@ -41,6 +42,9 @@
#define IMX290_WINMODE_720P (1 << 4)
#define IMX290_WINMODE_CROP (4 << 4)
#define IMX290_FR_FDG_SEL CCI_REG8(0x3009)
#define IMX290_FDG_HCG BIT(4)
#define IMX290_FRSEL_60FPS BIT(0)
#define IMX290_FDG_LCG 0
#define IMX290_BLKLEVEL CCI_REG16_LE(0x300a)
#define IMX290_GAIN CCI_REG8(0x3014)
#define IMX290_VMAX CCI_REG24_LE(0x3018)
Expand Down Expand Up @@ -162,6 +166,10 @@

#define IMX290_NUM_SUPPLIES 3

static bool hcg_mode;
module_param(hcg_mode, bool, 0664);
MODULE_PARM_DESC(hcg_mode, "Enable HCG mode");

enum imx290_colour_variant {
IMX290_VARIANT_COLOUR,
IMX290_VARIANT_MONO,
Expand All @@ -172,12 +180,15 @@ enum imx290_model {
IMX290_MODEL_IMX290LQR,
IMX290_MODEL_IMX290LLR,
IMX290_MODEL_IMX327LQR,
IMX290_MODEL_IMX462LQR,
IMX290_MODEL_IMX462LLR,
};

struct imx290_model_info {
enum imx290_colour_variant colour_variant;
const struct cci_reg_sequence *init_regs;
size_t init_regs_num;
unsigned int max_analog_gain;
const char *name;
};

Expand Down Expand Up @@ -317,6 +328,50 @@ static const struct cci_reg_sequence imx290_global_init_settings_290[] = {
{ CCI_REG8(0x33b3), 0x04 },
};

static const struct cci_reg_sequence imx290_global_init_settings_462[] = {
{ CCI_REG8(0x300f), 0x00 },
{ CCI_REG8(0x3010), 0x21 },
{ CCI_REG8(0x3011), 0x02 },
{ CCI_REG8(0x3016), 0x09 },
{ CCI_REG8(0x3070), 0x02 },
{ CCI_REG8(0x3071), 0x11 },
{ CCI_REG8(0x309b), 0x10 },
{ CCI_REG8(0x309c), 0x22 },
{ CCI_REG8(0x30a2), 0x02 },
{ CCI_REG8(0x30a6), 0x20 },
{ CCI_REG8(0x30a8), 0x20 },
{ CCI_REG8(0x30aa), 0x20 },
{ CCI_REG8(0x30ac), 0x20 },
{ CCI_REG8(0x30b0), 0x43 },
{ CCI_REG8(0x3119), 0x9e },
{ CCI_REG8(0x311c), 0x1e },
{ CCI_REG8(0x311e), 0x08 },
{ CCI_REG8(0x3128), 0x05 },
{ CCI_REG8(0x313d), 0x83 },
{ CCI_REG8(0x3150), 0x03 },
{ CCI_REG8(0x317e), 0x00 },
{ CCI_REG8(0x32b8), 0x50 },
{ CCI_REG8(0x32b9), 0x10 },
{ CCI_REG8(0x32ba), 0x00 },
{ CCI_REG8(0x32bb), 0x04 },
{ CCI_REG8(0x32c8), 0x50 },
{ CCI_REG8(0x32c9), 0x10 },
{ CCI_REG8(0x32ca), 0x00 },
{ CCI_REG8(0x32cb), 0x04 },
{ CCI_REG8(0x332c), 0xd3 },
{ CCI_REG8(0x332d), 0x10 },
{ CCI_REG8(0x332e), 0x0d },
{ CCI_REG8(0x3358), 0x06 },
{ CCI_REG8(0x3359), 0xe1 },
{ CCI_REG8(0x335a), 0x11 },
{ CCI_REG8(0x3360), 0x1e },
{ CCI_REG8(0x3361), 0x61 },
{ CCI_REG8(0x3362), 0x10 },
{ CCI_REG8(0x33b0), 0x50 },
{ CCI_REG8(0x33b2), 0x1a },
{ CCI_REG8(0x33b3), 0x04 },
};

#define IMX290_NUM_CLK_REGS 2
static const struct cci_reg_sequence xclk_regs[][IMX290_NUM_CLK_REGS] = {
[IMX290_CLK_37_125] = {
Expand Down Expand Up @@ -649,7 +704,8 @@ static int imx290_set_data_lanes(struct imx290 *imx290)
&ret);
cci_write(imx290->regmap, IMX290_CSI_LANE_MODE, imx290->nlanes - 1,
&ret);
cci_write(imx290->regmap, IMX290_FR_FDG_SEL, 0x01, &ret);
cci_write(imx290->regmap, IMX290_FR_FDG_SEL, IMX290_FRSEL_60FPS |
(hcg_mode ? IMX290_FDG_HCG : IMX290_FDG_LCG), &ret);

return ret;
}
Expand Down Expand Up @@ -878,14 +934,10 @@ static int imx290_ctrl_init(struct imx290 *imx290)
* up to 72.0dB (240) add further digital gain. Limit the range to
* analog gain only, support for digital gain can be added separately
* if needed.
*
* The IMX327 and IMX462 are largely compatible with the IMX290, but
* have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
* gain. When support for those sensors gets added to the driver, the
* gain control should be adjusted accordingly.
*/
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
V4L2_CID_ANALOGUE_GAIN, 0,
imx290->model->max_analog_gain, 1, 0);

/*
* Correct range will be determined through imx290_ctrl_update setting
Expand Down Expand Up @@ -1436,20 +1488,37 @@ static const struct imx290_model_info imx290_models[] = {
.colour_variant = IMX290_VARIANT_COLOUR,
.init_regs = imx290_global_init_settings_290,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290),
.max_analog_gain = 100,
.name = "imx290",
},
[IMX290_MODEL_IMX290LLR] = {
.colour_variant = IMX290_VARIANT_MONO,
.init_regs = imx290_global_init_settings_290,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290),
.max_analog_gain = 100,
.name = "imx290",
},
[IMX290_MODEL_IMX327LQR] = {
.colour_variant = IMX290_VARIANT_COLOUR,
.init_regs = imx290_global_init_settings_327,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_327),
.max_analog_gain = 98,
.name = "imx327",
},
[IMX290_MODEL_IMX462LQR] = {
.colour_variant = IMX290_VARIANT_COLOUR,
.init_regs = imx290_global_init_settings_462,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_462),
.max_analog_gain = 98,
.name = "imx462",
},
[IMX290_MODEL_IMX462LLR] = {
.colour_variant = IMX290_VARIANT_MONO,
.init_regs = imx290_global_init_settings_462,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_462),
.max_analog_gain = 98,
.name = "imx462",
},
};

static int imx290_parse_dt(struct imx290 *imx290)
Expand Down Expand Up @@ -1645,6 +1714,12 @@ static const struct of_device_id imx290_of_match[] = {
}, {
.compatible = "sony,imx327lqr",
.data = &imx290_models[IMX290_MODEL_IMX327LQR],
}, {
.compatible = "sony,imx462lqr",
.data = &imx290_models[IMX290_MODEL_IMX462LQR],
}, {
.compatible = "sony,imx462llr",
.data = &imx290_models[IMX290_MODEL_IMX462LLR],
},
{ /* sentinel */ },
};
Expand Down