Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH V2 2/2] thermal: broadcom: add Northstar thermal driver
From: Jon Mason @ 2017-03-31 14:23 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Stephen Warren, Lee Jones, Eric Anholt, Florian Fainelli, Ray Jui,
	Scott Branden, BCM Kernel Feedback,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-arm-kernel, Rafał Miłecki
In-Reply-To: <d678d252-a95a-58c0-8098-4401c67040a1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Fri, Mar 31, 2017 at 3:03 AM, Rafał Miłecki <zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 03/24/2017 03:35 PM, Jon Mason wrote:
>>
>> On Thu, Mar 23, 2017 at 11:30:45PM +0100, Rafał Miłecki wrote:
>>>
>>> diff --git a/drivers/thermal/broadcom/ns-thermal.c
>>> b/drivers/thermal/broadcom/ns-thermal.c
>>> new file mode 100644
>>> index 000000000000..acf3a4de62a4
>>> --- /dev/null
>>> +++ b/drivers/thermal/broadcom/ns-thermal.c
>>> @@ -0,0 +1,98 @@
>>> +/*
>>> + * Copyright (C) 2017 Rafał Miłecki <rafal-g1n6cQUeyibVItvQsEIGlw@public.gmane.org>
>>> + *
>>> + * 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/of_address.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/thermal.h>
>>> +
>>> +#define PVTMON_CONTROL0                                        0x00
>>> +#define PVTMON_CONTROL0_SEL_MASK                       0x0000000e
>>> +#define PVTMON_CONTROL0_SEL_TEMP_MONITOR               0x00000000
>>> +#define PVTMON_CONTROL0_SEL_TEST_MODE                  0x0000000e
>>> +#define PVTMON_STATUS                                  0x08
>>> +
>>> +struct ns_thermal {
>>> +       void __iomem *pvtmon;
>>> +};
>>> +
>>> +static int ns_thermal_get_temp(void *data, int *temp)
>>> +{
>>> +       struct ns_thermal *ns_thermal = data;
>>> +       u32 val;
>>> +
>>> +       val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0);
>>> +       if ((val & PVTMON_CONTROL0_SEL_MASK) !=
>>> PVTMON_CONTROL0_SEL_TEMP_MONITOR) {
>>> +               val &= ~PVTMON_CONTROL0_SEL_MASK;
>>> +               val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR;
>>
>>
>> I think this is slightly confusing here.  If this was off, ORing in 0
>> will not enable it.  I think we need to flip the #define to make it
>> PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE (or a less crappy name).
>> then use this line here to toggle it.  Something like
>>
>>                 val &= ~PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE;
>
>
> I don't understand this, can you help me further?
>
> OR-ing with 0 is only a cosmetic thing obviously - just to make it clear
> which
> value we expect to be set in bits 1:3. The important part is:
> val &= ~PVTMON_CONTROL0_SEL_MASK;

You are using a side effect of the masking to clear/enable the block.
I'm simply saying that we should be explicit about enabling it.  My
concern is that using the side effect hides what is being done and
could result in a bug somewhere down the line.  I think this is
improbable based on the code, but wanted to err on the side of
caution.

>
> AFAIU selecting any mode other than TEMP_MONITOR will disable monitor
> access.
> AFAIU even switchint to TEST_MODE will prevent access to temp, so I don't
> see
> how we could use PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE. It could be any
> value other than 0.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/3] dt-bindings: arm: amlogic: Add SoC information bindings
From: Neil Armstrong @ 2017-03-31 14:10 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Kevin Hilman, carlo, linux-amlogic, Linux ARM,
	Linux Kernel Mailing List, devicetree
In-Reply-To: <CAK8P3a199j=7mb=CMgROvaOCVU8=kYda9wkvG3O4rtqweSyC0g@mail.gmail.com>

On 03/31/2017 03:44 PM, Arnd Bergmann wrote:
> On Fri, Mar 31, 2017 at 10:47 AM, Neil Armstrong
> <narmstrong@baylibre.com> wrote:
>> Add bindings for the SoC information register of the Amlogic SoCs.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  Documentation/devicetree/bindings/arm/amlogic.txt | 20 ++++++++++++++++++++
>>  1 file changed, 20 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
>> index bfd5b55..b850985 100644
>> --- a/Documentation/devicetree/bindings/arm/amlogic.txt
>> +++ b/Documentation/devicetree/bindings/arm/amlogic.txt
>> @@ -52,3 +52,23 @@ Board compatible values:
>>    - "amlogic,q201" (Meson gxm s912)
>>    - "nexbox,a95x" (Meson gxbb or Meson gxl s905x)
>>    - "nexbox,a1" (Meson gxm s912)
>> +
>> +Amlogic Meson GX SoCs Information
>> +----------------------------------
>> +
>> +The Meson SoCs have a Product Register that allows to retrieve SoC type,
>> +package and revision information. If present, a device node for this register
>> +should be added.
>> +
>> +Required properties:
>> +  - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-socinfo".
>> +  - reg: Base address and length of the register block.
>> +
>> +Examples
>> +--------
>> +
>> +       chipid@220 {
>> +               compatible = "amlogic,meson-gx-socinfo";
>> +               reg = <0x0 0x00220 0x0 0x4>;
>> +       };
>> +
> 
> The register location would hint that this is in the middle of some block of
> random registers, i.e. a syscon or some unrelated device.
> 
> Are you sure that "socinfo" is the actual name of the IP block and that
> it only has a single 32-bit register?
> 
>      Arnd
> 

Hi Arnd,

I'm sorry I did not find any relevant registers in the docs or source code describing
it in a specific block of registers, and no close enough register definitions either.
They may be used by the secure firmware I imagine.

For the register name, Amlogic refers it to "cpu_version" in their code, but it really
gives some details on the whole SoC and package, and socinfo seems better.

Neil

^ permalink raw reply

* Re: [PATCH 2/3] dt-bindings: arm: amlogic: Add SoC information bindings
From: Arnd Bergmann @ 2017-03-31 13:44 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Kevin Hilman, carlo-KA+7E9HrN00dnm+yROfE0A,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Linux ARM,
	Linux Kernel Mailing List, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1490950079-10145-3-git-send-email-narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>

On Fri, Mar 31, 2017 at 10:47 AM, Neil Armstrong
<narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
> Add bindings for the SoC information register of the Amlogic SoCs.
>
> Signed-off-by: Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/arm/amlogic.txt | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
> index bfd5b55..b850985 100644
> --- a/Documentation/devicetree/bindings/arm/amlogic.txt
> +++ b/Documentation/devicetree/bindings/arm/amlogic.txt
> @@ -52,3 +52,23 @@ Board compatible values:
>    - "amlogic,q201" (Meson gxm s912)
>    - "nexbox,a95x" (Meson gxbb or Meson gxl s905x)
>    - "nexbox,a1" (Meson gxm s912)
> +
> +Amlogic Meson GX SoCs Information
> +----------------------------------
> +
> +The Meson SoCs have a Product Register that allows to retrieve SoC type,
> +package and revision information. If present, a device node for this register
> +should be added.
> +
> +Required properties:
> +  - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-socinfo".
> +  - reg: Base address and length of the register block.
> +
> +Examples
> +--------
> +
> +       chipid@220 {
> +               compatible = "amlogic,meson-gx-socinfo";
> +               reg = <0x0 0x00220 0x0 0x4>;
> +       };
> +

The register location would hint that this is in the middle of some block of
random registers, i.e. a syscon or some unrelated device.

Are you sure that "socinfo" is the actual name of the IP block and that
it only has a single 32-bit register?

     Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCHv3 00/10] Nokia H4+ support
From: Greg Kroah-Hartman @ 2017-03-31 13:33 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Rob Herring, Sebastian Reichel, Gustavo F. Padovan, Johan Hedberg,
	Samuel Thibault, Pavel Machek, Tony Lindgren, Jiri Slaby,
	Mark Rutland, open list:BLUETOOTH DRIVERS,
	linux-serial@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, David S. Miller
In-Reply-To: <C1A408F2-1DF8-4F49-B399-B936542DE6BC@holtmann.org>

On Wed, Mar 29, 2017 at 11:33:26PM +0200, Marcel Holtmann wrote:
> Hi Rob,
> 
> >> Here is PATCHv3 for the Nokia bluetooth patchset. I addressed all comments from
> >> Rob and Pavel regarding the serdev patches and dropped the *.dts patches, since
> >> they were queued by Tony. I also changed the patch order, so that the serdev
> >> patches come first. All of them have Acked-by from Rob, so I think it makes
> >> sense to merge them to serdev subsystem (now) and provide an immutable branch
> >> for the bluetooth subsystem.
> > 
> > Greg doesn't read cover letters generally and since the serdev patches
> > are Cc rather than To him, he's probably not planning to pick them up.
> 
> I wonder actually if we should merge all of these via bluetooth-next
> tree with proper Ack from Greg. However it would be good to also get
> buy in from Dave for merging this ultimately through net-next.

I don't really care where it goes.  I can take the whole thing in my
tty/serial tree now if no one objects and I get an ack from the relevant
maintainers {hint...}

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH 2/2] drivers/serial: Add driver for Aspeed virtual UART
From: Greg Kroah-Hartman @ 2017-03-31 13:31 UTC (permalink / raw)
  To: Joel Stanley
  Cc: Jiri Slaby, Mark Rutland, Rob Herring, Jeremy Kerr,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	openbmc-uLR06cmDAlY/bJ5BZ2RsiQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Benjamin Herrenschmidt
In-Reply-To: <20170328054458.29341-3-joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>

On Tue, Mar 28, 2017 at 04:14:58PM +1030, Joel Stanley wrote:
> From: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
> 
> This change adds a driver for the 16550-based Aspeed virtual UART
> device. We use a similar process to the of_serial driver for device
> probe, but expose some VUART-specific functions through sysfs too.
> 
> OpenPOWER host firmware doesn't like it when the host-side of the
> VUART's FIFO is not drained. This driver only disables host TX discard
> mode when the port is in use. We set the VUART enabled bit when we bind
> to the device, and clear it on unbind.
> 
> We don't want to do this on open/release, as the host may be using this
> bit to configure serial output modes, which is independent of whether
> the devices has been opened by BMC userspace.
> 
> Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/serial/8250.txt |   2 +
>  drivers/tty/serial/Kconfig                        |  10 +
>  drivers/tty/serial/Makefile                       |   1 +
>  drivers/tty/serial/aspeed-vuart.c                 | 335 ++++++++++++++++++++++
>  4 files changed, 348 insertions(+)
>  create mode 100644 drivers/tty/serial/aspeed-vuart.c
> 
> diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt
> index f86bb06c39e9..a12e9277ac5d 100644
> --- a/Documentation/devicetree/bindings/serial/8250.txt
> +++ b/Documentation/devicetree/bindings/serial/8250.txt
> @@ -19,6 +19,8 @@ Required properties:
>  	- "altr,16550-FIFO128"
>  	- "fsl,16550-FIFO64"
>  	- "fsl,ns16550"
> +	- "aspeed,ast2400-vuart"
> +	- "aspeed,ast2500-vuart"
>  	- "serial" if the port type is unknown.
>  - reg : offset and length of the register set for the device.
>  - interrupts : should contain uart interrupt.
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index e9cf5b67f1b7..758b69a51078 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1129,6 +1129,16 @@ config SERIAL_NETX_CONSOLE
>  	  If you have enabled the serial port on the Hilscher NetX SoC
>  	  you can make it the console by answering Y to this option.
>  
> +config SERIAL_ASPEED_VUART
> +	tristate "Aspeed Virtual UART"
> +	depends on OF
> +	depends on SERIAL_8250
> +	help
> +	  If you want to use the virtual UART (VUART) device on Aspeed
> +	  BMC platforms, enable this option. This enables the 16550A-
> +	  compatible device on the local LPC bus, giving a UART device
> +	  with no physical RS232 connections.
> +
>  config SERIAL_OMAP
>  	tristate "OMAP serial port support"
>  	depends on ARCH_OMAP2PLUS
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 2d6288bc4554..5b97b0fa29e2 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250/
>  
>  obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
>  obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
> +obj-$(CONFIG_SERIAL_ASPEED_VUART) += aspeed-vuart.o
>  obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
>  obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o
>  obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
> diff --git a/drivers/tty/serial/aspeed-vuart.c b/drivers/tty/serial/aspeed-vuart.c
> new file mode 100644
> index 000000000000..fc6fa6d243c8
> --- /dev/null
> +++ b/drivers/tty/serial/aspeed-vuart.c
> @@ -0,0 +1,335 @@
> +/*
> + *  Serial Port driver for Aspeed VUART device
> + *
> + *    Copyright (C) 2016 Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>, IBM Corp.
> + *    Copyright (C) 2006 Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>, IBM Corp.
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License
> + *  as published by the Free Software Foundation; either version
> + *  2 of the License, or (at your option) any later version.
> + *
> + */
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/clk.h>
> +
> +#include "8250/8250.h"
> +
> +#define AST_VUART_GCRA		0x20
> +#define AST_VUART_GCRA_VUART_EN		0x01
> +#define AST_VUART_GCRA_HOST_TX_DISCARD	0x20
> +#define AST_VUART_GCRB		0x24
> +#define AST_VUART_GCRB_HOST_SIRQ_MASK	0xf0
> +#define AST_VUART_GCRB_HOST_SIRQ_SHIFT	4
> +#define AST_VUART_ADDRL		0x28
> +#define AST_VUART_ADDRH		0x2c
> +
> +struct ast_vuart {
> +	struct platform_device *pdev;
> +	void __iomem		*regs;
> +	struct clk		*clk;
> +	int			line;
> +};
> +
> +static ssize_t ast_vuart_show_addr(struct device *dev,
> +		struct device_attribute *attr, char *buf)
> +{
> +	struct ast_vuart *vuart = dev_get_drvdata(dev);
> +	u16 addr;
> +
> +	addr = (readb(vuart->regs + AST_VUART_ADDRH) << 8) |
> +		(readb(vuart->regs + AST_VUART_ADDRL));
> +
> +	return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
> +}
> +
> +static ssize_t ast_vuart_set_addr(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t count)
> +{
> +	struct ast_vuart *vuart = dev_get_drvdata(dev);
> +	unsigned long val;
> +	int err;
> +
> +	err = kstrtoul(buf, 0, &val);
> +	if (err)
> +		return err;
> +
> +	writeb((val >> 8) & 0xff, vuart->regs + AST_VUART_ADDRH);
> +	writeb((val >> 0) & 0xff, vuart->regs + AST_VUART_ADDRL);
> +
> +	return count;
> +}
> +
> +static DEVICE_ATTR(lpc_address, 0664,
> +		ast_vuart_show_addr, ast_vuart_set_addr);

DEVICE_ATTR_RW()?

And why random sysfs files for a uart?  Where have you documented these?

> +
> +static ssize_t ast_vuart_show_sirq(struct device *dev,
> +		struct device_attribute *attr, char *buf)
> +{
> +	struct ast_vuart *vuart = dev_get_drvdata(dev);
> +	u8 reg;
> +
> +	reg = readb(vuart->regs + AST_VUART_GCRB);
> +	reg &= AST_VUART_GCRB_HOST_SIRQ_MASK;
> +	reg >>= AST_VUART_GCRB_HOST_SIRQ_SHIFT;
> +
> +	return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg);
> +}
> +
> +static ssize_t ast_vuart_set_sirq(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t count)
> +{
> +	struct ast_vuart *vuart = dev_get_drvdata(dev);
> +	unsigned long val;
> +	int err;
> +	u8 reg;
> +
> +	err = kstrtoul(buf, 0, &val);
> +	if (err)
> +		return err;
> +
> +	val <<= AST_VUART_GCRB_HOST_SIRQ_SHIFT;
> +	val &= AST_VUART_GCRB_HOST_SIRQ_MASK;
> +
> +	reg = readb(vuart->regs + AST_VUART_GCRB);
> +	reg &= ~AST_VUART_GCRB_HOST_SIRQ_MASK;
> +	reg |= val;
> +	writeb(reg, vuart->regs + AST_VUART_GCRB);
> +
> +	return count;
> +}
> +
> +static DEVICE_ATTR(sirq, 0664,
> +		ast_vuart_show_sirq, ast_vuart_set_sirq);

DEVICE_ATTR_RW().

> +
> +static void ast_vuart_set_enabled(struct ast_vuart *vuart, bool enabled)
> +{
> +	u8 reg;
> +
> +	reg = readb(vuart->regs + AST_VUART_GCRA);
> +	reg &= ~AST_VUART_GCRA_VUART_EN;
> +	if (enabled)
> +		reg |= AST_VUART_GCRA_VUART_EN;
> +	writeb(reg, vuart->regs + AST_VUART_GCRA);
> +}
> +
> +static void ast_vuart_set_host_tx_discard(struct ast_vuart *vuart, bool discard)
> +{
> +	u8 reg;
> +
> +	reg = readb(vuart->regs + AST_VUART_GCRA);
> +
> +	/* if the HOST_TX_DISCARD bit is set, discard is *disabled* */
> +	reg &= ~AST_VUART_GCRA_HOST_TX_DISCARD;
> +	if (!discard)
> +		reg |= AST_VUART_GCRA_HOST_TX_DISCARD;
> +
> +	writeb(reg, vuart->regs + AST_VUART_GCRA);
> +}
> +
> +static int ast_vuart_startup(struct uart_port *uart_port)
> +{
> +	struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
> +	struct ast_vuart *vuart = uart_8250_port->port.private_data;
> +	int rc;
> +
> +	rc = serial8250_do_startup(uart_port);
> +	if (rc)
> +		return rc;
> +
> +	ast_vuart_set_host_tx_discard(vuart, false);
> +
> +	return 0;
> +}
> +
> +static void ast_vuart_shutdown(struct uart_port *uart_port)
> +{
> +	struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
> +	struct ast_vuart *vuart = uart_8250_port->port.private_data;
> +
> +	ast_vuart_set_host_tx_discard(vuart, true);
> +
> +	serial8250_do_shutdown(uart_port);
> +}
> +
> +
> +/**
> + * The device tree parsing code here is heavily based on that of the of_serial
> + * driver, but we have a few core differences, as we need to use our own
> + * ioremapping for extra register support
> + */
> +static int ast_vuart_probe(struct platform_device *pdev)
> +{
> +	struct uart_8250_port port;
> +	struct resource resource;
> +	struct ast_vuart *vuart;
> +	struct device_node *np;
> +	u32 clk, prop;
> +	int rc;
> +
> +	np = pdev->dev.of_node;
> +
> +	vuart = devm_kzalloc(&pdev->dev, sizeof(*vuart), GFP_KERNEL);
> +	if (!vuart)
> +		return -ENOMEM;
> +
> +	vuart->pdev = pdev;
> +	rc = of_address_to_resource(np, 0, &resource);
> +	if (rc) {
> +		dev_warn(&pdev->dev, "invalid address\n");
> +		return rc;
> +	}
> +
> +	/* create our own mapping for VUART-specific registers */
> +	vuart->regs = devm_ioremap_resource(&pdev->dev, &resource);
> +	if (IS_ERR(vuart->regs)) {
> +		dev_warn(&pdev->dev, "failed to map registers\n");
> +		return PTR_ERR(vuart->regs);
> +	}
> +
> +	memset(&port, 0, sizeof(port));
> +	port.port.private_data = vuart;
> +	port.port.membase = vuart->regs;
> +	port.port.mapbase = resource.start;
> +	port.port.mapsize = resource_size(&resource);
> +	port.port.startup = ast_vuart_startup;
> +	port.port.shutdown = ast_vuart_shutdown;
> +
> +	if (of_property_read_u32(np, "clock-frequency", &clk)) {
> +		vuart->clk = devm_clk_get(&pdev->dev, NULL);
> +		if (IS_ERR(vuart->clk)) {
> +			dev_warn(&pdev->dev,
> +				"clk or clock-frequency not defined\n");
> +			return PTR_ERR(vuart->clk);
> +		}
> +
> +		rc = clk_prepare_enable(vuart->clk);
> +		if (rc < 0)
> +			return rc;
> +
> +		clk = clk_get_rate(vuart->clk);
> +	}
> +
> +	/* If current-speed was set, then try not to change it. */
> +	if (of_property_read_u32(np, "current-speed", &prop) == 0)
> +		port.port.custom_divisor = clk / (16 * prop);
> +
> +	/* Check for shifted address mapping */
> +	if (of_property_read_u32(np, "reg-offset", &prop) == 0)
> +		port.port.mapbase += prop;
> +
> +	/* Check for registers offset within the devices address range */
> +	if (of_property_read_u32(np, "reg-shift", &prop) == 0)
> +		port.port.regshift = prop;
> +
> +	/* Check for fifo size */
> +	if (of_property_read_u32(np, "fifo-size", &prop) == 0)
> +		port.port.fifosize = prop;
> +
> +	/* Check for a fixed line number */
> +	rc = of_alias_get_id(np, "serial");
> +	if (rc >= 0)
> +		port.port.line = rc;
> +
> +	port.port.irq = irq_of_parse_and_map(np, 0);
> +	port.port.irqflags = IRQF_SHARED;
> +	port.port.iotype = UPIO_MEM;
> +	if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
> +		switch (prop) {
> +		case 1:
> +			port.port.iotype = UPIO_MEM;
> +			break;
> +		case 4:
> +			port.port.iotype = of_device_is_big_endian(np) ?
> +				       UPIO_MEM32BE : UPIO_MEM32;
> +			break;
> +		default:
> +			dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n",
> +				 prop);
> +			rc = -EINVAL;
> +			goto err_clk_disable;
> +		}
> +	}
> +
> +	port.port.type = PORT_16550A;
> +	port.port.uartclk = clk;
> +	port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
> +		| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
> +
> +	if (of_find_property(np, "no-loopback-test", NULL))
> +		port.port.flags |= UPF_SKIP_TEST;
> +
> +	port.port.dev = &pdev->dev;
> +
> +	if (port.port.fifosize)
> +		port.capabilities = UART_CAP_FIFO;
> +
> +	if (of_property_read_bool(pdev->dev.of_node,
> +				  "auto-flow-control"))
> +		port.capabilities |= UART_CAP_AFE;
> +
> +	rc = serial8250_register_8250_port(&port);
> +	if (rc < 0)
> +		goto err_clk_disable;
> +
> +
> +	vuart->line = rc;
> +	ast_vuart_set_enabled(vuart, true);
> +	ast_vuart_set_host_tx_discard(vuart, true);
> +	platform_set_drvdata(pdev, vuart);
> +
> +	/* extra sysfs control */
> +	rc = device_create_file(&pdev->dev, &dev_attr_lpc_address);
> +	if (rc)
> +		dev_warn(&pdev->dev, "can't create lpc_address file\n");
> +	rc = device_create_file(&pdev->dev, &dev_attr_sirq);
> +	if (rc)
> +		dev_warn(&pdev->dev, "can't create sirq file\n");

use an attribute group?  You just raced userspace and lost :(

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 1/3] device property: Move FW type specific functionality to FW specific files
From: Sakari Ailus @ 2017-03-31 13:20 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
	sudeep.holla-5wv7dgnIgG8, lorenzo.pieralisi-5wv7dgnIgG8,
	rafael-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, ahs3-H+wXaHxf7aLQT0dZR+AlfA,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w
In-Reply-To: <20170327113100.GZ2957-3PARRvDOhMZrdx17CPfAsdBPR1lH4CV8@public.gmane.org>

Hi Mika,

Thanks for the review again!

Mika Westerberg wrote:
> On Fri, Mar 24, 2017 at 01:03:50PM +0200, Sakari Ailus wrote:
>> +static int acpi_fwnode_property_read_int_array(
>
> This is really ugly way to split arguments into multiple lines IMHO.
>
>> +	struct fwnode_handle *fwnode, const char *propname,
>> +	unsigned int elem_size, void *val, size_t nval)
>
>
> I would much more see something like:
>
> static int
> acpi_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
> 	const char *propname, unsigned int elem_size, void *val, size_t nval)
>
> or even
>
> static int
> acpi_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
> 				    const char *propname,
> 				    unsigned int elem_size,
> 				    void *val, size_t nval)
>
> ditto for all occurences.
>
> Other than that this patch looks reasonable to me.

I don't think CodingStyle defines any particular points where to wrap 
the lines. Different conventions seem to exist:

$ git grep '^\(static\|const\|inline\|int\|struct\|u\[0-9\).*($' |wc -l
3106

Not all of the occurrences found exhibit such indentation but then again 
the above does not catch all of those that do either.

I can change that if you insist but I'm telling you that it wouldn't be 
alone in the kernel. :-)

-- 
Kind regards,

Sakari Ailus
sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v3 2/7] UDC: Rename amd5536udc driver file based on IP
From: Raviteja Garimella @ 2017-03-31 13:16 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Rob Herring, Mark Rutland, Greg Kroah-Hartman, devicetree,
	linux-kernel, BCM Kernel Feedback, linux-usb
In-Reply-To: <87wpb5ixmo.fsf@linux.intel.com>

Hi Felipe,

On Fri, Mar 31, 2017 at 3:19 PM, Felipe Balbi <balbi@kernel.org> wrote:
>
> Hi,
>
> Raviteja Garimella <raviteja.garimella@broadcom.com> writes:
>
>> This patch renames the amd5536udc.c that has the core driver
>> functionality of Synopsys UDC to snps_udc_core.c
>>
>> The symbols exported here can be used by any UDC driver that uses
>> the same Synopsys IP.
>>
>> Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
>
> unfortunately, this patch doesn't apply:
>
> Applying: UDC: Rename amd5536udc driver file based on IP
> error: corrupt patch at line 235
> Patch failed at 0001 UDC: Rename amd5536udc driver file based on IP
> The copy of the patch that failed is found in: .git/rebase-apply/patch
> When you have resolved this problem, run "git am --continue".
> If you prefer to skip this patch, run "git am --skip" instead.
> To restore the original branch and stop patching, run "git am --abort".
>
> Can you rebase on testing/next and resend?

I rebased my patches against testing/next branch, resolved the merge conflicts.
Just resent the patches 2/7 to 7/7. Please use them. I verified they are getting
applied without issues now.

Thanks,
Ravi
>
> --
> balbi

^ permalink raw reply

* [RESEND PATCH v3 7/7] UDC: Add Synopsys UDC Platform driver
From: Raviteja Garimella @ 2017-03-31 13:09 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Greg Kroah-Hartman, Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb
In-Reply-To: <1490965753-3511-1-git-send-email-raviteja.garimella@broadcom.com>

This patch adds platform driver support for Synopsys UDC.

A new driver file (snps_udc_plat.c) is created for this purpose
where the platform driver registration is done based on OF
node.

Currently, UDC integrated into Broadcom's iProc SoCs (Northstar2
and Cygnus) work with this driver.

New members are added to the UDC data structure for having platform
device support along with extcon and phy support.

Kconfig and Makefiles are modified to select platform driver for
compilation.

Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
---
 drivers/usb/gadget/udc/Kconfig         |  16 +-
 drivers/usb/gadget/udc/Makefile        |   1 +
 drivers/usb/gadget/udc/amd5536udc.h    |  14 ++
 drivers/usb/gadget/udc/snps_udc_core.c |  54 ++++--
 drivers/usb/gadget/udc/snps_udc_plat.c | 344 +++++++++++++++++++++++++++++++++
 5 files changed, 409 insertions(+), 20 deletions(-)
 create mode 100644 drivers/usb/gadget/udc/snps_udc_plat.c

diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 707814d..b788caf 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -255,7 +255,7 @@ config USB_MV_U3D
 	  controller, which support super speed USB peripheral.
 
 config USB_SNP_CORE
-	depends on USB_AMD5536UDC
+	depends on (USB_AMD5536UDC || USB_SNP_UDC_PLAT)
 	tristate
 	help
 	  This enables core driver support for Synopsys USB 2.0 Device
@@ -268,6 +268,20 @@ config USB_SNP_CORE
 	  This IP is different to the High Speed OTG IP that can be enabled
 	  by selecting USB_DWC2 or USB_DWC3 options.
 
+config USB_SNP_UDC_PLAT
+	tristate "Synopsys USB 2.0 Device controller"
+	depends on (USB_GADGET && OF)
+	select USB_GADGET_DUALSPEED
+	select USB_SNP_CORE
+	default ARCH_BCM_IPROC
+	help
+	  This adds Platform Device support for Synopsys Designware core
+	  AHB subsystem USB2.0 Device Controller (UDC).
+
+	  This driver works with UDCs integrated into Broadcom's Northstar2
+	  and Cygnus SoCs.
+
+	  If unsure, say N.
 #
 # Controllers available in both integrated and discrete versions
 #
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index 4f4fd62..ea9e1c7 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -37,4 +37,5 @@ obj-$(CONFIG_USB_FOTG210_UDC)	+= fotg210-udc.o
 obj-$(CONFIG_USB_MV_U3D)	+= mv_u3d_core.o
 obj-$(CONFIG_USB_GR_UDC)	+= gr_udc.o
 obj-$(CONFIG_USB_GADGET_XILINX)	+= udc-xilinx.o
+obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o
 obj-$(CONFIG_USB_BDC_UDC)	+= bdc/
diff --git a/drivers/usb/gadget/udc/amd5536udc.h b/drivers/usb/gadget/udc/amd5536udc.h
index c252457..7884281 100644
--- a/drivers/usb/gadget/udc/amd5536udc.h
+++ b/drivers/usb/gadget/udc/amd5536udc.h
@@ -16,6 +16,7 @@
 /* debug control */
 /* #define UDC_VERBOSE */
 
+#include <linux/extcon.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
@@ -28,6 +29,9 @@
 #define UDC_HSA0_REV 1
 #define UDC_HSB1_REV 2
 
+/* Broadcom chip rev. */
+#define UDC_BCM_REV 10
+
 /*
  * SETUP usb commands
  * needed, because some SETUP's are handled in hw, but must be passed to
@@ -112,6 +116,7 @@
 #define UDC_DEVCTL_BRLEN_MASK			0x00ff0000
 #define UDC_DEVCTL_BRLEN_OFS			16
 
+#define UDC_DEVCTL_SRX_FLUSH			14
 #define UDC_DEVCTL_CSR_DONE			13
 #define UDC_DEVCTL_DEVNAK			12
 #define UDC_DEVCTL_SD				10
@@ -564,7 +569,15 @@ struct udc {
 	u16				cur_intf;
 	u16				cur_alt;
 
+	/* for platform device and extcon support */
 	struct device			*dev;
+	struct phy			*udc_phy;
+	struct extcon_dev		*edev;
+	struct extcon_specific_cable_nb	extcon_nb;
+	struct notifier_block		nb;
+	struct delayed_work		drd_work;
+	struct workqueue_struct		*drd_wq;
+	u32				conn_type;
 };
 
 #define to_amd5536_udc(g)	(container_of((g), struct udc, gadget))
@@ -580,6 +593,7 @@ int udc_enable_dev_setup_interrupts(struct udc *dev);
 int udc_mask_unused_interrupts(struct udc *dev);
 irqreturn_t udc_irq(int irq, void *pdev);
 void gadget_release(struct device *pdev);
+void empty_req_queue(struct udc_ep *ep);
 void udc_basic_init(struct udc *dev);
 void free_dma_pools(struct udc *dev);
 int init_dma_pools(struct udc *dev);
diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c
index d592f77..38a165d 100644
--- a/drivers/usb/gadget/udc/snps_udc_core.c
+++ b/drivers/usb/gadget/udc/snps_udc_core.c
@@ -41,7 +41,6 @@
 #include "amd5536udc.h"
 
 static void udc_tasklet_disconnect(unsigned long);
-static void empty_req_queue(struct udc_ep *);
 static void udc_setup_endpoints(struct udc *dev);
 static void udc_soft_reset(struct udc *dev);
 static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
@@ -1244,7 +1243,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
 }
 
 /* Empty request queue of an endpoint; caller holds spinlock */
-static void empty_req_queue(struct udc_ep *ep)
+void empty_req_queue(struct udc_ep *ep)
 {
 	struct udc_request	*req;
 
@@ -1256,6 +1255,7 @@ static void empty_req_queue(struct udc_ep *ep)
 		complete_req(ep, req, -ESHUTDOWN);
 	}
 }
+EXPORT_SYMBOL_GPL(empty_req_queue);
 
 /* Dequeues a request packet, called by gadget driver */
 static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
