diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index 06ea5293d389..ac9ade367e0a 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -16,7 +16,6 @@ #include #include -#include "es2.h" #include "greybus.h" #include "greybus_protocols.h" @@ -74,6 +73,17 @@ struct gb_camera_stream_config { * Camera Protocol Operations */ +/* vendor request to control the CSI transmitter */ +#define REQUEST_CSI_TX_CONTROL 0x08 + +struct ap_csi_config_request { + __u8 csi_id; + __u8 clock_mode; + __u8 num_lanes; + __u8 padding; + __le32 bus_freq; +} __packed; + static int gb_camera_configure_streams(struct gb_camera *gcam, unsigned int nstreams, unsigned int flags, @@ -81,7 +91,7 @@ static int gb_camera_configure_streams(struct gb_camera *gcam, { struct gb_camera_configure_streams_request *req; struct gb_camera_configure_streams_response *resp; - struct es2_ap_csi_config csi_cfg; + struct ap_csi_config_request csi_cfg; unsigned int i; size_t req_size; size_t resp_size; @@ -150,21 +160,22 @@ static int gb_camera_configure_streams(struct gb_camera *gcam, } } + memset(&csi_cfg, 0, sizeof(csi_cfg)); + /* Configure the CSI transmitter. Hardcode the parameters for now. */ if (nstreams && !(resp->flags & GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED)) { csi_cfg.csi_id = 1; csi_cfg.clock_mode = 0; csi_cfg.num_lanes = 4; - csi_cfg.bus_freq = 960000000; - - ret = es2_ap_csi_setup(gcam->connection->hd, true, &csi_cfg); + csi_cfg.bus_freq = cpu_to_le32(960000000); + ret = gb_hd_output(gcam->connection->hd, &csi_cfg, + sizeof(csi_cfg), REQUEST_CSI_TX_CONTROL, + false); } else if (nstreams == 0) { csi_cfg.csi_id = 1; - csi_cfg.clock_mode = 0; - csi_cfg.num_lanes = 0; - csi_cfg.bus_freq = 0; - - ret = es2_ap_csi_setup(gcam->connection->hd, false, &csi_cfg); + ret = gb_hd_output(gcam->connection->hd, &csi_cfg, + sizeof(csi_cfg), REQUEST_CSI_TX_CONTROL, + false); } if (ret < 0) diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c index af5d7496c6be..1b5487fec903 100644 --- a/drivers/staging/greybus/es2.c +++ b/drivers/staging/greybus/es2.c @@ -13,7 +13,6 @@ #include #include -#include "es2.h" #include "greybus.h" #include "kernel_ver.h" #include "connection.h" @@ -134,14 +133,6 @@ struct cport_to_ep { __u8 endpoint_out; }; -struct es2_ap_csi_config_request { - __u8 csi_id; - __u8 clock_mode; - __u8 num_lanes; - __u8 padding; - __le32 bus_freq; -} __packed; - static inline struct es2_ap_dev *hd_to_es2(struct gb_host_device *hd) { return (struct es2_ap_dev *)&hd->hd_priv; @@ -220,38 +211,87 @@ static int unmap_cport(struct es2_ap_dev *es2, u16 cport_id) } #endif -int es2_ap_csi_setup(struct gb_host_device *hd, bool start, - struct es2_ap_csi_config *cfg) +static int output_sync(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd) { - struct es2_ap_csi_config_request *cfg_req; - struct es2_ap_dev *es2 = hd_to_es2(hd); struct usb_device *udev = es2->usb_dev; + u8 *data; int retval; - cfg_req = kzalloc(sizeof(*cfg_req), GFP_KERNEL); - if (!cfg_req) + data = kmalloc(size, GFP_KERNEL); + if (!data) return -ENOMEM; - - cfg_req->csi_id = cfg->csi_id; - - if (start) { - cfg_req->clock_mode = cfg->clock_mode; - cfg_req->num_lanes = cfg->num_lanes; - cfg_req->bus_freq = cpu_to_le32(cfg->bus_freq); - } + memcpy(data, req, size); retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - REQUEST_CSI_TX_CONTROL, + cmd, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_INTERFACE, 0, 0, cfg_req, - sizeof(*cfg_req), ES2_TIMEOUT); + USB_RECIP_INTERFACE, + 0, 0, data, size, ES2_TIMEOUT); if (retval < 0) - dev_err(&udev->dev, "failed to setup csi: %d\n", retval); + dev_err(&udev->dev, "%s: return error %d\n", __func__, retval); + else + retval = 0; - kfree(cfg_req); + kfree(data); return retval; } -EXPORT_SYMBOL_GPL(es2_ap_csi_setup); + +static void ap_urb_complete(struct urb *urb) +{ + struct usb_ctrlrequest *dr = urb->context; + + kfree(dr); + usb_free_urb(urb); +} + +static int output_async(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd) +{ + struct usb_device *udev = es2->usb_dev; + struct urb *urb; + struct usb_ctrlrequest *dr; + u8 *buf; + int retval; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; + + dr = kmalloc(sizeof(*dr) + size, GFP_ATOMIC); + if (!dr) { + usb_free_urb(urb); + return -ENOMEM; + } + + buf = (u8 *)dr + sizeof(*dr); + memcpy(buf, req, size); + + dr->bRequest = cmd; + dr->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE; + dr->wValue = 0; + dr->wIndex = 0; + dr->wLength = cpu_to_le16(size); + + usb_fill_control_urb(urb, udev, usb_sndctrlpipe(udev, 0), + (unsigned char *)dr, buf, size, + ap_urb_complete, dr); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) { + usb_free_urb(urb); + kfree(dr); + } + return retval; +} + +static int output(struct gb_host_device *hd, void *req, u16 size, u8 cmd, + bool async) +{ + struct es2_ap_dev *es2 = hd_to_es2(hd); + + if (async) + return output_async(es2, req, size, cmd); + + return output_sync(es2, req, size, cmd); +} static int es2_cport_in_enable(struct es2_ap_dev *es2, struct es2_cport_in *cport_in) @@ -560,6 +600,7 @@ static struct gb_hd_driver es2_driver = { .cport_enable = cport_enable, .latency_tag_enable = latency_tag_enable, .latency_tag_disable = latency_tag_disable, + .output = output, }; /* Common function to report consistent warnings based on URB status */ diff --git a/drivers/staging/greybus/es2.h b/drivers/staging/greybus/es2.h deleted file mode 100644 index ea2977049481..000000000000 --- a/drivers/staging/greybus/es2.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Greybus "AP" USB driver for "ES2" controller chips - * - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - * - * Released under the GPLv2 only. - */ - -#ifndef __ES2_H -#define __ES2_H - -#include - -struct gb_host_device; - -struct es2_ap_csi_config { - u8 csi_id; - u8 clock_mode; - u8 num_lanes; - u32 bus_freq; -}; - -int es2_ap_csi_setup(struct gb_host_device *hd, bool start, - struct es2_ap_csi_config *cfg); - -#endif /* __ES2_H */ diff --git a/drivers/staging/greybus/hd.c b/drivers/staging/greybus/hd.c index bff6861b8af7..b11a63644235 100644 --- a/drivers/staging/greybus/hd.c +++ b/drivers/staging/greybus/hd.c @@ -17,6 +17,15 @@ static struct ida gb_hd_bus_id_map; +int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd, + bool async) +{ + if (!hd || !hd->driver || !hd->driver->output) + return -EINVAL; + return hd->driver->output(hd, req, size, cmd, async); +} +EXPORT_SYMBOL_GPL(gb_hd_output); + static void gb_hd_release(struct device *dev) { struct gb_host_device *hd = to_gb_host_device(dev); diff --git a/drivers/staging/greybus/hd.h b/drivers/staging/greybus/hd.h index d828129475cd..e11359b145e6 100644 --- a/drivers/staging/greybus/hd.h +++ b/drivers/staging/greybus/hd.h @@ -23,6 +23,8 @@ struct gb_hd_driver { void (*message_cancel)(struct gb_message *message); int (*latency_tag_enable)(struct gb_host_device *hd, u16 cport_id); int (*latency_tag_disable)(struct gb_host_device *hd, u16 cport_id); + int (*output)(struct gb_host_device *hd, void *req, u16 size, u8 cmd, + bool async); }; struct gb_host_device { @@ -53,6 +55,8 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, int gb_hd_add(struct gb_host_device *hd); void gb_hd_del(struct gb_host_device *hd); void gb_hd_put(struct gb_host_device *hd); +int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd, + bool in_irq); int gb_hd_init(void); void gb_hd_exit(void);