All of lore.kernel.org
 help / color / mirror / Atom feed
From: daniel@caiaq.de (Daniel Mack)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for USB host port 2 on PXA310.
Date: Wed, 14 Apr 2010 00:06:42 +0200	[thread overview]
Message-ID: <20100413220642.GW30801@buzzloop.caiaq.de> (raw)
In-Reply-To: <fa93111b71cf1e43eef23869466072be4db67bcd.1270651775.git.grinberg@compulab.co.il>

On Wed, Apr 07, 2010 at 06:05:22PM +0300, Igor Grinberg wrote:
> Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
> Signed-off-by: Mike Rapoport <mike@compulab.co.il>
> ---
>  arch/arm/mach-pxa/Makefile      |    1 +
>  arch/arm/mach-pxa/pxa310-ulpi.c |  240 +++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-pxa/pxa310-ulpi.h |   85 ++++++++++++++
>  3 files changed, 326 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.c
>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.h

The USB OTG/ULPI framework could well be reused for that I think. All
that you would need is a struct otg_io_access_ops with two function
pointers to read and write registers. Then you can use otg_ulpi_create()
to set up an ULPI compliant device connected to the bus.

Have a look at the MXC code, I believe adopting that framework is better
than re-inventing it.

Daniel



> diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
> index 86bc87b..76d52f4 100644
> --- a/arch/arm/mach-pxa/Makefile
> +++ b/arch/arm/mach-pxa/Makefile
> @@ -21,6 +21,7 @@ obj-$(CONFIG_PXA25x)		+= mfp-pxa2xx.o pxa2xx.o pxa25x.o
>  obj-$(CONFIG_PXA27x)		+= mfp-pxa2xx.o pxa2xx.o pxa27x.o
>  obj-$(CONFIG_PXA3xx)		+= mfp-pxa3xx.o pxa3xx.o smemc.o
>  obj-$(CONFIG_CPU_PXA300)	+= pxa300.o
> +obj-$(CONFIG_CPU_PXA310)	+= pxa310-ulpi.o
>  obj-$(CONFIG_CPU_PXA320)	+= pxa320.o
>  obj-$(CONFIG_CPU_PXA930)	+= pxa930.o
>  
> diff --git a/arch/arm/mach-pxa/pxa310-ulpi.c b/arch/arm/mach-pxa/pxa310-ulpi.c
> new file mode 100644
> index 0000000..ab82db8
> --- /dev/null
> +++ b/arch/arm/mach-pxa/pxa310-ulpi.c
> @@ -0,0 +1,240 @@
> +/*
> + * linux/arch/arm/mach-pxa/pxa310-ulpi.c
> + *
> + * PXA310 ULPI USB host implementation.
> + *
> + * Copyright (C) 2010 CompuLab Ltd.
> + *
> + * Igor Grinberg <grinberg@compulab.co.il>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include <linux/clk.h>
> +
> +#include <mach/regs-u2d.h>
> +
> +#include "pxa310-ulpi.h"
> +
> +static void __iomem *u2d_mmio_base;
> +
> +static inline unsigned int u2d_readl(unsigned int off)
> +{
> +	return __raw_readl(u2d_mmio_base + off);
> +}
> +
> +static inline void u2d_writel(unsigned int off, unsigned int val)
> +{
> +	__raw_writel(val, u2d_mmio_base + off);
> +}
> +
> +static inline enum u2d_phy_mode ulpi_get_phymode(void)
> +{
> +	return (u2d_readl(U2DOTGUSR) & 0xF0000000) >> 28;
> +}
> +
> +static bool ulpi_is_in_sync_mode(void)
> +{
> +	enum u2d_phy_mode state = ulpi_get_phymode();
> +
> +	return (state == SYNCH) || (state == PRE_SYNCH);
> +}
> +
> +static int ulpi_poll(void)
> +{
> +	int timeout = 50000;
> +
> +	while (timeout--) {
> +		if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
> +			return 0;
> +
> +		cpu_relax();
> +	}
> +
> +	pr_warning("%s: ULPI access timed out!\n", __func__);
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int ulpi_reg_read(u8 reg, u8 *value)
> +{
> +	int err = 0;
> +
> +	if (!ulpi_is_in_sync_mode()) {
> +		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
> +		return -EBUSY;
> +	}
> +
> +	u2d_writel(U2DOTGUCR,
> +		   U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << U2DOTGUCR_ADDR_S));
> +	msleep(5);
> +
> +	err = ulpi_poll();
> +	if (err)
> +		return err;
> +
> +	*value = (u8)(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA);
> +
> +	return 0;
> +}
> +
> +static int ulpi_reg_write(u8 reg, u8 value)
> +{
> +	int err;
> +
> +	if (!ulpi_is_in_sync_mode()) {
> +		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
> +		return -EBUSY;
> +	}
> +
> +	u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << U2DOTGUCR_ADDR_S)
> +					    | (value << U2DOTGUCR_WDATA_S));
> +	msleep(5);
> +
> +	err = ulpi_poll();
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static int u2d_clk_enable(void)
> +{
> +	int err;
> +	struct clk *u2d_clk;
> +
> +	u2d_clk = clk_get(NULL, "U2DCLK");
> +	if (IS_ERR(u2d_clk)) {
> +		err = PTR_ERR(u2d_clk);
> +		pr_err("%s: failed to get U2DCLK: %d\n", __func__, err);
> +		return err;
> +	}
> +	clk_enable(u2d_clk);
> +
> +	return 0;
> +}
> +
> +static void u2d_otg_host_init(void)
> +{
> +	u32 u2dotgcr;
> +
> +	/* setup OTG controller registers */
> +	u2dotgcr = u2d_readl(U2DOTGCR);
> +	u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
> +	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
> +	u2d_writel(U2DOTGCR, u2dotgcr);
> +	msleep(5);
> +	u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
> +	msleep(5);
> +
> +	/* no OTG interrupts in host mode */
> +	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~U2DOTGICR_MASK);
> +}
> +
> +static void u2d_ulpi_rtsm(void)
> +{
> +	u32 u2dotgcr;
> +
> +	/* put PHY to sync mode */
> +	u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_RTSM);
> +	msleep(10);
> +
> +	/* setup OTG sync mode */
> +	u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_ULAF;
> +	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
> +	u2d_writel(U2DOTGCR, u2dotgcr);
> +}
> +
> +static void u2d_disable_otg_device(void)
> +{
> +	/* disable USB2 Device controller */
> +	u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
> +	u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
> +
> +	/* disable the otg interrupts */
> +	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~U2DOTGICR_MASK);
> +}
> +
> +static int u2d_set_ulpi_serial(enum u2d_phy_mode mode)
> +{
> +	int err = 0;
> +	u32 u2dotgcr;
> +
> +	/* enable the 15K Ohm pull-down resistor on D+ */
> +	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DPPULLDOWN);
> +	if (err)
> +		return err;
> +
> +	/* enable the 15K Ohm pull-down resistor on D- */
> +	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DMPULLDOWN);
> +	if (err)
> +		return err;
> +
> +	/* drive 5V on VBUS */
> +	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DRVVBUS);
> +	if (err)
> +		return err;
> +
> +	/* configure UHC for 6/3-pin serial mode */
> +	if (mode == SER_6PIN)
> +		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
> +	else if (mode == SER_3PIN)
> +		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
> +
> +	/* put PHY into host mode */
> +	err = ulpi_reg_write(ULPI_FUNCTION_CONTROL_SET, 0x45);
> +	if (err)
> +		return err;
> +
> +	/* set PHY to serial 6/3 pin mode */
> +	if (mode == SER_6PIN)
> +		err = ulpi_reg_write(ULPI_INTERFACE_CONTROL, ULPI_IC_6PIN);
> +	else if (mode == SER_3PIN)
> +		err = ulpi_reg_write(ULPI_INTERFACE_CONTROL, ULPI_IC_3PIN);
> +	if (err)
> +		return err;
> +
> +	/* enable the serial mode */
> +	u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
> +	u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
> +
> +	return 0;
> +}
> +
> +int pxa310_ulpi_init(enum u2d_phy_mode mode)
> +{
> +	int err;
> +
> +	err = u2d_clk_enable();
> +	if (err)
> +		goto err_out;
> +
> +	u2d_mmio_base = ioremap(U2D_PHYS_BASE, 0x1300);
> +	if (u2d_mmio_base == NULL) {
> +		pr_err("%s: failed to remap U2D registers address space\n",
> +			__func__);
> +		err = -ENOMEM;
> +		goto err_out;
> +	}
> +
> +	u2d_otg_host_init();
> +	u2d_ulpi_rtsm();
> +	u2d_disable_otg_device();
> +
> +	err = u2d_set_ulpi_serial(mode);
> +	if (err)
> +		goto err_out;
> +
> +	return 0;
> +
> +err_out:
> +	pr_err("%s: ULPI init failed: %d\n", __func__, err);
> +	return err;
> +}
> diff --git a/arch/arm/mach-pxa/pxa310-ulpi.h b/arch/arm/mach-pxa/pxa310-ulpi.h
> new file mode 100644
> index 0000000..87558f0
> --- /dev/null
> +++ b/arch/arm/mach-pxa/pxa310-ulpi.h
> @@ -0,0 +1,85 @@
> +/*
> + * linux/arch/arm/mach-pxa/pxa310-ulpi.h
> + *
> + * PXA310 ULPI USB host header file.
> + *
> + * Copyright (C) 2010 CompuLab Ltd.
> + *
> + * Igor Grinberg <grinberg@compulab.co.il>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef __PXA310_ULPI__
> +#define __PXA310_ULPI__
> +
> +/* OTG Interrupts */
> +#define U2DOTGICR_MASK		0x37F7F
> +
> +/* PXA310 USB OTG Controller */
> +#define ULPI_VENDOR_LOW		0x0
> +#define ULPI_VENDOR_HIGH		0x1
> +#define ULPI_PRODUCT_LOW		0x2
> +#define ULPI_PRODUCT_HIGH		0x3
> +#define ULPI_FUNCTION_CONTROL		0x4
> +#define ULPI_FUNCTION_CONTROL_SET	0x5
> +#define ULPI_FUNCTION_CONTROL_CLEAR	0x6
> +#define ULPI_INTERFACE_CONTROL		0x7
> +#define ULPI_INTERFACE_CONTROL_SET	0x8
> +#define ULPI_INTERFACE_CONTROL_CLEAR	0x9
> +#define ULPI_OTG_CONTROL		0xA
> +#define ULPI_OTG_CONTROL_SET		0xB
> +#define ULPI_OTG_CONTROL_CLEAR		0xC
> +#define ULPI_INT_RISE			0xD
> +#define ULPI_INT_RISE_SET		0xE
> +#define ULPI_INT_RISE_CLEAR		0xF
> +#define ULPI_INT_FALL			0x10
> +#define ULPI_INT_FALL_SET		0x11
> +#define ULPI_INT_FALL_CLEAR		0x12
> +#define ULPI_INT_STATUS		0x13
> +#define ULPI_INT_LATCH			0x14
> +#define ULPI_DEBUG			0x15
> +#define ULPI_SCRATCH			0x16
> +#define ULPI_SCRATCH_SET		0x17
> +#define ULPI_SCRATCH_CLEAR		0x18
> +
> +#define ULPI_FC_RESET		(1 << 5)	/* XCVR Reset */
> +#define ULPI_FC_SUSPENDM	(1 << 6)	/* XCVR SuspendM, Low Power Mode */
> +
> +#define ULPI_IC_6PIN		(1 << 0)	/* XCVR 6 pin mode */
> +#define ULPI_IC_3PIN		(1 << 1)	/* XCVR 3 pin mode */
> +#define ULPI_IC_CARKIT		(1 << 2)	/* Carkit mode */
> +#define ULPI_IC_CLKSUSPENDM	(1 << 3)	/* Active low clock suspend */
> +
> +#define ULPI_OC_IDPULLUP	(1 << 0)	/* ID Pull Up, enable sampling of ID line */
> +#define ULPI_OC_DPPULLDOWN	(1 << 1)	/* Enable the 15K Ohm pull down resistor on D+ */
> +#define ULPI_OC_DMPULLDOWN	(1 << 2)	/* Enable the 15K Ohm pull down resistor on D- */
> +#define ULPI_OC_DISCHRGVBUS	(1 << 3)	/* Discharge Vbus */
> +#define ULPI_OC_CHRGVBUS	(1 << 4)	/* Charge Vbus, for Vbus pulsing SRP */
> +#define ULPI_OC_DRVVBUS	(1 << 5)	/* Drive 5V on Vbus */
> +#define ULPI_OC_DRVVBUSEXT	(1 << 6)	/* Drive Vbus using external supply */
> +
> +#define ULPI_INT_HOSTDISCON	(1 << 0)	/* Host Disconnect */
> +#define ULPI_INT_VBUSVALID	(1 << 1)	/* Vbus Valid */
> +#define ULPI_INT_SESSIONVALID	(1 << 2)	/* Session Valid */
> +#define ULPI_INT_SESSIONEND	(1 << 3)	/* Session End */
> +#define ULPI_INT_IDGND		(1 << 4)	/* current status of IDGND */
> +
> +#define U2DOTGUCR_ADDR_S	(16)
> +#define U2DOTGUCR_WDATA_S	(8)
> +
> +#define U2D_PHYS_BASE   0x54100000
> +
> +enum u2d_phy_mode {
> +	SYNCH		= 0,
> +	CARKIT		= (1 << 0),
> +	SER_3PIN	= (1 << 1),
> +	SER_6PIN	= (1 << 2),
> +	LOWPOWER	= (1 << 3),
> +	PRE_SYNCH	= (1 << 4),
> +};
> +
> +int pxa310_ulpi_init(enum u2d_phy_mode);
> +
> +#endif /* __PXA310_ULPI__ */
> -- 
> 1.6.4.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2010-04-13 22:06 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-04-07 15:05 [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Igor Grinberg
2010-04-07 15:05 ` [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for " Igor Grinberg
2010-04-13 20:18   ` Eric Miao
2010-04-13 22:06   ` Daniel Mack [this message]
2010-04-13 22:47     ` Eric Miao
2010-04-14 15:03       ` Igor Grinberg
2010-04-07 15:05 ` [PATCH 2/2] [ARM] pxa/cm-x300: enable USB host port 2 on modules with PXA310 cpu Igor Grinberg
2010-04-12  5:52 ` [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Mike Rapoport

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100413220642.GW30801@buzzloop.caiaq.de \
    --to=daniel@caiaq.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.