@@ -1623,6 +1623,9 @@ static void udc_setup_endpoints(struct udc *dev)
 /* Bringup after Connect event, initial bringup to be ready for ep0 events */
 static void usb_connect(struct udc *dev)
 {
+	/* Return if already connected */
+	if (dev->connected)
+		return;
 
 	dev_info(dev->dev, "USB Connect\n");
 
@@ -1641,6 +1644,9 @@ static void usb_connect(struct udc *dev)
  */
 static void usb_disconnect(struct udc *dev)
 {
+	/* Return if already disconnected */
+	if (!dev->connected)
+		return;
 
 	dev_info(dev->dev, "USB Disconnect\n");
 
@@ -1715,11 +1721,15 @@ static void udc_soft_reset(struct udc *dev)
 	/* device int. status reset */
 	writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
 
-	spin_lock_irqsave(&udc_irq_spinlock, flags);
-	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
-	readl(&dev->regs->cfg);
-	spin_unlock_irqrestore(&udc_irq_spinlock, flags);
-
+	/* Don't do this for Broadcom UDC since this is a reserved
+	 * bit.
+	 */
+	if (dev->chiprev != UDC_BCM_REV) {
+		spin_lock_irqsave(&udc_irq_spinlock, flags);
+		writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+		readl(&dev->regs->cfg);
+		spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+	}
 }
 
 /* RDE timer callback to set RDE bit */
@@ -3171,21 +3181,27 @@ int udc_probe(struct udc *dev)
 	dev_info(dev->dev, "%s\n", mod_desc);
 
 	snprintf(tmp, sizeof(tmp), "%d", dev->irq);
-	dev_info(dev->dev,
-		 "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
-		 tmp, dev->phys_addr, dev->chiprev,
-		 (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
-	strcpy(tmp, UDC_DRIVER_VERSION_STRING);
-	if (dev->chiprev == UDC_HSA0_REV) {
-		dev_err(dev->dev, "chip revision is A0; too old\n");
-		retval = -ENODEV;
-		goto finished;
+
+	/* Print this device info for AMD chips only*/
+	if (dev->chiprev == UDC_HSA0_REV ||
+	    dev->chiprev == UDC_HSB1_REV) {
+		dev_info(dev->dev, "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+			 tmp, dev->phys_addr, dev->chiprev,
+			 (dev->chiprev == UDC_HSA0_REV) ?
+			 "A0" : "B1");
+		strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+		if (dev->chiprev == UDC_HSA0_REV) {
+			dev_err(dev->dev, "chip revision is A0; too old\n");
+			retval = -ENODEV;
+			goto finished;
+		}
+		dev_info(dev->dev,
+			 "driver version: %s(for Geode5536 B1)\n", tmp);
 	}
-	dev_info(dev->dev,
-		 "driver version: %s(for Geode5536 B1)\n", tmp);
+
 	udc = dev;
 
-	retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
+	retval = usb_add_gadget_udc_release(udc->dev, &dev->gadget,
 					    gadget_release);
 	if (retval)
 		goto finished;
diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c
new file mode 100644
index 0000000..2e11f19
--- /dev/null
+++ b/drivers/usb/gadget/udc/snps_udc_plat.c
@@ -0,0 +1,344 @@
+/*
+ * snps_udc_plat.c - Synopsys UDC Platform Driver
+ *
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/extcon.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/module.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include "amd5536udc.h"
+
+/* description */
+#define UDC_MOD_DESCRIPTION     "Synopsys UDC platform driver"
+
+void start_udc(struct udc *udc)
+{
+	if (udc->driver) {
+		dev_info(udc->dev, "Connecting...\n");
+		udc_enable_dev_setup_interrupts(udc);
+		udc_basic_init(udc);
+		udc->connected = 1;
+	}
+}
+
+void stop_udc(struct udc *udc)
+{
+	int tmp;
+	u32 reg;
+
+	spin_lock(&udc->lock);
+
+	/* Flush the receieve fifo */
+	reg = readl(&udc->regs->ctl);
+	reg |= AMD_BIT(UDC_DEVCTL_SRX_FLUSH);
+	writel(reg, &udc->regs->ctl);
+
+	reg = readl(&udc->regs->ctl);
+	reg &= ~(AMD_BIT(UDC_DEVCTL_SRX_FLUSH));
+	writel(reg, &udc->regs->ctl);
+	dev_dbg(udc->dev, "ep rx queue flushed\n");
+
+	/* Mask interrupts. Required more so when the
+	 * UDC is connected to a DRD phy.
+	 */
+	udc_mask_unused_interrupts(udc);
+
+	/* Disconnect gadget driver */
+	if (udc->driver) {
+		spin_unlock(&udc->lock);
+		udc->driver->disconnect(&udc->gadget);
+		spin_lock(&udc->lock);
+
+		/* empty queues */
+		for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+			empty_req_queue(&udc->ep[tmp]);
+	}
+	udc->connected = 0;
+
+	spin_unlock(&udc->lock);
+	dev_info(udc->dev, "Device disconnected\n");
+}
+
+void udc_drd_work(struct work_struct *work)
+{
+	struct udc *udc;
+
+	udc = container_of(to_delayed_work(work),
+			   struct udc, drd_work);
+
+	if (udc->conn_type) {
+		dev_dbg(udc->dev, "idle -> device\n");
+		start_udc(udc);
+	} else {
+		dev_dbg(udc->dev, "device -> idle\n");
+		stop_udc(udc);
+	}
+}
+
+static int usbd_connect_notify(struct notifier_block *self,
+			       unsigned long event, void *ptr)
+{
+	struct udc *udc = container_of(self, struct udc, nb);
+
+	dev_dbg(udc->dev, "%s: event: %lu\n", __func__, event);
+
+	udc->conn_type = event;
+
+	schedule_delayed_work(&udc->drd_work, 0);
+
+	return NOTIFY_OK;
+}
+
+static int udc_plat_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct udc *udc;
+	int ret;
+
+	udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		return -ENOMEM;
+
+	spin_lock_init(&udc->lock);
+	udc->dev = dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	udc->virt_addr = devm_ioremap_resource(dev, res);
+	if (IS_ERR(udc->regs))
+		return PTR_ERR(udc->regs);
+
+	/* udc csr registers base */
+	udc->csr = udc->virt_addr + UDC_CSR_ADDR;
+
+	/* dev registers base */
+	udc->regs = udc->virt_addr + UDC_DEVCFG_ADDR;
+
+	/* ep registers base */
+	udc->ep_regs = udc->virt_addr + UDC_EPREGS_ADDR;
+
+	/* fifo's base */
+	udc->rxfifo = (u32 __iomem *)(udc->virt_addr + UDC_RXFIFO_ADDR);
+	udc->txfifo = (u32 __iomem *)(udc->virt_addr + UDC_TXFIFO_ADDR);
+
+	udc->phys_addr = (unsigned long)res->start;
+
+	udc->irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (udc->irq <= 0) {
+		dev_err(dev, "Can't parse and map interrupt\n");
+		return -EINVAL;
+	}
+
+	udc->udc_phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
+	if (IS_ERR(udc->udc_phy)) {
+		dev_err(dev, "Failed to obtain phy from device tree\n");
+		return PTR_ERR(udc->udc_phy);
+	}
+
+	ret = phy_init(udc->udc_phy);
+	if (ret) {
+		dev_err(dev, "UDC phy init failed");
+		return ret;
+	}
+
+	ret = phy_power_on(udc->udc_phy);
+	if (ret) {
+		dev_err(dev, "UDC phy power on failed");
+		phy_exit(udc->udc_phy);
+		return ret;
+	}
+
+	/* Register for extcon if supported */
+	if (of_get_property(dev->of_node, "extcon", NULL)) {
+		udc->edev = extcon_get_edev_by_phandle(dev, 0);
+		if (IS_ERR(udc->edev)) {
+			if (PTR_ERR(udc->edev) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_err(dev, "Invalid or missing extcon\n");
+			ret = PTR_ERR(udc->edev);
+			goto exit_phy;
+		}
+
+		udc->nb.notifier_call = usbd_connect_notify;
+		ret = extcon_register_notifier(udc->edev, EXTCON_USB,
+					       &udc->nb);
+		if (ret < 0) {
+			dev_err(dev, "Can't register extcon device\n");
+			goto exit_phy;
+		}
+
+		ret = extcon_get_cable_state_(udc->edev, EXTCON_USB);
+		if (ret < 0) {
+			dev_err(dev, "Can't get cable state\n");
+			goto exit_extcon;
+		} else if (ret) {
+			udc->conn_type = ret;
+		}
+		INIT_DELAYED_WORK(&udc->drd_work, udc_drd_work);
+	}
+
+	/* init dma pools */
+	if (use_dma) {
+		ret = init_dma_pools(udc);
+		if (ret != 0)
+			goto exit_extcon;
+	}
+
+	ret = devm_request_irq(dev, udc->irq, udc_irq, IRQF_SHARED,
+			       "snps-udc", udc);
+	if (ret < 0) {
+		dev_err(dev, "Request irq %d failed for UDC\n", udc->irq);
+		goto exit_dma;
+	}
+
+	platform_set_drvdata(pdev, udc);
+	udc->chiprev = UDC_BCM_REV;
+
+	if (udc_probe(udc)) {
+		ret = -ENODEV;
+		goto exit_dma;
+	}
+	dev_info(dev, "Synopsys UDC platform driver probe successful\n");
+
+	return 0;
+
+exit_dma:
+	if (use_dma)
+		free_dma_pools(udc);
+exit_extcon:
+	if (udc->edev)
+		extcon_unregister_notifier(udc->edev, EXTCON_USB, &udc->nb);
+exit_phy:
+	if (udc->udc_phy) {
+		phy_power_off(udc->udc_phy);
+		phy_exit(udc->udc_phy);
+	}
+	return ret;
+}
+
+static int udc_plat_remove(struct platform_device *pdev)
+{
+	struct udc *dev;
+
+	dev = platform_get_drvdata(pdev);
+
+	usb_del_gadget_udc(&dev->gadget);
+	/* gadget driver must not be registered */
+	if (WARN_ON(dev->driver))
+		return 0;
+
+	/* dma pool cleanup */
+	free_dma_pools(dev);
+
+	udc_remove(dev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (dev->drd_wq) {
+		flush_workqueue(dev->drd_wq);
+		destroy_workqueue(dev->drd_wq);
+	}
+
+	phy_power_off(dev->udc_phy);
+	phy_exit(dev->udc_phy);
+	extcon_unregister_notifier(dev->edev, EXTCON_USB, &dev->nb);
+
+	dev_info(&pdev->dev, "Synopsys UDC platform driver removed\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int udc_plat_suspend(struct device *dev)
+{
+	struct udc *udc;
+
+	udc = dev_get_drvdata(dev);
+	stop_udc(udc);
+
+	if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) {
+		dev_dbg(udc->dev, "device -> idle\n");
+		stop_udc(udc);
+	}
+	phy_power_off(udc->udc_phy);
+	phy_exit(udc->udc_phy);
+
+	return 0;
+}
+
+static int udc_plat_resume(struct device *dev)
+{
+	struct udc *udc;
+	int ret;
+
+	udc = dev_get_drvdata(dev);
+
+	ret = phy_init(udc->udc_phy);
+	if (ret) {
+		dev_err(udc->dev, "UDC phy init failure");
+		return ret;
+	}
+
+	ret = phy_power_on(udc->udc_phy);
+	if (ret) {
+		dev_err(udc->dev, "UDC phy power on failure");
+		phy_exit(udc->udc_phy);
+		return ret;
+	}
+
+	if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) {
+		dev_dbg(udc->dev, "idle -> device\n");
+		start_udc(udc);
+	}
+
+	return 0;
+}
+static const struct dev_pm_ops udc_plat_pm_ops = {
+	.suspend	= udc_plat_suspend,
+	.resume		= udc_plat_resume,
+};
+#endif
+
+#if defined(CONFIG_OF)
+static const struct of_device_id of_udc_match[] = {
+	{ .compatible = "brcm,ns2-udc", },
+	{ .compatible = "brcm,cygnus-udc", },
+	{ .compatible = "brcm,iproc-udc", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, of_udc_match);
+#endif
+
+static struct platform_driver udc_plat_driver = {
+	.probe		= udc_plat_probe,
+	.remove		= udc_plat_remove,
+	.driver		= {
+		.name	= "snps-udc-plat",
+		.of_match_table = of_match_ptr(of_udc_match),
+#ifdef CONFIG_PM_SLEEP
+		.pm	= &udc_plat_pm_ops,
+#endif
+	},
+};
+module_platform_driver(udc_plat_driver);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
-- 
2.1.0

^ permalink raw reply related

* [RESEND PATCH v3 6/7] DT bindings documentation for Broadcom IPROC USB Device controller.
From: Raviteja Garimella @ 2017-03-31 13:09 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Greg Kroah-Hartman, Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb
In-Reply-To: <1490965753-3511-1-git-send-email-raviteja.garimella@broadcom.com>

The device node is used for UDCs integrated into Broadcom's
iProc family of SoCs'. The UDC is based on Synopsys Designware
Cores AHB Subsystem USB Device Controller IP.

Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
---
 Documentation/devicetree/bindings/usb/iproc-udc.txt | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/iproc-udc.txt

diff --git a/Documentation/devicetree/bindings/usb/iproc-udc.txt b/Documentation/devicetree/bindings/usb/iproc-udc.txt
new file mode 100644
index 0000000..272d7fa
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/iproc-udc.txt
@@ -0,0 +1,21 @@
+Broadcom IPROC USB Device controller.
+
+The device node is used for UDCs integrated into Broadcom's
+iProc family (Northstar2, Cygnus) of SoCs'. The UDC is based
+on Synopsys Designware Cores AHB Subsystem Device Controller
+IP.
+
+Required properties:
+ - compatible: Add the compatibility strings for supported platforms.
+   For Broadcom NS2 platform, add "brcm,ns2-udc","brcm,iproc-udc".
+   For Broadcom Cygnus platform, add "brcm,cygnus-udc", "brcm,iproc-udc".
+ - reg: Offset and length of UDC register set
+ - interrupts: description of interrupt line
+ - phys: phandle to phy node.
+
+Example:
+	udc_dwc: usb@664e0000 {
+		compatible = "brcm,ns2-udc", "brcm,iproc-udc";
+		reg = <0x664e0000 0x2000>;
+		interrupts = <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbdrd_phy>;
-- 
2.1.0

^ permalink raw reply related

* [RESEND PATCH v3 5/7] UDC: Use struct dma_pool instead of pci_pool
From: Raviteja Garimella @ 2017-03-31 13:09 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Greg Kroah-Hartman, Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb
In-Reply-To: <1490965753-3511-1-git-send-email-raviteja.garimella@broadcom.com>

Using dma_pool instead of pci_pool will make snps_udc_core driver
to be compatible with non-pci platforms.

Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
---
 drivers/usb/gadget/udc/snps_udc_core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c
index 5ca8b7b..d592f77 100644
--- a/drivers/usb/gadget/udc/snps_udc_core.c
+++ b/drivers/usb/gadget/udc/snps_udc_core.c
@@ -543,7 +543,7 @@ udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
 
 	if (ep->dma) {
 		/* ep0 in requests are allocated from data pool here */
-		dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+		dma_desc = dma_pool_alloc(ep->dev->data_requests, gfp,
 						&req->td_phys);
 		if (!dma_desc) {
 			kfree(req);
@@ -582,7 +582,7 @@ static void udc_free_dma_chain(struct udc *dev, struct udc_request *req)
 	for (i = 1; i < req->chain_len; i++) {
 		td = phys_to_virt(addr);
 		addr_next = (dma_addr_t)td->next;
-		pci_pool_free(dev->data_requests, td, addr);
+		dma_pool_free(dev->data_requests, td, addr);
 		addr = addr_next;
 	}
 }
@@ -608,7 +608,7 @@ udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
 		if (req->chain_len > 1)
 			udc_free_dma_chain(ep->dev, req);
 
-		pci_pool_free(ep->dev->data_requests, req->td_data,
+		dma_pool_free(ep->dev->data_requests, req->td_data,
 							req->td_phys);
 	}
 	kfree(req);
@@ -803,7 +803,7 @@ static int udc_create_dma_chain(
 	for (i = buf_len; i < bytes; i += buf_len) {
 		/* create or determine next desc. */
 		if (create_new_chain) {
-			td = pci_pool_alloc(ep->dev->data_requests,
+			td = dma_pool_alloc(ep->dev->data_requests,
 					    gfp_flags, &dma_addr);
 			if (!td)
 				return -ENOMEM;
-- 
2.1.0

^ permalink raw reply related

* [RESEND PATCH v3 4/7] UDC: Provide correct arguments for 'dma_pool_create'
From: Raviteja Garimella @ 2017-03-31 13:09 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Greg Kroah-Hartman, Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb
In-Reply-To: <1490965753-3511-1-git-send-email-raviteja.garimella@broadcom.com>

Change the argument from NULL to a struct device for the
dma_pool_create call during dma init.

Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
---
 drivers/usb/gadget/udc/snps_udc_core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c
index a35fef9..5ca8b7b 100644
--- a/drivers/usb/gadget/udc/snps_udc_core.c
+++ b/drivers/usb/gadget/udc/snps_udc_core.c
@@ -3097,7 +3097,7 @@ int init_dma_pools(struct udc *dev)
 	}
 
 	/* DMA setup */
-	dev->data_requests = dma_pool_create("data_requests", NULL,
+	dev->data_requests = dma_pool_create("data_requests", dev->dev,
 		sizeof(struct udc_data_dma), 0, 0);
 	if (!dev->data_requests) {
 		DBG(dev, "can't get request data pool\n");
@@ -3108,7 +3108,7 @@ int init_dma_pools(struct udc *dev)
 	dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
 
 	/* dma desc for setup data */
-	dev->stp_requests = dma_pool_create("setup requests", NULL,
+	dev->stp_requests = dma_pool_create("setup requests", dev->dev,
 		sizeof(struct udc_stp_dma), 0, 0);
 	if (!dev->stp_requests) {
 		DBG(dev, "can't get stp request pool\n");
-- 
2.1.0

^ permalink raw reply related

* [RESEND PATCH v3 3/7] UDC: make debug prints compatible with both pci and platform devices
From: Raviteja Garimella @ 2017-03-31 13:09 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Greg Kroah-Hartman, Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb
In-Reply-To: <1490965753-3511-1-git-send-email-raviteja.garimella@broadcom.com>

This patch adds a struct device member to UDC data structure and
makes changes to the arguments of dev_err and dev_dbg calls so that
the debug prints work for both pci and platform devices.

Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
---
 drivers/usb/gadget/udc/amd5536udc.h     |  4 +++-
 drivers/usb/gadget/udc/amd5536udc_pci.c |  1 +
 drivers/usb/gadget/udc/snps_udc_core.c  | 28 ++++++++++++++--------------
 3 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/gadget/udc/amd5536udc.h b/drivers/usb/gadget/udc/amd5536udc.h
index bd2a18e..c252457 100644
--- a/drivers/usb/gadget/udc/amd5536udc.h
+++ b/drivers/usb/gadget/udc/amd5536udc.h
@@ -563,6 +563,8 @@ struct udc {
 	u16				cur_config;
 	u16				cur_intf;
 	u16				cur_alt;
+
+	struct device			*dev;
 };
 
 #define to_amd5536_udc(g)	(container_of((g), struct udc, gadget))
@@ -639,7 +641,7 @@ MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
 
 /* debug macros ------------------------------------------------------------*/
 
-#define DBG(udc , args...)	dev_dbg(&(udc)->pdev->dev, args)
+#define DBG(udc , args...)	dev_dbg(udc->dev, args)
 
 #ifdef UDC_VERBOSE
 #define VDBG			DBG
diff --git a/drivers/usb/gadget/udc/amd5536udc_pci.c b/drivers/usb/gadget/udc/amd5536udc_pci.c
index 2a2d0a9..57a13f0 100644
--- a/drivers/usb/gadget/udc/amd5536udc_pci.c
+++ b/drivers/usb/gadget/udc/amd5536udc_pci.c
@@ -168,6 +168,7 @@ static int udc_pci_probe(
 	dev->phys_addr = resource;
 	dev->irq = pdev->irq;
 	dev->pdev = pdev;
+	dev->dev = &pdev->dev;
 
 	/* general probing */
 	if (udc_probe(dev)) {
diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c
index 91d0f1a..a35fef9 100644
--- a/drivers/usb/gadget/udc/snps_udc_core.c
+++ b/drivers/usb/gadget/udc/snps_udc_core.c
@@ -209,18 +209,18 @@ static void print_regs(struct udc *dev)
 	if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
 		DBG(dev, "DMA mode       = PPBNDU (packet per buffer "
 			"WITHOUT desc. update)\n");
-		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+		dev_info(dev->dev, "DMA mode (%s)\n", "PPBNDU");
 	} else if (use_dma && use_dma_ppb && use_dma_ppb_du) {
 		DBG(dev, "DMA mode       = PPBDU (packet per buffer "
 			"WITH desc. update)\n");
-		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+		dev_info(dev->dev, "DMA mode (%s)\n", "PPBDU");
 	}
 	if (use_dma && use_dma_bufferfill_mode) {
 		DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
-		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+		dev_info(dev->dev, "DMA mode (%s)\n", "BF");
 	}
 	if (!use_dma)
-		dev_info(&dev->pdev->dev, "FIFO mode\n");
+		dev_info(dev->dev, "FIFO mode\n");
 	DBG(dev, "-------------------------------------------------------\n");
 }
 
@@ -1624,7 +1624,7 @@ static void udc_setup_endpoints(struct udc *dev)
 static void usb_connect(struct udc *dev)
 {
 
-	dev_info(&dev->pdev->dev, "USB Connect\n");
+	dev_info(dev->dev, "USB Connect\n");
 
 	dev->connected = 1;
 
@@ -1642,7 +1642,7 @@ static void usb_connect(struct udc *dev)
 static void usb_disconnect(struct udc *dev)
 {
 
-	dev_info(&dev->pdev->dev, "USB Disconnect\n");
+	dev_info(dev->dev, "USB Disconnect\n");
 
 	dev->connected = 0;
 
@@ -2106,7 +2106,7 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
 	}
 	/* HE event ? */
 	if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
-		dev_err(&dev->pdev->dev, "HE ep%dout occurred\n", ep->num);
+		dev_err(dev->dev, "HE ep%dout occurred\n", ep->num);
 
 		/* clear HE */
 		writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
@@ -2305,7 +2305,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
 	if (use_dma) {
 		/* BNA ? */
 		if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
-			dev_err(&dev->pdev->dev,
+			dev_err(dev->dev,
 				"BNA ep%din occurred - DESPTR = %08lx\n",
 				ep->num,
 				(unsigned long) readl(&ep->regs->desptr));
@@ -2318,7 +2318,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
 	}
 	/* HE event ? */
 	if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
-		dev_err(&dev->pdev->dev,
+		dev_err(dev->dev,
 			"HE ep%dn occurred - DESPTR = %08lx\n",
 			ep->num, (unsigned long) readl(&ep->regs->desptr));
 
@@ -2956,7 +2956,7 @@ __acquires(dev->lock)
 
 		/* link up all endpoints */
 		udc_setup_endpoints(dev);
-		dev_info(&dev->pdev->dev, "Connect: %s\n",
+		dev_info(dev->dev, "Connect: %s\n",
 			 usb_speed_string(dev->gadget.speed));
 
 		/* init ep 0 */
@@ -3168,20 +3168,20 @@ int udc_probe(struct udc *dev)
 	/* init registers, interrupts, ... */
 	startup_registers(dev);
 
-	dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+	dev_info(dev->dev, "%s\n", mod_desc);
 
 	snprintf(tmp, sizeof(tmp), "%d", dev->irq);
-	dev_info(&dev->pdev->dev,
+	dev_info(dev->dev,
 		 "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
 		 tmp, dev->phys_addr, dev->chiprev,
 		 (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
 	strcpy(tmp, UDC_DRIVER_VERSION_STRING);
 	if (dev->chiprev == UDC_HSA0_REV) {
-		dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+		dev_err(dev->dev, "chip revision is A0; too old\n");
 		retval = -ENODEV;
 		goto finished;
 	}
-	dev_info(&dev->pdev->dev,
+	dev_info(dev->dev,
 		 "driver version: %s(for Geode5536 B1)\n", tmp);
 	udc = dev;
 
-- 
2.1.0

^ permalink raw reply related

* [RESEND PATCH v3 2/7] UDC: Rename amd5536udc driver file based on IP
From: Raviteja Garimella @ 2017-03-31 13:09 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Greg Kroah-Hartman, Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb
In-Reply-To: <1490965753-3511-1-git-send-email-raviteja.garimella@broadcom.com>

This patch renames the amd5536udc.c that has the core driver
functionality of Synopsys UDC to snps_udc_core.c

The symbols exported here can be used by any UDC driver that uses
the same Synopsys IP.

Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
---
 drivers/usb/gadget/udc/Makefile        |    2 +-
 drivers/usb/gadget/udc/amd5536udc.c    | 3219 --------------------------------
 drivers/usb/gadget/udc/snps_udc_core.c | 3219 ++++++++++++++++++++++++++++++++
 3 files changed, 3220 insertions(+), 3220 deletions(-)
 delete mode 100644 drivers/usb/gadget/udc/amd5536udc.c
 create mode 100644 drivers/usb/gadget/udc/snps_udc_core.c

diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index 626e1f1..4f4fd62 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_USB_GADGET)	+= udc-core.o
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_NET2272)	+= net2272.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
-obj-$(CONFIG_USB_SNP_CORE)	+= amd5536udc.o
+obj-$(CONFIG_USB_SNP_CORE)	+= snps_udc_core.o
 obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc_pci.o
 obj-$(CONFIG_USB_PXA25X)	+= pxa25x_udc.o
 obj-$(CONFIG_USB_PXA27X)	+= pxa27x_udc.o
diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c
deleted file mode 100644
index 91d0f1a..0000000
--- a/drivers/usb/gadget/udc/amd5536udc.c
+++ /dev/null
@@ -1,3219 +0,0 @@
-/*
- * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
- *
- * Copyright (C) 2005-2007 AMD (http://www.amd.com)
- * Author: Thomas Dahlmann
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/*
- * This file does the core driver implementation for the UDC that is based
- * on Synopsys device controller IP (different than HS OTG IP) that is either
- * connected through PCI bus or integrated to SoC platforms.
- */
-
-/* Driver strings */
-#define UDC_MOD_DESCRIPTION		"Synopsys USB Device Controller"
-#define UDC_DRIVER_VERSION_STRING	"01.00.0206"
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/ioctl.h>
-#include <linux/fs.h>
-#include <linux/dmapool.h>
-#include <linux/prefetch.h>
-#include <linux/moduleparam.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-#include "amd5536udc.h"
-
-static void udc_tasklet_disconnect(unsigned long);
-static void empty_req_queue(struct udc_ep *);
-static void udc_setup_endpoints(struct udc *dev);
-static void udc_soft_reset(struct udc *dev);
-static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
-static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
-
-/* description */
-static const char mod_desc[] = UDC_MOD_DESCRIPTION;
-static const char name[] = "udc";
-
-/* structure to hold endpoint function pointers */
-static const struct usb_ep_ops udc_ep_ops;
-
-/* received setup data */
-static union udc_setup_data setup_data;
-
-/* pointer to device object */
-static struct udc *udc;
-
-/* irq spin lock for soft reset */
-static DEFINE_SPINLOCK(udc_irq_spinlock);
-/* stall spin lock */
-static DEFINE_SPINLOCK(udc_stall_spinlock);
-
-/*
-* slave mode: pending bytes in rx fifo after nyet,
-* used if EPIN irq came but no req was available
-*/
-static unsigned int udc_rxfifo_pending;
-
-/* count soft resets after suspend to avoid loop */
-static int soft_reset_occured;
-static int soft_reset_after_usbreset_occured;
-
-/* timer */
-static struct timer_list udc_timer;
-static int stop_timer;
-
-/* set_rde -- Is used to control enabling of RX DMA. Problem is
- * that UDC has only one bit (RDE) to enable/disable RX DMA for
- * all OUT endpoints. So we have to handle race conditions like
- * when OUT data reaches the fifo but no request was queued yet.
- * This cannot be solved by letting the RX DMA disabled until a
- * request gets queued because there may be other OUT packets
- * in the FIFO (important for not blocking control traffic).
- * The value of set_rde controls the correspondig timer.
- *
- * set_rde -1 == not used, means it is alloed to be set to 0 or 1
- * set_rde  0 == do not touch RDE, do no start the RDE timer
- * set_rde  1 == timer function will look whether FIFO has data
- * set_rde  2 == set by timer function to enable RX DMA on next call
- */
-static int set_rde = -1;
-
-static DECLARE_COMPLETION(on_exit);
-static struct timer_list udc_pollstall_timer;
-static int stop_pollstall_timer;
-static DECLARE_COMPLETION(on_pollstall_exit);
-
-/* tasklet for usb disconnect */
-static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
-		(unsigned long) &udc);
-
-
-/* endpoint names used for print */
-static const char ep0_string[] = "ep0in";
-static const struct {
-	const char *name;
-	const struct usb_ep_caps caps;
-} ep_info[] = {
-#define EP_INFO(_name, _caps) \
-	{ \
-		.name = _name, \
-		.caps = _caps, \
-	}
-
-	EP_INFO(ep0_string,
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep1in-int",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep2in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep3in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep4in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep5in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep6in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep7in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep8in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep9in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep10in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep11in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep12in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep13in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep14in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep15in-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
-	EP_INFO("ep0out",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep1out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep2out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep3out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep4out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep5out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep6out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep7out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep8out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep9out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep10out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep11out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep12out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep13out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep14out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-	EP_INFO("ep15out-bulk",
-		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
-
-#undef EP_INFO
-};
-
-/* buffer fill mode */
-static int use_dma_bufferfill_mode;
-/* tx buffer size for high speed */
-static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
-
-/*---------------------------------------------------------------------------*/
-/* Prints UDC device registers and endpoint irq registers */
-static void print_regs(struct udc *dev)
-{
-	DBG(dev, "------- Device registers -------\n");
-	DBG(dev, "dev config     = %08x\n", readl(&dev->regs->cfg));
-	DBG(dev, "dev control    = %08x\n", readl(&dev->regs->ctl));
-	DBG(dev, "dev status     = %08x\n", readl(&dev->regs->sts));
-	DBG(dev, "\n");
-	DBG(dev, "dev int's      = %08x\n", readl(&dev->regs->irqsts));
-	DBG(dev, "dev intmask    = %08x\n", readl(&dev->regs->irqmsk));
-	DBG(dev, "\n");
-	DBG(dev, "dev ep int's   = %08x\n", readl(&dev->regs->ep_irqsts));
-	DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
-	DBG(dev, "\n");
-	DBG(dev, "USE DMA        = %d\n", use_dma);
-	if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
-		DBG(dev, "DMA mode       = PPBNDU (packet per buffer "
-			"WITHOUT desc. update)\n");
-		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
-	} else if (use_dma && use_dma_ppb && use_dma_ppb_du) {
-		DBG(dev, "DMA mode       = PPBDU (packet per buffer "
-			"WITH desc. update)\n");
-		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
-	}
-	if (use_dma && use_dma_bufferfill_mode) {
-		DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
-		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
-	}
-	if (!use_dma)
-		dev_info(&dev->pdev->dev, "FIFO mode\n");
-	DBG(dev, "-------------------------------------------------------\n");
-}
-
-/* Masks unused interrupts */
-int udc_mask_unused_interrupts(struct udc *dev)
-{
-	u32 tmp;
-
-	/* mask all dev interrupts */
-	tmp =	AMD_BIT(UDC_DEVINT_SVC) |
-		AMD_BIT(UDC_DEVINT_ENUM) |
-		AMD_BIT(UDC_DEVINT_US) |
-		AMD_BIT(UDC_DEVINT_UR) |
-		AMD_BIT(UDC_DEVINT_ES) |
-		AMD_BIT(UDC_DEVINT_SI) |
-		AMD_BIT(UDC_DEVINT_SOF)|
-		AMD_BIT(UDC_DEVINT_SC);
-	writel(tmp, &dev->regs->irqmsk);
-
-	/* mask all ep interrupts */
-	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(udc_mask_unused_interrupts);
-
-/* Enables endpoint 0 interrupts */
-static int udc_enable_ep0_interrupts(struct udc *dev)
-{
-	u32 tmp;
-
-	DBG(dev, "udc_enable_ep0_interrupts()\n");
-
-	/* read irq mask */
-	tmp = readl(&dev->regs->ep_irqmsk);
-	/* enable ep0 irq's */
-	tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
-		& AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
-	writel(tmp, &dev->regs->ep_irqmsk);
-
-	return 0;
-}
-
-/* Enables device interrupts for SET_INTF and SET_CONFIG */
-int udc_enable_dev_setup_interrupts(struct udc *dev)
-{
-	u32 tmp;
-
-	DBG(dev, "enable device interrupts for setup data\n");
-
-	/* read irq mask */
-	tmp = readl(&dev->regs->irqmsk);
-
-	/* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
-	tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
-		& AMD_UNMASK_BIT(UDC_DEVINT_SC)
-		& AMD_UNMASK_BIT(UDC_DEVINT_UR)
-		& AMD_UNMASK_BIT(UDC_DEVINT_SVC)
-		& AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
-	writel(tmp, &dev->regs->irqmsk);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(udc_enable_dev_setup_interrupts);
-
-/* Calculates fifo start of endpoint based on preceding endpoints */
-static int udc_set_txfifo_addr(struct udc_ep *ep)
-{
-	struct udc	*dev;
-	u32 tmp;
-	int i;
-
-	if (!ep || !(ep->in))
-		return -EINVAL;
-
-	dev = ep->dev;
-	ep->txfifo = dev->txfifo;
-
-	/* traverse ep's */
-	for (i = 0; i < ep->num; i++) {
-		if (dev->ep[i].regs) {
-			/* read fifo size */
-			tmp = readl(&dev->ep[i].regs->bufin_framenum);
-			tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
-			ep->txfifo += tmp;
-		}
-	}
-	return 0;
-}
-
-/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
-static u32 cnak_pending;
-
-static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
-{
-	if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
-		DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
-		cnak_pending |= 1 << (num);
-		ep->naking = 1;
-	} else
-		cnak_pending = cnak_pending & (~(1 << (num)));
-}
-
-
-/* Enables endpoint, is called by gadget driver */
-static int
-udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
-{
-	struct udc_ep		*ep;
-	struct udc		*dev;
-	u32			tmp;
-	unsigned long		iflags;
-	u8 udc_csr_epix;
-	unsigned		maxpacket;
-
-	if (!usbep
-			|| usbep->name == ep0_string
-			|| !desc
-			|| desc->bDescriptorType != USB_DT_ENDPOINT)
-		return -EINVAL;
-
-	ep = container_of(usbep, struct udc_ep, ep);
-	dev = ep->dev;
-
-	DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
-
-	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
-		return -ESHUTDOWN;
-
-	spin_lock_irqsave(&dev->lock, iflags);
-	ep->ep.desc = desc;
-
-	ep->halted = 0;
-
-	/* set traffic type */
-	tmp = readl(&dev->ep[ep->num].regs->ctl);
-	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
-	writel(tmp, &dev->ep[ep->num].regs->ctl);
-
-	/* set max packet size */
-	maxpacket = usb_endpoint_maxp(desc);
-	tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
-	tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
-	ep->ep.maxpacket = maxpacket;
-	writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
-
-	/* IN ep */
-	if (ep->in) {
-
-		/* ep ix in UDC CSR register space */
-		udc_csr_epix = ep->num;
-
-		/* set buffer size (tx fifo entries) */
-		tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
-		/* double buffering: fifo size = 2 x max packet size */
-		tmp = AMD_ADDBITS(
-				tmp,
-				maxpacket * UDC_EPIN_BUFF_SIZE_MULT
-					  / UDC_DWORD_BYTES,
-				UDC_EPIN_BUFF_SIZE);
-		writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
-
-		/* calc. tx fifo base addr */
-		udc_set_txfifo_addr(ep);
-
-		/* flush fifo */
-		tmp = readl(&ep->regs->ctl);
-		tmp |= AMD_BIT(UDC_EPCTL_F);
-		writel(tmp, &ep->regs->ctl);
-
-	/* OUT ep */
-	} else {
-		/* ep ix in UDC CSR register space */
-		udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
-
-		/* set max packet size UDC CSR	*/
-		tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
-		tmp = AMD_ADDBITS(tmp, maxpacket,
-					UDC_CSR_NE_MAX_PKT);
-		writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
-
-		if (use_dma && !ep->in) {
-			/* alloc and init BNA dummy request */
-			ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
-			ep->bna_occurred = 0;
-		}
-
-		if (ep->num != UDC_EP0OUT_IX)
-			dev->data_ep_enabled = 1;
-	}
-
-	/* set ep values */
-	tmp = readl(&dev->csr->ne[udc_csr_epix]);
-	/* max packet */
-	tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT);
-	/* ep number */
-	tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
-	/* ep direction */
-	tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
-	/* ep type */
-	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
-	/* ep config */
-	tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
-	/* ep interface */
-	tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
-	/* ep alt */
-	tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
-	/* write reg */
-	writel(tmp, &dev->csr->ne[udc_csr_epix]);
-
-	/* enable ep irq */
-	tmp = readl(&dev->regs->ep_irqmsk);
-	tmp &= AMD_UNMASK_BIT(ep->num);
-	writel(tmp, &dev->regs->ep_irqmsk);
-
-	/*
-	 * clear NAK by writing CNAK
-	 * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
-	 */
-	if (!use_dma || ep->in) {
-		tmp = readl(&ep->regs->ctl);
-		tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-		writel(tmp, &ep->regs->ctl);
-		ep->naking = 0;
-		UDC_QUEUE_CNAK(ep, ep->num);
-	}
-	tmp = desc->bEndpointAddress;
-	DBG(dev, "%s enabled\n", usbep->name);
-
-	spin_unlock_irqrestore(&dev->lock, iflags);
-	return 0;
-}
-
-/* Resets endpoint */
-static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
-{
-	u32		tmp;
-
-	VDBG(ep->dev, "ep-%d reset\n", ep->num);
-	ep->ep.desc = NULL;
-	ep->ep.ops = &udc_ep_ops;
-	INIT_LIST_HEAD(&ep->queue);
-
-	usb_ep_set_maxpacket_limit(&ep->ep,(u16) ~0);
-	/* set NAK */
-	tmp = readl(&ep->regs->ctl);
-	tmp |= AMD_BIT(UDC_EPCTL_SNAK);
-	writel(tmp, &ep->regs->ctl);
-	ep->naking = 1;
-
-	/* disable interrupt */
-	tmp = readl(&regs->ep_irqmsk);
-	tmp |= AMD_BIT(ep->num);
-	writel(tmp, &regs->ep_irqmsk);
-
-	if (ep->in) {
-		/* unset P and IN bit of potential former DMA */
-		tmp = readl(&ep->regs->ctl);
-		tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
-		writel(tmp, &ep->regs->ctl);
-
-		tmp = readl(&ep->regs->sts);
-		tmp |= AMD_BIT(UDC_EPSTS_IN);
-		writel(tmp, &ep->regs->sts);
-
-		/* flush the fifo */
-		tmp = readl(&ep->regs->ctl);
-		tmp |= AMD_BIT(UDC_EPCTL_F);
-		writel(tmp, &ep->regs->ctl);
-
-	}
-	/* reset desc pointer */
-	writel(0, &ep->regs->desptr);
-}
-
-/* Disables endpoint, is called by gadget driver */
-static int udc_ep_disable(struct usb_ep *usbep)
-{
-	struct udc_ep	*ep = NULL;
-	unsigned long	iflags;
-
-	if (!usbep)
-		return -EINVAL;
-
-	ep = container_of(usbep, struct udc_ep, ep);
-	if (usbep->name == ep0_string || !ep->ep.desc)
-		return -EINVAL;
-
-	DBG(ep->dev, "Disable ep-%d\n", ep->num);
-
-	spin_lock_irqsave(&ep->dev->lock, iflags);
-	udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
-	empty_req_queue(ep);
-	ep_init(ep->dev->regs, ep);
-	spin_unlock_irqrestore(&ep->dev->lock, iflags);
-
-	return 0;
-}
-
-/* Allocates request packet, called by gadget driver */
-static struct usb_request *
-udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
-{
-	struct udc_request	*req;
-	struct udc_data_dma	*dma_desc;
-	struct udc_ep	*ep;
-
-	if (!usbep)
-		return NULL;
-
-	ep = container_of(usbep, struct udc_ep, ep);
-
-	VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
-	req = kzalloc(sizeof(struct udc_request), gfp);
-	if (!req)
-		return NULL;
-
-	req->req.dma = DMA_DONT_USE;
-	INIT_LIST_HEAD(&req->queue);
-
-	if (ep->dma) {
-		/* ep0 in requests are allocated from data pool here */
-		dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
-						&req->td_phys);
-		if (!dma_desc) {
-			kfree(req);
-			return NULL;
-		}
-
-		VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
-				"td_phys = %lx\n",
-				req, dma_desc,
-				(unsigned long)req->td_phys);
-		/* prevent from using desc. - set HOST BUSY */
-		dma_desc->status = AMD_ADDBITS(dma_desc->status,
-						UDC_DMA_STP_STS_BS_HOST_BUSY,
-						UDC_DMA_STP_STS_BS);
-		dma_desc->bufptr = cpu_to_le32(DMA_DONT_USE);
-		req->td_data = dma_desc;
-		req->td_data_last = NULL;
-		req->chain_len = 1;
-	}
-
-	return &req->req;
-}
-
-/* frees pci pool descriptors of a DMA chain */
-static void udc_free_dma_chain(struct udc *dev, struct udc_request *req)
-{
-	struct udc_data_dma *td = req->td_data;
-	unsigned int i;
-
-	dma_addr_t addr_next = 0x00;
-	dma_addr_t addr = (dma_addr_t)td->next;
-
-	DBG(dev, "free chain req = %p\n", req);
-
-	/* do not free first desc., will be done by free for request */
-	for (i = 1; i < req->chain_len; i++) {
-		td = phys_to_virt(addr);
-		addr_next = (dma_addr_t)td->next;
-		pci_pool_free(dev->data_requests, td, addr);
-		addr = addr_next;
-	}
-}
-
-/* Frees request packet, called by gadget driver */
-static void
-udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
-{
-	struct udc_ep	*ep;
-	struct udc_request	*req;
-
-	if (!usbep || !usbreq)
-		return;
-
-	ep = container_of(usbep, struct udc_ep, ep);
-	req = container_of(usbreq, struct udc_request, req);
-	VDBG(ep->dev, "free_req req=%p\n", req);
-	BUG_ON(!list_empty(&req->queue));
-	if (req->td_data) {
-		VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
-
-		/* free dma chain if created */
-		if (req->chain_len > 1)
-			udc_free_dma_chain(ep->dev, req);
-
-		pci_pool_free(ep->dev->data_requests, req->td_data,
-							req->td_phys);
-	}
-	kfree(req);
-}
-
-/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
-static void udc_init_bna_dummy(struct udc_request *req)
-{
-	if (req) {
-		/* set last bit */
-		req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
-		/* set next pointer to itself */
-		req->td_data->next = req->td_phys;
-		/* set HOST BUSY */
-		req->td_data->status
-			= AMD_ADDBITS(req->td_data->status,
-					UDC_DMA_STP_STS_BS_DMA_DONE,
-					UDC_DMA_STP_STS_BS);
-#ifdef UDC_VERBOSE
-		pr_debug("bna desc = %p, sts = %08x\n",
-			req->td_data, req->td_data->status);
-#endif
-	}
-}
-
-/* Allocate BNA dummy descriptor */
-static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
-{
-	struct udc_request *req = NULL;
-	struct usb_request *_req = NULL;
-
-	/* alloc the dummy request */
-	_req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
-	if (_req) {
-		req = container_of(_req, struct udc_request, req);
-		ep->bna_dummy_req = req;
-		udc_init_bna_dummy(req);
-	}
-	return req;
-}
-
-/* Write data to TX fifo for IN packets */
-static void
-udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
-{
-	u8			*req_buf;
-	u32			*buf;
-	int			i, j;
-	unsigned		bytes = 0;
-	unsigned		remaining = 0;
-
-	if (!req || !ep)
-		return;
-
-	req_buf = req->buf + req->actual;
-	prefetch(req_buf);
-	remaining = req->length - req->actual;
-
-	buf = (u32 *) req_buf;
-
-	bytes = ep->ep.maxpacket;
-	if (bytes > remaining)
-		bytes = remaining;
-
-	/* dwords first */
-	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
-		writel(*(buf + i), ep->txfifo);
-
-	/* remaining bytes must be written by byte access */
-	for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
-		writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
-							ep->txfifo);
-	}
-
-	/* dummy write confirm */
-	writel(0, &ep->regs->confirm);
-}
-
-/* Read dwords from RX fifo for OUT transfers */
-static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
-{
-	int i;
-
-	VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
-
-	for (i = 0; i < dwords; i++)
-		*(buf + i) = readl(dev->rxfifo);
-	return 0;
-}
-
-/* Read bytes from RX fifo for OUT transfers */
-static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
-{
-	int i, j;
-	u32 tmp;
-
-	VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
-
-	/* dwords first */
-	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
-		*((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
-
-	/* remaining bytes must be read by byte access */
-	if (bytes % UDC_DWORD_BYTES) {
-		tmp = readl(dev->rxfifo);
-		for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
-			*(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
-			tmp = tmp >> UDC_BITS_PER_BYTE;
-		}
-	}
-
-	return 0;
-}
-
-/* Read data from RX fifo for OUT transfers */
-static int
-udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
-{
-	u8 *buf;
-	unsigned buf_space;
-	unsigned bytes = 0;
-	unsigned finished = 0;
-
-	/* received number bytes */
-	bytes = readl(&ep->regs->sts);
-	bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
-
-	buf_space = req->req.length - req->req.actual;
-	buf = req->req.buf + req->req.actual;
-	if (bytes > buf_space) {
-		if ((buf_space % ep->ep.maxpacket) != 0) {
-			DBG(ep->dev,
-				"%s: rx %d bytes, rx-buf space = %d bytesn\n",
-				ep->ep.name, bytes, buf_space);
-			req->req.status = -EOVERFLOW;
-		}
-		bytes = buf_space;
-	}
-	req->req.actual += bytes;
-
-	/* last packet ? */
-	if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
-		|| ((req->req.actual == req->req.length) && !req->req.zero))
-		finished = 1;
-
-	/* read rx fifo bytes */
-	VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
-	udc_rxfifo_read_bytes(ep->dev, buf, bytes);
-
-	return finished;
-}
-
-/* Creates or re-inits a DMA chain */
-static int udc_create_dma_chain(
-	struct udc_ep *ep,
-	struct udc_request *req,
-	unsigned long buf_len, gfp_t gfp_flags
-)
-{
-	unsigned long bytes = req->req.length;
-	unsigned int i;
-	dma_addr_t dma_addr;
-	struct udc_data_dma	*td = NULL;
-	struct udc_data_dma	*last = NULL;
-	unsigned long txbytes;
-	unsigned create_new_chain = 0;
-	unsigned len;
-
-	VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
-	     bytes, buf_len);
-	dma_addr = DMA_DONT_USE;
-
-	/* unset L bit in first desc for OUT */
-	if (!ep->in)
-		req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
-
-	/* alloc only new desc's if not already available */
-	len = req->req.length / ep->ep.maxpacket;
-	if (req->req.length % ep->ep.maxpacket)
-		len++;
-
-	if (len > req->chain_len) {
-		/* shorter chain already allocated before */
-		if (req->chain_len > 1)
-			udc_free_dma_chain(ep->dev, req);
-		req->chain_len = len;
-		create_new_chain = 1;
-	}
-
-	td = req->td_data;
-	/* gen. required number of descriptors and buffers */
-	for (i = buf_len; i < bytes; i += buf_len) {
-		/* create or determine next desc. */
-		if (create_new_chain) {
-			td = pci_pool_alloc(ep->dev->data_requests,
-					    gfp_flags, &dma_addr);
-			if (!td)
-				return -ENOMEM;
-
-			td->status = 0;
-		} else if (i == buf_len) {
-			/* first td */
-			td = (struct udc_data_dma *)phys_to_virt(
-						req->td_data->next);
-			td->status = 0;
-		} else {
-			td = (struct udc_data_dma *)phys_to_virt(last->next);
-			td->status = 0;
-		}
-
-		if (td)
-			td->bufptr = req->req.dma + i; /* assign buffer */
-		else
-			break;
-
-		/* short packet ? */
-		if ((bytes - i) >= buf_len) {
-			txbytes = buf_len;
-		} else {
-			/* short packet */
-			txbytes = bytes - i;
-		}
-
-		/* link td and assign tx bytes */
-		if (i == buf_len) {
-			if (create_new_chain)
-				req->td_data->next = dma_addr;
-			/*
-			 * else
-			 *	req->td_data->next = virt_to_phys(td);
-			 */
-			/* write tx bytes */
-			if (ep->in) {
-				/* first desc */
-				req->td_data->status =
-					AMD_ADDBITS(req->td_data->status,
-						    ep->ep.maxpacket,
-						    UDC_DMA_IN_STS_TXBYTES);
-				/* second desc */
-				td->status = AMD_ADDBITS(td->status,
-							txbytes,
-							UDC_DMA_IN_STS_TXBYTES);
-			}
-		} else {
-			if (create_new_chain)
-				last->next = dma_addr;
-			/*
-			 * else
-			 *	last->next = virt_to_phys(td);
-			 */
-			if (ep->in) {
-				/* write tx bytes */
-				td->status = AMD_ADDBITS(td->status,
-							txbytes,
-							UDC_DMA_IN_STS_TXBYTES);
-			}
-		}
-		last = td;
-	}
-	/* set last bit */
-	if (td) {
-		td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
-		/* last desc. points to itself */
-		req->td_data_last = td;
-	}
-
-	return 0;
-}
-
-/* create/re-init a DMA descriptor or a DMA descriptor chain */
-static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
-{
-	int	retval = 0;
-	u32	tmp;
-
-	VDBG(ep->dev, "prep_dma\n");
-	VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
-			ep->num, req->td_data);
-
-	/* set buffer pointer */
-	req->td_data->bufptr = req->req.dma;
-
-	/* set last bit */
-	req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
-
-	/* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
-	if (use_dma_ppb) {
-
-		retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
-		if (retval != 0) {
-			if (retval == -ENOMEM)
-				DBG(ep->dev, "Out of DMA memory\n");
-			return retval;
-		}
-		if (ep->in) {
-			if (req->req.length == ep->ep.maxpacket) {
-				/* write tx bytes */
-				req->td_data->status =
-					AMD_ADDBITS(req->td_data->status,
-						ep->ep.maxpacket,
-						UDC_DMA_IN_STS_TXBYTES);
-
-			}
-		}
-
-	}
-
-	if (ep->in) {
-		VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
-				"maxpacket=%d ep%d\n",
-				use_dma_ppb, req->req.length,
-				ep->ep.maxpacket, ep->num);
-		/*
-		 * if bytes < max packet then tx bytes must
-		 * be written in packet per buffer mode
-		 */
-		if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
-				|| ep->num == UDC_EP0OUT_IX
-				|| ep->num == UDC_EP0IN_IX) {
-			/* write tx bytes */
-			req->td_data->status =
-				AMD_ADDBITS(req->td_data->status,
-						req->req.length,
-						UDC_DMA_IN_STS_TXBYTES);
-			/* reset frame num */
-			req->td_data->status =
-				AMD_ADDBITS(req->td_data->status,
-						0,
-						UDC_DMA_IN_STS_FRAMENUM);
-		}
-		/* set HOST BUSY */
-		req->td_data->status =
-			AMD_ADDBITS(req->td_data->status,
-				UDC_DMA_STP_STS_BS_HOST_BUSY,
-				UDC_DMA_STP_STS_BS);
-	} else {
-		VDBG(ep->dev, "OUT set host ready\n");
-		/* set HOST READY */
-		req->td_data->status =
-			AMD_ADDBITS(req->td_data->status,
-				UDC_DMA_STP_STS_BS_HOST_READY,
-				UDC_DMA_STP_STS_BS);
-
-
-			/* clear NAK by writing CNAK */
-			if (ep->naking) {
-				tmp = readl(&ep->regs->ctl);
-				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-				writel(tmp, &ep->regs->ctl);
-				ep->naking = 0;
-				UDC_QUEUE_CNAK(ep, ep->num);
-			}
-
-	}
-
-	return retval;
-}
-
-/* Completes request packet ... caller MUST hold lock */
-static void
-complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
-__releases(ep->dev->lock)
-__acquires(ep->dev->lock)
-{
-	struct udc		*dev;
-	unsigned		halted;
-
-	VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
-
-	dev = ep->dev;
-	/* unmap DMA */
-	if (ep->dma)
-		usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in);
-
-	halted = ep->halted;
-	ep->halted = 1;
-
-	/* set new status if pending */
-	if (req->req.status == -EINPROGRESS)
-		req->req.status = sts;
-
-	/* remove from ep queue */
-	list_del_init(&req->queue);
-
-	VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
-		&req->req, req->req.length, ep->ep.name, sts);
-
-	spin_unlock(&dev->lock);
-	usb_gadget_giveback_request(&ep->ep, &req->req);
-	spin_lock(&dev->lock);
-	ep->halted = halted;
-}
-
-/* Iterates to the end of a DMA chain and returns last descriptor */
-static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
-{
-	struct udc_data_dma	*td;
-
-	td = req->td_data;
-	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L)))
-		td = phys_to_virt(td->next);
-
-	return td;
-
-}
-
-/* Iterates to the end of a DMA chain and counts bytes received */
-static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
-{
-	struct udc_data_dma	*td;
-	u32 count;
-
-	td = req->td_data;
-	/* received number bytes */
-	count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
-
-	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
-		td = phys_to_virt(td->next);
-		/* received number bytes */
-		if (td) {
-			count += AMD_GETBITS(td->status,
-				UDC_DMA_OUT_STS_RXBYTES);
-		}
-	}
-
-	return count;
-
-}
-
-/* Enabling RX DMA */
-static void udc_set_rde(struct udc *dev)
-{
-	u32 tmp;
-
-	VDBG(dev, "udc_set_rde()\n");
-	/* stop RDE timer */
-	if (timer_pending(&udc_timer)) {
-		set_rde = 0;
-		mod_timer(&udc_timer, jiffies - 1);
-	}
-	/* set RDE */
-	tmp = readl(&dev->regs->ctl);
-	tmp |= AMD_BIT(UDC_DEVCTL_RDE);
-	writel(tmp, &dev->regs->ctl);
-}
-
-/* Queues a request packet, called by gadget driver */
-static int
-udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
-{
-	int			retval = 0;
-	u8			open_rxfifo = 0;
-	unsigned long		iflags;
-	struct udc_ep		*ep;
-	struct udc_request	*req;
-	struct udc		*dev;
-	u32			tmp;
-
-	/* check the inputs */
-	req = container_of(usbreq, struct udc_request, req);
-
-	if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
-			|| !list_empty(&req->queue))
-		return -EINVAL;
-
-	ep = container_of(usbep, struct udc_ep, ep);
-	if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
-		return -EINVAL;
-
-	VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
-	dev = ep->dev;
-
-	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
-		return -ESHUTDOWN;
-
-	/* map dma (usually done before) */
-	if (ep->dma) {
-		VDBG(dev, "DMA map req %p\n", req);
-		retval = usb_gadget_map_request(&udc->gadget, usbreq, ep->in);
-		if (retval)
-			return retval;
-	}
-
-	VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
-			usbep->name, usbreq, usbreq->length,
-			req->td_data, usbreq->buf);
-
-	spin_lock_irqsave(&dev->lock, iflags);
-	usbreq->actual = 0;
-	usbreq->status = -EINPROGRESS;
-	req->dma_done = 0;
-
-	/* on empty queue just do first transfer */
-	if (list_empty(&ep->queue)) {
-		/* zlp */
-		if (usbreq->length == 0) {
-			/* IN zlp's are handled by hardware */
-			complete_req(ep, req, 0);
-			VDBG(dev, "%s: zlp\n", ep->ep.name);
-			/*
-			 * if set_config or set_intf is waiting for ack by zlp
-			 * then set CSR_DONE
-			 */
-			if (dev->set_cfg_not_acked) {
-				tmp = readl(&dev->regs->ctl);
-				tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
-				writel(tmp, &dev->regs->ctl);
-				dev->set_cfg_not_acked = 0;
-			}
-			/* setup command is ACK'ed now by zlp */
-			if (dev->waiting_zlp_ack_ep0in) {
-				/* clear NAK by writing CNAK in EP0_IN */
-				tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
-				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-				writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
-				dev->ep[UDC_EP0IN_IX].naking = 0;
-				UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
-							UDC_EP0IN_IX);
-				dev->waiting_zlp_ack_ep0in = 0;
-			}
-			goto finished;
-		}
-		if (ep->dma) {
-			retval = prep_dma(ep, req, GFP_ATOMIC);
-			if (retval != 0)
-				goto finished;
-			/* write desc pointer to enable DMA */
-			if (ep->in) {
-				/* set HOST READY */
-				req->td_data->status =
-					AMD_ADDBITS(req->td_data->status,
-						UDC_DMA_IN_STS_BS_HOST_READY,
-						UDC_DMA_IN_STS_BS);
-			}
-
-			/* disabled rx dma while descriptor update */
-			if (!ep->in) {
-				/* stop RDE timer */
-				if (timer_pending(&udc_timer)) {
-					set_rde = 0;
-					mod_timer(&udc_timer, jiffies - 1);
-				}
-				/* clear RDE */
-				tmp = readl(&dev->regs->ctl);
-				tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
-				writel(tmp, &dev->regs->ctl);
-				open_rxfifo = 1;
-
-				/*
-				 * if BNA occurred then let BNA dummy desc.
-				 * point to current desc.
-				 */
-				if (ep->bna_occurred) {
-					VDBG(dev, "copy to BNA dummy desc.\n");
-					memcpy(ep->bna_dummy_req->td_data,
-						req->td_data,
-						sizeof(struct udc_data_dma));
-				}
-			}
-			/* write desc pointer */
-			writel(req->td_phys, &ep->regs->desptr);
-
-			/* clear NAK by writing CNAK */
-			if (ep->naking) {
-				tmp = readl(&ep->regs->ctl);
-				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-				writel(tmp, &ep->regs->ctl);
-				ep->naking = 0;
-				UDC_QUEUE_CNAK(ep, ep->num);
-			}
-
-			if (ep->in) {
-				/* enable ep irq */
-				tmp = readl(&dev->regs->ep_irqmsk);
-				tmp &= AMD_UNMASK_BIT(ep->num);
-				writel(tmp, &dev->regs->ep_irqmsk);
-			}
-		} else if (ep->in) {
-				/* enable ep irq */
-				tmp = readl(&dev->regs->ep_irqmsk);
-				tmp &= AMD_UNMASK_BIT(ep->num);
-				writel(tmp, &dev->regs->ep_irqmsk);
-			}
-
-	} else if (ep->dma) {
-
-		/*
-		 * prep_dma not used for OUT ep's, this is not possible
-		 * for PPB modes, because of chain creation reasons
-		 */
-		if (ep->in) {
-			retval = prep_dma(ep, req, GFP_ATOMIC);
-			if (retval != 0)
-				goto finished;
-		}
-	}
-	VDBG(dev, "list_add\n");
-	/* add request to ep queue */
-	if (req) {
-
-		list_add_tail(&req->queue, &ep->queue);
-
-		/* open rxfifo if out data queued */
-		if (open_rxfifo) {
-			/* enable DMA */
-			req->dma_going = 1;
-			udc_set_rde(dev);
-			if (ep->num != UDC_EP0OUT_IX)
-				dev->data_ep_queued = 1;
-		}
-		/* stop OUT naking */
-		if (!ep->in) {
-			if (!use_dma && udc_rxfifo_pending) {
-				DBG(dev, "udc_queue(): pending bytes in "
-					"rxfifo after nyet\n");
-				/*
-				 * read pending bytes afer nyet:
-				 * referring to isr
-				 */
-				if (udc_rxfifo_read(ep, req)) {
-					/* finish */
-					complete_req(ep, req, 0);
-				}
-				udc_rxfifo_pending = 0;
-
-			}
-		}
-	}
-
-finished:
-	spin_unlock_irqrestore(&dev->lock, iflags);
-	return retval;
-}
-
-/* Empty request queue of an endpoint; caller holds spinlock */
-static void empty_req_queue(struct udc_ep *ep)
-{
-	struct udc_request	*req;
-
-	ep->halted = 1;
-	while (!list_empty(&ep->queue)) {
-		req = list_entry(ep->queue.next,
-			struct udc_request,
-			queue);
-		complete_req(ep, req, -ESHUTDOWN);
-	}
-}
-
-/* Dequeues a request packet, called by gadget driver */
-static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
-{
-	struct udc_ep		*ep;
-	struct udc_request	*req;
-	unsigned		halted;
-	unsigned long		iflags;
-
-	ep = container_of(usbep, struct udc_ep, ep);
-	if (!usbep || !usbreq || (!ep->ep.desc && (ep->num != 0
-				&& ep->num != UDC_EP0OUT_IX)))
-		return -EINVAL;
-
-	req = container_of(usbreq, struct udc_request, req);
-
-	spin_lock_irqsave(&ep->dev->lock, iflags);
-	halted = ep->halted;
-	ep->halted = 1;
-	/* request in processing or next one */
-	if (ep->queue.next == &req->queue) {
-		if (ep->dma && req->dma_going) {
-			if (ep->in)
-				ep->cancel_transfer = 1;
-			else {
-				u32 tmp;
-				u32 dma_sts;
-				/* stop potential receive DMA */
-				tmp = readl(&udc->regs->ctl);
-				writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
-							&udc->regs->ctl);
-				/*
-				 * Cancel transfer later in ISR
-				 * if descriptor was touched.
-				 */
-				dma_sts = AMD_GETBITS(req->td_data->status,
-							UDC_DMA_OUT_STS_BS);
-				if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
-					ep->cancel_transfer = 1;
-				else {
-					udc_init_bna_dummy(ep->req);
-					writel(ep->bna_dummy_req->td_phys,
-						&ep->regs->desptr);
-				}
-				writel(tmp, &udc->regs->ctl);
-			}
-		}
-	}
-	complete_req(ep, req, -ECONNRESET);
-	ep->halted = halted;
-
-	spin_unlock_irqrestore(&ep->dev->lock, iflags);
-	return 0;
-}
-
-/* Halt or clear halt of endpoint */
-static int
-udc_set_halt(struct usb_ep *usbep, int halt)
-{
-	struct udc_ep	*ep;
-	u32 tmp;
-	unsigned long iflags;
-	int retval = 0;
-
-	if (!usbep)
-		return -EINVAL;
-
-	pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
-
-	ep = container_of(usbep, struct udc_ep, ep);
-	if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
-		return -EINVAL;
-	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
-		return -ESHUTDOWN;
-
-	spin_lock_irqsave(&udc_stall_spinlock, iflags);
-	/* halt or clear halt */
-	if (halt) {
-		if (ep->num == 0)
-			ep->dev->stall_ep0in = 1;
-		else {
-			/*
-			 * set STALL
-			 * rxfifo empty not taken into acount
-			 */
-			tmp = readl(&ep->regs->ctl);
-			tmp |= AMD_BIT(UDC_EPCTL_S);
-			writel(tmp, &ep->regs->ctl);
-			ep->halted = 1;
-
-			/* setup poll timer */
-			if (!timer_pending(&udc_pollstall_timer)) {
-				udc_pollstall_timer.expires = jiffies +
-					HZ * UDC_POLLSTALL_TIMER_USECONDS
-					/ (1000 * 1000);
-				if (!stop_pollstall_timer) {
-					DBG(ep->dev, "start polltimer\n");
-					add_timer(&udc_pollstall_timer);
-				}
-			}
-		}
-	} else {
-		/* ep is halted by set_halt() before */
-		if (ep->halted) {
-			tmp = readl(&ep->regs->ctl);
-			/* clear stall bit */
-			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
-			/* clear NAK by writing CNAK */
-			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-			writel(tmp, &ep->regs->ctl);
-			ep->halted = 0;
-			UDC_QUEUE_CNAK(ep, ep->num);
-		}
-	}
-	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
-	return retval;
-}
-
-/* gadget interface */
-static const struct usb_ep_ops udc_ep_ops = {
-	.enable		= udc_ep_enable,
-	.disable	= udc_ep_disable,
-
-	.alloc_request	= udc_alloc_request,
-	.free_request	= udc_free_request,
-
-	.queue		= udc_queue,
-	.dequeue	= udc_dequeue,
-
-	.set_halt	= udc_set_halt,
-	/* fifo ops not implemented */
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* Get frame counter (not implemented) */
-static int udc_get_frame(struct usb_gadget *gadget)
-{
-	return -EOPNOTSUPP;
-}
-
-/* Initiates a remote wakeup */
-static int udc_remote_wakeup(struct udc *dev)
-{
-	unsigned long flags;
-	u32 tmp;
-
-	DBG(dev, "UDC initiates remote wakeup\n");
-
-	spin_lock_irqsave(&dev->lock, flags);
-
-	tmp = readl(&dev->regs->ctl);
-	tmp |= AMD_BIT(UDC_DEVCTL_RES);
-	writel(tmp, &dev->regs->ctl);
-	tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
-	writel(tmp, &dev->regs->ctl);
-
-	spin_unlock_irqrestore(&dev->lock, flags);
-	return 0;
-}
-
-/* Remote wakeup gadget interface */
-static int udc_wakeup(struct usb_gadget *gadget)
-{
-	struct udc		*dev;
-
-	if (!gadget)
-		return -EINVAL;
-	dev = container_of(gadget, struct udc, gadget);
-	udc_remote_wakeup(dev);
-
-	return 0;
-}
-
-static int amd5536_udc_start(struct usb_gadget *g,
-		struct usb_gadget_driver *driver);
-static int amd5536_udc_stop(struct usb_gadget *g);
-
-static const struct usb_gadget_ops udc_ops = {
-	.wakeup		= udc_wakeup,
-	.get_frame	= udc_get_frame,
-	.udc_start	= amd5536_udc_start,
-	.udc_stop	= amd5536_udc_stop,
-};
-
-/* Setups endpoint parameters, adds endpoints to linked list */
-static void make_ep_lists(struct udc *dev)
-{
-	/* make gadget ep lists */
-	INIT_LIST_HEAD(&dev->gadget.ep_list);
-	list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
-						&dev->gadget.ep_list);
-	list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
-						&dev->gadget.ep_list);
-	list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
-						&dev->gadget.ep_list);
-
-	/* fifo config */
-	dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
-	if (dev->gadget.speed == USB_SPEED_FULL)
-		dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
-	else if (dev->gadget.speed == USB_SPEED_HIGH)
-		dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
-	dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
-}
-
-/* Inits UDC context */
-void udc_basic_init(struct udc *dev)
-{
-	u32	tmp;
-
-	DBG(dev, "udc_basic_init()\n");
-
-	dev->gadget.speed = USB_SPEED_UNKNOWN;
-
-	/* stop RDE timer */
-	if (timer_pending(&udc_timer)) {
-		set_rde = 0;
-		mod_timer(&udc_timer, jiffies - 1);
-	}
-	/* stop poll stall timer */
-	if (timer_pending(&udc_pollstall_timer))
-		mod_timer(&udc_pollstall_timer, jiffies - 1);
-	/* disable DMA */
-	tmp = readl(&dev->regs->ctl);
-	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
-	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
-	writel(tmp, &dev->regs->ctl);
-
-	/* enable dynamic CSR programming */
-	tmp = readl(&dev->regs->cfg);
-	tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
-	/* set self powered */
-	tmp |= AMD_BIT(UDC_DEVCFG_SP);
-	/* set remote wakeupable */
-	tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
-	writel(tmp, &dev->regs->cfg);
-
-	make_ep_lists(dev);
-
-	dev->data_ep_enabled = 0;
-	dev->data_ep_queued = 0;
-}
-EXPORT_SYMBOL_GPL(udc_basic_init);
-
-/* init registers at driver load time */
-static int startup_registers(struct udc *dev)
-{
-	u32 tmp;
-
-	/* init controller by soft reset */
-	udc_soft_reset(dev);
-
-	/* mask not needed interrupts */
-	udc_mask_unused_interrupts(dev);
-
-	/* put into initial config */
-	udc_basic_init(dev);
-	/* link up all endpoints */
-	udc_setup_endpoints(dev);
-
-	/* program speed */
-	tmp = readl(&dev->regs->cfg);
-	if (use_fullspeed)
-		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
-	else
-		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
-	writel(tmp, &dev->regs->cfg);
-
-	return 0;
-}
-
-/* Sets initial endpoint parameters */
-static void udc_setup_endpoints(struct udc *dev)
-{
-	struct udc_ep	*ep;
-	u32	tmp;
-	u32	reg;
-
-	DBG(dev, "udc_setup_endpoints()\n");
-
-	/* read enum speed */
-	tmp = readl(&dev->regs->sts);
-	tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
-	if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH)
-		dev->gadget.speed = USB_SPEED_HIGH;
-	else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL)
-		dev->gadget.speed = USB_SPEED_FULL;
-
-	/* set basic ep parameters */
-	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
-		ep = &dev->ep[tmp];
-		ep->dev = dev;
-		ep->ep.name = ep_info[tmp].name;
-		ep->ep.caps = ep_info[tmp].caps;
-		ep->num = tmp;
-		/* txfifo size is calculated at enable time */
-		ep->txfifo = dev->txfifo;
-
-		/* fifo size */
-		if (tmp < UDC_EPIN_NUM) {
-			ep->fifo_depth = UDC_TXFIFO_SIZE;
-			ep->in = 1;
-		} else {
-			ep->fifo_depth = UDC_RXFIFO_SIZE;
-			ep->in = 0;
-
-		}
-		ep->regs = &dev->ep_regs[tmp];
-		/*
-		 * ep will be reset only if ep was not enabled before to avoid
-		 * disabling ep interrupts when ENUM interrupt occurs but ep is
-		 * not enabled by gadget driver
-		 */
-		if (!ep->ep.desc)
-			ep_init(dev->regs, ep);
-
-		if (use_dma) {
-			/*
-			 * ep->dma is not really used, just to indicate that
-			 * DMA is active: remove this
-			 * dma regs = dev control regs
-			 */
-			ep->dma = &dev->regs->ctl;
-
-			/* nak OUT endpoints until enable - not for ep0 */
-			if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
-						&& tmp > UDC_EPIN_NUM) {
-				/* set NAK */
-				reg = readl(&dev->ep[tmp].regs->ctl);
-				reg |= AMD_BIT(UDC_EPCTL_SNAK);
-				writel(reg, &dev->ep[tmp].regs->ctl);
-				dev->ep[tmp].naking = 1;
-
-			}
-		}
-	}
-	/* EP0 max packet */
-	if (dev->gadget.speed == USB_SPEED_FULL) {
-		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep,
-					   UDC_FS_EP0IN_MAX_PKT_SIZE);
-		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep,
-					   UDC_FS_EP0OUT_MAX_PKT_SIZE);
-	} else if (dev->gadget.speed == USB_SPEED_HIGH) {
-		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep,
-					   UDC_EP0IN_MAX_PKT_SIZE);
-		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep,
-					   UDC_EP0OUT_MAX_PKT_SIZE);
-	}
-
-	/*
-	 * with suspend bug workaround, ep0 params for gadget driver
-	 * are set at gadget driver bind() call
-	 */
-	dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
-	dev->ep[UDC_EP0IN_IX].halted = 0;
-	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
-
-	/* init cfg/alt/int */
-	dev->cur_config = 0;
-	dev->cur_intf = 0;
-	dev->cur_alt = 0;
-}
-
-/* Bringup after Connect event, initial bringup to be ready for ep0 events */
-static void usb_connect(struct udc *dev)
-{
-
-	dev_info(&dev->pdev->dev, "USB Connect\n");
-
-	dev->connected = 1;
-
-	/* put into initial config */
-	udc_basic_init(dev);
-
-	/* enable device setup interrupts */
-	udc_enable_dev_setup_interrupts(dev);
-}
-
-/*
- * Calls gadget with disconnect event and resets the UDC and makes
- * initial bringup to be ready for ep0 events
- */
-static void usb_disconnect(struct udc *dev)
-{
-
-	dev_info(&dev->pdev->dev, "USB Disconnect\n");
-
-	dev->connected = 0;
-
-	/* mask interrupts */
-	udc_mask_unused_interrupts(dev);
-
-	/* REVISIT there doesn't seem to be a point to having this
-	 * talk to a tasklet ... do it directly, we already hold
-	 * the spinlock needed to process the disconnect.
-	 */
-
-	tasklet_schedule(&disconnect_tasklet);
-}
-
-/* Tasklet for disconnect to be outside of interrupt context */
-static void udc_tasklet_disconnect(unsigned long par)
-{
-	struct udc *dev = (struct udc *)(*((struct udc **) par));
-	u32 tmp;
-
-	DBG(dev, "Tasklet disconnect\n");
-	spin_lock_irq(&dev->lock);
-
-	if (dev->driver) {
-		spin_unlock(&dev->lock);
-		dev->driver->disconnect(&dev->gadget);
-		spin_lock(&dev->lock);
-
-		/* empty queues */
-		for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
-			empty_req_queue(&dev->ep[tmp]);
-
-	}
-
-	/* disable ep0 */
-	ep_init(dev->regs,
-			&dev->ep[UDC_EP0IN_IX]);
-
-
-	if (!soft_reset_occured) {
-		/* init controller by soft reset */
-		udc_soft_reset(dev);
-		soft_reset_occured++;
-	}
-
-	/* re-enable dev interrupts */
-	udc_enable_dev_setup_interrupts(dev);
-	/* back to full speed ? */
-	if (use_fullspeed) {
-		tmp = readl(&dev->regs->cfg);
-		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
-		writel(tmp, &dev->regs->cfg);
-	}
-
-	spin_unlock_irq(&dev->lock);
-}
-
-/* Reset the UDC core */
-static void udc_soft_reset(struct udc *dev)
-{
-	unsigned long	flags;
-
-	DBG(dev, "Soft reset\n");
-	/*
-	 * reset possible waiting interrupts, because int.
-	 * status is lost after soft reset,
-	 * ep int. status reset
-	 */
-	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
-	/* device int. status reset */
-	writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
-
-	spin_lock_irqsave(&udc_irq_spinlock, flags);
-	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
-	readl(&dev->regs->cfg);
-	spin_unlock_irqrestore(&udc_irq_spinlock, flags);
-
-}
-
-/* RDE timer callback to set RDE bit */
-static void udc_timer_function(unsigned long v)
-{
-	u32 tmp;
-
-	spin_lock_irq(&udc_irq_spinlock);
-
-	if (set_rde > 0) {
-		/*
-		 * open the fifo if fifo was filled on last timer call
-		 * conditionally
-		 */
-		if (set_rde > 1) {
-			/* set RDE to receive setup data */
-			tmp = readl(&udc->regs->ctl);
-			tmp |= AMD_BIT(UDC_DEVCTL_RDE);
-			writel(tmp, &udc->regs->ctl);
-			set_rde = -1;
-		} else if (readl(&udc->regs->sts)
-				& AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
-			/*
-			 * if fifo empty setup polling, do not just
-			 * open the fifo
-			 */
-			udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
-			if (!stop_timer)
-				add_timer(&udc_timer);
-		} else {
-			/*
-			 * fifo contains data now, setup timer for opening
-			 * the fifo when timer expires to be able to receive
-			 * setup packets, when data packets gets queued by
-			 * gadget layer then timer will forced to expire with
-			 * set_rde=0 (RDE is set in udc_queue())
-			 */
-			set_rde++;
-			/* debug: lhadmot_timer_start = 221070 */
-			udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
-			if (!stop_timer)
-				add_timer(&udc_timer);
-		}
-
-	} else
-		set_rde = -1; /* RDE was set by udc_queue() */
-	spin_unlock_irq(&udc_irq_spinlock);
-	if (stop_timer)
-		complete(&on_exit);
-
-}
-
-/* Handle halt state, used in stall poll timer */
-static void udc_handle_halt_state(struct udc_ep *ep)
-{
-	u32 tmp;
-	/* set stall as long not halted */
-	if (ep->halted == 1) {
-		tmp = readl(&ep->regs->ctl);
-		/* STALL cleared ? */
-		if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
-			/*
-			 * FIXME: MSC spec requires that stall remains
-			 * even on receivng of CLEAR_FEATURE HALT. So
-			 * we would set STALL again here to be compliant.
-			 * But with current mass storage drivers this does
-			 * not work (would produce endless host retries).
-			 * So we clear halt on CLEAR_FEATURE.
-			 *
-			DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
-			tmp |= AMD_BIT(UDC_EPCTL_S);
-			writel(tmp, &ep->regs->ctl);*/
-
-			/* clear NAK by writing CNAK */
-			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-			writel(tmp, &ep->regs->ctl);
-			ep->halted = 0;
-			UDC_QUEUE_CNAK(ep, ep->num);
-		}
-	}
-}
-
-/* Stall timer callback to poll S bit and set it again after */
-static void udc_pollstall_timer_function(unsigned long v)
-{
-	struct udc_ep *ep;
-	int halted = 0;
-
-	spin_lock_irq(&udc_stall_spinlock);
-	/*
-	 * only one IN and OUT endpoints are handled
-	 * IN poll stall
-	 */
-	ep = &udc->ep[UDC_EPIN_IX];
-	udc_handle_halt_state(ep);
-	if (ep->halted)
-		halted = 1;
-	/* OUT poll stall */
-	ep = &udc->ep[UDC_EPOUT_IX];
-	udc_handle_halt_state(ep);
-	if (ep->halted)
-		halted = 1;
-
-	/* setup timer again when still halted */
-	if (!stop_pollstall_timer && halted) {
-		udc_pollstall_timer.expires = jiffies +
-					HZ * UDC_POLLSTALL_TIMER_USECONDS
-					/ (1000 * 1000);
-		add_timer(&udc_pollstall_timer);
-	}
-	spin_unlock_irq(&udc_stall_spinlock);
-
-	if (stop_pollstall_timer)
-		complete(&on_pollstall_exit);
-}
-
-/* Inits endpoint 0 so that SETUP packets are processed */
-static void activate_control_endpoints(struct udc *dev)
-{
-	u32 tmp;
-
-	DBG(dev, "activate_control_endpoints\n");
-
-	/* flush fifo */
-	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
-	tmp |= AMD_BIT(UDC_EPCTL_F);
-	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
-
-	/* set ep0 directions */
-	dev->ep[UDC_EP0IN_IX].in = 1;
-	dev->ep[UDC_EP0OUT_IX].in = 0;
-
-	/* set buffer size (tx fifo entries) of EP0_IN */
-	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
-	if (dev->gadget.speed == USB_SPEED_FULL)
-		tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
-					UDC_EPIN_BUFF_SIZE);
-	else if (dev->gadget.speed == USB_SPEED_HIGH)
-		tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
-					UDC_EPIN_BUFF_SIZE);
-	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
-
-	/* set max packet size of EP0_IN */
-	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
-	if (dev->gadget.speed == USB_SPEED_FULL)
-		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
-					UDC_EP_MAX_PKT_SIZE);
-	else if (dev->gadget.speed == USB_SPEED_HIGH)
-		tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
-				UDC_EP_MAX_PKT_SIZE);
-	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
-
-	/* set max packet size of EP0_OUT */
-	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
-	if (dev->gadget.speed == USB_SPEED_FULL)
-		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
-					UDC_EP_MAX_PKT_SIZE);
-	else if (dev->gadget.speed == USB_SPEED_HIGH)
-		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
-					UDC_EP_MAX_PKT_SIZE);
-	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
-
-	/* set max packet size of EP0 in UDC CSR */
-	tmp = readl(&dev->csr->ne[0]);
-	if (dev->gadget.speed == USB_SPEED_FULL)
-		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
-					UDC_CSR_NE_MAX_PKT);
-	else if (dev->gadget.speed == USB_SPEED_HIGH)
-		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
-					UDC_CSR_NE_MAX_PKT);
-	writel(tmp, &dev->csr->ne[0]);
-
-	if (use_dma) {
-		dev->ep[UDC_EP0OUT_IX].td->status |=
-			AMD_BIT(UDC_DMA_OUT_STS_L);
-		/* write dma desc address */
-		writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
-			&dev->ep[UDC_EP0OUT_IX].regs->subptr);
-		writel(dev->ep[UDC_EP0OUT_IX].td_phys,
-			&dev->ep[UDC_EP0OUT_IX].regs->desptr);
-		/* stop RDE timer */
-		if (timer_pending(&udc_timer)) {
-			set_rde = 0;
-			mod_timer(&udc_timer, jiffies - 1);
-		}
-		/* stop pollstall timer */
-		if (timer_pending(&udc_pollstall_timer))
-			mod_timer(&udc_pollstall_timer, jiffies - 1);
-		/* enable DMA */
-		tmp = readl(&dev->regs->ctl);
-		tmp |= AMD_BIT(UDC_DEVCTL_MODE)
-				| AMD_BIT(UDC_DEVCTL_RDE)
-				| AMD_BIT(UDC_DEVCTL_TDE);
-		if (use_dma_bufferfill_mode)
-			tmp |= AMD_BIT(UDC_DEVCTL_BF);
-		else if (use_dma_ppb_du)
-			tmp |= AMD_BIT(UDC_DEVCTL_DU);
-		writel(tmp, &dev->regs->ctl);
-	}
-
-	/* clear NAK by writing CNAK for EP0IN */
-	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
-	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
-	dev->ep[UDC_EP0IN_IX].naking = 0;
-	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
-
-	/* clear NAK by writing CNAK for EP0OUT */
-	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
-	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
-	dev->ep[UDC_EP0OUT_IX].naking = 0;
-	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
-}
-
-/* Make endpoint 0 ready for control traffic */
-static int setup_ep0(struct udc *dev)
-{
-	activate_control_endpoints(dev);
-	/* enable ep0 interrupts */
-	udc_enable_ep0_interrupts(dev);
-	/* enable device setup interrupts */
-	udc_enable_dev_setup_interrupts(dev);
-
-	return 0;
-}
-
-/* Called by gadget driver to register itself */
-static int amd5536_udc_start(struct usb_gadget *g,
-		struct usb_gadget_driver *driver)
-{
-	struct udc *dev = to_amd5536_udc(g);
-	u32 tmp;
-
-	driver->driver.bus = NULL;
-	dev->driver = driver;
-
-	/* Some gadget drivers use both ep0 directions.
-	 * NOTE: to gadget driver, ep0 is just one endpoint...
-	 */
-	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
-		dev->ep[UDC_EP0IN_IX].ep.driver_data;
-
-	/* get ready for ep0 traffic */
-	setup_ep0(dev);
-
-	/* clear SD */
-	tmp = readl(&dev->regs->ctl);
-	tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
-	writel(tmp, &dev->regs->ctl);
-
-	usb_connect(dev);
-
-	return 0;
-}
-
-/* shutdown requests and disconnect from gadget */
-static void
-shutdown(struct udc *dev, struct usb_gadget_driver *driver)
-__releases(dev->lock)
-__acquires(dev->lock)
-{
-	int tmp;
-
-	/* empty queues and init hardware */
-	udc_basic_init(dev);
-
-	for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
-		empty_req_queue(&dev->ep[tmp]);
-
-	udc_setup_endpoints(dev);
-}
-
-/* Called by gadget driver to unregister itself */
-static int amd5536_udc_stop(struct usb_gadget *g)
-{
-	struct udc *dev = to_amd5536_udc(g);
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&dev->lock, flags);
-	udc_mask_unused_interrupts(dev);
-	shutdown(dev, NULL);
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	dev->driver = NULL;
-
-	/* set SD */
-	tmp = readl(&dev->regs->ctl);
-	tmp |= AMD_BIT(UDC_DEVCTL_SD);
-	writel(tmp, &dev->regs->ctl);
-
-	return 0;
-}
-
-/* Clear pending NAK bits */
-static void udc_process_cnak_queue(struct udc *dev)
-{
-	u32 tmp;
-	u32 reg;
-
-	/* check epin's */
-	DBG(dev, "CNAK pending queue processing\n");
-	for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
-		if (cnak_pending & (1 << tmp)) {
-			DBG(dev, "CNAK pending for ep%d\n", tmp);
-			/* clear NAK by writing CNAK */
-			reg = readl(&dev->ep[tmp].regs->ctl);
-			reg |= AMD_BIT(UDC_EPCTL_CNAK);
-			writel(reg, &dev->ep[tmp].regs->ctl);
-			dev->ep[tmp].naking = 0;
-			UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
-		}
-	}
-	/* ...	and ep0out */
-	if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
-		DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
-		/* clear NAK by writing CNAK */
-		reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
-		reg |= AMD_BIT(UDC_EPCTL_CNAK);
-		writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
-		dev->ep[UDC_EP0OUT_IX].naking = 0;
-		UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
-				dev->ep[UDC_EP0OUT_IX].num);
-	}
-}
-
-/* Enabling RX DMA after setup packet */
-static void udc_ep0_set_rde(struct udc *dev)
-{
-	if (use_dma) {
-		/*
-		 * only enable RXDMA when no data endpoint enabled
-		 * or data is queued
-		 */
-		if (!dev->data_ep_enabled || dev->data_ep_queued) {
-			udc_set_rde(dev);
-		} else {
-			/*
-			 * setup timer for enabling RDE (to not enable
-			 * RXFIFO DMA for data endpoints to early)
-			 */
-			if (set_rde != 0 && !timer_pending(&udc_timer)) {
-				udc_timer.expires =
-					jiffies + HZ/UDC_RDE_TIMER_DIV;
-				set_rde = 1;
-				if (!stop_timer)
-					add_timer(&udc_timer);
-			}
-		}
-	}
-}
-
-
-/* Interrupt handler for data OUT traffic */
-static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
-{
-	irqreturn_t		ret_val = IRQ_NONE;
-	u32			tmp;
-	struct udc_ep		*ep;
-	struct udc_request	*req;
-	unsigned int		count;
-	struct udc_data_dma	*td = NULL;
-	unsigned		dma_done;
-
-	VDBG(dev, "ep%d irq\n", ep_ix);
-	ep = &dev->ep[ep_ix];
-
-	tmp = readl(&ep->regs->sts);
-	if (use_dma) {
-		/* BNA event ? */
-		if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
-			DBG(dev, "BNA ep%dout occurred - DESPTR = %x\n",
-					ep->num, readl(&ep->regs->desptr));
-			/* clear BNA */
-			writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
-			if (!ep->cancel_transfer)
-				ep->bna_occurred = 1;
-			else
-				ep->cancel_transfer = 0;
-			ret_val = IRQ_HANDLED;
-			goto finished;
-		}
-	}
-	/* HE event ? */
-	if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
-		dev_err(&dev->pdev->dev, "HE ep%dout occurred\n", ep->num);
-
-		/* clear HE */
-		writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
-		ret_val = IRQ_HANDLED;
-		goto finished;
-	}
-
-	if (!list_empty(&ep->queue)) {
-
-		/* next request */
-		req = list_entry(ep->queue.next,
-			struct udc_request, queue);
-	} else {
-		req = NULL;
-		udc_rxfifo_pending = 1;
-	}
-	VDBG(dev, "req = %p\n", req);
-	/* fifo mode */
-	if (!use_dma) {
-
-		/* read fifo */
-		if (req && udc_rxfifo_read(ep, req)) {
-			ret_val = IRQ_HANDLED;
-
-			/* finish */
-			complete_req(ep, req, 0);
-			/* next request */
-			if (!list_empty(&ep->queue) && !ep->halted) {
-				req = list_entry(ep->queue.next,
-					struct udc_request, queue);
-			} else
-				req = NULL;
-		}
-
-	/* DMA */
-	} else if (!ep->cancel_transfer && req) {
-		ret_val = IRQ_HANDLED;
-
-		/* check for DMA done */
-		if (!use_dma_ppb) {
-			dma_done = AMD_GETBITS(req->td_data->status,
-						UDC_DMA_OUT_STS_BS);
-		/* packet per buffer mode - rx bytes */
-		} else {
-			/*
-			 * if BNA occurred then recover desc. from
-			 * BNA dummy desc.
-			 */
-			if (ep->bna_occurred) {
-				VDBG(dev, "Recover desc. from BNA dummy\n");
-				memcpy(req->td_data, ep->bna_dummy_req->td_data,
-						sizeof(struct udc_data_dma));
-				ep->bna_occurred = 0;
-				udc_init_bna_dummy(ep->req);
-			}
-			td = udc_get_last_dma_desc(req);
-			dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
-		}
-		if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
-			/* buffer fill mode - rx bytes */
-			if (!use_dma_ppb) {
-				/* received number bytes */
-				count = AMD_GETBITS(req->td_data->status,
-						UDC_DMA_OUT_STS_RXBYTES);
-				VDBG(dev, "rx bytes=%u\n", count);
-			/* packet per buffer mode - rx bytes */
-			} else {
-				VDBG(dev, "req->td_data=%p\n", req->td_data);
-				VDBG(dev, "last desc = %p\n", td);
-				/* received number bytes */
-				if (use_dma_ppb_du) {
-					/* every desc. counts bytes */
-					count = udc_get_ppbdu_rxbytes(req);
-				} else {
-					/* last desc. counts bytes */
-					count = AMD_GETBITS(td->status,
-						UDC_DMA_OUT_STS_RXBYTES);
-					if (!count && req->req.length
-						== UDC_DMA_MAXPACKET) {
-						/*
-						 * on 64k packets the RXBYTES
-						 * field is zero
-						 */
-						count = UDC_DMA_MAXPACKET;
-					}
-				}
-				VDBG(dev, "last desc rx bytes=%u\n", count);
-			}
-
-			tmp = req->req.length - req->req.actual;
-			if (count > tmp) {
-				if ((tmp % ep->ep.maxpacket) != 0) {
-					DBG(dev, "%s: rx %db, space=%db\n",
-						ep->ep.name, count, tmp);
-					req->req.status = -EOVERFLOW;
-				}
-				count = tmp;
-			}
-			req->req.actual += count;
-			req->dma_going = 0;
-			/* complete request */
-			complete_req(ep, req, 0);
-
-			/* next request */
-			if (!list_empty(&ep->queue) && !ep->halted) {
-				req = list_entry(ep->queue.next,
-					struct udc_request,
-					queue);
-				/*
-				 * DMA may be already started by udc_queue()
-				 * called by gadget drivers completion
-				 * routine. This happens when queue
-				 * holds one request only.
-				 */
-				if (req->dma_going == 0) {
-					/* next dma */
-					if (prep_dma(ep, req, GFP_ATOMIC) != 0)
-						goto finished;
-					/* write desc pointer */
-					writel(req->td_phys,
-						&ep->regs->desptr);
-					req->dma_going = 1;
-					/* enable DMA */
-					udc_set_rde(dev);
-				}
-			} else {
-				/*
-				 * implant BNA dummy descriptor to allow
-				 * RXFIFO opening by RDE
-				 */
-				if (ep->bna_dummy_req) {
-					/* write desc pointer */
-					writel(ep->bna_dummy_req->td_phys,
-						&ep->regs->desptr);
-					ep->bna_occurred = 0;
-				}
-
-				/*
-				 * schedule timer for setting RDE if queue
-				 * remains empty to allow ep0 packets pass
-				 * through
-				 */
-				if (set_rde != 0
-						&& !timer_pending(&udc_timer)) {
-					udc_timer.expires =
-						jiffies
-						+ HZ*UDC_RDE_TIMER_SECONDS;
-					set_rde = 1;
-					if (!stop_timer)
-						add_timer(&udc_timer);
-				}
-				if (ep->num != UDC_EP0OUT_IX)
-					dev->data_ep_queued = 0;
-			}
-
-		} else {
-			/*
-			* RX DMA must be reenabled for each desc in PPBDU mode
-			* and must be enabled for PPBNDU mode in case of BNA
-			*/
-			udc_set_rde(dev);
-		}
-
-	} else if (ep->cancel_transfer) {
-		ret_val = IRQ_HANDLED;
-		ep->cancel_transfer = 0;
-	}
-
-	/* check pending CNAKS */
-	if (cnak_pending) {
-		/* CNAk processing when rxfifo empty only */
-		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
-			udc_process_cnak_queue(dev);
-	}
-
-	/* clear OUT bits in ep status */
-	writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
-finished:
-	return ret_val;
-}
-
-/* Interrupt handler for data IN traffic */
-static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
-{
-	irqreturn_t ret_val = IRQ_NONE;
-	u32 tmp;
-	u32 epsts;
-	struct udc_ep *ep;
-	struct udc_request *req;
-	struct udc_data_dma *td;
-	unsigned len;
-
-	ep = &dev->ep[ep_ix];
-
-	epsts = readl(&ep->regs->sts);
-	if (use_dma) {
-		/* BNA ? */
-		if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
-			dev_err(&dev->pdev->dev,
-				"BNA ep%din occurred - DESPTR = %08lx\n",
-				ep->num,
-				(unsigned long) readl(&ep->regs->desptr));
-
-			/* clear BNA */
-			writel(epsts, &ep->regs->sts);
-			ret_val = IRQ_HANDLED;
-			goto finished;
-		}
-	}
-	/* HE event ? */
-	if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
-		dev_err(&dev->pdev->dev,
-			"HE ep%dn occurred - DESPTR = %08lx\n",
-			ep->num, (unsigned long) readl(&ep->regs->desptr));
-
-		/* clear HE */
-		writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
-		ret_val = IRQ_HANDLED;
-		goto finished;
-	}
-
-	/* DMA completion */
-	if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
-		VDBG(dev, "TDC set- completion\n");
-		ret_val = IRQ_HANDLED;
-		if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
-			req = list_entry(ep->queue.next,
-					struct udc_request, queue);
-			/*
-			 * length bytes transferred
-			 * check dma done of last desc. in PPBDU mode
-			 */
-			if (use_dma_ppb_du) {
-				td = udc_get_last_dma_desc(req);
-				if (td)
-					req->req.actual = req->req.length;
-			} else {
-				/* assume all bytes transferred */
-				req->req.actual = req->req.length;
-			}
-
-			if (req->req.actual == req->req.length) {
-				/* complete req */
-				complete_req(ep, req, 0);
-				req->dma_going = 0;
-				/* further request available ? */
-				if (list_empty(&ep->queue)) {
-					/* disable interrupt */
-					tmp = readl(&dev->regs->ep_irqmsk);
-					tmp |= AMD_BIT(ep->num);
-					writel(tmp, &dev->regs->ep_irqmsk);
-				}
-			}
-		}
-		ep->cancel_transfer = 0;
-
-	}
-	/*
-	 * status reg has IN bit set and TDC not set (if TDC was handled,
-	 * IN must not be handled (UDC defect) ?
-	 */
-	if ((epsts & AMD_BIT(UDC_EPSTS_IN))
-			&& !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
-		ret_val = IRQ_HANDLED;
-		if (!list_empty(&ep->queue)) {
-			/* next request */
-			req = list_entry(ep->queue.next,
-					struct udc_request, queue);
-			/* FIFO mode */
-			if (!use_dma) {
-				/* write fifo */
-				udc_txfifo_write(ep, &req->req);
-				len = req->req.length - req->req.actual;
-				if (len > ep->ep.maxpacket)
-					len = ep->ep.maxpacket;
-				req->req.actual += len;
-				if (req->req.actual == req->req.length
-					|| (len != ep->ep.maxpacket)) {
-					/* complete req */
-					complete_req(ep, req, 0);
-				}
-			/* DMA */
-			} else if (req && !req->dma_going) {
-				VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
-					req, req->td_data);
-				if (req->td_data) {
-
-					req->dma_going = 1;
-
-					/*
-					 * unset L bit of first desc.
-					 * for chain
-					 */
-					if (use_dma_ppb && req->req.length >
-							ep->ep.maxpacket) {
-						req->td_data->status &=
-							AMD_CLEAR_BIT(
-							UDC_DMA_IN_STS_L);
-					}
-
-					/* write desc pointer */
-					writel(req->td_phys, &ep->regs->desptr);
-
-					/* set HOST READY */
-					req->td_data->status =
-						AMD_ADDBITS(
-						req->td_data->status,
-						UDC_DMA_IN_STS_BS_HOST_READY,
-						UDC_DMA_IN_STS_BS);
-
-					/* set poll demand bit */
-					tmp = readl(&ep->regs->ctl);
-					tmp |= AMD_BIT(UDC_EPCTL_P);
-					writel(tmp, &ep->regs->ctl);
-				}
-			}
-
-		} else if (!use_dma && ep->in) {
-			/* disable interrupt */
-			tmp = readl(
-				&dev->regs->ep_irqmsk);
-			tmp |= AMD_BIT(ep->num);
-			writel(tmp,
-				&dev->regs->ep_irqmsk);
-		}
-	}
-	/* clear status bits */
-	writel(epsts, &ep->regs->sts);
-
-finished:
-	return ret_val;
-
-}
-
-/* Interrupt handler for Control OUT traffic */
-static irqreturn_t udc_control_out_isr(struct udc *dev)
-__releases(dev->lock)
-__acquires(dev->lock)
-{
-	irqreturn_t ret_val = IRQ_NONE;
-	u32 tmp;
-	int setup_supported;
-	u32 count;
-	int set = 0;
-	struct udc_ep	*ep;
-	struct udc_ep	*ep_tmp;
-
-	ep = &dev->ep[UDC_EP0OUT_IX];
-
-	/* clear irq */
-	writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
-
-	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
-	/* check BNA and clear if set */
-	if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
-		VDBG(dev, "ep0: BNA set\n");
-		writel(AMD_BIT(UDC_EPSTS_BNA),
-			&dev->ep[UDC_EP0OUT_IX].regs->sts);
-		ep->bna_occurred = 1;
-		ret_val = IRQ_HANDLED;
-		goto finished;
-	}
-
-	/* type of data: SETUP or DATA 0 bytes */
-	tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
-	VDBG(dev, "data_typ = %x\n", tmp);
-
-	/* setup data */
-	if (tmp == UDC_EPSTS_OUT_SETUP) {
-		ret_val = IRQ_HANDLED;
-
-		ep->dev->stall_ep0in = 0;
-		dev->waiting_zlp_ack_ep0in = 0;
-
-		/* set NAK for EP0_IN */
-		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
-		tmp |= AMD_BIT(UDC_EPCTL_SNAK);
-		writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
-		dev->ep[UDC_EP0IN_IX].naking = 1;
-		/* get setup data */
-		if (use_dma) {
-
-			/* clear OUT bits in ep status */
-			writel(UDC_EPSTS_OUT_CLEAR,
-				&dev->ep[UDC_EP0OUT_IX].regs->sts);
-
-			setup_data.data[0] =
-				dev->ep[UDC_EP0OUT_IX].td_stp->data12;
-			setup_data.data[1] =
-				dev->ep[UDC_EP0OUT_IX].td_stp->data34;
-			/* set HOST READY */
-			dev->ep[UDC_EP0OUT_IX].td_stp->status =
-					UDC_DMA_STP_STS_BS_HOST_READY;
-		} else {
-			/* read fifo */
-			udc_rxfifo_read_dwords(dev, setup_data.data, 2);
-		}
-
-		/* determine direction of control data */
-		if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
-			dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
-			/* enable RDE */
-			udc_ep0_set_rde(dev);
-			set = 0;
-		} else {
-			dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
-			/*
-			 * implant BNA dummy descriptor to allow RXFIFO opening
-			 * by RDE
-			 */
-			if (ep->bna_dummy_req) {
-				/* write desc pointer */
-				writel(ep->bna_dummy_req->td_phys,
-					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
-				ep->bna_occurred = 0;
-			}
-
-			set = 1;
-			dev->ep[UDC_EP0OUT_IX].naking = 1;
-			/*
-			 * setup timer for enabling RDE (to not enable
-			 * RXFIFO DMA for data to early)
-			 */
-			set_rde = 1;
-			if (!timer_pending(&udc_timer)) {
-				udc_timer.expires = jiffies +
-							HZ/UDC_RDE_TIMER_DIV;
-				if (!stop_timer)
-					add_timer(&udc_timer);
-			}
-		}
-
-		/*
-		 * mass storage reset must be processed here because
-		 * next packet may be a CLEAR_FEATURE HALT which would not
-		 * clear the stall bit when no STALL handshake was received
-		 * before (autostall can cause this)
-		 */
-		if (setup_data.data[0] == UDC_MSCRES_DWORD0
-				&& setup_data.data[1] == UDC_MSCRES_DWORD1) {
-			DBG(dev, "MSC Reset\n");
-			/*
-			 * clear stall bits
-			 * only one IN and OUT endpoints are handled
-			 */
-			ep_tmp = &udc->ep[UDC_EPIN_IX];
-			udc_set_halt(&ep_tmp->ep, 0);
-			ep_tmp = &udc->ep[UDC_EPOUT_IX];
-			udc_set_halt(&ep_tmp->ep, 0);
-		}
-
-		/* call gadget with setup data received */
-		spin_unlock(&dev->lock);
-		setup_supported = dev->driver->setup(&dev->gadget,
-						&setup_data.request);
-		spin_lock(&dev->lock);
-
-		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
-		/* ep0 in returns data (not zlp) on IN phase */
-		if (setup_supported >= 0 && setup_supported <
-				UDC_EP0IN_MAXPACKET) {
-			/* clear NAK by writing CNAK in EP0_IN */
-			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
-			dev->ep[UDC_EP0IN_IX].naking = 0;
-			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
-
-		/* if unsupported request then stall */
-		} else if (setup_supported < 0) {
-			tmp |= AMD_BIT(UDC_EPCTL_S);
-			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
-		} else
-			dev->waiting_zlp_ack_ep0in = 1;
-
-
-		/* clear NAK by writing CNAK in EP0_OUT */
-		if (!set) {
-			tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
-			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
-			writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
-			dev->ep[UDC_EP0OUT_IX].naking = 0;
-			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
-		}
-
-		if (!use_dma) {
-			/* clear OUT bits in ep status */
-			writel(UDC_EPSTS_OUT_CLEAR,
-				&dev->ep[UDC_EP0OUT_IX].regs->sts);
-		}
-
-	/* data packet 0 bytes */
-	} else if (tmp == UDC_EPSTS_OUT_DATA) {
-		/* clear OUT bits in ep status */
-		writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
-
-		/* get setup data: only 0 packet */
-		if (use_dma) {
-			/* no req if 0 packet, just reactivate */
-			if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
-				VDBG(dev, "ZLP\n");
-
-				/* set HOST READY */
-				dev->ep[UDC_EP0OUT_IX].td->status =
-					AMD_ADDBITS(
-					dev->ep[UDC_EP0OUT_IX].td->status,
-					UDC_DMA_OUT_STS_BS_HOST_READY,
-					UDC_DMA_OUT_STS_BS);
-				/* enable RDE */
-				udc_ep0_set_rde(dev);
-				ret_val = IRQ_HANDLED;
-
-			} else {
-				/* control write */
-				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
-				/* re-program desc. pointer for possible ZLPs */
-				writel(dev->ep[UDC_EP0OUT_IX].td_phys,
-					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
-				/* enable RDE */
-				udc_ep0_set_rde(dev);
-			}
-		} else {
-
-			/* received number bytes */
-			count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
-			count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
-			/* out data for fifo mode not working */
-			count = 0;
-
-			/* 0 packet or real data ? */
-			if (count != 0) {
-				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
-			} else {
-				/* dummy read confirm */
-				readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
-				ret_val = IRQ_HANDLED;
-			}
-		}
-	}
-
-	/* check pending CNAKS */
-	if (cnak_pending) {
-		/* CNAk processing when rxfifo empty only */
-		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
-			udc_process_cnak_queue(dev);
-	}
-
-finished:
-	return ret_val;
-}
-
-/* Interrupt handler for Control IN traffic */
-static irqreturn_t udc_control_in_isr(struct udc *dev)
-{
-	irqreturn_t ret_val = IRQ_NONE;
-	u32 tmp;
-	struct udc_ep *ep;
-	struct udc_request *req;
-	unsigned len;
-
-	ep = &dev->ep[UDC_EP0IN_IX];
-
-	/* clear irq */
-	writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
-
-	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
-	/* DMA completion */
-	if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
-		VDBG(dev, "isr: TDC clear\n");
-		ret_val = IRQ_HANDLED;
-
-		/* clear TDC bit */
-		writel(AMD_BIT(UDC_EPSTS_TDC),
-				&dev->ep[UDC_EP0IN_IX].regs->sts);
-
-	/* status reg has IN bit set ? */
-	} else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
-		ret_val = IRQ_HANDLED;
-
-		if (ep->dma) {
-			/* clear IN bit */
-			writel(AMD_BIT(UDC_EPSTS_IN),
-				&dev->ep[UDC_EP0IN_IX].regs->sts);
-		}
-		if (dev->stall_ep0in) {
-			DBG(dev, "stall ep0in\n");
-			/* halt ep0in */
-			tmp = readl(&ep->regs->ctl);
-			tmp |= AMD_BIT(UDC_EPCTL_S);
-			writel(tmp, &ep->regs->ctl);
-		} else {
-			if (!list_empty(&ep->queue)) {
-				/* next request */
-				req = list_entry(ep->queue.next,
-						struct udc_request, queue);
-
-				if (ep->dma) {
-					/* write desc pointer */
-					writel(req->td_phys, &ep->regs->desptr);
-					/* set HOST READY */
-					req->td_data->status =
-						AMD_ADDBITS(
-						req->td_data->status,
-						UDC_DMA_STP_STS_BS_HOST_READY,
-						UDC_DMA_STP_STS_BS);
-
-					/* set poll demand bit */
-					tmp =
-					readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
-					tmp |= AMD_BIT(UDC_EPCTL_P);
-					writel(tmp,
-					&dev->ep[UDC_EP0IN_IX].regs->ctl);
-
-					/* all bytes will be transferred */
-					req->req.actual = req->req.length;
-
-					/* complete req */
-					complete_req(ep, req, 0);
-
-				} else {
-					/* write fifo */
-					udc_txfifo_write(ep, &req->req);
-
-					/* lengh bytes transferred */
-					len = req->req.length - req->req.actual;
-					if (len > ep->ep.maxpacket)
-						len = ep->ep.maxpacket;
-
-					req->req.actual += len;
-					if (req->req.actual == req->req.length
-						|| (len != ep->ep.maxpacket)) {
-						/* complete req */
-						complete_req(ep, req, 0);
-					}
-				}
-
-			}
-		}
-		ep->halted = 0;
-		dev->stall_ep0in = 0;
-		if (!ep->dma) {
-			/* clear IN bit */
-			writel(AMD_BIT(UDC_EPSTS_IN),
-				&dev->ep[UDC_EP0IN_IX].regs->sts);
-		}
-	}
-
-	return ret_val;
-}
-
-
-/* Interrupt handler for global device events */
-static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
-__releases(dev->lock)
-__acquires(dev->lock)
-{
-	irqreturn_t ret_val = IRQ_NONE;
-	u32 tmp;
-	u32 cfg;
-	struct udc_ep *ep;
-	u16 i;
-	u8 udc_csr_epix;
-
-	/* SET_CONFIG irq ? */
-	if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
-		ret_val = IRQ_HANDLED;
-
-		/* read config value */
-		tmp = readl(&dev->regs->sts);
-		cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
-		DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
-		dev->cur_config = cfg;
-		dev->set_cfg_not_acked = 1;
-
-		/* make usb request for gadget driver */
-		memset(&setup_data, 0 , sizeof(union udc_setup_data));
-		setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
-		setup_data.request.wValue = cpu_to_le16(dev->cur_config);
-
-		/* programm the NE registers */
-		for (i = 0; i < UDC_EP_NUM; i++) {
-			ep = &dev->ep[i];
-			if (ep->in) {
-
-				/* ep ix in UDC CSR register space */
-				udc_csr_epix = ep->num;
-
-
-			/* OUT ep */
-			} else {
-				/* ep ix in UDC CSR register space */
-				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
-			}
-
-			tmp = readl(&dev->csr->ne[udc_csr_epix]);
-			/* ep cfg */
-			tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
-						UDC_CSR_NE_CFG);
-			/* write reg */
-			writel(tmp, &dev->csr->ne[udc_csr_epix]);
-
-			/* clear stall bits */
-			ep->halted = 0;
-			tmp = readl(&ep->regs->ctl);
-			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
-			writel(tmp, &ep->regs->ctl);
-		}
-		/* call gadget zero with setup data received */
-		spin_unlock(&dev->lock);
-		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
-		spin_lock(&dev->lock);
-
-	} /* SET_INTERFACE ? */
-	if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
-		ret_val = IRQ_HANDLED;
-
-		dev->set_cfg_not_acked = 1;
-		/* read interface and alt setting values */
-		tmp = readl(&dev->regs->sts);
-		dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
-		dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
-
-		/* make usb request for gadget driver */
-		memset(&setup_data, 0 , sizeof(union udc_setup_data));
-		setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
-		setup_data.request.bRequestType = USB_RECIP_INTERFACE;
-		setup_data.request.wValue = cpu_to_le16(dev->cur_alt);
-		setup_data.request.wIndex = cpu_to_le16(dev->cur_intf);
-
-		DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
-				dev->cur_alt, dev->cur_intf);
-
-		/* programm the NE registers */
-		for (i = 0; i < UDC_EP_NUM; i++) {
-			ep = &dev->ep[i];
-			if (ep->in) {
-
-				/* ep ix in UDC CSR register space */
-				udc_csr_epix = ep->num;
-
-
-			/* OUT ep */
-			} else {
-				/* ep ix in UDC CSR register space */
-				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
-			}
-
-			/* UDC CSR reg */
-			/* set ep values */
-			tmp = readl(&dev->csr->ne[udc_csr_epix]);
-			/* ep interface */
-			tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
-						UDC_CSR_NE_INTF);
-			/* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
-			/* ep alt */
-			tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
-						UDC_CSR_NE_ALT);
-			/* write reg */
-			writel(tmp, &dev->csr->ne[udc_csr_epix]);
-
-			/* clear stall bits */
-			ep->halted = 0;
-			tmp = readl(&ep->regs->ctl);
-			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
-			writel(tmp, &ep->regs->ctl);
-		}
-
-		/* call gadget zero with setup data received */
-		spin_unlock(&dev->lock);
-		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
-		spin_lock(&dev->lock);
-
-	} /* USB reset */
-	if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
-		DBG(dev, "USB Reset interrupt\n");
-		ret_val = IRQ_HANDLED;
-
-		/* allow soft reset when suspend occurs */
-		soft_reset_occured = 0;
-
-		dev->waiting_zlp_ack_ep0in = 0;
-		dev->set_cfg_not_acked = 0;
-
-		/* mask not needed interrupts */
-		udc_mask_unused_interrupts(dev);
-
-		/* call gadget to resume and reset configs etc. */
-		spin_unlock(&dev->lock);
-		if (dev->sys_suspended && dev->driver->resume) {
-			dev->driver->resume(&dev->gadget);
-			dev->sys_suspended = 0;
-		}
-		usb_gadget_udc_reset(&dev->gadget, dev->driver);
-		spin_lock(&dev->lock);
-
-		/* disable ep0 to empty req queue */
-		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
-		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
-
-		/* soft reset when rxfifo not empty */
-		tmp = readl(&dev->regs->sts);
-		if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
-				&& !soft_reset_after_usbreset_occured) {
-			udc_soft_reset(dev);
-			soft_reset_after_usbreset_occured++;
-		}
-
-		/*
-		 * DMA reset to kill potential old DMA hw hang,
-		 * POLL bit is already reset by ep_init() through
-		 * disconnect()
-		 */
-		DBG(dev, "DMA machine reset\n");
-		tmp = readl(&dev->regs->cfg);
-		writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
-		writel(tmp, &dev->regs->cfg);
-
-		/* put into initial config */
-		udc_basic_init(dev);
-
-		/* enable device setup interrupts */
-		udc_enable_dev_setup_interrupts(dev);
-
-		/* enable suspend interrupt */
-		tmp = readl(&dev->regs->irqmsk);
-		tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
-		writel(tmp, &dev->regs->irqmsk);
-
-	} /* USB suspend */
-	if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
-		DBG(dev, "USB Suspend interrupt\n");
-		ret_val = IRQ_HANDLED;
-		if (dev->driver->suspend) {
-			spin_unlock(&dev->lock);
-			dev->sys_suspended = 1;
-			dev->driver->suspend(&dev->gadget);
-			spin_lock(&dev->lock);
-		}
-	} /* new speed ? */
-	if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
-		DBG(dev, "ENUM interrupt\n");
-		ret_val = IRQ_HANDLED;
-		soft_reset_after_usbreset_occured = 0;
-
-		/* disable ep0 to empty req queue */
-		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
-		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
-
-		/* link up all endpoints */
-		udc_setup_endpoints(dev);
-		dev_info(&dev->pdev->dev, "Connect: %s\n",
-			 usb_speed_string(dev->gadget.speed));
-
-		/* init ep 0 */
-		activate_control_endpoints(dev);
-
-		/* enable ep0 interrupts */
-		udc_enable_ep0_interrupts(dev);
-	}
-	/* session valid change interrupt */
-	if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
-		DBG(dev, "USB SVC interrupt\n");
-		ret_val = IRQ_HANDLED;
-
-		/* check that session is not valid to detect disconnect */
-		tmp = readl(&dev->regs->sts);
-		if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
-			/* disable suspend interrupt */
-			tmp = readl(&dev->regs->irqmsk);
-			tmp |= AMD_BIT(UDC_DEVINT_US);
-			writel(tmp, &dev->regs->irqmsk);
-			DBG(dev, "USB Disconnect (session valid low)\n");
-			/* cleanup on disconnect */
-			usb_disconnect(udc);
-		}
-
-	}
-
-	return ret_val;
-}
-
-/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
-irqreturn_t udc_irq(int irq, void *pdev)
-{
-	struct udc *dev = pdev;
-	u32 reg;
-	u16 i;
-	u32 ep_irq;
-	irqreturn_t ret_val = IRQ_NONE;
-
-	spin_lock(&dev->lock);
-
-	/* check for ep irq */
-	reg = readl(&dev->regs->ep_irqsts);
-	if (reg) {
-		if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
-			ret_val |= udc_control_out_isr(dev);
-		if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
-			ret_val |= udc_control_in_isr(dev);
-
-		/*
-		 * data endpoint
-		 * iterate ep's
-		 */
-		for (i = 1; i < UDC_EP_NUM; i++) {
-			ep_irq = 1 << i;
-			if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
-				continue;
-
-			/* clear irq status */
-			writel(ep_irq, &dev->regs->ep_irqsts);
-
-			/* irq for out ep ? */
-			if (i > UDC_EPIN_NUM)
-				ret_val |= udc_data_out_isr(dev, i);
-			else
-				ret_val |= udc_data_in_isr(dev, i);
-		}
-
-	}
-
-
-	/* check for dev irq */
-	reg = readl(&dev->regs->irqsts);
-	if (reg) {
-		/* clear irq */
-		writel(reg, &dev->regs->irqsts);
-		ret_val |= udc_dev_isr(dev, reg);
-	}
-
-
-	spin_unlock(&dev->lock);
-	return ret_val;
-}
-EXPORT_SYMBOL_GPL(udc_irq);
-
-/* Tears down device */
-void gadget_release(struct device *pdev)
-{
-	struct amd5536udc *dev = dev_get_drvdata(pdev);
-	kfree(dev);
-}
-EXPORT_SYMBOL_GPL(gadget_release);
-
-/* Cleanup on device remove */
-void udc_remove(struct udc *dev)
-{
-	/* remove timer */
-	stop_timer++;
-	if (timer_pending(&udc_timer))
-		wait_for_completion(&on_exit);
-	if (udc_timer.data)
-		del_timer_sync(&udc_timer);
-	/* remove pollstall timer */
-	stop_pollstall_timer++;
-	if (timer_pending(&udc_pollstall_timer))
-		wait_for_completion(&on_pollstall_exit);
-	if (udc_pollstall_timer.data)
-		del_timer_sync(&udc_pollstall_timer);
-	udc = NULL;
-}
-EXPORT_SYMBOL_GPL(udc_remove);
-
-/* free all the dma pools */
-void free_dma_pools(struct udc *dev)
-{
-	dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td,
-		      dev->ep[UDC_EP0OUT_IX].td_phys);
-	dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
-		      dev->ep[UDC_EP0OUT_IX].td_stp_dma);
-	dma_pool_destroy(dev->stp_requests);
-	dma_pool_destroy(dev->data_requests);
-}
-EXPORT_SYMBOL_GPL(free_dma_pools);
-
-/* create dma pools on init */
-int init_dma_pools(struct udc *dev)
-{
-	struct udc_stp_dma	*td_stp;
-	struct udc_data_dma	*td_data;
-	int retval;
-
-	/* consistent DMA mode setting ? */
-	if (use_dma_ppb) {
-		use_dma_bufferfill_mode = 0;
-	} else {
-		use_dma_ppb_du = 0;
-		use_dma_bufferfill_mode = 1;
-	}
-
-	/* DMA setup */
-	dev->data_requests = dma_pool_create("data_requests", NULL,
-		sizeof(struct udc_data_dma), 0, 0);
-	if (!dev->data_requests) {
-		DBG(dev, "can't get request data pool\n");
-		return -ENOMEM;
-	}
-
-	/* EP0 in dma regs = dev control regs */
-	dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
-
-	/* dma desc for setup data */
-	dev->stp_requests = dma_pool_create("setup requests", NULL,
-		sizeof(struct udc_stp_dma), 0, 0);
-	if (!dev->stp_requests) {
-		DBG(dev, "can't get stp request pool\n");
-		retval = -ENOMEM;
-		goto err_create_dma_pool;
-	}
-	/* setup */
-	td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
-				&dev->ep[UDC_EP0OUT_IX].td_stp_dma);
-	if (!td_stp) {
-		retval = -ENOMEM;
-		goto err_alloc_dma;
-	}
-	dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
-
-	/* data: 0 packets !? */
-	td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
-				&dev->ep[UDC_EP0OUT_IX].td_phys);
-	if (!td_data) {
-		retval = -ENOMEM;
-		goto err_alloc_phys;
-	}
-	dev->ep[UDC_EP0OUT_IX].td = td_data;
-	return 0;
-
-err_alloc_phys:
-	dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
-		      dev->ep[UDC_EP0OUT_IX].td_stp_dma);
-err_alloc_dma:
-	dma_pool_destroy(dev->stp_requests);
-	dev->stp_requests = NULL;
-err_create_dma_pool:
-	dma_pool_destroy(dev->data_requests);
-	dev->data_requests = NULL;
-	return retval;
-}
-EXPORT_SYMBOL_GPL(init_dma_pools);
-
-/* general probe */
-int udc_probe(struct udc *dev)
-{
-	char		tmp[128];
-	u32		reg;
-	int		retval;
-
-	/* mark timer as not initialized */
-	udc_timer.data = 0;
-	udc_pollstall_timer.data = 0;
-
-	/* device struct setup */
-	dev->gadget.ops = &udc_ops;
-
-	dev_set_name(&dev->gadget.dev, "gadget");
-	dev->gadget.name = name;
-	dev->gadget.max_speed = USB_SPEED_HIGH;
-
-	/* init registers, interrupts, ... */
-	startup_registers(dev);
-
-	dev_info(&dev->pdev->dev, "%s\n", mod_desc);
-
-	snprintf(tmp, sizeof(tmp), "%d", dev->irq);
-	dev_info(&dev->pdev->dev,
-		 "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
-		 tmp, dev->phys_addr, dev->chiprev,
-		 (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
-	strcpy(tmp, UDC_DRIVER_VERSION_STRING);
-	if (dev->chiprev == UDC_HSA0_REV) {
-		dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
-		retval = -ENODEV;
-		goto finished;
-	}
-	dev_info(&dev->pdev->dev,
-		 "driver version: %s(for Geode5536 B1)\n", tmp);
-	udc = dev;
-
-	retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
-					    gadget_release);
-	if (retval)
-		goto finished;
-
-	/* timer init */
-	init_timer(&udc_timer);
-	udc_timer.function = udc_timer_function;
-	udc_timer.data = 1;
-	/* timer pollstall init */
-	init_timer(&udc_pollstall_timer);
-	udc_pollstall_timer.function = udc_pollstall_timer_function;
-	udc_pollstall_timer.data = 1;
-
-	/* set SD */
-	reg = readl(&dev->regs->ctl);
-	reg |= AMD_BIT(UDC_DEVCTL_SD);
-	writel(reg, &dev->regs->ctl);
-
-	/* print dev register info */
-	print_regs(dev);
-
-	return 0;
-
-finished:
-	return retval;
-}
-EXPORT_SYMBOL_GPL(udc_probe);
-
-MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
-MODULE_AUTHOR("Thomas Dahlmann");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c
new file mode 100644
index 0000000..91d0f1a
--- /dev/null
+++ b/drivers/usb/gadget/udc/snps_udc_core.c
@@ -0,0 +1,3219 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * This file does the core driver implementation for the UDC that is based
+ * on Synopsys device controller IP (different than HS OTG IP) that is either
+ * connected through PCI bus or integrated to SoC platforms.
+ */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION		"Synopsys USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING	"01.00.0206"
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/prefetch.h>
+#include <linux/moduleparam.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include "amd5536udc.h"
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde  0 == do not touch RDE, do no start the RDE timer
+ * set_rde  1 == timer function will look whether FIFO has data
+ * set_rde  2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+		(unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const struct {
+	const char *name;
+	const struct usb_ep_caps caps;
+} ep_info[] = {
+#define EP_INFO(_name, _caps) \
+	{ \
+		.name = _name, \
+		.caps = _caps, \
+	}
+
+	EP_INFO(ep0_string,
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep1in-int",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep2in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep3in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep4in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep5in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep6in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep7in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep8in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep9in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep10in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep11in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep12in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep13in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep14in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep15in-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+	EP_INFO("ep0out",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep1out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep2out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep3out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep4out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep5out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep6out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep7out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep8out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep9out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep10out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep11out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep12out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep13out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep14out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+	EP_INFO("ep15out-bulk",
+		USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+
+#undef EP_INFO
+};
+
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+	DBG(dev, "------- Device registers -------\n");
+	DBG(dev, "dev config     = %08x\n", readl(&dev->regs->cfg));
+	DBG(dev, "dev control    = %08x\n", readl(&dev->regs->ctl));
+	DBG(dev, "dev status     = %08x\n", readl(&dev->regs->sts));
+	DBG(dev, "\n");
+	DBG(dev, "dev int's      = %08x\n", readl(&dev->regs->irqsts));
+	DBG(dev, "dev intmask    = %08x\n", readl(&dev->regs->irqmsk));
+	DBG(dev, "\n");
+	DBG(dev, "dev ep int's   = %08x\n", readl(&dev->regs->ep_irqsts));
+	DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+	DBG(dev, "\n");
+	DBG(dev, "USE DMA        = %d\n", use_dma);
+	if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+		DBG(dev, "DMA mode       = PPBNDU (packet per buffer "
+			"WITHOUT desc. update)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+	} else if (use_dma && use_dma_ppb && use_dma_ppb_du) {
+		DBG(dev, "DMA mode       = PPBDU (packet per buffer "
+			"WITH desc. update)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+	}
+	if (use_dma && use_dma_bufferfill_mode) {
+		DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+	}
+	if (!use_dma)
+		dev_info(&dev->pdev->dev, "FIFO mode\n");
+	DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+int udc_mask_unused_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	/* mask all dev interrupts */
+	tmp =	AMD_BIT(UDC_DEVINT_SVC) |
+		AMD_BIT(UDC_DEVINT_ENUM) |
+		AMD_BIT(UDC_DEVINT_US) |
+		AMD_BIT(UDC_DEVINT_UR) |
+		AMD_BIT(UDC_DEVINT_ES) |
+		AMD_BIT(UDC_DEVINT_SI) |
+		AMD_BIT(UDC_DEVINT_SOF)|
+		AMD_BIT(UDC_DEVINT_SC);
+	writel(tmp, &dev->regs->irqmsk);
+
+	/* mask all ep interrupts */
+	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(udc_mask_unused_interrupts);
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	/* enable ep0 irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+		& AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "enable device interrupts for setup data\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->irqmsk);
+
+	/* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+		& AMD_UNMASK_BIT(UDC_DEVINT_SC)
+		& AMD_UNMASK_BIT(UDC_DEVINT_UR)
+		& AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+		& AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+	writel(tmp, &dev->regs->irqmsk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(udc_enable_dev_setup_interrupts);
+
+/* Calculates fifo start of endpoint based on preceding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+	struct udc	*dev;
+	u32 tmp;
+	int i;
+
+	if (!ep || !(ep->in))
+		return -EINVAL;
+
+	dev = ep->dev;
+	ep->txfifo = dev->txfifo;
+
+	/* traverse ep's */
+	for (i = 0; i < ep->num; i++) {
+		if (dev->ep[i].regs) {
+			/* read fifo size */
+			tmp = readl(&dev->ep[i].regs->bufin_framenum);
+			tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+			ep->txfifo += tmp;
+		}
+	}
+	return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+	if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+		DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+		cnak_pending |= 1 << (num);
+		ep->naking = 1;
+	} else
+		cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+	struct udc_ep		*ep;
+	struct udc		*dev;
+	u32			tmp;
+	unsigned long		iflags;
+	u8 udc_csr_epix;
+	unsigned		maxpacket;
+
+	if (!usbep
+			|| usbep->name == ep0_string
+			|| !desc
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	dev = ep->dev;
+
+	DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	ep->ep.desc = desc;
+
+	ep->halted = 0;
+
+	/* set traffic type */
+	tmp = readl(&dev->ep[ep->num].regs->ctl);
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+	writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+	/* set max packet size */
+	maxpacket = usb_endpoint_maxp(desc);
+	tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+	tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
+	ep->ep.maxpacket = maxpacket;
+	writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+	/* IN ep */
+	if (ep->in) {
+
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num;
+
+		/* set buffer size (tx fifo entries) */
+		tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+		/* double buffering: fifo size = 2 x max packet size */
+		tmp = AMD_ADDBITS(
+				tmp,
+				maxpacket * UDC_EPIN_BUFF_SIZE_MULT
+					  / UDC_DWORD_BYTES,
+				UDC_EPIN_BUFF_SIZE);
+		writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+		/* calc. tx fifo base addr */
+		udc_set_txfifo_addr(ep);
+
+		/* flush fifo */
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_F);
+		writel(tmp, &ep->regs->ctl);
+
+	/* OUT ep */
+	} else {
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+		/* set max packet size UDC CSR	*/
+		tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+		tmp = AMD_ADDBITS(tmp, maxpacket,
+					UDC_CSR_NE_MAX_PKT);
+		writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+		if (use_dma && !ep->in) {
+			/* alloc and init BNA dummy request */
+			ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+			ep->bna_occurred = 0;
+		}
+
+		if (ep->num != UDC_EP0OUT_IX)
+			dev->data_ep_enabled = 1;
+	}
+
+	/* set ep values */
+	tmp = readl(&dev->csr->ne[udc_csr_epix]);
+	/* max packet */
+	tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT);
+	/* ep number */
+	tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+	/* ep direction */
+	tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+	/* ep type */
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+	/* ep config */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+	/* ep interface */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+	/* ep alt */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+	/* write reg */
+	writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+	/* enable ep irq */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	tmp &= AMD_UNMASK_BIT(ep->num);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	/*
+	 * clear NAK by writing CNAK
+	 * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+	 */
+	if (!use_dma || ep->in) {
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(tmp, &ep->regs->ctl);
+		ep->naking = 0;
+		UDC_QUEUE_CNAK(ep, ep->num);
+	}
+	tmp = desc->bEndpointAddress;
+	DBG(dev, "%s enabled\n", usbep->name);
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+	u32		tmp;
+
+	VDBG(ep->dev, "ep-%d reset\n", ep->num);
+	ep->ep.desc = NULL;
+	ep->ep.ops = &udc_ep_ops;
+	INIT_LIST_HEAD(&ep->queue);
+
+	usb_ep_set_maxpacket_limit(&ep->ep,(u16) ~0);
+	/* set NAK */
+	tmp = readl(&ep->regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+	writel(tmp, &ep->regs->ctl);
+	ep->naking = 1;
+
+	/* disable interrupt */
+	tmp = readl(&regs->ep_irqmsk);
+	tmp |= AMD_BIT(ep->num);
+	writel(tmp, &regs->ep_irqmsk);
+
+	if (ep->in) {
+		/* unset P and IN bit of potential former DMA */
+		tmp = readl(&ep->regs->ctl);
+		tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+		writel(tmp, &ep->regs->ctl);
+
+		tmp = readl(&ep->regs->sts);
+		tmp |= AMD_BIT(UDC_EPSTS_IN);
+		writel(tmp, &ep->regs->sts);
+
+		/* flush the fifo */
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_F);
+		writel(tmp, &ep->regs->ctl);
+
+	}
+	/* reset desc pointer */
+	writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+	struct udc_ep	*ep = NULL;
+	unsigned long	iflags;
+
+	if (!usbep)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (usbep->name == ep0_string || !ep->ep.desc)
+		return -EINVAL;
+
+	DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+	empty_req_queue(ep);
+	ep_init(ep->dev->regs, ep);
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+	return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+	struct udc_request	*req;
+	struct udc_data_dma	*dma_desc;
+	struct udc_ep	*ep;
+
+	if (!usbep)
+		return NULL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+
+	VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+	req = kzalloc(sizeof(struct udc_request), gfp);
+	if (!req)
+		return NULL;
+
+	req->req.dma = DMA_DONT_USE;
+	INIT_LIST_HEAD(&req->queue);
+
+	if (ep->dma) {
+		/* ep0 in requests are allocated from data pool here */
+		dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+						&req->td_phys);
+		if (!dma_desc) {
+			kfree(req);
+			return NULL;
+		}
+
+		VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+				"td_phys = %lx\n",
+				req, dma_desc,
+				(unsigned long)req->td_phys);
+		/* prevent from using desc. - set HOST BUSY */
+		dma_desc->status = AMD_ADDBITS(dma_desc->status,
+						UDC_DMA_STP_STS_BS_HOST_BUSY,
+						UDC_DMA_STP_STS_BS);
+		dma_desc->bufptr = cpu_to_le32(DMA_DONT_USE);
+		req->td_data = dma_desc;
+		req->td_data_last = NULL;
+		req->chain_len = 1;
+	}
+
+	return &req->req;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static void udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+	struct udc_data_dma *td = req->td_data;
+	unsigned int i;
+
+	dma_addr_t addr_next = 0x00;
+	dma_addr_t addr = (dma_addr_t)td->next;
+
+	DBG(dev, "free chain req = %p\n", req);
+
+	/* do not free first desc., will be done by free for request */
+	for (i = 1; i < req->chain_len; i++) {
+		td = phys_to_virt(addr);
+		addr_next = (dma_addr_t)td->next;
+		pci_pool_free(dev->data_requests, td, addr);
+		addr = addr_next;
+	}
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep	*ep;
+	struct udc_request	*req;
+
+	if (!usbep || !usbreq)
+		return;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	req = container_of(usbreq, struct udc_request, req);
+	VDBG(ep->dev, "free_req req=%p\n", req);
+	BUG_ON(!list_empty(&req->queue));
+	if (req->td_data) {
+		VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+		/* free dma chain if created */
+		if (req->chain_len > 1)
+			udc_free_dma_chain(ep->dev, req);
+
+		pci_pool_free(ep->dev->data_requests, req->td_data,
+							req->td_phys);
+	}
+	kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+	if (req) {
+		/* set last bit */
+		req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+		/* set next pointer to itself */
+		req->td_data->next = req->td_phys;
+		/* set HOST BUSY */
+		req->td_data->status
+			= AMD_ADDBITS(req->td_data->status,
+					UDC_DMA_STP_STS_BS_DMA_DONE,
+					UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+		pr_debug("bna desc = %p, sts = %08x\n",
+			req->td_data, req->td_data->status);
+#endif
+	}
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+	struct udc_request *req = NULL;
+	struct usb_request *_req = NULL;
+
+	/* alloc the dummy request */
+	_req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+	if (_req) {
+		req = container_of(_req, struct udc_request, req);
+		ep->bna_dummy_req = req;
+		udc_init_bna_dummy(req);
+	}
+	return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+	u8			*req_buf;
+	u32			*buf;
+	int			i, j;
+	unsigned		bytes = 0;
+	unsigned		remaining = 0;
+
+	if (!req || !ep)
+		return;
+
+	req_buf = req->buf + req->actual;
+	prefetch(req_buf);
+	remaining = req->length - req->actual;
+
+	buf = (u32 *) req_buf;
+
+	bytes = ep->ep.maxpacket;
+	if (bytes > remaining)
+		bytes = remaining;
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
+		writel(*(buf + i), ep->txfifo);
+
+	/* remaining bytes must be written by byte access */
+	for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+		writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+							ep->txfifo);
+	}
+
+	/* dummy write confirm */
+	writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+	int i;
+
+	VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+	for (i = 0; i < dwords; i++)
+		*(buf + i) = readl(dev->rxfifo);
+	return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+	int i, j;
+	u32 tmp;
+
+	VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
+		*((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+
+	/* remaining bytes must be read by byte access */
+	if (bytes % UDC_DWORD_BYTES) {
+		tmp = readl(dev->rxfifo);
+		for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+			*(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+			tmp = tmp >> UDC_BITS_PER_BYTE;
+		}
+	}
+
+	return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+	u8 *buf;
+	unsigned buf_space;
+	unsigned bytes = 0;
+	unsigned finished = 0;
+
+	/* received number bytes */
+	bytes = readl(&ep->regs->sts);
+	bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+	buf_space = req->req.length - req->req.actual;
+	buf = req->req.buf + req->req.actual;
+	if (bytes > buf_space) {
+		if ((buf_space % ep->ep.maxpacket) != 0) {
+			DBG(ep->dev,
+				"%s: rx %d bytes, rx-buf space = %d bytesn\n",
+				ep->ep.name, bytes, buf_space);
+			req->req.status = -EOVERFLOW;
+		}
+		bytes = buf_space;
+	}
+	req->req.actual += bytes;
+
+	/* last packet ? */
+	if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+		|| ((req->req.actual == req->req.length) && !req->req.zero))
+		finished = 1;
+
+	/* read rx fifo bytes */
+	VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+	udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+	return finished;
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+	struct udc_ep *ep,
+	struct udc_request *req,
+	unsigned long buf_len, gfp_t gfp_flags
+)
+{
+	unsigned long bytes = req->req.length;
+	unsigned int i;
+	dma_addr_t dma_addr;
+	struct udc_data_dma	*td = NULL;
+	struct udc_data_dma	*last = NULL;
+	unsigned long txbytes;
+	unsigned create_new_chain = 0;
+	unsigned len;
+
+	VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+	     bytes, buf_len);
+	dma_addr = DMA_DONT_USE;
+
+	/* unset L bit in first desc for OUT */
+	if (!ep->in)
+		req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+
+	/* alloc only new desc's if not already available */
+	len = req->req.length / ep->ep.maxpacket;
+	if (req->req.length % ep->ep.maxpacket)
+		len++;
+
+	if (len > req->chain_len) {
+		/* shorter chain already allocated before */
+		if (req->chain_len > 1)
+			udc_free_dma_chain(ep->dev, req);
+		req->chain_len = len;
+		create_new_chain = 1;
+	}
+
+	td = req->td_data;
+	/* gen. required number of descriptors and buffers */
+	for (i = buf_len; i < bytes; i += buf_len) {
+		/* create or determine next desc. */
+		if (create_new_chain) {
+			td = pci_pool_alloc(ep->dev->data_requests,
+					    gfp_flags, &dma_addr);
+			if (!td)
+				return -ENOMEM;
+
+			td->status = 0;
+		} else if (i == buf_len) {
+			/* first td */
+			td = (struct udc_data_dma *)phys_to_virt(
+						req->td_data->next);
+			td->status = 0;
+		} else {
+			td = (struct udc_data_dma *)phys_to_virt(last->next);
+			td->status = 0;
+		}
+
+		if (td)
+			td->bufptr = req->req.dma + i; /* assign buffer */
+		else
+			break;
+
+		/* short packet ? */
+		if ((bytes - i) >= buf_len) {
+			txbytes = buf_len;
+		} else {
+			/* short packet */
+			txbytes = bytes - i;
+		}
+
+		/* link td and assign tx bytes */
+		if (i == buf_len) {
+			if (create_new_chain)
+				req->td_data->next = dma_addr;
+			/*
+			 * else
+			 *	req->td_data->next = virt_to_phys(td);
+			 */
+			/* write tx bytes */
+			if (ep->in) {
+				/* first desc */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+						    ep->ep.maxpacket,
+						    UDC_DMA_IN_STS_TXBYTES);
+				/* second desc */
+				td->status = AMD_ADDBITS(td->status,
+							txbytes,
+							UDC_DMA_IN_STS_TXBYTES);
+			}
+		} else {
+			if (create_new_chain)
+				last->next = dma_addr;
+			/*
+			 * else
+			 *	last->next = virt_to_phys(td);
+			 */
+			if (ep->in) {
+				/* write tx bytes */
+				td->status = AMD_ADDBITS(td->status,
+							txbytes,
+							UDC_DMA_IN_STS_TXBYTES);
+			}
+		}
+		last = td;
+	}
+	/* set last bit */
+	if (td) {
+		td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+		/* last desc. points to itself */
+		req->td_data_last = td;
+	}
+
+	return 0;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+	int	retval = 0;
+	u32	tmp;
+
+	VDBG(ep->dev, "prep_dma\n");
+	VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+			ep->num, req->td_data);
+
+	/* set buffer pointer */
+	req->td_data->bufptr = req->req.dma;
+
+	/* set last bit */
+	req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+	/* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+	if (use_dma_ppb) {
+
+		retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+		if (retval != 0) {
+			if (retval == -ENOMEM)
+				DBG(ep->dev, "Out of DMA memory\n");
+			return retval;
+		}
+		if (ep->in) {
+			if (req->req.length == ep->ep.maxpacket) {
+				/* write tx bytes */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+						ep->ep.maxpacket,
+						UDC_DMA_IN_STS_TXBYTES);
+
+			}
+		}
+
+	}
+
+	if (ep->in) {
+		VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+				"maxpacket=%d ep%d\n",
+				use_dma_ppb, req->req.length,
+				ep->ep.maxpacket, ep->num);
+		/*
+		 * if bytes < max packet then tx bytes must
+		 * be written in packet per buffer mode
+		 */
+		if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+				|| ep->num == UDC_EP0OUT_IX
+				|| ep->num == UDC_EP0IN_IX) {
+			/* write tx bytes */
+			req->td_data->status =
+				AMD_ADDBITS(req->td_data->status,
+						req->req.length,
+						UDC_DMA_IN_STS_TXBYTES);
+			/* reset frame num */
+			req->td_data->status =
+				AMD_ADDBITS(req->td_data->status,
+						0,
+						UDC_DMA_IN_STS_FRAMENUM);
+		}
+		/* set HOST BUSY */
+		req->td_data->status =
+			AMD_ADDBITS(req->td_data->status,
+				UDC_DMA_STP_STS_BS_HOST_BUSY,
+				UDC_DMA_STP_STS_BS);
+	} else {
+		VDBG(ep->dev, "OUT set host ready\n");
+		/* set HOST READY */
+		req->td_data->status =
+			AMD_ADDBITS(req->td_data->status,
+				UDC_DMA_STP_STS_BS_HOST_READY,
+				UDC_DMA_STP_STS_BS);
+
+
+			/* clear NAK by writing CNAK */
+			if (ep->naking) {
+				tmp = readl(&ep->regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &ep->regs->ctl);
+				ep->naking = 0;
+				UDC_QUEUE_CNAK(ep, ep->num);
+			}
+
+	}
+
+	return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+	struct udc		*dev;
+	unsigned		halted;
+
+	VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+	dev = ep->dev;
+	/* unmap DMA */
+	if (ep->dma)
+		usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in);
+
+	halted = ep->halted;
+	ep->halted = 1;
+
+	/* set new status if pending */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = sts;
+
+	/* remove from ep queue */
+	list_del_init(&req->queue);
+
+	VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+		&req->req, req->req.length, ep->ep.name, sts);
+
+	spin_unlock(&dev->lock);
+	usb_gadget_giveback_request(&ep->ep, &req->req);
+	spin_lock(&dev->lock);
+	ep->halted = halted;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+	struct udc_data_dma	*td;
+
+	td = req->td_data;
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L)))
+		td = phys_to_virt(td->next);
+
+	return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+	struct udc_data_dma	*td;
+	u32 count;
+
+	td = req->td_data;
+	/* received number bytes */
+	count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+		td = phys_to_virt(td->next);
+		/* received number bytes */
+		if (td) {
+			count += AMD_GETBITS(td->status,
+				UDC_DMA_OUT_STS_RXBYTES);
+		}
+	}
+
+	return count;
+
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+	u32 tmp;
+
+	VDBG(dev, "udc_set_rde()\n");
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+	/* set RDE */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+	writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+	int			retval = 0;
+	u8			open_rxfifo = 0;
+	unsigned long		iflags;
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	struct udc		*dev;
+	u32			tmp;
+
+	/* check the inputs */
+	req = container_of(usbreq, struct udc_request, req);
+
+	if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+			|| !list_empty(&req->queue))
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+
+	VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+	dev = ep->dev;
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* map dma (usually done before) */
+	if (ep->dma) {
+		VDBG(dev, "DMA map req %p\n", req);
+		retval = usb_gadget_map_request(&udc->gadget, usbreq, ep->in);
+		if (retval)
+			return retval;
+	}
+
+	VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+			usbep->name, usbreq, usbreq->length,
+			req->td_data, usbreq->buf);
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	usbreq->actual = 0;
+	usbreq->status = -EINPROGRESS;
+	req->dma_done = 0;
+
+	/* on empty queue just do first transfer */
+	if (list_empty(&ep->queue)) {
+		/* zlp */
+		if (usbreq->length == 0) {
+			/* IN zlp's are handled by hardware */
+			complete_req(ep, req, 0);
+			VDBG(dev, "%s: zlp\n", ep->ep.name);
+			/*
+			 * if set_config or set_intf is waiting for ack by zlp
+			 * then set CSR_DONE
+			 */
+			if (dev->set_cfg_not_acked) {
+				tmp = readl(&dev->regs->ctl);
+				tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+				writel(tmp, &dev->regs->ctl);
+				dev->set_cfg_not_acked = 0;
+			}
+			/* setup command is ACK'ed now by zlp */
+			if (dev->waiting_zlp_ack_ep0in) {
+				/* clear NAK by writing CNAK in EP0_IN */
+				tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+				dev->ep[UDC_EP0IN_IX].naking = 0;
+				UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+							UDC_EP0IN_IX);
+				dev->waiting_zlp_ack_ep0in = 0;
+			}
+			goto finished;
+		}
+		if (ep->dma) {
+			retval = prep_dma(ep, req, GFP_ATOMIC);
+			if (retval != 0)
+				goto finished;
+			/* write desc pointer to enable DMA */
+			if (ep->in) {
+				/* set HOST READY */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+						UDC_DMA_IN_STS_BS_HOST_READY,
+						UDC_DMA_IN_STS_BS);
+			}
+
+			/* disabled rx dma while descriptor update */
+			if (!ep->in) {
+				/* stop RDE timer */
+				if (timer_pending(&udc_timer)) {
+					set_rde = 0;
+					mod_timer(&udc_timer, jiffies - 1);
+				}
+				/* clear RDE */
+				tmp = readl(&dev->regs->ctl);
+				tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+				writel(tmp, &dev->regs->ctl);
+				open_rxfifo = 1;
+
+				/*
+				 * if BNA occurred then let BNA dummy desc.
+				 * point to current desc.
+				 */
+				if (ep->bna_occurred) {
+					VDBG(dev, "copy to BNA dummy desc.\n");
+					memcpy(ep->bna_dummy_req->td_data,
+						req->td_data,
+						sizeof(struct udc_data_dma));
+				}
+			}
+			/* write desc pointer */
+			writel(req->td_phys, &ep->regs->desptr);
+
+			/* clear NAK by writing CNAK */
+			if (ep->naking) {
+				tmp = readl(&ep->regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &ep->regs->ctl);
+				ep->naking = 0;
+				UDC_QUEUE_CNAK(ep, ep->num);
+			}
+
+			if (ep->in) {
+				/* enable ep irq */
+				tmp = readl(&dev->regs->ep_irqmsk);
+				tmp &= AMD_UNMASK_BIT(ep->num);
+				writel(tmp, &dev->regs->ep_irqmsk);
+			}
+		} else if (ep->in) {
+				/* enable ep irq */
+				tmp = readl(&dev->regs->ep_irqmsk);
+				tmp &= AMD_UNMASK_BIT(ep->num);
+				writel(tmp, &dev->regs->ep_irqmsk);
+			}
+
+	} else if (ep->dma) {
+
+		/*
+		 * prep_dma not used for OUT ep's, this is not possible
+		 * for PPB modes, because of chain creation reasons
+		 */
+		if (ep->in) {
+			retval = prep_dma(ep, req, GFP_ATOMIC);
+			if (retval != 0)
+				goto finished;
+		}
+	}
+	VDBG(dev, "list_add\n");
+	/* add request to ep queue */
+	if (req) {
+
+		list_add_tail(&req->queue, &ep->queue);
+
+		/* open rxfifo if out data queued */
+		if (open_rxfifo) {
+			/* enable DMA */
+			req->dma_going = 1;
+			udc_set_rde(dev);
+			if (ep->num != UDC_EP0OUT_IX)
+				dev->data_ep_queued = 1;
+		}
+		/* stop OUT naking */
+		if (!ep->in) {
+			if (!use_dma && udc_rxfifo_pending) {
+				DBG(dev, "udc_queue(): pending bytes in "
+					"rxfifo after nyet\n");
+				/*
+				 * read pending bytes afer nyet:
+				 * referring to isr
+				 */
+				if (udc_rxfifo_read(ep, req)) {
+					/* finish */
+					complete_req(ep, req, 0);
+				}
+				udc_rxfifo_pending = 0;
+
+			}
+		}
+	}
+
+finished:
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+	struct udc_request	*req;
+
+	ep->halted = 1;
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next,
+			struct udc_request,
+			queue);
+		complete_req(ep, req, -ESHUTDOWN);
+	}
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	unsigned		halted;
+	unsigned long		iflags;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!usbep || !usbreq || (!ep->ep.desc && (ep->num != 0
+				&& ep->num != UDC_EP0OUT_IX)))
+		return -EINVAL;
+
+	req = container_of(usbreq, struct udc_request, req);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	halted = ep->halted;
+	ep->halted = 1;
+	/* request in processing or next one */
+	if (ep->queue.next == &req->queue) {
+		if (ep->dma && req->dma_going) {
+			if (ep->in)
+				ep->cancel_transfer = 1;
+			else {
+				u32 tmp;
+				u32 dma_sts;
+				/* stop potential receive DMA */
+				tmp = readl(&udc->regs->ctl);
+				writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+							&udc->regs->ctl);
+				/*
+				 * Cancel transfer later in ISR
+				 * if descriptor was touched.
+				 */
+				dma_sts = AMD_GETBITS(req->td_data->status,
+							UDC_DMA_OUT_STS_BS);
+				if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+					ep->cancel_transfer = 1;
+				else {
+					udc_init_bna_dummy(ep->req);
+					writel(ep->bna_dummy_req->td_phys,
+						&ep->regs->desptr);
+				}
+				writel(tmp, &udc->regs->ctl);
+			}
+		}
+	}
+	complete_req(ep, req, -ECONNRESET);
+	ep->halted = halted;
+
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+	return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+	struct udc_ep	*ep;
+	u32 tmp;
+	unsigned long iflags;
+	int retval = 0;
+
+	if (!usbep)
+		return -EINVAL;
+
+	pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+	/* halt or clear halt */
+	if (halt) {
+		if (ep->num == 0)
+			ep->dev->stall_ep0in = 1;
+		else {
+			/*
+			 * set STALL
+			 * rxfifo empty not taken into acount
+			 */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 1;
+
+			/* setup poll timer */
+			if (!timer_pending(&udc_pollstall_timer)) {
+				udc_pollstall_timer.expires = jiffies +
+					HZ * UDC_POLLSTALL_TIMER_USECONDS
+					/ (1000 * 1000);
+				if (!stop_pollstall_timer) {
+					DBG(ep->dev, "start polltimer\n");
+					add_timer(&udc_pollstall_timer);
+				}
+			}
+		}
+	} else {
+		/* ep is halted by set_halt() before */
+		if (ep->halted) {
+			tmp = readl(&ep->regs->ctl);
+			/* clear stall bit */
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			/* clear NAK by writing CNAK */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+	return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+	.enable		= udc_ep_enable,
+	.disable	= udc_ep_disable,
+
+	.alloc_request	= udc_alloc_request,
+	.free_request	= udc_free_request,
+
+	.queue		= udc_queue,
+	.dequeue	= udc_dequeue,
+
+	.set_halt	= udc_set_halt,
+	/* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+	return -EOPNOTSUPP;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+	unsigned long flags;
+	u32 tmp;
+
+	DBG(dev, "UDC initiates remote wakeup\n");
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+	tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 0;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+	struct udc		*dev;
+
+	if (!gadget)
+		return -EINVAL;
+	dev = container_of(gadget, struct udc, gadget);
+	udc_remote_wakeup(dev);
+
+	return 0;
+}
+
+static int amd5536_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int amd5536_udc_stop(struct usb_gadget *g);
+
+static const struct usb_gadget_ops udc_ops = {
+	.wakeup		= udc_wakeup,
+	.get_frame	= udc_get_frame,
+	.udc_start	= amd5536_udc_start,
+	.udc_stop	= amd5536_udc_stop,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+	/* make gadget ep lists */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+
+	/* fifo config */
+	dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+	dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* Inits UDC context */
+void udc_basic_init(struct udc *dev)
+{
+	u32	tmp;
+
+	DBG(dev, "udc_basic_init()\n");
+
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+	/* stop poll stall timer */
+	if (timer_pending(&udc_pollstall_timer))
+		mod_timer(&udc_pollstall_timer, jiffies - 1);
+	/* disable DMA */
+	tmp = readl(&dev->regs->ctl);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+	writel(tmp, &dev->regs->ctl);
+
+	/* enable dynamic CSR programming */
+	tmp = readl(&dev->regs->cfg);
+	tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+	/* set self powered */
+	tmp |= AMD_BIT(UDC_DEVCFG_SP);
+	/* set remote wakeupable */
+	tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+	writel(tmp, &dev->regs->cfg);
+
+	make_ep_lists(dev);
+
+	dev->data_ep_enabled = 0;
+	dev->data_ep_queued = 0;
+}
+EXPORT_SYMBOL_GPL(udc_basic_init);
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+	u32 tmp;
+
+	/* init controller by soft reset */
+	udc_soft_reset(dev);
+
+	/* mask not needed interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	/* put into initial config */
+	udc_basic_init(dev);
+	/* link up all endpoints */
+	udc_setup_endpoints(dev);
+
+	/* program speed */
+	tmp = readl(&dev->regs->cfg);
+	if (use_fullspeed)
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+	else
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+	writel(tmp, &dev->regs->cfg);
+
+	return 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+	struct udc_ep	*ep;
+	u32	tmp;
+	u32	reg;
+
+	DBG(dev, "udc_setup_endpoints()\n");
+
+	/* read enum speed */
+	tmp = readl(&dev->regs->sts);
+	tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+	if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH)
+		dev->gadget.speed = USB_SPEED_HIGH;
+	else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL)
+		dev->gadget.speed = USB_SPEED_FULL;
+
+	/* set basic ep parameters */
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+		ep = &dev->ep[tmp];
+		ep->dev = dev;
+		ep->ep.name = ep_info[tmp].name;
+		ep->ep.caps = ep_info[tmp].caps;
+		ep->num = tmp;
+		/* txfifo size is calculated at enable time */
+		ep->txfifo = dev->txfifo;
+
+		/* fifo size */
+		if (tmp < UDC_EPIN_NUM) {
+			ep->fifo_depth = UDC_TXFIFO_SIZE;
+			ep->in = 1;
+		} else {
+			ep->fifo_depth = UDC_RXFIFO_SIZE;
+			ep->in = 0;
+
+		}
+		ep->regs = &dev->ep_regs[tmp];
+		/*
+		 * ep will be reset only if ep was not enabled before to avoid
+		 * disabling ep interrupts when ENUM interrupt occurs but ep is
+		 * not enabled by gadget driver
+		 */
+		if (!ep->ep.desc)
+			ep_init(dev->regs, ep);
+
+		if (use_dma) {
+			/*
+			 * ep->dma is not really used, just to indicate that
+			 * DMA is active: remove this
+			 * dma regs = dev control regs
+			 */
+			ep->dma = &dev->regs->ctl;
+
+			/* nak OUT endpoints until enable - not for ep0 */
+			if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+						&& tmp > UDC_EPIN_NUM) {
+				/* set NAK */
+				reg = readl(&dev->ep[tmp].regs->ctl);
+				reg |= AMD_BIT(UDC_EPCTL_SNAK);
+				writel(reg, &dev->ep[tmp].regs->ctl);
+				dev->ep[tmp].naking = 1;
+
+			}
+		}
+	}
+	/* EP0 max packet */
+	if (dev->gadget.speed == USB_SPEED_FULL) {
+		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep,
+					   UDC_FS_EP0IN_MAX_PKT_SIZE);
+		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep,
+					   UDC_FS_EP0OUT_MAX_PKT_SIZE);
+	} else if (dev->gadget.speed == USB_SPEED_HIGH) {
+		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep,
+					   UDC_EP0IN_MAX_PKT_SIZE);
+		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep,
+					   UDC_EP0OUT_MAX_PKT_SIZE);
+	}
+
+	/*
+	 * with suspend bug workaround, ep0 params for gadget driver
+	 * are set at gadget driver bind() call
+	 */
+	dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+	dev->ep[UDC_EP0IN_IX].halted = 0;
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+	/* init cfg/alt/int */
+	dev->cur_config = 0;
+	dev->cur_intf = 0;
+	dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+	dev_info(&dev->pdev->dev, "USB Connect\n");
+
+	dev->connected = 1;
+
+	/* put into initial config */
+	udc_basic_init(dev);
+
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+	dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+	dev->connected = 0;
+
+	/* mask interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	/* REVISIT there doesn't seem to be a point to having this
+	 * talk to a tasklet ... do it directly, we already hold
+	 * the spinlock needed to process the disconnect.
+	 */
+
+	tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+	struct udc *dev = (struct udc *)(*((struct udc **) par));
+	u32 tmp;
+
+	DBG(dev, "Tasklet disconnect\n");
+	spin_lock_irq(&dev->lock);
+
+	if (dev->driver) {
+		spin_unlock(&dev->lock);
+		dev->driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+
+		/* empty queues */
+		for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+			empty_req_queue(&dev->ep[tmp]);
+
+	}
+
+	/* disable ep0 */
+	ep_init(dev->regs,
+			&dev->ep[UDC_EP0IN_IX]);
+
+
+	if (!soft_reset_occured) {
+		/* init controller by soft reset */
+		udc_soft_reset(dev);
+		soft_reset_occured++;
+	}
+
+	/* re-enable dev interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+	/* back to full speed ? */
+	if (use_fullspeed) {
+		tmp = readl(&dev->regs->cfg);
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+		writel(tmp, &dev->regs->cfg);
+	}
+
+	spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+	unsigned long	flags;
+
+	DBG(dev, "Soft reset\n");
+	/*
+	 * reset possible waiting interrupts, because int.
+	 * status is lost after soft reset,
+	 * ep int. status reset
+	 */
+	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+	/* device int. status reset */
+	writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+	spin_lock_irqsave(&udc_irq_spinlock, flags);
+	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	readl(&dev->regs->cfg);
+	spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+	u32 tmp;
+
+	spin_lock_irq(&udc_irq_spinlock);
+
+	if (set_rde > 0) {
+		/*
+		 * open the fifo if fifo was filled on last timer call
+		 * conditionally
+		 */
+		if (set_rde > 1) {
+			/* set RDE to receive setup data */
+			tmp = readl(&udc->regs->ctl);
+			tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+			writel(tmp, &udc->regs->ctl);
+			set_rde = -1;
+		} else if (readl(&udc->regs->sts)
+				& AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			/*
+			 * if fifo empty setup polling, do not just
+			 * open the fifo
+			 */
+			udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+			if (!stop_timer)
+				add_timer(&udc_timer);
+		} else {
+			/*
+			 * fifo contains data now, setup timer for opening
+			 * the fifo when timer expires to be able to receive
+			 * setup packets, when data packets gets queued by
+			 * gadget layer then timer will forced to expire with
+			 * set_rde=0 (RDE is set in udc_queue())
+			 */
+			set_rde++;
+			/* debug: lhadmot_timer_start = 221070 */
+			udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+			if (!stop_timer)
+				add_timer(&udc_timer);
+		}
+
+	} else
+		set_rde = -1; /* RDE was set by udc_queue() */
+	spin_unlock_irq(&udc_irq_spinlock);
+	if (stop_timer)
+		complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+	u32 tmp;
+	/* set stall as long not halted */
+	if (ep->halted == 1) {
+		tmp = readl(&ep->regs->ctl);
+		/* STALL cleared ? */
+		if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+			/*
+			 * FIXME: MSC spec requires that stall remains
+			 * even on receivng of CLEAR_FEATURE HALT. So
+			 * we would set STALL again here to be compliant.
+			 * But with current mass storage drivers this does
+			 * not work (would produce endless host retries).
+			 * So we clear halt on CLEAR_FEATURE.
+			 *
+			DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);*/
+
+			/* clear NAK by writing CNAK */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+	struct udc_ep *ep;
+	int halted = 0;
+
+	spin_lock_irq(&udc_stall_spinlock);
+	/*
+	 * only one IN and OUT endpoints are handled
+	 * IN poll stall
+	 */
+	ep = &udc->ep[UDC_EPIN_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+	/* OUT poll stall */
+	ep = &udc->ep[UDC_EPOUT_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+
+	/* setup timer again when still halted */
+	if (!stop_pollstall_timer && halted) {
+		udc_pollstall_timer.expires = jiffies +
+					HZ * UDC_POLLSTALL_TIMER_USECONDS
+					/ (1000 * 1000);
+		add_timer(&udc_pollstall_timer);
+	}
+	spin_unlock_irq(&udc_stall_spinlock);
+
+	if (stop_pollstall_timer)
+		complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "activate_control_endpoints\n");
+
+	/* flush fifo */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_F);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+	/* set ep0 directions */
+	dev->ep[UDC_EP0IN_IX].in = 1;
+	dev->ep[UDC_EP0OUT_IX].in = 0;
+
+	/* set buffer size (tx fifo entries) of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+					UDC_EPIN_BUFF_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+					UDC_EPIN_BUFF_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+	/* set max packet size of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+				UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0_OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0 in UDC CSR */
+	tmp = readl(&dev->csr->ne[0]);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+					UDC_CSR_NE_MAX_PKT);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+					UDC_CSR_NE_MAX_PKT);
+	writel(tmp, &dev->csr->ne[0]);
+
+	if (use_dma) {
+		dev->ep[UDC_EP0OUT_IX].td->status |=
+			AMD_BIT(UDC_DMA_OUT_STS_L);
+		/* write dma desc address */
+		writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+			&dev->ep[UDC_EP0OUT_IX].regs->subptr);
+		writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+			&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+		/* stop RDE timer */
+		if (timer_pending(&udc_timer)) {
+			set_rde = 0;
+			mod_timer(&udc_timer, jiffies - 1);
+		}
+		/* stop pollstall timer */
+		if (timer_pending(&udc_pollstall_timer))
+			mod_timer(&udc_pollstall_timer, jiffies - 1);
+		/* enable DMA */
+		tmp = readl(&dev->regs->ctl);
+		tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+				| AMD_BIT(UDC_DEVCTL_RDE)
+				| AMD_BIT(UDC_DEVCTL_TDE);
+		if (use_dma_bufferfill_mode)
+			tmp |= AMD_BIT(UDC_DEVCTL_BF);
+		else if (use_dma_ppb_du)
+			tmp |= AMD_BIT(UDC_DEVCTL_DU);
+		writel(tmp, &dev->regs->ctl);
+	}
+
+	/* clear NAK by writing CNAK for EP0IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+	dev->ep[UDC_EP0IN_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+	/* clear NAK by writing CNAK for EP0OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	dev->ep[UDC_EP0OUT_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+	activate_control_endpoints(dev);
+	/* enable ep0 interrupts */
+	udc_enable_ep0_interrupts(dev);
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+
+	return 0;
+}
+
+/* Called by gadget driver to register itself */
+static int amd5536_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct udc *dev = to_amd5536_udc(g);
+	u32 tmp;
+
+	driver->driver.bus = NULL;
+	dev->driver = driver;
+
+	/* Some gadget drivers use both ep0 directions.
+	 * NOTE: to gadget driver, ep0 is just one endpoint...
+	 */
+	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+		dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+	/* get ready for ep0 traffic */
+	setup_ep0(dev);
+
+	/* clear SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &dev->regs->ctl);
+
+	usb_connect(dev);
+
+	return 0;
+}
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	int tmp;
+
+	/* empty queues and init hardware */
+	udc_basic_init(dev);
+
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+		empty_req_queue(&dev->ep[tmp]);
+
+	udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+static int amd5536_udc_stop(struct usb_gadget *g)
+{
+	struct udc *dev = to_amd5536_udc(g);
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	udc_mask_unused_interrupts(dev);
+	shutdown(dev, NULL);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	dev->driver = NULL;
+
+	/* set SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &dev->regs->ctl);
+
+	return 0;
+}
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+	u32 tmp;
+	u32 reg;
+
+	/* check epin's */
+	DBG(dev, "CNAK pending queue processing\n");
+	for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+		if (cnak_pending & (1 << tmp)) {
+			DBG(dev, "CNAK pending for ep%d\n", tmp);
+			/* clear NAK by writing CNAK */
+			reg = readl(&dev->ep[tmp].regs->ctl);
+			reg |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(reg, &dev->ep[tmp].regs->ctl);
+			dev->ep[tmp].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+		}
+	}
+	/* ...	and ep0out */
+	if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+		DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+		/* clear NAK by writing CNAK */
+		reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		reg |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		dev->ep[UDC_EP0OUT_IX].naking = 0;
+		UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+				dev->ep[UDC_EP0OUT_IX].num);
+	}
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+	if (use_dma) {
+		/*
+		 * only enable RXDMA when no data endpoint enabled
+		 * or data is queued
+		 */
+		if (!dev->data_ep_enabled || dev->data_ep_queued) {
+			udc_set_rde(dev);
+		} else {
+			/*
+			 * setup timer for enabling RDE (to not enable
+			 * RXFIFO DMA for data endpoints to early)
+			 */
+			if (set_rde != 0 && !timer_pending(&udc_timer)) {
+				udc_timer.expires =
+					jiffies + HZ/UDC_RDE_TIMER_DIV;
+				set_rde = 1;
+				if (!stop_timer)
+					add_timer(&udc_timer);
+			}
+		}
+	}
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+	irqreturn_t		ret_val = IRQ_NONE;
+	u32			tmp;
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	unsigned int		count;
+	struct udc_data_dma	*td = NULL;
+	unsigned		dma_done;
+
+	VDBG(dev, "ep%d irq\n", ep_ix);
+	ep = &dev->ep[ep_ix];
+
+	tmp = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA event ? */
+		if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+			DBG(dev, "BNA ep%dout occurred - DESPTR = %x\n",
+					ep->num, readl(&ep->regs->desptr));
+			/* clear BNA */
+			writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+			if (!ep->cancel_transfer)
+				ep->bna_occurred = 1;
+			else
+				ep->cancel_transfer = 0;
+			ret_val = IRQ_HANDLED;
+			goto finished;
+		}
+	}
+	/* HE event ? */
+	if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+		dev_err(&dev->pdev->dev, "HE ep%dout occurred\n", ep->num);
+
+		/* clear HE */
+		writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	if (!list_empty(&ep->queue)) {
+
+		/* next request */
+		req = list_entry(ep->queue.next,
+			struct udc_request, queue);
+	} else {
+		req = NULL;
+		udc_rxfifo_pending = 1;
+	}
+	VDBG(dev, "req = %p\n", req);
+	/* fifo mode */
+	if (!use_dma) {
+
+		/* read fifo */
+		if (req && udc_rxfifo_read(ep, req)) {
+			ret_val = IRQ_HANDLED;
+
+			/* finish */
+			complete_req(ep, req, 0);
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			} else
+				req = NULL;
+		}
+
+	/* DMA */
+	} else if (!ep->cancel_transfer && req) {
+		ret_val = IRQ_HANDLED;
+
+		/* check for DMA done */
+		if (!use_dma_ppb) {
+			dma_done = AMD_GETBITS(req->td_data->status,
+						UDC_DMA_OUT_STS_BS);
+		/* packet per buffer mode - rx bytes */
+		} else {
+			/*
+			 * if BNA occurred then recover desc. from
+			 * BNA dummy desc.
+			 */
+			if (ep->bna_occurred) {
+				VDBG(dev, "Recover desc. from BNA dummy\n");
+				memcpy(req->td_data, ep->bna_dummy_req->td_data,
+						sizeof(struct udc_data_dma));
+				ep->bna_occurred = 0;
+				udc_init_bna_dummy(ep->req);
+			}
+			td = udc_get_last_dma_desc(req);
+			dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+		}
+		if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+			/* buffer fill mode - rx bytes */
+			if (!use_dma_ppb) {
+				/* received number bytes */
+				count = AMD_GETBITS(req->td_data->status,
+						UDC_DMA_OUT_STS_RXBYTES);
+				VDBG(dev, "rx bytes=%u\n", count);
+			/* packet per buffer mode - rx bytes */
+			} else {
+				VDBG(dev, "req->td_data=%p\n", req->td_data);
+				VDBG(dev, "last desc = %p\n", td);
+				/* received number bytes */
+				if (use_dma_ppb_du) {
+					/* every desc. counts bytes */
+					count = udc_get_ppbdu_rxbytes(req);
+				} else {
+					/* last desc. counts bytes */
+					count = AMD_GETBITS(td->status,
+						UDC_DMA_OUT_STS_RXBYTES);
+					if (!count && req->req.length
+						== UDC_DMA_MAXPACKET) {
+						/*
+						 * on 64k packets the RXBYTES
+						 * field is zero
+						 */
+						count = UDC_DMA_MAXPACKET;
+					}
+				}
+				VDBG(dev, "last desc rx bytes=%u\n", count);
+			}
+
+			tmp = req->req.length - req->req.actual;
+			if (count > tmp) {
+				if ((tmp % ep->ep.maxpacket) != 0) {
+					DBG(dev, "%s: rx %db, space=%db\n",
+						ep->ep.name, count, tmp);
+					req->req.status = -EOVERFLOW;
+				}
+				count = tmp;
+			}
+			req->req.actual += count;
+			req->dma_going = 0;
+			/* complete request */
+			complete_req(ep, req, 0);
+
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+					struct udc_request,
+					queue);
+				/*
+				 * DMA may be already started by udc_queue()
+				 * called by gadget drivers completion
+				 * routine. This happens when queue
+				 * holds one request only.
+				 */
+				if (req->dma_going == 0) {
+					/* next dma */
+					if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+						goto finished;
+					/* write desc pointer */
+					writel(req->td_phys,
+						&ep->regs->desptr);
+					req->dma_going = 1;
+					/* enable DMA */
+					udc_set_rde(dev);
+				}
+			} else {
+				/*
+				 * implant BNA dummy descriptor to allow
+				 * RXFIFO opening by RDE
+				 */
+				if (ep->bna_dummy_req) {
+					/* write desc pointer */
+					writel(ep->bna_dummy_req->td_phys,
+						&ep->regs->desptr);
+					ep->bna_occurred = 0;
+				}
+
+				/*
+				 * schedule timer for setting RDE if queue
+				 * remains empty to allow ep0 packets pass
+				 * through
+				 */
+				if (set_rde != 0
+						&& !timer_pending(&udc_timer)) {
+					udc_timer.expires =
+						jiffies
+						+ HZ*UDC_RDE_TIMER_SECONDS;
+					set_rde = 1;
+					if (!stop_timer)
+						add_timer(&udc_timer);
+				}
+				if (ep->num != UDC_EP0OUT_IX)
+					dev->data_ep_queued = 0;
+			}
+
+		} else {
+			/*
+			* RX DMA must be reenabled for each desc in PPBDU mode
+			* and must be enabled for PPBNDU mode in case of BNA
+			*/
+			udc_set_rde(dev);
+		}
+
+	} else if (ep->cancel_transfer) {
+		ret_val = IRQ_HANDLED;
+		ep->cancel_transfer = 0;
+	}
+
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+			udc_process_cnak_queue(dev);
+	}
+
+	/* clear OUT bits in ep status */
+	writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+	return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	u32 epsts;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	struct udc_data_dma *td;
+	unsigned len;
+
+	ep = &dev->ep[ep_ix];
+
+	epsts = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA ? */
+		if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+			dev_err(&dev->pdev->dev,
+				"BNA ep%din occurred - DESPTR = %08lx\n",
+				ep->num,
+				(unsigned long) readl(&ep->regs->desptr));
+
+			/* clear BNA */
+			writel(epsts, &ep->regs->sts);
+			ret_val = IRQ_HANDLED;
+			goto finished;
+		}
+	}
+	/* HE event ? */
+	if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+		dev_err(&dev->pdev->dev,
+			"HE ep%dn occurred - DESPTR = %08lx\n",
+			ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+		/* clear HE */
+		writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	/* DMA completion */
+	if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG(dev, "TDC set- completion\n");
+		ret_val = IRQ_HANDLED;
+		if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+			req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			/*
+			 * length bytes transferred
+			 * check dma done of last desc. in PPBDU mode
+			 */
+			if (use_dma_ppb_du) {
+				td = udc_get_last_dma_desc(req);
+				if (td)
+					req->req.actual = req->req.length;
+			} else {
+				/* assume all bytes transferred */
+				req->req.actual = req->req.length;
+			}
+
+			if (req->req.actual == req->req.length) {
+				/* complete req */
+				complete_req(ep, req, 0);
+				req->dma_going = 0;
+				/* further request available ? */
+				if (list_empty(&ep->queue)) {
+					/* disable interrupt */
+					tmp = readl(&dev->regs->ep_irqmsk);
+					tmp |= AMD_BIT(ep->num);
+					writel(tmp, &dev->regs->ep_irqmsk);
+				}
+			}
+		}
+		ep->cancel_transfer = 0;
+
+	}
+	/*
+	 * status reg has IN bit set and TDC not set (if TDC was handled,
+	 * IN must not be handled (UDC defect) ?
+	 */
+	if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+			&& !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+		ret_val = IRQ_HANDLED;
+		if (!list_empty(&ep->queue)) {
+			/* next request */
+			req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			/* FIFO mode */
+			if (!use_dma) {
+				/* write fifo */
+				udc_txfifo_write(ep, &req->req);
+				len = req->req.length - req->req.actual;
+				if (len > ep->ep.maxpacket)
+					len = ep->ep.maxpacket;
+				req->req.actual += len;
+				if (req->req.actual == req->req.length
+					|| (len != ep->ep.maxpacket)) {
+					/* complete req */
+					complete_req(ep, req, 0);
+				}
+			/* DMA */
+			} else if (req && !req->dma_going) {
+				VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+					req, req->td_data);
+				if (req->td_data) {
+
+					req->dma_going = 1;
+
+					/*
+					 * unset L bit of first desc.
+					 * for chain
+					 */
+					if (use_dma_ppb && req->req.length >
+							ep->ep.maxpacket) {
+						req->td_data->status &=
+							AMD_CLEAR_BIT(
+							UDC_DMA_IN_STS_L);
+					}
+
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+
+					/* set HOST READY */
+					req->td_data->status =
+						AMD_ADDBITS(
+						req->td_data->status,
+						UDC_DMA_IN_STS_BS_HOST_READY,
+						UDC_DMA_IN_STS_BS);
+
+					/* set poll demand bit */
+					tmp = readl(&ep->regs->ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp, &ep->regs->ctl);
+				}
+			}
+
+		} else if (!use_dma && ep->in) {
+			/* disable interrupt */
+			tmp = readl(
+				&dev->regs->ep_irqmsk);
+			tmp |= AMD_BIT(ep->num);
+			writel(tmp,
+				&dev->regs->ep_irqmsk);
+		}
+	}
+	/* clear status bits */
+	writel(epsts, &ep->regs->sts);
+
+finished:
+	return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	int setup_supported;
+	u32 count;
+	int set = 0;
+	struct udc_ep	*ep;
+	struct udc_ep	*ep_tmp;
+
+	ep = &dev->ep[UDC_EP0OUT_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+	/* check BNA and clear if set */
+	if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+		VDBG(dev, "ep0: BNA set\n");
+		writel(AMD_BIT(UDC_EPSTS_BNA),
+			&dev->ep[UDC_EP0OUT_IX].regs->sts);
+		ep->bna_occurred = 1;
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	/* type of data: SETUP or DATA 0 bytes */
+	tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+	VDBG(dev, "data_typ = %x\n", tmp);
+
+	/* setup data */
+	if (tmp == UDC_EPSTS_OUT_SETUP) {
+		ret_val = IRQ_HANDLED;
+
+		ep->dev->stall_ep0in = 0;
+		dev->waiting_zlp_ack_ep0in = 0;
+
+		/* set NAK for EP0_IN */
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+		writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		dev->ep[UDC_EP0IN_IX].naking = 1;
+		/* get setup data */
+		if (use_dma) {
+
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_CLEAR,
+				&dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+			setup_data.data[0] =
+				dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+			setup_data.data[1] =
+				dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+			/* set HOST READY */
+			dev->ep[UDC_EP0OUT_IX].td_stp->status =
+					UDC_DMA_STP_STS_BS_HOST_READY;
+		} else {
+			/* read fifo */
+			udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+		}
+
+		/* determine direction of control data */
+		if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+			/* enable RDE */
+			udc_ep0_set_rde(dev);
+			set = 0;
+		} else {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+			/*
+			 * implant BNA dummy descriptor to allow RXFIFO opening
+			 * by RDE
+			 */
+			if (ep->bna_dummy_req) {
+				/* write desc pointer */
+				writel(ep->bna_dummy_req->td_phys,
+					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+				ep->bna_occurred = 0;
+			}
+
+			set = 1;
+			dev->ep[UDC_EP0OUT_IX].naking = 1;
+			/*
+			 * setup timer for enabling RDE (to not enable
+			 * RXFIFO DMA for data to early)
+			 */
+			set_rde = 1;
+			if (!timer_pending(&udc_timer)) {
+				udc_timer.expires = jiffies +
+							HZ/UDC_RDE_TIMER_DIV;
+				if (!stop_timer)
+					add_timer(&udc_timer);
+			}
+		}
+
+		/*
+		 * mass storage reset must be processed here because
+		 * next packet may be a CLEAR_FEATURE HALT which would not
+		 * clear the stall bit when no STALL handshake was received
+		 * before (autostall can cause this)
+		 */
+		if (setup_data.data[0] == UDC_MSCRES_DWORD0
+				&& setup_data.data[1] == UDC_MSCRES_DWORD1) {
+			DBG(dev, "MSC Reset\n");
+			/*
+			 * clear stall bits
+			 * only one IN and OUT endpoints are handled
+			 */
+			ep_tmp = &udc->ep[UDC_EPIN_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+			ep_tmp = &udc->ep[UDC_EPOUT_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+		}
+
+		/* call gadget with setup data received */
+		spin_unlock(&dev->lock);
+		setup_supported = dev->driver->setup(&dev->gadget,
+						&setup_data.request);
+		spin_lock(&dev->lock);
+
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		/* ep0 in returns data (not zlp) on IN phase */
+		if (setup_supported >= 0 && setup_supported <
+				UDC_EP0IN_MAXPACKET) {
+			/* clear NAK by writing CNAK in EP0_IN */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+			dev->ep[UDC_EP0IN_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+		/* if unsupported request then stall */
+		} else if (setup_supported < 0) {
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		} else
+			dev->waiting_zlp_ack_ep0in = 1;
+
+
+		/* clear NAK by writing CNAK in EP0_OUT */
+		if (!set) {
+			tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			dev->ep[UDC_EP0OUT_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+		}
+
+		if (!use_dma) {
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_CLEAR,
+				&dev->ep[UDC_EP0OUT_IX].regs->sts);
+		}
+
+	/* data packet 0 bytes */
+	} else if (tmp == UDC_EPSTS_OUT_DATA) {
+		/* clear OUT bits in ep status */
+		writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+		/* get setup data: only 0 packet */
+		if (use_dma) {
+			/* no req if 0 packet, just reactivate */
+			if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+				VDBG(dev, "ZLP\n");
+
+				/* set HOST READY */
+				dev->ep[UDC_EP0OUT_IX].td->status =
+					AMD_ADDBITS(
+					dev->ep[UDC_EP0OUT_IX].td->status,
+					UDC_DMA_OUT_STS_BS_HOST_READY,
+					UDC_DMA_OUT_STS_BS);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+				ret_val = IRQ_HANDLED;
+
+			} else {
+				/* control write */
+				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+				/* re-program desc. pointer for possible ZLPs */
+				writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+			}
+		} else {
+
+			/* received number bytes */
+			count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+			count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+			/* out data for fifo mode not working */
+			count = 0;
+
+			/* 0 packet or real data ? */
+			if (count != 0) {
+				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+			} else {
+				/* dummy read confirm */
+				readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+				ret_val = IRQ_HANDLED;
+			}
+		}
+	}
+
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+			udc_process_cnak_queue(dev);
+	}
+
+finished:
+	return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	unsigned len;
+
+	ep = &dev->ep[UDC_EP0IN_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+	/* DMA completion */
+	if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG(dev, "isr: TDC clear\n");
+		ret_val = IRQ_HANDLED;
+
+		/* clear TDC bit */
+		writel(AMD_BIT(UDC_EPSTS_TDC),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+
+	/* status reg has IN bit set ? */
+	} else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+		ret_val = IRQ_HANDLED;
+
+		if (ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+		if (dev->stall_ep0in) {
+			DBG(dev, "stall ep0in\n");
+			/* halt ep0in */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		} else {
+			if (!list_empty(&ep->queue)) {
+				/* next request */
+				req = list_entry(ep->queue.next,
+						struct udc_request, queue);
+
+				if (ep->dma) {
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+					/* set HOST READY */
+					req->td_data->status =
+						AMD_ADDBITS(
+						req->td_data->status,
+						UDC_DMA_STP_STS_BS_HOST_READY,
+						UDC_DMA_STP_STS_BS);
+
+					/* set poll demand bit */
+					tmp =
+					readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp,
+					&dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+					/* all bytes will be transferred */
+					req->req.actual = req->req.length;
+
+					/* complete req */
+					complete_req(ep, req, 0);
+
+				} else {
+					/* write fifo */
+					udc_txfifo_write(ep, &req->req);
+
+					/* lengh bytes transferred */
+					len = req->req.length - req->req.actual;
+					if (len > ep->ep.maxpacket)
+						len = ep->ep.maxpacket;
+
+					req->req.actual += len;
+					if (req->req.actual == req->req.length
+						|| (len != ep->ep.maxpacket)) {
+						/* complete req */
+						complete_req(ep, req, 0);
+					}
+				}
+
+			}
+		}
+		ep->halted = 0;
+		dev->stall_ep0in = 0;
+		if (!ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+	}
+
+	return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	u32 cfg;
+	struct udc_ep *ep;
+	u16 i;
+	u8 udc_csr_epix;
+
+	/* SET_CONFIG irq ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+		ret_val = IRQ_HANDLED;
+
+		/* read config value */
+		tmp = readl(&dev->regs->sts);
+		cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+		DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+		dev->cur_config = cfg;
+		dev->set_cfg_not_acked = 1;
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+		setup_data.request.wValue = cpu_to_le16(dev->cur_config);
+
+		/* programm the NE registers */
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			/* OUT ep */
+			} else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			tmp = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep cfg */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+						UDC_CSR_NE_CFG);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		}
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* SET_INTERFACE ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+		ret_val = IRQ_HANDLED;
+
+		dev->set_cfg_not_acked = 1;
+		/* read interface and alt setting values */
+		tmp = readl(&dev->regs->sts);
+		dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+		dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+		setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+		setup_data.request.wValue = cpu_to_le16(dev->cur_alt);
+		setup_data.request.wIndex = cpu_to_le16(dev->cur_intf);
+
+		DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+				dev->cur_alt, dev->cur_intf);
+
+		/* programm the NE registers */
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			/* OUT ep */
+			} else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			/* UDC CSR reg */
+			/* set ep values */
+			tmp = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep interface */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+						UDC_CSR_NE_INTF);
+			/* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+			/* ep alt */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+						UDC_CSR_NE_ALT);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		}
+
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* USB reset */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+		DBG(dev, "USB Reset interrupt\n");
+		ret_val = IRQ_HANDLED;
+
+		/* allow soft reset when suspend occurs */
+		soft_reset_occured = 0;
+
+		dev->waiting_zlp_ack_ep0in = 0;
+		dev->set_cfg_not_acked = 0;
+
+		/* mask not needed interrupts */
+		udc_mask_unused_interrupts(dev);
+
+		/* call gadget to resume and reset configs etc. */
+		spin_unlock(&dev->lock);
+		if (dev->sys_suspended && dev->driver->resume) {
+			dev->driver->resume(&dev->gadget);
+			dev->sys_suspended = 0;
+		}
+		usb_gadget_udc_reset(&dev->gadget, dev->driver);
+		spin_lock(&dev->lock);
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+		/* soft reset when rxfifo not empty */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+				&& !soft_reset_after_usbreset_occured) {
+			udc_soft_reset(dev);
+			soft_reset_after_usbreset_occured++;
+		}
+
+		/*
+		 * DMA reset to kill potential old DMA hw hang,
+		 * POLL bit is already reset by ep_init() through
+		 * disconnect()
+		 */
+		DBG(dev, "DMA machine reset\n");
+		tmp = readl(&dev->regs->cfg);
+		writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+		writel(tmp, &dev->regs->cfg);
+
+		/* put into initial config */
+		udc_basic_init(dev);
+
+		/* enable device setup interrupts */
+		udc_enable_dev_setup_interrupts(dev);
+
+		/* enable suspend interrupt */
+		tmp = readl(&dev->regs->irqmsk);
+		tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+		writel(tmp, &dev->regs->irqmsk);
+
+	} /* USB suspend */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+		DBG(dev, "USB Suspend interrupt\n");
+		ret_val = IRQ_HANDLED;
+		if (dev->driver->suspend) {
+			spin_unlock(&dev->lock);
+			dev->sys_suspended = 1;
+			dev->driver->suspend(&dev->gadget);
+			spin_lock(&dev->lock);
+		}
+	} /* new speed ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+		DBG(dev, "ENUM interrupt\n");
+		ret_val = IRQ_HANDLED;
+		soft_reset_after_usbreset_occured = 0;
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+		/* link up all endpoints */
+		udc_setup_endpoints(dev);
+		dev_info(&dev->pdev->dev, "Connect: %s\n",
+			 usb_speed_string(dev->gadget.speed));
+
+		/* init ep 0 */
+		activate_control_endpoints(dev);
+
+		/* enable ep0 interrupts */
+		udc_enable_ep0_interrupts(dev);
+	}
+	/* session valid change interrupt */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+		DBG(dev, "USB SVC interrupt\n");
+		ret_val = IRQ_HANDLED;
+
+		/* check that session is not valid to detect disconnect */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+			/* disable suspend interrupt */
+			tmp = readl(&dev->regs->irqmsk);
+			tmp |= AMD_BIT(UDC_DEVINT_US);
+			writel(tmp, &dev->regs->irqmsk);
+			DBG(dev, "USB Disconnect (session valid low)\n");
+			/* cleanup on disconnect */
+			usb_disconnect(udc);
+		}
+
+	}
+
+	return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+irqreturn_t udc_irq(int irq, void *pdev)
+{
+	struct udc *dev = pdev;
+	u32 reg;
+	u16 i;
+	u32 ep_irq;
+	irqreturn_t ret_val = IRQ_NONE;
+
+	spin_lock(&dev->lock);
+
+	/* check for ep irq */
+	reg = readl(&dev->regs->ep_irqsts);
+	if (reg) {
+		if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+			ret_val |= udc_control_out_isr(dev);
+		if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+			ret_val |= udc_control_in_isr(dev);
+
+		/*
+		 * data endpoint
+		 * iterate ep's
+		 */
+		for (i = 1; i < UDC_EP_NUM; i++) {
+			ep_irq = 1 << i;
+			if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+				continue;
+
+			/* clear irq status */
+			writel(ep_irq, &dev->regs->ep_irqsts);
+
+			/* irq for out ep ? */
+			if (i > UDC_EPIN_NUM)
+				ret_val |= udc_data_out_isr(dev, i);
+			else
+				ret_val |= udc_data_in_isr(dev, i);
+		}
+
+	}
+
+
+	/* check for dev irq */
+	reg = readl(&dev->regs->irqsts);
+	if (reg) {
+		/* clear irq */
+		writel(reg, &dev->regs->irqsts);
+		ret_val |= udc_dev_isr(dev, reg);
+	}
+
+
+	spin_unlock(&dev->lock);
+	return ret_val;
+}
+EXPORT_SYMBOL_GPL(udc_irq);
+
+/* Tears down device */
+void gadget_release(struct device *pdev)
+{
+	struct amd5536udc *dev = dev_get_drvdata(pdev);
+	kfree(dev);
+}
+EXPORT_SYMBOL_GPL(gadget_release);
+
+/* Cleanup on device remove */
+void udc_remove(struct udc *dev)
+{
+	/* remove timer */
+	stop_timer++;
+	if (timer_pending(&udc_timer))
+		wait_for_completion(&on_exit);
+	if (udc_timer.data)
+		del_timer_sync(&udc_timer);
+	/* remove pollstall timer */
+	stop_pollstall_timer++;
+	if (timer_pending(&udc_pollstall_timer))
+		wait_for_completion(&on_pollstall_exit);
+	if (udc_pollstall_timer.data)
+		del_timer_sync(&udc_pollstall_timer);
+	udc = NULL;
+}
+EXPORT_SYMBOL_GPL(udc_remove);
+
+/* free all the dma pools */
+void free_dma_pools(struct udc *dev)
+{
+	dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td,
+		      dev->ep[UDC_EP0OUT_IX].td_phys);
+	dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
+		      dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+	dma_pool_destroy(dev->stp_requests);
+	dma_pool_destroy(dev->data_requests);
+}
+EXPORT_SYMBOL_GPL(free_dma_pools);
+
+/* create dma pools on init */
+int init_dma_pools(struct udc *dev)
+{
+	struct udc_stp_dma	*td_stp;
+	struct udc_data_dma	*td_data;
+	int retval;
+
+	/* consistent DMA mode setting ? */
+	if (use_dma_ppb) {
+		use_dma_bufferfill_mode = 0;
+	} else {
+		use_dma_ppb_du = 0;
+		use_dma_bufferfill_mode = 1;
+	}
+
+	/* DMA setup */
+	dev->data_requests = dma_pool_create("data_requests", NULL,
+		sizeof(struct udc_data_dma), 0, 0);
+	if (!dev->data_requests) {
+		DBG(dev, "can't get request data pool\n");
+		return -ENOMEM;
+	}
+
+	/* EP0 in dma regs = dev control regs */
+	dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+	/* dma desc for setup data */
+	dev->stp_requests = dma_pool_create("setup requests", NULL,
+		sizeof(struct udc_stp_dma), 0, 0);
+	if (!dev->stp_requests) {
+		DBG(dev, "can't get stp request pool\n");
+		retval = -ENOMEM;
+		goto err_create_dma_pool;
+	}
+	/* setup */
+	td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+	if (!td_stp) {
+		retval = -ENOMEM;
+		goto err_alloc_dma;
+	}
+	dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+	/* data: 0 packets !? */
+	td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IX].td_phys);
+	if (!td_data) {
+		retval = -ENOMEM;
+		goto err_alloc_phys;
+	}
+	dev->ep[UDC_EP0OUT_IX].td = td_data;
+	return 0;
+
+err_alloc_phys:
+	dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
+		      dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+err_alloc_dma:
+	dma_pool_destroy(dev->stp_requests);
+	dev->stp_requests = NULL;
+err_create_dma_pool:
+	dma_pool_destroy(dev->data_requests);
+	dev->data_requests = NULL;
+	return retval;
+}
+EXPORT_SYMBOL_GPL(init_dma_pools);
+
+/* general probe */
+int udc_probe(struct udc *dev)
+{
+	char		tmp[128];
+	u32		reg;
+	int		retval;
+
+	/* mark timer as not initialized */
+	udc_timer.data = 0;
+	udc_pollstall_timer.data = 0;
+
+	/* device struct setup */
+	dev->gadget.ops = &udc_ops;
+
+	dev_set_name(&dev->gadget.dev, "gadget");
+	dev->gadget.name = name;
+	dev->gadget.max_speed = USB_SPEED_HIGH;
+
+	/* init registers, interrupts, ... */
+	startup_registers(dev);
+
+	dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+	snprintf(tmp, sizeof(tmp), "%d", dev->irq);
+	dev_info(&dev->pdev->dev,
+		 "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+		 tmp, dev->phys_addr, dev->chiprev,
+		 (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+	strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+	if (dev->chiprev == UDC_HSA0_REV) {
+		dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+		retval = -ENODEV;
+		goto finished;
+	}
+	dev_info(&dev->pdev->dev,
+		 "driver version: %s(for Geode5536 B1)\n", tmp);
+	udc = dev;
+
+	retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
+					    gadget_release);
+	if (retval)
+		goto finished;
+
+	/* timer init */
+	init_timer(&udc_timer);
+	udc_timer.function = udc_timer_function;
+	udc_timer.data = 1;
+	/* timer pollstall init */
+	init_timer(&udc_pollstall_timer);
+	udc_pollstall_timer.function = udc_pollstall_timer_function;
+	udc_pollstall_timer.data = 1;
+
+	/* set SD */
+	reg = readl(&dev->regs->ctl);
+	reg |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(reg, &dev->regs->ctl);
+
+	/* print dev register info */
+	print_regs(dev);
+
+	return 0;
+
+finished:
+	return retval;
+}
+EXPORT_SYMBOL_GPL(udc_probe);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
-- 
2.1.0

^ permalink raw reply related

* [RESEND PATCH v3 0/7] Platform driver support for 'amd5536udc' driver
From: Raviteja Garimella @ 2017-03-31 13:09 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Greg Kroah-Hartman, Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb

Resending PATCH v3 after rebasing with testing/next branch in 
Felipe Balbi's git tree. Resolved few merge conflicts. 
Tested applying all patches. Patch 1/7 can be ignored since it's
already applied.

Changes in PATCH v3:
===================
1. Updated bindings documentation and platform driver to add
   "brcm,iproc-udc" compatibility string.

2. Added a patch to replace references of struct pci_pool with
   struct dma_pool so that it is compatibile with non-pci drivers.

Changes in PATCH v2:
===================
1. Updated bindings documentation:
   -- compatibility string for each supported SoC
   -- removed extcon node
   -- rename the file name to just iproc-udc.txt

2. Modified comptability strings in platform driver file
   to reflect the change made in 1.

3 Kconfig
   -- Resolved warnings shown by kbuild-test-robot  

The changes are being submitted as PATCH this time. Below are the
details of main changes with respect to previous RFC versions.

Changes in PATCH v1:
===================
Patch 1/6 now splits the driver into amd5536udc_pci_.c (which
contains only the PCI device registration part), and amd5536udc.c
will still be driver that does the rest of UDC driver functionality.

Patch 2/6 renames amd5536udc.c to snps_udc_core.c.

The DT compatibilty string is changed to "brcm,iproc-snps-udc"
as per review comments for RFCv2. The driver and bindings
documentation is modified to reflect this.

This is RFC for the changes made as per the review comments made for
the previous version. I would like to know  if this approach (the way
the driver is split and the naming and all)looks good to be submitted.


Changes in RFC v2:
=================
1. Split the driver into platform/pci specific drivers with a core driver
   file that handles the common driver routines that are exported.

2. Split the driver into number of patches as suggested in previous
   review comments.

3. Added the devicetree bindings documentation for Synopsys platform
   driver.

Introduction (RFC v1):
=====================
This patch adds platform device support to the existing 'amd5536udc'
driver.

The UDC is based on Synopsys Designware core USB (2.0) Device controller
IP.

The driver so far supports UDCs that are a part of AMD southbridge
and is connected through PCI bus.

The same driver can be used with UDCs that are integrated into SoCs
like Broadcom's Northstar2/Cygnus platforms by adding platform device
suooprt.

This patch contains all the changes that were required to get the driver
functional on Broadcom's Northstar2 platform. 

This is a request for comments from maintainers/others regarding approach
on whether to have 2 different drivers (one each for AMD and Broadcom)
with a common library (3 files in total), or have a single driver like
it's done in this patch and have the driver filename changed to some
common name based on ther underlying IP, like snps_udc.c.

Below are the main changes done:

1. Added OF based platform device registration -- so that the driver gets
   probed based on the device tree entry. Like wise, remove routine and
   platform PM ops are supported.

2. Modified debug prints to be compatible with both pci and platform
   devices.

3. Added members to 'struct udc' in header file for extcon and phy support.
   This is required if the UDC is connected to a Dual Role Device Phy
   where the Phy can be configured to be in Device mode or Host mode based
   on the type of external cable that is connected to the port.
 
4. Added checks in udc connect/disconnect routines so as to return if the
   routine is already called.

5. Modified the arguments passed to dma_pool_create routine -- which
   expects struct device, whereas NULL is passed in the existing version.
 
6. Kconfig changes are done so that the driver now depends on either of
   CONFIG_OF or CONFIG_PCI. More description about the Synopsys IP is
   provided.

Repo: https://github.com/Broadcom/arm64-linux.git
Branch: snps_udc_v3

Raviteja Garimella (7):
  usb: gadget: udc: amd5536: split core and PCI layer
  UDC: Rename amd5536udc driver file based on IP
  UDC: make debug prints compatible with both pci and platform devices
  UDC: Provide correct arguments for 'dma_pool_create'
  UDC: Use struct dma_pool instead of pci_pool
  DT bindings documentation for Broadcom IPROC USB Device controller.
  UDC: Add Synopsys UDC Platform driver

 .../devicetree/bindings/usb/iproc-udc.txt          |   21 +
 drivers/usb/gadget/udc/Kconfig                     |   32 +
 drivers/usb/gadget/udc/Makefile                    |    4 +-
 drivers/usb/gadget/udc/amd5536udc.c                | 3409 --------------------
 drivers/usb/gadget/udc/amd5536udc.h                |   54 +-
 drivers/usb/gadget/udc/amd5536udc_pci.c            |  218 ++
 drivers/usb/gadget/udc/snps_udc_core.c             | 3235 +++++++++++++++++++
 drivers/usb/gadget/udc/snps_udc_plat.c             |  344 ++
 8 files changed, 3906 insertions(+), 3411 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/iproc-udc.txt
 delete mode 100644 drivers/usb/gadget/udc/amd5536udc.c
 create mode 100644 drivers/usb/gadget/udc/amd5536udc_pci.c
 create mode 100644 drivers/usb/gadget/udc/snps_udc_core.c
 create mode 100644 drivers/usb/gadget/udc/snps_udc_plat.c

-- 
2.1.0

^ permalink raw reply

* [PATCH v2 8/8] dt-bindings: clock: gxbb: expose spdif master clock
From: Jerome Brunet @ 2017-03-31 13:04 UTC (permalink / raw)
  To: Neil Armstrong, Michael Turquette, Stephen Boyd, Kevin Hilman,
	Carlo Caione
  Cc: Jerome Brunet, linux-clk, linux-amlogic, linux-kernel, devicetree
In-Reply-To: <20170331130411.4781-1-jbrunet@baylibre.com>

Expose the spdif master clock and the mux to select the appropriate spdif
clock parent depending on the data source.

Acked-by: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/gxbb.h              | 4 ++--
 include/dt-bindings/clock/gxbb-clkc.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 742bc3b42565..17c6aef033ff 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -280,10 +280,10 @@
 /* CLKID_CTS_AMCLK */
 #define CLKID_CTS_AMCLK_SEL	  108
 #define CLKID_CTS_AMCLK_DIV	  109
-#define CLKID_CTS_MCLK_I958	  110
+/* CLKID_CTS_MCLK_I958 */
 #define CLKID_CTS_MCLK_I958_SEL	  111
 #define CLKID_CTS_MCLK_I958_DIV	  112
-#define CLKID_CTS_I958		  113
+/* CLKID_CTS_I958 */
 
 #define NR_CLKS			  114
 
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index 0d231bef92e0..4516bc4253b5 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -44,5 +44,7 @@
 #define CLKID_MALI_1		105
 #define CLKID_MALI		106
 #define CLKID_CTS_AMCLK		107
+#define CLKID_CTS_MCLK_I958	110
+#define CLKID_CTS_I958		113
 
 #endif /* __GXBB_CLKC_H */
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2 7/8] dt-bindings: clock: gxbb: expose i2s master clock
From: Jerome Brunet @ 2017-03-31 13:04 UTC (permalink / raw)
  To: Neil Armstrong, Michael Turquette, Stephen Boyd, Kevin Hilman,
	Carlo Caione
  Cc: Jerome Brunet, linux-clk, linux-amlogic, linux-kernel, devicetree
