3cd1ff6b1ebc7f73101b4428540599494f9815bd
[openwrt/staging/rmilecki.git] /
1 From 99a58cae54a24652ab2e088d0eec2a1a31b22d86 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
5 sensor
6
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
9 writes.
10
11 Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
12 ---
13 drivers/media/i2c/Kconfig | 2 +-
14 drivers/media/i2c/imx477.c | 68 +++++++++++++++++++++++++++++++++-----
15 2 files changed, 60 insertions(+), 10 deletions(-)
16
17 --- a/drivers/media/i2c/Kconfig
18 +++ b/drivers/media/i2c/Kconfig
19 @@ -823,7 +823,7 @@ config VIDEO_IMX477
20 depends on MEDIA_CAMERA_SUPPORT
21 help
22 This is a Video4Linux2 sensor driver for the Sony
23 - IMX477 camera.
24 + IMX477 camera. Also supports the Sony IMX378.
25
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
30 @@ -12,6 +12,7 @@
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>
38 @@ -26,6 +27,7 @@
39 /* Chip ID */
40 #define IMX477_REG_CHIP_ID 0x0016
41 #define IMX477_CHIP_ID 0x0477
42 +#define IMX378_CHIP_ID 0x0378
43
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
49
50 +struct imx477_compatible_data {
51 + unsigned int chip_id;
52 + struct imx477_reg_list extra_regs;
53 +};
54 +
55 struct imx477 {
56 struct v4l2_subdev sd;
57 struct media_pad pad[NUM_PADS];
58 @@ -1107,6 +1114,9 @@ struct imx477 {
59
60 /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
61 unsigned int long_exp_shift;
62 +
63 + /* Any extra information related to different compatible sensors */
64 + const struct imx477_compatible_data *compatible_data;
65 };
66
67 static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd)
68 @@ -1673,11 +1683,18 @@ static int imx477_start_streaming(struct
69 {
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;
73 int ret;
74
75 if (!imx477->common_regs_written) {
76 ret = imx477_write_regs(imx477, mode_common_regs,
77 ARRAY_SIZE(mode_common_regs));
78 + if (!ret) {
79 + extra_regs = &imx477->compatible_data->extra_regs;
80 + ret = imx477_write_regs(imx477, extra_regs->regs,
81 + extra_regs->num_of_regs);
82 + }
83 +
84 if (ret) {
85 dev_err(&client->dev, "%s failed to set common settings\n",
86 __func__);
87 @@ -1863,7 +1880,7 @@ static int imx477_get_regulators(struct
88 }
89
90 /* Verify chip ID */
91 -static int imx477_identify_module(struct imx477 *imx477)
92 +static int imx477_identify_module(struct imx477 *imx477, u32 expected_id)
93 {
94 struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
95 int ret;
96 @@ -1873,16 +1890,18 @@ static int imx477_identify_module(struct
97 IMX477_REG_VALUE_16BIT, &val);
98 if (ret) {
99 dev_err(&client->dev, "failed to read chip id %x, with error %d\n",
100 - IMX477_CHIP_ID, ret);
101 + expected_id, ret);
102 return ret;
103 }
104
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);
109 + expected_id, val);
110 return -EIO;
111 }
112
113 + dev_info(&client->dev, "Device found is imx%x\n", val);
114 +
115 return 0;
116 }
117
118 @@ -2078,10 +2097,39 @@ error_out:
119 return ret;
120 }
121
122 +static const struct imx477_compatible_data imx477_compatible = {
123 + .chip_id = IMX477_CHIP_ID,
124 + .extra_regs = {
125 + .num_of_regs = 0,
126 + .regs = NULL
127 + }
128 +};
129 +
130 +static const struct imx477_reg imx378_regs[] = {
131 + {0x3e35, 0x01},
132 + {0x4421, 0x08},
133 + {0x3ff9, 0x00},
134 +};
135 +
136 +static const struct imx477_compatible_data imx378_compatible = {
137 + .chip_id = IMX378_CHIP_ID,
138 + .extra_regs = {
139 + .num_of_regs = ARRAY_SIZE(imx378_regs),
140 + .regs = imx378_regs
141 + }
142 +};
143 +
144 +static const struct of_device_id imx477_dt_ids[] = {
145 + { .compatible = "sony,imx477", .data = &imx477_compatible },
146 + { .compatible = "sony,imx378", .data = &imx378_compatible },
147 + { /* sentinel */ }
148 +};
149 +
150 static int imx477_probe(struct i2c_client *client)
151 {
152 struct device *dev = &client->dev;
153 struct imx477 *imx477;
154 + const struct of_device_id *match;
155 int ret;
156
157 imx477 = devm_kzalloc(&client->dev, sizeof(*imx477), GFP_KERNEL);
158 @@ -2090,6 +2138,12 @@ static int imx477_probe(struct i2c_clien
159
160 v4l2_i2c_subdev_init(&imx477->sd, client, &imx477_subdev_ops);
161
162 + match = of_match_device(imx477_dt_ids, dev);
163 + if (!match)
164 + return -ENODEV;
165 + imx477->compatible_data =
166 + (const struct imx477_compatible_data *)match->data;
167 +
168 /* Check the hardware configuration in device tree */
169 if (imx477_check_hwcfg(dev))
170 return -EINVAL;
171 @@ -2126,7 +2180,7 @@ static int imx477_probe(struct i2c_clien
172 if (ret)
173 return ret;
174
175 - ret = imx477_identify_module(imx477);
176 + ret = imx477_identify_module(imx477, imx477->compatible_data->chip_id);
177 if (ret)
178 goto error_power_off;
179
180 @@ -2198,10 +2252,6 @@ static int imx477_remove(struct i2c_clie
181 return 0;
182 }
183
184 -static const struct of_device_id imx477_dt_ids[] = {
185 - { .compatible = "sony,imx477" },
186 - { /* sentinel */ }
187 -};
188 MODULE_DEVICE_TABLE(of, imx477_dt_ids);
189
190 static const struct dev_pm_ops imx477_pm_ops = {