greybus: host: provide "generic" apbridge output calls
authorGreg Kroah-Hartman <gregkh@google.com>
Wed, 23 Dec 2015 02:21:51 +0000 (18:21 -0800)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 12 Jan 2016 19:11:49 +0000 (11:11 -0800)
Provide a new function, gb_hd_output() to send data to the apbridge.
This is useful for the camera and audio drivers that need to do this
type of messaging.

The camera driver is converted to use this new function, the audio
driver can use it when it gets merged later.

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Tested-by: Mark Greer <mgreer@animalcreek.com>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
drivers/staging/greybus/camera.c
drivers/staging/greybus/es2.c
drivers/staging/greybus/es2.h [deleted file]
drivers/staging/greybus/hd.c
drivers/staging/greybus/hd.h

index 06ea5293d389d5e2ff02e8cc9ed7147bee024fd3..ac9ade367e0a8afe91af77e2e2a250e5c55e9da6 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 
-#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)
index af5d7496c6be59478ef6e287bad99173ba751bd9..1b5487fec903b8e7f04022cc11700c6b2351783f 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/debugfs.h>
 #include <asm/unaligned.h>
 
-#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 (file)
index ea29770..0000000
+++ /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 <linux/types.h>
-
-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 */
index bff6861b8af79e5816a2a7bc2f82d6d34c0afa0e..b11a6364423595b987cc59011a342040f78d4258 100644 (file)
 
 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);
index d828129475cdd16c7f4eb140d05d9513b06e6cb9..e11359b145e641823f967b1001269fefe9791e23 100644 (file)
@@ -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);