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 | |
23 | enum max96712_pattern { |
24 | MAX96712_PATTERN_CHECKERBOARD = 0, |
25 | MAX96712_PATTERN_GRADIENT, |
26 | }; |
27 | |
28 | struct 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 | |
43 | static 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 | |
56 | static 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 | |
67 | static 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 | |
79 | static 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 | |
91 | static 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 | |
104 | static 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 | |
110 | static 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 | |
121 | static 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 | |
164 | static 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 | |
226 | static 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 | |
241 | static const struct v4l2_subdev_video_ops max96712_video_ops = { |
242 | .s_stream = max96712_s_stream, |
243 | }; |
244 | |
245 | static 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 | |
257 | static 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 | |
262 | static const struct v4l2_subdev_ops max96712_subdev_ops = { |
263 | .video = &max96712_video_ops, |
264 | .pad = &max96712_pad_ops, |
265 | }; |
266 | |
267 | static const char * const max96712_test_pattern[] = { |
268 | "Checkerboard" , |
269 | "Gradient" , |
270 | }; |
271 | |
272 | static 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 | |
287 | static const struct v4l2_ctrl_ops max96712_ctrl_ops = { |
288 | .s_ctrl = max96712_s_ctrl, |
289 | }; |
290 | |
291 | static 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; |
334 | error: |
335 | v4l2_ctrl_handler_free(hdl: &priv->ctrl_handler); |
336 | |
337 | return ret; |
338 | } |
339 | |
340 | static 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 | |
389 | static const struct regmap_config max96712_i2c_regmap = { |
390 | .reg_bits = 16, |
391 | .val_bits = 8, |
392 | .max_register = 0x1f00, |
393 | }; |
394 | |
395 | static 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 | |
436 | static 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 | |
445 | static const struct of_device_id max96712_of_table[] = { |
446 | { .compatible = "maxim,max96712" }, |
447 | { /* sentinel */ }, |
448 | }; |
449 | MODULE_DEVICE_TABLE(of, max96712_of_table); |
450 | |
451 | static 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 | |
460 | module_i2c_driver(max96712_i2c_driver); |
461 | |
462 | MODULE_DESCRIPTION("Maxim MAX96712 Quad GMSL2 Deserializer Driver" ); |
463 | MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>" ); |
464 | MODULE_LICENSE("GPL" ); |
465 | |