|
@@ -43,14 +43,16 @@
|
|
#include <linux/usb_gadget.h>
|
|
#include <linux/usb_gadget.h>
|
|
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <asm/byteorder.h>
|
|
|
|
+#include <asm/hardware.h>
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/system.h>
|
|
#include <asm/system.h>
|
|
#include <asm/mach-types.h>
|
|
#include <asm/mach-types.h>
|
|
|
|
|
|
-#include <asm/arch/hardware.h>
|
|
|
|
#include <asm/arch/gpio.h>
|
|
#include <asm/arch/gpio.h>
|
|
#include <asm/arch/board.h>
|
|
#include <asm/arch/board.h>
|
|
|
|
+#include <asm/arch/cpu.h>
|
|
|
|
+#include <asm/arch/at91sam9261_matrix.h>
|
|
|
|
|
|
#include "at91_udc.h"
|
|
#include "at91_udc.h"
|
|
|
|
|
|
@@ -78,27 +80,11 @@
|
|
static const char driver_name [] = "at91_udc";
|
|
static const char driver_name [] = "at91_udc";
|
|
static const char ep0name[] = "ep0";
|
|
static const char ep0name[] = "ep0";
|
|
|
|
|
|
-/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
-/*
|
|
|
|
- * Read from a UDP register.
|
|
|
|
- */
|
|
|
|
-static inline unsigned long at91_udp_read(unsigned int reg)
|
|
|
|
-{
|
|
|
|
- void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
|
|
|
|
-
|
|
|
|
- return __raw_readl(udp_base + reg);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * Write to a UDP register.
|
|
|
|
- */
|
|
|
|
-static inline void at91_udp_write(unsigned int reg, unsigned long value)
|
|
|
|
-{
|
|
|
|
- void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
|
|
|
|
-
|
|
|
|
- __raw_writel(value, udp_base + reg);
|
|
|
|
-}
|
|
|
|
|
|
+#define at91_udp_read(dev, reg) \
|
|
|
|
+ __raw_readl((dev)->udp_baseaddr + (reg))
|
|
|
|
+#define at91_udp_write(dev, reg, val) \
|
|
|
|
+ __raw_writel((val), (dev)->udp_baseaddr + (reg))
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
@@ -210,13 +196,13 @@ static int proc_udc_show(struct seq_file *s, void *unused)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- tmp = at91_udp_read(AT91_UDP_FRM_NUM);
|
|
|
|
|
|
+ tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM);
|
|
seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
|
|
seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
|
|
(tmp & AT91_UDP_FRM_OK) ? " ok" : "",
|
|
(tmp & AT91_UDP_FRM_OK) ? " ok" : "",
|
|
(tmp & AT91_UDP_FRM_ERR) ? " err" : "",
|
|
(tmp & AT91_UDP_FRM_ERR) ? " err" : "",
|
|
(tmp & AT91_UDP_NUM));
|
|
(tmp & AT91_UDP_NUM));
|
|
|
|
|
|
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
|
|
|
|
|
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
|
seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
|
|
seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
|
|
(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
|
|
(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
|
|
(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
|
|
(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
|
|
@@ -224,13 +210,13 @@ static int proc_udc_show(struct seq_file *s, void *unused)
|
|
(tmp & AT91_UDP_CONFG) ? " confg" : "",
|
|
(tmp & AT91_UDP_CONFG) ? " confg" : "",
|
|
(tmp & AT91_UDP_FADDEN) ? " fadden" : "");
|
|
(tmp & AT91_UDP_FADDEN) ? " fadden" : "");
|
|
|
|
|
|
- tmp = at91_udp_read(AT91_UDP_FADDR);
|
|
|
|
|
|
+ tmp = at91_udp_read(udc, AT91_UDP_FADDR);
|
|
seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp,
|
|
seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp,
|
|
(tmp & AT91_UDP_FEN) ? " fen" : "",
|
|
(tmp & AT91_UDP_FEN) ? " fen" : "",
|
|
(tmp & AT91_UDP_FADD));
|
|
(tmp & AT91_UDP_FADD));
|
|
|
|
|
|
- proc_irq_show(s, "imr ", at91_udp_read(AT91_UDP_IMR));
|
|
|
|
- proc_irq_show(s, "isr ", at91_udp_read(AT91_UDP_ISR));
|
|
|
|
|
|
+ proc_irq_show(s, "imr ", at91_udp_read(udc, AT91_UDP_IMR));
|
|
|
|
+ proc_irq_show(s, "isr ", at91_udp_read(udc, AT91_UDP_ISR));
|
|
|
|
|
|
if (udc->enabled && udc->vbus) {
|
|
if (udc->enabled && udc->vbus) {
|
|
proc_ep_show(s, &udc->ep[0]);
|
|
proc_ep_show(s, &udc->ep[0]);
|
|
@@ -286,6 +272,7 @@ static inline void remove_debug_file(struct at91_udc *udc) {}
|
|
static void done(struct at91_ep *ep, struct at91_request *req, int status)
|
|
static void done(struct at91_ep *ep, struct at91_request *req, int status)
|
|
{
|
|
{
|
|
unsigned stopped = ep->stopped;
|
|
unsigned stopped = ep->stopped;
|
|
|
|
+ struct at91_udc *udc = ep->udc;
|
|
|
|
|
|
list_del_init(&req->queue);
|
|
list_del_init(&req->queue);
|
|
if (req->req.status == -EINPROGRESS)
|
|
if (req->req.status == -EINPROGRESS)
|
|
@@ -301,7 +288,7 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status)
|
|
|
|
|
|
/* ep0 is always ready; other endpoints need a non-empty queue */
|
|
/* ep0 is always ready; other endpoints need a non-empty queue */
|
|
if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
|
|
if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
|
|
- at91_udp_write(AT91_UDP_IDR, ep->int_mask);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*-------------------------------------------------------------------------*/
|
|
@@ -554,8 +541,8 @@ ok:
|
|
* reset/init endpoint fifo. NOTE: leaves fifo_bank alone,
|
|
* reset/init endpoint fifo. NOTE: leaves fifo_bank alone,
|
|
* since endpoint resets don't reset hw pingpong state.
|
|
* since endpoint resets don't reset hw pingpong state.
|
|
*/
|
|
*/
|
|
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
- at91_udp_write(AT91_UDP_RST_EP, 0);
|
|
|
|
|
|
+ at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
+ at91_udp_write(dev, AT91_UDP_RST_EP, 0);
|
|
|
|
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
return 0;
|
|
return 0;
|
|
@@ -564,6 +551,7 @@ ok:
|
|
static int at91_ep_disable (struct usb_ep * _ep)
|
|
static int at91_ep_disable (struct usb_ep * _ep)
|
|
{
|
|
{
|
|
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
|
|
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
|
|
|
|
+ struct at91_udc *udc = ep->udc;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
if (ep == &ep->udc->ep[0])
|
|
if (ep == &ep->udc->ep[0])
|
|
@@ -579,8 +567,8 @@ static int at91_ep_disable (struct usb_ep * _ep)
|
|
|
|
|
|
/* reset fifos and endpoint */
|
|
/* reset fifos and endpoint */
|
|
if (ep->udc->clocked) {
|
|
if (ep->udc->clocked) {
|
|
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
- at91_udp_write(AT91_UDP_RST_EP, 0);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
|
|
__raw_writel(0, ep->creg);
|
|
__raw_writel(0, ep->creg);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -695,10 +683,10 @@ static int at91_ep_queue(struct usb_ep *_ep,
|
|
* reconfigures the endpoints.
|
|
* reconfigures the endpoints.
|
|
*/
|
|
*/
|
|
if (dev->wait_for_config_ack) {
|
|
if (dev->wait_for_config_ack) {
|
|
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
|
|
|
|
|
+ tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT);
|
|
tmp ^= AT91_UDP_CONFG;
|
|
tmp ^= AT91_UDP_CONFG;
|
|
VDBG("toggle config\n");
|
|
VDBG("toggle config\n");
|
|
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
|
|
|
|
|
+ at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp);
|
|
}
|
|
}
|
|
if (req->req.length == 0) {
|
|
if (req->req.length == 0) {
|
|
ep0_in_status:
|
|
ep0_in_status:
|
|
@@ -727,7 +715,7 @@ ep0_in_status:
|
|
|
|
|
|
if (req && !status) {
|
|
if (req && !status) {
|
|
list_add_tail (&req->queue, &ep->queue);
|
|
list_add_tail (&req->queue, &ep->queue);
|
|
- at91_udp_write(AT91_UDP_IER, ep->int_mask);
|
|
|
|
|
|
+ at91_udp_write(dev, AT91_UDP_IER, ep->int_mask);
|
|
}
|
|
}
|
|
done:
|
|
done:
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
@@ -758,6 +746,7 @@ static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
|
static int at91_ep_set_halt(struct usb_ep *_ep, int value)
|
|
static int at91_ep_set_halt(struct usb_ep *_ep, int value)
|
|
{
|
|
{
|
|
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
|
|
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
|
|
|
|
+ struct at91_udc *udc = ep->udc;
|
|
u32 __iomem *creg;
|
|
u32 __iomem *creg;
|
|
u32 csr;
|
|
u32 csr;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -785,8 +774,8 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value)
|
|
csr |= AT91_UDP_FORCESTALL;
|
|
csr |= AT91_UDP_FORCESTALL;
|
|
VDBG("halt %s\n", ep->ep.name);
|
|
VDBG("halt %s\n", ep->ep.name);
|
|
} else {
|
|
} else {
|
|
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
- at91_udp_write(AT91_UDP_RST_EP, 0);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
|
|
csr &= ~AT91_UDP_FORCESTALL;
|
|
csr &= ~AT91_UDP_FORCESTALL;
|
|
}
|
|
}
|
|
__raw_writel(csr, creg);
|
|
__raw_writel(csr, creg);
|
|
@@ -813,9 +802,11 @@ static struct usb_ep_ops at91_ep_ops = {
|
|
|
|
|
|
static int at91_get_frame(struct usb_gadget *gadget)
|
|
static int at91_get_frame(struct usb_gadget *gadget)
|
|
{
|
|
{
|
|
|
|
+ struct at91_udc *udc = to_udc(gadget);
|
|
|
|
+
|
|
if (!to_udc(gadget)->clocked)
|
|
if (!to_udc(gadget)->clocked)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
|
|
|
|
|
|
+ return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
|
|
}
|
|
}
|
|
|
|
|
|
static int at91_wakeup(struct usb_gadget *gadget)
|
|
static int at91_wakeup(struct usb_gadget *gadget)
|
|
@@ -833,11 +824,11 @@ static int at91_wakeup(struct usb_gadget *gadget)
|
|
|
|
|
|
/* NOTE: some "early versions" handle ESR differently ... */
|
|
/* NOTE: some "early versions" handle ESR differently ... */
|
|
|
|
|
|
- glbstate = at91_udp_read(AT91_UDP_GLB_STAT);
|
|
|
|
|
|
+ glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
|
if (!(glbstate & AT91_UDP_ESR))
|
|
if (!(glbstate & AT91_UDP_ESR))
|
|
goto done;
|
|
goto done;
|
|
glbstate |= AT91_UDP_ESR;
|
|
glbstate |= AT91_UDP_ESR;
|
|
- at91_udp_write(AT91_UDP_GLB_STAT, glbstate);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
|
|
|
|
|
|
done:
|
|
done:
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
@@ -861,6 +852,7 @@ static void udc_reinit(struct at91_udc *udc)
|
|
ep->stopped = 0;
|
|
ep->stopped = 0;
|
|
ep->fifo_bank = 0;
|
|
ep->fifo_bank = 0;
|
|
ep->ep.maxpacket = ep->maxpacket;
|
|
ep->ep.maxpacket = ep->maxpacket;
|
|
|
|
+ ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
|
|
// initialiser une queue par endpoint
|
|
// initialiser une queue par endpoint
|
|
INIT_LIST_HEAD(&ep->queue);
|
|
INIT_LIST_HEAD(&ep->queue);
|
|
}
|
|
}
|
|
@@ -915,14 +907,41 @@ static void pullup(struct at91_udc *udc, int is_on)
|
|
if (!udc->enabled || !udc->vbus)
|
|
if (!udc->enabled || !udc->vbus)
|
|
is_on = 0;
|
|
is_on = 0;
|
|
DBG("%sactive\n", is_on ? "" : "in");
|
|
DBG("%sactive\n", is_on ? "" : "in");
|
|
|
|
+
|
|
if (is_on) {
|
|
if (is_on) {
|
|
clk_on(udc);
|
|
clk_on(udc);
|
|
- at91_udp_write(AT91_UDP_TXVC, 0);
|
|
|
|
- at91_set_gpio_value(udc->board.pullup_pin, 1);
|
|
|
|
- } else {
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_TXVC, 0);
|
|
|
|
+ if (cpu_is_at91rm9200())
|
|
|
|
+ at91_set_gpio_value(udc->board.pullup_pin, 1);
|
|
|
|
+ else if (cpu_is_at91sam9260()) {
|
|
|
|
+ u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
|
|
|
|
+
|
|
|
|
+ txvc |= AT91_UDP_TXVC_PUON;
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_TXVC, txvc);
|
|
|
|
+ } else if (cpu_is_at91sam9261()) {
|
|
|
|
+ u32 usbpucr;
|
|
|
|
+
|
|
|
|
+ usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
|
|
|
|
+ usbpucr |= AT91_MATRIX_USBPUCR_PUON;
|
|
|
|
+ at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
stop_activity(udc);
|
|
stop_activity(udc);
|
|
- at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
|
|
|
- at91_set_gpio_value(udc->board.pullup_pin, 0);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
|
|
|
+ if (cpu_is_at91rm9200())
|
|
|
|
+ at91_set_gpio_value(udc->board.pullup_pin, 0);
|
|
|
|
+ else if (cpu_is_at91sam9260()) {
|
|
|
|
+ u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
|
|
|
|
+
|
|
|
|
+ txvc &= ~AT91_UDP_TXVC_PUON;
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_TXVC, txvc);
|
|
|
|
+ } else if (cpu_is_at91sam9261()) {
|
|
|
|
+ u32 usbpucr;
|
|
|
|
+
|
|
|
|
+ usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
|
|
|
|
+ usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
|
|
|
|
+ at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
|
|
|
|
+ }
|
|
clk_off(udc);
|
|
clk_off(udc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -936,7 +955,10 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
|
|
// VDBG("vbus %s\n", is_active ? "on" : "off");
|
|
// VDBG("vbus %s\n", is_active ? "on" : "off");
|
|
local_irq_save(flags);
|
|
local_irq_save(flags);
|
|
udc->vbus = (is_active != 0);
|
|
udc->vbus = (is_active != 0);
|
|
- pullup(udc, is_active);
|
|
|
|
|
|
+ if (udc->driver)
|
|
|
|
+ pullup(udc, is_active);
|
|
|
|
+ else
|
|
|
|
+ pullup(udc, 0);
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -1086,7 +1108,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
|
|
|
|
|
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
|
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
|
| USB_REQ_SET_CONFIGURATION:
|
|
| USB_REQ_SET_CONFIGURATION:
|
|
- tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
|
|
|
|
|
|
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
|
|
if (pkt.r.wValue)
|
|
if (pkt.r.wValue)
|
|
udc->wait_for_config_ack = (tmp == 0);
|
|
udc->wait_for_config_ack = (tmp == 0);
|
|
else
|
|
else
|
|
@@ -1103,7 +1125,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
|
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
|
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
|
| USB_REQ_GET_STATUS:
|
|
| USB_REQ_GET_STATUS:
|
|
tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
|
|
tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
|
|
- if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
|
|
|
|
|
|
+ if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
|
|
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
|
|
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
|
|
PACKET("get device status\n");
|
|
PACKET("get device status\n");
|
|
__raw_writeb(tmp, dreg);
|
|
__raw_writeb(tmp, dreg);
|
|
@@ -1114,17 +1136,17 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
|
| USB_REQ_SET_FEATURE:
|
|
| USB_REQ_SET_FEATURE:
|
|
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
|
|
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
|
|
goto stall;
|
|
goto stall;
|
|
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
|
|
|
|
|
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
|
tmp |= AT91_UDP_ESR;
|
|
tmp |= AT91_UDP_ESR;
|
|
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
|
|
goto succeed;
|
|
goto succeed;
|
|
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
|
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
|
| USB_REQ_CLEAR_FEATURE:
|
|
| USB_REQ_CLEAR_FEATURE:
|
|
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
|
|
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
|
|
goto stall;
|
|
goto stall;
|
|
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
|
|
|
|
|
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
|
tmp &= ~AT91_UDP_ESR;
|
|
tmp &= ~AT91_UDP_ESR;
|
|
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
|
|
goto succeed;
|
|
goto succeed;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1206,8 +1228,8 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
|
} else if (ep->is_in)
|
|
} else if (ep->is_in)
|
|
goto stall;
|
|
goto stall;
|
|
|
|
|
|
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
- at91_udp_write(AT91_UDP_RST_EP, 0);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
|
|
tmp = __raw_readl(ep->creg);
|
|
tmp = __raw_readl(ep->creg);
|
|
tmp |= CLR_FX;
|
|
tmp |= CLR_FX;
|
|
tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
|
|
tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
|
|
@@ -1222,7 +1244,10 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
|
#undef w_length
|
|
#undef w_length
|
|
|
|
|
|
/* pass request up to the gadget driver */
|
|
/* pass request up to the gadget driver */
|
|
- status = udc->driver->setup(&udc->gadget, &pkt.r);
|
|
|
|
|
|
+ if (udc->driver)
|
|
|
|
+ status = udc->driver->setup(&udc->gadget, &pkt.r);
|
|
|
|
+ else
|
|
|
|
+ status = -ENODEV;
|
|
if (status < 0) {
|
|
if (status < 0) {
|
|
stall:
|
|
stall:
|
|
VDBG("req %02x.%02x protocol STALL; stat %d\n",
|
|
VDBG("req %02x.%02x protocol STALL; stat %d\n",
|
|
@@ -1300,13 +1325,13 @@ static void handle_ep0(struct at91_udc *udc)
|
|
if (udc->wait_for_addr_ack) {
|
|
if (udc->wait_for_addr_ack) {
|
|
u32 tmp;
|
|
u32 tmp;
|
|
|
|
|
|
- at91_udp_write(AT91_UDP_FADDR,
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_FADDR,
|
|
AT91_UDP_FEN | udc->addr);
|
|
AT91_UDP_FEN | udc->addr);
|
|
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
|
|
|
|
|
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
|
tmp &= ~AT91_UDP_FADDEN;
|
|
tmp &= ~AT91_UDP_FADDEN;
|
|
if (udc->addr)
|
|
if (udc->addr)
|
|
tmp |= AT91_UDP_FADDEN;
|
|
tmp |= AT91_UDP_FADDEN;
|
|
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
|
|
|
|
|
|
udc->wait_for_addr_ack = 0;
|
|
udc->wait_for_addr_ack = 0;
|
|
VDBG("address %d\n", udc->addr);
|
|
VDBG("address %d\n", udc->addr);
|
|
@@ -1374,28 +1399,28 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
|
|
while (rescans--) {
|
|
while (rescans--) {
|
|
u32 status;
|
|
u32 status;
|
|
|
|
|
|
- status = at91_udp_read(AT91_UDP_ISR)
|
|
|
|
- & at91_udp_read(AT91_UDP_IMR);
|
|
|
|
|
|
+ status = at91_udp_read(udc, AT91_UDP_ISR)
|
|
|
|
+ & at91_udp_read(udc, AT91_UDP_IMR);
|
|
if (!status)
|
|
if (!status)
|
|
break;
|
|
break;
|
|
|
|
|
|
/* USB reset irq: not maskable */
|
|
/* USB reset irq: not maskable */
|
|
if (status & AT91_UDP_ENDBUSRES) {
|
|
if (status & AT91_UDP_ENDBUSRES) {
|
|
- at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
|
|
|
|
- at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS);
|
|
/* Atmel code clears this irq twice */
|
|
/* Atmel code clears this irq twice */
|
|
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
|
|
|
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
|
VDBG("end bus reset\n");
|
|
VDBG("end bus reset\n");
|
|
udc->addr = 0;
|
|
udc->addr = 0;
|
|
stop_activity(udc);
|
|
stop_activity(udc);
|
|
|
|
|
|
/* enable ep0 */
|
|
/* enable ep0 */
|
|
- at91_udp_write(AT91_UDP_CSR(0),
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_CSR(0),
|
|
AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
|
|
AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
|
|
udc->gadget.speed = USB_SPEED_FULL;
|
|
udc->gadget.speed = USB_SPEED_FULL;
|
|
udc->suspended = 0;
|
|
udc->suspended = 0;
|
|
- at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0));
|
|
|
|
|
|
/*
|
|
/*
|
|
* NOTE: this driver keeps clocks off unless the
|
|
* NOTE: this driver keeps clocks off unless the
|
|
@@ -1406,9 +1431,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
|
|
|
|
|
|
/* host initiated suspend (3+ms bus idle) */
|
|
/* host initiated suspend (3+ms bus idle) */
|
|
} else if (status & AT91_UDP_RXSUSP) {
|
|
} else if (status & AT91_UDP_RXSUSP) {
|
|
- at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP);
|
|
|
|
- at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM);
|
|
|
|
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
|
|
// VDBG("bus suspend\n");
|
|
// VDBG("bus suspend\n");
|
|
if (udc->suspended)
|
|
if (udc->suspended)
|
|
continue;
|
|
continue;
|
|
@@ -1425,9 +1450,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
|
|
|
|
|
|
/* host initiated resume */
|
|
/* host initiated resume */
|
|
} else if (status & AT91_UDP_RXRSM) {
|
|
} else if (status & AT91_UDP_RXRSM) {
|
|
- at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM);
|
|
|
|
- at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP);
|
|
|
|
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
|
|
// VDBG("bus resume\n");
|
|
// VDBG("bus resume\n");
|
|
if (!udc->suspended)
|
|
if (!udc->suspended)
|
|
continue;
|
|
continue;
|
|
@@ -1485,8 +1510,6 @@ static struct at91_udc controller = {
|
|
},
|
|
},
|
|
.udc = &controller,
|
|
.udc = &controller,
|
|
.maxpacket = 8,
|
|
.maxpacket = 8,
|
|
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
|
|
|
|
- + AT91_UDP_CSR(0)),
|
|
|
|
.int_mask = 1 << 0,
|
|
.int_mask = 1 << 0,
|
|
},
|
|
},
|
|
.ep[1] = {
|
|
.ep[1] = {
|
|
@@ -1497,8 +1520,6 @@ static struct at91_udc controller = {
|
|
.udc = &controller,
|
|
.udc = &controller,
|
|
.is_pingpong = 1,
|
|
.is_pingpong = 1,
|
|
.maxpacket = 64,
|
|
.maxpacket = 64,
|
|
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
|
|
|
|
- + AT91_UDP_CSR(1)),
|
|
|
|
.int_mask = 1 << 1,
|
|
.int_mask = 1 << 1,
|
|
},
|
|
},
|
|
.ep[2] = {
|
|
.ep[2] = {
|
|
@@ -1509,8 +1530,6 @@ static struct at91_udc controller = {
|
|
.udc = &controller,
|
|
.udc = &controller,
|
|
.is_pingpong = 1,
|
|
.is_pingpong = 1,
|
|
.maxpacket = 64,
|
|
.maxpacket = 64,
|
|
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
|
|
|
|
- + AT91_UDP_CSR(2)),
|
|
|
|
.int_mask = 1 << 2,
|
|
.int_mask = 1 << 2,
|
|
},
|
|
},
|
|
.ep[3] = {
|
|
.ep[3] = {
|
|
@@ -1521,8 +1540,6 @@ static struct at91_udc controller = {
|
|
},
|
|
},
|
|
.udc = &controller,
|
|
.udc = &controller,
|
|
.maxpacket = 8,
|
|
.maxpacket = 8,
|
|
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
|
|
|
|
- + AT91_UDP_CSR(3)),
|
|
|
|
.int_mask = 1 << 3,
|
|
.int_mask = 1 << 3,
|
|
},
|
|
},
|
|
.ep[4] = {
|
|
.ep[4] = {
|
|
@@ -1533,8 +1550,6 @@ static struct at91_udc controller = {
|
|
.udc = &controller,
|
|
.udc = &controller,
|
|
.is_pingpong = 1,
|
|
.is_pingpong = 1,
|
|
.maxpacket = 256,
|
|
.maxpacket = 256,
|
|
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
|
|
|
|
- + AT91_UDP_CSR(4)),
|
|
|
|
.int_mask = 1 << 4,
|
|
.int_mask = 1 << 4,
|
|
},
|
|
},
|
|
.ep[5] = {
|
|
.ep[5] = {
|
|
@@ -1545,8 +1560,6 @@ static struct at91_udc controller = {
|
|
.udc = &controller,
|
|
.udc = &controller,
|
|
.is_pingpong = 1,
|
|
.is_pingpong = 1,
|
|
.maxpacket = 256,
|
|
.maxpacket = 256,
|
|
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
|
|
|
|
- + AT91_UDP_CSR(5)),
|
|
|
|
.int_mask = 1 << 5,
|
|
.int_mask = 1 << 5,
|
|
},
|
|
},
|
|
/* ep6 and ep7 are also reserved (custom silicon might use them) */
|
|
/* ep6 and ep7 are also reserved (custom silicon might use them) */
|
|
@@ -1572,9 +1585,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|
int retval;
|
|
int retval;
|
|
|
|
|
|
if (!driver
|
|
if (!driver
|
|
- || driver->speed != USB_SPEED_FULL
|
|
|
|
|
|
+ || driver->speed < USB_SPEED_FULL
|
|
|| !driver->bind
|
|
|| !driver->bind
|
|
- || !driver->unbind
|
|
|
|
|| !driver->setup) {
|
|
|| !driver->setup) {
|
|
DBG("bad parameter.\n");
|
|
DBG("bad parameter.\n");
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -1595,6 +1607,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|
if (retval) {
|
|
if (retval) {
|
|
DBG("driver->bind() returned %d\n", retval);
|
|
DBG("driver->bind() returned %d\n", retval);
|
|
udc->driver = NULL;
|
|
udc->driver = NULL;
|
|
|
|
+ udc->gadget.dev.driver = NULL;
|
|
|
|
+ udc->gadget.dev.driver_data = NULL;
|
|
|
|
+ udc->enabled = 0;
|
|
|
|
+ udc->selfpowered = 0;
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1611,12 +1627,12 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
|
{
|
|
{
|
|
struct at91_udc *udc = &controller;
|
|
struct at91_udc *udc = &controller;
|
|
|
|
|
|
- if (!driver || driver != udc->driver)
|
|
|
|
|
|
+ if (!driver || driver != udc->driver || !driver->unbind)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
local_irq_disable();
|
|
local_irq_disable();
|
|
udc->enabled = 0;
|
|
udc->enabled = 0;
|
|
- at91_udp_write(AT91_UDP_IDR, ~0);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IDR, ~0);
|
|
pullup(udc, 0);
|
|
pullup(udc, 0);
|
|
local_irq_enable();
|
|
local_irq_enable();
|
|
|
|
|
|
@@ -1641,6 +1657,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
|
struct device *dev = &pdev->dev;
|
|
struct device *dev = &pdev->dev;
|
|
struct at91_udc *udc;
|
|
struct at91_udc *udc;
|
|
int retval;
|
|
int retval;
|
|
|
|
+ struct resource *res;
|
|
|
|
|
|
if (!dev->platform_data) {
|
|
if (!dev->platform_data) {
|
|
/* small (so we copy it) but critical! */
|
|
/* small (so we copy it) but critical! */
|
|
@@ -1658,7 +1675,13 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) {
|
|
|
|
|
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
|
+ if (!res)
|
|
|
|
+ return -ENXIO;
|
|
|
|
+
|
|
|
|
+ if (!request_mem_region(res->start,
|
|
|
|
+ res->end - res->start + 1,
|
|
|
|
+ driver_name)) {
|
|
DBG("someone's using UDC memory\n");
|
|
DBG("someone's using UDC memory\n");
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
}
|
|
}
|
|
@@ -1668,15 +1691,23 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
|
udc->gadget.dev.parent = dev;
|
|
udc->gadget.dev.parent = dev;
|
|
udc->board = *(struct at91_udc_data *) dev->platform_data;
|
|
udc->board = *(struct at91_udc_data *) dev->platform_data;
|
|
udc->pdev = pdev;
|
|
udc->pdev = pdev;
|
|
- udc_reinit(udc);
|
|
|
|
udc->enabled = 0;
|
|
udc->enabled = 0;
|
|
|
|
|
|
|
|
+ udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
|
|
|
|
+ if (!udc->udp_baseaddr) {
|
|
|
|
+ release_mem_region(res->start, res->end - res->start + 1);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ udc_reinit(udc);
|
|
|
|
+
|
|
/* get interface and function clocks */
|
|
/* get interface and function clocks */
|
|
udc->iclk = clk_get(dev, "udc_clk");
|
|
udc->iclk = clk_get(dev, "udc_clk");
|
|
udc->fclk = clk_get(dev, "udpck");
|
|
udc->fclk = clk_get(dev, "udpck");
|
|
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
|
|
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
|
|
DBG("clocks missing\n");
|
|
DBG("clocks missing\n");
|
|
- return -ENODEV;
|
|
|
|
|
|
+ retval = -ENODEV;
|
|
|
|
+ goto fail0;
|
|
}
|
|
}
|
|
|
|
|
|
retval = device_register(&udc->gadget.dev);
|
|
retval = device_register(&udc->gadget.dev);
|
|
@@ -1685,8 +1716,10 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
|
|
|
|
|
/* don't do anything until we have both gadget driver and VBUS */
|
|
/* don't do anything until we have both gadget driver and VBUS */
|
|
clk_enable(udc->iclk);
|
|
clk_enable(udc->iclk);
|
|
- at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
|
|
|
- at91_udp_write(AT91_UDP_IDR, 0xffffffff);
|
|
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
|
|
|
|
+ /* Clear all pending interrupts - UDP may be used by bootloader. */
|
|
|
|
+ at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
|
|
clk_disable(udc->iclk);
|
|
clk_disable(udc->iclk);
|
|
|
|
|
|
/* request UDC and maybe VBUS irqs */
|
|
/* request UDC and maybe VBUS irqs */
|
|
@@ -1698,6 +1731,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
|
goto fail1;
|
|
goto fail1;
|
|
}
|
|
}
|
|
if (udc->board.vbus_pin > 0) {
|
|
if (udc->board.vbus_pin > 0) {
|
|
|
|
+ /*
|
|
|
|
+ * Get the initial state of VBUS - we cannot expect
|
|
|
|
+ * a pending interrupt.
|
|
|
|
+ */
|
|
|
|
+ udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
|
|
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
|
|
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
|
|
IRQF_DISABLED, driver_name, udc)) {
|
|
IRQF_DISABLED, driver_name, udc)) {
|
|
DBG("request vbus irq %d failed\n",
|
|
DBG("request vbus irq %d failed\n",
|
|
@@ -1720,7 +1758,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
|
fail1:
|
|
fail1:
|
|
device_unregister(&udc->gadget.dev);
|
|
device_unregister(&udc->gadget.dev);
|
|
fail0:
|
|
fail0:
|
|
- release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
|
|
|
|
|
|
+ release_mem_region(res->start, res->end - res->start + 1);
|
|
DBG("%s probe failed, %d\n", driver_name, retval);
|
|
DBG("%s probe failed, %d\n", driver_name, retval);
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
@@ -1728,13 +1766,14 @@ fail0:
|
|
static int __devexit at91udc_remove(struct platform_device *pdev)
|
|
static int __devexit at91udc_remove(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct at91_udc *udc = platform_get_drvdata(pdev);
|
|
struct at91_udc *udc = platform_get_drvdata(pdev);
|
|
|
|
+ struct resource *res;
|
|
|
|
|
|
DBG("remove\n");
|
|
DBG("remove\n");
|
|
|
|
|
|
- pullup(udc, 0);
|
|
|
|
|
|
+ if (udc->driver)
|
|
|
|
+ return -EBUSY;
|
|
|
|
|
|
- if (udc->driver != 0)
|
|
|
|
- usb_gadget_unregister_driver(udc->driver);
|
|
|
|
|
|
+ pullup(udc, 0);
|
|
|
|
|
|
device_init_wakeup(&pdev->dev, 0);
|
|
device_init_wakeup(&pdev->dev, 0);
|
|
remove_debug_file(udc);
|
|
remove_debug_file(udc);
|
|
@@ -1742,7 +1781,10 @@ static int __devexit at91udc_remove(struct platform_device *pdev)
|
|
free_irq(udc->board.vbus_pin, udc);
|
|
free_irq(udc->board.vbus_pin, udc);
|
|
free_irq(udc->udp_irq, udc);
|
|
free_irq(udc->udp_irq, udc);
|
|
device_unregister(&udc->gadget.dev);
|
|
device_unregister(&udc->gadget.dev);
|
|
- release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
|
|
|
|
|
|
+
|
|
|
|
+ iounmap(udc->udp_baseaddr);
|
|
|
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
|
+ release_mem_region(res->start, res->end - res->start + 1);
|
|
|
|
|
|
clk_put(udc->iclk);
|
|
clk_put(udc->iclk);
|
|
clk_put(udc->fclk);
|
|
clk_put(udc->fclk);
|