In-Reply-To: <20170331130411.4781-1-jbrunet@baylibre.com>

Expose cts_amclk in the device tree bindings

Acked-by: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/gxbb.h              | 2 +-
 include/dt-bindings/clock/gxbb-clkc.h | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 3b0665099a1e..742bc3b42565 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -277,7 +277,7 @@
 #define CLKID_MALI_1_DIV	 104
 /* CLKID_MALI_1	*/
 /* CLKID_MALI	*/
-#define CLKID_CTS_AMCLK		  107
+/* CLKID_CTS_AMCLK */
 #define CLKID_CTS_AMCLK_SEL	  108
 #define CLKID_CTS_AMCLK_DIV	  109
 #define CLKID_CTS_MCLK_I958	  110
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index 1d4614bc8154..0d231bef92e0 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -43,5 +43,6 @@
 #define CLKID_MALI_1_SEL	103
 #define CLKID_MALI_1		105
 #define CLKID_MALI		106
+#define CLKID_CTS_AMCLK		107
 
 #endif /* __GXBB_CLKC_H */
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2 1/8] dt-bindings: clock: gxbb: expose spdif clock gates
From: Jerome Brunet @ 2017-03-31 13:04 UTC (permalink / raw)
  To: Neil Armstrong, Michael Turquette, Stephen Boyd, Kevin Hilman,
	Carlo Caione
  Cc: Jerome Brunet, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170331130411.4781-1-jbrunet-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>

