1 From d0cc0819d6750d39624741d9091ab3f73836f11b Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Thu, 16 Feb 2023 00:29:50 +0200
4 Subject: [PATCH] media: i2c: imx290: Add support for the mono sensor
7 Should be upstream commit 9bf52c7136d1
9 The IMX290 module is available as either mono or colour (Bayer).
11 Update the driver so that it can advertise the correct mono
12 formats instead of the colour ones.
14 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
15 Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
16 Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
17 Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
18 Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
20 drivers/media/i2c/imx290.c | 75 +++++++++++++++++++++++++++++++-------
21 1 file changed, 61 insertions(+), 14 deletions(-)
23 --- a/drivers/media/i2c/imx290.c
24 +++ b/drivers/media/i2c/imx290.c
26 #include <linux/gpio/consumer.h>
27 #include <linux/i2c.h>
28 #include <linux/module.h>
29 +#include <linux/of_device.h>
30 #include <linux/pm_runtime.h>
31 #include <linux/regmap.h>
32 #include <linux/regulator/consumer.h>
35 #define IMX290_NUM_SUPPLIES 3
37 +enum imx290_colour_variant {
38 + IMX290_VARIANT_COLOUR,
39 + IMX290_VARIANT_MONO,
44 + IMX290_MODEL_IMX290LQR,
45 + IMX290_MODEL_IMX290LLR,
48 +struct imx290_model_info {
49 + enum imx290_colour_variant colour_variant;
52 struct imx290_regval {
55 @@ -180,6 +196,7 @@ struct imx290 {
57 struct regmap *regmap;
59 + const struct imx290_model_info *model;
61 struct v4l2_subdev sd;
63 @@ -417,7 +434,7 @@ static inline int imx290_modes_num(const
66 struct imx290_format_info {
68 + u32 code[IMX290_VARIANT_MAX];
70 const struct imx290_regval *regs;
71 unsigned int num_regs;
72 @@ -425,26 +442,33 @@ struct imx290_format_info {
74 static const struct imx290_format_info imx290_formats[] = {
76 - .code = MEDIA_BUS_FMT_SRGGB10_1X10,
78 + [IMX290_VARIANT_COLOUR] = MEDIA_BUS_FMT_SRGGB10_1X10,
79 + [IMX290_VARIANT_MONO] = MEDIA_BUS_FMT_Y10_1X10
82 .regs = imx290_10bit_settings,
83 .num_regs = ARRAY_SIZE(imx290_10bit_settings),
85 - .code = MEDIA_BUS_FMT_SRGGB12_1X12,
87 + [IMX290_VARIANT_COLOUR] = MEDIA_BUS_FMT_SRGGB12_1X12,
88 + [IMX290_VARIANT_MONO] = MEDIA_BUS_FMT_Y12_1X12
91 .regs = imx290_12bit_settings,
92 .num_regs = ARRAY_SIZE(imx290_12bit_settings),
96 -static const struct imx290_format_info *imx290_format_info(u32 code)
97 +static const struct imx290_format_info *
98 +imx290_format_info(const struct imx290 *imx290, u32 code)
102 for (i = 0; i < ARRAY_SIZE(imx290_formats); ++i) {
103 const struct imx290_format_info *info = &imx290_formats[i];
105 - if (info->code == code)
106 + if (info->code[imx290->model->colour_variant] == code)
110 @@ -541,7 +565,7 @@ static int imx290_set_black_level(struct
111 const struct v4l2_mbus_framefmt *format,
112 unsigned int black_level, int *err)
114 - unsigned int bpp = imx290_format_info(format->code)->bpp;
115 + unsigned int bpp = imx290_format_info(imx290, format->code)->bpp;
117 return imx290_write(imx290, IMX290_BLKLEVEL,
118 black_level >> (16 - bpp), err);
119 @@ -553,7 +577,7 @@ static int imx290_setup_format(struct im
120 const struct imx290_format_info *info;
123 - info = imx290_format_info(format->code);
124 + info = imx290_format_info(imx290, format->code);
126 ret = imx290_set_register_array(imx290, info->regs, info->num_regs);
128 @@ -654,7 +678,7 @@ static void imx290_ctrl_update(struct im
130 /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
131 pixel_rate = link_freq * 2 * imx290->nlanes;
132 - do_div(pixel_rate, imx290_format_info(format->code)->bpp);
133 + do_div(pixel_rate, imx290_format_info(imx290, format->code)->bpp);
135 __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index);
136 __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, pixel_rate);
137 @@ -849,10 +873,12 @@ static int imx290_enum_mbus_code(struct
138 struct v4l2_subdev_state *sd_state,
139 struct v4l2_subdev_mbus_code_enum *code)
141 + const struct imx290 *imx290 = to_imx290(sd);
143 if (code->index >= ARRAY_SIZE(imx290_formats))
146 - code->code = imx290_formats[code->index].code;
147 + code->code = imx290_formats[code->index].code[imx290->model->colour_variant];
151 @@ -864,7 +890,7 @@ static int imx290_enum_frame_size(struct
152 const struct imx290 *imx290 = to_imx290(sd);
153 const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290);
155 - if (!imx290_format_info(fse->code))
156 + if (!imx290_format_info(imx290, fse->code))
159 if (fse->index >= imx290_modes_num(imx290))
160 @@ -893,8 +919,8 @@ static int imx290_set_fmt(struct v4l2_su
161 fmt->format.width = mode->width;
162 fmt->format.height = mode->height;
164 - if (!imx290_format_info(fmt->format.code))
165 - fmt->format.code = imx290_formats[0].code;
166 + if (!imx290_format_info(imx290, fmt->format.code))
167 + fmt->format.code = imx290_formats[0].code[imx290->model->colour_variant];
169 fmt->format.field = V4L2_FIELD_NONE;
171 @@ -1182,6 +1208,15 @@ static s64 imx290_check_link_freqs(const
175 +static const struct imx290_model_info imx290_models[] = {
176 + [IMX290_MODEL_IMX290LQR] = {
177 + .colour_variant = IMX290_VARIANT_COLOUR,
179 + [IMX290_MODEL_IMX290LLR] = {
180 + .colour_variant = IMX290_VARIANT_MONO,
184 static int imx290_parse_dt(struct imx290 *imx290)
186 /* Only CSI2 is supported for now: */
187 @@ -1192,6 +1227,8 @@ static int imx290_parse_dt(struct imx290
191 + imx290->model = of_device_get_match_data(imx290->dev);
193 endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx290->dev), NULL);
195 dev_err(imx290->dev, "Endpoint node not found\n");
196 @@ -1357,8 +1394,18 @@ static void imx290_remove(struct i2c_cli
199 static const struct of_device_id imx290_of_match[] = {
200 - { .compatible = "sony,imx290" },
203 + /* Deprecated - synonym for "sony,imx290lqr" */
204 + .compatible = "sony,imx290",
205 + .data = &imx290_models[IMX290_MODEL_IMX290LQR],
207 + .compatible = "sony,imx290lqr",
208 + .data = &imx290_models[IMX290_MODEL_IMX290LQR],
210 + .compatible = "sony,imx290llr",
211 + .data = &imx290_models[IMX290_MODEL_IMX290LLR],
213 + { /* sentinel */ },
215 MODULE_DEVICE_TABLE(of, imx290_of_match);