1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Driver for ST MIPID02 CSI-2 to PARALLEL bridge |
4 | * |
5 | * Copyright (C) STMicroelectronics SA 2019 |
6 | * Authors: Mickael Guene <mickael.guene@st.com> |
7 | * for STMicroelectronics. |
8 | * |
9 | * |
10 | */ |
11 | |
12 | #include <linux/clk.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/gpio/consumer.h> |
15 | #include <linux/i2c.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of_graph.h> |
18 | #include <linux/regulator/consumer.h> |
19 | #include <media/mipi-csi2.h> |
20 | #include <media/v4l2-async.h> |
21 | #include <media/v4l2-cci.h> |
22 | #include <media/v4l2-ctrls.h> |
23 | #include <media/v4l2-device.h> |
24 | #include <media/v4l2-fwnode.h> |
25 | #include <media/v4l2-subdev.h> |
26 | |
27 | #define MIPID02_CLK_LANE_WR_REG1 CCI_REG8(0x01) |
28 | #define MIPID02_CLK_LANE_REG1 CCI_REG8(0x02) |
29 | #define MIPID02_CLK_LANE_REG3 CCI_REG8(0x04) |
30 | #define MIPID02_DATA_LANE0_REG1 CCI_REG8(0x05) |
31 | #define MIPID02_DATA_LANE0_REG2 CCI_REG8(0x06) |
32 | #define MIPID02_DATA_LANE1_REG1 CCI_REG8(0x09) |
33 | #define MIPID02_DATA_LANE1_REG2 CCI_REG8(0x0a) |
34 | #define MIPID02_MODE_REG1 CCI_REG8(0x14) |
35 | #define MIPID02_MODE_REG2 CCI_REG8(0x15) |
36 | #define MIPID02_DATA_ID_RREG CCI_REG8(0x17) |
37 | #define MIPID02_DATA_SELECTION_CTRL CCI_REG8(0x19) |
38 | #define MIPID02_PIX_WIDTH_CTRL CCI_REG8(0x1e) |
39 | #define MIPID02_PIX_WIDTH_CTRL_EMB CCI_REG8(0x1f) |
40 | |
41 | /* Bits definition for MIPID02_CLK_LANE_REG1 */ |
42 | #define CLK_ENABLE BIT(0) |
43 | /* Bits definition for MIPID02_CLK_LANE_REG3 */ |
44 | #define CLK_MIPI_CSI BIT(1) |
45 | /* Bits definition for MIPID02_DATA_LANE0_REG1 */ |
46 | #define DATA_ENABLE BIT(0) |
47 | /* Bits definition for MIPID02_DATA_LANEx_REG2 */ |
48 | #define DATA_MIPI_CSI BIT(0) |
49 | /* Bits definition for MIPID02_MODE_REG1 */ |
50 | #define MODE_DATA_SWAP BIT(2) |
51 | #define MODE_NO_BYPASS BIT(6) |
52 | /* Bits definition for MIPID02_MODE_REG2 */ |
53 | #define MODE_HSYNC_ACTIVE_HIGH BIT(1) |
54 | #define MODE_VSYNC_ACTIVE_HIGH BIT(2) |
55 | #define MODE_PCLK_SAMPLE_RISING BIT(3) |
56 | /* Bits definition for MIPID02_DATA_SELECTION_CTRL */ |
57 | #define SELECTION_MANUAL_DATA BIT(2) |
58 | #define SELECTION_MANUAL_WIDTH BIT(3) |
59 | |
60 | static const u32 mipid02_supported_fmt_codes[] = { |
61 | MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, |
62 | MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, |
63 | MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, |
64 | MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, |
65 | MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, |
66 | MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, |
67 | MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16, |
68 | MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16, |
69 | MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24, |
70 | MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, |
71 | MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, |
72 | MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, |
73 | MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_JPEG_1X8 |
74 | }; |
75 | |
76 | /* regulator supplies */ |
77 | static const char * const mipid02_supply_name[] = { |
78 | "VDDE" , /* 1.8V digital I/O supply */ |
79 | "VDDIN" , /* 1V8 voltage regulator supply */ |
80 | }; |
81 | |
82 | #define MIPID02_NUM_SUPPLIES ARRAY_SIZE(mipid02_supply_name) |
83 | |
84 | #define MIPID02_SINK_0 0 |
85 | #define MIPID02_SINK_1 1 |
86 | #define MIPID02_SOURCE 2 |
87 | #define MIPID02_PAD_NB 3 |
88 | |
89 | struct mipid02_dev { |
90 | struct i2c_client *i2c_client; |
91 | struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES]; |
92 | struct v4l2_subdev sd; |
93 | struct regmap *regmap; |
94 | struct media_pad pad[MIPID02_PAD_NB]; |
95 | struct clk *xclk; |
96 | struct gpio_desc *reset_gpio; |
97 | /* endpoints info */ |
98 | struct v4l2_fwnode_endpoint rx; |
99 | struct v4l2_fwnode_endpoint tx; |
100 | /* remote source */ |
101 | struct v4l2_async_notifier notifier; |
102 | struct v4l2_subdev *s_subdev; |
103 | /* registers */ |
104 | struct { |
105 | u8 clk_lane_reg1; |
106 | u8 data_lane0_reg1; |
107 | u8 data_lane1_reg1; |
108 | u8 mode_reg1; |
109 | u8 mode_reg2; |
110 | u8 data_selection_ctrl; |
111 | u8 data_id_rreg; |
112 | u8 pix_width_ctrl; |
113 | u8 pix_width_ctrl_emb; |
114 | } r; |
115 | }; |
116 | |
117 | static int bpp_from_code(__u32 code) |
118 | { |
119 | switch (code) { |
120 | case MEDIA_BUS_FMT_SBGGR8_1X8: |
121 | case MEDIA_BUS_FMT_SGBRG8_1X8: |
122 | case MEDIA_BUS_FMT_SGRBG8_1X8: |
123 | case MEDIA_BUS_FMT_SRGGB8_1X8: |
124 | case MEDIA_BUS_FMT_Y8_1X8: |
125 | return 8; |
126 | case MEDIA_BUS_FMT_SBGGR10_1X10: |
127 | case MEDIA_BUS_FMT_SGBRG10_1X10: |
128 | case MEDIA_BUS_FMT_SGRBG10_1X10: |
129 | case MEDIA_BUS_FMT_SRGGB10_1X10: |
130 | return 10; |
131 | case MEDIA_BUS_FMT_SBGGR12_1X12: |
132 | case MEDIA_BUS_FMT_SGBRG12_1X12: |
133 | case MEDIA_BUS_FMT_SGRBG12_1X12: |
134 | case MEDIA_BUS_FMT_SRGGB12_1X12: |
135 | return 12; |
136 | case MEDIA_BUS_FMT_YUYV8_1X16: |
137 | case MEDIA_BUS_FMT_YVYU8_1X16: |
138 | case MEDIA_BUS_FMT_UYVY8_1X16: |
139 | case MEDIA_BUS_FMT_VYUY8_1X16: |
140 | case MEDIA_BUS_FMT_RGB565_1X16: |
141 | case MEDIA_BUS_FMT_YUYV8_2X8: |
142 | case MEDIA_BUS_FMT_YVYU8_2X8: |
143 | case MEDIA_BUS_FMT_UYVY8_2X8: |
144 | case MEDIA_BUS_FMT_VYUY8_2X8: |
145 | case MEDIA_BUS_FMT_RGB565_2X8_LE: |
146 | case MEDIA_BUS_FMT_RGB565_2X8_BE: |
147 | return 16; |
148 | case MEDIA_BUS_FMT_BGR888_1X24: |
149 | return 24; |
150 | default: |
151 | return 0; |
152 | } |
153 | } |
154 | |
155 | static u8 data_type_from_code(__u32 code) |
156 | { |
157 | switch (code) { |
158 | case MEDIA_BUS_FMT_SBGGR8_1X8: |
159 | case MEDIA_BUS_FMT_SGBRG8_1X8: |
160 | case MEDIA_BUS_FMT_SGRBG8_1X8: |
161 | case MEDIA_BUS_FMT_SRGGB8_1X8: |
162 | case MEDIA_BUS_FMT_Y8_1X8: |
163 | return MIPI_CSI2_DT_RAW8; |
164 | case MEDIA_BUS_FMT_SBGGR10_1X10: |
165 | case MEDIA_BUS_FMT_SGBRG10_1X10: |
166 | case MEDIA_BUS_FMT_SGRBG10_1X10: |
167 | case MEDIA_BUS_FMT_SRGGB10_1X10: |
168 | return MIPI_CSI2_DT_RAW10; |
169 | case MEDIA_BUS_FMT_SBGGR12_1X12: |
170 | case MEDIA_BUS_FMT_SGBRG12_1X12: |
171 | case MEDIA_BUS_FMT_SGRBG12_1X12: |
172 | case MEDIA_BUS_FMT_SRGGB12_1X12: |
173 | return MIPI_CSI2_DT_RAW12; |
174 | case MEDIA_BUS_FMT_YUYV8_1X16: |
175 | case MEDIA_BUS_FMT_YVYU8_1X16: |
176 | case MEDIA_BUS_FMT_UYVY8_1X16: |
177 | case MEDIA_BUS_FMT_VYUY8_1X16: |
178 | case MEDIA_BUS_FMT_YUYV8_2X8: |
179 | case MEDIA_BUS_FMT_YVYU8_2X8: |
180 | case MEDIA_BUS_FMT_UYVY8_2X8: |
181 | case MEDIA_BUS_FMT_VYUY8_2X8: |
182 | return MIPI_CSI2_DT_YUV422_8B; |
183 | case MEDIA_BUS_FMT_BGR888_1X24: |
184 | return MIPI_CSI2_DT_RGB888; |
185 | case MEDIA_BUS_FMT_RGB565_1X16: |
186 | case MEDIA_BUS_FMT_RGB565_2X8_LE: |
187 | case MEDIA_BUS_FMT_RGB565_2X8_BE: |
188 | return MIPI_CSI2_DT_RGB565; |
189 | default: |
190 | return 0; |
191 | } |
192 | } |
193 | |
194 | static __u32 get_fmt_code(__u32 code) |
195 | { |
196 | unsigned int i; |
197 | |
198 | for (i = 0; i < ARRAY_SIZE(mipid02_supported_fmt_codes); i++) { |
199 | if (code == mipid02_supported_fmt_codes[i]) |
200 | return code; |
201 | } |
202 | |
203 | return mipid02_supported_fmt_codes[0]; |
204 | } |
205 | |
206 | static __u32 serial_to_parallel_code(__u32 serial) |
207 | { |
208 | if (serial == MEDIA_BUS_FMT_RGB565_1X16) |
209 | return MEDIA_BUS_FMT_RGB565_2X8_LE; |
210 | if (serial == MEDIA_BUS_FMT_YUYV8_1X16) |
211 | return MEDIA_BUS_FMT_YUYV8_2X8; |
212 | if (serial == MEDIA_BUS_FMT_YVYU8_1X16) |
213 | return MEDIA_BUS_FMT_YVYU8_2X8; |
214 | if (serial == MEDIA_BUS_FMT_UYVY8_1X16) |
215 | return MEDIA_BUS_FMT_UYVY8_2X8; |
216 | if (serial == MEDIA_BUS_FMT_VYUY8_1X16) |
217 | return MEDIA_BUS_FMT_VYUY8_2X8; |
218 | if (serial == MEDIA_BUS_FMT_BGR888_1X24) |
219 | return MEDIA_BUS_FMT_BGR888_3X8; |
220 | |
221 | return serial; |
222 | } |
223 | |
224 | static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd) |
225 | { |
226 | return container_of(sd, struct mipid02_dev, sd); |
227 | } |
228 | |
229 | static int mipid02_get_regulators(struct mipid02_dev *bridge) |
230 | { |
231 | unsigned int i; |
232 | |
233 | for (i = 0; i < MIPID02_NUM_SUPPLIES; i++) |
234 | bridge->supplies[i].supply = mipid02_supply_name[i]; |
235 | |
236 | return devm_regulator_bulk_get(dev: &bridge->i2c_client->dev, |
237 | MIPID02_NUM_SUPPLIES, |
238 | consumers: bridge->supplies); |
239 | } |
240 | |
241 | static void mipid02_apply_reset(struct mipid02_dev *bridge) |
242 | { |
243 | gpiod_set_value_cansleep(desc: bridge->reset_gpio, value: 0); |
244 | usleep_range(min: 5000, max: 10000); |
245 | gpiod_set_value_cansleep(desc: bridge->reset_gpio, value: 1); |
246 | usleep_range(min: 5000, max: 10000); |
247 | gpiod_set_value_cansleep(desc: bridge->reset_gpio, value: 0); |
248 | usleep_range(min: 5000, max: 10000); |
249 | } |
250 | |
251 | static int mipid02_set_power_on(struct mipid02_dev *bridge) |
252 | { |
253 | struct i2c_client *client = bridge->i2c_client; |
254 | int ret; |
255 | |
256 | ret = clk_prepare_enable(clk: bridge->xclk); |
257 | if (ret) { |
258 | dev_err(&client->dev, "%s: failed to enable clock\n" , __func__); |
259 | return ret; |
260 | } |
261 | |
262 | ret = regulator_bulk_enable(MIPID02_NUM_SUPPLIES, |
263 | consumers: bridge->supplies); |
264 | if (ret) { |
265 | dev_err(&client->dev, "%s: failed to enable regulators\n" , |
266 | __func__); |
267 | goto xclk_off; |
268 | } |
269 | |
270 | if (bridge->reset_gpio) { |
271 | dev_dbg(&client->dev, "apply reset" ); |
272 | mipid02_apply_reset(bridge); |
273 | } else { |
274 | dev_dbg(&client->dev, "don't apply reset" ); |
275 | usleep_range(min: 5000, max: 10000); |
276 | } |
277 | |
278 | return 0; |
279 | |
280 | xclk_off: |
281 | clk_disable_unprepare(clk: bridge->xclk); |
282 | return ret; |
283 | } |
284 | |
285 | static void mipid02_set_power_off(struct mipid02_dev *bridge) |
286 | { |
287 | regulator_bulk_disable(MIPID02_NUM_SUPPLIES, consumers: bridge->supplies); |
288 | clk_disable_unprepare(clk: bridge->xclk); |
289 | } |
290 | |
291 | static int mipid02_detect(struct mipid02_dev *bridge) |
292 | { |
293 | u64 reg; |
294 | |
295 | /* |
296 | * There is no version registers. Just try to read register |
297 | * MIPID02_CLK_LANE_WR_REG1. |
298 | */ |
299 | return cci_read(map: bridge->regmap, MIPID02_CLK_LANE_WR_REG1, val: ®, NULL); |
300 | } |
301 | |
302 | /* |
303 | * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency |
304 | * will be retrieve from connected device via v4l2_get_link_freq, bit per pixel |
305 | * and number of lanes. |
306 | */ |
307 | static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge, |
308 | struct v4l2_mbus_framefmt *fmt) |
309 | { |
310 | struct i2c_client *client = bridge->i2c_client; |
311 | struct v4l2_subdev *subdev = bridge->s_subdev; |
312 | struct v4l2_fwnode_endpoint *ep = &bridge->rx; |
313 | u32 bpp = bpp_from_code(code: fmt->code); |
314 | /* |
315 | * clk_lane_reg1 requires 4 times the unit interval time, and bitrate |
316 | * is twice the link frequency, hence ui_4 = 1000000000 * 4 / 2 |
317 | */ |
318 | u64 ui_4 = 2000000000; |
319 | s64 link_freq; |
320 | |
321 | link_freq = v4l2_get_link_freq(handler: subdev->ctrl_handler, mul: bpp, |
322 | div: 2 * ep->bus.mipi_csi2.num_data_lanes); |
323 | if (link_freq < 0) { |
324 | dev_err(&client->dev, "Failed to get link frequency" ); |
325 | return -EINVAL; |
326 | } |
327 | |
328 | dev_dbg(&client->dev, "detect link_freq = %lld Hz" , link_freq); |
329 | do_div(ui_4, link_freq); |
330 | bridge->r.clk_lane_reg1 |= ui_4 << 2; |
331 | |
332 | return 0; |
333 | } |
334 | |
335 | static int mipid02_configure_clk_lane(struct mipid02_dev *bridge) |
336 | { |
337 | struct i2c_client *client = bridge->i2c_client; |
338 | struct v4l2_fwnode_endpoint *ep = &bridge->rx; |
339 | bool *polarities = ep->bus.mipi_csi2.lane_polarities; |
340 | |
341 | /* midid02 doesn't support clock lane remapping */ |
342 | if (ep->bus.mipi_csi2.clock_lane != 0) { |
343 | dev_err(&client->dev, "clk lane must be map to lane 0\n" ); |
344 | return -EINVAL; |
345 | } |
346 | bridge->r.clk_lane_reg1 |= (polarities[0] << 1) | CLK_ENABLE; |
347 | |
348 | return 0; |
349 | } |
350 | |
351 | static int mipid02_configure_data0_lane(struct mipid02_dev *bridge, int nb, |
352 | bool are_lanes_swap, bool *polarities) |
353 | { |
354 | bool are_pin_swap = are_lanes_swap ? polarities[2] : polarities[1]; |
355 | |
356 | if (nb == 1 && are_lanes_swap) |
357 | return 0; |
358 | |
359 | /* |
360 | * data lane 0 as pin swap polarity reversed compared to clock and |
361 | * data lane 1 |
362 | */ |
363 | if (!are_pin_swap) |
364 | bridge->r.data_lane0_reg1 = 1 << 1; |
365 | bridge->r.data_lane0_reg1 |= DATA_ENABLE; |
366 | |
367 | return 0; |
368 | } |
369 | |
370 | static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb, |
371 | bool are_lanes_swap, bool *polarities) |
372 | { |
373 | bool are_pin_swap = are_lanes_swap ? polarities[1] : polarities[2]; |
374 | |
375 | if (nb == 1 && !are_lanes_swap) |
376 | return 0; |
377 | |
378 | if (are_pin_swap) |
379 | bridge->r.data_lane1_reg1 = 1 << 1; |
380 | bridge->r.data_lane1_reg1 |= DATA_ENABLE; |
381 | |
382 | return 0; |
383 | } |
384 | |
385 | static int mipid02_configure_from_rx(struct mipid02_dev *bridge, |
386 | struct v4l2_mbus_framefmt *fmt) |
387 | { |
388 | struct v4l2_fwnode_endpoint *ep = &bridge->rx; |
389 | bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2; |
390 | bool *polarities = ep->bus.mipi_csi2.lane_polarities; |
391 | int nb = ep->bus.mipi_csi2.num_data_lanes; |
392 | int ret; |
393 | |
394 | ret = mipid02_configure_clk_lane(bridge); |
395 | if (ret) |
396 | return ret; |
397 | |
398 | ret = mipid02_configure_data0_lane(bridge, nb, are_lanes_swap, |
399 | polarities); |
400 | if (ret) |
401 | return ret; |
402 | |
403 | ret = mipid02_configure_data1_lane(bridge, nb, are_lanes_swap, |
404 | polarities); |
405 | if (ret) |
406 | return ret; |
407 | |
408 | bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0; |
409 | bridge->r.mode_reg1 |= (nb - 1) << 1; |
410 | |
411 | return mipid02_configure_from_rx_speed(bridge, fmt); |
412 | } |
413 | |
414 | static int mipid02_configure_from_tx(struct mipid02_dev *bridge) |
415 | { |
416 | struct v4l2_fwnode_endpoint *ep = &bridge->tx; |
417 | |
418 | bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH; |
419 | bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; |
420 | bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; |
421 | if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) |
422 | bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH; |
423 | if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
424 | bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH; |
425 | if (ep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
426 | bridge->r.mode_reg2 |= MODE_PCLK_SAMPLE_RISING; |
427 | |
428 | return 0; |
429 | } |
430 | |
431 | static int mipid02_configure_from_code(struct mipid02_dev *bridge, |
432 | struct v4l2_mbus_framefmt *fmt) |
433 | { |
434 | u8 data_type; |
435 | |
436 | bridge->r.data_id_rreg = 0; |
437 | |
438 | if (fmt->code != MEDIA_BUS_FMT_JPEG_1X8) { |
439 | bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA; |
440 | |
441 | data_type = data_type_from_code(code: fmt->code); |
442 | if (!data_type) |
443 | return -EINVAL; |
444 | bridge->r.data_id_rreg = data_type; |
445 | } |
446 | |
447 | return 0; |
448 | } |
449 | |
450 | static int mipid02_stream_disable(struct mipid02_dev *bridge) |
451 | { |
452 | struct i2c_client *client = bridge->i2c_client; |
453 | int ret = -EINVAL; |
454 | |
455 | if (!bridge->s_subdev) |
456 | goto error; |
457 | |
458 | ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 0); |
459 | if (ret) |
460 | goto error; |
461 | |
462 | /* Disable all lanes */ |
463 | cci_write(map: bridge->regmap, MIPID02_CLK_LANE_REG1, val: 0, err: &ret); |
464 | cci_write(map: bridge->regmap, MIPID02_DATA_LANE0_REG1, val: 0, err: &ret); |
465 | cci_write(map: bridge->regmap, MIPID02_DATA_LANE1_REG1, val: 0, err: &ret); |
466 | if (ret) |
467 | goto error; |
468 | error: |
469 | if (ret) |
470 | dev_err(&client->dev, "failed to stream off %d" , ret); |
471 | |
472 | return ret; |
473 | } |
474 | |
475 | static int mipid02_stream_enable(struct mipid02_dev *bridge) |
476 | { |
477 | struct i2c_client *client = bridge->i2c_client; |
478 | struct v4l2_subdev_state *state; |
479 | struct v4l2_mbus_framefmt *fmt; |
480 | int ret = -EINVAL; |
481 | |
482 | if (!bridge->s_subdev) |
483 | goto error; |
484 | |
485 | memset(&bridge->r, 0, sizeof(bridge->r)); |
486 | |
487 | state = v4l2_subdev_lock_and_get_active_state(sd: &bridge->sd); |
488 | fmt = v4l2_subdev_state_get_format(state, MIPID02_SINK_0); |
489 | |
490 | /* build registers content */ |
491 | ret = mipid02_configure_from_rx(bridge, fmt); |
492 | if (ret) |
493 | goto error; |
494 | ret = mipid02_configure_from_tx(bridge); |
495 | if (ret) |
496 | goto error; |
497 | ret = mipid02_configure_from_code(bridge, fmt); |
498 | if (ret) |
499 | goto error; |
500 | |
501 | v4l2_subdev_unlock_state(state); |
502 | |
503 | /* write mipi registers */ |
504 | cci_write(map: bridge->regmap, MIPID02_CLK_LANE_REG1, |
505 | val: bridge->r.clk_lane_reg1, err: &ret); |
506 | cci_write(map: bridge->regmap, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI, err: &ret); |
507 | cci_write(map: bridge->regmap, MIPID02_DATA_LANE0_REG1, |
508 | val: bridge->r.data_lane0_reg1, err: &ret); |
509 | cci_write(map: bridge->regmap, MIPID02_DATA_LANE0_REG2, DATA_MIPI_CSI, err: &ret); |
510 | cci_write(map: bridge->regmap, MIPID02_DATA_LANE1_REG1, |
511 | val: bridge->r.data_lane1_reg1, err: &ret); |
512 | cci_write(map: bridge->regmap, MIPID02_DATA_LANE1_REG2, DATA_MIPI_CSI, err: &ret); |
513 | cci_write(map: bridge->regmap, MIPID02_MODE_REG1, |
514 | MODE_NO_BYPASS | bridge->r.mode_reg1, err: &ret); |
515 | cci_write(map: bridge->regmap, MIPID02_MODE_REG2, val: bridge->r.mode_reg2, err: &ret); |
516 | cci_write(map: bridge->regmap, MIPID02_DATA_ID_RREG, val: bridge->r.data_id_rreg, |
517 | err: &ret); |
518 | cci_write(map: bridge->regmap, MIPID02_DATA_SELECTION_CTRL, |
519 | val: bridge->r.data_selection_ctrl, err: &ret); |
520 | cci_write(map: bridge->regmap, MIPID02_PIX_WIDTH_CTRL, |
521 | val: bridge->r.pix_width_ctrl, err: &ret); |
522 | cci_write(map: bridge->regmap, MIPID02_PIX_WIDTH_CTRL_EMB, |
523 | val: bridge->r.pix_width_ctrl_emb, err: &ret); |
524 | if (ret) |
525 | goto error; |
526 | |
527 | ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 1); |
528 | if (ret) |
529 | goto error; |
530 | |
531 | return 0; |
532 | |
533 | error: |
534 | dev_err(&client->dev, "failed to stream on %d" , ret); |
535 | mipid02_stream_disable(bridge); |
536 | |
537 | return ret; |
538 | } |
539 | |
540 | static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) |
541 | { |
542 | struct mipid02_dev *bridge = to_mipid02_dev(sd); |
543 | struct i2c_client *client = bridge->i2c_client; |
544 | int ret = 0; |
545 | |
546 | dev_dbg(&client->dev, "%s : requested %d\n" , __func__, enable); |
547 | |
548 | ret = enable ? mipid02_stream_enable(bridge) : |
549 | mipid02_stream_disable(bridge); |
550 | if (ret) |
551 | dev_err(&client->dev, "failed to stream %s (%d)\n" , |
552 | enable ? "enable" : "disable" , ret); |
553 | |
554 | return ret; |
555 | } |
556 | |
557 | static const struct v4l2_mbus_framefmt default_fmt = { |
558 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, |
559 | .field = V4L2_FIELD_NONE, |
560 | .colorspace = V4L2_COLORSPACE_SRGB, |
561 | .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, |
562 | .quantization = V4L2_QUANTIZATION_FULL_RANGE, |
563 | .xfer_func = V4L2_XFER_FUNC_DEFAULT, |
564 | .width = 640, |
565 | .height = 480, |
566 | }; |
567 | |
568 | static int mipid02_init_state(struct v4l2_subdev *sd, |
569 | struct v4l2_subdev_state *state) |
570 | { |
571 | *v4l2_subdev_state_get_format(state, MIPID02_SINK_0) = default_fmt; |
572 | /* MIPID02_SINK_1 isn't supported yet */ |
573 | *v4l2_subdev_state_get_format(state, MIPID02_SOURCE) = default_fmt; |
574 | |
575 | return 0; |
576 | } |
577 | |
578 | static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, |
579 | struct v4l2_subdev_state *sd_state, |
580 | struct v4l2_subdev_mbus_code_enum *code) |
581 | { |
582 | struct v4l2_mbus_framefmt *sink_fmt; |
583 | int ret = 0; |
584 | |
585 | switch (code->pad) { |
586 | case MIPID02_SINK_0: |
587 | if (code->index >= ARRAY_SIZE(mipid02_supported_fmt_codes)) |
588 | ret = -EINVAL; |
589 | else |
590 | code->code = mipid02_supported_fmt_codes[code->index]; |
591 | break; |
592 | case MIPID02_SOURCE: |
593 | if (code->index == 0) { |
594 | sink_fmt = v4l2_subdev_state_get_format(sd_state, |
595 | MIPID02_SINK_0); |
596 | code->code = serial_to_parallel_code(serial: sink_fmt->code); |
597 | } else { |
598 | ret = -EINVAL; |
599 | } |
600 | break; |
601 | default: |
602 | ret = -EINVAL; |
603 | } |
604 | |
605 | return ret; |
606 | } |
607 | |
608 | static int mipid02_set_fmt(struct v4l2_subdev *sd, |
609 | struct v4l2_subdev_state *sd_state, |
610 | struct v4l2_subdev_format *fmt) |
611 | { |
612 | struct mipid02_dev *bridge = to_mipid02_dev(sd); |
613 | struct i2c_client *client = bridge->i2c_client; |
614 | struct v4l2_mbus_framefmt *pad_fmt; |
615 | |
616 | dev_dbg(&client->dev, "%s for %d" , __func__, fmt->pad); |
617 | |
618 | /* second CSI-2 pad not yet supported */ |
619 | if (fmt->pad == MIPID02_SINK_1) |
620 | return -EINVAL; |
621 | |
622 | pad_fmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); |
623 | fmt->format.code = get_fmt_code(code: fmt->format.code); |
624 | |
625 | /* code may need to be converted */ |
626 | if (fmt->pad == MIPID02_SOURCE) |
627 | fmt->format.code = serial_to_parallel_code(serial: fmt->format.code); |
628 | |
629 | *pad_fmt = fmt->format; |
630 | |
631 | /* Propagate the format to the source pad in case of sink pad update */ |
632 | if (fmt->pad == MIPID02_SINK_0) { |
633 | pad_fmt = v4l2_subdev_state_get_format(sd_state, |
634 | MIPID02_SOURCE); |
635 | *pad_fmt = fmt->format; |
636 | pad_fmt->code = serial_to_parallel_code(serial: fmt->format.code); |
637 | } |
638 | |
639 | return 0; |
640 | } |
641 | |
642 | static const struct v4l2_subdev_video_ops mipid02_video_ops = { |
643 | .s_stream = mipid02_s_stream, |
644 | }; |
645 | |
646 | static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { |
647 | .enum_mbus_code = mipid02_enum_mbus_code, |
648 | .get_fmt = v4l2_subdev_get_fmt, |
649 | .set_fmt = mipid02_set_fmt, |
650 | }; |
651 | |
652 | static const struct v4l2_subdev_ops mipid02_subdev_ops = { |
653 | .video = &mipid02_video_ops, |
654 | .pad = &mipid02_pad_ops, |
655 | }; |
656 | |
657 | static const struct v4l2_subdev_internal_ops mipid02_subdev_internal_ops = { |
658 | .init_state = mipid02_init_state, |
659 | }; |
660 | |
661 | static const struct media_entity_operations mipid02_subdev_entity_ops = { |
662 | .link_validate = v4l2_subdev_link_validate, |
663 | }; |
664 | |
665 | static int mipid02_async_bound(struct v4l2_async_notifier *notifier, |
666 | struct v4l2_subdev *s_subdev, |
667 | struct v4l2_async_connection *asd) |
668 | { |
669 | struct mipid02_dev *bridge = to_mipid02_dev(sd: notifier->sd); |
670 | struct i2c_client *client = bridge->i2c_client; |
671 | int source_pad; |
672 | int ret; |
673 | |
674 | dev_dbg(&client->dev, "sensor_async_bound call %p" , s_subdev); |
675 | |
676 | source_pad = media_entity_get_fwnode_pad(entity: &s_subdev->entity, |
677 | fwnode: s_subdev->fwnode, |
678 | MEDIA_PAD_FL_SOURCE); |
679 | if (source_pad < 0) { |
680 | dev_err(&client->dev, "Couldn't find output pad for subdev %s\n" , |
681 | s_subdev->name); |
682 | return source_pad; |
683 | } |
684 | |
685 | ret = media_create_pad_link(source: &s_subdev->entity, source_pad, |
686 | sink: &bridge->sd.entity, sink_pad: 0, |
687 | MEDIA_LNK_FL_ENABLED | |
688 | MEDIA_LNK_FL_IMMUTABLE); |
689 | if (ret) { |
690 | dev_err(&client->dev, "Couldn't create media link %d" , ret); |
691 | return ret; |
692 | } |
693 | |
694 | bridge->s_subdev = s_subdev; |
695 | |
696 | return 0; |
697 | } |
698 | |
699 | static void mipid02_async_unbind(struct v4l2_async_notifier *notifier, |
700 | struct v4l2_subdev *s_subdev, |
701 | struct v4l2_async_connection *asd) |
702 | { |
703 | struct mipid02_dev *bridge = to_mipid02_dev(sd: notifier->sd); |
704 | |
705 | bridge->s_subdev = NULL; |
706 | } |
707 | |
708 | static const struct v4l2_async_notifier_operations mipid02_notifier_ops = { |
709 | .bound = mipid02_async_bound, |
710 | .unbind = mipid02_async_unbind, |
711 | }; |
712 | |
713 | static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) |
714 | { |
715 | struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; |
716 | struct i2c_client *client = bridge->i2c_client; |
717 | struct v4l2_async_connection *asd; |
718 | struct device_node *ep_node; |
719 | int ret; |
720 | |
721 | /* parse rx (endpoint 0) */ |
722 | ep_node = of_graph_get_endpoint_by_regs(parent: bridge->i2c_client->dev.of_node, |
723 | port_reg: 0, reg: 0); |
724 | if (!ep_node) { |
725 | dev_err(&client->dev, "unable to find port0 ep" ); |
726 | ret = -EINVAL; |
727 | goto error; |
728 | } |
729 | |
730 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), vep: &ep); |
731 | if (ret) { |
732 | dev_err(&client->dev, "Could not parse v4l2 endpoint %d\n" , |
733 | ret); |
734 | goto error_of_node_put; |
735 | } |
736 | |
737 | /* do some sanity checks */ |
738 | if (ep.bus.mipi_csi2.num_data_lanes > 2) { |
739 | dev_err(&client->dev, "max supported data lanes is 2 / got %d" , |
740 | ep.bus.mipi_csi2.num_data_lanes); |
741 | ret = -EINVAL; |
742 | goto error_of_node_put; |
743 | } |
744 | |
745 | /* register it for later use */ |
746 | bridge->rx = ep; |
747 | |
748 | /* register async notifier so we get noticed when sensor is connected */ |
749 | v4l2_async_subdev_nf_init(notifier: &bridge->notifier, sd: &bridge->sd); |
750 | asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier, |
751 | of_fwnode_handle(ep_node), |
752 | struct v4l2_async_connection); |
753 | of_node_put(node: ep_node); |
754 | |
755 | if (IS_ERR(ptr: asd)) { |
756 | dev_err(&client->dev, "fail to register asd to notifier %ld" , |
757 | PTR_ERR(asd)); |
758 | return PTR_ERR(ptr: asd); |
759 | } |
760 | bridge->notifier.ops = &mipid02_notifier_ops; |
761 | |
762 | ret = v4l2_async_nf_register(notifier: &bridge->notifier); |
763 | if (ret) |
764 | v4l2_async_nf_cleanup(notifier: &bridge->notifier); |
765 | |
766 | return ret; |
767 | |
768 | error_of_node_put: |
769 | of_node_put(node: ep_node); |
770 | error: |
771 | |
772 | return ret; |
773 | } |
774 | |
775 | static int mipid02_parse_tx_ep(struct mipid02_dev *bridge) |
776 | { |
777 | struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_PARALLEL }; |
778 | struct i2c_client *client = bridge->i2c_client; |
779 | struct device_node *ep_node; |
780 | int ret; |
781 | |
782 | /* parse tx (endpoint 2) */ |
783 | ep_node = of_graph_get_endpoint_by_regs(parent: bridge->i2c_client->dev.of_node, |
784 | port_reg: 2, reg: 0); |
785 | if (!ep_node) { |
786 | dev_err(&client->dev, "unable to find port1 ep" ); |
787 | ret = -EINVAL; |
788 | goto error; |
789 | } |
790 | |
791 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), vep: &ep); |
792 | if (ret) { |
793 | dev_err(&client->dev, "Could not parse v4l2 endpoint\n" ); |
794 | goto error_of_node_put; |
795 | } |
796 | |
797 | of_node_put(node: ep_node); |
798 | bridge->tx = ep; |
799 | |
800 | return 0; |
801 | |
802 | error_of_node_put: |
803 | of_node_put(node: ep_node); |
804 | error: |
805 | |
806 | return -EINVAL; |
807 | } |
808 | |
809 | static int mipid02_probe(struct i2c_client *client) |
810 | { |
811 | struct device *dev = &client->dev; |
812 | struct mipid02_dev *bridge; |
813 | u32 clk_freq; |
814 | int ret; |
815 | |
816 | bridge = devm_kzalloc(dev, size: sizeof(*bridge), GFP_KERNEL); |
817 | if (!bridge) |
818 | return -ENOMEM; |
819 | |
820 | bridge->i2c_client = client; |
821 | v4l2_i2c_subdev_init(sd: &bridge->sd, client, ops: &mipid02_subdev_ops); |
822 | |
823 | /* got and check clock */ |
824 | bridge->xclk = devm_clk_get(dev, id: "xclk" ); |
825 | if (IS_ERR(ptr: bridge->xclk)) { |
826 | dev_err(dev, "failed to get xclk\n" ); |
827 | return PTR_ERR(ptr: bridge->xclk); |
828 | } |
829 | |
830 | clk_freq = clk_get_rate(clk: bridge->xclk); |
831 | if (clk_freq < 6000000 || clk_freq > 27000000) { |
832 | dev_err(dev, "xclk freq must be in 6-27 Mhz range. got %d Hz\n" , |
833 | clk_freq); |
834 | return -EINVAL; |
835 | } |
836 | |
837 | bridge->reset_gpio = devm_gpiod_get_optional(dev, con_id: "reset" , |
838 | flags: GPIOD_OUT_HIGH); |
839 | |
840 | if (IS_ERR(ptr: bridge->reset_gpio)) { |
841 | dev_err(dev, "failed to get reset GPIO\n" ); |
842 | return PTR_ERR(ptr: bridge->reset_gpio); |
843 | } |
844 | |
845 | ret = mipid02_get_regulators(bridge); |
846 | if (ret) { |
847 | dev_err(dev, "failed to get regulators %d" , ret); |
848 | return ret; |
849 | } |
850 | |
851 | /* Initialise the regmap for further cci access */ |
852 | bridge->regmap = devm_cci_regmap_init_i2c(client, reg_addr_bits: 16); |
853 | if (IS_ERR(ptr: bridge->regmap)) |
854 | return dev_err_probe(dev, err: PTR_ERR(ptr: bridge->regmap), |
855 | fmt: "failed to get cci regmap\n" ); |
856 | |
857 | bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
858 | bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; |
859 | bridge->sd.internal_ops = &mipid02_subdev_internal_ops; |
860 | bridge->sd.entity.ops = &mipid02_subdev_entity_ops; |
861 | bridge->pad[0].flags = MEDIA_PAD_FL_SINK; |
862 | bridge->pad[1].flags = MEDIA_PAD_FL_SINK; |
863 | bridge->pad[2].flags = MEDIA_PAD_FL_SOURCE; |
864 | ret = media_entity_pads_init(entity: &bridge->sd.entity, MIPID02_PAD_NB, |
865 | pads: bridge->pad); |
866 | if (ret) { |
867 | dev_err(&client->dev, "pads init failed %d" , ret); |
868 | return ret; |
869 | } |
870 | |
871 | ret = v4l2_subdev_init_finalize(&bridge->sd); |
872 | if (ret < 0) { |
873 | dev_err(dev, "subdev init error: %d\n" , ret); |
874 | goto entity_cleanup; |
875 | } |
876 | |
877 | /* enable clock, power and reset device if available */ |
878 | ret = mipid02_set_power_on(bridge); |
879 | if (ret) |
880 | goto entity_cleanup; |
881 | |
882 | ret = mipid02_detect(bridge); |
883 | if (ret) { |
884 | dev_err(&client->dev, "failed to detect mipid02 %d" , ret); |
885 | goto power_off; |
886 | } |
887 | |
888 | ret = mipid02_parse_tx_ep(bridge); |
889 | if (ret) { |
890 | dev_err(&client->dev, "failed to parse tx %d" , ret); |
891 | goto power_off; |
892 | } |
893 | |
894 | ret = mipid02_parse_rx_ep(bridge); |
895 | if (ret) { |
896 | dev_err(&client->dev, "failed to parse rx %d" , ret); |
897 | goto power_off; |
898 | } |
899 | |
900 | ret = v4l2_async_register_subdev(sd: &bridge->sd); |
901 | if (ret < 0) { |
902 | dev_err(&client->dev, "v4l2_async_register_subdev failed %d" , |
903 | ret); |
904 | goto unregister_notifier; |
905 | } |
906 | |
907 | dev_info(&client->dev, "mipid02 device probe successfully" ); |
908 | |
909 | return 0; |
910 | |
911 | unregister_notifier: |
912 | v4l2_async_nf_unregister(notifier: &bridge->notifier); |
913 | v4l2_async_nf_cleanup(notifier: &bridge->notifier); |
914 | power_off: |
915 | mipid02_set_power_off(bridge); |
916 | entity_cleanup: |
917 | media_entity_cleanup(entity: &bridge->sd.entity); |
918 | |
919 | return ret; |
920 | } |
921 | |
922 | static void mipid02_remove(struct i2c_client *client) |
923 | { |
924 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
925 | struct mipid02_dev *bridge = to_mipid02_dev(sd); |
926 | |
927 | v4l2_async_nf_unregister(notifier: &bridge->notifier); |
928 | v4l2_async_nf_cleanup(notifier: &bridge->notifier); |
929 | v4l2_async_unregister_subdev(sd: &bridge->sd); |
930 | mipid02_set_power_off(bridge); |
931 | media_entity_cleanup(entity: &bridge->sd.entity); |
932 | } |
933 | |
934 | static const struct of_device_id mipid02_dt_ids[] = { |
935 | { .compatible = "st,st-mipid02" }, |
936 | { /* sentinel */ } |
937 | }; |
938 | MODULE_DEVICE_TABLE(of, mipid02_dt_ids); |
939 | |
940 | static struct i2c_driver mipid02_i2c_driver = { |
941 | .driver = { |
942 | .name = "st-mipid02" , |
943 | .of_match_table = mipid02_dt_ids, |
944 | }, |
945 | .probe = mipid02_probe, |
946 | .remove = mipid02_remove, |
947 | }; |
948 | |
949 | module_i2c_driver(mipid02_i2c_driver); |
950 | |
951 | MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>" ); |
952 | MODULE_DESCRIPTION("STMicroelectronics MIPID02 CSI-2 bridge driver" ); |
953 | MODULE_LICENSE("GPL v2" ); |
954 | |