aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea/ci.h
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2012-05-11 17:25:47 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-11 16:52:10 -0700
commit5f36e231e9dbffb5264612e5b5817ab574a5e5db (patch)
treea71027cded532334d3d51cbf737925240d34e7df /drivers/usb/chipidea/ci.h
parentusb: chipidea: split the driver code into units (diff)
downloadlinux-dev-5f36e231e9dbffb5264612e5b5817ab574a5e5db.tar.xz
linux-dev-5f36e231e9dbffb5264612e5b5817ab574a5e5db.zip
usb: chipidea: add support for roles
Add some generic code for roles and implement simple role switching based on ID pin state and/or a sysfs file. At this, we also rename the device to ci_hdrc, which is what it is. The "manual" switch is made into a sysfs file and not debugfs, because it might be useful even in non-debug context. For some boards, like sheevaplug, it seems to be the only way to switch roles without modifying the hardware, since the ID pin is always grounded. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/chipidea/ci.h')
-rw-r--r--drivers/usb/chipidea/ci.h64
1 files changed, 61 insertions, 3 deletions
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index f5b3b8538a3b..56cb73b1e903 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -14,6 +14,7 @@
#define __DRIVERS_USB_CHIPIDEA_CI_H
#include <linux/list.h>
+#include <linux/irqreturn.h>
#include <linux/usb/gadget.h>
/******************************************************************************
@@ -47,6 +48,26 @@ struct ci13xxx_ep {
struct dma_pool *td_pool;
};
+enum ci_role {
+ CI_ROLE_HOST = 0,
+ CI_ROLE_GADGET,
+ CI_ROLE_END,
+};
+
+/**
+ * struct ci_role_driver - host/gadget role driver
+ * start: start this role
+ * stop: stop this role
+ * irq: irq handler for this role
+ * name: role name string (host/gadget)
+ */
+struct ci_role_driver {
+ int (*start)(struct ci13xxx *);
+ void (*stop)(struct ci13xxx *);
+ irqreturn_t (*irq)(struct ci13xxx *);
+ const char *name;
+};
+
struct hw_bank {
unsigned lpm; /* is LPM? */
void __iomem *abs; /* bus map offset */
@@ -85,8 +106,47 @@ struct ci13xxx {
struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
int vbus_active; /* is VBUS active */
struct usb_phy *transceiver; /* Transceiver struct */
+ struct ci_role_driver *roles[CI_ROLE_END];
+ enum ci_role role;
+ bool is_otg;
+ struct work_struct work;
+ struct workqueue_struct *wq;
};
+static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
+{
+ BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
+ return ci->roles[ci->role];
+}
+
+static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
+{
+ int ret;
+
+ if (role >= CI_ROLE_END)
+ return -EINVAL;
+
+ if (!ci->roles[role])
+ return -ENXIO;
+
+ ret = ci->roles[role]->start(ci);
+ if (!ret)
+ ci->role = role;
+ return ret;
+}
+
+static inline void ci_role_stop(struct ci13xxx *ci)
+{
+ enum ci_role role = ci->role;
+
+ if (role == CI_ROLE_END)
+ return;
+
+ ci->role = CI_ROLE_END;
+
+ ci->roles[role]->stop(ci);
+}
+
/******************************************************************************
* REGISTERS
*****************************************************************************/
@@ -107,6 +167,7 @@ enum ci13xxx_regs {
OP_ENDPTLISTADDR,
OP_PORTSC,
OP_DEVLC,
+ OP_OTGSC,
OP_USBMODE,
OP_ENDPTSETUPSTAT,
OP_ENDPTPRIME,
@@ -118,7 +179,6 @@ enum ci13xxx_regs {
OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
};
-
/**
* ffs_nr: find first (least significant) bit set
* @x: the word to search
@@ -193,8 +253,6 @@ static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
return (val & mask) >> ffs_nr(mask);
}
-int hw_device_init(struct ci13xxx *udc, void __iomem *base,
- uintptr_t cap_offset);
int hw_device_reset(struct ci13xxx *ci);
int hw_port_test_set(struct ci13xxx *ci, u8 mode);