1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Greybus Camera protocol driver. |
4 | * |
5 | * Copyright 2015 Google Inc. |
6 | * Copyright 2015 Linaro Ltd. |
7 | */ |
8 | |
9 | #include <linux/debugfs.h> |
10 | #include <linux/fs.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/string.h> |
15 | #include <linux/uaccess.h> |
16 | #include <linux/vmalloc.h> |
17 | #include <linux/greybus.h> |
18 | |
19 | #include "gb-camera.h" |
20 | #include "greybus_protocols.h" |
21 | |
22 | enum gb_camera_debugs_buffer_id { |
23 | GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES, |
24 | GB_CAMERA_DEBUGFS_BUFFER_STREAMS, |
25 | GB_CAMERA_DEBUGFS_BUFFER_CAPTURE, |
26 | GB_CAMERA_DEBUGFS_BUFFER_FLUSH, |
27 | GB_CAMERA_DEBUGFS_BUFFER_MAX, |
28 | }; |
29 | |
30 | struct gb_camera_debugfs_buffer { |
31 | char data[PAGE_SIZE]; |
32 | size_t length; |
33 | }; |
34 | |
35 | enum gb_camera_state { |
36 | GB_CAMERA_STATE_UNCONFIGURED, |
37 | GB_CAMERA_STATE_CONFIGURED, |
38 | }; |
39 | |
40 | /** |
41 | * struct gb_camera - A Greybus Camera Device |
42 | * @connection: the greybus connection for camera management |
43 | * @data_connection: the greybus connection for camera data |
44 | * @data_cport_id: the data CPort ID on the module side |
45 | * @mutex: protects the connection and state fields |
46 | * @state: the current module state |
47 | * @debugfs: debugfs entries for camera protocol operations testing |
48 | * @module: Greybus camera module registered to HOST processor. |
49 | */ |
50 | struct gb_camera { |
51 | struct gb_bundle *bundle; |
52 | struct gb_connection *connection; |
53 | struct gb_connection *data_connection; |
54 | u16 data_cport_id; |
55 | |
56 | struct mutex mutex; |
57 | enum gb_camera_state state; |
58 | |
59 | struct { |
60 | struct dentry *root; |
61 | struct gb_camera_debugfs_buffer *buffers; |
62 | } debugfs; |
63 | |
64 | struct gb_camera_module module; |
65 | }; |
66 | |
67 | struct gb_camera_stream_config { |
68 | unsigned int width; |
69 | unsigned int height; |
70 | unsigned int format; |
71 | unsigned int vc; |
72 | unsigned int dt[2]; |
73 | unsigned int max_size; |
74 | }; |
75 | |
76 | struct gb_camera_fmt_info { |
77 | enum v4l2_mbus_pixelcode mbus_code; |
78 | unsigned int gb_format; |
79 | unsigned int bpp; |
80 | }; |
81 | |
82 | /* GB format to media code map */ |
83 | static const struct gb_camera_fmt_info gb_fmt_info[] = { |
84 | { |
85 | .mbus_code = V4L2_MBUS_FMT_UYVY8_1X16, |
86 | .gb_format = 0x01, |
87 | .bpp = 16, |
88 | }, |
89 | { |
90 | .mbus_code = V4L2_MBUS_FMT_NV12_1x8, |
91 | .gb_format = 0x12, |
92 | .bpp = 12, |
93 | }, |
94 | { |
95 | .mbus_code = V4L2_MBUS_FMT_NV21_1x8, |
96 | .gb_format = 0x13, |
97 | .bpp = 12, |
98 | }, |
99 | { |
100 | .mbus_code = V4L2_MBUS_FMT_YU12_1x8, |
101 | .gb_format = 0x16, |
102 | .bpp = 12, |
103 | }, |
104 | { |
105 | .mbus_code = V4L2_MBUS_FMT_YV12_1x8, |
106 | .gb_format = 0x17, |
107 | .bpp = 12, |
108 | }, |
109 | { |
110 | .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, |
111 | .gb_format = 0x40, |
112 | .bpp = 0, |
113 | }, |
114 | { |
115 | .mbus_code = V4L2_MBUS_FMT_GB_CAM_METADATA_1X8, |
116 | .gb_format = 0x41, |
117 | .bpp = 0, |
118 | }, |
119 | { |
120 | .mbus_code = V4L2_MBUS_FMT_GB_CAM_DEBUG_DATA_1X8, |
121 | .gb_format = 0x42, |
122 | .bpp = 0, |
123 | }, |
124 | { |
125 | .mbus_code = V4L2_MBUS_FMT_SBGGR10_1X10, |
126 | .gb_format = 0x80, |
127 | .bpp = 10, |
128 | }, |
129 | { |
130 | .mbus_code = V4L2_MBUS_FMT_SGBRG10_1X10, |
131 | .gb_format = 0x81, |
132 | .bpp = 10, |
133 | }, |
134 | { |
135 | .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, |
136 | .gb_format = 0x82, |
137 | .bpp = 10, |
138 | }, |
139 | { |
140 | .mbus_code = V4L2_MBUS_FMT_SRGGB10_1X10, |
141 | .gb_format = 0x83, |
142 | .bpp = 10, |
143 | }, |
144 | { |
145 | .mbus_code = V4L2_MBUS_FMT_SBGGR12_1X12, |
146 | .gb_format = 0x84, |
147 | .bpp = 12, |
148 | }, |
149 | { |
150 | .mbus_code = V4L2_MBUS_FMT_SGBRG12_1X12, |
151 | .gb_format = 0x85, |
152 | .bpp = 12, |
153 | }, |
154 | { |
155 | .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, |
156 | .gb_format = 0x86, |
157 | .bpp = 12, |
158 | }, |
159 | { |
160 | .mbus_code = V4L2_MBUS_FMT_SRGGB12_1X12, |
161 | .gb_format = 0x87, |
162 | .bpp = 12, |
163 | }, |
164 | }; |
165 | |
166 | static const struct gb_camera_fmt_info *gb_camera_get_format_info(u16 gb_fmt) |
167 | { |
168 | unsigned int i; |
169 | |
170 | for (i = 0; i < ARRAY_SIZE(gb_fmt_info); i++) { |
171 | if (gb_fmt_info[i].gb_format == gb_fmt) |
172 | return &gb_fmt_info[i]; |
173 | } |
174 | |
175 | return NULL; |
176 | } |
177 | |
178 | #define ES2_APB_CDSI0_CPORT 16 |
179 | #define ES2_APB_CDSI1_CPORT 17 |
180 | |
181 | #define GB_CAMERA_MAX_SETTINGS_SIZE 8192 |
182 | |
183 | #define gcam_dbg(gcam, format...) dev_dbg(&gcam->bundle->dev, format) |
184 | #define gcam_info(gcam, format...) dev_info(&gcam->bundle->dev, format) |
185 | #define gcam_err(gcam, format...) dev_err(&gcam->bundle->dev, format) |
186 | |
187 | static int gb_camera_operation_sync_flags(struct gb_connection *connection, |
188 | int type, unsigned int flags, |
189 | void *request, size_t request_size, |
190 | void *response, size_t *response_size) |
191 | { |
192 | struct gb_operation *operation; |
193 | int ret; |
194 | |
195 | operation = gb_operation_create_flags(connection, type, request_size, |
196 | response_size: *response_size, flags, |
197 | GFP_KERNEL); |
198 | if (!operation) |
199 | return -ENOMEM; |
200 | |
201 | if (request_size) |
202 | memcpy(operation->request->payload, request, request_size); |
203 | |
204 | ret = gb_operation_request_send_sync(operation); |
205 | if (ret) { |
206 | dev_err(&connection->hd->dev, |
207 | "%s: synchronous operation of type 0x%02x failed: %d\n" , |
208 | connection->name, type, ret); |
209 | } else { |
210 | *response_size = operation->response->payload_size; |
211 | |
212 | if (operation->response->payload_size) |
213 | memcpy(response, operation->response->payload, |
214 | operation->response->payload_size); |
215 | } |
216 | |
217 | gb_operation_put(operation); |
218 | |
219 | return ret; |
220 | } |
221 | |
222 | static int gb_camera_get_max_pkt_size(struct gb_camera *gcam, |
223 | struct gb_camera_configure_streams_response *resp) |
224 | { |
225 | unsigned int max_pkt_size = 0; |
226 | unsigned int i; |
227 | |
228 | for (i = 0; i < resp->num_streams; i++) { |
229 | struct gb_camera_stream_config_response *cfg = &resp->config[i]; |
230 | const struct gb_camera_fmt_info *fmt_info; |
231 | unsigned int pkt_size; |
232 | |
233 | fmt_info = gb_camera_get_format_info(gb_fmt: cfg->format); |
234 | if (!fmt_info) { |
235 | gcam_err(gcam, "unsupported greybus image format: %d\n" , |
236 | cfg->format); |
237 | return -EIO; |
238 | } |
239 | |
240 | if (fmt_info->bpp == 0) { |
241 | pkt_size = le32_to_cpu(cfg->max_pkt_size); |
242 | |
243 | if (pkt_size == 0) { |
244 | gcam_err(gcam, |
245 | "Stream %u: invalid zero maximum packet size\n" , |
246 | i); |
247 | return -EIO; |
248 | } |
249 | } else { |
250 | pkt_size = le16_to_cpu(cfg->width) * fmt_info->bpp / 8; |
251 | |
252 | if (pkt_size != le32_to_cpu(cfg->max_pkt_size)) { |
253 | gcam_err(gcam, |
254 | "Stream %u: maximum packet size mismatch (%u/%u)\n" , |
255 | i, pkt_size, cfg->max_pkt_size); |
256 | return -EIO; |
257 | } |
258 | } |
259 | |
260 | max_pkt_size = max(pkt_size, max_pkt_size); |
261 | } |
262 | |
263 | return max_pkt_size; |
264 | } |
265 | |
266 | /* |
267 | * Validate the stream configuration response verifying padding is correctly |
268 | * set and the returned number of streams is supported |
269 | */ |
270 | static const int gb_camera_configure_streams_validate_response(struct gb_camera *gcam, |
271 | struct gb_camera_configure_streams_response *resp, |
272 | unsigned int nstreams) |
273 | { |
274 | unsigned int i; |
275 | |
276 | /* Validate the returned response structure */ |
277 | if (resp->padding[0] || resp->padding[1]) { |
278 | gcam_err(gcam, "response padding != 0\n" ); |
279 | return -EIO; |
280 | } |
281 | |
282 | if (resp->num_streams > nstreams) { |
283 | gcam_err(gcam, "got #streams %u > request %u\n" , |
284 | resp->num_streams, nstreams); |
285 | return -EIO; |
286 | } |
287 | |
288 | for (i = 0; i < resp->num_streams; i++) { |
289 | struct gb_camera_stream_config_response *cfg = &resp->config[i]; |
290 | |
291 | if (cfg->padding) { |
292 | gcam_err(gcam, "stream #%u padding != 0\n" , i); |
293 | return -EIO; |
294 | } |
295 | } |
296 | |
297 | return 0; |
298 | } |
299 | |
300 | /* ----------------------------------------------------------------------------- |
301 | * Hardware Configuration |
302 | */ |
303 | |
304 | static int gb_camera_set_intf_power_mode(struct gb_camera *gcam, u8 intf_id, |
305 | bool hs) |
306 | { |
307 | struct gb_svc *svc = gcam->connection->hd->svc; |
308 | int ret; |
309 | |
310 | if (hs) |
311 | ret = gb_svc_intf_set_power_mode(svc, intf_id, |
312 | GB_SVC_UNIPRO_HS_SERIES_A, |
313 | GB_SVC_UNIPRO_FAST_MODE, tx_gear: 2, tx_nlanes: 2, |
314 | GB_SVC_SMALL_AMPLITUDE, |
315 | GB_SVC_NO_DE_EMPHASIS, |
316 | GB_SVC_UNIPRO_FAST_MODE, rx_gear: 2, rx_nlanes: 2, |
317 | GB_SVC_PWRM_RXTERMINATION | |
318 | GB_SVC_PWRM_TXTERMINATION, quirks: 0, |
319 | NULL, NULL); |
320 | else |
321 | ret = gb_svc_intf_set_power_mode(svc, intf_id, |
322 | GB_SVC_UNIPRO_HS_SERIES_A, |
323 | GB_SVC_UNIPRO_SLOW_AUTO_MODE, |
324 | tx_gear: 2, tx_nlanes: 1, |
325 | GB_SVC_SMALL_AMPLITUDE, |
326 | GB_SVC_NO_DE_EMPHASIS, |
327 | GB_SVC_UNIPRO_SLOW_AUTO_MODE, |
328 | rx_gear: 2, rx_nlanes: 1, |
329 | flags: 0, quirks: 0, |
330 | NULL, NULL); |
331 | |
332 | return ret; |
333 | } |
334 | |
335 | static int gb_camera_set_power_mode(struct gb_camera *gcam, bool hs) |
336 | { |
337 | struct gb_interface *intf = gcam->connection->intf; |
338 | struct gb_svc *svc = gcam->connection->hd->svc; |
339 | int ret; |
340 | |
341 | ret = gb_camera_set_intf_power_mode(gcam, intf_id: intf->interface_id, hs); |
342 | if (ret < 0) { |
343 | gcam_err(gcam, "failed to set module interface to %s (%d)\n" , |
344 | hs ? "HS" : "PWM" , ret); |
345 | return ret; |
346 | } |
347 | |
348 | ret = gb_camera_set_intf_power_mode(gcam, intf_id: svc->ap_intf_id, hs); |
349 | if (ret < 0) { |
350 | gb_camera_set_intf_power_mode(gcam, intf_id: intf->interface_id, hs: !hs); |
351 | gcam_err(gcam, "failed to set AP interface to %s (%d)\n" , |
352 | hs ? "HS" : "PWM" , ret); |
353 | return ret; |
354 | } |
355 | |
356 | return 0; |
357 | } |
358 | |
359 | struct ap_csi_config_request { |
360 | __u8 csi_id; |
361 | __u8 flags; |
362 | #define GB_CAMERA_CSI_FLAG_CLOCK_CONTINUOUS 0x01 |
363 | __u8 num_lanes; |
364 | __u8 padding; |
365 | __le32 csi_clk_freq; |
366 | __le32 max_pkt_size; |
367 | } __packed; |
368 | |
369 | /* |
370 | * TODO: Compute the number of lanes dynamically based on bandwidth |
371 | * requirements. |
372 | */ |
373 | #define GB_CAMERA_CSI_NUM_DATA_LANES 4 |
374 | |
375 | #define GB_CAMERA_CSI_CLK_FREQ_MAX 999000000U |
376 | #define GB_CAMERA_CSI_CLK_FREQ_MIN 100000000U |
377 | #define GB_CAMERA_CSI_CLK_FREQ_MARGIN 150000000U |
378 | |
379 | static int gb_camera_setup_data_connection(struct gb_camera *gcam, |
380 | struct gb_camera_configure_streams_response *resp, |
381 | struct gb_camera_csi_params *csi_params) |
382 | { |
383 | struct ap_csi_config_request csi_cfg; |
384 | struct gb_connection *conn; |
385 | unsigned int clk_freq; |
386 | int ret; |
387 | |
388 | /* |
389 | * Create the data connection between the camera module data CPort and |
390 | * APB CDSI1. The CDSI1 CPort ID is hardcoded by the ES2 bridge. |
391 | */ |
392 | conn = gb_connection_create_offloaded(bundle: gcam->bundle, cport_id: gcam->data_cport_id, |
393 | GB_CONNECTION_FLAG_NO_FLOWCTRL | |
394 | GB_CONNECTION_FLAG_CDSI1); |
395 | if (IS_ERR(ptr: conn)) |
396 | return PTR_ERR(ptr: conn); |
397 | |
398 | gcam->data_connection = conn; |
399 | gb_connection_set_data(connection: conn, data: gcam); |
400 | |
401 | ret = gb_connection_enable(connection: conn); |
402 | if (ret) |
403 | goto error_conn_destroy; |
404 | |
405 | /* Set the UniPro link to high speed mode. */ |
406 | ret = gb_camera_set_power_mode(gcam, hs: true); |
407 | if (ret < 0) |
408 | goto error_conn_disable; |
409 | |
410 | /* |
411 | * Configure the APB-A CSI-2 transmitter. |
412 | * |
413 | * Hardcode the number of lanes to 4 and compute the bus clock frequency |
414 | * based on the module bandwidth requirements with a safety margin. |
415 | */ |
416 | memset(&csi_cfg, 0, sizeof(csi_cfg)); |
417 | csi_cfg.csi_id = 1; |
418 | csi_cfg.flags = 0; |
419 | csi_cfg.num_lanes = GB_CAMERA_CSI_NUM_DATA_LANES; |
420 | |
421 | clk_freq = resp->data_rate / 2 / GB_CAMERA_CSI_NUM_DATA_LANES; |
422 | clk_freq = clamp(clk_freq + GB_CAMERA_CSI_CLK_FREQ_MARGIN, |
423 | GB_CAMERA_CSI_CLK_FREQ_MIN, |
424 | GB_CAMERA_CSI_CLK_FREQ_MAX); |
425 | csi_cfg.csi_clk_freq = clk_freq; |
426 | |
427 | ret = gb_camera_get_max_pkt_size(gcam, resp); |
428 | if (ret < 0) { |
429 | ret = -EIO; |
430 | goto error_power; |
431 | } |
432 | csi_cfg.max_pkt_size = ret; |
433 | |
434 | ret = gb_hd_output(hd: gcam->connection->hd, req: &csi_cfg, |
435 | size: sizeof(csi_cfg), |
436 | GB_APB_REQUEST_CSI_TX_CONTROL, in_irq: false); |
437 | if (ret < 0) { |
438 | gcam_err(gcam, "failed to start the CSI transmitter\n" ); |
439 | goto error_power; |
440 | } |
441 | |
442 | if (csi_params) { |
443 | csi_params->clk_freq = csi_cfg.csi_clk_freq; |
444 | csi_params->num_lanes = csi_cfg.num_lanes; |
445 | } |
446 | |
447 | return 0; |
448 | |
449 | error_power: |
450 | gb_camera_set_power_mode(gcam, hs: false); |
451 | error_conn_disable: |
452 | gb_connection_disable(connection: gcam->data_connection); |
453 | error_conn_destroy: |
454 | gb_connection_destroy(connection: gcam->data_connection); |
455 | gcam->data_connection = NULL; |
456 | return ret; |
457 | } |
458 | |
459 | static void gb_camera_teardown_data_connection(struct gb_camera *gcam) |
460 | { |
461 | struct ap_csi_config_request csi_cfg; |
462 | int ret; |
463 | |
464 | /* Stop the APB1 CSI transmitter. */ |
465 | memset(&csi_cfg, 0, sizeof(csi_cfg)); |
466 | csi_cfg.csi_id = 1; |
467 | |
468 | ret = gb_hd_output(hd: gcam->connection->hd, req: &csi_cfg, |
469 | size: sizeof(csi_cfg), |
470 | GB_APB_REQUEST_CSI_TX_CONTROL, in_irq: false); |
471 | |
472 | if (ret < 0) |
473 | gcam_err(gcam, "failed to stop the CSI transmitter\n" ); |
474 | |
475 | /* Set the UniPro link to low speed mode. */ |
476 | gb_camera_set_power_mode(gcam, hs: false); |
477 | |
478 | /* Destroy the data connection. */ |
479 | gb_connection_disable(connection: gcam->data_connection); |
480 | gb_connection_destroy(connection: gcam->data_connection); |
481 | gcam->data_connection = NULL; |
482 | } |
483 | |
484 | /* ----------------------------------------------------------------------------- |
485 | * Camera Protocol Operations |
486 | */ |
487 | |
488 | static int gb_camera_capabilities(struct gb_camera *gcam, |
489 | u8 *capabilities, size_t *size) |
490 | { |
491 | int ret; |
492 | |
493 | ret = gb_pm_runtime_get_sync(bundle: gcam->bundle); |
494 | if (ret) |
495 | return ret; |
496 | |
497 | mutex_lock(&gcam->mutex); |
498 | |
499 | if (!gcam->connection) { |
500 | ret = -EINVAL; |
501 | goto done; |
502 | } |
503 | |
504 | ret = gb_camera_operation_sync_flags(connection: gcam->connection, |
505 | GB_CAMERA_TYPE_CAPABILITIES, |
506 | GB_OPERATION_FLAG_SHORT_RESPONSE, |
507 | NULL, request_size: 0, |
508 | response: (void *)capabilities, response_size: size); |
509 | if (ret) |
510 | gcam_err(gcam, "failed to retrieve capabilities: %d\n" , ret); |
511 | |
512 | done: |
513 | mutex_unlock(lock: &gcam->mutex); |
514 | |
515 | gb_pm_runtime_put_autosuspend(bundle: gcam->bundle); |
516 | |
517 | return ret; |
518 | } |
519 | |
520 | static int gb_camera_configure_streams(struct gb_camera *gcam, |
521 | unsigned int *num_streams, |
522 | unsigned int *flags, |
523 | struct gb_camera_stream_config *streams, |
524 | struct gb_camera_csi_params *csi_params) |
525 | { |
526 | struct gb_camera_configure_streams_request *req; |
527 | struct gb_camera_configure_streams_response *resp; |
528 | unsigned int nstreams = *num_streams; |
529 | unsigned int i; |
530 | size_t req_size; |
531 | size_t resp_size; |
532 | int ret; |
533 | |
534 | if (nstreams > GB_CAMERA_MAX_STREAMS) |
535 | return -EINVAL; |
536 | |
537 | req_size = sizeof(*req) + nstreams * sizeof(req->config[0]); |
538 | resp_size = sizeof(*resp) + nstreams * sizeof(resp->config[0]); |
539 | |
540 | req = kmalloc(size: req_size, GFP_KERNEL); |
541 | resp = kmalloc(size: resp_size, GFP_KERNEL); |
542 | if (!req || !resp) { |
543 | kfree(objp: req); |
544 | kfree(objp: resp); |
545 | return -ENOMEM; |
546 | } |
547 | |
548 | req->num_streams = nstreams; |
549 | req->flags = *flags; |
550 | req->padding = 0; |
551 | |
552 | for (i = 0; i < nstreams; ++i) { |
553 | struct gb_camera_stream_config_request *cfg = &req->config[i]; |
554 | |
555 | cfg->width = cpu_to_le16(streams[i].width); |
556 | cfg->height = cpu_to_le16(streams[i].height); |
557 | cfg->format = cpu_to_le16(streams[i].format); |
558 | cfg->padding = 0; |
559 | } |
560 | |
561 | mutex_lock(&gcam->mutex); |
562 | |
563 | ret = gb_pm_runtime_get_sync(bundle: gcam->bundle); |
564 | if (ret) |
565 | goto done_skip_pm_put; |
566 | |
567 | if (!gcam->connection) { |
568 | ret = -EINVAL; |
569 | goto done; |
570 | } |
571 | |
572 | ret = gb_camera_operation_sync_flags(connection: gcam->connection, |
573 | GB_CAMERA_TYPE_CONFIGURE_STREAMS, |
574 | GB_OPERATION_FLAG_SHORT_RESPONSE, |
575 | request: req, request_size: req_size, |
576 | response: resp, response_size: &resp_size); |
577 | if (ret < 0) |
578 | goto done; |
579 | |
580 | ret = gb_camera_configure_streams_validate_response(gcam, resp, |
581 | nstreams); |
582 | if (ret < 0) |
583 | goto done; |
584 | |
585 | *flags = resp->flags; |
586 | *num_streams = resp->num_streams; |
587 | |
588 | for (i = 0; i < resp->num_streams; ++i) { |
589 | struct gb_camera_stream_config_response *cfg = &resp->config[i]; |
590 | |
591 | streams[i].width = le16_to_cpu(cfg->width); |
592 | streams[i].height = le16_to_cpu(cfg->height); |
593 | streams[i].format = le16_to_cpu(cfg->format); |
594 | streams[i].vc = cfg->virtual_channel; |
595 | streams[i].dt[0] = cfg->data_type[0]; |
596 | streams[i].dt[1] = cfg->data_type[1]; |
597 | streams[i].max_size = le32_to_cpu(cfg->max_size); |
598 | } |
599 | |
600 | if ((resp->flags & GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED) || |
601 | (req->flags & GB_CAMERA_CONFIGURE_STREAMS_TEST_ONLY)) |
602 | goto done; |
603 | |
604 | if (gcam->state == GB_CAMERA_STATE_CONFIGURED) { |
605 | gb_camera_teardown_data_connection(gcam); |
606 | gcam->state = GB_CAMERA_STATE_UNCONFIGURED; |
607 | |
608 | /* |
609 | * When unconfiguring streams release the PM runtime reference |
610 | * that was acquired when streams were configured. The bundle |
611 | * won't be suspended until the PM runtime reference acquired at |
612 | * the beginning of this function gets released right before |
613 | * returning. |
614 | */ |
615 | gb_pm_runtime_put_noidle(bundle: gcam->bundle); |
616 | } |
617 | |
618 | if (resp->num_streams == 0) |
619 | goto done; |
620 | |
621 | /* |
622 | * Make sure the bundle won't be suspended until streams get |
623 | * unconfigured after the stream is configured successfully |
624 | */ |
625 | gb_pm_runtime_get_noresume(bundle: gcam->bundle); |
626 | |
627 | /* Setup CSI-2 connection from APB-A to AP */ |
628 | ret = gb_camera_setup_data_connection(gcam, resp, csi_params); |
629 | if (ret < 0) { |
630 | memset(req, 0, sizeof(*req)); |
631 | gb_operation_sync(connection: gcam->connection, |
632 | GB_CAMERA_TYPE_CONFIGURE_STREAMS, |
633 | request: req, request_size: sizeof(*req), |
634 | response: resp, response_size: sizeof(*resp)); |
635 | *flags = 0; |
636 | *num_streams = 0; |
637 | gb_pm_runtime_put_noidle(bundle: gcam->bundle); |
638 | goto done; |
639 | } |
640 | |
641 | gcam->state = GB_CAMERA_STATE_CONFIGURED; |
642 | |
643 | done: |
644 | gb_pm_runtime_put_autosuspend(bundle: gcam->bundle); |
645 | |
646 | done_skip_pm_put: |
647 | mutex_unlock(lock: &gcam->mutex); |
648 | kfree(objp: req); |
649 | kfree(objp: resp); |
650 | return ret; |
651 | } |
652 | |
653 | static int gb_camera_capture(struct gb_camera *gcam, u32 request_id, |
654 | unsigned int streams, unsigned int num_frames, |
655 | size_t settings_size, const void *settings) |
656 | { |
657 | struct gb_camera_capture_request *req; |
658 | size_t req_size; |
659 | int ret; |
660 | |
661 | if (settings_size > GB_CAMERA_MAX_SETTINGS_SIZE) |
662 | return -EINVAL; |
663 | |
664 | req_size = sizeof(*req) + settings_size; |
665 | req = kmalloc(size: req_size, GFP_KERNEL); |
666 | if (!req) |
667 | return -ENOMEM; |
668 | |
669 | req->request_id = cpu_to_le32(request_id); |
670 | req->streams = streams; |
671 | req->padding = 0; |
672 | req->num_frames = cpu_to_le16(num_frames); |
673 | memcpy(req->settings, settings, settings_size); |
674 | |
675 | mutex_lock(&gcam->mutex); |
676 | |
677 | if (!gcam->connection) { |
678 | ret = -EINVAL; |
679 | goto done; |
680 | } |
681 | |
682 | ret = gb_operation_sync(connection: gcam->connection, GB_CAMERA_TYPE_CAPTURE, |
683 | request: req, request_size: req_size, NULL, response_size: 0); |
684 | done: |
685 | mutex_unlock(lock: &gcam->mutex); |
686 | |
687 | kfree(objp: req); |
688 | |
689 | return ret; |
690 | } |
691 | |
692 | static int gb_camera_flush(struct gb_camera *gcam, u32 *request_id) |
693 | { |
694 | struct gb_camera_flush_response resp; |
695 | int ret; |
696 | |
697 | mutex_lock(&gcam->mutex); |
698 | |
699 | if (!gcam->connection) { |
700 | ret = -EINVAL; |
701 | goto done; |
702 | } |
703 | |
704 | ret = gb_operation_sync(connection: gcam->connection, GB_CAMERA_TYPE_FLUSH, NULL, request_size: 0, |
705 | response: &resp, response_size: sizeof(resp)); |
706 | |
707 | if (ret < 0) |
708 | goto done; |
709 | |
710 | if (request_id) |
711 | *request_id = le32_to_cpu(resp.request_id); |
712 | |
713 | done: |
714 | mutex_unlock(lock: &gcam->mutex); |
715 | |
716 | return ret; |
717 | } |
718 | |
719 | static int gb_camera_request_handler(struct gb_operation *op) |
720 | { |
721 | struct gb_camera *gcam = gb_connection_get_data(connection: op->connection); |
722 | struct gb_camera_metadata_request *payload; |
723 | struct gb_message *request; |
724 | |
725 | if (op->type != GB_CAMERA_TYPE_METADATA) { |
726 | gcam_err(gcam, "Unsupported unsolicited event: %u\n" , op->type); |
727 | return -EINVAL; |
728 | } |
729 | |
730 | request = op->request; |
731 | |
732 | if (request->payload_size < sizeof(*payload)) { |
733 | gcam_err(gcam, "Wrong event size received (%zu < %zu)\n" , |
734 | request->payload_size, sizeof(*payload)); |
735 | return -EINVAL; |
736 | } |
737 | |
738 | payload = request->payload; |
739 | |
740 | gcam_dbg(gcam, "received metadata for request %u, frame %u, stream %u\n" , |
741 | payload->request_id, payload->frame_number, payload->stream); |
742 | |
743 | return 0; |
744 | } |
745 | |
746 | /* ----------------------------------------------------------------------------- |
747 | * Interface with HOST gmp camera. |
748 | */ |
749 | static unsigned int gb_camera_mbus_to_gb(enum v4l2_mbus_pixelcode mbus_code) |
750 | { |
751 | unsigned int i; |
752 | |
753 | for (i = 0; i < ARRAY_SIZE(gb_fmt_info); i++) { |
754 | if (gb_fmt_info[i].mbus_code == mbus_code) |
755 | return gb_fmt_info[i].gb_format; |
756 | } |
757 | return gb_fmt_info[0].gb_format; |
758 | } |
759 | |
760 | static enum v4l2_mbus_pixelcode gb_camera_gb_to_mbus(u16 gb_fmt) |
761 | { |
762 | unsigned int i; |
763 | |
764 | for (i = 0; i < ARRAY_SIZE(gb_fmt_info); i++) { |
765 | if (gb_fmt_info[i].gb_format == gb_fmt) |
766 | return gb_fmt_info[i].mbus_code; |
767 | } |
768 | return gb_fmt_info[0].mbus_code; |
769 | } |
770 | |
771 | static ssize_t gb_camera_op_capabilities(void *priv, char *data, size_t len) |
772 | { |
773 | struct gb_camera *gcam = priv; |
774 | size_t capabilities_len = len; |
775 | int ret; |
776 | |
777 | ret = gb_camera_capabilities(gcam, capabilities: data, size: &capabilities_len); |
778 | if (ret) |
779 | return ret; |
780 | |
781 | return capabilities_len; |
782 | } |
783 | |
784 | static int gb_camera_op_configure_streams(void *priv, unsigned int *nstreams, |
785 | unsigned int *flags, struct gb_camera_stream *streams, |
786 | struct gb_camera_csi_params *csi_params) |
787 | { |
788 | struct gb_camera *gcam = priv; |
789 | struct gb_camera_stream_config *gb_streams; |
790 | unsigned int gb_flags = 0; |
791 | unsigned int gb_nstreams = *nstreams; |
792 | unsigned int i; |
793 | int ret; |
794 | |
795 | if (gb_nstreams > GB_CAMERA_MAX_STREAMS) |
796 | return -EINVAL; |
797 | |
798 | gb_streams = kcalloc(n: gb_nstreams, size: sizeof(*gb_streams), GFP_KERNEL); |
799 | if (!gb_streams) |
800 | return -ENOMEM; |
801 | |
802 | for (i = 0; i < gb_nstreams; i++) { |
803 | gb_streams[i].width = streams[i].width; |
804 | gb_streams[i].height = streams[i].height; |
805 | gb_streams[i].format = |
806 | gb_camera_mbus_to_gb(mbus_code: streams[i].pixel_code); |
807 | } |
808 | |
809 | if (*flags & GB_CAMERA_IN_FLAG_TEST) |
810 | gb_flags |= GB_CAMERA_CONFIGURE_STREAMS_TEST_ONLY; |
811 | |
812 | ret = gb_camera_configure_streams(gcam, num_streams: &gb_nstreams, |
813 | flags: &gb_flags, streams: gb_streams, csi_params); |
814 | if (ret < 0) |
815 | goto done; |
816 | if (gb_nstreams > *nstreams) { |
817 | ret = -EINVAL; |
818 | goto done; |
819 | } |
820 | |
821 | *flags = 0; |
822 | if (gb_flags & GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED) |
823 | *flags |= GB_CAMERA_OUT_FLAG_ADJUSTED; |
824 | |
825 | for (i = 0; i < gb_nstreams; i++) { |
826 | streams[i].width = gb_streams[i].width; |
827 | streams[i].height = gb_streams[i].height; |
828 | streams[i].vc = gb_streams[i].vc; |
829 | streams[i].dt[0] = gb_streams[i].dt[0]; |
830 | streams[i].dt[1] = gb_streams[i].dt[1]; |
831 | streams[i].max_size = gb_streams[i].max_size; |
832 | streams[i].pixel_code = |
833 | gb_camera_gb_to_mbus(gb_streams[i].format); |
834 | } |
835 | *nstreams = gb_nstreams; |
836 | |
837 | done: |
838 | kfree(objp: gb_streams); |
839 | return ret; |
840 | } |
841 | |
842 | static int gb_camera_op_capture(void *priv, u32 request_id, |
843 | unsigned int streams, unsigned int num_frames, |
844 | size_t settings_size, const void *settings) |
845 | { |
846 | struct gb_camera *gcam = priv; |
847 | |
848 | return gb_camera_capture(gcam, request_id, streams, num_frames, |
849 | settings_size, settings); |
850 | } |
851 | |
852 | static int gb_camera_op_flush(void *priv, u32 *request_id) |
853 | { |
854 | struct gb_camera *gcam = priv; |
855 | |
856 | return gb_camera_flush(gcam, request_id); |
857 | } |
858 | |
859 | static const struct gb_camera_ops gb_cam_ops = { |
860 | .capabilities = gb_camera_op_capabilities, |
861 | .configure_streams = gb_camera_op_configure_streams, |
862 | .capture = gb_camera_op_capture, |
863 | .flush = gb_camera_op_flush, |
864 | }; |
865 | |
866 | /* ----------------------------------------------------------------------------- |
867 | * DebugFS |
868 | */ |
869 | |
870 | static ssize_t gb_camera_debugfs_capabilities(struct gb_camera *gcam, |
871 | char *buf, size_t len) |
872 | { |
873 | struct gb_camera_debugfs_buffer *buffer = |
874 | &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES]; |
875 | size_t size = 1024; |
876 | unsigned int i; |
877 | u8 *caps; |
878 | int ret; |
879 | |
880 | caps = kmalloc(size, GFP_KERNEL); |
881 | if (!caps) |
882 | return -ENOMEM; |
883 | |
884 | ret = gb_camera_capabilities(gcam, capabilities: caps, size: &size); |
885 | if (ret < 0) |
886 | goto done; |
887 | |
888 | /* |
889 | * hex_dump_to_buffer() doesn't return the number of bytes dumped prior |
890 | * to v4.0, we need our own implementation :-( |
891 | */ |
892 | buffer->length = 0; |
893 | |
894 | for (i = 0; i < size; i += 16) { |
895 | unsigned int nbytes = min_t(unsigned int, size - i, 16); |
896 | |
897 | buffer->length += sprintf(buf: buffer->data + buffer->length, |
898 | fmt: "%*ph\n" , nbytes, caps + i); |
899 | } |
900 | |
901 | done: |
902 | kfree(objp: caps); |
903 | return ret; |
904 | } |
905 | |
906 | static ssize_t gb_camera_debugfs_configure_streams(struct gb_camera *gcam, |
907 | char *buf, size_t len) |
908 | { |
909 | struct gb_camera_debugfs_buffer *buffer = |
910 | &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_STREAMS]; |
911 | struct gb_camera_stream_config *streams; |
912 | unsigned int nstreams; |
913 | unsigned int flags; |
914 | unsigned int i; |
915 | char *token; |
916 | int ret; |
917 | |
918 | /* Retrieve number of streams to configure */ |
919 | token = strsep(&buf, ";" ); |
920 | if (!token) |
921 | return -EINVAL; |
922 | |
923 | ret = kstrtouint(s: token, base: 10, res: &nstreams); |
924 | if (ret < 0) |
925 | return ret; |
926 | |
927 | if (nstreams > GB_CAMERA_MAX_STREAMS) |
928 | return -EINVAL; |
929 | |
930 | token = strsep(&buf, ";" ); |
931 | if (!token) |
932 | return -EINVAL; |
933 | |
934 | ret = kstrtouint(s: token, base: 10, res: &flags); |
935 | if (ret < 0) |
936 | return ret; |
937 | |
938 | /* For each stream to configure parse width, height and format */ |
939 | streams = kcalloc(n: nstreams, size: sizeof(*streams), GFP_KERNEL); |
940 | if (!streams) |
941 | return -ENOMEM; |
942 | |
943 | for (i = 0; i < nstreams; ++i) { |
944 | struct gb_camera_stream_config *stream = &streams[i]; |
945 | |
946 | /* width */ |
947 | token = strsep(&buf, ";" ); |
948 | if (!token) { |
949 | ret = -EINVAL; |
950 | goto done; |
951 | } |
952 | ret = kstrtouint(s: token, base: 10, res: &stream->width); |
953 | if (ret < 0) |
954 | goto done; |
955 | |
956 | /* height */ |
957 | token = strsep(&buf, ";" ); |
958 | if (!token) |
959 | goto done; |
960 | |
961 | ret = kstrtouint(s: token, base: 10, res: &stream->height); |
962 | if (ret < 0) |
963 | goto done; |
964 | |
965 | /* Image format code */ |
966 | token = strsep(&buf, ";" ); |
967 | if (!token) |
968 | goto done; |
969 | |
970 | ret = kstrtouint(s: token, base: 16, res: &stream->format); |
971 | if (ret < 0) |
972 | goto done; |
973 | } |
974 | |
975 | ret = gb_camera_configure_streams(gcam, num_streams: &nstreams, flags: &flags, streams, |
976 | NULL); |
977 | if (ret < 0) |
978 | goto done; |
979 | |
980 | buffer->length = sprintf(buf: buffer->data, fmt: "%u;%u;" , nstreams, flags); |
981 | |
982 | for (i = 0; i < nstreams; ++i) { |
983 | struct gb_camera_stream_config *stream = &streams[i]; |
984 | |
985 | buffer->length += sprintf(buf: buffer->data + buffer->length, |
986 | fmt: "%u;%u;%u;%u;%u;%u;%u;" , |
987 | stream->width, stream->height, |
988 | stream->format, stream->vc, |
989 | stream->dt[0], stream->dt[1], |
990 | stream->max_size); |
991 | } |
992 | |
993 | ret = len; |
994 | |
995 | done: |
996 | kfree(objp: streams); |
997 | return ret; |
998 | }; |
999 | |
1000 | static ssize_t gb_camera_debugfs_capture(struct gb_camera *gcam, |
1001 | char *buf, size_t len) |
1002 | { |
1003 | unsigned int request_id; |
1004 | unsigned int streams_mask; |
1005 | unsigned int num_frames; |
1006 | char *token; |
1007 | int ret; |
1008 | |
1009 | /* Request id */ |
1010 | token = strsep(&buf, ";" ); |
1011 | if (!token) |
1012 | return -EINVAL; |
1013 | ret = kstrtouint(s: token, base: 10, res: &request_id); |
1014 | if (ret < 0) |
1015 | return ret; |
1016 | |
1017 | /* Stream mask */ |
1018 | token = strsep(&buf, ";" ); |
1019 | if (!token) |
1020 | return -EINVAL; |
1021 | ret = kstrtouint(s: token, base: 16, res: &streams_mask); |
1022 | if (ret < 0) |
1023 | return ret; |
1024 | |
1025 | /* number of frames */ |
1026 | token = strsep(&buf, ";" ); |
1027 | if (!token) |
1028 | return -EINVAL; |
1029 | ret = kstrtouint(s: token, base: 10, res: &num_frames); |
1030 | if (ret < 0) |
1031 | return ret; |
1032 | |
1033 | ret = gb_camera_capture(gcam, request_id, streams: streams_mask, num_frames, settings_size: 0, |
1034 | NULL); |
1035 | if (ret < 0) |
1036 | return ret; |
1037 | |
1038 | return len; |
1039 | } |
1040 | |
1041 | static ssize_t gb_camera_debugfs_flush(struct gb_camera *gcam, |
1042 | char *buf, size_t len) |
1043 | { |
1044 | struct gb_camera_debugfs_buffer *buffer = |
1045 | &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_FLUSH]; |
1046 | unsigned int req_id; |
1047 | int ret; |
1048 | |
1049 | ret = gb_camera_flush(gcam, request_id: &req_id); |
1050 | if (ret < 0) |
1051 | return ret; |
1052 | |
1053 | buffer->length = sprintf(buf: buffer->data, fmt: "%u" , req_id); |
1054 | |
1055 | return len; |
1056 | } |
1057 | |
1058 | struct gb_camera_debugfs_entry { |
1059 | const char *name; |
1060 | unsigned int mask; |
1061 | unsigned int buffer; |
1062 | ssize_t (*execute)(struct gb_camera *gcam, char *buf, size_t len); |
1063 | }; |
1064 | |
1065 | static const struct gb_camera_debugfs_entry gb_camera_debugfs_entries[] = { |
1066 | { |
1067 | .name = "capabilities" , |
1068 | .mask = S_IFREG | 0444, |
1069 | .buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES, |
1070 | .execute = gb_camera_debugfs_capabilities, |
1071 | }, { |
1072 | .name = "configure_streams" , |
1073 | .mask = S_IFREG | 0666, |
1074 | .buffer = GB_CAMERA_DEBUGFS_BUFFER_STREAMS, |
1075 | .execute = gb_camera_debugfs_configure_streams, |
1076 | }, { |
1077 | .name = "capture" , |
1078 | .mask = S_IFREG | 0666, |
1079 | .buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPTURE, |
1080 | .execute = gb_camera_debugfs_capture, |
1081 | }, { |
1082 | .name = "flush" , |
1083 | .mask = S_IFREG | 0666, |
1084 | .buffer = GB_CAMERA_DEBUGFS_BUFFER_FLUSH, |
1085 | .execute = gb_camera_debugfs_flush, |
1086 | }, |
1087 | }; |
1088 | |
1089 | static ssize_t gb_camera_debugfs_read(struct file *file, char __user *buf, |
1090 | size_t len, loff_t *offset) |
1091 | { |
1092 | const struct gb_camera_debugfs_entry *op = file->private_data; |
1093 | struct gb_camera *gcam = file_inode(f: file)->i_private; |
1094 | struct gb_camera_debugfs_buffer *buffer; |
1095 | ssize_t ret; |
1096 | |
1097 | /* For read-only entries the operation is triggered by a read. */ |
1098 | if (!(op->mask & 0222)) { |
1099 | ret = op->execute(gcam, NULL, 0); |
1100 | if (ret < 0) |
1101 | return ret; |
1102 | } |
1103 | |
1104 | buffer = &gcam->debugfs.buffers[op->buffer]; |
1105 | |
1106 | return simple_read_from_buffer(to: buf, count: len, ppos: offset, from: buffer->data, |
1107 | available: buffer->length); |
1108 | } |
1109 | |
1110 | static ssize_t gb_camera_debugfs_write(struct file *file, |
1111 | const char __user *buf, size_t len, |
1112 | loff_t *offset) |
1113 | { |
1114 | const struct gb_camera_debugfs_entry *op = file->private_data; |
1115 | struct gb_camera *gcam = file_inode(f: file)->i_private; |
1116 | ssize_t ret; |
1117 | char *kbuf; |
1118 | |
1119 | if (len > 1024) |
1120 | return -EINVAL; |
1121 | |
1122 | kbuf = memdup_user_nul(buf, len); |
1123 | if (IS_ERR(ptr: kbuf)) |
1124 | return PTR_ERR(ptr: kbuf); |
1125 | |
1126 | ret = op->execute(gcam, kbuf, len); |
1127 | |
1128 | done: |
1129 | kfree(objp: kbuf); |
1130 | return ret; |
1131 | } |
1132 | |
1133 | static int gb_camera_debugfs_open(struct inode *inode, struct file *file) |
1134 | { |
1135 | unsigned int i; |
1136 | |
1137 | for (i = 0; i < ARRAY_SIZE(gb_camera_debugfs_entries); ++i) { |
1138 | const struct gb_camera_debugfs_entry *entry = |
1139 | &gb_camera_debugfs_entries[i]; |
1140 | |
1141 | if (!strcmp(file->f_path.dentry->d_iname, entry->name)) { |
1142 | file->private_data = (void *)entry; |
1143 | break; |
1144 | } |
1145 | } |
1146 | |
1147 | return 0; |
1148 | } |
1149 | |
1150 | static const struct file_operations gb_camera_debugfs_ops = { |
1151 | .open = gb_camera_debugfs_open, |
1152 | .read = gb_camera_debugfs_read, |
1153 | .write = gb_camera_debugfs_write, |
1154 | }; |
1155 | |
1156 | static int gb_camera_debugfs_init(struct gb_camera *gcam) |
1157 | { |
1158 | struct gb_connection *connection = gcam->connection; |
1159 | char dirname[27]; |
1160 | unsigned int i; |
1161 | |
1162 | /* |
1163 | * Create root debugfs entry and a file entry for each camera operation. |
1164 | */ |
1165 | snprintf(buf: dirname, size: 27, fmt: "camera-%u.%u" , connection->intf->interface_id, |
1166 | gcam->bundle->id); |
1167 | |
1168 | gcam->debugfs.root = debugfs_create_dir(name: dirname, parent: gb_debugfs_get()); |
1169 | |
1170 | gcam->debugfs.buffers = |
1171 | vmalloc(array_size(GB_CAMERA_DEBUGFS_BUFFER_MAX, |
1172 | sizeof(*gcam->debugfs.buffers))); |
1173 | if (!gcam->debugfs.buffers) |
1174 | return -ENOMEM; |
1175 | |
1176 | for (i = 0; i < ARRAY_SIZE(gb_camera_debugfs_entries); ++i) { |
1177 | const struct gb_camera_debugfs_entry *entry = |
1178 | &gb_camera_debugfs_entries[i]; |
1179 | |
1180 | gcam->debugfs.buffers[i].length = 0; |
1181 | |
1182 | debugfs_create_file(name: entry->name, mode: entry->mask, |
1183 | parent: gcam->debugfs.root, data: gcam, |
1184 | fops: &gb_camera_debugfs_ops); |
1185 | } |
1186 | |
1187 | return 0; |
1188 | } |
1189 | |
1190 | static void gb_camera_debugfs_cleanup(struct gb_camera *gcam) |
1191 | { |
1192 | debugfs_remove_recursive(dentry: gcam->debugfs.root); |
1193 | |
1194 | vfree(addr: gcam->debugfs.buffers); |
1195 | } |
1196 | |
1197 | /* ----------------------------------------------------------------------------- |
1198 | * Init & Cleanup |
1199 | */ |
1200 | |
1201 | static void gb_camera_cleanup(struct gb_camera *gcam) |
1202 | { |
1203 | gb_camera_debugfs_cleanup(gcam); |
1204 | |
1205 | mutex_lock(&gcam->mutex); |
1206 | if (gcam->data_connection) { |
1207 | gb_connection_disable(connection: gcam->data_connection); |
1208 | gb_connection_destroy(connection: gcam->data_connection); |
1209 | gcam->data_connection = NULL; |
1210 | } |
1211 | |
1212 | if (gcam->connection) { |
1213 | gb_connection_disable(connection: gcam->connection); |
1214 | gb_connection_destroy(connection: gcam->connection); |
1215 | gcam->connection = NULL; |
1216 | } |
1217 | mutex_unlock(lock: &gcam->mutex); |
1218 | } |
1219 | |
1220 | static void gb_camera_release_module(struct kref *ref) |
1221 | { |
1222 | struct gb_camera_module *cam_mod = |
1223 | container_of(ref, struct gb_camera_module, refcount); |
1224 | kfree(objp: cam_mod->priv); |
1225 | } |
1226 | |
1227 | static int gb_camera_probe(struct gb_bundle *bundle, |
1228 | const struct greybus_bundle_id *id) |
1229 | { |
1230 | struct gb_connection *conn; |
1231 | struct gb_camera *gcam; |
1232 | u16 mgmt_cport_id = 0; |
1233 | u16 data_cport_id = 0; |
1234 | unsigned int i; |
1235 | int ret; |
1236 | |
1237 | /* |
1238 | * The camera bundle must contain exactly two CPorts, one for the |
1239 | * camera management protocol and one for the camera data protocol. |
1240 | */ |
1241 | if (bundle->num_cports != 2) |
1242 | return -ENODEV; |
1243 | |
1244 | for (i = 0; i < bundle->num_cports; ++i) { |
1245 | struct greybus_descriptor_cport *desc = &bundle->cport_desc[i]; |
1246 | |
1247 | switch (desc->protocol_id) { |
1248 | case GREYBUS_PROTOCOL_CAMERA_MGMT: |
1249 | mgmt_cport_id = le16_to_cpu(desc->id); |
1250 | break; |
1251 | case GREYBUS_PROTOCOL_CAMERA_DATA: |
1252 | data_cport_id = le16_to_cpu(desc->id); |
1253 | break; |
1254 | default: |
1255 | return -ENODEV; |
1256 | } |
1257 | } |
1258 | |
1259 | if (!mgmt_cport_id || !data_cport_id) |
1260 | return -ENODEV; |
1261 | |
1262 | gcam = kzalloc(size: sizeof(*gcam), GFP_KERNEL); |
1263 | if (!gcam) |
1264 | return -ENOMEM; |
1265 | |
1266 | mutex_init(&gcam->mutex); |
1267 | |
1268 | gcam->bundle = bundle; |
1269 | gcam->state = GB_CAMERA_STATE_UNCONFIGURED; |
1270 | gcam->data_cport_id = data_cport_id; |
1271 | |
1272 | conn = gb_connection_create(bundle, cport_id: mgmt_cport_id, |
1273 | handler: gb_camera_request_handler); |
1274 | if (IS_ERR(ptr: conn)) { |
1275 | ret = PTR_ERR(ptr: conn); |
1276 | goto error; |
1277 | } |
1278 | |
1279 | gcam->connection = conn; |
1280 | gb_connection_set_data(connection: conn, data: gcam); |
1281 | |
1282 | ret = gb_connection_enable(connection: conn); |
1283 | if (ret) |
1284 | goto error; |
1285 | |
1286 | ret = gb_camera_debugfs_init(gcam); |
1287 | if (ret < 0) |
1288 | goto error; |
1289 | |
1290 | gcam->module.priv = gcam; |
1291 | gcam->module.ops = &gb_cam_ops; |
1292 | gcam->module.interface_id = gcam->connection->intf->interface_id; |
1293 | gcam->module.release = gb_camera_release_module; |
1294 | ret = gb_camera_register(module: &gcam->module); |
1295 | if (ret < 0) |
1296 | goto error; |
1297 | |
1298 | greybus_set_drvdata(bundle, data: gcam); |
1299 | |
1300 | gb_pm_runtime_put_autosuspend(bundle: gcam->bundle); |
1301 | |
1302 | return 0; |
1303 | |
1304 | error: |
1305 | gb_camera_cleanup(gcam); |
1306 | kfree(objp: gcam); |
1307 | return ret; |
1308 | } |
1309 | |
1310 | static void gb_camera_disconnect(struct gb_bundle *bundle) |
1311 | { |
1312 | struct gb_camera *gcam = greybus_get_drvdata(bundle); |
1313 | int ret; |
1314 | |
1315 | ret = gb_pm_runtime_get_sync(bundle); |
1316 | if (ret) |
1317 | gb_pm_runtime_get_noresume(bundle); |
1318 | |
1319 | gb_camera_cleanup(gcam); |
1320 | gb_camera_unregister(module: &gcam->module); |
1321 | } |
1322 | |
1323 | static const struct greybus_bundle_id gb_camera_id_table[] = { |
1324 | { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) }, |
1325 | { }, |
1326 | }; |
1327 | |
1328 | #ifdef CONFIG_PM |
1329 | static int gb_camera_suspend(struct device *dev) |
1330 | { |
1331 | struct gb_bundle *bundle = to_gb_bundle(dev); |
1332 | struct gb_camera *gcam = greybus_get_drvdata(bundle); |
1333 | |
1334 | if (gcam->data_connection) |
1335 | gb_connection_disable(connection: gcam->data_connection); |
1336 | |
1337 | gb_connection_disable(connection: gcam->connection); |
1338 | |
1339 | return 0; |
1340 | } |
1341 | |
1342 | static int gb_camera_resume(struct device *dev) |
1343 | { |
1344 | struct gb_bundle *bundle = to_gb_bundle(dev); |
1345 | struct gb_camera *gcam = greybus_get_drvdata(bundle); |
1346 | int ret; |
1347 | |
1348 | ret = gb_connection_enable(connection: gcam->connection); |
1349 | if (ret) { |
1350 | gcam_err(gcam, "failed to enable connection: %d\n" , ret); |
1351 | return ret; |
1352 | } |
1353 | |
1354 | if (gcam->data_connection) { |
1355 | ret = gb_connection_enable(connection: gcam->data_connection); |
1356 | if (ret) { |
1357 | gcam_err(gcam, |
1358 | "failed to enable data connection: %d\n" , ret); |
1359 | return ret; |
1360 | } |
1361 | } |
1362 | |
1363 | return 0; |
1364 | } |
1365 | #endif |
1366 | |
1367 | static const struct dev_pm_ops gb_camera_pm_ops = { |
1368 | SET_RUNTIME_PM_OPS(gb_camera_suspend, gb_camera_resume, NULL) |
1369 | }; |
1370 | |
1371 | static struct greybus_driver gb_camera_driver = { |
1372 | .name = "camera" , |
1373 | .probe = gb_camera_probe, |
1374 | .disconnect = gb_camera_disconnect, |
1375 | .id_table = gb_camera_id_table, |
1376 | .driver.pm = &gb_camera_pm_ops, |
1377 | }; |
1378 | |
1379 | module_greybus_driver(gb_camera_driver); |
1380 | |
1381 | MODULE_LICENSE("GPL v2" ); |
1382 | |