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