From e1de81a57ccb09261708ea79e8c71747378f6ddd Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Fri, 11 Mar 2011 14:57:36 +0100 Subject: usb: musb: ux500: add ux500 specific code for gadget side Although U8500 and U5500 platforms use paltform dma, Inventra dma specific code can work for them for the most part. Only difference is for the Rx path where this patch is making use of request->short_not_ok to select dma mode. usb: musb: ux500: add dma name for ux500 usb: musb: ux500: add dma glue layer for ux500 DMA is mainly intended for mass storage class. Unaligned sizes and buffers are not supported. usb: musb: ux500: add configuration and build options for ux500 dma usb: musb: clear AUTOSET while clearing DMAENAB On the completion of tx dma, dma is disabled by clearing MUSB_TXCSR_DMAENAB in TXCSR. If MUSB_TXCSR_AUTOSET was set in txstate() it will remain set although it is not needed in PIO mode. Clear it as soon as it is not needed. usb: musb: ux500: copy dma mask from platform device to musb device musb code checks dma mask before calling dma hooks. usb: musb: do not release dma channel on channel_program failure Musb hcd releases dma channel (hw_ep->tx_channel / hw_ep->rx_channel ) if ->channel_program() fails. A null hw_ep->tx_channel is then used to continue the transfer in pio mode. Next call to musb_ep_program() will try to allocate the dma channel again. This patch allows the transfer to continue in pio mode if ->channel_program() fails without releasing the dma channel. usb: musb: restore rxcsr on channel_program failure Rxcsr is configured for dma transfer before calling ->channel_program(). Restore rxcsr if ->channel_program() fails. usb: musb: ux500: enable host side dma support Host side dma support for ux500 is enabled by piggybacking on Inventra dma support. Signed-off-by: Mian Yousaf Kaukab --- drivers/usb/musb/Kconfig | 15 +++++++++++++++ drivers/usb/musb/musb_core.h | 1 + drivers/usb/musb/musb_host.c | 25 +++++++++++-------------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index fc34b8b1191..448dc12f3ff 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -107,3 +107,18 @@ config USB_TUSB_OMAP_DMA help Enable DMA transfers on TUSB 6010 when OMAP DMA is available. +config USB_UX500_DMA + bool + depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY + default USB_MUSB_UX500 + help + Enable DMA transfers on UX500 platforms. + +config USB_MUSB_DEBUG + depends on USB_MUSB_HDRC + bool "Enable debugging messages" + default n + help + This enables musb debugging. To set the logging level use the debug + module parameter. Starting at level 3, per-transfer (urb, usb_request, + packet, or dma transfer) tracing may kick in. diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index b3c065ab9db..0de1fad9a1f 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -276,6 +276,7 @@ struct musb_hw_ep { u8 rx_reinit; u8 tx_reinit; + bool do_tx_pio; /* peripheral side */ struct musb_ep ep_in; /* TX */ diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 8b2473fa0f4..fbed2b34892 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -290,7 +290,7 @@ start: dev_dbg(musb->controller, "Start TX%d %s\n", epnum, hw_ep->tx_channel ? "dma" : "pio"); - if (!hw_ep->tx_channel) + if (!hw_ep->tx_channel || hw_ep->do_tx_pio) musb_h_tx_start(hw_ep); else if (is_cppi_enabled() || tusb_dma_omap()) musb_h_tx_dma_start(hw_ep); @@ -615,7 +615,7 @@ static bool musb_tx_dma_program(struct dma_controller *dma, u16 csr; u8 mode; -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) if (length > channel->max_len) length = channel->max_len; @@ -656,8 +656,6 @@ static bool musb_tx_dma_program(struct dma_controller *dma, if (!dma->channel_program(channel, pkt_size, mode, urb->transfer_dma + offset, length)) { - dma->channel_release(channel); - hw_ep->tx_channel = NULL; csr = musb_readw(epio, MUSB_TXCSR); csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); @@ -792,11 +790,11 @@ static void musb_ep_program(struct musb *musb, u8 epnum, else load_count = min((u32) packet_sz, len); - if (dma_channel && musb_tx_dma_program(dma_controller, + if (!dma_channel || !musb_tx_dma_program(dma_controller, hw_ep, qh, urb, offset, len)) - load_count = 0; + hw_ep->do_tx_pio = true; - if (load_count) { + if (hw_ep->do_tx_pio) { /* PIO to load FIFO */ qh->segsize = load_count; musb_write_fifo(hw_ep, load_count, buf); @@ -1100,7 +1098,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) struct urb *urb = next_urb(qh); u32 status = 0; void __iomem *mbase = musb->mregs; - struct dma_channel *dma; + struct dma_channel *dma = NULL; bool transfer_pending = false; musb_ep_select(mbase, epnum); @@ -1533,7 +1531,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* FIXME this is _way_ too much in-line logic for Mentor DMA */ -#ifndef CONFIG_USB_INVENTRA_DMA +#if !defined(CONFIG_USB_INVENTRA_DMA) && !defined(CONFIG_USB_UX500_DMA) if (rx_csr & MUSB_RXCSR_H_REQPKT) { /* REVISIT this happened for a while on some short reads... * the cleanup still needs investigation... looks bad... @@ -1565,7 +1563,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) | MUSB_RXCSR_RXPKTRDY); musb_writew(hw_ep->regs, MUSB_RXCSR, val); -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) if (usb_pipeisoc(pipe)) { struct usb_iso_packet_descriptor *d; @@ -1621,7 +1619,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) } /* we are expecting IN packets */ -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) if (dma) { struct dma_controller *c; u16 rx_count; @@ -1729,10 +1727,9 @@ void musb_host_rx(struct musb *musb, u8 epnum) dma->desired_mode, buf, length); if (!ret) { - c->channel_release(dma); - hw_ep->rx_channel = NULL; dma = NULL; - /* REVISIT reset CSR */ + /* Restore CSR */ + musb_writew(epio, MUSB_RXCSR, rx_csr); } } #endif /* Mentor DMA */ -- cgit v1.2.3 From 44ca0f780269d7e86df095dbd96368e88e32dfa9 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Thu, 24 Mar 2011 11:53:38 +0100 Subject: usb: usb_storage: do not align length of request for CBW to maxp size Mass-storage and file-storage gadgets align the length to maximum-packet-size when preparing the request to receive CBW. This is unnecessary and prevents the controller driver from knowing that a short-packet is expected. It is incorrect to set short_not_ok when preparing the request to receive CBW. CBW will be a short-packet so short_not_ok must not be set. This patch makes bh->bulk_out_intended_length unnecessary so it is also removed. Signed-off-by: Mian Yousaf Kaukab --- drivers/usb/gadget/f_mass_storage.c | 24 ++++-------------------- drivers/usb/gadget/file_storage.c | 28 ++++++---------------------- drivers/usb/gadget/storage_common.c | 7 ------- 3 files changed, 10 insertions(+), 49 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 5b933958200..4a10e539d34 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -475,20 +475,6 @@ static int exception_in_progress(struct fsg_common *common) return common->state > FSG_STATE_IDLE; } -/* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_common *common, - struct fsg_buffhd *bh, unsigned int length) -{ - unsigned int rem; - - bh->bulk_out_intended_length = length; - rem = length % common->bulk_out_maxpacket; - if (rem > 0) - length += common->bulk_out_maxpacket - rem; - bh->outreq->length = length; -} - - /*-------------------------------------------------------------------------*/ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) @@ -587,9 +573,9 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_buffhd *bh = req->context; dump_msg(common, "bulk-out", req->buf, req->actual); - if (req->status || req->actual != bh->bulk_out_intended_length) + if (req->status || req->actual != req->length) DBG(common, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, bh->bulk_out_intended_length); + req->status, req->actual, req->length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); @@ -981,7 +967,6 @@ static int do_write(struct fsg_common *common) * the bulk-out maxpacket size */ bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; bh->outreq->short_not_ok = 1; if (!start_out_transfer(common, bh)) /* Dunno what to do if common->fsg is NULL */ @@ -1627,7 +1612,6 @@ static int throw_away_data(struct fsg_common *common) * the bulk-out maxpacket size. */ bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; bh->outreq->short_not_ok = 1; if (!start_out_transfer(common, bh)) /* Dunno what to do if common->fsg is NULL */ @@ -2296,8 +2280,8 @@ static int get_next_command(struct fsg_common *common) } /* Queue a request to read a Bulk-only CBW */ - set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN); - bh->outreq->short_not_ok = 1; + bh->outreq->length = USB_BULK_CB_WRAP_LEN; + bh->outreq->short_not_ok = 0; if (!start_out_transfer(common, bh)) /* Don't know what to do if common->fsg is NULL */ return -EIO; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 639e14a2fd1..06960f94866 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -497,19 +497,6 @@ static int exception_in_progress(struct fsg_dev *fsg) return (fsg->state > FSG_STATE_IDLE); } -/* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_dev *fsg, - struct fsg_buffhd *bh, unsigned int length) -{ - unsigned int rem; - - bh->bulk_out_intended_length = length; - rem = length % fsg->bulk_out_maxpacket; - if (rem > 0) - length += fsg->bulk_out_maxpacket - rem; - bh->outreq->length = length; -} - static struct fsg_dev *the_fsg; static struct usb_gadget_driver fsg_driver; @@ -730,10 +717,9 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_buffhd *bh = req->context; dump_msg(fsg, "bulk-out", req->buf, req->actual); - if (req->status || req->actual != bh->bulk_out_intended_length) + if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, - bh->bulk_out_intended_length); + req->status, req->actual, req->length); if (req->status == -ECONNRESET) // Request was cancelled usb_ep_fifo_flush(ep); @@ -1355,8 +1341,7 @@ static int do_write(struct fsg_dev *fsg) /* amount is always divisible by 512, hence by * the bulk-out maxpacket size */ - bh->outreq->length = bh->bulk_out_intended_length = - amount; + bh->outreq->length = amount; bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); @@ -1985,8 +1970,7 @@ static int throw_away_data(struct fsg_dev *fsg) /* amount is always divisible by 512, hence by * the bulk-out maxpacket size */ - bh->outreq->length = bh->bulk_out_intended_length = - amount; + bh->outreq->length = amount; bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); @@ -2665,8 +2649,8 @@ static int get_next_command(struct fsg_dev *fsg) } /* Queue a request to read a Bulk-only CBW */ - set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); - bh->outreq->short_not_ok = 1; + bh->outreq->length = USB_BULK_CB_WRAP_LEN; + bh->outreq->short_not_ok = 0; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index d3dd227a2bf..795ce0f04b2 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -286,13 +286,6 @@ struct fsg_buffhd { enum fsg_buffer_state state; struct fsg_buffhd *next; - /* - * The NetChip 2280 is faster, and handles some protocol faults - * better, if we don't submit any short bulk-out read requests. - * So we will record the intended request length here. - */ - unsigned int bulk_out_intended_length; - struct usb_request *inreq; int inreq_busy; struct usb_request *outreq; -- cgit v1.2.3 From bbfd94bcc217787f814ed9aac16707f03b700f4c Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Wed, 6 Apr 2011 14:05:08 +0200 Subject: usb: otg: ab8500-usb: workaround for connector id detection Signed-off-by: Mian Yousaf Kaukab --- drivers/usb/otg/ab8500-usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 07ccea9ada4..1e2adcd1f92 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -526,6 +526,8 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) goto fail1; } + /* Needed to enable ID detection. */ + ab8500_usb_wd_workaround(ab); dev_info(&pdev->dev, "AB8500 usb driver initialized\n"); return 0; -- cgit v1.2.3 From 9df1447c51a14e477692613d68865bc502f80e8b Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Fri, 8 Apr 2011 17:41:52 +0200 Subject: usb: otg: ab8500-usb: let controller driver manage state Changes to the state made here conflicts with the changes made within the usb controller driver usb: otg: ab8500-usb: split phy_control into separate enable and disable functions Preparing to add clocks, regulators and qos control usb: otg: ab8500-usb: update interrupt registrations and handlers Ab8500 v1 and v2 both do not update link status unless phy is disabled. This patch adds host disconnect and peripheral disconnect interrupts for v2 as well. Interrupts handlers are thus renamed to reflect this change. Interrupts setup functions are combined into one as now there are common interrupts for v1 and v2. usb: otg: ab8500-usb: only disable previously enabled phy Keep track of the transceiver mode only disable the mode which was previously enabled. usb: otg: ab8500-usb: add transceiver clock control usb: otg: ab8500-usb: add power supply control usb: otg: ab8500-usb: add platform quality of service hooks usb: otg: ab8500-usb: update log message and add chip revision usb: otg: ab8500-usb: workaround for multiple connection detection This patch implements fix for ab8500 chip v2 bug # 31952 usb: otg: ab8500-usb: return correct error status in irq setup Rreturn correct error status if platform_get_irq_byname() fails Reported-by: Philippe Langlais usb: otg: ab8500-usb: fix unbalanced clock and regulator disable warnings To prevent clock and regulator frameworks from complaining, only disable the host or peripheral phy if they were enabled. Reported-by: Sakethram Bommisetti Signed-off-by: Mian Yousaf Kaukab --- drivers/usb/otg/ab8500-usb.c | 395 +++++++++++++++++++++++++++++-------------- 1 file changed, 271 insertions(+), 124 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 1e2adcd1f92..a3b23567b36 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -29,22 +29,29 @@ #include #include #include +#include +#include #include #include +#include +#include #define AB8500_MAIN_WD_CTRL_REG 0x01 #define AB8500_USB_LINE_STAT_REG 0x80 #define AB8500_USB_PHY_CTRL_REG 0x8A +#define AB8500_VBUS_CTRL_REG 0x82 #define AB8500_BIT_OTG_STAT_ID (1 << 0) #define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0) #define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1) #define AB8500_BIT_WD_CTRL_ENABLE (1 << 0) #define AB8500_BIT_WD_CTRL_KICK (1 << 1) +#define AB8500_BIT_VBUS_ENABLE (1 << 0) #define AB8500_V1x_LINK_STAT_WAIT (HZ/10) #define AB8500_WD_KICK_DELAY_US 100 /* usec */ #define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */ +#define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */ #define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */ /* Usb line status register */ @@ -67,6 +74,12 @@ enum ab8500_usb_link_status { USB_LINK_NOT_VALID_LINK }; +enum ab8500_usb_mode { + USB_IDLE = 0, + USB_PERIPHERAL, + USB_HOST +}; + struct ab8500_usb { struct otg_transceiver otg; struct device *dev; @@ -80,6 +93,11 @@ struct ab8500_usb { struct work_struct phy_dis_work; unsigned long link_status_wait; int rev; + enum ab8500_usb_mode mode; + struct clk *sysclk; + struct regulator *v_ape; + struct regulator *v_musb; + struct regulator *v_ulpi; }; static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x) @@ -113,40 +131,93 @@ static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) 0); } -static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host, +static void ab8500_usb_regulator_ctrl(struct ab8500_usb *ab, bool sel_host, bool enable) { - u8 ctrl_reg; - abx500_get_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_PHY_CTRL_REG, - &ctrl_reg); - if (sel_host) { - if (enable) - ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN; - else - ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN; + if (enable) { + regulator_enable(ab->v_ape); + regulator_enable(ab->v_ulpi); + regulator_enable(ab->v_musb); + + if (sel_host && (ab->rev < 0x20)) + /* Enable v-usb */ + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_REGU_CTRL1, + AB8500_VBUS_CTRL_REG, + AB8500_BIT_VBUS_ENABLE, + AB8500_BIT_VBUS_ENABLE); } else { - if (enable) - ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN; - else - ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN; + regulator_disable(ab->v_musb); + regulator_disable(ab->v_ulpi); + regulator_disable(ab->v_ape); + + if (sel_host && (ab->rev < 0x20)) + /* Disable v-usb */ + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_REGU_CTRL1, + AB8500_VBUS_CTRL_REG, + AB8500_BIT_VBUS_ENABLE, + 0); } +} - abx500_set_register_interruptible(ab->dev, +static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) +{ + u8 bit; + bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : + AB8500_BIT_PHY_CTRL_DEVICE_EN; + + clk_enable(ab->sysclk); + + ab8500_usb_regulator_ctrl(ab, sel_host, true); + + prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + (char *)dev_name(ab->dev), 100); + + abx500_mask_and_set_register_interruptible(ab->dev, AB8500_USB, AB8500_USB_PHY_CTRL_REG, - ctrl_reg); + bit, + bit); /* Needed to enable the phy.*/ - if (enable) - ab8500_usb_wd_workaround(ab); + ab8500_usb_wd_workaround(ab); +} + +static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) +{ + u8 bit; + bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : + AB8500_BIT_PHY_CTRL_DEVICE_EN; + + /* Wrokaround for v2.0 bug # 31952 */ + if (ab->rev == 0x20) { + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + bit, + bit); + udelay(AB8500_V20_31952_DISABLE_DELAY_US); + } + + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + bit, + 0); + + clk_disable(ab->sysclk); + + ab8500_usb_regulator_ctrl(ab, sel_host, false); + + prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + (char *)dev_name(ab->dev), 50); } -#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_ctrl(ab, true, true) -#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_ctrl(ab, true, false) -#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true) -#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false) +#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_enable(ab, true) +#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_disable(ab, true) +#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_enable(ab, false) +#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_disable(ab, false) static int ab8500_usb_link_status_update(struct ab8500_usb *ab) { @@ -166,10 +237,11 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) case USB_LINK_NOT_CONFIGURED: case USB_LINK_RESERVED: case USB_LINK_NOT_VALID_LINK: - /* TODO: Disable regulators. */ - ab8500_usb_host_phy_dis(ab); - ab8500_usb_peri_phy_dis(ab); - ab->otg.state = OTG_STATE_B_IDLE; + if (ab->mode == USB_HOST) + ab8500_usb_host_phy_dis(ab); + else if (ab->mode == USB_PERIPHERAL) + ab8500_usb_peri_phy_dis(ab); + ab->mode = USB_IDLE; ab->otg.default_a = false; ab->vbus_draw = 0; event = USB_EVENT_NONE; @@ -182,8 +254,8 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) case USB_LINK_HOST_CHG_HS: case USB_LINK_HOST_CHG_HS_CHIRP: if (ab->otg.gadget) { - /* TODO: Enable regulators. */ ab8500_usb_peri_phy_en(ab); + ab->mode = USB_PERIPHERAL; v = ab->otg.gadget; } event = USB_EVENT_VBUS; @@ -191,11 +263,10 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) case USB_LINK_HM_IDGND: if (ab->otg.host) { - /* TODO: Enable regulators. */ ab8500_usb_host_phy_en(ab); + ab->mode = USB_HOST; v = ab->otg.host; } - ab->otg.state = OTG_STATE_A_IDLE; ab->otg.default_a = true; event = USB_EVENT_ID; break; @@ -225,7 +296,7 @@ static void ab8500_usb_delayed_work(struct work_struct *work) ab8500_usb_link_status_update(ab); } -static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data) +static irqreturn_t ab8500_usb_v1x_connect_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; @@ -235,20 +306,25 @@ static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data) +static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; /* Link status will not be updated till phy is disabled. */ - ab8500_usb_peri_phy_dis(ab); + if (ab->mode == USB_HOST) + ab8500_usb_host_phy_dis(ab); + else if (ab->mode == USB_PERIPHERAL) + ab8500_usb_peri_phy_dis(ab); + ab->mode = USB_IDLE; - /* Wait for link status to become stable. */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); + if (ab->rev < 0x20) + /* Wait for link status to become stable. */ + schedule_delayed_work(&ab->dwork, ab->link_status_wait); return IRQ_HANDLED; } -static irqreturn_t ab8500_usb_v20_irq(int irq, void *data) +static irqreturn_t ab8500_usb_v20_link_status_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; @@ -312,12 +388,10 @@ static int ab8500_usb_set_peripheral(struct otg_transceiver *otg, */ if (!gadget) { - /* TODO: Disable regulators. */ ab->otg.gadget = NULL; schedule_work(&ab->phy_dis_work); } else { ab->otg.gadget = gadget; - ab->otg.state = OTG_STATE_B_IDLE; /* Phy will not be enabled if cable is already * plugged-in. Schedule to enable phy. @@ -345,7 +419,6 @@ static int ab8500_usb_set_host(struct otg_transceiver *otg, */ if (!host) { - /* TODO: Disable regulators. */ ab->otg.host = NULL; schedule_work(&ab->phy_dis_work); } else { @@ -360,113 +433,166 @@ static int ab8500_usb_set_host(struct otg_transceiver *otg, return 0; } +static void ab8500_usb_regulator_put(struct ab8500_usb *ab) +{ + + if (ab->v_ape) + regulator_put(ab->v_ape); + + if (ab->v_ulpi) + regulator_put(ab->v_ulpi); + + if (ab->v_musb) + regulator_put(ab->v_musb); +} + +static int ab8500_usb_regulator_get(struct ab8500_usb *ab) +{ + int err; + + ab->v_ape = regulator_get(ab->dev, "v-ape"); + if (IS_ERR(ab->v_ape)) { + dev_err(ab->dev, "Could not get v-ape supply\n"); + err = PTR_ERR(ab->v_ape); + goto reg_error; + } + + ab->v_ulpi = regulator_get(ab->dev, "vddulpivio18"); + if (IS_ERR(ab->v_ulpi)) { + dev_err(ab->dev, "Could not get vddulpivio18 supply\n"); + err = PTR_ERR(ab->v_ulpi); + goto reg_error; + } + + ab->v_musb = regulator_get(ab->dev, "musb_1v8"); + if (IS_ERR(ab->v_musb)) { + dev_err(ab->dev, "Could not get musb_1v8 supply\n"); + err = PTR_ERR(ab->v_musb); + goto reg_error; + } + + return 0; + +reg_error: + ab8500_usb_regulator_put(ab); + return err; +} + static void ab8500_usb_irq_free(struct ab8500_usb *ab) { - if (ab->rev < 0x20) { + if (ab->irq_num_id_rise) free_irq(ab->irq_num_id_rise, ab); + + if (ab->irq_num_id_fall) free_irq(ab->irq_num_id_fall, ab); + + if (ab->irq_num_vbus_rise) free_irq(ab->irq_num_vbus_rise, ab); + + if (ab->irq_num_vbus_fall) free_irq(ab->irq_num_vbus_fall, ab); - } else { + + if (ab->irq_num_link_status) free_irq(ab->irq_num_link_status, ab); - } } -static int ab8500_usb_v1x_res_setup(struct platform_device *pdev, +static int ab8500_usb_irq_setup(struct platform_device *pdev, struct ab8500_usb *ab) { int err; + int irq; - ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R"); - if (ab->irq_num_id_rise < 0) { - dev_err(&pdev->dev, "ID rise irq not found\n"); - return ab->irq_num_id_rise; - } - err = request_threaded_irq(ab->irq_num_id_rise, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-id-rise", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for ID rise irq\n"); - goto fail0; + if (ab->rev < 0x20) { + irq = platform_get_irq_byname(pdev, "ID_WAKEUP_R"); + if (irq < 0) { + err = irq; + dev_err(&pdev->dev, "ID rise irq not found\n"); + goto irq_fail; + } + err = request_threaded_irq(irq, NULL, + ab8500_usb_v1x_connect_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-id-rise", ab); + if (err < 0) { + dev_err(ab->dev, + "request_irq failed for ID rise irq\n"); + goto irq_fail; + } + ab->irq_num_id_rise = irq; + + irq = platform_get_irq_byname(pdev, "VBUS_DET_R"); + if (irq < 0) { + err = irq; + dev_err(&pdev->dev, "VBUS rise irq not found\n"); + goto irq_fail; + } + err = request_threaded_irq(irq, NULL, + ab8500_usb_v1x_connect_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-vbus-rise", ab); + if (err < 0) { + dev_err(ab->dev, + "request_irq failed for Vbus rise irq\n"); + goto irq_fail; + } + ab->irq_num_vbus_rise = irq; + }else { /* 0x20 */ + irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS"); + if (irq < 0) { + err = irq; + dev_err(&pdev->dev, "Link status irq not found\n"); + goto irq_fail; + } + + err = request_threaded_irq(irq, NULL, + ab8500_usb_v20_link_status_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-link-status", ab); + if (err < 0) { + dev_err(ab->dev, + "request_irq failed for link status irq\n"); + return err; + } + ab->irq_num_link_status = irq; } - ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F"); - if (ab->irq_num_id_fall < 0) { + irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F"); + if (irq < 0) { + err = irq; dev_err(&pdev->dev, "ID fall irq not found\n"); return ab->irq_num_id_fall; } - err = request_threaded_irq(ab->irq_num_id_fall, NULL, - ab8500_usb_v1x_common_irq, + err = request_threaded_irq(irq, NULL, + ab8500_usb_disconnect_irq, IRQF_NO_SUSPEND | IRQF_SHARED, "usb-id-fall", ab); if (err < 0) { dev_err(ab->dev, "request_irq failed for ID fall irq\n"); - goto fail1; - } - - ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R"); - if (ab->irq_num_vbus_rise < 0) { - dev_err(&pdev->dev, "VBUS rise irq not found\n"); - return ab->irq_num_vbus_rise; - } - err = request_threaded_irq(ab->irq_num_vbus_rise, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-vbus-rise", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for Vbus rise irq\n"); - goto fail2; + goto irq_fail; } + ab->irq_num_id_fall = irq; - ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F"); - if (ab->irq_num_vbus_fall < 0) { + irq = platform_get_irq_byname(pdev, "VBUS_DET_F"); + if (irq < 0) { + err = irq; dev_err(&pdev->dev, "VBUS fall irq not found\n"); - return ab->irq_num_vbus_fall; + goto irq_fail; } - err = request_threaded_irq(ab->irq_num_vbus_fall, NULL, - ab8500_usb_v1x_vbus_fall_irq, + err = request_threaded_irq(irq, NULL, + ab8500_usb_disconnect_irq, IRQF_NO_SUSPEND | IRQF_SHARED, "usb-vbus-fall", ab); if (err < 0) { dev_err(ab->dev, "request_irq failed for Vbus fall irq\n"); - goto fail3; + goto irq_fail; } + ab->irq_num_vbus_fall = irq; return 0; -fail3: - free_irq(ab->irq_num_vbus_rise, ab); -fail2: - free_irq(ab->irq_num_id_fall, ab); -fail1: - free_irq(ab->irq_num_id_rise, ab); -fail0: - return err; -} - -static int ab8500_usb_v2_res_setup(struct platform_device *pdev, - struct ab8500_usb *ab) -{ - int err; - - ab->irq_num_link_status = platform_get_irq_byname(pdev, - "USB_LINK_STATUS"); - if (ab->irq_num_link_status < 0) { - dev_err(&pdev->dev, "Link status irq not found\n"); - return ab->irq_num_link_status; - } - err = request_threaded_irq(ab->irq_num_link_status, NULL, - ab8500_usb_v20_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-link-status", ab); - if (err < 0) { - dev_err(ab->dev, - "request_irq failed for link status irq\n"); - return err; - } - - return 0; +irq_fail: + ab8500_usb_irq_free(ab); + return err; } static int __devinit ab8500_usb_probe(struct platform_device *pdev) @@ -492,7 +618,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) ab->rev = rev; ab->otg.dev = ab->dev; ab->otg.label = "ab8500"; - ab->otg.state = OTG_STATE_UNDEFINED; + ab->otg.state = OTG_STATE_B_IDLE; ab->otg.set_host = ab8500_usb_set_host; ab->otg.set_peripheral = ab8500_usb_set_peripheral; ab->otg.set_suspend = ab8500_usb_set_suspend; @@ -510,29 +636,44 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) /* all: Disable phy when called from set_host and set_peripheral */ INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); - if (ab->rev < 0x20) { - err = ab8500_usb_v1x_res_setup(pdev, ab); - ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT; - } else { - err = ab8500_usb_v2_res_setup(pdev, ab); + err = ab8500_usb_regulator_get(ab); + if (err) + goto fail0; + + ab->sysclk = clk_get(ab->dev, "sysclk"); + if (IS_ERR(ab->sysclk)) { + err = PTR_ERR(ab->sysclk); + goto fail1; } + if (ab->rev < 0x20) + ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT; + + err = ab8500_usb_irq_setup(pdev, ab); if (err < 0) - goto fail0; + goto fail2; err = otg_set_transceiver(&ab->otg); if (err) { dev_err(&pdev->dev, "Can't register transceiver\n"); - goto fail1; + goto fail3; } /* Needed to enable ID detection. */ ab8500_usb_wd_workaround(ab); - dev_info(&pdev->dev, "AB8500 usb driver initialized\n"); + + prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + (char *)dev_name(ab->dev), 50); + + dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", ab->rev); return 0; -fail1: +fail3: ab8500_usb_irq_free(ab); +fail2: + clk_put(ab->sysclk); +fail1: + ab8500_usb_regulator_put(ab); fail0: kfree(ab); return err; @@ -550,8 +691,14 @@ static int __devexit ab8500_usb_remove(struct platform_device *pdev) otg_set_transceiver(NULL); - ab8500_usb_host_phy_dis(ab); - ab8500_usb_peri_phy_dis(ab); + if (ab->mode == USB_HOST) + ab8500_usb_host_phy_dis(ab); + else if (ab->mode == USB_PERIPHERAL) + ab8500_usb_peri_phy_dis(ab); + + clk_put(ab->sysclk); + + ab8500_usb_regulator_put(ab); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 88d6a323f93036f958c47b412426a66d5ec1f843 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Tue, 12 Apr 2011 14:40:39 +0200 Subject: usb: otg: ab8500-usb: report vbus draw in the notifier call Signed-off-by: Mian Yousaf Kaukab --- drivers/usb/otg/ab8500-usb.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index a3b23567b36..cfb6474d07c 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -223,7 +223,6 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) { u8 reg; enum ab8500_usb_link_status lsts; - void *v = NULL; enum usb_xceiv_events event; abx500_get_register_interruptible(ab->dev, @@ -256,7 +255,6 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) if (ab->otg.gadget) { ab8500_usb_peri_phy_en(ab); ab->mode = USB_PERIPHERAL; - v = ab->otg.gadget; } event = USB_EVENT_VBUS; break; @@ -265,7 +263,6 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) if (ab->otg.host) { ab8500_usb_host_phy_en(ab); ab->mode = USB_HOST; - v = ab->otg.host; } ab->otg.default_a = true; event = USB_EVENT_ID; @@ -283,7 +280,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) break; } - atomic_notifier_call_chain(&ab->otg.notifier, event, v); + atomic_notifier_call_chain(&ab->otg.notifier, event, &ab->vbus_draw); return 0; } @@ -356,16 +353,11 @@ static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA) ab->vbus_draw = mA; - if (mA) - atomic_notifier_call_chain(&ab->otg.notifier, - USB_EVENT_ENUMERATED, ab->otg.gadget); + atomic_notifier_call_chain(&ab->otg.notifier, + USB_EVENT_VBUS, &ab->vbus_draw); return 0; } -/* TODO: Implement some way for charging or other drivers to read - * ab->vbus_draw. - */ - static int ab8500_usb_set_suspend(struct otg_transceiver *x, int suspend) { /* TODO */ -- cgit v1.2.3 From e7b124e72056c34ae01b87cc81a1a208adda453c Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Fri, 13 Aug 2010 14:14:54 +0200 Subject: Workaround for hardware problem in host mode for the MUSB chipset. Add missed TXPKTRDY check. FIFOFLUSH is broken when a real packet is in the FIFO. This hardware feature only works when the FIFO is empty. The workaround described requires limiting the maximum number of USB devices to 126, 128 - 2. Signed-off-by: Hans Petter Selasky Signed-off-by: Praveena Nadahally Acked-by: Linus Walleij --- drivers/usb/core/hub.c | 8 +++++--- drivers/usb/musb/musb_host.c | 45 +++++++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a428aa080a3..72150c7ea3a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1579,12 +1579,14 @@ static void choose_devnum(struct usb_device *udev) * bus->devnum_next. */ devnum = find_next_zero_bit(bus->devmap.devicemap, 128, bus->devnum_next); - if (devnum >= 128) + /* Due to Hardware bugs we need to reserve a device address + * for flushing of endpoints. */ + if (devnum >= 127) devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1); - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + bus->devnum_next = devnum >= 126 ? 1 : devnum + 1; } - if (devnum < 128) { + if (devnum < 127) { set_bit(devnum, bus->devmap.devicemap); udev->devnum = devnum; } diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index fbed2b34892..bafe726ef2a 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -108,24 +108,41 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) { struct musb *musb = ep->musb; void __iomem *epio = ep->regs; + void __iomem *regs = ep->musb->mregs; u16 csr; - u16 lastcsr = 0; - int retries = 1000; + u8 addr; + int retries = 3000; /* 3ms */ + /* + * NOTE: We are using a hack here because the FIFO-FLUSH + * bit is broken in hardware! The hack consists of changing + * the TXFUNCADDR to an unused device address and waiting + * for any pending USB packets to hit the 3-strikes and your + * gone rule. + */ + addr = musb_readb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, MUSB_TXFUNCADDR)); csr = musb_readw(epio, MUSB_TXCSR); while (csr & MUSB_TXCSR_FIFONOTEMPTY) { - if (csr != lastcsr) - dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr); - lastcsr = csr; - csr |= MUSB_TXCSR_FLUSHFIFO; - musb_writew(epio, MUSB_TXCSR, csr); + musb_writeb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, + MUSB_TXFUNCADDR), 127); csr = musb_readw(epio, MUSB_TXCSR); - if (WARN(retries-- < 1, - "Could not flush host TX%d fifo: csr: %04x\n", - ep->epnum, csr)) - return; - mdelay(1); + retries--; + if (retries == 0) { + /* can happen if the USB clocks are OFF */ + DBG(3, "Could not flush host TX%d " + "fifo: csr=0x%04x\n", ep->epnum, csr); + break; + } + udelay(1); } + /* clear any errors */ + csr &= ~(MUSB_TXCSR_H_ERROR + | MUSB_TXCSR_H_RXSTALL + | MUSB_TXCSR_H_NAKTIMEOUT); + musb_writew(epio, MUSB_TXCSR, csr); + + /* restore endpoint address */ + musb_writeb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, MUSB_TXFUNCADDR), addr); } static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) @@ -1128,7 +1145,9 @@ void musb_host_tx(struct musb *musb, u8 epnum) dev_dbg(musb->controller, "TX 3strikes on ep=%d\n", epnum); status = -ETIMEDOUT; - + } else if (tx_csr & MUSB_TXCSR_TXPKTRDY) { + /* BUSY - can happen during USB transfer cancel */ + return; } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum); -- cgit v1.2.3 From 9a9063201b990ee53781451deebde5aea8298c3c Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 14 Oct 2011 11:59:34 +0200 Subject: arm: ux500: common dbx500 prcmu driver api This patch updates the PRCMU driver API to be the same (as far as possible) in U8500 and U4500. - has been renamed . - The platform specific APIs have moved to and (but these should not be directly included). - The PRCMU QoS API has been put in . ST Ericsson ID: 334772 ST Ericsson FOSS-OUT ID: trivial ST Ericsson Linux next: 318371 Change-Id: I6ce117ec35ebf2e987178ccacce09afb554d2736 Signed-off-by: Mattias Nilsson Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/23863 Reviewed-by: Jonas ABERG --- drivers/usb/otg/ab8500-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index cfb6474d07c..e69c9988ea9 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #define AB8500_MAIN_WD_CTRL_REG 0x01 #define AB8500_USB_LINE_STAT_REG 0x80 -- cgit v1.2.3 From bc3c1a76d6fe4f721b69276dab2daefaeab476de Mon Sep 17 00:00:00 2001 From: Robert Marklund Date: Thu, 23 Jun 2011 13:23:32 +0200 Subject: musb: Update print for change in 3.0 Change-Id: Ic543021ab89f519ac8811b4608ce9e7ac04ef464 Signed-off-by: Robert Marklund --- drivers/usb/musb/musb_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index bafe726ef2a..73ebcca75b0 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -129,7 +129,7 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) retries--; if (retries == 0) { /* can happen if the USB clocks are OFF */ - DBG(3, "Could not flush host TX%d " + dev_dbg(musb->controller, "Could not flush host TX%d " "fifo: csr=0x%04x\n", ep->epnum, csr); break; } -- cgit v1.2.3 From dcaadb35b4b6cb131e5dd0d4eea6052aede081be Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 16 Jun 2011 11:38:23 +0530 Subject: USB:Dedicated charger connect issue on ABv3 During dedicated charger disconnect, (USB PHY enable - delay - disable) sequence is no longer done for platforms using ABv3. This sequence was done for ABv2 to have multiple dedicated charger detection working. Change-Id: Id27e8f0da9ad65c9ae692048c162402453e18592 Signed-off-by: Sakethram Bommisetti Signed-off-by: dushyanth.sr Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25191 Reviewed-by: Philippe LANGLAIS --- drivers/usb/otg/ab8500-usb.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index e69c9988ea9..25de231a012 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -77,7 +77,8 @@ enum ab8500_usb_link_status { enum ab8500_usb_mode { USB_IDLE = 0, USB_PERIPHERAL, - USB_HOST + USB_HOST, + USB_DEDICATED_CHG }; struct ab8500_usb { @@ -170,7 +171,6 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) clk_enable(ab->sysclk); ab8500_usb_regulator_ctrl(ab, sel_host, true); - prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 100); @@ -184,12 +184,8 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) ab8500_usb_wd_workaround(ab); } -static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) +static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab,u8 bit) { - u8 bit; - bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : - AB8500_BIT_PHY_CTRL_DEVICE_EN; - /* Wrokaround for v2.0 bug # 31952 */ if (ab->rev == 0x20) { abx500_mask_and_set_register_interruptible(ab->dev, @@ -199,6 +195,15 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) bit); udelay(AB8500_V20_31952_DISABLE_DELAY_US); } +} + +static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) +{ + u8 bit; + bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : + AB8500_BIT_PHY_CTRL_DEVICE_EN; + + ab8500_usb_wd_linkstatus(ab,bit); abx500_mask_and_set_register_interruptible(ab->dev, AB8500_USB, @@ -276,6 +281,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) case USB_LINK_ACA_RID_C_HS_CHIRP: case USB_LINK_DEDICATED_CHG: /* TODO: vbus_draw */ + ab->mode = USB_DEDICATED_CHG; event = USB_EVENT_CHARGER; break; } @@ -312,6 +318,14 @@ static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) ab8500_usb_host_phy_dis(ab); else if (ab->mode == USB_PERIPHERAL) ab8500_usb_peri_phy_dis(ab); + else if (ab->mode == USB_DEDICATED_CHG && ab->rev == 0x20) { + ab8500_usb_wd_linkstatus(ab,AB8500_BIT_PHY_CTRL_DEVICE_EN); + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_BIT_PHY_CTRL_DEVICE_EN, + 0); + } ab->mode = USB_IDLE; if (ab->rev < 0x20) -- cgit v1.2.3 From a0c2e019b2ed832107a775db90d51b70059eeec5 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 28 Jun 2011 14:04:56 +0530 Subject: USB:Software fix for usb eye diagram issue when drawing more than 100mA AB V2 has eye diagram issues when drawing more than 100mA from VBUS.So setting charging current to 100mA in case of standard host Change-Id: Iaa5eb5751a4b0665fbe6f6148b712ffa9f96a06b Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25958 Reviewed-by: Praveena NADAHALLY Reviewed-by: Philippe LANGLAIS --- drivers/usb/otg/ab8500-usb.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 25de231a012..fd5943b7d38 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -356,6 +356,21 @@ static void ab8500_usb_phy_disable_work(struct work_struct *work) ab8500_usb_peri_phy_dis(ab); } +static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) +{ + if (mA > 100) { + /* AB V2 has eye diagram issues when drawing more + * than 100mA from VBUS.So setting charging current + * to 100mA in case of standard host + */ + if (ab->rev < 0x30) + mA = 100; + else + mA = 300; + } + return mA; +} + static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA) { struct ab8500_usb *ab; @@ -365,6 +380,8 @@ static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA) ab = xceiv_to_ab(otg); + mA = ab8500_eyediagram_workaroud(ab, mA); + ab->vbus_draw = mA; atomic_notifier_call_chain(&ab->otg.notifier, -- cgit v1.2.3 From ebc7b79e171847d6fe458497157821259cda7ae1 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 14 Jul 2011 17:30:24 +0530 Subject: USB:Enable GPIO configuration at connect GPIO alternate configuration is set when the USB is connected and reset at USB disconnect. Change-Id: I07d9c2ed5028879ecff309aa9e4ac25deac148f5 Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/27203 Reviewed-by: QATOOLS Reviewed-by: Praveena NADAHALLY Reviewed-by: Philippe LANGLAIS --- arch/arm/mach-ux500/board-mop500-usb.h | 13 +++++++++++++ arch/arm/mach-ux500/include/mach/usb.h | 8 ++++++++ arch/arm/mach-ux500/usb.c | 35 ++++++++++++++++++++++++++++++++++ drivers/usb/otg/ab8500-usb.c | 16 ++++++++++++++++ include/linux/mfd/ab8500.h | 1 + 5 files changed, 73 insertions(+) create mode 100644 arch/arm/mach-ux500/board-mop500-usb.h diff --git a/arch/arm/mach-ux500/board-mop500-usb.h b/arch/arm/mach-ux500/board-mop500-usb.h new file mode 100644 index 00000000000..85288463a73 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-usb.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Saketh Ram Bommisetti + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __BOARD_MOP500_USB_H +#define __BOARD_MOP500_USB_H + +extern struct ab8500_usbgpio_platform_data ab8500_usbgpio_plat_data; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h index d3739d41881..5c27a72c10d 100644 --- a/arch/arm/mach-ux500/include/mach/usb.h +++ b/arch/arm/mach-ux500/include/mach/usb.h @@ -22,4 +22,12 @@ struct ux500_musb_board_data { void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg, int *dma_tx_cfg); + +struct ab8500_usbgpio_platform_data { + int (*get)(struct device *device); + void (*enable)(void); + void (*disable)(void); + void (*put)(void); +}; + #endif diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 0a01cbdfe06..b4f3b821922 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include "pins.h" +#include "board-mop500-usb.h" #define MUSB_DMA40_RX_CH { \ .mode = STEDMA40_MODE_LOGICAL, \ @@ -86,6 +89,7 @@ static struct ux500_musb_board_data musb_board_data = { }; static u64 ux500_musb_dmamask = DMA_BIT_MASK(32); +static struct ux500_pins *usb_gpio_pins; static struct musb_hdrc_config musb_hdrc_config = { .multipoint = true, @@ -130,6 +134,37 @@ struct platform_device ux500_musb_device = { .resource = usb_resources, }; +static void enable_gpio(void) +{ + ux500_pins_enable(usb_gpio_pins); +} +static void disable_gpio(void) +{ + ux500_pins_disable(usb_gpio_pins); +} +static int get_gpio(struct device *device) +{ + usb_gpio_pins = ux500_pins_get(dev_name(device)); + + if (usb_gpio_pins == NULL) { + dev_err(device, "Could not get %s:usb_gpio_pins structure\n", + dev_name(device)); + + return PTR_ERR(usb_gpio_pins); + } + return 0; +} +static void put_gpio(void) +{ + ux500_pins_put(usb_gpio_pins); +} +struct ab8500_usbgpio_platform_data ab8500_usbgpio_plat_data = { + .get = &get_gpio, + .enable = &enable_gpio, + .disable = &disable_gpio, + .put = &put_gpio, +}; + static inline void ux500_usb_dma_update_rx_ch_config(int *src_dev_type) { u32 idx; diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index fd5943b7d38..fcd3847e6d5 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -35,6 +35,7 @@ #include #include #include +#include #define AB8500_MAIN_WD_CTRL_REG 0x01 #define AB8500_USB_LINE_STAT_REG 0x80 @@ -99,6 +100,7 @@ struct ab8500_usb { struct regulator *v_ape; struct regulator *v_musb; struct regulator *v_ulpi; + struct ab8500_usbgpio_platform_data *usb_gpio; }; static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x) @@ -168,6 +170,8 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : AB8500_BIT_PHY_CTRL_DEVICE_EN; + ab->usb_gpio->enable(); + clk_enable(ab->sysclk); ab8500_usb_regulator_ctrl(ab, sel_host, true); @@ -215,6 +219,8 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) ab8500_usb_regulator_ctrl(ab, sel_host, false); + ab->usb_gpio->disable(); + prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 50); } @@ -354,6 +360,7 @@ static void ab8500_usb_phy_disable_work(struct work_struct *work) if (!ab->otg.gadget) ab8500_usb_peri_phy_dis(ab); + } static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) @@ -621,6 +628,8 @@ irq_fail: static int __devinit ab8500_usb_probe(struct platform_device *pdev) { struct ab8500_usb *ab; + struct ab8500_platform_data *ab8500_pdata = + dev_get_platdata(pdev->dev.parent); int err; int rev; @@ -646,6 +655,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) ab->otg.set_peripheral = ab8500_usb_set_peripheral; ab->otg.set_suspend = ab8500_usb_set_suspend; ab->otg.set_power = ab8500_usb_set_power; + ab->usb_gpio = ab8500_pdata->usb; platform_set_drvdata(pdev, ab); @@ -685,6 +695,10 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) /* Needed to enable ID detection. */ ab8500_usb_wd_workaround(ab); + err = ab->usb_gpio->get(ab->dev); + if (err < 0) + goto fail3; + prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 50); @@ -723,6 +737,8 @@ static int __devexit ab8500_usb_remove(struct platform_device *pdev) ab8500_usb_regulator_put(ab); + ab->usb_gpio->put(); + platform_set_drvdata(pdev, NULL); kfree(ab); diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index 838c6b487cc..9bb244621d3 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h @@ -193,6 +193,7 @@ struct ab8500_platform_data { int num_regulator; struct regulator_init_data *regulator; struct ab8500_gpio_platform_data *gpio; + struct ab8500_usbgpio_platform_data *usb; }; extern int __devinit ab8500_init(struct ab8500 *ab8500); -- cgit v1.2.3 From 8d0b9726d86b82ac56c9c885f8f587921d038de0 Mon Sep 17 00:00:00 2001 From: sidhartk Date: Wed, 17 Nov 2010 13:04:20 +0530 Subject: USB: Double Buffering Merging patch from gerrit id 6301 The patches enables hardware double buffering support for endpoint to enable Massstorage improve performance. Signed-off-by: sidhartk Change-Id: Ic5d1a4e5a17898b0eb90947a1bc3bb8f2d26f79c Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/8759 Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/musb_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 20a28731c33..e39578c4610 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1103,8 +1103,8 @@ static struct musb_fifo_cfg __initdata mode_4_cfg[] = { /* mode 5 - fits in 8KB */ static struct musb_fifo_cfg __initdata mode_5_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, -- cgit v1.2.3 From 8cb1223fae530caebef8d2d499250b6109f0dc16 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Wed, 24 Aug 2011 17:43:47 +0530 Subject: Generic:USB:Pairing suspend/resume correctly for musb Changing the resume_noirq call to resume call so that suspend/resume is paired and we will have a stable USB power save. ST-Ericsson ID: ER 280150 Signed-off-by: Sakethram Bommisetti --- drivers/usb/musb/musb_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index e39578c4610..da92b6a23fc 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2308,7 +2308,7 @@ static int musb_suspend(struct device *dev) return 0; } -static int musb_resume_noirq(struct device *dev) +static int musb_resume(struct device *dev) { struct musb *musb = dev_to_musb(dev); @@ -2353,7 +2353,7 @@ static int musb_runtime_resume(struct device *dev) static const struct dev_pm_ops musb_dev_pm_ops = { .suspend = musb_suspend, - .resume_noirq = musb_resume_noirq, + .resume = musb_resume, .runtime_suspend = musb_runtime_suspend, .runtime_resume = musb_runtime_resume, }; -- cgit v1.2.3 From 474f193673d8a32e566bc9e6662035359c2b0db6 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 25 Aug 2011 11:57:38 +0530 Subject: USB : Mass Storage : Performance Increase When ceiling and changing the page code values the performance of mass storage is affected. To achieve faster write operation removing ceiling and changing of page code values ST-Ericsson ID : 283277 Change-Id: I16792c07011c46d3775278d1836d78af9830b2dc Signed-off-by: rajaram Conflicts: drivers/usb/gadget/f_mass_storage.c Signed-off-by: Sakethram Bommisetti --- drivers/usb/gadget/f_mass_storage.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 4a10e539d34..6c1e1db831a 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -1368,32 +1368,7 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) limit = 65535; /* Should really be FSG_BUFLEN */ } - /* No block descriptors */ - - /* - * The mode pages, in numerical order. The only page we support - * is the Caching page. - */ - if (page_code == 0x08 || all_pages) { - valid_page = 1; - buf[0] = 0x08; /* Page code */ - buf[1] = 10; /* Page length */ - memset(buf+2, 0, 10); /* None of the fields are changeable */ - - if (!changeable_values) { - buf[2] = 0x04; /* Write cache enable, */ - /* Read cache not disabled */ - /* No cache retention priorities */ - put_unaligned_be16(0xffff, &buf[4]); - /* Don't disable prefetch */ - /* Minimum prefetch = 0 */ - put_unaligned_be16(0xffff, &buf[8]); - /* Maximum prefetch */ - put_unaligned_be16(0xffff, &buf[10]); - /* Maximum prefetch ceiling */ - } - buf += 12; - } + valid_page = 1; /* * Check that a valid page was requested and the mode data length -- cgit v1.2.3 From e66c202be4fe727a5b806a87ac8016b930b8e509 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 25 Aug 2011 19:37:15 +0530 Subject: ux500: Removed USB support for AB8500 1.0 and 1.1 Removing AB8500 1.0 and 1.1 support and the VUSB regulator is a requirement to complete the ER stated below. ST-Ericsson Linux next: - ST-Ericsson ID: ER 327257 ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Sakethram Bommisetti Signed-off-by: Bengt Jonsson --- drivers/usb/otg/ab8500-usb.c | 81 ++++---------------------------------------- 1 file changed, 7 insertions(+), 74 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index fcd3847e6d5..d6039ec20f3 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -123,10 +123,8 @@ static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) (AB8500_BIT_WD_CTRL_ENABLE | AB8500_BIT_WD_CTRL_KICK)); - if (ab->rev > 0x10) /* v1.1 v2.0 */ + if (ab->rev > 0x10) /* v2.0 v3.0 */ udelay(AB8500_WD_V11_DISABLE_DELAY_US); - else /* v1.0 */ - msleep(AB8500_WD_V10_DISABLE_DELAY_MS); abx500_set_register_interruptible(ab->dev, AB8500_SYS_CTRL2_BLOCK, @@ -142,25 +140,10 @@ static void ab8500_usb_regulator_ctrl(struct ab8500_usb *ab, bool sel_host, regulator_enable(ab->v_ulpi); regulator_enable(ab->v_musb); - if (sel_host && (ab->rev < 0x20)) - /* Enable v-usb */ - abx500_mask_and_set_register_interruptible(ab->dev, - AB8500_REGU_CTRL1, - AB8500_VBUS_CTRL_REG, - AB8500_BIT_VBUS_ENABLE, - AB8500_BIT_VBUS_ENABLE); } else { regulator_disable(ab->v_musb); regulator_disable(ab->v_ulpi); regulator_disable(ab->v_ape); - - if (sel_host && (ab->rev < 0x20)) - /* Disable v-usb */ - abx500_mask_and_set_register_interruptible(ab->dev, - AB8500_REGU_CTRL1, - AB8500_VBUS_CTRL_REG, - AB8500_BIT_VBUS_ENABLE, - 0); } } @@ -184,8 +167,6 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) bit, bit); - /* Needed to enable the phy.*/ - ab8500_usb_wd_workaround(ab); } static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab,u8 bit) @@ -215,6 +196,9 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) bit, 0); + /* Needed to disable the phy.*/ + ab8500_usb_wd_workaround(ab); + clk_disable(ab->sysclk); ab8500_usb_regulator_ctrl(ab, sel_host, false); @@ -305,16 +289,6 @@ static void ab8500_usb_delayed_work(struct work_struct *work) ab8500_usb_link_status_update(ab); } -static irqreturn_t ab8500_usb_v1x_connect_irq(int irq, void *data) -{ - struct ab8500_usb *ab = (struct ab8500_usb *) data; - - /* Wait for link status to become stable. */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - - return IRQ_HANDLED; -} - static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; @@ -334,10 +308,6 @@ static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) } ab->mode = USB_IDLE; - if (ab->rev < 0x20) - /* Wait for link status to become stable. */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - return IRQ_HANDLED; } @@ -532,41 +502,7 @@ static int ab8500_usb_irq_setup(struct platform_device *pdev, int err; int irq; - if (ab->rev < 0x20) { - irq = platform_get_irq_byname(pdev, "ID_WAKEUP_R"); - if (irq < 0) { - err = irq; - dev_err(&pdev->dev, "ID rise irq not found\n"); - goto irq_fail; - } - err = request_threaded_irq(irq, NULL, - ab8500_usb_v1x_connect_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-id-rise", ab); - if (err < 0) { - dev_err(ab->dev, - "request_irq failed for ID rise irq\n"); - goto irq_fail; - } - ab->irq_num_id_rise = irq; - - irq = platform_get_irq_byname(pdev, "VBUS_DET_R"); - if (irq < 0) { - err = irq; - dev_err(&pdev->dev, "VBUS rise irq not found\n"); - goto irq_fail; - } - err = request_threaded_irq(irq, NULL, - ab8500_usb_v1x_connect_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-vbus-rise", ab); - if (err < 0) { - dev_err(ab->dev, - "request_irq failed for Vbus rise irq\n"); - goto irq_fail; - } - ab->irq_num_vbus_rise = irq; - }else { /* 0x20 */ + if (ab->rev > 0x10) { /* 0x20 0x30 */ irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS"); if (irq < 0) { err = irq; @@ -637,8 +573,8 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) if (rev < 0) { dev_err(&pdev->dev, "Chip id read failed\n"); return rev; - } else if (rev < 0x10) { - dev_err(&pdev->dev, "Unsupported AB8500 chip\n"); + } else if (rev < 0x20) { + dev_err(&pdev->dev, "Unsupported AB8500 chip rev=%d\n", rev); return -ENODEV; } @@ -679,9 +615,6 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) goto fail1; } - if (ab->rev < 0x20) - ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT; - err = ab8500_usb_irq_setup(pdev, ab); if (err < 0) goto fail2; -- cgit v1.2.3 From b05f7f43a406a76cc87590fc013e066eb69cc670 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Fri, 26 Aug 2011 15:03:07 +0530 Subject: USB: Enable RNDIS Enable RNDIS for Android Platform. Also provide the runtime configuration binding as Microsoft driver doesn't support the RNDIS in composite mode Also make the Class, SubClass and Protocol of IAD same as that of first interface as mentioned in the specification. ST-Ericsson ID: CR 272413 Signed-off-by: Sakethram Bommisetti Signed-off-by: Ajay Jawade --- drivers/usb/gadget/f_rndis.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 3ea4666be3d..be5620690d5 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -183,8 +183,8 @@ rndis_iad_descriptor = { .bFirstInterface = 0, /* XXX, hardcoded */ .bInterfaceCount = 2, // control + data .bFunctionClass = USB_CLASS_COMM, - .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bFunctionProtocol = USB_CDC_PROTO_NONE, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_CDC_ACM_PROTO_VENDOR, /* .iFunction = DYNAMIC */ }; -- cgit v1.2.3 From 66a6b287dda121c8a16c4abe04da87cb18fd5ef3 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 20 Oct 2011 13:25:52 +0200 Subject: USB:Updating the documentation Documentation from usb. Signed-off-by: Sakethram Bommisetti --- Documentation/DocBook/ux500_usb.tmpl | 147 +++++++++++++++++++++++++++++++++++ drivers/usb/musb/ux500.c | 33 ++++++++ drivers/usb/musb/ux500_dma.c | 97 ++++++++++++++++++++++- 3 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 Documentation/DocBook/ux500_usb.tmpl diff --git a/Documentation/DocBook/ux500_usb.tmpl b/Documentation/DocBook/ux500_usb.tmpl new file mode 100644 index 00000000000..f31f3784e93 --- /dev/null +++ b/Documentation/DocBook/ux500_usb.tmpl @@ -0,0 +1,147 @@ + + + + + + USB Driver Function guide + + + + Praveena + Nadahally + +
+ praveen.nadahally@stericsson.com +
+
+
+ + Rajaram + Ragupathy + +
+ ragupathy.rajaram@stericsson.com +
+
+
+ + SakethRam + Bommisetti + +
+ sakethram.bommisetti@stericsson.com +
+
+
+
+ + + 2011 + ST-Ericsson + + + + + Connectivity + + + + + + This documentation 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. + + + + This program 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. + + + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + + +
+ + + + + Introduction + + This documentation describes ST-Ericsson's adaptation on USB external DMA and communication between Mentor USB IP controller and the USB + transreceiver + + + + + Concepts + + + In ST-Ericsson's USB driver, the open source linux gadget stack and Mentor IP USB 2.0 driver is used. Since the USB Transceiver and Mentor USB IP controller are on different hardware, API's are defined for the communication between them. These API's are available in ux500.c file. + The ST-Ericsson's USB driver doesn't have the internal DMA dedicated for USB. So, the external system DMA is used. The integration of external DMA with the mentor chip is available in ux500_dma.c file. + Changes have been made in the musb_core.c file where endpoints are configured as per the platform and also integrated DMA specific chnages in the musb_gadget.c file. + + + + + + + Known Bugs And Assumptions + + + + + + None. + + + + + + + + + + + + + Internal Functions Provided + + List of internal functions + + + +
+ ux500_dma.c +!Idrivers/usb/musb/ux500_dma.c +
+
+ ux500.c +!Idrivers/usb/musb/ux500.c +
+
+ +
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index f7e04bf34a1..0806a41f090 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -35,6 +35,12 @@ struct ux500_glue { }; #define glue_to_musb(g) platform_get_drvdata(g->musb) +/** + * ux500_musb_init() - Initialize the platform USB driver. + * @musb: struct musb pointer. + * + * This function initialize the USB controller and Phy. +*/ static int ux500_musb_init(struct musb *musb) { musb->xceiv = otg_get_transceiver(); @@ -46,6 +52,12 @@ static int ux500_musb_init(struct musb *musb) return 0; } +/** + * ux500_musb_exit() - unregister the platform USB driver. + * @musb: struct musb pointer. + * + * This function unregisters the USB controller. + */ static int ux500_musb_exit(struct musb *musb) { otg_put_transceiver(musb->xceiv); @@ -58,6 +70,13 @@ static const struct musb_platform_ops ux500_ops = { .exit = ux500_musb_exit, }; +/** + * ux500_probe() - Allocate the resources. + * @pdev: struct platform_device. + * + * This function allocates the required memory for the + * structures and initialize interrupts. + */ static int __init ux500_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; @@ -155,6 +174,13 @@ static int __exit ux500_remove(struct platform_device *pdev) } #ifdef CONFIG_PM +/** + * ux500_suspend() - Handles the platform suspend. + * @dev: struct device + * + * This function gets triggered when the platform + * is going to suspend + */ static int ux500_suspend(struct device *dev) { struct ux500_glue *glue = dev_get_drvdata(dev); @@ -166,6 +192,13 @@ static int ux500_suspend(struct device *dev) return 0; } +/** + * ux500_resume() - Handles the platform resume. + * @dev: struct device + * + * This function gets triggered when the platform + * is going to resume + */ static int ux500_resume(struct device *dev) { struct ux500_glue *glue = dev_get_drvdata(dev); diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index ef4333f4bbe..ecab2bf997e 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -56,7 +56,13 @@ struct ux500_dma_controller { dma_addr_t phy_base; }; -/* Work function invoked from DMA callback to handle tx transfers. */ +/** + * ux500_tx_work() - Invoked by worker thread + * @data: worker queue data + * + * This function is invoked by worker thread when the DMA transfer + * is completed in the transmit direction. +*/ static void ux500_tx_work(struct work_struct *data) { struct ux500_dma_channel *ux500_channel = container_of(data, @@ -76,7 +82,13 @@ static void ux500_tx_work(struct work_struct *data) spin_unlock_irqrestore(&musb->lock, flags); } -/* Work function invoked from DMA callback to handle rx transfers. */ +/** + * ux500_rx_work() - Invoked by worker thread + * @data: worker queue data + * + * This function is invoked by worker thread when the + * DMA transfer is completed in the receive direction. +*/ static void ux500_rx_work(struct work_struct *data) { struct ux500_dma_channel *ux500_channel = container_of(data, @@ -96,6 +108,12 @@ static void ux500_rx_work(struct work_struct *data) spin_unlock_irqrestore(&musb->lock, flags); } +/** + * ux500_dma_callback() - callback invoked when there is DMA data transfer + * @private_data: pointer to DMA channel. + * + * This callback is invoked when the DMA tranfer is completed. +*/ void ux500_dma_callback(void *private_data) { struct dma_channel *channel = (struct dma_channel *)private_data; @@ -104,6 +122,18 @@ void ux500_dma_callback(void *private_data) schedule_work(&ux500_channel->channel_work); } +/** + * ux500_configure_channel() - configures the source, destination addresses and + * starts the transfer + * @channel: pointer to DMA channel + * @packet_sz: packet size + * @mode: Dma mode + * @dma_addr: DMA source address for transmit direction + * or DMA destination address for receive direction + * @len: length + * This function configures the source and destination addresses for DMA + * operation and initiates the DMA transfer +*/ static bool ux500_configure_channel(struct dma_channel *channel, u16 packet_sz, u8 mode, dma_addr_t dma_addr, u32 len) @@ -162,6 +192,15 @@ static bool ux500_configure_channel(struct dma_channel *channel, return true; } +/** + * ux500_dma_controller_allocate() - allocates the DMA channels + * @c: pointer to DMA controller + * @hw_ep: pointer to endpoint + * @is_tx: transmit or receive direction + * + * This function allocates the DMA channel and initializes + * the channel +*/ static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c, struct musb_hw_ep *hw_ep, u8 is_tx) { @@ -200,7 +239,13 @@ static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c, return &(ux500_channel->channel); } - +/** + * ux500_dma_channel_release() - releases the DMA channel + * @channel: channel to be released + * + * This function releases the DMA channel + * +*/ static void ux500_dma_channel_release(struct dma_channel *channel) { struct ux500_dma_channel *ux500_channel = channel->private_data; @@ -227,6 +272,16 @@ static int ux500_dma_is_compatible(struct dma_channel *channel, return true; } +/** + * ux500_dma_channel_program() - Configures the channel and initiates transfer + * @channel: pointer to DMA channel + * @packet_sz: packet size + * @mode: mode + * @dma_addr: physical address of memory + * @len: length + * + * This function configures the channel and initiates the DMA transfer +*/ static int ux500_dma_channel_program(struct dma_channel *channel, u16 packet_sz, u8 mode, dma_addr_t dma_addr, u32 len) @@ -248,6 +303,12 @@ static int ux500_dma_channel_program(struct dma_channel *channel, return ret; } +/** + * ux500_dma_channel_abort() - aborts the DMA transfer + * @channel: pointer to DMA channel. + * + * This function aborts the DMA transfer. +*/ static int ux500_dma_channel_abort(struct dma_channel *channel) { struct ux500_dma_channel *ux500_channel = channel->private_data; @@ -282,6 +343,12 @@ static int ux500_dma_channel_abort(struct dma_channel *channel) return 0; } +/** + * ux500_dma_controller_stop() - releases all the channels and frees the DMA pipes + * @c: pointer to DMA controller + * + * This function frees all of the logical channels and frees the DMA pipes +*/ static int ux500_dma_controller_stop(struct dma_controller *c) { struct ux500_dma_controller *controller = container_of(c, @@ -313,6 +380,15 @@ static int ux500_dma_controller_stop(struct dma_controller *c) return 0; } + +/** + * ux500_dma_controller_start() - creates the logical channels pool and registers callbacks + * @c: pointer to DMA Controller + * + * This function requests the logical channels from the DMA driver and creates + * logical channels based on event lines and also registers the callbacks which + * are invoked after data transfer in the transmit or receive direction. +*/ static int ux500_dma_controller_start(struct dma_controller *c) { struct ux500_dma_controller *controller = container_of(c, @@ -389,6 +465,12 @@ static int ux500_dma_controller_start(struct dma_controller *c) return 0; } +/** + * dma_controller_destroy() - deallocates the DMA controller + * @c: pointer to dma controller. + * + * This function deallocates the DMA controller. +*/ void dma_controller_destroy(struct dma_controller *c) { struct ux500_dma_controller *controller = container_of(c, @@ -397,6 +479,15 @@ void dma_controller_destroy(struct dma_controller *c) kfree(controller); } +/** + * dma_controller_create() - creates the dma controller and initializes callbacks + * + * @musb: pointer to mentor core driver data instance| + * @base: base address of musb registers. + * + * This function creates the DMA controller and initializes the callbacks + * that are invoked from the Mentor IP core. +*/ struct dma_controller *__init dma_controller_create(struct musb *musb, void __iomem *base) { -- cgit v1.2.3 From cd4b11b970bd9247aa1fffa404affe0563256c4a Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 6 Sep 2011 10:05:02 +0530 Subject: musb:host: Linux Kernel3.0 host Integration The handling of device connection in host mode. ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Icdf576355fd5743bd48af0c8e33ae34526fc53a4 Signed-off-by: Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30020 Reviewed-by: Praveena NADAHALLY --- drivers/usb/musb/musb_core.c | 2 +- drivers/usb/musb/ux500.c | 112 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index da92b6a23fc..1e46c24531c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1868,7 +1868,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) status = -ENODEV; goto fail0; } - + dev->dma_mask = 0 ; /* allocate */ musb = allocate_instance(dev, plat->config, ctrl); if (!musb) { diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 0806a41f090..a80663d4187 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -28,6 +28,8 @@ #include "musb_core.h" +static void ux500_musb_set_vbus(struct musb *musb, int is_on); + struct ux500_glue { struct device *dev; struct platform_device *musb; @@ -35,12 +37,107 @@ struct ux500_glue { }; #define glue_to_musb(g) platform_get_drvdata(g->musb) -/** - * ux500_musb_init() - Initialize the platform USB driver. - * @musb: struct musb pointer. - * - * This function initialize the USB controller and Phy. -*/ +/* blocking notifier support */ +static int musb_otg_notifications(struct notifier_block *nb, + unsigned long event, void *unused) +{ + struct musb *musb = container_of(nb, struct musb, nb); + + switch (event) { + case USB_EVENT_ID: + dev_dbg(musb->controller, "ID GND\n"); + if (is_otg_enabled(musb)) { +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + if (musb->gadget_driver) + ux500_musb_set_vbus(musb, 1); +#endif + } else { + ux500_musb_set_vbus(musb, 1); + } + break; + + case USB_EVENT_VBUS: + dev_dbg(musb->controller, "VBUS Connect\n"); + + break; + + case USB_EVENT_NONE: + dev_dbg(musb->controller, "VBUS Disconnect\n"); +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) + if (musb->gadget_driver) +#endif + { + dev_dbg(musb->controller, "Add runtime powermangement code here\n"); + } + + break; + default: + dev_dbg(musb->controller, "ID float\n"); + return NOTIFY_DONE; + } + return NOTIFY_OK; +} + +static void ux500_musb_set_vbus(struct musb *musb, int is_on) +{ + u8 devctl; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + int ret = 1; + /* HDRC controls CPEN, but beware current surges during device + * connect. They can trigger transient overcurrent conditions + * that must be ignored. + */ + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + if (is_on) { + if (musb->xceiv->state == OTG_STATE_A_IDLE) { + /* start the session */ + devctl |= MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + /* + * Wait for the musb to set as A device to enable the + * VBUS + */ + while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + + if (time_after(jiffies, timeout)) { + dev_err(musb->controller, + "configured as A device timeout"); + ret = -EINVAL; + break; + } + } + + } else { + musb->is_active = 1; + musb->xceiv->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + devctl |= MUSB_DEVCTL_SESSION; + MUSB_HST_MODE(musb); + } + } else { + musb->is_active = 0; + + /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and + * jumping right to B_IDLE... + */ + + musb->xceiv->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; + devctl &= ~MUSB_DEVCTL_SESSION; + + MUSB_DEV_MODE(musb); + } + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + dev_dbg(musb->controller, "VBUS %s, devctl %02x " + /* otg %3x conf %08x prcm %08x */ "\n", + otg_state_string(musb->xceiv->state), + musb_readb(musb->mregs, MUSB_DEVCTL)); +} + static int ux500_musb_init(struct musb *musb) { musb->xceiv = otg_get_transceiver(); @@ -49,6 +146,7 @@ static int ux500_musb_init(struct musb *musb) return -ENODEV; } + musb->nb.notifier_call = musb_otg_notifications; return 0; } @@ -68,6 +166,8 @@ static int ux500_musb_exit(struct musb *musb) static const struct musb_platform_ops ux500_ops = { .init = ux500_musb_init, .exit = ux500_musb_exit, + + .set_vbus = ux500_musb_set_vbus, }; /** -- cgit v1.2.3 From 69d97a51cc01e91e31b703f2d3bafc8208bb3b7c Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 6 Sep 2011 10:44:44 +0530 Subject: musb: host: unmap the buffer for PIO in EP0 The USB stack maps the buffer for DMA if the controller supports DMA.The buffer needs to be unmapped before CPU can perform PIO data transfers. ST-Ericsson ID: 353110 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I7811591f4f82f06af036bbde28cfa6f6de40cf8d Signed-off-by: Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30144 Reviewed-by: Praveena NADAHALLY --- drivers/usb/musb/musb_host.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 73ebcca75b0..ff02e5924fb 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -813,6 +813,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum, if (hw_ep->do_tx_pio) { /* PIO to load FIFO */ + /* Unmap the buffer so that CPU can use it */ + usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); qh->segsize = load_count; musb_write_fifo(hw_ep, load_count, buf); } @@ -905,6 +907,8 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) if (fifo_count < len) urb->status = -EOVERFLOW; + /* Unmap the buffer so that CPU can use it */ + usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); musb_read_fifo(hw_ep, fifo_count, fifo_dest); urb->actual_length += fifo_count; @@ -944,6 +948,8 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) fifo_count, (fifo_count == 1) ? "" : "s", fifo_dest); + /* Unmap the buffer so that CPU can use it */ + usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); musb_write_fifo(hw_ep, fifo_count, fifo_dest); urb->actual_length += fifo_count; -- cgit v1.2.3 From e1d6116db3c9f014e33f93e845778ac74a3e5280 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Fri, 2 Sep 2011 17:45:15 +0530 Subject: ux500: usb: core: USB Hub support musb host USB Hub support musb host ST-Ericsson ID: CR 279072 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Change-Id: I22ded0d7cadc8d83996336cfe3917e345c48bd45 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30052 Reviewed-by: Praveena NADAHALLY --- drivers/usb/core/hub.c | 31 +++++++++++++++++++++++++++++++ drivers/usb/core/notify.c | 7 +++++++ drivers/usb/core/usb.h | 4 ++++ include/linux/usb.h | 8 ++++++++ 4 files changed, 50 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 72150c7ea3a..98801cf4c18 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -30,6 +30,12 @@ #include "usb.h" +#ifdef CONFIG_ARCH_U8500 +#define MAX_TOPO_LEVEL_U8500 2 +#define MAX_USB_DEVICE_U8500 8 +int usb_device_count; +#endif + /* if we are in debug mode, always announce new devices */ #ifdef DEBUG #ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES @@ -1292,11 +1298,20 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!hub_is_superspeed(hdev) || !hdev->parent) usb_enable_autosuspend(hdev); +#ifdef CONFIG_ARCH_U8500 + if (hdev->level > MAX_TOPO_LEVEL_U8500) { + dev_err(&intf->dev, + "Unsupported bus topology: > %d " + " hub nesting\n", MAX_TOPO_LEVEL_U8500); + return -E2BIG; + } +#else if (hdev->level == MAX_TOPO_LEVEL) { dev_err(&intf->dev, "Unsupported bus topology: hub nested too deep\n"); return -E2BIG; } +#endif #ifdef CONFIG_USB_OTG_BLACKLIST_HUB if (hdev->parent) { @@ -3260,6 +3275,22 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, goto loop; } +#ifdef CONFIG_ARCH_U8500 + if (hdev->parent == NULL) + usb_device_count = 1; + + if (usb_device_count > MAX_USB_DEVICE_U8500) { + + dev_err(&udev->dev, + "device connected is more than %d\n", + MAX_USB_DEVICE_U8500); + + status = -ENOTCONN; /* Don't retry */ + goto loop; + } +#endif + + /* reset (non-USB 3.0 devices) and get descriptor */ status = hub_port_init(hub, udev, port1, i); if (status < 0) diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 7542dce3f5a..87c5edcbdf5 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -45,11 +45,18 @@ EXPORT_SYMBOL_GPL(usb_unregister_notify); void usb_notify_add_device(struct usb_device *udev) { +#ifdef CONFIG_ARCH_U8500 + usb_device_count++; +#endif + blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); } void usb_notify_remove_device(struct usb_device *udev) { +#ifdef CONFIG_ARCH_U8500 + usb_device_count--; +#endif /* Protect against simultaneous usbfs open */ mutex_lock(&usbfs_mutex); blocking_notifier_call_chain(&usb_notifier_list, diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index d44d4b7bbf1..f9eaaa04e26 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,5 +1,9 @@ #include +#ifdef CONFIG_ARCH_U8500 +extern int usb_device_count; +#endif + /* Functions local to drivers/usb/core/ */ extern int usb_create_sysfs_dev_files(struct usb_device *dev); diff --git a/include/linux/usb.h b/include/linux/usb.h index 73c7df48960..8c47a3bfaff 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -362,7 +362,15 @@ struct usb_bus { * limit. Because the arrays need to add a bit for hub status data, we * do 31, so plus one evens out to four bytes. */ + +#ifdef CONFIG_ARCH_U8500 +/** +* On U8500 platform we support 16 ports only +*/ +#define USB_MAXCHILDREN (16) +#else #define USB_MAXCHILDREN (31) +#endif struct usb_tt; -- cgit v1.2.3 From 5b5ae0f5ee397c95ad45702c647d158ba0939970 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Mon, 5 Sep 2011 17:26:43 +0530 Subject: ux500: USB: Set the charging cur to 300mA for ABV3 In case of AB-V3, the eye diagram related issues are resolved. So, set the device charging current to 300mA when connected to standard host. Also, add the USB PHY tuning values to improve the USB eye diagram ST-Ericsson ID: 330203 ST-Ericsson Linux next: ER 330203 ST-Ericsson FOSS-OUT ID: NA Change-Id: I7cd49289ce7e1a6d88263198e7b1258c923c1282 Signed-off-by: Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30031 Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index d6039ec20f3..2dbd3436dc4 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -55,6 +55,18 @@ #define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */ #define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */ +/* Registers in bank 0x11 */ +#define AB8500_BANK12_ACCESS 0x00 + +/* Registers in bank 0x12 */ +#define AB8500_USB_PHY_TUNE1 0x05 +#define AB8500_USB_PHY_TUNE2 0x06 +#define AB8500_USB_PHY_TUNE3 0x07 + + + + + /* Usb line status register */ enum ab8500_usb_link_status { USB_LINK_NOT_CONFIGURED = 0, @@ -568,6 +580,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) dev_get_platdata(pdev->dev.parent); int err; int rev; + int ret = -1; rev = abx500_get_chip_id(&pdev->dev); if (rev < 0) { @@ -625,6 +638,52 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) goto fail3; } + /* Write Phy tuning values */ + if (ab->rev == 0x30) { + /* Enable the PBT/Bank 0x12 access */ + ret = abx500_set_register_interruptible(ab->dev, + AB8500_DEVELOPMENT, + AB8500_BANK12_ACCESS, + 0x01); + if (ret < 0) + printk(KERN_ERR "Failed to enable bank12" + " access ret=%d\n", ret); + + ret = abx500_set_register_interruptible(ab->dev, + AB8500_DEBUG, + AB8500_USB_PHY_TUNE1, + 0xC8); + if (ret < 0) + printk(KERN_ERR "Failed to set PHY_TUNE1" + " register ret=%d\n", ret); + + ret = abx500_set_register_interruptible(ab->dev, + AB8500_DEBUG, + AB8500_USB_PHY_TUNE2, + 0x00); + if (ret < 0) + printk(KERN_ERR "Failed to set PHY_TUNE2" + " register ret=%d\n", ret); + + ret = abx500_set_register_interruptible(ab->dev, + AB8500_DEBUG, + AB8500_USB_PHY_TUNE3, + 0x78); + + if (ret < 0) + printk(KERN_ERR "Failed to set PHY_TUNE3" + " regester ret=%d\n", ret); + + /* Switch to normal mode/disable Bank 0x12 access */ + ret = abx500_set_register_interruptible(ab->dev, + AB8500_DEVELOPMENT, + AB8500_BANK12_ACCESS, + 0x00); + + if (ret < 0) + printk(KERN_ERR "Failed to switch bank12" + " access ret=%d\n", ret); + } /* Needed to enable ID detection. */ ab8500_usb_wd_workaround(ab); -- cgit v1.2.3 From cd5a920e73e075364f690d336f1998dc554145e5 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 8 Sep 2011 14:39:13 +0530 Subject: ux500:USB:Boot time detection Enabling the phy during the booting of kernel if usb is connected. ST-Ericsson ID: NA ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: Ic750bf42dbfc9bfb60cc9930e9ea9aa1f58cf8ff Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30436 Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 2dbd3436dc4..4863b99ec28 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -41,6 +41,10 @@ #define AB8500_USB_LINE_STAT_REG 0x80 #define AB8500_USB_PHY_CTRL_REG 0x8A #define AB8500_VBUS_CTRL_REG 0x82 +#define AB8500_IT_SOURCE2_REG 0x01 +#define AB8500_IT_SOURCE20_REG 0x13 +#define AB8500_SRC_INT_USB_HOST 0x04 +#define AB8500_SRC_INT_USB_DEVICE 0x80 #define AB8500_BIT_OTG_STAT_ID (1 << 0) #define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0) @@ -444,6 +448,84 @@ static int ab8500_usb_set_host(struct otg_transceiver *otg, return 0; } +/** + * ab8500_usb_boot_detect : detect the USB cable during boot time. + * @device: value for device. + * + * This function is used to detect the USB cable during boot time. + */ +static int ab8500_usb_boot_detect(struct ab8500_usb *ab) +{ + int err; + struct device *device = ab->dev; + u8 usb_status = 0; + u8 val = 0; + + /* Disabling PHY before selective enable or disable */ + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_BIT_PHY_CTRL_DEVICE_EN, + AB8500_BIT_PHY_CTRL_DEVICE_EN); + + udelay(100); + + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_BIT_PHY_CTRL_DEVICE_EN, + 0); + + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_BIT_PHY_CTRL_HOST_EN, + AB8500_BIT_PHY_CTRL_HOST_EN); + + udelay(100); + + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_PHY_CTRL_REG, + AB8500_BIT_PHY_CTRL_HOST_EN, + 0); + + + err = abx500_get_register_interruptible(device, + AB8500_INTERRUPT, AB8500_IT_SOURCE20_REG, + &usb_status); + if (err < 0) { + dev_err(device, "Read IT 20 failed\n"); + return err; + } + + if (usb_status & AB8500_SRC_INT_USB_HOST) + ab8500_usb_host_phy_en(ab); + + + err = abx500_get_register_interruptible(device, + AB8500_INTERRUPT, AB8500_IT_SOURCE2_REG, + &usb_status); + if (err < 0) { + dev_err(device, "Read IT 2 failed\n"); + return err; + } + + if (usb_status & AB8500_SRC_INT_USB_DEVICE) { + /* Check if it is a dedicated charger */ + (void)abx500_get_register_interruptible(device, + AB8500_USB, AB8500_USB_LINE_STAT_REG, &val); + + val = (val >> 3) & 0x0F; + + if (val == USB_LINK_DEDICATED_CHG) + ab->mode = USB_DEDICATED_CHG; + else + ab8500_usb_peri_phy_en(ab); + } + + return 0; +} static void ab8500_usb_regulator_put(struct ab8500_usb *ab) { @@ -696,6 +778,10 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", ab->rev); + err = ab8500_usb_boot_detect(ab); + if (err < 0) + goto fail3; + return 0; fail3: ab8500_usb_irq_free(ab); -- cgit v1.2.3 From 325343ae6da7fb9b4aaa73965f776438a5bb4c67 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 8 Sep 2011 17:53:19 +0530 Subject: ux500:USB:Disable DMA for device mode Checking the compatibility and disabling the dma. ST-Ericsson ID: NA ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Sakethram Bommisetti Change-Id: Ic52084e5439932ea688d687c4a61cf76fd861e79 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30467 --- drivers/usb/musb/ux500_dma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index ecab2bf997e..e334d247537 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -263,13 +263,14 @@ static void ux500_dma_channel_release(struct dma_channel *channel) static int ux500_dma_is_compatible(struct dma_channel *channel, u16 maxpacket, void *buf, u32 length) { - if ((maxpacket & 0x3) || + /*if ((maxpacket & 0x3) || ((int)buf & 0x3) || (length < 512) || (length & 0x3)) return false; else - return true; + return true;*/ + return false; } /** -- cgit v1.2.3 From 6692f466de752ae2d0bb68cd554e777d41cc030d Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Mon, 12 Sep 2011 11:25:25 +0530 Subject: U8500:USB:Fix for wrong handling of QOS Updating the QOS entry rather than creating a new one. ST-Ericsson ID: NA ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Sakethram Bommisetti Change-Id: I89cc6ddb154c13cd5e9e34d31adba7eef791acfc Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30620 Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 4863b99ec28..cd49c38c628 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -174,7 +174,7 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) clk_enable(ab->sysclk); ab8500_usb_regulator_ctrl(ab, sel_host, true); - prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 100); abx500_mask_and_set_register_interruptible(ab->dev, @@ -221,7 +221,7 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) ab->usb_gpio->disable(); - prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 50); } -- cgit v1.2.3 From 626d089505294db7922f052aebb66d9d625cec34 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Mon, 12 Sep 2011 15:32:40 +0530 Subject: ux500: usb: Move request ARM OPP qos to usb driver ST-Ericsson ID: - ST-Ericsson Linux next: Not tested ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Sakethram Bommisetti Signed-off-by: Jonas Aaberg Change-Id: I70bc1f067032973d20261edb7cdc73631ad30d1c Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30691 Reviewed-by: Rabin VINCENT Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 55 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index cd49c38c628..4eb9ba06468 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -36,6 +36,7 @@ #include #include #include +#include #define AB8500_MAIN_WD_CTRL_REG 0x01 #define AB8500_USB_LINE_STAT_REG 0x80 @@ -68,8 +69,8 @@ #define AB8500_USB_PHY_TUNE3 0x07 - - +#define USB_PROBE_DELAY 1000 /* 1 seconds */ +#define USB_LIMIT (200) /* If we have more than 200 irqs per second */ /* Usb line status register */ enum ab8500_usb_link_status { @@ -117,6 +118,7 @@ struct ab8500_usb { struct regulator *v_musb; struct regulator *v_ulpi; struct ab8500_usbgpio_platform_data *usb_gpio; + struct delayed_work work_usb_workaround; }; static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x) @@ -148,6 +150,33 @@ static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) 0); } +static void ab8500_usb_load(struct work_struct *work) +{ + int cpu; + unsigned int num_irqs = 0; + static unsigned int old_num_irqs = UINT_MAX; + struct delayed_work *work_usb_workaround = to_delayed_work(work); + struct ab8500_usb *ab = container_of(work_usb_workaround, + struct ab8500_usb, work_usb_workaround); + + for_each_online_cpu(cpu) + num_irqs += kstat_irqs_cpu(IRQ_DB8500_USBOTG, cpu); + + if ((num_irqs > old_num_irqs) && + (num_irqs - old_num_irqs) > USB_LIMIT) + prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, + "usb", 125); + else + prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, + "usb", 25); + + old_num_irqs = num_irqs; + + schedule_delayed_work_on(0, + &ab->work_usb_workaround, + msecs_to_jiffies(USB_PROBE_DELAY)); +} + static void ab8500_usb_regulator_ctrl(struct ab8500_usb *ab, bool sel_host, bool enable) { @@ -174,9 +203,16 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) clk_enable(ab->sysclk); ab8500_usb_regulator_ctrl(ab, sel_host, true); + prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 100); + if (!sel_host) { + schedule_delayed_work_on(0, + &ab->work_usb_workaround, + msecs_to_jiffies(USB_PROBE_DELAY)); + } + abx500_mask_and_set_register_interruptible(ab->dev, AB8500_USB, AB8500_USB_PHY_CTRL_REG, @@ -223,6 +259,13 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 50); + + if (!sel_host) { + + cancel_delayed_work_sync(&ab->work_usb_workaround); + prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, + "usb", 25); + } } #define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_enable(ab, true) @@ -299,8 +342,8 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) static void ab8500_usb_delayed_work(struct work_struct *work) { - struct ab8500_usb *ab = container_of(work, struct ab8500_usb, - dwork.work); + struct delayed_work *dwork = to_delayed_work(work); + struct ab8500_usb *ab = container_of(dwork, struct ab8500_usb, dwork); ab8500_usb_link_status_update(ab); } @@ -700,6 +743,8 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) /* all: Disable phy when called from set_host and set_peripheral */ INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); + INIT_DELAYED_WORK_DEFERRABLE(&ab->work_usb_workaround, + ab8500_usb_load); err = ab8500_usb_regulator_get(ab); if (err) goto fail0; @@ -778,6 +823,8 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", ab->rev); + prcmu_qos_add_requirement(PRCMU_QOS_ARM_OPP, "usb", 25); + err = ab8500_usb_boot_detect(ab); if (err < 0) goto fail3; -- cgit v1.2.3 From 231f35e51ab12b730cdcb3302cf6e2ef24336db7 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Mon, 12 Sep 2011 19:37:44 +0530 Subject: USB: Generating unique serial number for USB This patch adds code to extract Public ID which is unique for each board and use it as serial number for USB. This will enable us to connect multiple boards to host as usb devices and access individually. ST-Ericsson ID: 277646 Change-Id: I8daf882106a28127e18684da7a289cce6967f842 Signed-off-by: Sakethram Bommisetti Signed-off-by: dushyanth.sr Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30809 Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 4eb9ba06468..64876c36494 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -72,6 +72,9 @@ #define USB_PROBE_DELAY 1000 /* 1 seconds */ #define USB_LIMIT (200) /* If we have more than 200 irqs per second */ +#define PUBLIC_ID_BACKUPRAM1 (U8500_BACKUPRAM1_BASE + 0x0FC0) +#define MAX_USB_SERIAL_NUMBER_LEN 31 + /* Usb line status register */ enum ab8500_usb_link_status { USB_LINK_NOT_CONFIGURED = 0, @@ -119,6 +122,7 @@ struct ab8500_usb { struct regulator *v_ulpi; struct ab8500_usbgpio_platform_data *usb_gpio; struct delayed_work work_usb_workaround; + struct kobject *serial_number_kobj; }; static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x) @@ -698,6 +702,50 @@ irq_fail: return err; } +/* Sys interfaces */ +static ssize_t usb_serial_number + (struct kobject *kobj, struct attribute *attr, char *buf) +{ + u32 bufer[5]; + void __iomem *backup_ram = NULL; + + backup_ram = ioremap(PUBLIC_ID_BACKUPRAM1, 0x14); + + if (backup_ram) { + bufer[0] = readl(backup_ram); + bufer[1] = readl(backup_ram + 4); + bufer[2] = readl(backup_ram + 8); + bufer[3] = readl(backup_ram + 0x0c); + bufer[4] = readl(backup_ram + 0x10); + + snprintf(buf, MAX_USB_SERIAL_NUMBER_LEN+1, + "%.8X%.8X%.8X%.8X%.8X", + bufer[0], bufer[1], bufer[2], bufer[3], bufer[4]); + + iounmap(backup_ram); + } else + printk(KERN_ERR "$$ ioremap failed\n"); + + return strlen(buf); +} + +static struct attribute usb_serial_number_attribute = \ + {.name = "serial_number", .mode = S_IRUGO}; + +static struct attribute *serial_number[] = { + &usb_serial_number_attribute, + NULL +}; + +const struct sysfs_ops usb_sysfs_ops = { + .show = usb_serial_number, +}; + +static struct kobj_type ktype_serial_number = { + .sysfs_ops = &usb_sysfs_ops, + .default_attrs = serial_number, +}; + static int __devinit ab8500_usb_probe(struct platform_device *pdev) { struct ab8500_usb *ab; @@ -814,6 +862,22 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) /* Needed to enable ID detection. */ ab8500_usb_wd_workaround(ab); + ab->serial_number_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); + + if (ab->serial_number_kobj == NULL) + ret = -ENOMEM; + ab->serial_number_kobj->ktype = &ktype_serial_number; + kobject_init(ab->serial_number_kobj, ab->serial_number_kobj->ktype); + + ret = kobject_set_name(ab->serial_number_kobj, "usb_serial_number"); + if (ret) + kfree(ab->serial_number_kobj); + + ret = kobject_add(ab->serial_number_kobj, NULL, "usb_serial_number"); + if (ret) + kfree(ab->serial_number_kobj); + + err = ab->usb_gpio->get(ab->dev); if (err < 0) goto fail3; -- cgit v1.2.3 From 7cb94416bbe29f018ec5efcdb762c5d60b1d6583 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 13 Sep 2011 16:35:14 +0530 Subject: musb: host: linux Kernel3.0 host dma disabled The dma driver disabled in Host Mode. Only enabled in Device mode. ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Change-Id: I5d26d2990d1c01a2ce461eb87f2e8d4518f0e40a Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30823 Reviewed-by: Praveena NADAHALLY --- drivers/usb/musb/musb_core.c | 1 - drivers/usb/musb/musb_host.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 1e46c24531c..86c255d6efa 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1868,7 +1868,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) status = -ENODEV; goto fail0; } - dev->dma_mask = 0 ; /* allocate */ musb = allocate_instance(dev, plat->config, ctrl); if (!musb) { diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index ff02e5924fb..ed496068192 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -46,6 +46,7 @@ #include "musb_core.h" #include "musb_host.h" +static bool is_host_dma_enabled; /* MUSB HOST status 22-mar-2006 * @@ -710,7 +711,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, musb_ep_select(mbase, epnum); /* candidate for DMA? */ - dma_controller = musb->dma_controller; + dma_controller = is_host_dma_enabled ? musb->dma_controller : NULL; if (is_dma_capable() && epnum && dma_controller) { dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel; if (!dma_channel) { @@ -2274,6 +2275,7 @@ static int musb_h_start(struct usb_hcd *hcd) */ hcd->state = HC_STATE_RUNNING; musb->port1_status = 0; + is_host_dma_enabled = false; return 0; } -- cgit v1.2.3 From 4169fc084a152b07ab91a826a0ba67d740c38afd Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 13 Sep 2011 14:03:27 +0530 Subject: ux500:USB:Generic USB GPIO frame work Making the existing U8500 usb gpio framework to generic. This allows other platforms to use the same structure. ST-Ericsson ID: NA ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: I3d5edc139e247b2373d1dd77243421e74783a0ea Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30790 --- arch/arm/mach-ux500/board-mop500-usb.h | 13 ------------- arch/arm/mach-ux500/board-ux500-usb.h | 13 +++++++++++++ arch/arm/mach-ux500/include/mach/usb.h | 2 +- arch/arm/mach-ux500/usb.c | 4 ++-- drivers/usb/otg/ab8500-usb.c | 2 +- include/linux/mfd/ab8500.h | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) delete mode 100644 arch/arm/mach-ux500/board-mop500-usb.h create mode 100644 arch/arm/mach-ux500/board-ux500-usb.h diff --git a/arch/arm/mach-ux500/board-mop500-usb.h b/arch/arm/mach-ux500/board-mop500-usb.h deleted file mode 100644 index 85288463a73..00000000000 --- a/arch/arm/mach-ux500/board-mop500-usb.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * Author: Saketh Ram Bommisetti - * License terms: GNU General Public License (GPL) version 2 - */ - -#ifndef __BOARD_MOP500_USB_H -#define __BOARD_MOP500_USB_H - -extern struct ab8500_usbgpio_platform_data ab8500_usbgpio_plat_data; - -#endif diff --git a/arch/arm/mach-ux500/board-ux500-usb.h b/arch/arm/mach-ux500/board-ux500-usb.h new file mode 100644 index 00000000000..6b35a181c0a --- /dev/null +++ b/arch/arm/mach-ux500/board-ux500-usb.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Saketh Ram Bommisetti + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __BOARD_UX500_USB_H +#define __BOARD_UX500_USB_H + +extern struct abx500_usbgpio_platform_data abx500_usbgpio_plat_data; + +#endif diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h index 5c27a72c10d..6277958c8a5 100644 --- a/arch/arm/mach-ux500/include/mach/usb.h +++ b/arch/arm/mach-ux500/include/mach/usb.h @@ -23,7 +23,7 @@ struct ux500_musb_board_data { void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg, int *dma_tx_cfg); -struct ab8500_usbgpio_platform_data { +struct abx500_usbgpio_platform_data { int (*get)(struct device *device); void (*enable)(void); void (*disable)(void); diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index b4f3b821922..5ee6aff6f74 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -12,7 +12,7 @@ #include #include #include "pins.h" -#include "board-mop500-usb.h" +#include "board-ux500-usb.h" #define MUSB_DMA40_RX_CH { \ .mode = STEDMA40_MODE_LOGICAL, \ @@ -158,7 +158,7 @@ static void put_gpio(void) { ux500_pins_put(usb_gpio_pins); } -struct ab8500_usbgpio_platform_data ab8500_usbgpio_plat_data = { +struct abx500_usbgpio_platform_data abx500_usbgpio_plat_data = { .get = &get_gpio, .enable = &enable_gpio, .disable = &disable_gpio, diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 64876c36494..a6b28f20b53 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -120,7 +120,7 @@ struct ab8500_usb { struct regulator *v_ape; struct regulator *v_musb; struct regulator *v_ulpi; - struct ab8500_usbgpio_platform_data *usb_gpio; + struct abx500_usbgpio_platform_data *usb_gpio; struct delayed_work work_usb_workaround; struct kobject *serial_number_kobj; }; diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index 9bb244621d3..1588d446b4d 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h @@ -193,7 +193,7 @@ struct ab8500_platform_data { int num_regulator; struct regulator_init_data *regulator; struct ab8500_gpio_platform_data *gpio; - struct ab8500_usbgpio_platform_data *usb; + struct abx500_usbgpio_platform_data *usb; }; extern int __devinit ab8500_init(struct ab8500 *ab8500); -- cgit v1.2.3 From 4f8cf5bfbfc583ece489f3c08556e645ccac67a9 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 15 Sep 2011 14:47:20 +0530 Subject: ux500: musb: Add support for Accessory Charging Adaptor ACA will allow simultanious connection to a host/device accessory along with dedicated charger using a single USB port on the platform. ST-Ericsson ID: WP 265141 ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-10160 Signed-off-by: Sakethram Bommisetti Signed-off-by: dushyanth.sr Change-Id: I934ff2a4775661e2a4894da6e49360060e0fa011 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31035 Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index a6b28f20b53..346aab67eec 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -294,6 +294,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) case USB_LINK_NOT_CONFIGURED: case USB_LINK_RESERVED: case USB_LINK_NOT_VALID_LINK: + case USB_LINK_ACA_RID_B: if (ab->mode == USB_HOST) ab8500_usb_host_phy_dis(ab); else if (ab->mode == USB_PERIPHERAL) @@ -310,28 +311,36 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) case USB_LINK_HOST_CHG_NM: case USB_LINK_HOST_CHG_HS: case USB_LINK_HOST_CHG_HS_CHIRP: - if (ab->otg.gadget) { + case USB_LINK_ACA_RID_C_NM: + case USB_LINK_ACA_RID_C_HS: + case USB_LINK_ACA_RID_C_HS_CHIRP: + if (ab->mode == USB_HOST) { + ab->mode = USB_PERIPHERAL; + ab8500_usb_host_phy_dis(ab); ab8500_usb_peri_phy_en(ab); + } + if (ab->mode == USB_IDLE) { ab->mode = USB_PERIPHERAL; + ab8500_usb_peri_phy_en(ab); } event = USB_EVENT_VBUS; break; case USB_LINK_HM_IDGND: - if (ab->otg.host) { + case USB_LINK_ACA_RID_A: + if (ab->mode == USB_PERIPHERAL) { + ab->mode = USB_HOST; + ab8500_usb_peri_phy_dis(ab); ab8500_usb_host_phy_en(ab); + } + if (ab->mode == USB_IDLE) { ab->mode = USB_HOST; + ab8500_usb_host_phy_en(ab); } ab->otg.default_a = true; event = USB_EVENT_ID; break; - case USB_LINK_ACA_RID_A: - case USB_LINK_ACA_RID_B: - /* TODO */ - case USB_LINK_ACA_RID_C_NM: - case USB_LINK_ACA_RID_C_HS: - case USB_LINK_ACA_RID_C_HS_CHIRP: case USB_LINK_DEDICATED_CHG: /* TODO: vbus_draw */ ab->mode = USB_DEDICATED_CHG; -- cgit v1.2.3 From da5be73548806046aee1cbde68da6c5bba9865c2 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 13 Sep 2011 17:04:27 +0530 Subject: usb:musb:Enable DMA mode1 RX for without short pkt This patch enables the DMA mode1 RX support This feature is enabled based on the short_not_ok flag passed from gadget drivers. This will result in a thruput performance gain of around 40% for USB mass-storage/mtp use cases. ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Signed-off-by: Anand Gadiyar ti.com> Signed-off-by: Moiz Sonasath ti.com> Signed-off-by: Vikram Pandita ti.com> Tested-by: Vikram Pandita ti.com> Change-Id: I17f58a018c1b5c0a4d89172fd2978a4e5da337f0 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30833 Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/musb_gadget.c | 98 +++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index e81820370d6..7ae88092e46 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -634,6 +634,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) u16 len; u16 csr = musb_readw(epio, MUSB_RXCSR); struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; + u8 use_mode_1; if (hw_ep->is_shared_fifo) musb_ep = &hw_ep->ep_in; @@ -683,6 +684,17 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (csr & MUSB_RXCSR_RXPKTRDY) { len = musb_readw(epio, MUSB_RXCOUNT); + + /* + * Enable Mode 1 on RX transfers only when short_not_ok flag + * is set. Currently short_not_ok flag is set only from + * file_storage and f_mass_storage drivers + */ + + if (request->short_not_ok && len == musb_ep->packet_sz) + use_mode_1 = 1; + else + use_mode_1 = 0; if (request->actual < request->length) { #ifdef CONFIG_USB_INVENTRA_DMA if (is_buffer_mapped(req)) { @@ -714,50 +726,56 @@ static void rxstate(struct musb *musb, struct musb_request *req) * then becomes usable as a runtime "use mode 1" hint... */ - csr |= MUSB_RXCSR_DMAENAB; -#ifdef USE_MODE1 - csr |= MUSB_RXCSR_AUTOCLEAR; - /* csr |= MUSB_RXCSR_DMAMODE; */ + /* Experimental: Mode1 works with mass storage use cases */ + if (use_mode_1) { + csr |= MUSB_RXCSR_AUTOCLEAR; - /* this special sequence (enabling and then - * disabling MUSB_RXCSR_DMAMODE) is required - * to get DMAReq to activate - */ - musb_writew(epio, MUSB_RXCSR, - csr | MUSB_RXCSR_DMAMODE); -#else - if (!musb_ep->hb_mult && - musb_ep->hw_ep->rx_double_buffered) - csr |= MUSB_RXCSR_AUTOCLEAR; -#endif - musb_writew(epio, MUSB_RXCSR, csr); + musb_writew(epio, MUSB_RXCSR, csr); + csr |= MUSB_RXCSR_DMAENAB; + musb_writew(epio, MUSB_RXCSR, csr); - if (request->actual < request->length) { - int transfer_size = 0; -#ifdef USE_MODE1 - transfer_size = min(request->length - request->actual, - channel->max_len); -#else - transfer_size = min(request->length - request->actual, - (unsigned)len); -#endif - if (transfer_size <= musb_ep->packet_sz) - musb_ep->dma->desired_mode = 0; - else - musb_ep->dma->desired_mode = 1; + /* + * this special sequence (enabling and then + * disabling MUSB_RXCSR_DMAMODE) is required + * to get DMAReq to activate + */ - use_dma = c->channel_program( - channel, - musb_ep->packet_sz, - channel->desired_mode, - request->dma - + request->actual, - transfer_size); - } + musb_writew(epio, MUSB_RXCSR, + csr | MUSB_RXCSR_DMAMODE); + musb_writew(epio, MUSB_RXCSR, csr); + } else { + if (!musb_ep->hb_mult && + musb_ep->hw_ep->rx_double_buffered) + csr |= MUSB_RXCSR_AUTOCLEAR; + csr |= MUSB_RXCSR_DMAENAB; + musb_writew(epio, MUSB_RXCSR, csr); + } - if (use_dma) - return; - } + if (request->actual < request->length) { + int transfer_size = 0; + + if (use_mode_1) { + transfer_size = min(request->length - request->actual, + channel->max_len); + musb_ep->dma->desired_mode = 1; + } else { + transfer_size = min(request->length - request->actual, + (unsigned)len); + musb_ep->dma->desired_mode = 0; + } + + use_dma = c->channel_program( + channel, + musb_ep->packet_sz, + channel->desired_mode, + request->dma + + request->actual, + transfer_size); + } + + if (use_dma) + return; + } #elif defined(CONFIG_USB_UX500_DMA) if ((is_buffer_mapped(req)) && (request->actual < request->length)) { -- cgit v1.2.3 From 7e383010c0d0b59f44d068e9fb143c44b273e2de Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Fri, 16 Sep 2011 17:49:27 +0530 Subject: u8500: USB: Remove max current constraint for abv3 In case of connection to standard host, maximum allowed current is freely set as part of enumeration. Maximum current limitation is retained only for ab versions below 3.0. ST-Ericsson ID: 343538 ST-Ericsson FOSS-OUT ID: Trivial ST-Ericsson Linux next: NA Signed-off-by: Sakethram Bommisetti Signed-off-by: dushyanth.sr Change-Id: Ia3375ce167bec1b4321e69e42f107b0550e98053 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31268 Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 346aab67eec..fc7efe3e929 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -407,16 +407,13 @@ static void ab8500_usb_phy_disable_work(struct work_struct *work) static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) { - if (mA > 100) { - /* AB V2 has eye diagram issues when drawing more - * than 100mA from VBUS.So setting charging current - * to 100mA in case of standard host - */ - if (ab->rev < 0x30) - mA = 100; - else - mA = 300; - } + /* AB V2 has eye diagram issues when drawing more + * than 100mA from VBUS.So setting charging current + * to 100mA in case of standard host + */ + if ((ab->rev < 0x30) && (mA > 100)) + mA = 100; + return mA; } -- cgit v1.2.3 From d34390de4d838f800030e5a470489c2798fc8bba Mon Sep 17 00:00:00 2001 From: Avinash Kumar Date: Mon, 19 Sep 2011 15:36:01 +0530 Subject: usb:Migrate the patches to kernel 3.0 Following patches for usb driver are manually merged to kernel 3.0 d11e52a ux500: usb: add usb device mode support on u5500 1fecc55 ux500: usb: enabling adb and ACM functionality in u5500_defconfig 2847bf4 ux500: usb: error handling in musb for u5500 37f22da ux500: usb: U5500 v2 update e1b079d ux500: usb: Fix for enumeration when ON with cable 181701a ux500: usb: Fix for V2 emmc2 boot USB device issue 3a60721 mach-ux500: Handle the LinkStatus register. 086a83e usb: ux500: usb gpio enable/disable in pair ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: Id918b9a55d3b85faf7c003547748f17086af3ec7 Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30860 --- arch/arm/mach-ux500/include/mach/usb.h | 1 + arch/arm/mach-ux500/usb.c | 3 + drivers/usb/musb/Kconfig | 2 +- drivers/usb/otg/Kconfig | 9 + drivers/usb/otg/Makefile | 1 + drivers/usb/otg/ab5500-usb.c | 734 +++++++++++++++++++++++++++++++++ 6 files changed, 749 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/otg/ab5500-usb.c diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h index 6277958c8a5..e3f4858c2e8 100644 --- a/arch/arm/mach-ux500/include/mach/usb.h +++ b/arch/arm/mach-ux500/include/mach/usb.h @@ -28,6 +28,7 @@ struct abx500_usbgpio_platform_data { void (*enable)(void); void (*disable)(void); void (*put)(void); + int usb_cs; }; #endif diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 5ee6aff6f74..11ad6f47757 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -34,6 +34,8 @@ .dst_info.psize = STEDMA40_PSIZE_LOG_16, \ } +#define USB_OTG_GPIO_CS 76 + static struct stedma40_chan_cfg musb_dma_rx_ch[UX500_MUSB_DMA_NUM_RX_CHANNELS] = { MUSB_DMA40_RX_CH, @@ -163,6 +165,7 @@ struct abx500_usbgpio_platform_data abx500_usbgpio_plat_data = { .enable = &enable_gpio, .disable = &disable_gpio, .put = &put_gpio, + .usb_cs = USB_OTG_GPIO_CS, }; static inline void ux500_usb_dma_update_rx_ch_config(int *src_dev_type) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 448dc12f3ff..1d8366efaf0 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -60,7 +60,7 @@ config USB_MUSB_BLACKFIN config USB_MUSB_UX500 tristate "U8500 and U5500" - depends on (ARCH_U8500 && AB8500_USB) || (ARCH_U5500) + depends on (ARCH_U8500) || (ARCH_U5500) endchoice diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index c66481ad98d..3db06194f1f 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -122,6 +122,15 @@ config AB8500_USB This transceiver supports high and full speed devices plus, in host mode, low speed. +config AB5500_USB + tristate "AB5500 USB Transceiver Driver" + depends on AB5500_CORE + select USB_OTG_UTILS + help + Enable this to support the USB OTG transceiver in AB5500 chip. + This transceiver supports high and full speed devices plus, + in host mode, low speed. + config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 566655c5333..90249f46153 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -19,5 +19,6 @@ obj-$(CONFIG_USB_ULPI) += ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi_viewport.o obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o obj-$(CONFIG_AB8500_USB) += ab8500-usb.o +obj-$(CONFIG_AB5500_USB) += ab5500-usb.o fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c new file mode 100644 index 00000000000..a4f4f58f847 --- /dev/null +++ b/drivers/usb/otg/ab5500-usb.c @@ -0,0 +1,734 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Avinash Kumar for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* AB5500 USB macros + */ +#define AB5500_USB_HOST_ENABLE 0x1 +#define AB5500_USB_HOST_DISABLE 0x0 +#define AB5500_USB_DEVICE_ENABLE 0x2 +#define AB5500_USB_DEVICE_DISABLE 0x0 +#define AB5500_MAIN_WATCHDOG_ENABLE 0x1 +#define AB5500_MAIN_WATCHDOG_KICK 0x2 +#define AB5500_MAIN_WATCHDOG_DISABLE 0x0 +#define AB5500_USB_ADP_ENABLE 0x1 +#define AB5500_WATCHDOG_DELAY 10 +#define AB5500_WATCHDOG_DELAY_US 100 +#define AB5500_PHY_DELAY_US 100 +#define AB5500_USB_DEVICE_DISABLE 0x0 +#define AB5500_MAIN_WDOG_CTRL_REG 0x01 +#define AB5500_USB_LINE_STAT_REG 0x80 +#define AB5500_USB_PHY_CTRL_REG 0x8A +#define AB5500_MAIN_WATCHDOG_ENABLE 0x1 +#define AB5500_MAIN_WATCHDOG_KICK 0x2 +#define AB5500_MAIN_WATCHDOG_DISABLE 0x0 +#define AB5500_SYS_CTRL2_BLOCK 0x2 + +#define USB_PROBE_DELAY 1000 /* 1 seconds */ + +/* UsbLineStatus register - usb types */ +enum ab8500_usb_link_status { + USB_LINK_NOT_CONFIGURED, + USB_LINK_STD_HOST_NC, + USB_LINK_STD_HOST_C_NS, + USB_LINK_STD_HOST_C_S, + USB_LINK_HOST_CHG_NM, + USB_LINK_HOST_CHG_HS, + USB_LINK_HOST_CHG_HS_CHIRP, + USB_LINK_DEDICATED_CHG, + USB_LINK_ACA_RID_A, + USB_LINK_ACA_RID_B, + USB_LINK_ACA_RID_C_NM, + USB_LINK_ACA_RID_C_HS, + USB_LINK_ACA_RID_C_HS_CHIRP, + USB_LINK_HM_IDGND, + USB_LINK_OTG_HOST_NO_CURRENT, + USB_LINK_NOT_VALID_LINK, + USB_LINK_HM_IDGND_V2 = 18, +}; + +/** + * ab5500_usb_mode - Different states of ab usb_chip + * + * Used for USB cable plug-in state machine + */ +enum ab5500_usb_mode { + USB_IDLE, + USB_DEVICE, + USB_HOST, + USB_DEDICATED_CHG, +}; +struct ab5500_usb { + struct otg_transceiver otg; + struct device *dev; + int irq_num_id_rise; + int irq_num_id_fall; + int irq_num_vbus_rise; + int irq_num_vbus_fall; + int irq_num_link_status; + unsigned vbus_draw; + struct delayed_work dwork; + struct work_struct phy_dis_work; + unsigned long link_status_wait; + int rev; + int usb_cs_gpio; + enum ab5500_usb_mode mode; + struct clk *sysclk; + struct regulator *v_ape; + struct abx500_usbgpio_platform_data *usb_gpio; + struct delayed_work work_usb_workaround; +}; + +static int ab5500_usb_irq_setup(struct platform_device *pdev, + struct ab5500_usb *ab); +static int ab5500_usb_boot_detect(struct ab5500_usb *ab); +static int ab5500_usb_link_status_update(struct ab5500_usb *ab); + +static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host); + +static inline struct ab5500_usb *xceiv_to_ab(struct otg_transceiver *x) +{ + return container_of(x, struct ab5500_usb, otg); +} + +/** + * ab5500_usb_wd_workaround() - Kick the watch dog timer + * + * This function used to Kick the watch dog timer + */ +static void ab5500_usb_wd_workaround(struct ab5500_usb *ab) +{ + abx500_set_register_interruptible(ab->dev, + AB5500_SYS_CTRL2_BLOCK, + AB5500_MAIN_WDOG_CTRL_REG, + AB5500_MAIN_WATCHDOG_ENABLE); + + udelay(AB5500_WATCHDOG_DELAY_US); + + abx500_set_register_interruptible(ab->dev, + AB5500_SYS_CTRL2_BLOCK, + AB5500_MAIN_WDOG_CTRL_REG, + (AB5500_MAIN_WATCHDOG_ENABLE + | AB5500_MAIN_WATCHDOG_KICK)); + + udelay(AB5500_WATCHDOG_DELAY_US); + + abx500_set_register_interruptible(ab->dev, + AB5500_SYS_CTRL2_BLOCK, + AB5500_MAIN_WDOG_CTRL_REG, + AB5500_MAIN_WATCHDOG_DISABLE); + + udelay(AB5500_WATCHDOG_DELAY_US); +} + +static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) +{ + u8 bit; + bit = sel_host ? AB5500_USB_HOST_ENABLE : + AB5500_USB_DEVICE_ENABLE; + + ab->usb_gpio->enable(); + clk_enable(ab->sysclk); + regulator_enable(ab->v_ape); + + if (!sel_host) { + schedule_delayed_work_on(0, + &ab->work_usb_workaround, + msecs_to_jiffies(USB_PROBE_DELAY)); + } + + abx500_set_register_interruptible(ab->dev, + AB5500_BANK_USB, + AB5500_USB_PHY_CTRL_REG, + bit); +} + +static void ab5500_usb_phy_disable(struct ab5500_usb *ab, bool sel_host) +{ + u8 bit; + bit = sel_host ? AB5500_USB_HOST_ENABLE : + AB5500_USB_DEVICE_ENABLE; + + abx500_set_register_interruptible(ab->dev, + AB5500_BANK_USB, + AB5500_USB_PHY_CTRL_REG, + bit); + + /* Needed to disable the phy.*/ + ab5500_usb_wd_workaround(ab); + + regulator_disable(ab->v_ape); + clk_disable(ab->sysclk); + ab->usb_gpio->disable(); + if (!sel_host) { + + cancel_delayed_work_sync(&ab->work_usb_workaround); + prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, + "usb", 25); + } + +} + +#define ab5500_usb_peri_phy_en(ab) ab5500_usb_phy_enable(ab, false) +#define ab5500_usb_peri_phy_dis(ab) ab5500_usb_phy_disable(ab, false) +#define ab5500_usb_host_phy_en(ab) ab5500_usb_phy_enable(ab, true) +#define ab5500_usb_host_phy_dis(ab) ab5500_usb_phy_disable(ab, true) + +/* Work created after an link status update handler*/ +static int ab5500_usb_link_status_update(struct ab5500_usb *ab) +{ + u8 val = 0; + int ret = 0; + int gpioval = 0; + enum ab8500_usb_link_status lsts; + enum usb_xceiv_events event; + + (void)abx500_get_register_interruptible(ab->dev, + AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &val); + + lsts = (val >> 3) & 0x0F; + + switch (lsts) { + + case USB_LINK_STD_HOST_NC: + case USB_LINK_STD_HOST_C_NS: + case USB_LINK_STD_HOST_C_S: + case USB_LINK_HOST_CHG_NM: + case USB_LINK_HOST_CHG_HS: + case USB_LINK_HOST_CHG_HS_CHIRP: + if (ab->otg.gadget) { + ab5500_usb_peri_phy_en(ab); + ab->mode = USB_DEVICE; + } + gpio_set_value(ab->usb_cs_gpio, 1); + event = USB_EVENT_VBUS; + break; + + case USB_LINK_HM_IDGND: + if (ab->rev == AB5500_2_0) + break; + + /* enable usb chip Select */ + ret = gpio_direction_output(ab->usb_cs_gpio, gpioval); + if (ret < 0) { + dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); + gpio_free(ab->usb_cs_gpio); + return ret; + } + gpio_set_value(ab->usb_cs_gpio, 1); + + ab5500_usb_host_phy_en(ab); + + break; + + case USB_LINK_HM_IDGND_V2: + if (!(ab->rev == AB5500_2_0)) + break; + + /* enable usb chip Select */ + ret = gpio_direction_output(ab->usb_cs_gpio, gpioval); + if (ret < 0) { + dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); + gpio_free(ab->usb_cs_gpio); + return ret; + } + gpio_set_value(ab->usb_cs_gpio, 1); + + ab5500_usb_host_phy_en(ab); + + break; + default: + break; + } + + atomic_notifier_call_chain(&ab->otg.notifier, event, &ab->vbus_draw); + + return 0; +} + +static void ab5500_usb_delayed_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct ab5500_usb *ab = container_of(dwork, struct ab5500_usb, dwork); + + ab5500_usb_link_status_update(ab); +} + +/** + * This function is used to signal the completion of + * USB Link status register update + */ +static irqreturn_t ab5500_usb_link_status_irq(int irq, void *data) +{ + struct ab5500_usb *ab = (struct ab5500_usb *) data; + ab5500_usb_link_status_update(ab); + + return IRQ_HANDLED; +} + +static irqreturn_t ab5500_usb_device_insert_irq(int irq, void *data) +{ + int ret = 0, val = 1; + struct ab5500_usb *ab = (struct ab5500_usb *) data; + ab->mode = USB_DEVICE; + + ab5500_usb_peri_phy_en(ab); + /* enable usb chip Select */ + ret = gpio_direction_output(ab->usb_cs_gpio, val); + if (ret < 0) { + dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); + gpio_free(ab->usb_cs_gpio); + return ret; + } + gpio_set_value(ab->usb_cs_gpio, 1); + + return IRQ_HANDLED; +} + +/** + * This function used to remove the voltage for USB ab->dev mode. + */ +static irqreturn_t ab5500_usb_device_disconnect_irq(int irq, void *data) +{ + struct ab5500_usb *ab = (struct ab5500_usb *) data; + /* disable usb chip Select */ + gpio_set_value(ab->usb_cs_gpio, 0); + ab5500_usb_peri_phy_dis(ab); + return IRQ_HANDLED; +} + +/** + * ab5500_usb_host_disconnect_irq : work handler for host cable insert. + * @work: work structure + * + * This function is used to handle the host cable insert work. + */ +static void ab5500_usb_host_disconnect_irq(int irq, void *data) +{ + struct ab5500_usb *ab = (struct ab5500_usb *) data; + /* disable usb chip Select */ + gpio_set_value(ab->usb_cs_gpio, 0); + ab5500_usb_host_phy_dis(ab); + return IRQ_HANDLED; +} + +static void ab5500_usb_irq_free(struct ab5500_usb *ab) +{ + if (ab->irq_num_id_rise) + free_irq(ab->irq_num_id_rise, ab); + + if (ab->irq_num_id_fall) + free_irq(ab->irq_num_id_fall, ab); + + if (ab->irq_num_vbus_rise) + free_irq(ab->irq_num_vbus_rise, ab); + + if (ab->irq_num_vbus_fall) + free_irq(ab->irq_num_vbus_fall, ab); + + if (ab->irq_num_link_status) + free_irq(ab->irq_num_link_status, ab); +} + +/** + * ab5500_usb_irq_setup : register USB callback handlers for ab5500 + * @mode: value for mode. + * + * This function is used to register USB callback handlers for ab5500. + */ +static int ab5500_usb_irq_setup(struct platform_device *pdev, + struct ab5500_usb *ab) +{ + int ret = 0; + int irq, err; + + if (!ab->dev) + return -EINVAL; + + irq = platform_get_irq_byname(pdev, "usb_idgnd_f"); + if (irq < 0) { + dev_err(&pdev->dev, "ID fall irq not found\n"); + err = irq; + goto irq_fail; + } + ab->irq_num_id_fall = irq; + + irq = platform_get_irq_byname(pdev, "VBUS_F"); + if (irq < 0) { + dev_err(&pdev->dev, "VBUS fall irq not found\n"); + err = irq; + goto irq_fail; + + } + ab->irq_num_vbus_fall = irq; + + irq = platform_get_irq_byname(pdev, "VBUS_R"); + if (irq < 0) { + dev_err(&pdev->dev, "VBUS raise irq not found\n"); + err = irq; + goto irq_fail; + + } + ab->irq_num_vbus_rise = irq; + + irq = platform_get_irq_byname(pdev, "Link_Update"); + if (irq < 0) { + dev_err(&pdev->dev, "Link Update irq not found\n"); + err = irq; + goto irq_fail; + } + ab->irq_num_link_status = irq; + + + ret = request_threaded_irq(ab->irq_num_link_status, + NULL, ab5500_usb_link_status_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-link-status-update", ab); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb charge" + " detect done\n"); + err = ret; + goto irq_fail; + } + + ret = request_threaded_irq(ab->irq_num_vbus_rise, NULL, + ab5500_usb_device_insert_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-vbus-rise", ab); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb ab->dev" + " insertion\n"); + err = ret; + goto irq_fail; + } + + ret = request_threaded_irq(ab->irq_num_vbus_fall, NULL, + ab5500_usb_device_disconnect_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-vbus-fall", ab); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb ab->dev" + " removal\n"); + err = ret; + goto irq_fail; + } + + ret = request_threaded_irq((ab->irq_num_id_fall), NULL, + ab5500_usb_host_disconnect_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, + "usb-id-fall", ab); + if (ret < 0) { + printk(KERN_ERR "failed to set the callback" + " handler for usb host" + " removal\n"); + err = ret; + goto irq_fail; + } + + ab5500_usb_wd_workaround(ab); + return 0; + +irq_fail: + ab5500_usb_irq_free(ab); + return err; +} + +/** + * ab5500_usb_boot_detect : detect the USB cable during boot time. + * @mode: value for mode. + * + * This function is used to detect the USB cable during boot time. + */ +static int ab5500_usb_boot_detect(struct ab5500_usb *ab) +{ + int ret; + int val = 1; + int usb_status = 0; + int gpioval = 0; + enum ab8500_usb_link_status lsts; + if (!ab->dev) + return -EINVAL; + + abx500_set_register_interruptible(ab->dev, + AB5500_BANK_USB, + AB5500_USB_PHY_CTRL_REG, + AB5500_USB_DEVICE_ENABLE); + + udelay(AB5500_PHY_DELAY_US); + + abx500_set_register_interruptible(ab->dev, + AB5500_BANK_USB, + AB5500_USB_PHY_CTRL_REG, + AB5500_USB_DEVICE_DISABLE); + + abx500_set_register_interruptible(ab->dev, + AB5500_BANK_USB, + AB5500_USB_PHY_CTRL_REG, + AB5500_USB_HOST_ENABLE); + + udelay(AB5500_PHY_DELAY_US); + + abx500_set_register_interruptible(ab->dev, + AB5500_BANK_USB, + AB5500_USB_PHY_CTRL_REG, + AB5500_USB_HOST_DISABLE); + + ab5500_usb_wd_workaround(ab); + + (void)abx500_get_register_interruptible(ab->dev, + AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &usb_status); + + lsts = (usb_status >> 3) & 0x0F; + + switch (lsts) { + + case USB_LINK_STD_HOST_NC: + case USB_LINK_STD_HOST_C_NS: + case USB_LINK_STD_HOST_C_S: + case USB_LINK_HOST_CHG_NM: + case USB_LINK_HOST_CHG_HS: + case USB_LINK_HOST_CHG_HS_CHIRP: + + ab5500_usb_peri_phy_en(ab); + + /* enable usb chip Select */ + ret = gpio_direction_output(ab->usb_cs_gpio, val); + if (ret < 0) { + dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); + gpio_free(ab->usb_cs_gpio); + return ret; + } + gpio_set_value(ab->usb_cs_gpio, 1); + + break; + + case USB_LINK_HM_IDGND: + case USB_LINK_HM_IDGND_V2: + /* enable usb chip Select */ + ret = gpio_direction_output(ab->usb_cs_gpio, gpioval); + if (ret < 0) { + dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); + gpio_free(ab->usb_cs_gpio); + return ret; + } + gpio_set_value(ab->usb_cs_gpio, 1); + ab5500_usb_host_phy_en(ab); + + break; + default: + break; + } + + return 0; +} + +static int ab5500_usb_set_power(struct otg_transceiver *otg, unsigned mA) +{ + struct ab5500_usb *ab; + + if (!otg) + return -ENODEV; + + ab = xceiv_to_ab(otg); + + ab->vbus_draw = mA; + + atomic_notifier_call_chain(&ab->otg.notifier, + USB_EVENT_VBUS, &ab->vbus_draw); + return 0; +} + +static int ab5500_usb_set_suspend(struct otg_transceiver *x, int suspend) +{ + /* TODO */ + return 0; +} + +static int ab5500_usb_set_host(struct otg_transceiver *otg, + struct usb_bus *host) +{ + struct ab5500_usb *ab; + + if (!otg) + return -ENODEV; + + ab = xceiv_to_ab(otg); + + /* Some drivers call this function in atomic context. + * Do not update ab5500 registers directly till this + * is fixed. + */ + + if (!host) { + ab->otg.host = NULL; + schedule_work(&ab->phy_dis_work); + } else { + ab->otg.host = host; + /* Phy will not be enabled if cable is already + * plugged-in. Schedule to enable phy. + * Use same delay to avoid any race condition. + */ + schedule_delayed_work(&ab->dwork, ab->link_status_wait); + } + + return 0; +} + +static int ab5500_usb_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget) +{ + struct ab5500_usb *ab; + + if (!otg) + return -ENODEV; + + ab = xceiv_to_ab(otg); + + /* Some drivers call this function in atomic context. + * Do not update ab5500 registers directly till this + * is fixed. + */ + + if (!gadget) { + ab->otg.gadget = NULL; + schedule_work(&ab->phy_dis_work); + } else { + ab->otg.gadget = gadget; + /* Phy will not be enabled if cable is already + * plugged-in. Schedule to enable phy. + * Use same delay to avoid any race condition. + */ + schedule_delayed_work(&ab->dwork, ab->link_status_wait); + } + + return 0; +} + +static int __devinit ab5500_usb_probe(struct platform_device *pdev) +{ + struct ab5500_usb *ab; + struct abx500_usbgpio_platform_data *usb_pdata = + pdev->dev.platform_data; + int err; + int rev; + int ret = -1; + int irq; + ab = kzalloc(sizeof *ab, GFP_KERNEL); + if (!ab) + return -ENOMEM; + + ab->dev = &pdev->dev; + ab->rev = rev; + ab->otg.dev = ab->dev; + ab->otg.label = "ab5500"; + ab->otg.state = OTG_STATE_B_IDLE; + ab->otg.set_host = ab5500_usb_set_host; + ab->otg.set_peripheral = ab5500_usb_set_peripheral; + ab->otg.set_suspend = ab5500_usb_set_suspend; + ab->otg.set_power = ab5500_usb_set_power; + ab->usb_gpio = usb_pdata; + ab->mode = USB_IDLE; + + platform_set_drvdata(pdev, ab); + + ATOMIC_INIT_NOTIFIER_HEAD(&ab->otg.notifier); + + /* v1: Wait for link status to become stable. + * all: Updates form set_host and set_peripheral as they are atomic. + */ + INIT_DELAYED_WORK(&ab->dwork, ab5500_usb_delayed_work); + + err = otg_set_transceiver(&ab->otg); + if (err) + dev_err(&pdev->dev, "Can't register transceiver\n"); + + ab->usb_cs_gpio = ab->usb_gpio->usb_cs; + + ab->rev = abx500_get_chip_id(ab->dev); + + ab->sysclk = clk_get(ab->dev, "sysclk"); + if (IS_ERR(ab->sysclk)) { + ret = PTR_ERR(ab->sysclk); + ab->sysclk = NULL; + return ret; + } + + ab->v_ape = regulator_get(ab->dev, "v-ape"); + if (!ab->v_ape) { + dev_err(ab->dev, "Could not get v-ape supply\n"); + + return -EINVAL; + } + + ab5500_usb_irq_setup(pdev, ab); + + ret = gpio_request(ab->usb_cs_gpio, "usb-cs"); + if (ret < 0) + dev_err(&pdev->dev, "usb gpio request fail\n"); + + /* Aquire GPIO alternate config struct for USB */ + err = ab->usb_gpio->get(ab->dev); + if (err < 0) + goto fail1; + + err = ab5500_usb_boot_detect(ab); + if (err < 0) + goto fail1; + + return 0; + +fail1: + ab5500_usb_irq_free(ab); + kfree(ab); + return err; +} + +static int __devexit ab5500_usb_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver ab5500_usb_driver = { + .driver = { + .name = "ab5500-usb", + .owner = THIS_MODULE, + }, + .probe = ab5500_usb_probe, + .remove = __devexit_p(ab5500_usb_remove), +}; + +static int __init ab5500_usb_init(void) +{ + return platform_driver_register(&ab5500_usb_driver); +} +subsys_initcall(ab5500_usb_init); + +static void __exit ab5500_usb_exit(void) +{ + platform_driver_unregister(&ab5500_usb_driver); +} +module_exit(ab5500_usb_exit); + +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 3fcb2b7924a1c2e47165b7256a46af5f7130250a Mon Sep 17 00:00:00 2001 From: Avinash Kumar Date: Mon, 19 Sep 2011 16:51:21 +0530 Subject: u5500: usb: Kernel 3.0 fix for delayed work fixing issue of scheduling delayed work work_usb_workaround which is not needed for u5500 ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Avinash Kumar Change-Id: I07eaca9f90aa91892f05260e7722e6703e8baf84 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31340 Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab5500-usb.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index a4f4f58f847..bee9c42673c 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -95,7 +95,6 @@ struct ab5500_usb { struct clk *sysclk; struct regulator *v_ape; struct abx500_usbgpio_platform_data *usb_gpio; - struct delayed_work work_usb_workaround; }; static int ab5500_usb_irq_setup(struct platform_device *pdev, @@ -150,12 +149,6 @@ static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) clk_enable(ab->sysclk); regulator_enable(ab->v_ape); - if (!sel_host) { - schedule_delayed_work_on(0, - &ab->work_usb_workaround, - msecs_to_jiffies(USB_PROBE_DELAY)); - } - abx500_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, @@ -179,13 +172,6 @@ static void ab5500_usb_phy_disable(struct ab5500_usb *ab, bool sel_host) regulator_disable(ab->v_ape); clk_disable(ab->sysclk); ab->usb_gpio->disable(); - if (!sel_host) { - - cancel_delayed_work_sync(&ab->work_usb_workaround); - prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, - "usb", 25); - } - } #define ab5500_usb_peri_phy_en(ab) ab5500_usb_phy_enable(ab, false) -- cgit v1.2.3 From 499965ea9a33a9165a0c5861aa965a05ca0ae0ef Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Fri, 16 Sep 2011 16:46:55 +0530 Subject: musb : host : Enable Host DMA support This enables host functionality with DMA. ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Change-Id: I9f3d65f3cf337f557825725f99d78f4470a651f9 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31260 Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/musb_core.h | 1 - drivers/usb/musb/musb_host.c | 21 ++++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 0de1fad9a1f..b3c065ab9db 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -276,7 +276,6 @@ struct musb_hw_ep { u8 rx_reinit; u8 tx_reinit; - bool do_tx_pio; /* peripheral side */ struct musb_ep ep_in; /* TX */ diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index ed496068192..cfe315a9581 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -46,8 +46,6 @@ #include "musb_core.h" #include "musb_host.h" -static bool is_host_dma_enabled; - /* MUSB HOST status 22-mar-2006 * * - There's still lots of partial code duplication for fault paths, so @@ -308,7 +306,7 @@ start: dev_dbg(musb->controller, "Start TX%d %s\n", epnum, hw_ep->tx_channel ? "dma" : "pio"); - if (!hw_ep->tx_channel || hw_ep->do_tx_pio) + if (!hw_ep->tx_channel) musb_h_tx_start(hw_ep); else if (is_cppi_enabled() || tusb_dma_omap()) musb_h_tx_dma_start(hw_ep); @@ -674,6 +672,8 @@ static bool musb_tx_dma_program(struct dma_controller *dma, if (!dma->channel_program(channel, pkt_size, mode, urb->transfer_dma + offset, length)) { + dma->channel_release(channel); + hw_ep->tx_channel = NULL; csr = musb_readw(epio, MUSB_TXCSR); csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); @@ -711,7 +711,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, musb_ep_select(mbase, epnum); /* candidate for DMA? */ - dma_controller = is_host_dma_enabled ? musb->dma_controller : NULL; + dma_controller = musb->dma_controller; if (is_dma_capable() && epnum && dma_controller) { dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel; if (!dma_channel) { @@ -808,11 +808,11 @@ static void musb_ep_program(struct musb *musb, u8 epnum, else load_count = min((u32) packet_sz, len); - if (!dma_channel || !musb_tx_dma_program(dma_controller, + if (dma_channel && musb_tx_dma_program(dma_controller, hw_ep, qh, urb, offset, len)) - hw_ep->do_tx_pio = true; + load_count = 0; - if (hw_ep->do_tx_pio) { + if (load_count) { /* PIO to load FIFO */ /* Unmap the buffer so that CPU can use it */ usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); @@ -1122,7 +1122,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) struct urb *urb = next_urb(qh); u32 status = 0; void __iomem *mbase = musb->mregs; - struct dma_channel *dma = NULL; + struct dma_channel *dma; bool transfer_pending = false; musb_ep_select(mbase, epnum); @@ -1753,9 +1753,9 @@ void musb_host_rx(struct musb *musb, u8 epnum) dma->desired_mode, buf, length); if (!ret) { + c->channel_release(dma); + hw_ep->rx_channel = NULL; dma = NULL; - /* Restore CSR */ - musb_writew(epio, MUSB_RXCSR, rx_csr); } } #endif /* Mentor DMA */ @@ -2275,7 +2275,6 @@ static int musb_h_start(struct usb_hcd *hcd) */ hcd->state = HC_STATE_RUNNING; musb->port1_status = 0; - is_host_dma_enabled = false; return 0; } -- cgit v1.2.3 From d009be82dbbe1592125a3c2403dc01096e932622 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 20 Sep 2011 16:45:02 +0530 Subject: musb:host: Fix for musb host receive in PIO mode restore MUSB_RXCSR to original value when dma is not used. ST-Ericsson ID: ER 321774 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ia375a5a8da423bafae107248a4ea25158bce4793 Signed-off-by: Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31466 Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/musb_host.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index cfe315a9581..2582389881d 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1447,7 +1447,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) size_t xfer_len; void __iomem *mbase = musb->mregs; int pipe; - u16 rx_csr, val; + u16 rx_csr, val, restore_csr; bool iso_err = false; bool done = false; u32 status; @@ -1729,6 +1729,11 @@ void musb_host_rx(struct musb *musb, u8 epnum) */ val = musb_readw(epio, MUSB_RXCSR); + + /* retain the original value, + * which will be used to reset CSR + */ + restore_csr = val; val &= ~MUSB_RXCSR_H_REQPKT; if (dma->desired_mode == 0) @@ -1757,6 +1762,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) hw_ep->rx_channel = NULL; dma = NULL; } + musb_writew(epio, MUSB_RXCSR, restore_csr); } #endif /* Mentor DMA */ -- cgit v1.2.3 From c99809bdec651623ee233f9c98385f95abaef79f Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Wed, 21 Sep 2011 09:12:59 +0530 Subject: musb:host:Notifier call registered for host enable Registering notifier call handled, to enable the host funtionality. ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I4f415ac61153372c81f6fc4d46ffb1e4e63d0d2c Signed-off-by: Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31572 Reviewed-by: Rabin VINCENT --- drivers/usb/musb/ux500.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index a80663d4187..f860b5ce59a 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -47,11 +47,6 @@ static int musb_otg_notifications(struct notifier_block *nb, case USB_EVENT_ID: dev_dbg(musb->controller, "ID GND\n"); if (is_otg_enabled(musb)) { -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - if (musb->gadget_driver) - ux500_musb_set_vbus(musb, 1); -#endif - } else { ux500_musb_set_vbus(musb, 1); } break; @@ -63,13 +58,6 @@ static int musb_otg_notifications(struct notifier_block *nb, case USB_EVENT_NONE: dev_dbg(musb->controller, "VBUS Disconnect\n"); -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) - if (musb->gadget_driver) -#endif - { - dev_dbg(musb->controller, "Add runtime powermangement code here\n"); - } break; default: @@ -140,6 +128,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) static int ux500_musb_init(struct musb *musb) { + int status; musb->xceiv = otg_get_transceiver(); if (!musb->xceiv) { pr_err("HS USB OTG: no transceiver configured\n"); @@ -147,7 +136,16 @@ static int ux500_musb_init(struct musb *musb) } musb->nb.notifier_call = musb_otg_notifications; + status = otg_register_notifier(musb->xceiv, &musb->nb); + + if (status < 0) { + dev_dbg(musb->controller, "notification register failed\n"); + goto err1; + } + return 0; +err1: + return status; } /** -- cgit v1.2.3 From 806635f0692b390152db7001541d41e44a78ba58 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Fri, 23 Sep 2011 14:52:00 +0530 Subject: ux500:USB:Fix for Build issue of HTML Docs "pubfunctions" is required in the .tmpl file as the compiler uses it. Adding "pubfunctions" in ux500_usb.tmpl file. ST-Ericsson ID: NA ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Sakethram Bommisetti Change-Id: Ic927f2001e9d0fff070a7d7b9b9871c011905aef Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31845 Reviewed-by: Praveena NADAHALLY Reviewed-by: Jonas ABERG --- Documentation/DocBook/ux500_usb.tmpl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/ux500_usb.tmpl b/Documentation/DocBook/ux500_usb.tmpl index f31f3784e93..71b744386d4 100644 --- a/Documentation/DocBook/ux500_usb.tmpl +++ b/Documentation/DocBook/ux500_usb.tmpl @@ -121,7 +121,12 @@ - + + Public Functions Provided + + The musb driver doesn't export any functions. + + Internal Functions Provided @@ -143,5 +148,4 @@ !Idrivers/usb/musb/ux500.c - -- cgit v1.2.3 From aa8540e1d1db94d54595c70ded73c67bcbf0a396 Mon Sep 17 00:00:00 2001 From: Ravikant Singh Date: Fri, 23 Sep 2011 17:25:31 +0530 Subject: u5500: usb: ISR return type corrected for usb host return type changed to irqreturn_t from void for function ab5500_usb_host_disconnect_irq() ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Ravikant Singh Signed-off-by: Avinash Kumar Change-Id: I85819cb20418fc39e1febb7b1ea1a1211f825fb2 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31867 Reviewed-by: Jonas ABERG --- drivers/usb/otg/ab5500-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index bee9c42673c..3f69e4c2c06 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -308,7 +308,7 @@ static irqreturn_t ab5500_usb_device_disconnect_irq(int irq, void *data) * * This function is used to handle the host cable insert work. */ -static void ab5500_usb_host_disconnect_irq(int irq, void *data) +static irqreturn_t ab5500_usb_host_disconnect_irq(int irq, void *data) { struct ab5500_usb *ab = (struct ab5500_usb *) data; /* disable usb chip Select */ -- cgit v1.2.3 From 8a0572ff3fa953e321b330c6c4c59ced8bf06346 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Mon, 26 Sep 2011 19:17:30 +0530 Subject: musb:host: Fix for musb host receive in PIO mode restore MUSB_RXCSR code is misplaced,Handling properly. ST-Ericsson ID: AP 363893 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Change-Id: I3f0499487a1d5e4837ade52e6fb8f0f573cce217 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31989 Reviewed-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/musb/musb_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 2582389881d..54aed9b2386 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1761,8 +1761,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) c->channel_release(dma); hw_ep->rx_channel = NULL; dma = NULL; + musb_writew(epio, MUSB_RXCSR, restore_csr); } - musb_writew(epio, MUSB_RXCSR, restore_csr); } #endif /* Mentor DMA */ -- cgit v1.2.3 From a94703dcbf3d3d48194d33acbc08333e82469eb8 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Mon, 26 Sep 2011 19:48:44 +0530 Subject: Revert "ux500:USB:Disable DMA for device mode" This reverts commit cc851c0c7146330d1fe1b44f10ff8d88e2c09bb7. Change-Id: I437b587c6566170ea3f65cad6f2f72531b5fe33b Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31992 Tested-by: Thirupathi CHIPPAKURTHY Reviewed-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/musb/ux500_dma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index e334d247537..ecab2bf997e 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -263,14 +263,13 @@ static void ux500_dma_channel_release(struct dma_channel *channel) static int ux500_dma_is_compatible(struct dma_channel *channel, u16 maxpacket, void *buf, u32 length) { - /*if ((maxpacket & 0x3) || + if ((maxpacket & 0x3) || ((int)buf & 0x3) || (length < 512) || (length & 0x3)) return false; else - return true;*/ - return false; + return true; } /** -- cgit v1.2.3 From 73dd46689fc3dffc51fca5497b27ddfd9dfcea5e Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 22 Sep 2011 15:15:47 +0530 Subject: ux500:USB:Handing the state machine for Host and Device modes Setting the default state OTG_STATE_B_IDLE when there is removal of USB cable(Either Host or Device). ST-Ericsson ID: 363539 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: Ia066f9a1cb3433bc54bc934f9b0e9eeaf222f89b Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31860 Reviewed-by: Jonas ABERG Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/ux500.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index f860b5ce59a..95f7fa4a831 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -37,6 +37,32 @@ struct ux500_glue { }; #define glue_to_musb(g) platform_get_drvdata(g->musb) +static struct timer_list notify_timer; + +static void musb_notify_idle(unsigned long _musb) +{ + struct musb *musb = (void *)_musb; + unsigned long flags; + + u8 devctl; + + spin_lock_irqsave(&musb->lock, flags); + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + switch (musb->xceiv->state) { + case OTG_STATE_A_WAIT_BCON: + devctl &= ~MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + musb->xceiv->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + break; + case OTG_STATE_A_SUSPEND: + default: + break; + } + spin_unlock_irqrestore(&musb->lock, flags); +} + /* blocking notifier support */ static int musb_otg_notifications(struct notifier_block *nb, unsigned long event, void *unused) @@ -126,6 +152,40 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) musb_readb(musb->mregs, MUSB_DEVCTL)); } +static void ux500_musb_try_idle(struct musb *musb, unsigned long timeout) +{ + static unsigned long last_timer; + + if (timeout == 0) + timeout = jiffies + msecs_to_jiffies(3); + + /* Never idle if active, or when VBUS timeout is not set as host */ + if (musb->is_active || ((musb->a_wait_bcon == 0) + && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { + dev_dbg(musb->controller, "%s active, deleting timer\n", + otg_state_string(musb->xceiv->state)); + del_timer(¬ify_timer); + last_timer = jiffies; + return; + } + + if (time_after(last_timer, timeout)) { + if (!timer_pending(¬ify_timer)) + last_timer = timeout; + else { + dev_dbg(musb->controller, "Longer idle timer " + "already pending, ignoring\n"); + return; + } + } + last_timer = timeout; + + dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", + otg_state_string(musb->xceiv->state), + (unsigned long)jiffies_to_msecs(timeout - jiffies)); + mod_timer(¬ify_timer, timeout); +} + static int ux500_musb_init(struct musb *musb) { int status; @@ -143,6 +203,8 @@ static int ux500_musb_init(struct musb *musb) goto err1; } + setup_timer(¬ify_timer, musb_notify_idle, (unsigned long) musb); + return 0; err1: return status; @@ -166,6 +228,7 @@ static const struct musb_platform_ops ux500_ops = { .exit = ux500_musb_exit, .set_vbus = ux500_musb_set_vbus, + .try_idle = ux500_musb_try_idle, }; /** -- cgit v1.2.3 From a97dd81520e0a9fe3f45a038a21c50412cf1a6d7 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 22 Sep 2011 14:28:04 +0530 Subject: ux500: USB: Set the charging cur to 300mA for ABV3 In case of AB-V3, the eye diagram related issues are resolved. So, set the device charging current to 300mA when connected to standard host. Also, add the USB PHY tuning values to improve the USB eye diagram. This votage setting for v-initcore is missing as part of the patch:http://gerrit.lud.stericsson.com/gerrit/#change,30031 Adding the missing information from this patch ST-Ericsson ID: 330203 ST-Ericsson Linux next: ER 330203 ST-Ericsson FOSS-OUT ID: NA Change-Id: Id17fd6c1b6ac1f77890659c4d78eaece941b037a Signed-off-by: Sakethram Bommisetti Signed-off-by: Praveena Nadahally Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31849 Reviewed-by: Jonas ABERG Reviewed-by: Srinidhi KASAGAR Signed-off-by: Robert Marklund --- drivers/usb/otg/ab8500-usb.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index fc7efe3e929..dff49336fe5 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -184,9 +184,31 @@ static void ab8500_usb_load(struct work_struct *work) static void ab8500_usb_regulator_ctrl(struct ab8500_usb *ab, bool sel_host, bool enable) { + int ret = 0, volt = 0; + if (enable) { regulator_enable(ab->v_ape); + if (ab->rev >= 0x30) { + ret = regulator_set_voltage(ab->v_ulpi, + 1300000, 1350000); + if (ret < 0) + dev_err(ab->dev, "Failed to set the Vintcore" + " to 1.3V, ret=%d\n", ret); + ret = regulator_set_optimum_mode(ab->v_ulpi, + 28000); + if (ret < 0) + dev_err(ab->dev, "Failed to set optimum mode" + " (ret=%d)\n", ret); + + } regulator_enable(ab->v_ulpi); + if (ab->rev >= 0x30) { + volt = regulator_get_voltage(ab->v_ulpi); + if ((volt != 1300000) && (volt != 1350000)) + dev_err(ab->dev, "Vintcore is not" + " set to 1.3V" + " volt=%d\n", volt); + } regulator_enable(ab->v_musb); } else { @@ -820,7 +842,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) } /* Write Phy tuning values */ - if (ab->rev == 0x30) { + if (ab->rev >= 0x30) { /* Enable the PBT/Bank 0x12 access */ ret = abx500_set_register_interruptible(ab->dev, AB8500_DEVELOPMENT, -- cgit v1.2.3 From 56e30e119d97d522479abbfdec4241b5e3916af0 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 27 Sep 2011 16:18:13 +0530 Subject: musb: host: Wait for TXPKTRDY to clear in host MUSB_TXCSR_TXPKTRDY will not get cleared if the data is not on the bus. So, need to wait for it to clear in the DMA completion callback.As per musb datasheet, generally mode 1 needs to be used for data length greater than or equal to max packet size. ST-Ericsson ID:AP 363893 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: I934295798a5fbccf60c6f4004595b625a98098ed Signed-off-by: Signed-off-by: Praveena Signed-off-by: rajaram Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32012 Reviewed-by: Rabin VINCENT --- drivers/usb/musb/musb_host.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 54aed9b2386..07e25fa1bf2 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -636,7 +636,7 @@ static bool musb_tx_dma_program(struct dma_controller *dma, length = channel->max_len; csr = musb_readw(epio, MUSB_TXCSR); - if (length > pkt_size) { + if (length >= pkt_size) { mode = 1; csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB; /* autoset shouldn't be set in high bandwidth */ @@ -1154,6 +1154,21 @@ void musb_host_tx(struct musb *musb, u8 epnum) status = -ETIMEDOUT; } else if (tx_csr & MUSB_TXCSR_TXPKTRDY) { /* BUSY - can happen during USB transfer cancel */ + + /* MUSB_TXCSR_TXPKTRDY indicates that the data written + * to the FIFO by DMA has not still gone on the USB bus. + * DMA completion callback doesn't indicate that data has + * gone on the USB bus. So, if we reach this case, need to + * wait for the MUSB_TXCSR_TXPKTRDY to be cleared and then + * proceed. + */ + dev_dbg(musb->controller, "TXPKTRDY set. Data transfer ongoing. Wait...\n"); + + do { + tx_csr = musb_readw(epio, MUSB_TXCSR); + } while ((tx_csr & MUSB_TXCSR_TXPKTRDY) != 0); + dev_dbg(musb->controller, "TXPKTRDY Cleared. Continue...\n"); + return; } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum); -- cgit v1.2.3 From d0447b8d76591608870197a297ae2371dac1ddfc Mon Sep 17 00:00:00 2001 From: Ravikant Singh Date: Tue, 27 Sep 2011 18:09:44 +0530 Subject: u5500: usb: usb host fix fix for spurious usb interrupt, errorneous interrupt decoding for usb host case and usb host function handling ST-Ericsson ID: 352334 ST-Ericsson Linux next: Not Tested ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I01067da8158582863d825392b82996e1d9d06f8a Signed-off-by: Ravikant Singh Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31865 Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- arch/arm/mach-ux500/usb.c | 4 ++ drivers/usb/otg/ab5500-usb.c | 100 ++++++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 45 deletions(-) diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 11ad6f47757..363282eae61 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -90,7 +90,11 @@ static struct ux500_musb_board_data musb_board_data = { .dma_filter = stedma40_filter, }; +#ifdef CONFIG_USB_UX500_DMA static u64 ux500_musb_dmamask = DMA_BIT_MASK(32); +#else +static u64 ux500_musb_dmamask = DMA_BIT_MASK(0); +#endif static struct ux500_pins *usb_gpio_pins; static struct musb_hdrc_config musb_hdrc_config = { diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index 3f69e4c2c06..82168b407e7 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -24,9 +24,7 @@ /* AB5500 USB macros */ #define AB5500_USB_HOST_ENABLE 0x1 -#define AB5500_USB_HOST_DISABLE 0x0 #define AB5500_USB_DEVICE_ENABLE 0x2 -#define AB5500_USB_DEVICE_DISABLE 0x0 #define AB5500_MAIN_WATCHDOG_ENABLE 0x1 #define AB5500_MAIN_WATCHDOG_KICK 0x2 #define AB5500_MAIN_WATCHDOG_DISABLE 0x0 @@ -34,7 +32,6 @@ #define AB5500_WATCHDOG_DELAY 10 #define AB5500_WATCHDOG_DELAY_US 100 #define AB5500_PHY_DELAY_US 100 -#define AB5500_USB_DEVICE_DISABLE 0x0 #define AB5500_MAIN_WDOG_CTRL_REG 0x01 #define AB5500_USB_LINE_STAT_REG 0x80 #define AB5500_USB_PHY_CTRL_REG 0x8A @@ -43,6 +40,10 @@ #define AB5500_MAIN_WATCHDOG_DISABLE 0x0 #define AB5500_SYS_CTRL2_BLOCK 0x2 +/* UsbLineStatus register bit masks */ +#define AB5500_USB_LINK_STATUS_MASK_V1 0x78 +#define AB5500_USB_LINK_STATUS_MASK_V2 0xF8 + #define USB_PROBE_DELAY 1000 /* 1 seconds */ /* UsbLineStatus register - usb types */ @@ -80,7 +81,6 @@ enum ab5500_usb_mode { struct ab5500_usb { struct otg_transceiver otg; struct device *dev; - int irq_num_id_rise; int irq_num_id_fall; int irq_num_vbus_rise; int irq_num_vbus_fall; @@ -95,6 +95,8 @@ struct ab5500_usb { struct clk *sysclk; struct regulator *v_ape; struct abx500_usbgpio_platform_data *usb_gpio; + struct delayed_work work_usb_workaround; + bool phy_enabled; }; static int ab5500_usb_irq_setup(struct platform_device *pdev, @@ -142,6 +144,10 @@ static void ab5500_usb_wd_workaround(struct ab5500_usb *ab) static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) { u8 bit; + /* Workaround for spurious interrupt to be checked with Hardware Team*/ + if (ab->phy_enabled == true) + return; + ab->phy_enabled = true; bit = sel_host ? AB5500_USB_HOST_ENABLE : AB5500_USB_DEVICE_ENABLE; @@ -149,28 +155,36 @@ static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) clk_enable(ab->sysclk); regulator_enable(ab->v_ape); - abx500_set_register_interruptible(ab->dev, + if (!sel_host) { + schedule_delayed_work_on(0, + &ab->work_usb_workaround, + msecs_to_jiffies(USB_PROBE_DELAY)); + } + + abx500_mask_and_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, - bit); + bit, bit); } static void ab5500_usb_phy_disable(struct ab5500_usb *ab, bool sel_host) { u8 bit; + /* Workaround for spurious interrupt to be checked with Hardware Team*/ + if (ab->phy_enabled == false) + return; + ab->phy_enabled = false; bit = sel_host ? AB5500_USB_HOST_ENABLE : AB5500_USB_DEVICE_ENABLE; - abx500_set_register_interruptible(ab->dev, + abx500_mask_and_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, - bit); - + bit, 0); /* Needed to disable the phy.*/ ab5500_usb_wd_workaround(ab); - - regulator_disable(ab->v_ape); clk_disable(ab->sysclk); + regulator_disable(ab->v_ape); ab->usb_gpio->disable(); } @@ -186,12 +200,15 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) int ret = 0; int gpioval = 0; enum ab8500_usb_link_status lsts; - enum usb_xceiv_events event; + enum usb_xceiv_events event = USB_IDLE; (void)abx500_get_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &val); - lsts = (val >> 3) & 0x0F; + if (ab->rev == AB5500_2_0) + lsts = (val & AB5500_USB_LINK_STATUS_MASK_V2) >> 3; + else + lsts = (val & AB5500_USB_LINK_STATUS_MASK_V1) >> 3; switch (lsts) { @@ -201,12 +218,6 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) case USB_LINK_HOST_CHG_NM: case USB_LINK_HOST_CHG_HS: case USB_LINK_HOST_CHG_HS_CHIRP: - if (ab->otg.gadget) { - ab5500_usb_peri_phy_en(ab); - ab->mode = USB_DEVICE; - } - gpio_set_value(ab->usb_cs_gpio, 1); - event = USB_EVENT_VBUS; break; case USB_LINK_HM_IDGND: @@ -224,6 +235,9 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) ab5500_usb_host_phy_en(ab); + ab->otg.default_a = true; + event = USB_EVENT_ID; + break; case USB_LINK_HM_IDGND_V2: @@ -241,6 +255,9 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) ab5500_usb_host_phy_en(ab); + ab->otg.default_a = true; + event = USB_EVENT_ID; + break; default: break; @@ -275,10 +292,15 @@ static irqreturn_t ab5500_usb_device_insert_irq(int irq, void *data) { int ret = 0, val = 1; struct ab5500_usb *ab = (struct ab5500_usb *) data; + + enum usb_xceiv_events event; + ab->mode = USB_DEVICE; ab5500_usb_peri_phy_en(ab); + /* enable usb chip Select */ + event = USB_EVENT_VBUS; ret = gpio_direction_output(ab->usb_cs_gpio, val); if (ret < 0) { dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); @@ -287,6 +309,8 @@ static irqreturn_t ab5500_usb_device_insert_irq(int irq, void *data) } gpio_set_value(ab->usb_cs_gpio, 1); + atomic_notifier_call_chain(&ab->otg.notifier, event, &ab->vbus_draw); + return IRQ_HANDLED; } @@ -319,9 +343,6 @@ static irqreturn_t ab5500_usb_host_disconnect_irq(int irq, void *data) static void ab5500_usb_irq_free(struct ab5500_usb *ab) { - if (ab->irq_num_id_rise) - free_irq(ab->irq_num_id_rise, ab); - if (ab->irq_num_id_fall) free_irq(ab->irq_num_id_fall, ab); @@ -384,7 +405,6 @@ static int ab5500_usb_irq_setup(struct platform_device *pdev, } ab->irq_num_link_status = irq; - ret = request_threaded_irq(ab->irq_num_link_status, NULL, ab5500_usb_link_status_irq, IRQF_NO_SUSPEND | IRQF_SHARED, @@ -457,36 +477,39 @@ static int ab5500_usb_boot_detect(struct ab5500_usb *ab) if (!ab->dev) return -EINVAL; - abx500_set_register_interruptible(ab->dev, + abx500_mask_and_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, + AB5500_USB_DEVICE_ENABLE, AB5500_USB_DEVICE_ENABLE); udelay(AB5500_PHY_DELAY_US); - abx500_set_register_interruptible(ab->dev, + abx500_mask_and_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, - AB5500_USB_DEVICE_DISABLE); + AB5500_USB_DEVICE_ENABLE, 0); - abx500_set_register_interruptible(ab->dev, + abx500_mask_and_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, + AB5500_USB_HOST_ENABLE, AB5500_USB_HOST_ENABLE); udelay(AB5500_PHY_DELAY_US); - abx500_set_register_interruptible(ab->dev, + abx500_mask_and_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, - AB5500_USB_HOST_DISABLE); - - ab5500_usb_wd_workaround(ab); + AB5500_USB_HOST_ENABLE, 0); (void)abx500_get_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &usb_status); - lsts = (usb_status >> 3) & 0x0F; + if (ab->rev == AB5500_2_0) + lsts = (usb_status & AB5500_USB_LINK_STATUS_MASK_V2) >> 3; + else + lsts = (usb_status & AB5500_USB_LINK_STATUS_MASK_V1) >> 3; switch (lsts) { @@ -572,11 +595,6 @@ static int ab5500_usb_set_host(struct otg_transceiver *otg, schedule_work(&ab->phy_dis_work); } else { ab->otg.host = host; - /* Phy will not be enabled if cable is already - * plugged-in. Schedule to enable phy. - * Use same delay to avoid any race condition. - */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); } return 0; @@ -602,11 +620,6 @@ static int ab5500_usb_set_peripheral(struct otg_transceiver *otg, schedule_work(&ab->phy_dis_work); } else { ab->otg.gadget = gadget; - /* Phy will not be enabled if cable is already - * plugged-in. Schedule to enable phy. - * Use same delay to avoid any race condition. - */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); } return 0; @@ -618,15 +631,12 @@ static int __devinit ab5500_usb_probe(struct platform_device *pdev) struct abx500_usbgpio_platform_data *usb_pdata = pdev->dev.platform_data; int err; - int rev; int ret = -1; - int irq; ab = kzalloc(sizeof *ab, GFP_KERNEL); if (!ab) return -ENOMEM; ab->dev = &pdev->dev; - ab->rev = rev; ab->otg.dev = ab->dev; ab->otg.label = "ab5500"; ab->otg.state = OTG_STATE_B_IDLE; -- cgit v1.2.3 From e8369841e9f9fbcce3b659c1d8e9bf1d9549b14c Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Mon, 17 Oct 2011 13:02:11 +0200 Subject: ARM: ux500: usb: Replace mach prcmu driver with mainlined version The prcmu driver now exists in drivers/mfd Signed-off-by: Jonas Aaberg Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32057 --- drivers/usb/otg/ab8500-usb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index dff49336fe5..52c6bc5b03c 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -225,14 +225,12 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) AB8500_BIT_PHY_CTRL_DEVICE_EN; ab->usb_gpio->enable(); - clk_enable(ab->sysclk); ab8500_usb_regulator_ctrl(ab, sel_host, true); prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 100); - if (!sel_host) { schedule_delayed_work_on(0, &ab->work_usb_workaround, @@ -912,7 +910,6 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 50); - dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", ab->rev); prcmu_qos_add_requirement(PRCMU_QOS_ARM_OPP, "usb", 25); -- cgit v1.2.3 From 6b8bfb92938a827854c1edf8a045da193127a4fb Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Mon, 17 Oct 2011 14:41:45 +0200 Subject: usb: prcmu: fix path to header file Signed-off-by: Rabin Vincent Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32448 Reviewed-by: Jonas ABERG Tested-by: Jonas ABERG --- drivers/usb/otg/ab5500-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index 82168b407e7..2f3c48a8336 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From eac28b302f7e634f650b93f618aae30acb27812e Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Wed, 26 Oct 2011 13:41:39 +0200 Subject: usb: otg: ab8500: Fix for ioremap definition Signed-off-by: Philippe Langlais --- drivers/usb/otg/ab8500-usb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 52c6bc5b03c..01009237f9d 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -35,9 +35,12 @@ #include #include #include -#include #include +#include + +#include + #define AB8500_MAIN_WD_CTRL_REG 0x01 #define AB8500_USB_LINE_STAT_REG 0x80 #define AB8500_USB_PHY_CTRL_REG 0x8A -- cgit v1.2.3 From cfeb07658daee5e5ee23a90b4921d74598d4394b Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Sat, 1 Oct 2011 18:40:39 +0530 Subject: ux500:USB: Fix for CPU Idle from USB USB context is stored and restored at each time when the usb cable is pluged in. ST-Ericsson Linux next: NA ST-Ericsson ID: 363987 ST-Ericsson FOSS-OUT ID: NA Change-Id: I5fa7b32dd4f67dcc81f2418e872ed5107f8624c0 Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32785 Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- arch/arm/mach-ux500/include/mach/usb.h | 1 + drivers/usb/musb/ux500.c | 148 ++++++++++++++++++++++++++++++++- drivers/usb/otg/ab8500-usb.c | 4 + 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h index e3f4858c2e8..67fbd00e690 100644 --- a/arch/arm/mach-ux500/include/mach/usb.h +++ b/arch/arm/mach-ux500/include/mach/usb.h @@ -31,4 +31,5 @@ struct abx500_usbgpio_platform_data { int usb_cs; }; +void ux500_restore_context(void); #endif diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 95f7fa4a831..1c260ec113b 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -25,9 +25,11 @@ #include #include #include +#include #include "musb_core.h" +#define DEFAULT_DEVCTL 0x81 static void ux500_musb_set_vbus(struct musb *musb, int is_on); struct ux500_glue { @@ -38,6 +40,145 @@ struct ux500_glue { #define glue_to_musb(g) platform_get_drvdata(g->musb) static struct timer_list notify_timer; +struct musb_context_registers context; +struct musb *_musb; +void ux500_store_context(struct musb *musb) +{ +#ifdef CONFIG_PM + int i; + void __iomem *musb_base = musb->mregs; + void __iomem *epio; + _musb = musb; + + if (is_host_enabled(musb)) { + context.frame = musb_readw(musb_base, MUSB_FRAME); + context.testmode = musb_readb(musb_base, MUSB_TESTMODE); + } + context.power = musb_readb(musb_base, MUSB_POWER); + context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); + context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); + context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); + context.index = musb_readb(musb_base, MUSB_INDEX); + context.devctl = DEFAULT_DEVCTL; + for (i = 0; i < musb->config->num_eps; ++i) { + epio = musb->endpoints[i].regs; + context.index_regs[i].txmaxp = + musb_readw(epio, MUSB_TXMAXP); + context.index_regs[i].txcsr = + musb_readw(epio, MUSB_TXCSR); + context.index_regs[i].rxmaxp = + musb_readw(epio, MUSB_RXMAXP); + context.index_regs[i].rxcsr = + musb_readw(epio, MUSB_RXCSR); + + if (musb->dyn_fifo) { + context.index_regs[i].txfifoadd = + musb_read_txfifoadd(musb_base); + context.index_regs[i].rxfifoadd = + musb_read_rxfifoadd(musb_base); + context.index_regs[i].txfifosz = + musb_read_txfifosz(musb_base); + context.index_regs[i].rxfifosz = + musb_read_rxfifosz(musb_base); + } + if (is_host_enabled(musb)) { + context.index_regs[i].txtype = + musb_readb(epio, MUSB_TXTYPE); + context.index_regs[i].txinterval = + musb_readb(epio, MUSB_TXINTERVAL); + context.index_regs[i].rxtype = + musb_readb(epio, MUSB_RXTYPE); + context.index_regs[i].rxinterval = + musb_readb(epio, MUSB_RXINTERVAL); + + context.index_regs[i].txfunaddr = + musb_read_txfunaddr(musb_base, i); + context.index_regs[i].txhubaddr = + musb_read_txhubaddr(musb_base, i); + context.index_regs[i].txhubport = + musb_read_txhubport(musb_base, i); + + context.index_regs[i].rxfunaddr = + musb_read_rxfunaddr(musb_base, i); + context.index_regs[i].rxhubaddr = + musb_read_rxhubaddr(musb_base, i); + context.index_regs[i].rxhubport = + musb_read_rxhubport(musb_base, i); + } + } +#endif +} +void ux500_restore_context(void) +{ +#ifdef CONFIG_PM + int i; + struct musb *musb = _musb; + void __iomem *musb_base = musb->mregs; + void __iomem *ep_target_regs; + void __iomem *epio; + + if (is_host_enabled(musb)) { + musb_writew(musb_base, MUSB_FRAME, context.frame); + musb_writeb(musb_base, MUSB_TESTMODE, context.testmode); + } + musb_writeb(musb_base, MUSB_POWER, context.power); + musb_writew(musb_base, MUSB_INTRTXE, context.intrtxe); + musb_writew(musb_base, MUSB_INTRRXE, context.intrrxe); + musb_writeb(musb_base, MUSB_INTRUSBE, context.intrusbe); + musb_writeb(musb_base, MUSB_DEVCTL, context.devctl); + + for (i = 0; i < musb->config->num_eps; ++i) { + epio = musb->endpoints[i].regs; + musb_writew(epio, MUSB_TXMAXP, + context.index_regs[i].txmaxp); + musb_writew(epio, MUSB_TXCSR, + context.index_regs[i].txcsr); + musb_writew(epio, MUSB_RXMAXP, + context.index_regs[i].rxmaxp); + musb_writew(epio, MUSB_RXCSR, + context.index_regs[i].rxcsr); + + if (musb->dyn_fifo) { + musb_write_txfifosz(musb_base, + context.index_regs[i].txfifosz); + musb_write_rxfifosz(musb_base, + context.index_regs[i].rxfifosz); + musb_write_txfifoadd(musb_base, + context.index_regs[i].txfifoadd); + musb_write_rxfifoadd(musb_base, + context.index_regs[i].rxfifoadd); + } + + if (is_host_enabled(musb)) { + musb_writeb(epio, MUSB_TXTYPE, + context.index_regs[i].txtype); + musb_writeb(epio, MUSB_TXINTERVAL, + context.index_regs[i].txinterval); + musb_writeb(epio, MUSB_RXTYPE, + context.index_regs[i].rxtype); + musb_writeb(epio, MUSB_RXINTERVAL, + + musb->context.index_regs[i].rxinterval); + musb_write_txfunaddr(musb_base, i, + context.index_regs[i].txfunaddr); + musb_write_txhubaddr(musb_base, i, + context.index_regs[i].txhubaddr); + musb_write_txhubport(musb_base, i, + context.index_regs[i].txhubport); + + ep_target_regs = + musb_read_target_reg_base(i, musb_base); + + musb_write_rxfunaddr(ep_target_regs, + context.index_regs[i].rxfunaddr); + musb_write_rxhubaddr(ep_target_regs, + context.index_regs[i].rxhubaddr); + musb_write_rxhubport(ep_target_regs, + context.index_regs[i].rxhubport); + } + } +#endif +} static void musb_notify_idle(unsigned long _musb) { @@ -185,7 +326,10 @@ static void ux500_musb_try_idle(struct musb *musb, unsigned long timeout) (unsigned long)jiffies_to_msecs(timeout - jiffies)); mod_timer(¬ify_timer, timeout); } - +static void ux500_musb_enable(struct musb *musb) +{ + ux500_store_context(musb); +} static int ux500_musb_init(struct musb *musb) { int status; @@ -229,6 +373,8 @@ static const struct musb_platform_ops ux500_ops = { .set_vbus = ux500_musb_set_vbus, .try_idle = ux500_musb_try_idle, + + .enable = ux500_musb_enable, }; /** diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 01009237f9d..ed82c9859b9 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -340,10 +340,12 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) if (ab->mode == USB_HOST) { ab->mode = USB_PERIPHERAL; ab8500_usb_host_phy_dis(ab); + ux500_restore_context(); ab8500_usb_peri_phy_en(ab); } if (ab->mode == USB_IDLE) { ab->mode = USB_PERIPHERAL; + ux500_restore_context(); ab8500_usb_peri_phy_en(ab); } event = USB_EVENT_VBUS; @@ -354,10 +356,12 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) if (ab->mode == USB_PERIPHERAL) { ab->mode = USB_HOST; ab8500_usb_peri_phy_dis(ab); + ux500_restore_context(); ab8500_usb_host_phy_en(ab); } if (ab->mode == USB_IDLE) { ab->mode = USB_HOST; + ux500_restore_context(); ab8500_usb_host_phy_en(ab); } ab->otg.default_a = true; -- cgit v1.2.3 From fba12e1b72e7ece272e5353369b64b24633c862e Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Mon, 3 Oct 2011 16:23:44 +0530 Subject: ux500:USB: Handling the null pointer situation Connect and boot can cause a NULL pointer access if link status interrupt comes before we enable the MUSB platform initialization happens. ST-Ericsson Linux next: NA ST-Ericsson ID: 365151 ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Sakethram Bommisetti Change-Id: I91aaa269913a7fdf5b4f59927dd563cf8c456e4f Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32825 Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/ux500.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 1c260ec113b..ef89af12bbf 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -46,9 +46,15 @@ void ux500_store_context(struct musb *musb) { #ifdef CONFIG_PM int i; - void __iomem *musb_base = musb->mregs; + void __iomem *musb_base; void __iomem *epio; - _musb = musb; + + if (musb != NULL) + _musb = musb; + else + return; + + musb_base = musb->mregs; if (is_host_enabled(musb)) { context.frame = musb_readw(musb_base, MUSB_FRAME); @@ -112,11 +118,17 @@ void ux500_restore_context(void) { #ifdef CONFIG_PM int i; - struct musb *musb = _musb; - void __iomem *musb_base = musb->mregs; + struct musb *musb; + void __iomem *musb_base; void __iomem *ep_target_regs; void __iomem *epio; + if (_musb != NULL) + musb = _musb; + else + return; + + musb_base = musb->mregs; if (is_host_enabled(musb)) { musb_writew(musb_base, MUSB_FRAME, context.frame); musb_writeb(musb_base, MUSB_TESTMODE, context.testmode); -- cgit v1.2.3 From 3e85da3d4deb35c03e7fae5e0db505bce8e5860a Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 11 Oct 2011 14:48:04 +0530 Subject: USB:Interface Association Descriptors added to ECM Add IAD to bind the two interfaces of ECM, so that it works properly in composite gadget mode. ST-Ericsson ID: AP 366654 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Thirupathi Signed-off-by: Praveena Nadahally Acked-by: Linus Walleij Change-Id: I87c88c3b94aee72b93b3ceab508e8a67b76ce3bf Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33617 Reviewed-by: QABUILD Reviewed-by: Srinidhi KASAGAR --- drivers/usb/gadget/f_ecm.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 3691a0cb946..43aa7ad948c 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -106,6 +106,19 @@ static inline unsigned ecm_bitrate(struct usb_gadget *g) /* interface descriptor: */ +static struct usb_interface_assoc_descriptor +ecm_iad_descriptor = { + .bLength = sizeof ecm_iad_descriptor, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + + /* .bFirstInterface = DYNAMIC, */ + .bInterfaceCount = 2, /* control + data */ + .bFunctionClass = USB_CLASS_COMM, + .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bFunctionProtocol = USB_CDC_PROTO_NONE, + /* .iFunction = DYNAMIC */ +}; + static struct usb_interface_descriptor ecm_control_intf = { .bLength = sizeof ecm_control_intf, .bDescriptorType = USB_DT_INTERFACE, @@ -208,6 +221,7 @@ static struct usb_endpoint_descriptor fs_ecm_out_desc = { static struct usb_descriptor_header *ecm_fs_function[] = { /* CDC ECM control descriptors */ + (struct usb_descriptor_header *) &ecm_iad_descriptor, (struct usb_descriptor_header *) &ecm_control_intf, (struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_union_desc, @@ -256,6 +270,7 @@ static struct usb_endpoint_descriptor hs_ecm_out_desc = { static struct usb_descriptor_header *ecm_hs_function[] = { /* CDC ECM control descriptors */ + (struct usb_descriptor_header *) &ecm_iad_descriptor, (struct usb_descriptor_header *) &ecm_control_intf, (struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_union_desc, @@ -348,6 +363,7 @@ static struct usb_string ecm_string_defs[] = { [0].s = "CDC Ethernet Control Model (ECM)", [1].s = NULL /* DYNAMIC */, [2].s = "CDC Ethernet Data", + [3].s = "CDC ECM", { } /* end of list */ }; @@ -683,6 +699,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) if (status < 0) goto fail; ecm->ctrl_id = status; + ecm_iad_descriptor.bFirstInterface = status; ecm_control_intf.bInterfaceNumber = status; ecm_union_desc.bMasterInterface0 = status; @@ -873,6 +890,13 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) return status; ecm_string_defs[1].id = status; ecm_desc.iMACAddress = status; + + /* IAD label */ + status = usb_string_id(c->cdev); + if (status < 0) + return status; + ecm_string_defs[3].id = status; + ecm_iad_descriptor.iFunction = status; } /* allocate and initialize one new instance */ -- cgit v1.2.3 From da844c8b83732924144a2c5443c2a31f90b8c158 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 10 Nov 2011 09:11:03 +0100 Subject: mach-ux500: musb: Now musb is always in OTG mode This changed is needed since "usb: musb: drop a gigantic amount of ifdeferry" introduced by Felipe Balbi . Signed-off-by: Philippe Langlais --- arch/arm/mach-ux500/usb.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 363282eae61..1e7c0cc912e 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -105,13 +105,7 @@ static struct musb_hdrc_config musb_hdrc_config = { }; static struct musb_hdrc_platform_data musb_platform_data = { -#if defined(CONFIG_USB_MUSB_OTG) .mode = MUSB_OTG, -#elif defined(CONFIG_USB_MUSB_PERIPHERAL) - .mode = MUSB_PERIPHERAL, -#else /* defined(CONFIG_USB_MUSB_HOST) */ - .mode = MUSB_HOST, -#endif .config = &musb_hdrc_config, .board_data = &musb_board_data, }; -- cgit v1.2.3 From c79ed0dce7202d909d870b2c2d3ef0b8ff0125a7 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 25 Jan 2011 16:10:30 +0530 Subject: USB: gadget: OTG supplement revision 2.0 updates Introduce otg_version field in usb_gadget struct.UDC can advertise OTG spec version compatibility by setting otg_version field appropriately. Gadget drivers fill the bcdOTG field in OTG descriptor based on UDC's OTG version. Add sysfs file for host_request and UDC returns the same when HNP polling request arrives from the host. Signed-off-by: Pavankumar Kondeti Change-Id: Ic5ea40369159c10e524a13a2d9b1722fb3ee6921 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/13421 Reviewed-by: Praveena NADAHALLY Tested-by: Praveena NADAHALLY USB: gadget: Fix merge 3.x "OTG supplement revision 2.0 updates" Signed-off-by: Philippe Langlais --- .../ABI/testing/sysfs-devices-platform-_UDC_-gadget | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget b/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget index d548eaac230..3bf505e7227 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget +++ b/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget @@ -19,3 +19,16 @@ Description: Possible values are: 1 -> ignore the FUA flag 0 -> obey the FUA flag + +What: /sys/devices/platform/_UDC_/gadget/host_request +Date: December 2010 +Contact: Pavan Kondeti +Description: + OTG 2.0 compliant host keeps polling OTG2.0 peripheral + for host role. Set host_request flag, which tells host + to give up the host role to peripheral. + + 1 -> host role is requested + 0 -> no effect (automatically cleared upon reset/disconnect) + + (_UDC_ is the name of the USB Device Controller driver) -- cgit v1.2.3 From eb5cb770c2a7ba055a7c5d66f731b0e43289e4cc Mon Sep 17 00:00:00 2001 From: rajaram Date: Tue, 22 Nov 2011 12:11:02 +0100 Subject: usb : musb : Do not register musb core PM ops Currently musb core PM ops does save and restore of context The platform can enter CPU idle before the platform or runtime suspend is called.But musb core PM ops is not aware of CPU idle. and thus it saves and restores some junk context Since junk context is restored there is instability in usb functions. ux500 USB platform file handles the save and restore properly during cable connect and disconnent.So we don't require handling of context save and restore in musb core and hence not registering musb core PM ops. ST-Ericsson Linux next: NA ST-Ericsson ID: 370868,372121 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ie784c131792b686564561dc9b4bb262042e48504 Signed-off-by: rajaram --- drivers/usb/musb/musb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 86c255d6efa..9e48a919367 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2357,7 +2357,7 @@ static const struct dev_pm_ops musb_dev_pm_ops = { .runtime_resume = musb_runtime_resume, }; -#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) +#define MUSB_DEV_PM_OPS NULL #else #define MUSB_DEV_PM_OPS NULL #endif -- cgit v1.2.3