1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Maxim MAX9286 Quad GMSL2 Deserializer Driver
4 *
5 * Copyright (C) 2021 Renesas Electronics Corporation
6 * Copyright (C) 2021 Niklas Söderlund
7 */
8
9#include <linux/delay.h>
10#include <linux/i2c.h>
11#include <linux/module.h>
12#include <linux/of_graph.h>
13#include <linux/regmap.h>
14
15#include <media/v4l2-ctrls.h>
16#include <media/v4l2-fwnode.h>
17#include <media/v4l2-subdev.h>
18
19#define MAX96712_ID 0x20
20
21#define MAX96712_DPLL_FREQ 1000
22
23enum max96712_pattern {
24 MAX96712_PATTERN_CHECKERBOARD = 0,
25 MAX96712_PATTERN_GRADIENT,
26};
27
28struct max96712_priv {
29 struct i2c_client *client;
30 struct regmap *regmap;
31 struct gpio_desc *gpiod_pwdn;
32
33 bool cphy;
34 struct v4l2_mbus_config_mipi_csi2 mipi;
35
36 struct v4l2_subdev sd;
37 struct v4l2_ctrl_handler ctrl_handler;
38 struct media_pad pads[1];
39
40 enum max96712_pattern pattern;
41};
42
43static int max96712_read(struct max96712_priv *priv, int reg)
44{
45 int ret, val;
46
47 ret = regmap_read(map: priv->regmap, reg, val: &val);
48 if (ret) {
49 dev_err(&priv->client->dev, "read 0x%04x failed\n", reg);
50 return ret;
51 }
52
53 return val;
54}
55
56static int max96712_write(struct max96712_priv *priv, unsigned int reg, u8 val)
57{
58 int ret;
59
60 ret = regmap_write(map: priv->regmap, reg, val);
61 if (ret)
62 dev_err(&priv->client->dev, "write 0x%04x failed\n", reg);
63
64 return ret;
65}
66
67static int max96712_update_bits(struct max96712_priv *priv, unsigned int reg,
68 u8 mask, u8 val)
69{
70 int ret;
71
72 ret = regmap_update_bits(map: priv->regmap, reg, mask, val);
73 if (ret)
74 dev_err(&priv->client->dev, "update 0x%04x failed\n", reg);
75
76 return ret;
77}
78
79static int max96712_write_bulk(struct max96712_priv *priv, unsigned int reg,
80 const void *val, size_t val_count)
81{
82 int ret;
83
84 ret = regmap_bulk_write(map: priv->regmap, reg, val, val_count);
85 if (ret)
86 dev_err(&priv->client->dev, "bulk write 0x%04x failed\n", reg);
87
88 return ret;
89}
90
91static int max96712_write_bulk_value(struct max96712_priv *priv,
92 unsigned int reg, unsigned int val,
93 size_t val_count)
94{
95 unsigned int i;
96 u8 values[4];
97
98 for (i = 1; i <= val_count; i++)
99 values[i - 1] = (val >> ((val_count - i) * 8)) & 0xff;
100
101 return max96712_write_bulk(priv, reg, val: &values, val_count);
102}
103
104static void max96712_reset(struct max96712_priv *priv)
105{
106 max96712_update_bits(priv, reg: 0x13, mask: 0x40, val: 0x40);
107 msleep(msecs: 20);
108}
109
110static void max96712_mipi_enable(struct max96712_priv *priv, bool enable)
111{
112 if (enable) {
113 max96712_update_bits(priv, reg: 0x40b, mask: 0x02, val: 0x02);
114 max96712_update_bits(priv, reg: 0x8a0, mask: 0x80, val: 0x80);
115 } else {
116 max96712_update_bits(priv, reg: 0x8a0, mask: 0x80, val: 0x00);
117 max96712_update_bits(priv, reg: 0x40b, mask: 0x02, val: 0x00);
118 }
119}
120
121static void max96712_mipi_configure(struct max96712_priv *priv)
122{
123 unsigned int i;
124 u8 phy5 = 0;
125
126 max96712_mipi_enable(priv, enable: false);
127
128 /* Select 2x4 mode. */
129 max96712_write(priv, reg: 0x8a0, val: 0x04);
130
131 /* TODO: Add support for 2-lane and 1-lane configurations. */
132 if (priv->cphy) {
133 /* Configure a 3-lane C-PHY using PHY0 and PHY1. */
134 max96712_write(priv, reg: 0x94a, val: 0xa0);
135
136 /* Configure C-PHY timings. */
137 max96712_write(priv, reg: 0x8ad, val: 0x3f);
138 max96712_write(priv, reg: 0x8ae, val: 0x7d);
139 } else {
140 /* Configure a 4-lane D-PHY using PHY0 and PHY1. */
141 max96712_write(priv, reg: 0x94a, val: 0xc0);
142 }
143
144 /* Configure lane mapping for PHY0 and PHY1. */
145 /* TODO: Add support for lane swapping. */
146 max96712_write(priv, reg: 0x8a3, val: 0xe4);
147
148 /* Configure lane polarity for PHY0 and PHY1. */
149 for (i = 0; i < priv->mipi.num_data_lanes + 1; i++)
150 if (priv->mipi.lane_polarities[i])
151 phy5 |= BIT(i == 0 ? 5 : i < 3 ? i - 1 : i);
152 max96712_write(priv, reg: 0x8a5, val: phy5);
153
154 /* Set link frequency for PHY0 and PHY1. */
155 max96712_update_bits(priv, reg: 0x415, mask: 0x3f,
156 val: ((MAX96712_DPLL_FREQ / 100) & 0x1f) | BIT(5));
157 max96712_update_bits(priv, reg: 0x418, mask: 0x3f,
158 val: ((MAX96712_DPLL_FREQ / 100) & 0x1f) | BIT(5));
159
160 /* Enable PHY0 and PHY1 */
161 max96712_update_bits(priv, reg: 0x8a2, mask: 0xf0, val: 0x30);
162}
163
164static void max96712_pattern_enable(struct max96712_priv *priv, bool enable)
165{
166 const u32 h_active = 1920;
167 const u32 h_fp = 88;
168 const u32 h_sw = 44;
169 const u32 h_bp = 148;
170 const u32 h_tot = h_active + h_fp + h_sw + h_bp;
171
172 const u32 v_active = 1080;
173 const u32 v_fp = 4;
174 const u32 v_sw = 5;
175 const u32 v_bp = 36;
176 const u32 v_tot = v_active + v_fp + v_sw + v_bp;
177
178 if (!enable) {
179 max96712_write(priv, reg: 0x1051, val: 0x00);
180 return;
181 }
182
183 /* PCLK 75MHz. */
184 max96712_write(priv, reg: 0x0009, val: 0x01);
185
186 /* Configure Video Timing Generator for 1920x1080 @ 30 fps. */
187 max96712_write_bulk_value(priv, reg: 0x1052, val: 0, val_count: 3);
188 max96712_write_bulk_value(priv, reg: 0x1055, val: v_sw * h_tot, val_count: 3);
189 max96712_write_bulk_value(priv, reg: 0x1058,
190 val: (v_active + v_fp + + v_bp) * h_tot, val_count: 3);
191 max96712_write_bulk_value(priv, reg: 0x105b, val: 0, val_count: 3);
192 max96712_write_bulk_value(priv, reg: 0x105e, val: h_sw, val_count: 2);
193 max96712_write_bulk_value(priv, reg: 0x1060, val: h_active + h_fp + h_bp, val_count: 2);
194 max96712_write_bulk_value(priv, reg: 0x1062, val: v_tot, val_count: 2);
195 max96712_write_bulk_value(priv, reg: 0x1064,
196 val: h_tot * (v_sw + v_bp) + (h_sw + h_bp), val_count: 3);
197 max96712_write_bulk_value(priv, reg: 0x1067, val: h_active, val_count: 2);
198 max96712_write_bulk_value(priv, reg: 0x1069, val: h_fp + h_sw + h_bp, val_count: 2);
199 max96712_write_bulk_value(priv, reg: 0x106b, val: v_active, val_count: 2);
200
201 /* Generate VS, HS and DE in free-running mode. */
202 max96712_write(priv, reg: 0x1050, val: 0xfb);
203
204 /* Configure Video Pattern Generator. */
205 if (priv->pattern == MAX96712_PATTERN_CHECKERBOARD) {
206 /* Set checkerboard pattern size. */
207 max96712_write(priv, reg: 0x1074, val: 0x3c);
208 max96712_write(priv, reg: 0x1075, val: 0x3c);
209 max96712_write(priv, reg: 0x1076, val: 0x3c);
210
211 /* Set checkerboard pattern colors. */
212 max96712_write_bulk_value(priv, reg: 0x106e, val: 0xfecc00, val_count: 3);
213 max96712_write_bulk_value(priv, reg: 0x1071, val: 0x006aa7, val_count: 3);
214
215 /* Generate checkerboard pattern. */
216 max96712_write(priv, reg: 0x1051, val: 0x10);
217 } else {
218 /* Set gradient increment. */
219 max96712_write(priv, reg: 0x106d, val: 0x10);
220
221 /* Generate gradient pattern. */
222 max96712_write(priv, reg: 0x1051, val: 0x20);
223 }
224}
225
226static int max96712_s_stream(struct v4l2_subdev *sd, int enable)
227{
228 struct max96712_priv *priv = v4l2_get_subdevdata(sd);
229
230 if (enable) {
231 max96712_pattern_enable(priv, enable: true);
232 max96712_mipi_enable(priv, enable: true);
233 } else {
234 max96712_mipi_enable(priv, enable: false);
235 max96712_pattern_enable(priv, enable: false);
236 }
237
238 return 0;
239}
240
241static const struct v4l2_subdev_video_ops max96712_video_ops = {
242 .s_stream = max96712_s_stream,
243};
244
245static int max96712_get_pad_format(struct v4l2_subdev *sd,
246 struct v4l2_subdev_state *sd_state,
247 struct v4l2_subdev_format *format)
248{
249 format->format.width = 1920;
250 format->format.height = 1080;
251 format->format.code = MEDIA_BUS_FMT_RGB888_1X24;
252 format->format.field = V4L2_FIELD_NONE;
253
254 return 0;
255}
256
257static const struct v4l2_subdev_pad_ops max96712_pad_ops = {
258 .get_fmt = max96712_get_pad_format,
259 .set_fmt = max96712_get_pad_format,
260};
261
262static const struct v4l2_subdev_ops max96712_subdev_ops = {
263 .video = &max96712_video_ops,
264 .pad = &max96712_pad_ops,
265};
266
267static const char * const max96712_test_pattern[] = {
268 "Checkerboard",
269 "Gradient",
270};
271
272static int max96712_s_ctrl(struct v4l2_ctrl *ctrl)
273{
274 struct max96712_priv *priv =
275 container_of(ctrl->handler, struct max96712_priv, ctrl_handler);
276
277 switch (ctrl->id) {
278 case V4L2_CID_TEST_PATTERN:
279 priv->pattern = ctrl->val ?
280 MAX96712_PATTERN_GRADIENT :
281 MAX96712_PATTERN_CHECKERBOARD;
282 break;
283 }
284 return 0;
285}
286
287static const struct v4l2_ctrl_ops max96712_ctrl_ops = {
288 .s_ctrl = max96712_s_ctrl,
289};
290
291static int max96712_v4l2_register(struct max96712_priv *priv)
292{
293 long pixel_rate;
294 int ret;
295
296 v4l2_i2c_subdev_init(sd: &priv->sd, client: priv->client, ops: &max96712_subdev_ops);
297 priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
298 priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
299
300 v4l2_ctrl_handler_init(&priv->ctrl_handler, 2);
301
302 /*
303 * TODO: Once V4L2_CID_LINK_FREQ is changed from a menu control to an
304 * INT64 control it should be used here instead of V4L2_CID_PIXEL_RATE.
305 */
306 pixel_rate = MAX96712_DPLL_FREQ / priv->mipi.num_data_lanes * 1000000;
307 v4l2_ctrl_new_std(hdl: &priv->ctrl_handler, NULL, V4L2_CID_PIXEL_RATE,
308 min: pixel_rate, max: pixel_rate, step: 1, def: pixel_rate);
309
310 v4l2_ctrl_new_std_menu_items(hdl: &priv->ctrl_handler, ops: &max96712_ctrl_ops,
311 V4L2_CID_TEST_PATTERN,
312 ARRAY_SIZE(max96712_test_pattern) - 1,
313 mask: 0, def: 0, qmenu: max96712_test_pattern);
314
315 priv->sd.ctrl_handler = &priv->ctrl_handler;
316 ret = priv->ctrl_handler.error;
317 if (ret)
318 goto error;
319
320 priv->pads[0].flags = MEDIA_PAD_FL_SOURCE;
321 ret = media_entity_pads_init(entity: &priv->sd.entity, num_pads: 1, pads: priv->pads);
322 if (ret)
323 goto error;
324
325 v4l2_set_subdevdata(sd: &priv->sd, p: priv);
326
327 ret = v4l2_async_register_subdev(sd: &priv->sd);
328 if (ret < 0) {
329 dev_err(&priv->client->dev, "Unable to register subdevice\n");
330 goto error;
331 }
332
333 return 0;
334error:
335 v4l2_ctrl_handler_free(hdl: &priv->ctrl_handler);
336
337 return ret;
338}
339
340static int max96712_parse_dt(struct max96712_priv *priv)
341{
342 struct fwnode_handle *ep;
343 struct v4l2_fwnode_endpoint v4l2_ep = {
344 .bus_type = V4L2_MBUS_UNKNOWN,
345 };
346 unsigned int supported_lanes;
347 int ret;
348
349 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(&priv->client->dev), port: 4,
350 endpoint: 0, flags: 0);
351 if (!ep) {
352 dev_err(&priv->client->dev, "Not connected to subdevice\n");
353 return -EINVAL;
354 }
355
356 ret = v4l2_fwnode_endpoint_parse(fwnode: ep, vep: &v4l2_ep);
357 fwnode_handle_put(fwnode: ep);
358 if (ret) {
359 dev_err(&priv->client->dev, "Could not parse v4l2 endpoint\n");
360 return -EINVAL;
361 }
362
363 switch (v4l2_ep.bus_type) {
364 case V4L2_MBUS_CSI2_DPHY:
365 supported_lanes = 4;
366 priv->cphy = false;
367 break;
368 case V4L2_MBUS_CSI2_CPHY:
369 supported_lanes = 3;
370 priv->cphy = true;
371 break;
372 default:
373 dev_err(&priv->client->dev, "Unsupported bus-type %u\n",
374 v4l2_ep.bus_type);
375 return -EINVAL;
376 }
377
378 if (v4l2_ep.bus.mipi_csi2.num_data_lanes != supported_lanes) {
379 dev_err(&priv->client->dev, "Only %u data lanes supported\n",
380 supported_lanes);
381 return -EINVAL;
382 }
383
384 priv->mipi = v4l2_ep.bus.mipi_csi2;
385
386 return 0;
387}
388
389static const struct regmap_config max96712_i2c_regmap = {
390 .reg_bits = 16,
391 .val_bits = 8,
392 .max_register = 0x1f00,
393};
394
395static int max96712_probe(struct i2c_client *client)
396{
397 struct max96712_priv *priv;
398 int ret;
399
400 priv = devm_kzalloc(dev: &client->dev, size: sizeof(*priv), GFP_KERNEL);
401 if (!priv)
402 return -ENOMEM;
403
404 priv->client = client;
405 i2c_set_clientdata(client, data: priv);
406
407 priv->regmap = devm_regmap_init_i2c(client, &max96712_i2c_regmap);
408 if (IS_ERR(ptr: priv->regmap))
409 return PTR_ERR(ptr: priv->regmap);
410
411 priv->gpiod_pwdn = devm_gpiod_get_optional(dev: &client->dev, con_id: "enable",
412 flags: GPIOD_OUT_HIGH);
413 if (IS_ERR(ptr: priv->gpiod_pwdn))
414 return PTR_ERR(ptr: priv->gpiod_pwdn);
415
416 gpiod_set_consumer_name(desc: priv->gpiod_pwdn, name: "max96712-pwdn");
417 gpiod_set_value_cansleep(desc: priv->gpiod_pwdn, value: 1);
418
419 if (priv->gpiod_pwdn)
420 usleep_range(min: 4000, max: 5000);
421
422 if (max96712_read(priv, reg: 0x4a) != MAX96712_ID)
423 return -ENODEV;
424
425 max96712_reset(priv);
426
427 ret = max96712_parse_dt(priv);
428 if (ret)
429 return ret;
430
431 max96712_mipi_configure(priv);
432
433 return max96712_v4l2_register(priv);
434}
435
436static void max96712_remove(struct i2c_client *client)
437{
438 struct max96712_priv *priv = i2c_get_clientdata(client);
439
440 v4l2_async_unregister_subdev(sd: &priv->sd);
441
442 gpiod_set_value_cansleep(desc: priv->gpiod_pwdn, value: 0);
443}
444
445static const struct of_device_id max96712_of_table[] = {
446 { .compatible = "maxim,max96712" },
447 { /* sentinel */ },
448};
449MODULE_DEVICE_TABLE(of, max96712_of_table);
450
451static struct i2c_driver max96712_i2c_driver = {
452 .driver = {
453 .name = "max96712",
454 .of_match_table = of_match_ptr(max96712_of_table),
455 },
456 .probe = max96712_probe,
457 .remove = max96712_remove,
458};
459
460module_i2c_driver(max96712_i2c_driver);
461
462MODULE_DESCRIPTION("Maxim MAX96712 Quad GMSL2 Deserializer Driver");
463MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
464MODULE_LICENSE("GPL");
465

source code of linux/drivers/staging/media/max96712/max96712.c