Expose the clock gates required for the spdif output

Acked-by: Michael Turquette <mturquette-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Jerome Brunet <jbrunet-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
 drivers/clk/meson/gxbb.h              | 4 ++--
 include/dt-bindings/clock/gxbb-clkc.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 9d949244b104..0d535f7e7aed 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -209,7 +209,7 @@
 /* CLKID_ETH */
 #define CLKID_DEMUX		  37
 /* CLKID_AIU_GLUE */
-#define CLKID_IEC958		  39
+/* CLKID_IEC958 */
 /* CLKID_I2S_OUT */
 #define CLKID_AMCLK		  41
 #define CLKID_AIFIFO2		  42
@@ -251,7 +251,7 @@
 #define CLKID_GCLK_VENCI_INT	  78
 #define CLKID_DAC_CLK		  79
 /* CLKID_AOCLK_GATE */
-#define CLKID_IEC958_GATE	  81
+/* CLKID_IEC958_GATE */
 #define CLKID_ENC480P		  82
 #define CLKID_RNG1		  83
 #define CLKID_GCLK_VENCI_INT1	  84
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index cce6cb5418f1..1d4614bc8154 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -18,6 +18,7 @@
 #define CLKID_SAR_ADC		23
 #define CLKID_ETH		36
 #define CLKID_AIU_GLUE		38
