1 From c298f9514f99b9dfde64bb5f07fe09ee8dfdcd48 Mon Sep 17 00:00:00 2001
2 From: David Plowman <david.plowman@raspberrypi.com>
3 Date: Tue, 29 Jun 2021 14:43:01 +0100
4 Subject: [PATCH] media: i2c: imx477: Extend driver to support imx378
7 The imx378 sensor is almost identical to the imx477 and can be
8 supported as a "compatible" sensor with just a few extra register
11 Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
13 drivers/media/i2c/Kconfig | 2 +-
14 drivers/media/i2c/imx477.c | 68 +++++++++++++++++++++++++++++++++-----
15 2 files changed, 60 insertions(+), 10 deletions(-)
17 --- a/drivers/media/i2c/Kconfig
18 +++ b/drivers/media/i2c/Kconfig
19 @@ -807,7 +807,7 @@ config VIDEO_IMX477
20 depends on MEDIA_CAMERA_SUPPORT
22 This is a Video4Linux2 sensor driver for the Sony
24 + IMX477 camera. Also supports the Sony IMX378.
26 To compile this driver as a module, choose M here: the
27 module will be called imx477.
28 --- a/drivers/media/i2c/imx477.c
29 +++ b/drivers/media/i2c/imx477.c
31 #include <linux/gpio/consumer.h>
32 #include <linux/i2c.h>
33 #include <linux/module.h>
34 +#include <linux/of_device.h>
35 #include <linux/pm_runtime.h>
36 #include <linux/regulator/consumer.h>
37 #include <media/v4l2-ctrls.h>
40 #define IMX477_REG_CHIP_ID 0x0016
41 #define IMX477_CHIP_ID 0x0477
42 +#define IMX378_CHIP_ID 0x0378
44 #define IMX477_REG_MODE_SELECT 0x0100
45 #define IMX477_MODE_STANDBY 0x00
46 @@ -1069,6 +1071,11 @@ static const char * const imx477_supply_
47 #define IMX477_XCLR_MIN_DELAY_US 8000
48 #define IMX477_XCLR_DELAY_RANGE_US 1000
50 +struct imx477_compatible_data {
51 + unsigned int chip_id;
52 + struct imx477_reg_list extra_regs;
56 struct v4l2_subdev sd;
57 struct media_pad pad[NUM_PADS];
58 @@ -1107,6 +1114,9 @@ struct imx477 {
60 /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
61 unsigned int long_exp_shift;
63 + /* Any extra information related to different compatible sensors */
64 + const struct imx477_compatible_data *compatible_data;
67 static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd)
68 @@ -1673,11 +1683,18 @@ static int imx477_start_streaming(struct
70 struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
71 const struct imx477_reg_list *reg_list;
72 + const struct imx477_reg_list *extra_regs;
75 if (!imx477->common_regs_written) {
76 ret = imx477_write_regs(imx477, mode_common_regs,
77 ARRAY_SIZE(mode_common_regs));
79 + extra_regs = &imx477->compatible_data->extra_regs;
80 + ret = imx477_write_regs(imx477, extra_regs->regs,
81 + extra_regs->num_of_regs);
85 dev_err(&client->dev, "%s failed to set common settings\n",
87 @@ -1863,7 +1880,7 @@ static int imx477_get_regulators(struct
91 -static int imx477_identify_module(struct imx477 *imx477)
92 +static int imx477_identify_module(struct imx477 *imx477, u32 expected_id)
94 struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
96 @@ -1873,16 +1890,18 @@ static int imx477_identify_module(struct
97 IMX477_REG_VALUE_16BIT, &val);
99 dev_err(&client->dev, "failed to read chip id %x, with error %d\n",
100 - IMX477_CHIP_ID, ret);
105 - if (val != IMX477_CHIP_ID) {
106 + if (val != expected_id) {
107 dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
108 - IMX477_CHIP_ID, val);
113 + dev_info(&client->dev, "Device found is imx%x\n", val);
118 @@ -2078,10 +2097,39 @@ error_out:
122 +static const struct imx477_compatible_data imx477_compatible = {
123 + .chip_id = IMX477_CHIP_ID,
130 +static const struct imx477_reg imx378_regs[] = {
136 +static const struct imx477_compatible_data imx378_compatible = {
137 + .chip_id = IMX378_CHIP_ID,
139 + .num_of_regs = ARRAY_SIZE(imx378_regs),
140 + .regs = imx378_regs
144 +static const struct of_device_id imx477_dt_ids[] = {
145 + { .compatible = "sony,imx477", .data = &imx477_compatible },
146 + { .compatible = "sony,imx378", .data = &imx378_compatible },
150 static int imx477_probe(struct i2c_client *client)
152 struct device *dev = &client->dev;
153 struct imx477 *imx477;
154 + const struct of_device_id *match;
157 imx477 = devm_kzalloc(&client->dev, sizeof(*imx477), GFP_KERNEL);
158 @@ -2090,6 +2138,12 @@ static int imx477_probe(struct i2c_clien
160 v4l2_i2c_subdev_init(&imx477->sd, client, &imx477_subdev_ops);
162 + match = of_match_device(imx477_dt_ids, dev);
165 + imx477->compatible_data =
166 + (const struct imx477_compatible_data *)match->data;
168 /* Check the hardware configuration in device tree */
169 if (imx477_check_hwcfg(dev))
171 @@ -2126,7 +2180,7 @@ static int imx477_probe(struct i2c_clien
175 - ret = imx477_identify_module(imx477);
176 + ret = imx477_identify_module(imx477, imx477->compatible_data->chip_id);
178 goto error_power_off;
180 @@ -2198,10 +2252,6 @@ static int imx477_remove(struct i2c_clie
184 -static const struct of_device_id imx477_dt_ids[] = {
185 - { .compatible = "sony,imx477" },
188 MODULE_DEVICE_TABLE(of, imx477_dt_ids);
190 static const struct dev_pm_ops imx477_pm_ops = {