Skip to content

Commit

Permalink
usb: chipidea: add support for roles
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alexander Shishkin authored and Greg Kroah-Hartman committed May 11, 2012
1 parent e443b33 commit 5f36e23
Show file tree
Hide file tree
Showing 7 changed files with 325 additions and 115 deletions.
18 changes: 18 additions & 0 deletions drivers/usb/chipidea/bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@
#define DEVLC_PSPD (0x03UL << 25)
#define DEVLC_PSPD_HS (0x02UL << 25)

/* OTGSC */
#define OTGSC_IDPU BIT(5)
#define OTGSC_ID BIT(8)
#define OTGSC_AVV BIT(9)
#define OTGSC_ASV BIT(10)
#define OTGSC_BSV BIT(11)
#define OTGSC_BSE BIT(12)
#define OTGSC_IDIS BIT(16)
#define OTGSC_AVVIS BIT(17)
#define OTGSC_ASVIS BIT(18)
#define OTGSC_BSVIS BIT(19)
#define OTGSC_BSEIS BIT(20)
#define OTGSC_IDIE BIT(24)
#define OTGSC_AVVIE BIT(25)
#define OTGSC_ASVIE BIT(26)
#define OTGSC_BSVIE BIT(27)
#define OTGSC_BSEIE BIT(28)

/* USBMODE */
#define USBMODE_CM (0x03UL << 0)
#define USBMODE_CM_IDLE (0x00UL << 0)
Expand Down
64 changes: 61 additions & 3 deletions drivers/usb/chipidea/ci.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define __DRIVERS_USB_CHIPIDEA_CI_H

#include <linux/list.h>
#include <linux/irqreturn.h>
#include <linux/usb/gadget.h>

/******************************************************************************
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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
*****************************************************************************/
Expand All @@ -107,6 +167,7 @@ enum ci13xxx_regs {
OP_ENDPTLISTADDR,
OP_PORTSC,
OP_DEVLC,
OP_OTGSC,
OP_USBMODE,
OP_ENDPTSETUPSTAT,
OP_ENDPTPRIME,
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/chipidea/ci13xxx_msm.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)

dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");

plat_ci = platform_device_alloc("ci_udc", -1);
plat_ci = platform_device_alloc("ci_hdrc", -1);
if (!plat_ci) {
dev_err(&pdev->dev, "can't allocate ci_udc platform device\n");
dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
return -ENOMEM;
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/chipidea/ci13xxx_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
pci_set_master(pdev);
pci_try_set_mwi(pdev);

plat_ci = platform_device_alloc("ci_udc", -1);
plat_ci = platform_device_alloc("ci_hdrc", -1);
if (!plat_ci) {
dev_err(&pdev->dev, "can't allocate ci_udc platform device\n");
dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
retval = -ENOMEM;
goto disable_device;
}
Expand Down
Loading

0 comments on commit 5f36e23

Please sign in to comment.