+#define CLKID_IEC958		39
 #define CLKID_I2S_OUT		40
 #define CLKID_MIXER_IFACE	44
 #define CLKID_AIU		47
@@ -30,6 +31,7 @@
 #define CLKID_SANA		69
 #define CLKID_GCLK_VENCI_INT0	77
 #define CLKID_AOCLK_GATE	80
+#define CLKID_IEC958_GATE	81
 #define CLKID_AO_I2C		93
 #define CLKID_SD_EMMC_A		94
 #define CLKID_SD_EMMC_B		95
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2 0/8] clk: meson: gxbb: more clock controller update for audio support
From: Jerome Brunet @ 2017-03-31 13:04 UTC (permalink / raw)
  To: Neil Armstrong, Michael Turquette, Stephen Boyd, Kevin Hilman,
	Carlo Caione
  Cc: Jerome Brunet, linux-clk, linux-amlogic, linux-kernel, devicetree

The patchset is the 2nd round of update to the meson gxbb clock controller
to add initial audio support. The patchset is based on clk-next.

There is not much out of the ordinary here (adding new clocks and exposing
them) except maybe for 2 patches:
Patch #2: Adds a safety check while registering clocks to protect against
          holes in clk_hw_onecell_data, if it ever happens. Same thing is
	  done for the meson8b clock controller.
