diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.15/950-0414-media-i2c-imx477-Extend-driver-to-support-imx378-sen.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.15/950-0414-media-i2c-imx477-Extend-driver-to-support-imx378-sen.patch | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.15/950-0414-media-i2c-imx477-Extend-driver-to-support-imx378-sen.patch b/target/linux/bcm27xx/patches-5.15/950-0414-media-i2c-imx477-Extend-driver-to-support-imx378-sen.patch new file mode 100644 index 0000000000..3cd1ff6b1e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.15/950-0414-media-i2c-imx477-Extend-driver-to-support-imx378-sen.patch @@ -0,0 +1,190 @@ +From 99a58cae54a24652ab2e088d0eec2a1a31b22d86 Mon Sep 17 00:00:00 2001 +From: David Plowman <david.plowman@raspberrypi.com> +Date: Tue, 29 Jun 2021 14:43:01 +0100 +Subject: [PATCH] media: i2c: imx477: Extend driver to support imx378 + sensor + +The imx378 sensor is almost identical to the imx477 and can be +supported as a "compatible" sensor with just a few extra register +writes. + +Signed-off-by: David Plowman <david.plowman@raspberrypi.com> +--- + drivers/media/i2c/Kconfig | 2 +- + drivers/media/i2c/imx477.c | 68 +++++++++++++++++++++++++++++++++----- + 2 files changed, 60 insertions(+), 10 deletions(-) + +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -823,7 +823,7 @@ config VIDEO_IMX477 + depends on MEDIA_CAMERA_SUPPORT + help + This is a Video4Linux2 sensor driver for the Sony +- IMX477 camera. ++ IMX477 camera. Also supports the Sony IMX378. + + To compile this driver as a module, choose M here: the + module will be called imx477. +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -12,6 +12,7 @@ + #include <linux/gpio/consumer.h> + #include <linux/i2c.h> + #include <linux/module.h> ++#include <linux/of_device.h> + #include <linux/pm_runtime.h> + #include <linux/regulator/consumer.h> + #include <media/v4l2-ctrls.h> +@@ -26,6 +27,7 @@ + /* Chip ID */ + #define IMX477_REG_CHIP_ID 0x0016 + #define IMX477_CHIP_ID 0x0477 ++#define IMX378_CHIP_ID 0x0378 + + #define IMX477_REG_MODE_SELECT 0x0100 + #define IMX477_MODE_STANDBY 0x00 +@@ -1069,6 +1071,11 @@ static const char * const imx477_supply_ + #define IMX477_XCLR_MIN_DELAY_US 8000 + #define IMX477_XCLR_DELAY_RANGE_US 1000 + ++struct imx477_compatible_data { ++ unsigned int chip_id; ++ struct imx477_reg_list extra_regs; ++}; ++ + struct imx477 { + struct v4l2_subdev sd; + struct media_pad pad[NUM_PADS]; +@@ -1107,6 +1114,9 @@ struct imx477 { + + /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */ + unsigned int long_exp_shift; ++ ++ /* Any extra information related to different compatible sensors */ ++ const struct imx477_compatible_data *compatible_data; + }; + + static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd) +@@ -1673,11 +1683,18 @@ static int imx477_start_streaming(struct + { + struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd); + const struct imx477_reg_list *reg_list; ++ const struct imx477_reg_list *extra_regs; + int ret; + + if (!imx477->common_regs_written) { + ret = imx477_write_regs(imx477, mode_common_regs, + ARRAY_SIZE(mode_common_regs)); ++ if (!ret) { ++ extra_regs = &imx477->compatible_data->extra_regs; ++ ret = imx477_write_regs(imx477, extra_regs->regs, ++ extra_regs->num_of_regs); ++ } ++ + if (ret) { + dev_err(&client->dev, "%s failed to set common settings\n", + __func__); +@@ -1863,7 +1880,7 @@ static int imx477_get_regulators(struct + } + + /* Verify chip ID */ +-static int imx477_identify_module(struct imx477 *imx477) ++static int imx477_identify_module(struct imx477 *imx477, u32 expected_id) + { + struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd); + int ret; +@@ -1873,16 +1890,18 @@ static int imx477_identify_module(struct + IMX477_REG_VALUE_16BIT, &val); + if (ret) { + dev_err(&client->dev, "failed to read chip id %x, with error %d\n", +- IMX477_CHIP_ID, ret); ++ expected_id, ret); + return ret; + } + +- if (val != IMX477_CHIP_ID) { ++ if (val != expected_id) { + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", +- IMX477_CHIP_ID, val); ++ expected_id, val); + return -EIO; + } + ++ dev_info(&client->dev, "Device found is imx%x\n", val); ++ + return 0; + } + +@@ -2078,10 +2097,39 @@ error_out: + return ret; + } + ++static const struct imx477_compatible_data imx477_compatible = { ++ .chip_id = IMX477_CHIP_ID, ++ .extra_regs = { ++ .num_of_regs = 0, ++ .regs = NULL ++ } ++}; ++ ++static const struct imx477_reg imx378_regs[] = { ++ {0x3e35, 0x01}, ++ {0x4421, 0x08}, ++ {0x3ff9, 0x00}, ++}; ++ ++static const struct imx477_compatible_data imx378_compatible = { ++ .chip_id = IMX378_CHIP_ID, ++ .extra_regs = { ++ .num_of_regs = ARRAY_SIZE(imx378_regs), ++ .regs = imx378_regs ++ } ++}; ++ ++static const struct of_device_id imx477_dt_ids[] = { ++ { .compatible = "sony,imx477", .data = &imx477_compatible }, ++ { .compatible = "sony,imx378", .data = &imx378_compatible }, ++ { /* sentinel */ } ++}; ++ + static int imx477_probe(struct i2c_client *client) + { + struct device *dev = &client->dev; + struct imx477 *imx477; ++ const struct of_device_id *match; + int ret; + + imx477 = devm_kzalloc(&client->dev, sizeof(*imx477), GFP_KERNEL); +@@ -2090,6 +2138,12 @@ static int imx477_probe(struct i2c_clien + + v4l2_i2c_subdev_init(&imx477->sd, client, &imx477_subdev_ops); + ++ match = of_match_device(imx477_dt_ids, dev); ++ if (!match) ++ return -ENODEV; ++ imx477->compatible_data = ++ (const struct imx477_compatible_data *)match->data; ++ + /* Check the hardware configuration in device tree */ + if (imx477_check_hwcfg(dev)) + return -EINVAL; +@@ -2126,7 +2180,7 @@ static int imx477_probe(struct i2c_clien + if (ret) + return ret; + +- ret = imx477_identify_module(imx477); ++ ret = imx477_identify_module(imx477, imx477->compatible_data->chip_id); + if (ret) + goto error_power_off; + +@@ -2198,10 +2252,6 @@ static int imx477_remove(struct i2c_clie + return 0; + } + +-static const struct of_device_id imx477_dt_ids[] = { +- { .compatible = "sony,imx477" }, +- { /* sentinel */ } +-}; + MODULE_DEVICE_TABLE(of, imx477_dt_ids); + + static const struct dev_pm_ops imx477_pm_ops = { |