Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40dcd0e8 authored by Michael Grzeschik's avatar Michael Grzeschik Committed by Greg Kroah-Hartman
Browse files

usb: chipidea: add PTW, PTS and STS handling



This patch makes it possible to configure the PTW, PTS and STS bits
inside the portsc register for host and device mode before the driver
starts and the phy can be addressed as hardware implementation is
designed.

Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1c9af653
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -5,6 +5,11 @@ Required properties:
- reg: Should contain registers location and length
- interrupts: Should contain controller interrupt

Recommended properies:
- phy_type: the type of the phy connected to the core. Should be one
  of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
  property the PORTSC register won't be touched

Optional properties:
- fsl,usbphy: phandler of usb phy that connects to the only one port
- fsl,usbmisc: phandler of non-core register device, with one argument
+15 −1
Original line number Diff line number Diff line
@@ -48,10 +48,24 @@
#define PORTSC_SUSP           BIT(7)
#define PORTSC_HSP            BIT(9)
#define PORTSC_PTC            (0x0FUL << 16)
/* PTS and PTW for non lpm version only */
#define PORTSC_PTS(d)						\
	((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
#define PORTSC_PTW            BIT(28)
#define PORTSC_STS            BIT(29)

/* DEVLC */
#define DEVLC_PSPD            (0x03UL << 25)
#define DEVLC_PSPD_HS         (0x02UL << 25)
#define DEVLC_PTW             BIT(27)
#define DEVLC_STS             BIT(28)
#define DEVLC_PTS(d)          (((d) & 0x7) << 29)

/* Encoding for DEVLC_PTS and PORTSC_PTS */
#define PTS_UTMI              0
#define PTS_ULPI              2
#define PTS_SERIAL            3
#define PTS_HSIC              4

/* OTGSC */
#define OTGSC_IDPU	      BIT(5)
+48 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
#include <linux/usb/of.h>
#include <linux/phy.h>

#include "ci.h"
#include "udc.h"
@@ -207,6 +209,45 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
	return 0;
}

static void hw_phymode_configure(struct ci13xxx *ci)
{
	u32 portsc, lpm, sts;

	switch (ci->platdata->phy_mode) {
	case USBPHY_INTERFACE_MODE_UTMI:
		portsc = PORTSC_PTS(PTS_UTMI);
		lpm = DEVLC_PTS(PTS_UTMI);
		break;
	case USBPHY_INTERFACE_MODE_UTMIW:
		portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW;
		lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW;
		break;
	case USBPHY_INTERFACE_MODE_ULPI:
		portsc = PORTSC_PTS(PTS_ULPI);
		lpm = DEVLC_PTS(PTS_ULPI);
		break;
	case USBPHY_INTERFACE_MODE_SERIAL:
		portsc = PORTSC_PTS(PTS_SERIAL);
		lpm = DEVLC_PTS(PTS_SERIAL);
		sts = 1;
		break;
	case USBPHY_INTERFACE_MODE_HSIC:
		portsc = PORTSC_PTS(PTS_HSIC);
		lpm = DEVLC_PTS(PTS_HSIC);
		break;
	default:
		return;
	}

	if (ci->hw_bank.lpm) {
		hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm);
		hw_write(ci, OP_DEVLC, DEVLC_STS, sts);
	} else {
		hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc);
		hw_write(ci, OP_PORTSC, PORTSC_STS, sts);
	}
}

/**
 * hw_device_reset: resets chip (execute without interruption)
 * @ci: the controller
@@ -223,6 +264,7 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
	while (hw_read(ci, OP_USBCMD, USBCMD_RST))
		udelay(10);		/* not RTOS friendly */

	hw_phymode_configure(ci);

	if (ci->platdata->notify_event)
		ci->platdata->notify_event(ci,
@@ -369,6 +411,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
		return -ENODEV;
	}

	if (!dev->of_node && dev->parent)
		dev->of_node = dev->parent->of_node;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	base = devm_ioremap_resource(dev, res);
	if (IS_ERR(base))
@@ -408,6 +453,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
		return -ENODEV;
	}

	if (!ci->platdata->phy_mode)
		ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);

	/* initialize role(s) before the interrupt is requested */
	ret = ci_hdrc_host_init(ci);
	if (ret)
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ struct ci13xxx_platform_data {
	uintptr_t	 capoffset;
	unsigned	 power_budget;
	struct usb_phy	*phy;
	enum usb_phy_interface phy_mode;
	unsigned long	 flags;
#define CI13XXX_REGS_SHARED		BIT(0)
#define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)