Patch #3: Adds a new clock divider driver to implement the necessary
          policy for the i2s master clock (see patch changelog)

This patchset has been test on the gxbb p200 and gxl p230.

Changes since v1 [0]:
 - fix typo and use clamp function in patch #3

[0]: https://lkml.kernel.org/r/20170328144605.25278-1-jbrunet@baylibre.com

Jerome Brunet (8):
  dt-bindings: clock: gxbb: expose spdif clock gates
  clk: meson: gxbb: protect against holes in the onecell_data array
  clk: meson: add audio clock divider support
  clk: meson: gxbb: add cts_amclk
  clk: meson: gxbb: add cts_mclk_i958
  clk: meson: gxbb: add cts_i958 clock
  dt-bindings: clock: gxbb: expose i2s master clock
  dt-bindings: clock: gxbb: expose spdif master clock

 drivers/clk/meson/Makefile            |   2 +-
 drivers/clk/meson/clk-audio-divider.c | 144 ++++++++++++++++++++++++++++++++++
 drivers/clk/meson/clkc.h              |  10 +++
 drivers/clk/meson/gxbb.c              | 144 ++++++++++++++++++++++++++++++++++
 drivers/clk/meson/gxbb.h              |  13 ++-
 include/dt-bindings/clock/gxbb-clkc.h |   5 ++
 6 files changed, 314 insertions(+), 4 deletions(-)
 create mode 100644 drivers/clk/meson/clk-audio-divider.c

