Commit eb70e5ab authored by Alexander Shishkin's avatar Alexander Shishkin Committed by Greg Kroah-Hartman
Browse files

usb: chipidea: add host role



This adds EHCI host support to the chipidea driver. We want it to be
part of the hdrc driver and not a standalone (sub-)driver module, as
the structure of ehci-hcd.c suggests, so for chipidea controller we
hack it to not provide platform-related code, but only the ehci hcd.

The ehci-platform driver won't work for us here too, because the
controller uses the same registers for both device and host mode and
also otg-related bits, so it's not really possible to put ehci registers
into a separate resource.

This is not a pretty solution, but the alternative is exporting symbols
from the chipidea driver to a ehci-chipidea driver and doing all the
module refcounting.

Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 758fc986
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -18,6 +18,12 @@ config USB_CHIPIDEA_UDC
	  Say Y here to enable device controller functionality of the
	  ChipIdea driver.

config USB_CHIPIDEA_HOST
	bool "ChipIdea host controller"
	help
	  Say Y here to enable host controller functionality of the
	  ChipIdea driver.

config USB_CHIPIDEA_DEBUG
	bool "ChipIdea driver debug"
	help
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o

ci_hdrc-y				:= core.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o

ifneq ($(CONFIG_PCI),)
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
/* DCCPARAMS */
#define DCCPARAMS_DEN         (0x1F << 0)
#define DCCPARAMS_DC          BIT(7)
#define DCCPARAMS_HC          BIT(8)

/* TESTMODE */
#define TESTMODE_FORCE        BIT(0)
+6 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

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

/******************************************************************************
@@ -84,6 +85,7 @@ struct ci_role_driver {
/**
 * struct hw_bank - hardware register mapping representation
 * @lpm: set if the device is LPM capable
 * @phys: physical address of the controller's registers
 * @abs: absolute address of the beginning of register window
 * @cap: capability registers
 * @op: operational registers
@@ -92,6 +94,7 @@ struct ci_role_driver {
 */
struct hw_bank {
	unsigned	lpm;
	resource_size_t	phys;
	void __iomem	*abs;
	void __iomem	*cap;
	void __iomem	*op;
@@ -128,6 +131,7 @@ struct hw_bank {
 * @udc_driver: platform specific information supplied by parent device
 * @vbus_active: is VBUS active
 * @transceiver: pointer to USB PHY, if any
 * @hcd: pointer to usb_hcd for ehci host driver
 */
struct ci13xxx {
	struct device			*dev;
@@ -160,6 +164,7 @@ struct ci13xxx {
	struct ci13xxx_udc_driver	*udc_driver;
	int				vbus_active;
	struct usb_phy			*transceiver;
	struct usb_hcd			*hcd;
};

static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@@ -302,7 +307,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
	return (val & mask) >> ffs_nr(mask);
}

int hw_device_reset(struct ci13xxx *ci);
int hw_device_reset(struct ci13xxx *ci, u32 mode);

int hw_port_test_set(struct ci13xxx *ci, u8 mode);

+11 −4
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@
#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "host.h"
#include "debug.h"

/* Controller register map */
@@ -215,7 +216,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
  *
 * This function returns an error code
 */
int hw_device_reset(struct ci13xxx *ci)
int hw_device_reset(struct ci13xxx *ci, u32 mode)
{
	/* should flush & stop before reset */
	hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
@@ -235,12 +236,12 @@ int hw_device_reset(struct ci13xxx *ci)

	/* USBMODE should be configured step by step */
	hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
	hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC);
	hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
	/* HW >= 2.3 */
	hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);

	if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) {
		pr_err("cannot enter in device mode");
	if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
		pr_err("cannot enter in %s mode", ci_role(ci)->name);
		pr_err("lpm = %i", ci->hw_bank.lpm);
		return -ENODEV;
	}
@@ -371,6 +372,8 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
		return -ENODEV;
	}

	ci->hw_bank.phys = res->start;

	ci->irq = platform_get_irq(pdev, 0);
	if (ci->irq < 0) {
		dev_err(dev, "missing IRQ\n");
@@ -385,6 +388,10 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
	}

	/* initialize role(s) before the interrupt is requested */
	ret = ci_hdrc_host_init(ci);
	if (ret)
		dev_info(dev, "doesn't support host\n");

	ret = ci_hdrc_gadget_init(ci);
	if (ret)
		dev_info(dev, "doesn't support gadget\n");
Loading