diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-11-11 17:31:53 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-11-11 17:31:53 -0800 |
commit | 7fd94beecaff19b346efbf6b77288ab4b0b42dbd (patch) | |
tree | 01c1354e59c8c338fd2fe65772c169022aa0ca81 /drivers/usb/renesas_usbhs | |
parent | 0f89fc3fd861b8c50fc8c8db5b9a640959744ac7 (diff) | |
parent | f72e3b78867142a19b77f1de0698ce8b03dc6cbd (diff) | |
download | op-kernel-dev-7fd94beecaff19b346efbf6b77288ab4b0b42dbd.zip op-kernel-dev-7fd94beecaff19b346efbf6b77288ab4b0b42dbd.tar.gz |
Merge tag 'gadget-for-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
USB gadget patches from Felipe:
"usb: gadget: patches for v3.8
renesas_usbhs implements ->pullup() method, switches over
to devm_request_irq(), adds support for DMA Engine and
got a few miscelaneous cleanups.
The NCM gadget got an endianness fix and the Ethernet
gadget a frame size fix.
We're finally removing the g_file_storage gadget and
sticking to g_mass_storage and the new tcm_usb_gadget
gadgets since that was a huge duplicaton of effort anyway.
While removing g_file_storage, we also had to fix a bunch
of defconfigs which were still pointing to the old gadget.
There's a big series getting us closer to being able to
introduce our configfs interface. The series converts
functions into loadable modules which will, eventually,
be registered to the configfs interface.
Other than that there's the usual typo fixes and miscelaneous
cleanups all over the place."
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r-- | drivers/usb/renesas_usbhs/common.c | 5 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/common.h | 1 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.c | 14 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod.c | 3 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_gadget.c | 11 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_host.c | 45 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.c | 101 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.h | 1 |
8 files changed, 157 insertions, 24 deletions
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 072edc1..3bf922a 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -132,6 +132,11 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); } +void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable) +{ + usbhs_bset(priv, SYSCFG, DPRPU, enable ? DPRPU : 0); +} + void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode) { usbhs_write(priv, TESTMODE, mode); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index dddf40a..c69dd2f 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -285,6 +285,7 @@ void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); */ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); +void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable); void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode); /* diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index c021b20..9538f0f 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -163,7 +163,7 @@ static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) func = pkt->handler->dma_done; break; default: - dev_err(dev, "unknown pkt hander\n"); + dev_err(dev, "unknown pkt handler\n"); goto __usbhs_pkt_handler_end; } @@ -192,8 +192,8 @@ void usbhs_pkt_start(struct usbhs_pipe *pipe) /* * irq enable/disable function */ -#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, bempsts, e) -#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, brdysts, e) +#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_bempsts, e) +#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_brdysts, e) #define usbhsf_irq_callback_ctrl(pipe, status, enable) \ ({ \ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \ @@ -202,9 +202,9 @@ void usbhs_pkt_start(struct usbhs_pipe *pipe) if (!mod) \ return; \ if (enable) \ - mod->irq_##status |= status; \ + mod->status |= status; \ else \ - mod->irq_##status &= ~status; \ + mod->status &= ~status; \ usbhs_irq_callback_update(priv, mod); \ }) @@ -488,6 +488,8 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) usbhs_pipe_data_sequence(pipe, pkt->sequence); pkt->sequence = -1; /* -1 sequence will be ignored */ + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); + ret = usbhsf_fifo_select(pipe, fifo, 1); if (ret < 0) return 0; @@ -594,6 +596,7 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) usbhs_pipe_data_sequence(pipe, pkt->sequence); pkt->sequence = -1; /* -1 sequence will be ignored */ + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); usbhs_pipe_enable(pipe); usbhsf_rx_irq_ctrl(pipe, 1); @@ -795,6 +798,7 @@ static void xfer_work(struct work_struct *work) dev_dbg(dev, " %s %d (%d/ %d)\n", fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans); usbhs_pipe_enable(pipe); usbhsf_dma_start(pipe, fifo); dma_async_issue_pending(chan); diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 61933a9..6a030b9 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -151,7 +151,7 @@ int usbhs_mod_probe(struct usbhs_priv *priv) goto mod_init_host_err; /* irq settings */ - ret = request_irq(priv->irq, usbhs_interrupt, + ret = devm_request_irq(dev, priv->irq, usbhs_interrupt, priv->irqflags, dev_name(dev), priv); if (ret) { dev_err(dev, "irq request err\n"); @@ -172,7 +172,6 @@ void usbhs_mod_remove(struct usbhs_priv *priv) { usbhs_mod_host_remove(priv); usbhs_mod_gadget_remove(priv); - free_irq(priv->irq, priv); } /* diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 28478ce..dd41f61 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -883,6 +883,16 @@ static int usbhsg_get_frame(struct usb_gadget *gadget) return usbhs_frame_get_num(priv); } +static int usbhsg_pullup(struct usb_gadget *gadget, int is_on) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + + usbhs_sys_function_pullup(priv, is_on); + + return 0; +} + static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); @@ -900,6 +910,7 @@ static struct usb_gadget_ops usbhsg_gadget_ops = { .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, + .pullup = usbhsg_pullup, }; static int usbhsg_start(struct usbhs_priv *priv) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 069cd76..3d3cd6c 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -85,6 +85,7 @@ struct usbhsh_ep { struct usbhsh_device *udev; /* attached udev */ struct usb_host_endpoint *ep; struct list_head ep_list; /* list to usbhsh_device */ + unsigned int counter; /* pipe attach counter */ }; #define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */ @@ -271,8 +272,12 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, /******************** spin lock ********************/ usbhs_lock(priv, flags); - if (unlikely(usbhsh_uep_to_pipe(uep))) { - dev_err(dev, "uep already has pipe\n"); + /* + * if uep has been attached to pipe, + * reuse it + */ + if (usbhsh_uep_to_pipe(uep)) { + ret = 0; goto usbhsh_pipe_attach_done; } @@ -320,6 +325,9 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, } usbhsh_pipe_attach_done: + if (0 == ret) + uep->counter++; + usbhs_unlock(priv, flags); /******************** spin unlock ******************/ @@ -346,7 +354,7 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, if (unlikely(!pipe)) { dev_err(dev, "uep doens't have pipe\n"); - } else { + } else if (1 == uep->counter--) { /* last user */ struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); @@ -391,6 +399,7 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, /* * init endpoint */ + uep->counter = 0; INIT_LIST_HEAD(&uep->ep_list); list_add_tail(&uep->ep_list, &udev->ep_list_head); @@ -686,9 +695,9 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, } if (usb_pipein(urb->pipe)) - pipe->handler = &usbhs_fifo_pio_pop_handler; + pipe->handler = &usbhs_fifo_dma_pop_handler; else - pipe->handler = &usbhs_fifo_pio_push_handler; + pipe->handler = &usbhs_fifo_dma_push_handler; buf = (void *)(urb->transfer_buffer + urb->actual_length); len = urb->transfer_buffer_length - urb->actual_length; @@ -921,6 +930,19 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, */ static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map) { + if (map) { + struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); + struct urb *urb = ureq->urb; + + /* it can not use scatter/gather */ + if (urb->num_sgs) + return -EINVAL; + + pkt->dma = urb->transfer_dma; + if (!pkt->dma) + return -EINVAL; + } + return 0; } @@ -946,7 +968,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep = urb->ep; struct usbhsh_device *new_udev = NULL; int is_dir_in = usb_pipein(urb->pipe); - int i; int ret; dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out"); @@ -992,13 +1013,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, * attach pipe to endpoint * see [image of mod_host] */ - for (i = 0; i < 1024; i++) { - ret = usbhsh_pipe_attach(hpriv, urb); - if (ret < 0) - msleep(100); - else - break; - } + ret = usbhsh_pipe_attach(hpriv, urb); if (ret < 0) { dev_err(dev, "pipe attach failed\n"); goto usbhsh_urb_enqueue_error_free_endpoint; @@ -1072,8 +1087,6 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) { struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); int roothub_id = 1; /* only 1 root hub */ /* @@ -1085,8 +1098,6 @@ static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) else *buf = 0; - dev_dbg(dev, "%s (%02x)\n", __func__, *buf); - return !!(*buf); } diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 122526c..7926e1c 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -93,6 +93,82 @@ static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) } /* + * PIPEnTRN/PIPEnTRE functions + */ +static void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int num = usbhs_pipe_number(pipe); + u16 reg; + + /* + * It is impossible to calculate address, + * since PIPEnTRN addresses were mapped randomly. + */ +#define CASE_PIPExTRN(a) \ + case 0x ## a: \ + reg = PIPE ## a ## TRN; \ + break; + + switch (num) { + CASE_PIPExTRN(1); + CASE_PIPExTRN(2); + CASE_PIPExTRN(3); + CASE_PIPExTRN(4); + CASE_PIPExTRN(5); + CASE_PIPExTRN(B); + CASE_PIPExTRN(C); + CASE_PIPExTRN(D); + CASE_PIPExTRN(E); + CASE_PIPExTRN(F); + CASE_PIPExTRN(9); + CASE_PIPExTRN(A); + default: + dev_err(dev, "unknown pipe (%d)\n", num); + return; + } + __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); +} + +static void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int num = usbhs_pipe_number(pipe); + u16 reg; + + /* + * It is impossible to calculate address, + * since PIPEnTRE addresses were mapped randomly. + */ +#define CASE_PIPExTRE(a) \ + case 0x ## a: \ + reg = PIPE ## a ## TRE; \ + break; + + switch (num) { + CASE_PIPExTRE(1); + CASE_PIPExTRE(2); + CASE_PIPExTRE(3); + CASE_PIPExTRE(4); + CASE_PIPExTRE(5); + CASE_PIPExTRE(B); + CASE_PIPExTRE(C); + CASE_PIPExTRE(D); + CASE_PIPExTRE(E); + CASE_PIPExTRE(F); + CASE_PIPExTRE(9); + CASE_PIPExTRE(A); + default: + dev_err(dev, "unknown pipe (%d)\n", num); + return; + } + + __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); +} + +/* * PIPEBUF */ static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) @@ -264,6 +340,31 @@ int usbhs_pipe_is_stall(struct usbhs_pipe *pipe) return (int)(pid == PID_STALL10 || pid == PID_STALL11); } +void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len) +{ + if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) + return; + + /* + * clear and disable transfer counter for IN/OUT pipe + */ + usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR); + + /* + * Only IN direction bulk pipe can use transfer count. + * Without using this function, + * received data will break if it was large data size. + * see PIPEnTRN/PIPEnTRE for detail + */ + if (usbhs_pipe_is_dir_in(pipe)) { + int maxp = usbhs_pipe_get_maxpacket(pipe); + + usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp)); + usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */ + } +} + + /* * pipe setup */ diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 3d80c7b..b476fde 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -88,6 +88,7 @@ void usbhs_pipe_enable(struct usbhs_pipe *pipe); void usbhs_pipe_disable(struct usbhs_pipe *pipe); void usbhs_pipe_stall(struct usbhs_pipe *pipe); int usbhs_pipe_is_stall(struct usbhs_pipe *pipe); +void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len); void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, u16 epnum, u16 maxp); |