-- 
2.9.3

^ permalink raw reply

* Re: [PATCH] arm64: dts: rk3399: add support for firefly-rk3399 board
From: Heiko Stuebner @ 2017-03-31 12:56 UTC (permalink / raw)
  To: Kever Yang
  Cc: linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Jianqun Xu,
	Andreas Färber, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Andy Yan, Rob Herring,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Will Deacon,
	Mark Rutland, Catalin Marinas, Matthias Brugger
In-Reply-To: <1490954348-13889-1-git-send-email-kever.yang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

Hi Kever,

Am Freitag, 31. März 2017, 17:59:07 CEST schrieb Kever Yang:
> Firefly-rk3399 is a bord from T-Firefly, you can find detail about
> it here:
> http://en.t-firefly.com/en/firenow/Firefly_RK3399/
> 
> This patch add basic node for the board and make it able to bring
> up.

This more a first glance, I didn't check every binding, but already found
some dubious ones, so in general, please make sure to only include nodes
with approved bindings.


[...]

>  arch/arm64/boot/dts/rockchip/Makefile           |   1 +
>  arch/arm64/boot/dts/rockchip/rk3399-firefly.dts | 772 ++++++++++++++++++++++++

please provide a binding addition for the board in a separate patch as well.


>  2 files changed, 773 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
> 
> diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
> index 3a86289..dd3d550 100644
> --- a/arch/arm64/boot/dts/rockchip/Makefile
> +++ b/arch/arm64/boot/dts/rockchip/Makefile
> @@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-orion-r68-meta.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-evb.dtb
> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-firefly.dtb

