13265edafSLaurent Pinchart /* 23265edafSLaurent Pinchart * Greybus Camera protocol driver. 33265edafSLaurent Pinchart * 43265edafSLaurent Pinchart * Copyright 2015 Google Inc. 53265edafSLaurent Pinchart * Copyright 2015 Linaro Ltd. 63265edafSLaurent Pinchart * 73265edafSLaurent Pinchart * Released under the GPLv2 only. 83265edafSLaurent Pinchart */ 93265edafSLaurent Pinchart 103265edafSLaurent Pinchart #include <linux/debugfs.h> 113265edafSLaurent Pinchart #include <linux/fs.h> 123265edafSLaurent Pinchart #include <linux/kernel.h> 133265edafSLaurent Pinchart #include <linux/module.h> 143265edafSLaurent Pinchart #include <linux/slab.h> 153265edafSLaurent Pinchart #include <linux/string.h> 163265edafSLaurent Pinchart #include <linux/uaccess.h> 173265edafSLaurent Pinchart #include <linux/vmalloc.h> 183265edafSLaurent Pinchart 193a8dba4eSGjorgji Rosikopulos #include "gb-camera.h" 203265edafSLaurent Pinchart #include "greybus.h" 213265edafSLaurent Pinchart #include "greybus_protocols.h" 223265edafSLaurent Pinchart 233265edafSLaurent Pinchart enum gb_camera_debugs_buffer_id { 243265edafSLaurent Pinchart GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES, 253265edafSLaurent Pinchart GB_CAMERA_DEBUGFS_BUFFER_STREAMS, 263265edafSLaurent Pinchart GB_CAMERA_DEBUGFS_BUFFER_CAPTURE, 273265edafSLaurent Pinchart GB_CAMERA_DEBUGFS_BUFFER_FLUSH, 283265edafSLaurent Pinchart GB_CAMERA_DEBUGFS_BUFFER_MAX, 293265edafSLaurent Pinchart }; 303265edafSLaurent Pinchart 313265edafSLaurent Pinchart struct gb_camera_debugfs_buffer { 323265edafSLaurent Pinchart char data[PAGE_SIZE]; 333265edafSLaurent Pinchart size_t length; 343265edafSLaurent Pinchart }; 353265edafSLaurent Pinchart 363265edafSLaurent Pinchart /** 373265edafSLaurent Pinchart * struct gb_camera - A Greybus Camera Device 383265edafSLaurent Pinchart * @connection: the greybus connection for camera control 393265edafSLaurent Pinchart * @data_connected: whether the data connection has been established 403265edafSLaurent Pinchart * @debugfs: debugfs entries for camera protocol operations testing 413265edafSLaurent Pinchart */ 423265edafSLaurent Pinchart struct gb_camera { 433265edafSLaurent Pinchart struct gb_connection *connection; 443265edafSLaurent Pinchart bool data_connected; 453265edafSLaurent Pinchart 463265edafSLaurent Pinchart struct { 473265edafSLaurent Pinchart struct dentry *root; 483265edafSLaurent Pinchart struct gb_camera_debugfs_buffer *buffers; 493265edafSLaurent Pinchart } debugfs; 503265edafSLaurent Pinchart }; 513265edafSLaurent Pinchart 523265edafSLaurent Pinchart struct gb_camera_stream_config { 533265edafSLaurent Pinchart unsigned int width; 543265edafSLaurent Pinchart unsigned int height; 553265edafSLaurent Pinchart unsigned int format; 563265edafSLaurent Pinchart unsigned int vc; 573265edafSLaurent Pinchart unsigned int dt[2]; 583265edafSLaurent Pinchart unsigned int max_size; 593265edafSLaurent Pinchart }; 603265edafSLaurent Pinchart 613a8dba4eSGjorgji Rosikopulos struct gb_camera_fmt_map { 623a8dba4eSGjorgji Rosikopulos enum v4l2_mbus_pixelcode mbus_code; 633a8dba4eSGjorgji Rosikopulos unsigned int gb_format; 643a8dba4eSGjorgji Rosikopulos }; 653a8dba4eSGjorgji Rosikopulos 663a8dba4eSGjorgji Rosikopulos /* GB format to media code map */ 673a8dba4eSGjorgji Rosikopulos static const struct gb_camera_fmt_map mbus_to_gbus_format[] = { 683a8dba4eSGjorgji Rosikopulos { 693a8dba4eSGjorgji Rosikopulos .mbus_code = V4L2_MBUS_FMT_UYVY8_1X16, 703a8dba4eSGjorgji Rosikopulos .gb_format = 0x01, 713a8dba4eSGjorgji Rosikopulos }, 723a8dba4eSGjorgji Rosikopulos { 733a8dba4eSGjorgji Rosikopulos .mbus_code = V4L2_MBUS_FMT_YUYV8_1_5X8, 743a8dba4eSGjorgji Rosikopulos .gb_format = 0x16, 753a8dba4eSGjorgji Rosikopulos }, 763a8dba4eSGjorgji Rosikopulos { 773a8dba4eSGjorgji Rosikopulos .mbus_code = V4L2_MBUS_FMT_YVYU8_1_5X8, 783a8dba4eSGjorgji Rosikopulos .gb_format = 0x17, 793a8dba4eSGjorgji Rosikopulos }, 803a8dba4eSGjorgji Rosikopulos { 813a8dba4eSGjorgji Rosikopulos .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, 823a8dba4eSGjorgji Rosikopulos .gb_format = 0x40, 833a8dba4eSGjorgji Rosikopulos } 843a8dba4eSGjorgji Rosikopulos }; 853a8dba4eSGjorgji Rosikopulos 863265edafSLaurent Pinchart #define ES2_APB_CDSI0_CPORT 16 873265edafSLaurent Pinchart #define ES2_APB_CDSI1_CPORT 17 883265edafSLaurent Pinchart 893265edafSLaurent Pinchart #define GB_CAMERA_MAX_SETTINGS_SIZE 8192 903265edafSLaurent Pinchart 913265edafSLaurent Pinchart #define gcam_dbg(gcam, format...) \ 923265edafSLaurent Pinchart dev_dbg(&gcam->connection->bundle->dev, format) 933265edafSLaurent Pinchart #define gcam_info(gcam, format...) \ 943265edafSLaurent Pinchart dev_info(&gcam->connection->bundle->dev, format) 953265edafSLaurent Pinchart #define gcam_err(gcam, format...) \ 963265edafSLaurent Pinchart dev_err(&gcam->connection->bundle->dev, format) 973265edafSLaurent Pinchart 983265edafSLaurent Pinchart /* ----------------------------------------------------------------------------- 993265edafSLaurent Pinchart * Camera Protocol Operations 1003265edafSLaurent Pinchart */ 1013265edafSLaurent Pinchart 102ed4596e9SGreg Kroah-Hartman struct ap_csi_config_request { 103ed4596e9SGreg Kroah-Hartman __u8 csi_id; 104ed4596e9SGreg Kroah-Hartman __u8 clock_mode; 105ed4596e9SGreg Kroah-Hartman __u8 num_lanes; 106ed4596e9SGreg Kroah-Hartman __u8 padding; 107ed4596e9SGreg Kroah-Hartman __le32 bus_freq; 108ed4596e9SGreg Kroah-Hartman } __packed; 109ed4596e9SGreg Kroah-Hartman 1103265edafSLaurent Pinchart static int gb_camera_configure_streams(struct gb_camera *gcam, 1113265edafSLaurent Pinchart unsigned int nstreams, 112b787d413SJacopo Mondi unsigned int flags, 1133265edafSLaurent Pinchart struct gb_camera_stream_config *streams) 1143265edafSLaurent Pinchart { 1153265edafSLaurent Pinchart struct gb_camera_configure_streams_request *req; 1163265edafSLaurent Pinchart struct gb_camera_configure_streams_response *resp; 117ed4596e9SGreg Kroah-Hartman struct ap_csi_config_request csi_cfg; 1183265edafSLaurent Pinchart unsigned int i; 1193265edafSLaurent Pinchart size_t req_size; 1203265edafSLaurent Pinchart size_t resp_size; 1213265edafSLaurent Pinchart int ret; 1223265edafSLaurent Pinchart 1233265edafSLaurent Pinchart if (nstreams > GB_CAMERA_MAX_STREAMS) 1243265edafSLaurent Pinchart return -EINVAL; 1253265edafSLaurent Pinchart 1263265edafSLaurent Pinchart req_size = sizeof(*req) + nstreams * sizeof(req->config[0]); 1273265edafSLaurent Pinchart resp_size = sizeof(*resp) + nstreams * sizeof(resp->config[0]); 1283265edafSLaurent Pinchart 1293265edafSLaurent Pinchart req = kmalloc(req_size, GFP_KERNEL); 1303265edafSLaurent Pinchart resp = kmalloc(resp_size, GFP_KERNEL); 1313265edafSLaurent Pinchart if (!req || !resp) { 1323265edafSLaurent Pinchart ret = -ENOMEM; 1333265edafSLaurent Pinchart goto done; 1343265edafSLaurent Pinchart } 1353265edafSLaurent Pinchart 136b787d413SJacopo Mondi req->num_streams = nstreams; 137b787d413SJacopo Mondi req->flags = flags; 1383265edafSLaurent Pinchart req->padding = 0; 1393265edafSLaurent Pinchart 1403265edafSLaurent Pinchart for (i = 0; i < nstreams; ++i) { 1413265edafSLaurent Pinchart struct gb_camera_stream_config_request *cfg = &req->config[i]; 1423265edafSLaurent Pinchart 143c6622216SLaurent Pinchart cfg->width = cpu_to_le16(streams[i].width); 144c6622216SLaurent Pinchart cfg->height = cpu_to_le16(streams[i].height); 145c6622216SLaurent Pinchart cfg->format = cpu_to_le16(streams[i].format); 1463265edafSLaurent Pinchart cfg->padding = 0; 1473265edafSLaurent Pinchart } 1483265edafSLaurent Pinchart 1493265edafSLaurent Pinchart ret = gb_operation_sync(gcam->connection, 1503265edafSLaurent Pinchart GB_CAMERA_TYPE_CONFIGURE_STREAMS, 1513265edafSLaurent Pinchart req, req_size, resp, resp_size); 1523265edafSLaurent Pinchart if (ret < 0) 15312c8b0dcSJohan Hovold goto done; 1543265edafSLaurent Pinchart 155b787d413SJacopo Mondi if (resp->num_streams > nstreams) { 1563265edafSLaurent Pinchart gcam_dbg(gcam, "got #streams %u > request %u\n", 157b787d413SJacopo Mondi resp->num_streams, nstreams); 1583265edafSLaurent Pinchart ret = -EIO; 1593265edafSLaurent Pinchart goto done; 1603265edafSLaurent Pinchart } 1613265edafSLaurent Pinchart 1623265edafSLaurent Pinchart if (resp->padding != 0) { 1633265edafSLaurent Pinchart gcam_dbg(gcam, "response padding != 0"); 1643265edafSLaurent Pinchart ret = -EIO; 1653265edafSLaurent Pinchart goto done; 1663265edafSLaurent Pinchart } 1673265edafSLaurent Pinchart 1683265edafSLaurent Pinchart for (i = 0; i < nstreams; ++i) { 1693265edafSLaurent Pinchart struct gb_camera_stream_config_response *cfg = &resp->config[i]; 1703265edafSLaurent Pinchart 171c6622216SLaurent Pinchart streams[i].width = le16_to_cpu(cfg->width); 172c6622216SLaurent Pinchart streams[i].height = le16_to_cpu(cfg->height); 173c6622216SLaurent Pinchart streams[i].format = le16_to_cpu(cfg->format); 1743265edafSLaurent Pinchart streams[i].vc = cfg->virtual_channel; 1753265edafSLaurent Pinchart streams[i].dt[0] = cfg->data_type[0]; 1763265edafSLaurent Pinchart streams[i].dt[1] = cfg->data_type[1]; 177c6622216SLaurent Pinchart streams[i].max_size = le32_to_cpu(cfg->max_size); 1783265edafSLaurent Pinchart 1793265edafSLaurent Pinchart if (cfg->padding[0] || cfg->padding[1] || cfg->padding[2]) { 1803265edafSLaurent Pinchart gcam_dbg(gcam, "stream #%u padding != 0", i); 1813265edafSLaurent Pinchart ret = -EIO; 1823265edafSLaurent Pinchart goto done; 1833265edafSLaurent Pinchart } 1843265edafSLaurent Pinchart } 1853265edafSLaurent Pinchart 186ed4596e9SGreg Kroah-Hartman memset(&csi_cfg, 0, sizeof(csi_cfg)); 187ed4596e9SGreg Kroah-Hartman 188142b21feSLaurent Pinchart /* Configure the CSI transmitter. Hardcode the parameters for now. */ 189142b21feSLaurent Pinchart if (nstreams && !(resp->flags & GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED)) { 190142b21feSLaurent Pinchart csi_cfg.csi_id = 1; 191142b21feSLaurent Pinchart csi_cfg.clock_mode = 0; 1921f67ee5cSLaurent Pinchart csi_cfg.num_lanes = 4; 193ed4596e9SGreg Kroah-Hartman csi_cfg.bus_freq = cpu_to_le32(960000000); 194ed4596e9SGreg Kroah-Hartman ret = gb_hd_output(gcam->connection->hd, &csi_cfg, 195e5273381SGreg Kroah-Hartman sizeof(csi_cfg), 196e5273381SGreg Kroah-Hartman GB_APB_REQUEST_CSI_TX_CONTROL, false); 197142b21feSLaurent Pinchart } else if (nstreams == 0) { 198142b21feSLaurent Pinchart csi_cfg.csi_id = 1; 199ed4596e9SGreg Kroah-Hartman ret = gb_hd_output(gcam->connection->hd, &csi_cfg, 200e5273381SGreg Kroah-Hartman sizeof(csi_cfg), 201e5273381SGreg Kroah-Hartman GB_APB_REQUEST_CSI_TX_CONTROL, false); 202142b21feSLaurent Pinchart } 203142b21feSLaurent Pinchart 204142b21feSLaurent Pinchart if (ret < 0) 205142b21feSLaurent Pinchart gcam_err(gcam, "failed to %s the CSI transmitter\n", 206142b21feSLaurent Pinchart nstreams ? "start" : "stop"); 207142b21feSLaurent Pinchart 208b787d413SJacopo Mondi ret = resp->num_streams; 2093265edafSLaurent Pinchart 2103265edafSLaurent Pinchart done: 2113265edafSLaurent Pinchart kfree(req); 2123265edafSLaurent Pinchart kfree(resp); 2133265edafSLaurent Pinchart return ret; 2143265edafSLaurent Pinchart } 2153265edafSLaurent Pinchart 2163265edafSLaurent Pinchart static int gb_camera_capture(struct gb_camera *gcam, u32 request_id, 2173265edafSLaurent Pinchart unsigned int streams, unsigned int num_frames, 2183265edafSLaurent Pinchart size_t settings_size, const void *settings) 2193265edafSLaurent Pinchart { 2203265edafSLaurent Pinchart struct gb_camera_capture_request *req; 2213265edafSLaurent Pinchart size_t req_size; 222b9f71bc8SJohan Hovold int ret; 2233265edafSLaurent Pinchart 2243265edafSLaurent Pinchart if (settings_size > GB_CAMERA_MAX_SETTINGS_SIZE) 2253265edafSLaurent Pinchart return -EINVAL; 2263265edafSLaurent Pinchart 2273265edafSLaurent Pinchart req_size = sizeof(*req) + settings_size; 2283265edafSLaurent Pinchart req = kmalloc(req_size, GFP_KERNEL); 2293265edafSLaurent Pinchart if (!req) 2303265edafSLaurent Pinchart return -ENOMEM; 2313265edafSLaurent Pinchart 232c6622216SLaurent Pinchart req->request_id = cpu_to_le32(request_id); 2333265edafSLaurent Pinchart req->streams = streams; 2343265edafSLaurent Pinchart req->padding = 0; 235c6622216SLaurent Pinchart req->num_frames = cpu_to_le16(num_frames); 2363265edafSLaurent Pinchart memcpy(req->settings, settings, settings_size); 2373265edafSLaurent Pinchart 238b9f71bc8SJohan Hovold ret = gb_operation_sync(gcam->connection, GB_CAMERA_TYPE_CAPTURE, 2393265edafSLaurent Pinchart req, req_size, NULL, 0); 240b9f71bc8SJohan Hovold 241b9f71bc8SJohan Hovold kfree(req); 242b9f71bc8SJohan Hovold 243b9f71bc8SJohan Hovold return ret; 2443265edafSLaurent Pinchart } 2453265edafSLaurent Pinchart 2463265edafSLaurent Pinchart static int gb_camera_flush(struct gb_camera *gcam, u32 *request_id) 2473265edafSLaurent Pinchart { 2483265edafSLaurent Pinchart struct gb_camera_flush_response resp; 2493265edafSLaurent Pinchart int ret; 2503265edafSLaurent Pinchart 2513265edafSLaurent Pinchart ret = gb_operation_sync(gcam->connection, GB_CAMERA_TYPE_FLUSH, NULL, 0, 2523265edafSLaurent Pinchart &resp, sizeof(resp)); 2533265edafSLaurent Pinchart if (ret < 0) 2543265edafSLaurent Pinchart return ret; 2553265edafSLaurent Pinchart 2563265edafSLaurent Pinchart if (request_id) 257c6622216SLaurent Pinchart *request_id = le32_to_cpu(resp.request_id); 2583265edafSLaurent Pinchart 2593265edafSLaurent Pinchart return 0; 2603265edafSLaurent Pinchart } 2613265edafSLaurent Pinchart 2623265edafSLaurent Pinchart static int gb_camera_event_recv(u8 type, struct gb_operation *op) 2633265edafSLaurent Pinchart { 2643265edafSLaurent Pinchart struct gb_camera *gcam = op->connection->private; 2653265edafSLaurent Pinchart struct gb_camera_metadata_request *payload; 2663265edafSLaurent Pinchart struct gb_message *request; 2673265edafSLaurent Pinchart 2683265edafSLaurent Pinchart if (type != GB_CAMERA_TYPE_METADATA) { 2693265edafSLaurent Pinchart gcam_err(gcam, "Unsupported unsolicited event: %u\n", type); 2703265edafSLaurent Pinchart return -EINVAL; 2713265edafSLaurent Pinchart } 2723265edafSLaurent Pinchart 2733265edafSLaurent Pinchart request = op->request; 2743265edafSLaurent Pinchart 2753265edafSLaurent Pinchart if (request->payload_size < sizeof(*payload)) { 2763265edafSLaurent Pinchart gcam_err(gcam, "Wrong event size received (%zu < %zu)\n", 2773265edafSLaurent Pinchart request->payload_size, sizeof(*payload)); 2783265edafSLaurent Pinchart return -EINVAL; 2793265edafSLaurent Pinchart } 2803265edafSLaurent Pinchart 2813265edafSLaurent Pinchart payload = request->payload; 2823265edafSLaurent Pinchart 2833265edafSLaurent Pinchart gcam_dbg(gcam, "received metadata for request %u, frame %u, stream %u\n", 2843265edafSLaurent Pinchart payload->request_id, payload->frame_number, payload->stream); 2853265edafSLaurent Pinchart 2863265edafSLaurent Pinchart return 0; 2873265edafSLaurent Pinchart } 2883265edafSLaurent Pinchart 2893265edafSLaurent Pinchart /* ----------------------------------------------------------------------------- 2903a8dba4eSGjorgji Rosikopulos * Interface with HOST ara camera. 2913a8dba4eSGjorgji Rosikopulos */ 2923a8dba4eSGjorgji Rosikopulos static unsigned int gb_camera_mbus_to_gb(enum v4l2_mbus_pixelcode mbus_code) 2933a8dba4eSGjorgji Rosikopulos { 2943a8dba4eSGjorgji Rosikopulos unsigned int i; 2953a8dba4eSGjorgji Rosikopulos 2963a8dba4eSGjorgji Rosikopulos for (i = 0; i < ARRAY_SIZE(mbus_to_gbus_format); i++) { 2973a8dba4eSGjorgji Rosikopulos if (mbus_to_gbus_format[i].mbus_code == mbus_code) 2983a8dba4eSGjorgji Rosikopulos return mbus_to_gbus_format[i].gb_format; 2993a8dba4eSGjorgji Rosikopulos } 3003a8dba4eSGjorgji Rosikopulos return mbus_to_gbus_format[0].gb_format; 3013a8dba4eSGjorgji Rosikopulos } 3023a8dba4eSGjorgji Rosikopulos 3033a8dba4eSGjorgji Rosikopulos static enum v4l2_mbus_pixelcode gb_camera_gb_to_mbus(u16 gb_fmt) 3043a8dba4eSGjorgji Rosikopulos { 3053a8dba4eSGjorgji Rosikopulos unsigned int i; 3063a8dba4eSGjorgji Rosikopulos 3073a8dba4eSGjorgji Rosikopulos for (i = 0; i < ARRAY_SIZE(mbus_to_gbus_format); i++) { 3083a8dba4eSGjorgji Rosikopulos if (mbus_to_gbus_format[i].gb_format == gb_fmt) 3093a8dba4eSGjorgji Rosikopulos return mbus_to_gbus_format[i].mbus_code; 3103a8dba4eSGjorgji Rosikopulos } 3113a8dba4eSGjorgji Rosikopulos return mbus_to_gbus_format[0].mbus_code; 3123a8dba4eSGjorgji Rosikopulos } 3133a8dba4eSGjorgji Rosikopulos 3143a8dba4eSGjorgji Rosikopulos static int gb_camera_op_configure_streams(void *priv, unsigned int nstreams, 3153a8dba4eSGjorgji Rosikopulos struct gb_camera_stream *streams) 3163a8dba4eSGjorgji Rosikopulos { 3173a8dba4eSGjorgji Rosikopulos struct gb_camera *gcam = priv; 3183a8dba4eSGjorgji Rosikopulos struct gb_camera_stream_config *gb_streams; 3193a8dba4eSGjorgji Rosikopulos unsigned int i; 3203a8dba4eSGjorgji Rosikopulos int ret; 3213a8dba4eSGjorgji Rosikopulos 3223a8dba4eSGjorgji Rosikopulos if (nstreams > GB_CAMERA_MAX_STREAMS) 3233a8dba4eSGjorgji Rosikopulos return -EINVAL; 3243a8dba4eSGjorgji Rosikopulos 3253a8dba4eSGjorgji Rosikopulos gb_streams = kzalloc(nstreams * sizeof(*gb_streams), GFP_KERNEL); 3263a8dba4eSGjorgji Rosikopulos if (!gb_streams) 3273a8dba4eSGjorgji Rosikopulos return -ENOMEM; 3283a8dba4eSGjorgji Rosikopulos 3293a8dba4eSGjorgji Rosikopulos for (i = 0; i < nstreams; i++) { 3303a8dba4eSGjorgji Rosikopulos gb_streams[i].width = streams[i].width; 3313a8dba4eSGjorgji Rosikopulos gb_streams[i].height = streams[i].height; 3323a8dba4eSGjorgji Rosikopulos gb_streams[i].format = 3333a8dba4eSGjorgji Rosikopulos gb_camera_mbus_to_gb(streams[i].pixel_code); 3343a8dba4eSGjorgji Rosikopulos } 3353a8dba4eSGjorgji Rosikopulos 3363a8dba4eSGjorgji Rosikopulos ret = gb_camera_configure_streams(gcam, nstreams, 0, gb_streams); 3373a8dba4eSGjorgji Rosikopulos if (ret < 0) 3383a8dba4eSGjorgji Rosikopulos goto done; 3393a8dba4eSGjorgji Rosikopulos 3403a8dba4eSGjorgji Rosikopulos for (i = 0; i < nstreams; i++) { 3413a8dba4eSGjorgji Rosikopulos streams[i].width = gb_streams[i].width; 3423a8dba4eSGjorgji Rosikopulos streams[i].height = gb_streams[i].height; 3433a8dba4eSGjorgji Rosikopulos streams[i].vc = gb_streams[i].vc; 3443a8dba4eSGjorgji Rosikopulos streams[i].dt[0] = gb_streams[i].dt[0]; 3453a8dba4eSGjorgji Rosikopulos streams[i].dt[1] = gb_streams[i].dt[1]; 3463a8dba4eSGjorgji Rosikopulos streams[i].max_size = gb_streams[i].max_size; 3473a8dba4eSGjorgji Rosikopulos streams[i].pixel_code = 3483a8dba4eSGjorgji Rosikopulos gb_camera_gb_to_mbus(gb_streams[i].format); 3493a8dba4eSGjorgji Rosikopulos } 3503a8dba4eSGjorgji Rosikopulos 3513a8dba4eSGjorgji Rosikopulos done: 3523a8dba4eSGjorgji Rosikopulos kfree(gb_streams); 3533a8dba4eSGjorgji Rosikopulos return ret; 3543a8dba4eSGjorgji Rosikopulos } 3553a8dba4eSGjorgji Rosikopulos 3563a8dba4eSGjorgji Rosikopulos static int gb_camera_op_capture(void *priv, u32 request_id, 3573a8dba4eSGjorgji Rosikopulos unsigned int streams, unsigned int num_frames, 3583a8dba4eSGjorgji Rosikopulos size_t settings_size, const void *settings) 3593a8dba4eSGjorgji Rosikopulos { 3603a8dba4eSGjorgji Rosikopulos return gb_camera_capture(priv, request_id, streams, num_frames, 3613a8dba4eSGjorgji Rosikopulos settings_size, settings); 3623a8dba4eSGjorgji Rosikopulos } 3633a8dba4eSGjorgji Rosikopulos 3643a8dba4eSGjorgji Rosikopulos static int gb_camera_op_flush(void *priv, u32 *request_id) 3653a8dba4eSGjorgji Rosikopulos { 3663a8dba4eSGjorgji Rosikopulos return gb_camera_flush(priv, request_id); 3673a8dba4eSGjorgji Rosikopulos } 3683a8dba4eSGjorgji Rosikopulos 3693a8dba4eSGjorgji Rosikopulos struct gb_camera_ops gb_cam_ops = { 3703a8dba4eSGjorgji Rosikopulos .configure_streams = gb_camera_op_configure_streams, 3713a8dba4eSGjorgji Rosikopulos .capture = gb_camera_op_capture, 3723a8dba4eSGjorgji Rosikopulos .flush = gb_camera_op_flush, 3733a8dba4eSGjorgji Rosikopulos }; 3743a8dba4eSGjorgji Rosikopulos 3753a8dba4eSGjorgji Rosikopulos static int gb_camera_register_intf_ops(struct gb_camera *gcam) 3763a8dba4eSGjorgji Rosikopulos { 3773a8dba4eSGjorgji Rosikopulos return gb_camera_register(&gb_cam_ops, gcam); 3783a8dba4eSGjorgji Rosikopulos } 3793a8dba4eSGjorgji Rosikopulos 3803a8dba4eSGjorgji Rosikopulos /* ----------------------------------------------------------------------------- 3813265edafSLaurent Pinchart * DebugFS 3823265edafSLaurent Pinchart */ 3833265edafSLaurent Pinchart static ssize_t gb_camera_debugfs_capabilities(struct gb_camera *gcam, 3843265edafSLaurent Pinchart char *buf, size_t len) 3853265edafSLaurent Pinchart { 3863265edafSLaurent Pinchart return len; 3873265edafSLaurent Pinchart } 3883265edafSLaurent Pinchart 3893265edafSLaurent Pinchart static ssize_t gb_camera_debugfs_configure_streams(struct gb_camera *gcam, 3903265edafSLaurent Pinchart char *buf, size_t len) 3913265edafSLaurent Pinchart { 3923265edafSLaurent Pinchart struct gb_camera_debugfs_buffer *buffer = 3933265edafSLaurent Pinchart &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_STREAMS]; 3943265edafSLaurent Pinchart struct gb_camera_stream_config *streams; 3953265edafSLaurent Pinchart unsigned int nstreams; 396b787d413SJacopo Mondi unsigned int flags; 3973265edafSLaurent Pinchart unsigned int i; 3983265edafSLaurent Pinchart char *token; 3993265edafSLaurent Pinchart int ret; 4003265edafSLaurent Pinchart 4013265edafSLaurent Pinchart /* Retrieve number of streams to configure */ 402b787d413SJacopo Mondi token = strsep(&buf, ";"); 4033265edafSLaurent Pinchart if (token == NULL) 4043265edafSLaurent Pinchart return -EINVAL; 4053265edafSLaurent Pinchart 4063265edafSLaurent Pinchart ret = kstrtouint(token, 10, &nstreams); 4073265edafSLaurent Pinchart if (ret < 0) 4083265edafSLaurent Pinchart return ret; 4093265edafSLaurent Pinchart 4103265edafSLaurent Pinchart if (nstreams > GB_CAMERA_MAX_STREAMS) 4113265edafSLaurent Pinchart return -EINVAL; 4123265edafSLaurent Pinchart 413b787d413SJacopo Mondi token = strsep(&buf, ";"); 414b787d413SJacopo Mondi if (token == NULL) 415b787d413SJacopo Mondi return -EINVAL; 416b787d413SJacopo Mondi 417b787d413SJacopo Mondi ret = kstrtouint(token, 10, &flags); 418b787d413SJacopo Mondi if (ret < 0) 419b787d413SJacopo Mondi return ret; 420b787d413SJacopo Mondi 4213265edafSLaurent Pinchart /* For each stream to configure parse width, height and format */ 4223265edafSLaurent Pinchart streams = kzalloc(nstreams * sizeof(*streams), GFP_KERNEL); 4233265edafSLaurent Pinchart if (!streams) 4243265edafSLaurent Pinchart return -ENOMEM; 4253265edafSLaurent Pinchart 4263265edafSLaurent Pinchart for (i = 0; i < nstreams; ++i) { 4273265edafSLaurent Pinchart struct gb_camera_stream_config *stream = &streams[i]; 4283265edafSLaurent Pinchart 4293265edafSLaurent Pinchart /* width */ 4303265edafSLaurent Pinchart token = strsep(&buf, ";"); 4313265edafSLaurent Pinchart if (token == NULL) { 4323265edafSLaurent Pinchart ret = -EINVAL; 4333265edafSLaurent Pinchart goto done; 4343265edafSLaurent Pinchart } 4353265edafSLaurent Pinchart ret = kstrtouint(token, 10, &stream->width); 4363265edafSLaurent Pinchart if (ret < 0) 4373265edafSLaurent Pinchart goto done; 4383265edafSLaurent Pinchart 4393265edafSLaurent Pinchart /* height */ 4403265edafSLaurent Pinchart token = strsep(&buf, ";"); 4413265edafSLaurent Pinchart if (token == NULL) 4423265edafSLaurent Pinchart goto done; 4433265edafSLaurent Pinchart 4443265edafSLaurent Pinchart ret = kstrtouint(token, 10, &stream->height); 4453265edafSLaurent Pinchart if (ret < 0) 4463265edafSLaurent Pinchart goto done; 4473265edafSLaurent Pinchart 4483265edafSLaurent Pinchart /* Image format code */ 4493265edafSLaurent Pinchart token = strsep(&buf, ";"); 4503265edafSLaurent Pinchart if (token == NULL) 4513265edafSLaurent Pinchart goto done; 4523265edafSLaurent Pinchart 4533265edafSLaurent Pinchart ret = kstrtouint(token, 16, &stream->format); 4543265edafSLaurent Pinchart if (ret < 0) 4553265edafSLaurent Pinchart goto done; 4563265edafSLaurent Pinchart } 4573265edafSLaurent Pinchart 458b787d413SJacopo Mondi ret = gb_camera_configure_streams(gcam, nstreams, flags, streams); 4593265edafSLaurent Pinchart if (ret < 0) 4603265edafSLaurent Pinchart goto done; 4613265edafSLaurent Pinchart 4623265edafSLaurent Pinchart nstreams = ret; 4633265edafSLaurent Pinchart buffer->length = sprintf(buffer->data, "%u;", nstreams); 4643265edafSLaurent Pinchart 4653265edafSLaurent Pinchart for (i = 0; i < nstreams; ++i) { 4663265edafSLaurent Pinchart struct gb_camera_stream_config *stream = &streams[i]; 4673265edafSLaurent Pinchart 4683265edafSLaurent Pinchart buffer->length += sprintf(buffer->data + buffer->length, 4693265edafSLaurent Pinchart "%u;%u;%u;%u;%u;%u;%u;", 4703265edafSLaurent Pinchart stream->width, stream->height, 4713265edafSLaurent Pinchart stream->format, stream->vc, 4723265edafSLaurent Pinchart stream->dt[0], stream->dt[1], 4733265edafSLaurent Pinchart stream->max_size); 4743265edafSLaurent Pinchart } 4753265edafSLaurent Pinchart 4763265edafSLaurent Pinchart ret = len; 4773265edafSLaurent Pinchart 4783265edafSLaurent Pinchart done: 4793265edafSLaurent Pinchart kfree(streams); 4803265edafSLaurent Pinchart return ret; 4813265edafSLaurent Pinchart }; 4823265edafSLaurent Pinchart 4833265edafSLaurent Pinchart static ssize_t gb_camera_debugfs_capture(struct gb_camera *gcam, 4843265edafSLaurent Pinchart char *buf, size_t len) 4853265edafSLaurent Pinchart { 4863265edafSLaurent Pinchart unsigned int request_id; 4873265edafSLaurent Pinchart unsigned int streams_mask; 4883265edafSLaurent Pinchart unsigned int num_frames; 4893265edafSLaurent Pinchart char *token; 4903265edafSLaurent Pinchart int ret; 4913265edafSLaurent Pinchart 4923265edafSLaurent Pinchart /* Request id */ 4933265edafSLaurent Pinchart token = strsep(&buf, ";"); 4943265edafSLaurent Pinchart if (token == NULL) 4953265edafSLaurent Pinchart return -EINVAL; 4963265edafSLaurent Pinchart ret = kstrtouint(token, 10, &request_id); 4973265edafSLaurent Pinchart if (ret < 0) 4983265edafSLaurent Pinchart return ret; 4993265edafSLaurent Pinchart 5003265edafSLaurent Pinchart /* Stream mask */ 5013265edafSLaurent Pinchart token = strsep(&buf, ";"); 5023265edafSLaurent Pinchart if (token == NULL) 5033265edafSLaurent Pinchart return -EINVAL; 5043265edafSLaurent Pinchart ret = kstrtouint(token, 16, &streams_mask); 5053265edafSLaurent Pinchart if (ret < 0) 5063265edafSLaurent Pinchart return ret; 5073265edafSLaurent Pinchart 5083265edafSLaurent Pinchart /* number of frames */ 5093265edafSLaurent Pinchart token = strsep(&buf, ";"); 5103265edafSLaurent Pinchart if (token == NULL) 5113265edafSLaurent Pinchart return -EINVAL; 5123265edafSLaurent Pinchart ret = kstrtouint(token, 10, &num_frames); 5133265edafSLaurent Pinchart if (ret < 0) 5143265edafSLaurent Pinchart return ret; 5153265edafSLaurent Pinchart 5163265edafSLaurent Pinchart ret = gb_camera_capture(gcam, request_id, streams_mask, num_frames, 0, 5173265edafSLaurent Pinchart NULL); 5183265edafSLaurent Pinchart if (ret < 0) 5193265edafSLaurent Pinchart return ret; 5203265edafSLaurent Pinchart 5213265edafSLaurent Pinchart return len; 5223265edafSLaurent Pinchart } 5233265edafSLaurent Pinchart 5243265edafSLaurent Pinchart static ssize_t gb_camera_debugfs_flush(struct gb_camera *gcam, 5253265edafSLaurent Pinchart char *buf, size_t len) 5263265edafSLaurent Pinchart { 5273265edafSLaurent Pinchart struct gb_camera_debugfs_buffer *buffer = 5283265edafSLaurent Pinchart &gcam->debugfs.buffers[GB_CAMERA_DEBUGFS_BUFFER_FLUSH]; 5293265edafSLaurent Pinchart unsigned int req_id; 5303265edafSLaurent Pinchart int ret; 5313265edafSLaurent Pinchart 5323265edafSLaurent Pinchart ret = gb_camera_flush(gcam, &req_id); 5333265edafSLaurent Pinchart if (ret < 0) 5343265edafSLaurent Pinchart return ret; 5353265edafSLaurent Pinchart 5363265edafSLaurent Pinchart buffer->length = sprintf(buffer->data, "%u", req_id); 5373265edafSLaurent Pinchart 5383265edafSLaurent Pinchart return len; 5393265edafSLaurent Pinchart } 5403265edafSLaurent Pinchart 5413265edafSLaurent Pinchart struct gb_camera_debugfs_entry { 5423265edafSLaurent Pinchart const char *name; 5433265edafSLaurent Pinchart unsigned int mask; 5443265edafSLaurent Pinchart unsigned int buffer; 5453265edafSLaurent Pinchart ssize_t (*execute)(struct gb_camera *gcam, char *buf, size_t len); 5463265edafSLaurent Pinchart }; 5473265edafSLaurent Pinchart 5483265edafSLaurent Pinchart static const struct gb_camera_debugfs_entry gb_camera_debugfs_entries[] = { 5493265edafSLaurent Pinchart { 5503265edafSLaurent Pinchart .name = "capabilities", 5513265edafSLaurent Pinchart .mask = S_IFREG | S_IRUGO, 5523265edafSLaurent Pinchart .buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES, 5533265edafSLaurent Pinchart .execute = gb_camera_debugfs_capabilities, 5543265edafSLaurent Pinchart }, { 5553265edafSLaurent Pinchart .name = "configure_streams", 5563265edafSLaurent Pinchart .mask = S_IFREG | S_IRUGO | S_IWUGO, 5573265edafSLaurent Pinchart .buffer = GB_CAMERA_DEBUGFS_BUFFER_STREAMS, 5583265edafSLaurent Pinchart .execute = gb_camera_debugfs_configure_streams, 5593265edafSLaurent Pinchart }, { 5603265edafSLaurent Pinchart .name = "capture", 5613265edafSLaurent Pinchart .mask = S_IFREG | S_IRUGO | S_IWUGO, 5623265edafSLaurent Pinchart .buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPTURE, 5633265edafSLaurent Pinchart .execute = gb_camera_debugfs_capture, 5643265edafSLaurent Pinchart }, { 5653265edafSLaurent Pinchart .name = "flush", 5663265edafSLaurent Pinchart .mask = S_IFREG | S_IRUGO | S_IWUGO, 5673265edafSLaurent Pinchart .buffer = GB_CAMERA_DEBUGFS_BUFFER_FLUSH, 5683265edafSLaurent Pinchart .execute = gb_camera_debugfs_flush, 5693265edafSLaurent Pinchart }, 5703265edafSLaurent Pinchart }; 5713265edafSLaurent Pinchart 5723265edafSLaurent Pinchart static ssize_t gb_camera_debugfs_read(struct file *file, char __user *buf, 5733265edafSLaurent Pinchart size_t len, loff_t *offset) 5743265edafSLaurent Pinchart { 5753265edafSLaurent Pinchart const struct gb_camera_debugfs_entry *op = file->private_data; 5763265edafSLaurent Pinchart struct gb_camera *gcam = file->f_inode->i_private; 5773265edafSLaurent Pinchart struct gb_camera_debugfs_buffer *buffer; 5783265edafSLaurent Pinchart ssize_t ret; 5793265edafSLaurent Pinchart 5803265edafSLaurent Pinchart /* For read-only entries the operation is triggered by a read. */ 5813265edafSLaurent Pinchart if (!(op->mask & S_IWUGO)) { 5823265edafSLaurent Pinchart ret = op->execute(gcam, NULL, 0); 5833265edafSLaurent Pinchart if (ret < 0) 5843265edafSLaurent Pinchart return ret; 5853265edafSLaurent Pinchart } 5863265edafSLaurent Pinchart 5873265edafSLaurent Pinchart buffer = &gcam->debugfs.buffers[op->buffer]; 5883265edafSLaurent Pinchart 5893265edafSLaurent Pinchart return simple_read_from_buffer(buf, len, offset, buffer->data, 5903265edafSLaurent Pinchart buffer->length); 5913265edafSLaurent Pinchart } 5923265edafSLaurent Pinchart 5933265edafSLaurent Pinchart static ssize_t gb_camera_debugfs_write(struct file *file, 5943265edafSLaurent Pinchart const char __user *buf, size_t len, 5953265edafSLaurent Pinchart loff_t *offset) 5963265edafSLaurent Pinchart { 5973265edafSLaurent Pinchart const struct gb_camera_debugfs_entry *op = file->private_data; 5983265edafSLaurent Pinchart struct gb_camera *gcam = file->f_inode->i_private; 5993265edafSLaurent Pinchart ssize_t ret; 6003265edafSLaurent Pinchart char *kbuf; 6013265edafSLaurent Pinchart 6023265edafSLaurent Pinchart if (len > 1024) 6033265edafSLaurent Pinchart return -EINVAL; 6043265edafSLaurent Pinchart 6053265edafSLaurent Pinchart kbuf = kmalloc(len + 1, GFP_KERNEL); 6063265edafSLaurent Pinchart if (kbuf == NULL) 6073265edafSLaurent Pinchart return -ENOMEM; 6083265edafSLaurent Pinchart 6093265edafSLaurent Pinchart if (copy_from_user(kbuf, buf, len)) { 6103265edafSLaurent Pinchart ret = -EFAULT; 6113265edafSLaurent Pinchart goto done; 6123265edafSLaurent Pinchart } 6133265edafSLaurent Pinchart 6143265edafSLaurent Pinchart kbuf[len] = '\0'; 6153265edafSLaurent Pinchart 6163265edafSLaurent Pinchart ret = op->execute(gcam, kbuf, len); 6173265edafSLaurent Pinchart 6183265edafSLaurent Pinchart done: 6193265edafSLaurent Pinchart kfree(kbuf); 6203265edafSLaurent Pinchart return ret; 6213265edafSLaurent Pinchart } 6223265edafSLaurent Pinchart 6233265edafSLaurent Pinchart static int gb_camera_debugfs_open(struct inode *inode, struct file *file) 6243265edafSLaurent Pinchart { 6253265edafSLaurent Pinchart unsigned int i; 6263265edafSLaurent Pinchart 6273265edafSLaurent Pinchart for (i = 0; i < ARRAY_SIZE(gb_camera_debugfs_entries); ++i) { 6283265edafSLaurent Pinchart const struct gb_camera_debugfs_entry *entry = 6293265edafSLaurent Pinchart &gb_camera_debugfs_entries[i]; 6303265edafSLaurent Pinchart 6314dda744cSGreg Kroah-Hartman if (!strcmp(file->f_path.dentry->d_iname, entry->name)) { 6323265edafSLaurent Pinchart file->private_data = (void *)entry; 6333265edafSLaurent Pinchart break; 6343265edafSLaurent Pinchart } 6353265edafSLaurent Pinchart } 6363265edafSLaurent Pinchart 6373265edafSLaurent Pinchart return 0; 6383265edafSLaurent Pinchart } 6393265edafSLaurent Pinchart 6403265edafSLaurent Pinchart static const struct file_operations gb_camera_debugfs_ops = { 6413265edafSLaurent Pinchart .open = gb_camera_debugfs_open, 6423265edafSLaurent Pinchart .read = gb_camera_debugfs_read, 6433265edafSLaurent Pinchart .write = gb_camera_debugfs_write, 6443265edafSLaurent Pinchart }; 6453265edafSLaurent Pinchart 6463265edafSLaurent Pinchart static int gb_camera_debugfs_init(struct gb_camera *gcam) 6473265edafSLaurent Pinchart { 6483265edafSLaurent Pinchart struct gb_connection *connection = gcam->connection; 6493265edafSLaurent Pinchart char dirname[27]; 6503265edafSLaurent Pinchart unsigned int i; 6513265edafSLaurent Pinchart 6523265edafSLaurent Pinchart /* 6533265edafSLaurent Pinchart * Create root debugfs entry and a file entry for each camera operation. 6543265edafSLaurent Pinchart */ 6553265edafSLaurent Pinchart snprintf(dirname, 27, "camera-%u.%u", connection->intf->interface_id, 6563265edafSLaurent Pinchart connection->bundle->id); 6573265edafSLaurent Pinchart 6583265edafSLaurent Pinchart gcam->debugfs.root = debugfs_create_dir(dirname, gb_debugfs_get()); 6593265edafSLaurent Pinchart if (IS_ERR(gcam->debugfs.root)) { 6603265edafSLaurent Pinchart gcam_err(gcam, "debugfs root create failed (%ld)\n", 6613265edafSLaurent Pinchart PTR_ERR(gcam->debugfs.root)); 6623265edafSLaurent Pinchart return PTR_ERR(gcam->debugfs.root); 6633265edafSLaurent Pinchart } 6643265edafSLaurent Pinchart 6653265edafSLaurent Pinchart gcam->debugfs.buffers = vmalloc(sizeof(*gcam->debugfs.buffers) * 6663265edafSLaurent Pinchart GB_CAMERA_DEBUGFS_BUFFER_MAX); 6673265edafSLaurent Pinchart if (!gcam->debugfs.buffers) 6683265edafSLaurent Pinchart return -ENOMEM; 6693265edafSLaurent Pinchart 6703265edafSLaurent Pinchart for (i = 0; i < ARRAY_SIZE(gb_camera_debugfs_entries); ++i) { 6713265edafSLaurent Pinchart const struct gb_camera_debugfs_entry *entry = 6723265edafSLaurent Pinchart &gb_camera_debugfs_entries[i]; 6733265edafSLaurent Pinchart struct dentry *dentry; 6743265edafSLaurent Pinchart 6753265edafSLaurent Pinchart gcam->debugfs.buffers[i].length = 0; 6763265edafSLaurent Pinchart 6773265edafSLaurent Pinchart dentry = debugfs_create_file(entry->name, entry->mask, 6783265edafSLaurent Pinchart gcam->debugfs.root, gcam, 6793265edafSLaurent Pinchart &gb_camera_debugfs_ops); 6803265edafSLaurent Pinchart if (IS_ERR(dentry)) { 6813265edafSLaurent Pinchart gcam_err(gcam, 6823265edafSLaurent Pinchart "debugfs operation %s create failed (%ld)\n", 6833265edafSLaurent Pinchart entry->name, PTR_ERR(gcam->debugfs.root)); 6843265edafSLaurent Pinchart return PTR_ERR(dentry); 6853265edafSLaurent Pinchart } 6863265edafSLaurent Pinchart } 6873265edafSLaurent Pinchart 6883265edafSLaurent Pinchart return 0; 6893265edafSLaurent Pinchart } 6903265edafSLaurent Pinchart 6913265edafSLaurent Pinchart static void gb_camera_debugfs_cleanup(struct gb_camera *gcam) 6923265edafSLaurent Pinchart { 6933265edafSLaurent Pinchart if (gcam->debugfs.root) 6943265edafSLaurent Pinchart debugfs_remove_recursive(gcam->debugfs.root); 6953265edafSLaurent Pinchart 6963265edafSLaurent Pinchart vfree(gcam->debugfs.buffers); 6973265edafSLaurent Pinchart } 6983265edafSLaurent Pinchart 6993265edafSLaurent Pinchart /* ----------------------------------------------------------------------------- 7003265edafSLaurent Pinchart * Init & Cleanup 7013265edafSLaurent Pinchart */ 7023265edafSLaurent Pinchart 7033265edafSLaurent Pinchart static void gb_camera_cleanup(struct gb_camera *gcam) 7043265edafSLaurent Pinchart { 7053265edafSLaurent Pinchart gb_camera_debugfs_cleanup(gcam); 7063265edafSLaurent Pinchart 7073265edafSLaurent Pinchart if (gcam->data_connected) { 7083265edafSLaurent Pinchart struct gb_interface *intf = gcam->connection->intf; 7093265edafSLaurent Pinchart struct gb_svc *svc = gcam->connection->hd->svc; 7103265edafSLaurent Pinchart 7113265edafSLaurent Pinchart gb_svc_connection_destroy(svc, intf->interface_id, 7123265edafSLaurent Pinchart ES2_APB_CDSI0_CPORT, svc->ap_intf_id, 7133265edafSLaurent Pinchart ES2_APB_CDSI1_CPORT); 7143265edafSLaurent Pinchart } 7153265edafSLaurent Pinchart 7163265edafSLaurent Pinchart kfree(gcam); 7173265edafSLaurent Pinchart } 7183265edafSLaurent Pinchart 7193265edafSLaurent Pinchart static int gb_camera_connection_init(struct gb_connection *connection) 7203265edafSLaurent Pinchart { 7213265edafSLaurent Pinchart struct gb_svc *svc = connection->hd->svc; 7223265edafSLaurent Pinchart struct gb_camera *gcam; 7233265edafSLaurent Pinchart int ret; 7243265edafSLaurent Pinchart 7253265edafSLaurent Pinchart gcam = kzalloc(sizeof(*gcam), GFP_KERNEL); 7263265edafSLaurent Pinchart if (!gcam) 7273265edafSLaurent Pinchart return -ENOMEM; 7283265edafSLaurent Pinchart 7293265edafSLaurent Pinchart gcam->connection = connection; 7303265edafSLaurent Pinchart connection->private = gcam; 7313265edafSLaurent Pinchart 7323265edafSLaurent Pinchart /* 7333265edafSLaurent Pinchart * Create the data connection between camera module CDSI0 and APB CDS1. 7343265edafSLaurent Pinchart * The CPort IDs are hardcoded by the ES2 bridges. 7353265edafSLaurent Pinchart */ 7363265edafSLaurent Pinchart ret = gb_svc_connection_create(svc, connection->intf->interface_id, 7373265edafSLaurent Pinchart ES2_APB_CDSI0_CPORT, svc->ap_intf_id, 7383265edafSLaurent Pinchart ES2_APB_CDSI1_CPORT, false); 7393265edafSLaurent Pinchart if (ret < 0) 7403265edafSLaurent Pinchart goto error; 7413265edafSLaurent Pinchart 74241c23958SJohan Hovold gcam->data_connected = true; 74341c23958SJohan Hovold 744aab4a1a3SLaurent Pinchart ret = gb_svc_intf_set_power_mode(svc, connection->intf->interface_id, 745aab4a1a3SLaurent Pinchart GB_SVC_UNIPRO_HS_SERIES_A, 746aab4a1a3SLaurent Pinchart GB_SVC_UNIPRO_FAST_MODE, 2, 2, 747aab4a1a3SLaurent Pinchart GB_SVC_UNIPRO_FAST_MODE, 2, 2, 748aab4a1a3SLaurent Pinchart GB_SVC_PWRM_RXTERMINATION | 749aab4a1a3SLaurent Pinchart GB_SVC_PWRM_TXTERMINATION, 0); 750bcc050beSLaurent Pinchart if (ret < 0) 751bcc050beSLaurent Pinchart goto error; 752bcc050beSLaurent Pinchart 753aab4a1a3SLaurent Pinchart ret = gb_svc_intf_set_power_mode(svc, svc->ap_intf_id, 754aab4a1a3SLaurent Pinchart GB_SVC_UNIPRO_HS_SERIES_A, 755aab4a1a3SLaurent Pinchart GB_SVC_UNIPRO_FAST_MODE, 2, 2, 756aab4a1a3SLaurent Pinchart GB_SVC_UNIPRO_FAST_MODE, 2, 2, 757aab4a1a3SLaurent Pinchart GB_SVC_PWRM_RXTERMINATION | 758aab4a1a3SLaurent Pinchart GB_SVC_PWRM_TXTERMINATION, 0); 759bcc050beSLaurent Pinchart if (ret < 0) 760bcc050beSLaurent Pinchart goto error; 761bcc050beSLaurent Pinchart 7623265edafSLaurent Pinchart ret = gb_camera_debugfs_init(gcam); 7633265edafSLaurent Pinchart if (ret < 0) 7643265edafSLaurent Pinchart goto error; 7653265edafSLaurent Pinchart 7663a8dba4eSGjorgji Rosikopulos ret = gb_camera_register_intf_ops(gcam); 7673a8dba4eSGjorgji Rosikopulos if (ret < 0) 7683a8dba4eSGjorgji Rosikopulos goto error; 7693a8dba4eSGjorgji Rosikopulos 7703265edafSLaurent Pinchart return 0; 7713265edafSLaurent Pinchart 7723265edafSLaurent Pinchart error: 7733265edafSLaurent Pinchart gb_camera_cleanup(gcam); 7743265edafSLaurent Pinchart return ret; 7753265edafSLaurent Pinchart } 7763265edafSLaurent Pinchart 7773265edafSLaurent Pinchart static void gb_camera_connection_exit(struct gb_connection *connection) 7783265edafSLaurent Pinchart { 7793265edafSLaurent Pinchart struct gb_camera *gcam = connection->private; 7803265edafSLaurent Pinchart 7813265edafSLaurent Pinchart gb_camera_cleanup(gcam); 7823265edafSLaurent Pinchart } 7833265edafSLaurent Pinchart 7843265edafSLaurent Pinchart static struct gb_protocol camera_protocol = { 7853265edafSLaurent Pinchart .name = "camera", 7863265edafSLaurent Pinchart .id = GREYBUS_PROTOCOL_CAMERA_MGMT, 7873265edafSLaurent Pinchart .major = GB_CAMERA_VERSION_MAJOR, 7883265edafSLaurent Pinchart .minor = GB_CAMERA_VERSION_MINOR, 7893265edafSLaurent Pinchart .connection_init = gb_camera_connection_init, 7903265edafSLaurent Pinchart .connection_exit = gb_camera_connection_exit, 7913265edafSLaurent Pinchart .request_recv = gb_camera_event_recv, 7923265edafSLaurent Pinchart }; 7933265edafSLaurent Pinchart 7943265edafSLaurent Pinchart gb_protocol_driver(&camera_protocol); 7953265edafSLaurent Pinchart 7963265edafSLaurent Pinchart MODULE_LICENSE("GPL v2"); 797