if possible, please rebase on top of my for-next branch, as we also
have the first gru board in there now.

>  
>  always		:= $(dtb-y)
>  subdir-y	:= $(dts-dirs)
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
> new file mode 100644
> index 0000000..686977b
> --- /dev/null
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
> @@ -0,0 +1,772 @@
> +/*
> + * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + *  a) This file is free software; you can redistribute it and/or
> + *     modify it under the terms of the GNU General Public License as
> + *     published by the Free Software Foundation; either version 2 of the
> + *     License, or (at your option) any later version.
> + *
> + *     This file is distributed in the hope that it will be useful,
> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *     GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + *  b) Permission is hereby granted, free of charge, to any person
> + *     obtaining a copy of this software and associated documentation
> + *     files (the "Software"), to deal in the Software without
> + *     restriction, including without limitation the rights to use,
> + *     copy, modify, merge, publish, distribute, sublicense, and/or
> + *     sell copies of the Software, and to permit persons to whom the
> + *     Software is furnished to do so, subject to the following
> + *     conditions:
> + *
> + *     The above copyright notice and this permission notice shall be
> + *     included in all copies or substantial portions of the Software.
> + *
> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + *     OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/dts-v1/;
> +#include <dt-bindings/pwm/pwm.h>
> +#include "rk3399.dtsi"
> +
> +/ {
> +	model = "Rockchip RK3399 Firefly Board (Linux Opensource)";
> +	compatible = "rockchip,rk3399-firefly-linux", "rockchip,rk3399";

Just to make sure, is this really a Rockchip board? I would've expected
to see something like "firefly,firefly-rk3399" here, like on the rk3288-
variant. Not a requirement, just a question to clarify who designed the
board please :-) .


> +
> +	backlight: backlight {
> +		status = "okay";
> +		compatible = "pwm-backlight";
> +		enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
> +		pwms = <&pwm0 0 25000 0>;
> +		brightness-levels = <
> +			  0   1   2   3   4   5   6   7
> +			  8   9  10  11  12  13  14  15
> +			 16  17  18  19  20  21  22  23
> +			 24  25  26  27  28  29  30  31
> +			 32  33  34  35  36  37  38  39
> +			 40  41  42  43  44  45  46  47
> +			 48  49  50  51  52  53  54  55
> +			 56  57  58  59  60  61  62  63
> +			 64  65  66  67  68  69  70  71
> +			 72  73  74  75  76  77  78  79
> +			 80  81  82  83  84  85  86  87
> +			 88  89  90  91  92  93  94  95
> +			 96  97  98  99 100 101 102 103
> +			104 105 106 107 108 109 110 111
> +			112 113 114 115 116 117 118 119
> +			120 121 122 123 124 125 126 127
> +			128 129 130 131 132 133 134 135
> +			136 137 138 139 140 141 142 143
> +			144 145 146 147 148 149 150 151
> +			152 153 154 155 156 157 158 159
> +			160 161 162 163 164 165 166 167
> +			168 169 170 171 172 173 174 175
> +			176 177 178 179 180 181 182 183
> +			184 185 186 187 188 189 190 191
> +			192 193 194 195 196 197 198 199
> +			200 201 202 203 204 205 206 207
> +			208 209 210 211 212 213 214 215
> +			216 217 218 219 220 221 222 223
> +			224 225 226 227 228 229 230 231
> +			232 233 234 235 236 237 238 239
> +			240 241 242 243 244 245 246 247
> +			248 249 250 251 252 253 254 255>;
> +		default-brightness-level = <200>;
> +	};
> +
> +	clkin_gmac: external-gmac-clock {
> +		compatible = "fixed-clock";
> +		clock-frequency = <125000000>;
> +		clock-output-names = "clkin_gmac";
> +		#clock-cells = <0>;
> +	};
> +
> +	rt5640-sound {
> +		compatible = "simple-audio-card";
> +		simple-audio-card,format = "i2s";
> +		simple-audio-card,name = "rockchip,rt5640-codec";
> +		simple-audio-card,mclk-fs = <256>;
> +		simple-audio-card,widgets =
> +			"Microphone", "Mic Jack",
> +			"Headphone", "Headphone Jack";
> +		simple-audio-card,routing =
> +			"Mic Jack", "MICBIAS1",
> +			"IN1P", "Mic Jack",
> +			"Headphone Jack", "HPOL",
> +			"Headphone Jack", "HPOR";
> +		simple-audio-card,cpu {
> +			sound-dai = <&i2s1>;
> +		};
> +		simple-audio-card,codec {
> +			sound-dai = <&rt5640>;
> +		};
> +	};
> +
> +	sdio_pwrseq: sdio-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		clocks = <&rk808 1>;
> +		clock-names = "ext_clock";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&wifi_enable_h>;
> +
> +		/*
> +		 * On the module itself this is one of these (depending
> +		 * on the actual card populated):
> +		 * - SDIO_RESET_L_WL_REG_ON
> +		 * - PDN (power down when low)
> +		 */
> +		reset-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* GPIO0_B2 */

Thanks to Andy's persistence, we have nice constants in the pinctrl-
binding-header now, like RK_PB2 for the above. So you can drop the
comment and use the constant instead for easier reading.
Same for other pins.


> +	};
> +
> +	vcc3v3_pcie: vcc3v3-pcie-regulator {
> +		compatible = "regulator-fixed";
> +		enable-active-high;
> +		regulator-always-on;
> +		regulator-boot-on;
> +		gpio = <&gpio1 17 GPIO_ACTIVE_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pcie_drv>;
> +		regulator-name = "vcc3v3_pcie";
> +	};
> +
> +	vcc3v3_sys: vcc3v3-sys {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc3v3_sys";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +	};
> +
> +	vcc5v0_host: vcc5v0-host-regulator {
> +		compatible = "regulator-fixed";
> +		enable-active-high;
> +		gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&host_vbus_drv>;
> +		regulator-name = "vcc5v0_host";
> +		regulator-always-on;
> +	};
> +
> +	vcc5v0_sys: vcc5v0-sys {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc5v0_sys";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +	};
> +
> +	vcc_phy: vcc-phy-regulator {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc_phy";
> +		regulator-always-on;
> +		regulator-boot-on;
> +	};
> +
> +	vdd_log: vdd-log {
> +		compatible = "pwm-regulator";
> +		pwms = <&pwm2 0 25000 1>;
> +		regulator-name = "vdd_log";
> +		regulator-min-microvolt = <800000>;
> +		regulator-max-microvolt = <1400000>;
> +		regulator-always-on;
> +		regulator-boot-on;
> +
> +		/* for rockchip boot on */
> +		rockchip,pwm_id= <2>;
> +		rockchip,pwm_voltage = <1000000>;
> +	};
> +
> +	vccadc_ref: vccadc-ref {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc1v8_sys";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-min-microvolt = <1800000>;
> +		regulator-max-microvolt = <1800000>;
> +	};
> +
> +	wireless-wlan {
> +		compatible = "wlan-platdata";
> +		rockchip,grf = <&grf>;
> +		wifi_chip_type = "ap6354";
> +		sdio_vref = <1800>;
> +		WIFI,host_wake_irq = <&gpio0 3 GPIO_ACTIVE_HIGH>; /* GPIO0_a3 */
> +		status = "okay";

that is not a valid binding, am I right? ;-)
So should be dropped.

> +	};
> +
> +	wireless-bluetooth {
> +		compatible = "bluetooth-platdata";
> +		//wifi-bt-power-toggle;
> +		uart_rts_gpios = <&gpio2 19 GPIO_ACTIVE_LOW>; /* GPIO2_C3 */
> +		pinctrl-names = "default", "rts_gpio";
> +		pinctrl-0 = <&uart0_rts>;
> +		pinctrl-1 = <&uart0_gpios>;
> +		//BT,power_gpio  = <&gpio3 19 GPIO_ACTIVE_HIGH>; /* GPIOx_xx */
> +		BT,reset_gpio    = <&gpio0 9 GPIO_ACTIVE_HIGH>; /* GPIO0_B1 */
> +		BT,wake_gpio     = <&gpio2 26 GPIO_ACTIVE_HIGH>; /* GPIO2_D2 */
> +		BT,wake_host_irq = <&gpio0 4 GPIO_ACTIVE_HIGH>; /* GPIO0_A4 */
> +		status = "okay";
> +	};

same here

> +};
> +
> +&cpu_l0 {
> +	cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&cpu_l1 {
> +	cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&cpu_l2 {
> +	cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&cpu_l3 {
> +	cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&cpu_b0 {
> +	cpu-supply = <&vdd_cpu_b>;
> +};
> +
> +&cpu_b1 {
> +	cpu-supply = <&vdd_cpu_b>;
> +};
> +
> +&emmc_phy {
> +	status = "okay";
> +};
> +
> +&gmac {
> +	assigned-clocks = <&cru SCLK_RMII_SRC>;
> +	assigned-clock-parents = <&clkin_gmac>;
> +	clock_in_out = "input";
> +	phy-supply = <&vcc_phy>;
> +	phy-mode = "rgmii";
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&rgmii_pins>;
> +	snps,reset-gpio = <&gpio3 15 GPIO_ACTIVE_LOW>;
> +	snps,reset-active-low;
> +	snps,reset-delays-us = <0 10000 50000>;
> +	tx_delay = <0x28>;
> +	rx_delay = <0x11>;
> +	status = "okay";
> +};
> +
> +&i2c0 {
> +	status = "okay";
> +	i2c-scl-rising-time-ns = <168>;
> +	i2c-scl-falling-time-ns = <4>;
> +	clock-frequency = <400000>;
> +
> +	vdd_cpu_b: syr827@40 {
> +		compatible = "silergy,syr827";
> +		reg = <0x40>;
> +		vin-supply = <&vcc5v0_sys>;
> +		regulator-compatible = "fan53555-reg";
> +		regulator-name = "vdd_cpu_b";
> +		regulator-min-microvolt = <712500>;
> +		regulator-max-microvolt = <1500000>;
> +		regulator-ramp-delay = <1000>;
> +		vsel-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
> +		fcs,suspend-voltage-selector = <0>;
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-initial-state = <3>;
> +			regulator-state-mem {
> +			regulator-off-in-suspend;
> +		};
> +	};
> +
> +	vdd_gpu: syr828@41 {
> +		compatible = "silergy,syr828";
> +		reg = <0x41>;
> +		vin-supply = <&vcc5v0_sys>;
> +		regulator-compatible = "fan53555-reg";
> +		regulator-name = "vdd_gpu";
> +		regulator-min-microvolt = <712500>;
> +		regulator-max-microvolt = <1500000>;
> +		regulator-ramp-delay = <1000>;
> +		fcs,suspend-voltage-selector = <1>;
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-initial-state = <3>;
> +			regulator-state-mem {
> +			regulator-off-in-suspend;
> +		};
> +	};
> +
> +	rk808: pmic@1b {
> +		compatible = "rockchip,rk808";
> +		reg = <0x1b>;
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pmic_int_l>;
> +		rockchip,system-power-controller;
> +		wakeup-source;
> +		#clock-cells = <1>;
> +		clock-output-names = "xin32k", "rk808-clkout2";
> +
> +		vcc1-supply = <&vcc3v3_sys>;
> +		vcc2-supply = <&vcc3v3_sys>;
> +		vcc3-supply = <&vcc3v3_sys>;
> +		vcc4-supply = <&vcc3v3_sys>;
> +		vcc6-supply = <&vcc3v3_sys>;
> +		vcc7-supply = <&vcc3v3_sys>;
> +		vcc8-supply = <&vcc3v3_sys>;
> +		vcc9-supply = <&vcc3v3_sys>;
> +		vcc10-supply = <&vcc3v3_sys>;
> +		vcc11-supply = <&vcc3v3_sys>;
> +		vcc12-supply = <&vcc3v3_sys>;
> +		vddio-supply = <&vcc1v8_pmu>;
> +
> +		regulators {
> +			vdd_center: DCDC_REG1 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <750000>;
> +				regulator-max-microvolt = <1350000>;
> +				regulator-ramp-delay = <6001>;
> +				regulator-name = "vdd_center";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			vdd_cpu_l: DCDC_REG2 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <750000>;
> +				regulator-max-microvolt = <1350000>;
> +				regulator-ramp-delay = <6001>;
> +				regulator-name = "vdd_cpu_l";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			vcc_ddr: DCDC_REG3 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-name = "vcc_ddr";
> +				regulator-state-mem {
> +					regulator-on-in-suspend;
> +				};
> +			};
> +
> +			vcc_1v8: DCDC_REG4 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-name = "vcc_1v8";
> +				regulator-state-mem {
> +					regulator-on-in-suspend;
> +					regulator-suspend-microvolt = <1800000>;
> +				};
> +			};
> +
> +			vcc1v8_dvp: LDO_REG1 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-name = "vcc1v8_dvp";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			vcc3v0_tp: LDO_REG2 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <3000000>;
> +				regulator-max-microvolt = <3000000>;
> +				regulator-name = "vcc3v0_tp";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			vcc1v8_pmu: LDO_REG3 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-name = "vcc1v8_pmu";
> +				regulator-state-mem {
> +					regulator-on-in-suspend;
> +					regulator-suspend-microvolt = <1800000>;
> +				};
> +			};
> +
> +			vcc_sd: LDO_REG4 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <3300000>;
> +				regulator-name = "vcc_sd";
> +				regulator-state-mem {
> +					regulator-on-in-suspend;
> +					regulator-suspend-microvolt = <3300000>;
> +				};
> +			};
> +
> +			vcca3v0_codec: LDO_REG5 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <3000000>;
> +				regulator-max-microvolt = <3000000>;
> +				regulator-name = "vcca3v0_codec";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			vcc_1v5: LDO_REG6 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <1500000>;
> +				regulator-max-microvolt = <1500000>;
> +				regulator-name = "vcc_1v5";
> +				regulator-state-mem {
> +					regulator-on-in-suspend;
> +					regulator-suspend-microvolt = <1500000>;
> +				};
> +			};
> +
> +			vcca1v8_codec: LDO_REG7 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-name = "vcca1v8_codec";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			vcc_3v0: LDO_REG8 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-min-microvolt = <3000000>;
> +				regulator-max-microvolt = <3000000>;
> +				regulator-name = "vcc_3v0";
> +				regulator-state-mem {
> +					regulator-on-in-suspend;
> +					regulator-suspend-microvolt = <3000000>;
> +				};
> +			};
> +
> +			vcc3v3_s3: SWITCH_REG1 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-name = "vcc3v3_s3";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			vcc3v3_s0: SWITCH_REG2 {
> +				regulator-always-on;
> +				regulator-boot-on;
> +				regulator-name = "vcc3v3_s0";
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +		};
> +	};
> +};
> +
> +&i2c1 {
> +	status = "okay";
> +	i2c-scl-rising-time-ns = <300>;
> +	i2c-scl-falling-time-ns = <15>;
> +
> +	gsl3673: gsl3673@40 {
> +		compatible = "GSL,GSL3673";
> +		reg = <0x40>;
> +		screen_max_x = <1536>;
> +		screen_max_y = <2048>;
> +		irq_gpio_number = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>;
> +		rst_gpio_number = <&gpio4 22 GPIO_ACTIVE_HIGH>;

Again doesn't look like a valid binding.


> +	};
> +
> +	rt5640: rt5640@1c {
> +		#sound-dai-cells = <0>;
> +		compatible = "realtek,rt5640";
> +		reg = <0x1c>;
> +		clocks = <&cru SCLK_I2S_8CH_OUT>;
> +		clock-names = "mclk";
> +		realtek,in1-differential;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&rt5640_hpcon>;
> +		hp-con-gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
> +		//hp-det-gpio = <&gpio4 28 GPIO_ACTIVE_LOW>;

don't add commented lines please


> +		io-channels = <&saradc 4>;
> +		hp-det-adc-value = <500>;
> +	};
> +};
> +
> +&i2c3 {
> +	status = "okay";
> +	i2c-scl-rising-time-ns = <450>;
> +	i2c-scl-falling-time-ns = <15>;
> +};
> +
> +&i2c4 {
> +	status = "okay";
> +	i2c-scl-rising-time-ns = <600>;
> +	i2c-scl-falling-time-ns = <20>;
> +
> +	fusb0: fusb30x@22 {
> +		compatible = "fairchild,fusb302";

Has this made its way into the kernel yet?


Heiko
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2] dt-bindings: Add documentation for GP10B GPU
From: Thierry Reding @ 2017-03-31 12:56 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mark Rutland, devicetree, gnurou, linux-kernel, Jonathan Hunter,
	Rob Herring, linux-tegra, linux-arm-kernel
In-Reply-To: <20170330092644.11890-1-acourbot@nvidia.com>


[-- Attachment #1.1: Type: text/plain, Size: 2514 bytes --]

On Thu, Mar 30, 2017 at 06:26:44PM +0900, Alexandre Courbot wrote:
> GP10B's definition is mostly similar to GK20A's and GM20B's. The only
> noticeable difference is the use of power domains instead of a regulator
> for power supply.
> 
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
> Changes since v1:
> - It's much better when it compiles.
> 
>  .../devicetree/bindings/gpu/nvidia,gk20a.txt       | 25 +++++++++++++++++++++-
>  1 file changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt b/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt
> index ff3db65e50de..b7e4c7444510 100644
> --- a/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt
> +++ b/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt
> @@ -5,6 +5,7 @@ Required properties:
>    Currently recognized values:
>    - nvidia,gk20a
>    - nvidia,gm20b
> +  - nvidia,gp10b
>  - reg: Physical base address and length of the controller's registers.
>    Must contain two entries:
>    - first entry for bar0
> @@ -14,7 +15,8 @@ Required properties:
>  - interrupt-names: Must include the following entries:
>    - stall
>    - nonstall
> -- vdd-supply: regulator for supply voltage.
> +- vdd-supply: regulator for supply voltage. Only required for GPUs not using
> +  power domains.
>  - clocks: Must contain an entry for each entry in clock-names.
>    See ../clocks/clock-bindings.txt for details.
>  - clock-names: Must include the following entries:
> @@ -27,6 +29,8 @@ is also required:
>    See ../reset/reset.txt for details.
>  - reset-names: Must include the following entries:
>    - gpu
> +- power-domains: GPUs that make use of power domains can define this property
> +  instead of vdd-supply. Currently "nvidia,gp10b" makes use of this.
>  
>  Optional properties:
>  - iommus: A reference to the IOMMU. See ../iommu/iommu.txt for details.
> @@ -68,3 +72,22 @@ Example for GM20B:
>  		iommus = <&mc TEGRA_SWGROUP_GPU>;
>  		status = "disabled";
>  	};
> +
> +Example for GP10B:
> +
> +	gpu@17000000 {
> +		compatible = "nvidia,gp10b";
> +		reg = <0x0 0x17000000 0x0 0x1000000>,
> +		      <0x0 0x18000000 0x0 0x1000000>;

Would it make sense to add a reg-names property to give these meaning? I
know that the binding describes what each entry is, but having the names
specified in a property would make it more immediately obvious.

Just a thought, otherwise looks good to me.

Thierry

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v2] iommu/arm-smmu: Add global SMR masking property
From: Mark Rutland @ 2017-03-31 12:43 UTC (permalink / raw)
  To: Robin Murphy
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	will.deacon-5wv7dgnIgG8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <7472f6f57d04431bca5b2dba2a53918225eaf432.1490958040.git.robin.murphy-5wv7dgnIgG8@public.gmane.org>

On Fri, Mar 31, 2017 at 12:03:33PM +0100, Robin Murphy wrote:
> The current SMR masking support using a 2-cell iommu-specifier is
> primarily intended to handle individual masters with large and/or
> complex Stream ID assignments; it quickly gets a bit clunky in other SMR
> use-cases where we just want to consistently mask out the same part of
> every Stream ID (e.g. for MMU-500 configurations where the appended TBU
> number gets in the way unnecessarily). Let's add a new property to allow
> a single global mask value to better fit the latter situation.
> 
> Tested-by: Nipun Gupta <nipun.gupta-3arQi8VN3Tc@public.gmane.org>
> Signed-off-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> ---
> 
> v2: Rewrite the documentation to actually make sense, and add an
>     explicit example per Mark's suggestion.
> 
>  .../devicetree/bindings/iommu/arm,smmu.txt         | 27 ++++++++++++++++++++++
>  drivers/iommu/arm-smmu.c                           |  4 +++-
>  2 files changed, 30 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
> index 6cdf32d037fc..b744b231766f 100644
> --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
> @@ -60,6 +60,16 @@ conditions.
>                    aliases of secure registers have to be used during
>                    SMMU configuration.
>  
> +- stream-match-mask : For SMMUs supporting stream matching and using
> +                  #iommu-cells = <1>, specifies a fixed value to set in
> +                  the SMRn.MASK field of every stream match register
> +                  used, for cases where it is desirable to ignore some
> +                  portion of every Stream ID (e.g. for certain MMU-500
> +                  configurations given globally unique input IDs). This
> +                  property is not valid for SMMUs using stream indexing,
> +                  or using stream matching with #iommu-cells = <2>, and
> +                  may be ignored if present in such cases.

This generally sounds fine, but I'd like it to be a little more explicit
about what this means for matching. Can we change the first sentence to:

	For SMMUs supporting stream matching and using
	#iommu-cells = <1>, specifies a mask of bits to
	ignore when matching stream IDs (e.g. this may be
	programmed into the SMRn.MASK field of every
	stream match register used). 


Otherwise, this looks good to me; thanks for respinning this.

If you're happy to make the above change:

Acked-by: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>

Thanks,
Mark.

> +
>  ** Deprecated properties:
>  
>  - mmu-masters (deprecated in favour of the generic "iommus" binding) :
> @@ -109,3 +119,20 @@ conditions.
>          master3 {
>                  iommus = <&smmu2 1 0x30>;
>          };
> +
> +
> +        /* ARM MMU-500 with 10-bit stream ID input configuration */
> +        smmu3: iommu {
> +                compatible = "arm,mmu-500", "arm,smmu-v2";
> +                ...
> +                #iommu-cells = <1>;
> +                /* always ignore appended 5-bit TBU number */
> +                stream-match-mask = 0x7c00;
> +        };
> +
> +        bus {
> +                /* bus whose child devices emit one unique 10-bit stream
> +                   ID each, but may master through multiple SMMU TBUs */
> +                iommu-map = <0 &smmu3 0 0x400>;
> +                ...
> +        };
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index abf6496843a6..e394d55146a6 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -1590,13 +1590,15 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
>  
>  static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
>  {
> -	u32 fwid = 0;
> +	u32 mask, fwid = 0;
>  
>  	if (args->args_count > 0)
>  		fwid |= (u16)args->args[0];
>  
>  	if (args->args_count > 1)
>  		fwid |= (u16)args->args[1] << SMR_MASK_SHIFT;
> +	else if (!of_property_read_u32(args->np, "stream-match-mask", &mask))
> +		fwid |= (u16)mask << SMR_MASK_SHIFT;
>  
>  	return iommu_fwspec_add_ids(dev, &fwid, 1);
>  }
> -- 
> 2.11.0.dirty
> 

^ permalink raw reply

* Re: [PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver
From: Rob Herring @ 2017-03-31 12:38 UTC (permalink / raw)
  To: Nandor Han
  Cc: linus.walleij, gnurou, mark.rutland, linux-gpio, devicetree,
	linux-kernel, Semi Malinen
In-Reply-To: <6bf04ba1761f0692cb461558f0c8836f0d1f7ad8.1490595641.git.nandor.han@ge.com>

On Mon, Mar 27, 2017 at 09:23:00AM +0300, Nandor Han wrote:
> This is a simple driver that provides a /sys/class/gpio
> interface for controlling and configuring the GPIO lines.
> It does not provide support for chip select or interrupts.
> 
> Signed-off-by: Nandor Han <nandor.han@ge.com>
> Signed-off-by: Semi Malinen <semi.malinen@ge.com>
> ---
>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +

This should go with the binding patch or by itself.

>  drivers/gpio/Kconfig                               |   5 +
>  drivers/gpio/Makefile                              |   1 +
>  drivers/gpio/gpio-xra1403.c                        | 252 +++++++++++++++++++++
>  4 files changed, 259 insertions(+)
>  create mode 100644 drivers/gpio/gpio-xra1403.c

^ permalink raw reply

* [PATCH v2 2/2] iio: adc: stm32: add dt option to set resolution
From: Fabrice Gasnier @ 2017-03-31 12:32 UTC (permalink / raw)
  To: jic23, linux, robh+dt, linux-arm-kernel, devicetree, linux-kernel
  Cc: linux-iio, mark.rutland, mcoquelin.stm32, alexandre.torgue, lars,
	knaack.h, pmeerw, fabrice.gasnier, benjamin.gaignard,
	benjamin.gaignard, linus.walleij
In-Reply-To: <1490963559-32159-1-git-send-email-fabrice.gasnier@st.com>

stm32 adc supports several resolution. Add 'assigned-resolution-bits'
dt optional property to set it. Default to maximum resolution in case
it isn't set.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- rename property from 'st,adc-res' to 'assigned-resolution-bits', so it
  is more common.
---
 drivers/iio/adc/stm32-adc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 9b49a6ad..c28e7ff 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -60,6 +60,8 @@
 #define STM32F4_EOC			BIT(1)
 
 /* STM32F4_ADC_CR1 - bit fields */
+#define STM32F4_RES_SHIFT		24
+#define STM32F4_RES_MASK		GENMASK(25, 24)
 #define STM32F4_SCAN			BIT(8)
 #define STM32F4_EOCIE			BIT(5)
 
@@ -141,6 +143,7 @@ struct stm32_adc_regs {
  * @lock:		spinlock
  * @bufi:		data buffer index
  * @num_conv:		expected number of scan conversions
+ * @res:		data resolution (e.g. RES bitfield value)
  * @trigger_polarity:	external trigger polarity (e.g. exten)
  * @dma_chan:		dma channel
  * @rx_buf:		dma rx buffer cpu address
@@ -157,6 +160,7 @@ struct stm32_adc {
 	spinlock_t		lock;		/* interrupt lock */
 	unsigned int		bufi;
 	unsigned int		num_conv;
+	u32			res;
 	u32			trigger_polarity;
 	struct dma_chan		*dma_chan;
 	u8			*rx_buf;
@@ -196,6 +200,11 @@ struct stm32_adc_chan_spec {
 	{ IIO_VOLTAGE, 15, "in15" },
 };
 
+static const unsigned int stm32f4_adc_resolutions[] = {
+	/* sorted values so the index matches RES[1:0] in STM32F4_ADC_CR1 */
+	12, 10, 8, 6,
+};
+
 /**
  * stm32f4_sq - describe regular sequence registers
  * - L: sequence len (register & bit field)
@@ -302,6 +311,14 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc)
 	stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_EOCIE);
 }
 
+static void stm32_adc_set_res(struct stm32_adc *adc)
+{
+	u32 val = stm32_adc_readl(adc, STM32F4_ADC_CR1);
+
+	val = (val & ~STM32F4_RES_MASK) | (adc->res << STM32F4_RES_SHIFT);
+	stm32_adc_writel(adc, STM32F4_ADC_CR1, val);
+}
+
 /**
  * stm32_adc_start_conv() - Start conversions for regular channels.
  * @adc: stm32 adc instance
@@ -870,11 +887,37 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p)
 	{},
 };
 
+static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
+{
+	struct device_node *node = indio_dev->dev.of_node;
+	struct stm32_adc *adc = iio_priv(indio_dev);
+	unsigned int i;
+	u32 res;
+
+	if (of_property_read_u32(node, "assigned-resolution-bits", &res))
+		res = stm32f4_adc_resolutions[0];
+
+	for (i = 0; i < ARRAY_SIZE(stm32f4_adc_resolutions); i++)
+		if (res == stm32f4_adc_resolutions[i])
+			break;
+	if (i >= ARRAY_SIZE(stm32f4_adc_resolutions)) {
+		dev_err(&indio_dev->dev, "Bad resolution: %u bits\n", res);
+		return -EINVAL;
+	}
+
+	dev_dbg(&indio_dev->dev, "Using %u bits resolution\n", res);
+	adc->res = i;
+
+	return 0;
+}
+
 static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
 				    struct iio_chan_spec *chan,
 				    const struct stm32_adc_chan_spec *channel,
 				    int scan_index)
 {
+	struct stm32_adc *adc = iio_priv(indio_dev);
+
 	chan->type = channel->type;
 	chan->channel = channel->channel;
 	chan->datasheet_name = channel->name;
@@ -883,7 +926,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
 	chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
 	chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
 	chan->scan_type.sign = 'u';
-	chan->scan_type.realbits = 12;
+	chan->scan_type.realbits = stm32f4_adc_resolutions[adc->res];
 	chan->scan_type.storagebits = 16;
 	chan->ext_info = stm32_adc_ext_info;
 }
@@ -1022,6 +1065,11 @@ static int stm32_adc_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	ret = stm32_adc_of_get_resolution(indio_dev);
+	if (ret < 0)
+		goto err_clk_disable;
+	stm32_adc_set_res(adc);
+
 	ret = stm32_adc_chan_of_init(indio_dev);
 	if (ret < 0)
 		goto err_clk_disable;
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 1/2] dt-bindings: iio: stm32-adc: add option to set resolution
From: Fabrice Gasnier @ 2017-03-31 12:32 UTC (permalink / raw)
  To: jic23, linux, robh+dt, linux-arm-kernel, devicetree, linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, mcoquelin.stm32, knaack.h, fabrice.gasnier,
	linus.walleij, benjamin.gaignard
In-Reply-To: <1490963559-32159-1-git-send-email-fabrice.gasnier@st.com>

Add documentation for 'assigned-resolution-bits' dt optional property.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- rename property from 'st,adc-res' to 'assigned-resolution-bits' so it
  is more common.
---
 Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
index 5dfc88e..e35f9f1 100644
--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
@@ -57,6 +57,9 @@ Optional properties:
 - dmas: Phandle to dma channel for this ADC instance.
   See ../../dma/dma.txt for details.
 - dma-names: Must be "rx" when dmas property is being used.
+- assigned-resolution-bits: Resolution (bits) to use for conversions. Must
+  match device available resolutions (e.g. can be 6, 8, 10 or 12 on stm32f4).
+  Default is maximum resolution if unset.
 
 Example:
 	adc: adc@40012000 {
@@ -84,6 +87,7 @@ Example:
 			st,adc-channels = <8>;
 			dmas = <&dma2 0 0 0x400 0x0>;
 			dma-names = "rx";
+			assigned-resolution-bits = <8>;
 		};
 		...
 		other adc child nodes follow...
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 0/2] iio: allow to set STM32 ADC resolution
From: Fabrice Gasnier @ 2017-03-31 12:32 UTC (permalink / raw)
  To: jic23, linux, robh+dt, linux-arm-kernel, devicetree, linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, mcoquelin.stm32, knaack.h, fabrice.gasnier,
	linus.walleij, benjamin.gaignard

STM32 ADC supports several resolution. Add dt option so resolution
can be tuned at probe time. By default, maximum resolution is used
when it isn't set.

---
Changes in v2:
 - rename property from 'st,adc-res' to 'assigned-resolution-bits' so it
 is more common.

Fabrice Gasnier (2):
  dt-bindings: iio: stm32-adc: add option to set resolution
  iio: adc: stm32: add dt option to set resolution

 .../devicetree/bindings/iio/adc/st,stm32-adc.txt   |  4 ++
 drivers/iio/adc/stm32-adc.c                        | 50 +++++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletion(-)

-- 
1.9.1

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox