From 364df12e7007e48bfabebd9ecacc5c682964d738 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 | 9 +++++++++ drivers/usb/musb/musb_core.h | 1 + drivers/usb/musb/musb_host.c | 25 +++++++++++-------------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index f70cab3beee..1169c42b56e 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -114,4 +114,13 @@ config MUSB_PIO_ONLY endchoice +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. + endif # USB_MUSB_HDRC diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index f4a40f001c8..f072adba36a 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -275,6 +275,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 ef8d744800a..a0db9917f18 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); @@ -796,11 +794,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); @@ -1104,7 +1102,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); @@ -1537,7 +1535,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... @@ -1569,7 +1567,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; @@ -1625,7 +1623,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; @@ -1733,10 +1731,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 6529b6af625de5777a33cd60e6554cdd188ab095 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 a84af677dc5..4680e536ae3 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -535,6 +535,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 dd93605cc482e70486618048e4207ca69da5463f 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 | 396 +++++++++++++++++++++++++++++-------------- 1 file changed, 272 insertions(+), 124 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 4680e536ae3..5752b99ee76 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 usb_phy phy; 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 *phy_to_ab(struct usb_phy *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,11 +237,12 @@ 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->phy.state = OTG_STATE_B_IDLE; - ab->phy.otg->default_a = false; + 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->phy.otg.default_a = false; ab->vbus_draw = 0; event = USB_EVENT_NONE; break; @@ -184,6 +256,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) if (ab->phy.otg->gadget) { /* TODO: Enable regulators. */ ab8500_usb_peri_phy_en(ab); + ab->mode = USB_PERIPHERAL; v = ab->phy.otg->gadget; } event = USB_EVENT_VBUS; @@ -191,11 +264,10 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) case USB_LINK_HM_IDGND: if (ab->phy.otg->host) { - /* TODO: Enable regulators. */ ab8500_usb_host_phy_en(ab); + ab->mode = USB_HOST; v = ab->phy.otg->host; } - ab->phy.state = OTG_STATE_A_IDLE; ab->phy.otg->default_a = true; event = USB_EVENT_ID; break; @@ -225,7 +297,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 +307,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 +389,10 @@ static int ab8500_usb_set_peripheral(struct usb_otg *otg, */ if (!gadget) { - /* TODO: Disable regulators. */ otg->gadget = NULL; schedule_work(&ab->phy_dis_work); } else { otg->gadget = gadget; - otg->phy->state = OTG_STATE_B_IDLE; /* Phy will not be enabled if cable is already * plugged-in. Schedule to enable phy. @@ -344,7 +419,6 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) */ if (!host) { - /* TODO: Disable regulators. */ otg->host = NULL; schedule_work(&ab->phy_dis_work); } else { @@ -359,113 +433,166 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) 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) @@ -501,7 +628,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) ab->phy.label = "ab8500"; ab->phy.set_suspend = ab8500_usb_set_suspend; ab->phy.set_power = ab8500_usb_set_power; - ab->phy.state = OTG_STATE_UNDEFINED; + ab->phy.state = OTG_STATE_B_IDLE; otg->phy = &ab->phy; otg->set_host = ab8500_usb_set_host; @@ -519,29 +646,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 = usb_set_transceiver(&ab->phy); 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(otg); kfree(ab); @@ -560,8 +702,14 @@ static int __devexit ab8500_usb_remove(struct platform_device *pdev) usb_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 81bcbe738d08c523aa6794eae78323cd130d8bd3 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 | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 5752b99ee76..752151b416f 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_phy_events event; abx500_get_register_interruptible(ab->dev, @@ -257,7 +256,6 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) /* TODO: Enable regulators. */ ab8500_usb_peri_phy_en(ab); ab->mode = USB_PERIPHERAL; - v = ab->phy.otg->gadget; } event = USB_EVENT_VBUS; break; @@ -266,7 +264,6 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) if (ab->phy.otg->host) { ab8500_usb_host_phy_en(ab); ab->mode = USB_HOST; - v = ab->phy.otg->host; } ab->phy.otg->default_a = true; event = USB_EVENT_ID; @@ -284,7 +281,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) break; } - atomic_notifier_call_chain(&ab->phy.notifier, event, v); + atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); return 0; } @@ -357,9 +354,8 @@ static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) ab->vbus_draw = mA; - if (mA) - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_ENUMERATED, ab->phy.otg->gadget); + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_VBUS, &ab->vbus_draw); return 0; } -- cgit v1.2.3 From 8b9ca446cf0bf461ce30a2f5f698a7ec5543c901 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 ec6c97dadbe..98d9df0920f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1612,12 +1612,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 a0db9917f18..19b3fa625df 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) @@ -1132,7 +1149,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 4ebfd76352c691a2b04bf657b031451898cdde4e 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 752151b416f..7333d2f4431 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 e1bc7e2bdc21203502148805ce31f4bc379d6076 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 19b3fa625df..e825d3ff956 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 0512675b3f3eb1925f0d28b53b313b3c876aa578 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 7333d2f4431..afa93a4bd59 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, @@ -277,6 +282,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; } @@ -313,6 +319,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 a1caf5d2763762637f79559bd83b9f9511bec990 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 afa93a4bd59..cf537da1aa2 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -357,6 +357,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 usb_phy *phy, unsigned mA) { struct ab8500_usb *ab; @@ -366,6 +381,8 @@ static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) ab = phy_to_ab(phy); + mA = ab8500_eyediagram_workaroud(ab, mA); + ab->vbus_draw = mA; atomic_notifier_call_chain(&ab->phy.notifier, -- cgit v1.2.3 From 511089a5c2c77205bb253988128a131149cfa3df 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/abx500/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 4c1cc50a595..40e4b621864 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(struct device *parent, 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 a74af389bc6..3851a34f0ca 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -11,6 +11,9 @@ #include #include #include +#include +#include "pins.h" +#include "board-mop500-usb.h" #define MUSB_DMA40_RX_CH { \ .mode = STEDMA40_MODE_LOGICAL, \ @@ -87,6 +90,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, @@ -125,6 +129,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 cf537da1aa2..ad244d8c883 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 *phy_to_ab(struct usb_phy *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); } @@ -355,6 +361,7 @@ static void ab8500_usb_phy_disable_work(struct work_struct *work) if (!ab->phy.otg->gadget) ab8500_usb_peri_phy_dis(ab); + } static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) @@ -626,6 +633,8 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) { struct ab8500_usb *ab; struct usb_otg *otg; + struct ab8500_platform_data *ab8500_pdata = + dev_get_platdata(pdev->dev.parent); int err; int rev; @@ -660,6 +669,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) otg->phy = &ab->phy; otg->set_host = ab8500_usb_set_host; otg->set_peripheral = ab8500_usb_set_peripheral; + ab->usb_gpio = ab8500_pdata->usb; platform_set_drvdata(pdev, ab); @@ -699,6 +709,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); @@ -738,6 +752,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->phy.otg); diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index fccc3002f27..8cc2185b0a3 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -274,6 +274,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 80ddfc25baf8fcca2a5e311c3346bd9f560cf210 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 66aaccf0449..ce76ef3e182 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1123,8 +1123,8 @@ static struct musb_fifo_cfg __devinitdata mode_4_cfg[] = { /* mode 5 - fits in 8KB */ static struct musb_fifo_cfg __devinitdata 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 4fdffdbfe43ab3967b23345f745ea760f34f2a4d 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 ce76ef3e182..8045b6efa26 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2330,7 +2330,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) { /* for static cmos like DaVinci, register values were preserved * unless for some reason the whole soc powered down or the USB @@ -2371,7 +2371,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 539d649843f5b641ac2758a57392766a58eb3fdb 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 ad244d8c883..a09fb341cb8 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); @@ -306,16 +290,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; @@ -335,10 +309,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; } @@ -536,41 +506,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; @@ -642,8 +578,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; } @@ -693,9 +629,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 41a30f3b657a814f17f39be00b902ca6c21a92eb 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 52343654f5d..b8bfda4fc58 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -174,8 +174,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 1893c740396304487e9ead79360941a5c0920b13 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 | 67 +++++++++++++++- 3 files changed, 244 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 aa09dd417b9..421a6a480af 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 = usb_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) { usb_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 __devinit ux500_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; @@ -155,6 +174,13 @@ static int __devexit 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 d05c7fbbb70..389bf8890a5 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -64,14 +64,14 @@ void ux500_dma_callback(void *private_data) struct musb *musb = hw_ep->musb; unsigned long flags; - dev_dbg(musb->controller, "DMA rx transfer done on hw_ep=%d\n", + dev_dbg(musb->controller, "DMA tx transfer done on hw_ep=%d\n", hw_ep->epnum); spin_lock_irqsave(&musb->lock, flags); ux500_channel->channel.actual_len = ux500_channel->cur_len; ux500_channel->channel.status = MUSB_DMA_STATUS_FREE; musb_dma_completion(musb, hw_ep->epnum, - ux500_channel->is_tx); + ux500_channel->is_tx); spin_unlock_irqrestore(&musb->lock, flags); } @@ -134,6 +134,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) { @@ -172,7 +181,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; @@ -199,6 +214,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) @@ -220,6 +245,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; @@ -254,6 +285,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, @@ -285,6 +322,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, @@ -356,6 +402,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, @@ -364,6 +416,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 42744781ad1c28ead0b7663a7eec877f016ef522 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 8045b6efa26..e54b512b7b5 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1886,7 +1886,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 421a6a480af..201c6de0082 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 = usb_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 52b23ad5ede0668a07be02db0940bf16e82a635c 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 e825d3ff956..5765470aa80 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -817,6 +817,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); } @@ -909,6 +911,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; @@ -948,6 +952,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 c5b0321065e36cde8cdc18e125901b2914369c05 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 98d9df0920f..87c938adbc7 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 @@ -1326,11 +1332,20 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Hubs have proper suspend/resume support. */ 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) { @@ -3427,6 +3442,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 7728c91dfa2..a5fdc3ac0d7 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -46,11 +46,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 71648dcbe43..5994cef4d2d 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 73b68d1f2cb..33488200c17 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -372,7 +372,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 29390773a3081c76e16f9958a6ddb38b58febb09 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 a09fb341cb8..2b67433fa6c 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, @@ -573,6 +585,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) { @@ -639,6 +652,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 bfa8fffa3cd7da098ee89a6498897d03459d0c5b 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 2b67433fa6c..b6ec661c9aa 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) @@ -448,6 +452,84 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) 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) { @@ -710,6 +792,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 8c6a1ab20ca39b4d7f337c207e04f08cb2fed423 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 b6ec661c9aa..28752bd4b90 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 7e9ee1fd194478d4f4a38ad8ab9c7d3646688174 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 28752bd4b90..ff956a0ad14 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 *phy_to_ab(struct usb_phy *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) @@ -300,8 +343,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); } @@ -714,6 +757,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; @@ -792,6 +837,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 335b68a7e5fcf66b6ae24ece39ea188bdd384563 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 ff956a0ad14..bc0123101c2 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 *phy_to_ab(struct usb_phy *x) @@ -702,6 +706,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; @@ -828,6 +876,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 6d2bff7c6a6275b4209bf41208e611734b2cf340 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 e54b512b7b5..9b9f3de02c0 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1886,7 +1886,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 5765470aa80..d278ba4d391 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) { @@ -2278,6 +2279,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 212f06b70a02881a4f5f87f9905784806c80da06 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-mop500.c | 2 ++ 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/abx500/ab8500.h | 2 +- 7 files changed, 20 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-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 77d03c1fbd0..5c1da28427b 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -53,6 +53,7 @@ #include "devices-db8500.h" #include "board-mop500.h" #include "board-mop500-regulators.h" +#include "board-ux500-usb.h" static struct gpio_led snowball_led_array[] = { { @@ -194,6 +195,7 @@ static struct ab8500_platform_data ab8500_platdata = { .regulator = ab8500_regulators, .num_regulator = ARRAY_SIZE(ab8500_regulators), .gpio = &ab8500_gpio_pdata, + .usb = &abx500_usbgpio_plat_data, }; static struct resource ab8500_resources[] = { 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 40e4b621864..145823a4d37 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(struct device *parent, 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 3851a34f0ca..170b8934200 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -13,7 +13,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, \ @@ -153,7 +153,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 bc0123101c2..13fbabacbc8 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/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index 8cc2185b0a3..94a3329ccf9 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -274,7 +274,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 c4947d9f3516df71e776ff25531472e737eba3c0 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 | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 13fbabacbc8..a47bce1d776 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,29 +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->phy.otg->gadget) { - /* TODO: Enable regulators. */ + 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->phy.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->phy.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 112b4b841e6c902870daccbde4080b2ed3a12888 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 a47bce1d776..657c0834240 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 9c31e476c753f7c628a39fcb0e28c3c6a602cf43 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/board-u5500.c | 4 + 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 +++++++++++++++++++++++++++++++++ 7 files changed, 753 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/otg/ab5500-usb.c diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 0ff4be72a80..f040ab0ba7c 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c @@ -23,10 +23,12 @@ #include #include #include +#include #include "pins-db5500.h" #include "devices-db5500.h" #include +#include "board-ux500-usb.h" /* * GPIO @@ -111,6 +113,8 @@ static struct ab5500_platform_data ab5500_plf_data = { .init_settings = NULL, .init_settings_sz = 0, .pm_power_off = false, + .dev_data[AB5500_DEVID_USB] = &abx500_usbgpio_plat_data, + .dev_data_sz[AB5500_DEVID_USB] = sizeof(abx500_usbgpio_plat_data), }; static struct platform_device ab5500_device = { diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h index 145823a4d37..a9aa06190eb 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 170b8934200..37f9427307f 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -35,6 +35,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, @@ -158,6 +160,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 1169c42b56e..ac26a4f8545 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) + depends on (ARCH_U8500) || (ARCH_U5500) endchoice diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 5c87db06b59..168f5b0364f 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -108,6 +108,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 && USB_SUSPEND diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 41aa5098b13..e227d9add96 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -18,6 +18,7 @@ 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 obj-$(CONFIG_USB_MV_OTG) += mv_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 7479e15cd7d347367fd4bf01a9aff1128af8b580 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 e04da78768ed245061cbc75ffdc77500e0f4efe9 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 f072adba36a..f4a40f001c8 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -275,7 +275,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 d278ba4d391..9a3d2bc0439 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) { @@ -812,11 +812,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); @@ -1126,7 +1126,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); @@ -1757,9 +1757,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 */ @@ -2279,7 +2279,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 4d83f7fe5865287fd6b30851262bec9e9b6f05ae 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 9a3d2bc0439..fa9239f9ed7 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1451,7 +1451,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; @@ -1733,6 +1733,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) @@ -1761,6 +1766,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 6f45681b852d2016fe09d7781fc411058756cb52 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 201c6de0082..6bd8ab3d798 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 = usb_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 8da6bfbfa5b5db42ee2da03f30d3ee2b0635552e 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 3e86d8c0ac2eb5f1ed1d4f429cff643c995ef86b 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 89a75c608ce7569e26de956e6bfef2c78f39b877 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 fa9239f9ed7..70bf46c4487 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1765,8 +1765,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 6163e81fd431c7dcbeb1b8e2be25f5e0456dc186 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 6bd8ab3d798..c1381a5a460 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 9bd7c9e53254e920bb83b67aa67b771f4bec4d8f 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 657c0834240..9bce140eb8f 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 { @@ -833,7 +855,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 760e099efb373f7fb7a23bc4b9202066565614b9 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 70bf46c4487..cfbd088d863 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 */ @@ -1158,6 +1158,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 7ec1b9fb235618c189fd917a36ba2ceba8091aeb 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 37f9427307f..0a8929bd58b 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -91,7 +91,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 6d690675734606ee4d59043c03d438eabc483645 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 9bce140eb8f..14557117580 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, @@ -925,7 +923,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 3abb2a6e1c6ec70bc52255518c179e0676b9dced 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 97044611d613fd5ebfe584e5a92b525474ce3ae9 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 14557117580..661b978a0dc 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 4a9602ea9bf8ad1d5a57c8811647cef22de784cd 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 a9aa06190eb..2d1e54070f2 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 c1381a5a460..17da4e290f4 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 661b978a0dc..eb4c6537532 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->phy.otg->default_a = true; -- cgit v1.2.3 From 7d3cfe37174feb905b2c1bded337fd5f13242ed5 Mon Sep 17 00:00:00 2001 From: rajaram Date: Fri, 28 Oct 2011 11:46:46 +0530 Subject: u8500 : USB :New notification events for BatMan Added notification events for ACA cases so that battery manager can distinguish between Standard Host and ACA charger. ST-Ericsson Linux next: NA ST-Ericsson ID: 362951 ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: rajaram Signed-off-by: Sakethram Bommisetti Change-Id: I02a19bced97b408990d8effb785418bf182ac27b Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/34862 Tested-by: Rajaram REGUPATHY Reviewed-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/musb/ux500.c | 1 + drivers/usb/otg/ab8500-usb.c | 23 ++++++++++++++--------- include/linux/usb/otg.h | 3 +++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 17da4e290f4..51f14effa1f 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -212,6 +212,7 @@ static int musb_otg_notifications(struct notifier_block *nb, switch (event) { case USB_EVENT_ID: + case USB_EVENT_RIDA: dev_dbg(musb->controller, "ID GND\n"); if (is_otg_enabled(musb)) { ux500_musb_set_vbus(musb, 1); diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index eb4c6537532..93a99915b66 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -314,10 +314,11 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) lsts = (reg >> 3) & 0x0F; switch (lsts) { + case USB_LINK_ACA_RID_B: + event = USB_EVENT_RIDB; 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) @@ -325,18 +326,19 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) ab->mode = USB_IDLE; ab->phy.otg.default_a = false; ab->vbus_draw = 0; - event = USB_EVENT_NONE; + if (event != USB_EVENT_RIDB) + event = USB_EVENT_NONE; break; - + case USB_LINK_ACA_RID_C_NM: + case USB_LINK_ACA_RID_C_HS: + case USB_LINK_ACA_RID_C_HS_CHIRP: + event = USB_EVENT_RIDC; 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: - 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); @@ -348,11 +350,13 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) ux500_restore_context(); ab8500_usb_peri_phy_en(ab); } - event = USB_EVENT_VBUS; + if (event != USB_EVENT_RIDC) + event = USB_EVENT_VBUS; break; - case USB_LINK_HM_IDGND: case USB_LINK_ACA_RID_A: + event = USB_EVENT_RIDA; + case USB_LINK_HM_IDGND: if (ab->mode == USB_PERIPHERAL) { ab->mode = USB_HOST; ab8500_usb_peri_phy_dis(ab); @@ -365,7 +369,8 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) ab8500_usb_host_phy_en(ab); } ab->phy.otg->default_a = true; - event = USB_EVENT_ID; + if (event != USB_EVENT_RIDA) + event = USB_EVENT_ID; break; case USB_LINK_DEDICATED_CHG: diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 38ab3f46346..c3b77fcdce7 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -41,6 +41,9 @@ enum usb_phy_events { USB_EVENT_ID, /* id was grounded */ USB_EVENT_CHARGER, /* usb dedicated charger */ USB_EVENT_ENUMERATED, /* gadget driver enumerated */ + USB_EVENT_RIDA, + USB_EVENT_RIDB, + USB_EVENT_RIDC, }; struct usb_phy; -- cgit v1.2.3 From 8ec6202f325cc95f90c8769368f9684abe68b3f9 Mon Sep 17 00:00:00 2001 From: rajaram Date: Thu, 10 Nov 2011 08:40:09 +0530 Subject: ux500 : usb : prevent sleep during usb host audio load When playing audio in usb host audio UC noise is observed, The system wake up latency from sleep adds an extra overhead when transferring ISO packets in host mode. Hence managing latency when there is high usb activity in host mode and releasing when there is no activity. Change-Id: I2589a98adc793d62c325baa056784d8a2ed67143 Signed-off-by: rajaram Signed-off-by: Philippe Langlais Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/37240 Tested-by: Rajaram REGUPATHY Reviewed-by: QABUILD Reviewed-by: Srinidhi KASAGAR Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 93a99915b66..6b1b268acbc 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -71,6 +72,8 @@ #define AB8500_USB_PHY_TUNE2 0x06 #define AB8500_USB_PHY_TUNE3 0x07 +static struct pm_qos_request usb_pm_qos_latency; +static bool usb_pm_qos_is_latency_0; #define USB_PROBE_DELAY 1000 /* 1 seconds */ #define USB_LIMIT (200) /* If we have more than 200 irqs per second */ @@ -170,13 +173,27 @@ static void ab8500_usb_load(struct work_struct *work) 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, + (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); + if (!usb_pm_qos_is_latency_0) { + + pm_qos_add_request(&usb_pm_qos_latency, + PM_QOS_CPU_DMA_LATENCY, 0); + usb_pm_qos_is_latency_0 = true; + } + } else { + + if (usb_pm_qos_is_latency_0) { + + pm_qos_remove_request(&usb_pm_qos_latency); + usb_pm_qos_is_latency_0 = false; + } + prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, + "usb", 25); + } old_num_irqs = num_irqs; schedule_delayed_work_on(0, @@ -221,6 +238,7 @@ static void ab8500_usb_regulator_ctrl(struct ab8500_usb *ab, bool sel_host, } } + static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) { u8 bit; @@ -234,11 +252,10 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 100); - if (!sel_host) { - schedule_delayed_work_on(0, + + 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, -- cgit v1.2.3 From ed6b8a71d3ab63d73749278896ac515fc2ad0ca2 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 15 Nov 2011 13:49:23 +0530 Subject: u8500:USB:Handle multiple Link status fn calls During boot time, multiple calls are made to Link status function by otg_set_host and otg_set_peripheral. This in turn calls clock and regulator enabling multiple times which creates problem with the reference count of regulators. Hence this blocks the CPU idle since the regulators are not released properly due to multiple acquire. So, Link status function calls are removed from otg_set_host and otg_set_peripheral which are not needed. The Link status call during boot shall be handled by the ab8500_usb_boot_detect function. ST-Ericsson ID: 373105 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I2ead5b546273be822b3e9e9f588a1954b3fa10f2 Signed-off-by: Sakethram Bommisetti --- drivers/usb/otg/ab8500-usb.c | 67 ++++---------------------------------------- 1 file changed, 6 insertions(+), 61 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 6b1b268acbc..189e764a68d 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -504,23 +504,13 @@ static int ab8500_usb_set_peripheral(struct usb_otg *otg, ab = phy_to_ab(otg->phy); + ab->otg.gadget = gadget; /* Some drivers call this function in atomic context. * Do not update ab8500 registers directly till this * is fixed. */ - - if (!gadget) { - otg->gadget = NULL; + if (!gadget) schedule_work(&ab->phy_dis_work); - } else { - 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; } @@ -534,22 +524,14 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) ab = phy_to_ab(otg->phy); + ab->otg.host = host; + /* Some drivers call this function in atomic context. * Do not update ab8500 registers directly till this * is fixed. */ - - if (!host) { - otg->host = NULL; + if (!host) schedule_work(&ab->phy_dis_work); - } else { - 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; } @@ -561,11 +543,6 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) */ 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, @@ -595,39 +572,7 @@ static int ab8500_usb_boot_detect(struct ab8500_usb *ab) 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); - } + ab8500_usb_link_status_update(ab); return 0; } -- cgit v1.2.3 From 9107c03b38b67ae82f905fecf582a9501fb48036 Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Tue, 29 Nov 2011 18:37:44 +0530 Subject: ux500: usb:handle connection of microA to A cable Connect Micro-A to phone first,Then connect device usb session should be valid to detect the connected device,Until host cable (micro-A) removal. MUSB session bit is cleared when usb host cable (Micro-A) removal from the phone,Not in case of only device disconnection from the usb host cable. ST-Ericsson ID: 364426 ST-Ericsson FOSS-OUT ID: NA ST-Ericsson Linux next: NA Signed-off-by: Thirupathi --- drivers/usb/musb/ux500.c | 14 ++++++++++---- drivers/usb/otg/ab8500-usb.c | 9 ++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 51f14effa1f..8872393be94 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -192,11 +192,15 @@ static void musb_notify_idle(unsigned long _musb) 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); + if (devctl & MUSB_DEVCTL_BDEVICE) { + musb->xceiv->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + } else { + musb->xceiv->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + } break; + case OTG_STATE_A_SUSPEND: default: break; @@ -226,6 +230,8 @@ static int musb_otg_notifications(struct notifier_block *nb, case USB_EVENT_NONE: dev_dbg(musb->controller, "VBUS Disconnect\n"); + if (is_otg_enabled(musb)) + ux500_musb_set_vbus(musb, 0); break; default: diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 189e764a68d..f51ac3fe836 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -413,10 +413,17 @@ static void ab8500_usb_delayed_work(struct work_struct *work) static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; + enum usb_xceiv_events event; /* Link status will not be updated till phy is disabled. */ - if (ab->mode == USB_HOST) + if (ab->mode == USB_HOST) { + event = USB_EVENT_NONE; + ab->otg.default_a = false; + ab->vbus_draw = 0; + atomic_notifier_call_chain(&ab->otg.notifier, + event, &ab->vbus_draw); 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) { -- cgit v1.2.3 From 9d4c65b12c05826f8380d6ed80b96a0b7b484b41 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 6 Dec 2011 10:50:32 +0530 Subject: [Android]:USB:ab850:Correcting USB sysfs interface The USB serial number which is exposed via sysfs is exposed at the /sys/serial_number which is improper location. Sysfs entries should be exposed from /sys/devices/platform/ using a kobject from the device struct. Added a new sysfs entry for delaying the enumeration. User space has to update the values in kernel space and then the enumeration will start. ST-Ericsson Linux next: NA ST-Ericsson ID: 350337 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I93dc5e1fe7bd51e53aa767f7832a4f8e77fe1317 Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/41158 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/42051 Reviewed-by: QABUILD Reviewed-by: Rabin VINCENT Tested-by: Axel FAGERSTEDT --- drivers/usb/otg/ab8500-usb.c | 223 ++++++++++++++++++++++++------------------- 1 file changed, 123 insertions(+), 100 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index f51ac3fe836..5c5b6a9dcdb 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -128,7 +128,7 @@ struct ab8500_usb { struct regulator *v_ulpi; struct abx500_usbgpio_platform_data *usb_gpio; struct delayed_work work_usb_workaround; - struct kobject *serial_number_kobj; + bool sysfs_flag; }; static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x) @@ -330,75 +330,77 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) lsts = (reg >> 3) & 0x0F; - switch (lsts) { - case USB_LINK_ACA_RID_B: - event = USB_EVENT_RIDB; - case USB_LINK_NOT_CONFIGURED: - case USB_LINK_RESERVED: - case USB_LINK_NOT_VALID_LINK: - 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->phy.otg.default_a = false; - ab->vbus_draw = 0; - if (event != USB_EVENT_RIDB) - event = USB_EVENT_NONE; - break; - case USB_LINK_ACA_RID_C_NM: - case USB_LINK_ACA_RID_C_HS: - case USB_LINK_ACA_RID_C_HS_CHIRP: - event = USB_EVENT_RIDC; - 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->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); - } - if (event != USB_EVENT_RIDC) - event = USB_EVENT_VBUS; - break; - - case USB_LINK_ACA_RID_A: - event = USB_EVENT_RIDA; - case USB_LINK_HM_IDGND: - 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->sysfs_flag)) { + switch (lsts) { + case USB_LINK_ACA_RID_B: + event = USB_EVENT_RIDB; + case USB_LINK_NOT_CONFIGURED: + case USB_LINK_RESERVED: + case USB_LINK_NOT_VALID_LINK: + 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->phy.otg.default_a = false; + ab->vbus_draw = 0; + if (event != USB_EVENT_RIDB) + event = USB_EVENT_NONE; + break; + case USB_LINK_ACA_RID_C_NM: + case USB_LINK_ACA_RID_C_HS: + case USB_LINK_ACA_RID_C_HS_CHIRP: + event = USB_EVENT_RIDC; + 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->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); + } + if (event != USB_EVENT_RIDC) + event = USB_EVENT_VBUS; + break; + + case USB_LINK_ACA_RID_A: + event = USB_EVENT_RIDA; + case USB_LINK_HM_IDGND: + 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->phy.otg->default_a = true; + if (event != USB_EVENT_RIDA) + event = USB_EVENT_ID; + break; + + case USB_LINK_DEDICATED_CHG: + /* TODO: vbus_draw */ + ab->mode = USB_DEDICATED_CHG; + event = USB_EVENT_CHARGER; + break; } - if (ab->mode == USB_IDLE) { - ab->mode = USB_HOST; - ux500_restore_context(); - ab8500_usb_host_phy_en(ab); - } - ab->phy.otg->default_a = true; - if (event != USB_EVENT_RIDA) - event = USB_EVENT_ID; - break; - - case USB_LINK_DEDICATED_CHG: - /* TODO: vbus_draw */ - ab->mode = USB_DEDICATED_CHG; - event = USB_EVENT_CHARGER; - break; + atomic_notifier_call_chain(&ab->phy.notifier, event, + &ab->vbus_draw); } - atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); - return 0; } @@ -579,8 +581,6 @@ static int ab8500_usb_boot_detect(struct ab8500_usb *ab) AB8500_BIT_PHY_CTRL_HOST_EN, 0); - ab8500_usb_link_status_update(ab); - return 0; } @@ -713,8 +713,9 @@ irq_fail: } /* Sys interfaces */ -static ssize_t usb_serial_number - (struct kobject *kobj, struct attribute *attr, char *buf) +static ssize_t +serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 bufer[5]; void __iomem *backup_ram = NULL; @@ -734,27 +735,60 @@ static ssize_t usb_serial_number iounmap(backup_ram); } else - printk(KERN_ERR "$$ ioremap failed\n"); + dev_err(dev, "$$\n"); + + return strlen(buf); +} + +static DEVICE_ATTR(serial_number, 0644, serial_number_show, NULL); + +static ssize_t +boot_time_device_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ab8500_usb *ab = dev_get_drvdata(dev); + u8 val = ab->sysfs_flag; + + snprintf(buf, 2, "%d", val); return strlen(buf); } -static struct attribute usb_serial_number_attribute = \ - {.name = "serial_number", .mode = S_IRUGO}; +static ssize_t +boot_time_device_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct ab8500_usb *ab = dev_get_drvdata(dev); + + ab->sysfs_flag = false; + + ab8500_usb_link_status_update(ab); + + return n; +} +static DEVICE_ATTR(boot_time_device, 0644, + boot_time_device_show, boot_time_device_store); -static struct attribute *serial_number[] = { - &usb_serial_number_attribute, + +static struct attribute *ab8500_usb_attributes[] = { + &dev_attr_serial_number.attr, + &dev_attr_boot_time_device.attr, NULL }; - -const struct sysfs_ops usb_sysfs_ops = { - .show = usb_serial_number, +static const struct attribute_group ab8500_attr_group = { + .attrs = ab8500_usb_attributes, }; -static struct kobj_type ktype_serial_number = { - .sysfs_ops = &usb_sysfs_ops, - .default_attrs = serial_number, -}; +static int ab8500_create_sysfsentries(struct ab8500_usb *ab) +{ + int err; + + err = sysfs_create_group(&ab->dev->kobj, &ab8500_attr_group); + if (err) + sysfs_remove_group(&ab->dev->kobj, &ab8500_attr_group); + + return err; +} static int __devinit ab8500_usb_probe(struct platform_device *pdev) { @@ -798,9 +832,10 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) otg->set_host = ab8500_usb_set_host; otg->set_peripheral = ab8500_usb_set_peripheral; ab->usb_gpio = ab8500_pdata->usb; + ab->sysfs_flag = true; platform_set_drvdata(pdev, ab); - + dev_set_drvdata(ab->dev, ab); ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier); /* v1: Wait for link status to become stable. @@ -882,22 +917,6 @@ 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; @@ -912,6 +931,10 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) if (err < 0) goto fail3; + err = ab8500_create_sysfsentries(ab); + if (err) + goto fail3; + return 0; fail3: ab8500_usb_irq_free(ab); -- cgit v1.2.3 From 64d32b4540bd292f12c3e492709dd09475da4811 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 8872393be94..f0ce8ac3cf4 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 eb6d9f3e6dcd53ccd5b4092a4c24d38377ba4657 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 ccce83ab5ee3751591330a31acd3c07ca4df2c37 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 9b9f3de02c0..2f0f8a48d1a 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2375,7 +2375,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 From 9434741e88a02a8a13504c1b080b56ce156f2abd Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Fri, 21 Oct 2011 12:19:07 +0530 Subject: ux500: usb: restore INDEX register in resume path Restoring the missing INDEX register value in ux500_restore_context(). without this Hub enumeration is inconsistent, if we do multiple connect/disconnect. ST-Ericsson ID: 364906 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Thirupathi --- drivers/usb/musb/ux500.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index f0ce8ac3cf4..556f262f0a6 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -189,6 +189,7 @@ void ux500_restore_context(void) context.index_regs[i].rxhubport); } } + musb_writeb(musb_base, MUSB_INDEX, context.index); #endif } -- cgit v1.2.3 From b295cb74d06210da74c8876193a9fb0d124e4482 Mon Sep 17 00:00:00 2001 From: maheswarudu Date: Wed, 2 Nov 2011 19:40:10 +0530 Subject: ux500: USB : Save/Restore musb registers correctly In suspended state the registers are not saved and restored properly hence back ported. (http://git.kernel.org/?p=linux/kernel/git/gregkh/usb.git; a=commit;h=e4e5b136eb6f2d3aa10dca108a1b787dc92d67df) Also the code is aligned as per the latest linux-next. ST-Ericsson ID: 366298, 368370 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: I97ae0b055f6f1300a11190e1083349a6583f0377 Signed-off-by: maheswarudu --- drivers/usb/musb/ux500.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 556f262f0a6..dcff9c93653 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -59,6 +59,7 @@ void ux500_store_context(struct musb *musb) if (is_host_enabled(musb)) { context.frame = musb_readw(musb_base, MUSB_FRAME); context.testmode = musb_readb(musb_base, MUSB_TESTMODE); + context.busctl = musb_read_ulpi_buscontrol(musb->mregs); } context.power = musb_readb(musb_base, MUSB_POWER); context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); @@ -66,8 +67,19 @@ void ux500_store_context(struct musb *musb) 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; + struct musb_hw_ep *hw_ep; + + musb_writeb(musb_base, MUSB_INDEX, i); + hw_ep = &musb->endpoints[i]; + if (!hw_ep) + continue; + + epio = hw_ep->regs; + if (!epio) + continue; + context.index_regs[i].txmaxp = musb_readw(epio, MUSB_TXMAXP); context.index_regs[i].txcsr = @@ -132,6 +144,7 @@ void ux500_restore_context(void) if (is_host_enabled(musb)) { musb_writew(musb_base, MUSB_FRAME, context.frame); musb_writeb(musb_base, MUSB_TESTMODE, context.testmode); + musb_write_ulpi_buscontrol(musb->mregs, context.busctl); } musb_writeb(musb_base, MUSB_POWER, context.power); musb_writew(musb_base, MUSB_INTRTXE, context.intrtxe); @@ -140,7 +153,17 @@ void ux500_restore_context(void) musb_writeb(musb_base, MUSB_DEVCTL, context.devctl); for (i = 0; i < musb->config->num_eps; ++i) { - epio = musb->endpoints[i].regs; + struct musb_hw_ep *hw_ep; + + musb_writeb(musb_base, MUSB_INDEX, i); + hw_ep = &musb->endpoints[i]; + if (!hw_ep) + continue; + + epio = hw_ep->regs; + if (!epio) + continue; + musb_writew(epio, MUSB_TXMAXP, context.index_regs[i].txmaxp); musb_writew(epio, MUSB_TXCSR, -- cgit v1.2.3 From 2c2e0c520b7562f357fcfe2628352f8fd36cc0af Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Wed, 23 Nov 2011 18:07:24 +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. Bus reset happening due to scsi timeout,since in this case should not return continue for next transfers. ST-Ericsson ID:ER 365087 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Thirupathi --- drivers/usb/musb/musb_host.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index cfbd088d863..650e01eec1c 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1173,7 +1173,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) } 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 9785ed49a41db63920a2d63b6d792bacc7dee010 Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Fri, 9 Dec 2011 16:32:37 +0530 Subject: usb: musb: TXMAXP,TXCSR setting in Host mode The TXMAXP and TXCSR registers were not set correctly for the BULK OUT endpoints causing issues in Full speed in Host mode. ST-Ericsson Linux next: NA ST-Ericsson ID: 367049 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: If5f3552235d8909adef4777f08d612df432d8709 Signed-off-by: supriya karanth --- drivers/usb/musb/musb_host.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 650e01eec1c..0a108587e2e 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -640,7 +640,17 @@ static bool musb_tx_dma_program(struct dma_controller *dma, mode = 1; csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB; /* autoset shouldn't be set in high bandwidth */ - if (qh->hb_mult == 1) + /* + * Enable Autoset according to table + * below + * bulk_split hb_mult Autoset_Enable + * 0 1 Yes(Normal) + * 0 >1 No(High BW ISO) + * 1 1 Yes(HS bulk) + * 1 >1 Yes(FS bulk) + */ + if (qh->hb_mult == 1 || (qh->hb_mult > 1 && + can_bulk_split(hw_ep->musb, qh->type))) csr |= MUSB_TXCSR_AUTOSET; } else { mode = 0; @@ -787,6 +797,13 @@ static void musb_ep_program(struct musb *musb, u8 epnum, /* protocol/endpoint/interval/NAKlimit */ if (epnum) { musb_writeb(epio, MUSB_TXTYPE, qh->type_reg); + /* + * Set the TXMAXP register correctly for Bulk OUT + * endpoints in host mode + */ + if (can_bulk_split(musb, qh->type)) + qh->hb_mult = hw_ep->max_packet_sz_tx + / packet_sz; if (musb->double_buffer_not_ok) musb_writew(epio, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); -- cgit v1.2.3 From 97c6e96a8bddb4ce996e3f1f07aef680a9e960e6 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 20 Oct 2011 19:00:08 +0530 Subject: ux500:USB:Endpoint configuration New usb_gadget_ops call for endpoint configuration allows the platform to configure the endpoints. ST-Ericsson Linux next: NA ST-Ericsson ID: 369302 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I3dd468a590e4439e540865b67cbc501bbdc4dcf7 Signed-off-by: Sakethram Bommisetti Signed-off-by: Philippe Langlais Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/35058 Reviewed-by: Srinidhi KASAGAR --- drivers/usb/gadget/epautoconf.c | 6 ++++++ drivers/usb/musb/musb_core.h | 11 +++++++++++ drivers/usb/musb/musb_gadget.c | 9 +++++++++ drivers/usb/musb/ux500.c | 25 +++++++++++++++++++++++++ include/linux/usb/gadget.h | 2 ++ 5 files changed, 53 insertions(+) diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 51f3d42f5a6..14cbfa80afb 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -315,6 +315,12 @@ struct usb_ep *usb_ep_autoconfig_ss( #endif } + if (gadget->ops->configure_ep) { + ep = gadget->ops->configure_ep(gadget, type, desc); + if (ep && ep_matches(gadget, ep, desc, ep_comp)) + return ep; + } + /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { if (ep_matches(gadget, ep, desc, ep_comp)) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index f4a40f001c8..f7a37fa1bfe 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -229,6 +229,8 @@ struct musb_platform_ops { int (*adjust_channel_params)(struct dma_channel *channel, u16 packet_sz, u8 *mode, dma_addr_t *dma_addr, u32 *len); + struct usb_ep* (*configure_endpoints)(struct musb *musb, u8 type, + struct usb_endpoint_descriptor *desc); }; /* @@ -603,4 +605,13 @@ static inline int musb_platform_exit(struct musb *musb) return musb->ops->exit(musb); } +static inline struct usb_ep *musb_platform_configure_ep(struct musb *musb, + u8 type, struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep = NULL; + + if (musb->ops->configure_endpoints) + ep = musb->ops->configure_endpoints(musb, type, desc); + return ep; +} #endif /* __MUSB_CORE_H__ */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index f42c29b11f7..c2d0e4bfa67 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1753,6 +1753,14 @@ static int musb_gadget_start(struct usb_gadget *g, static int musb_gadget_stop(struct usb_gadget *g, struct usb_gadget_driver *driver); +static struct usb_ep *musb_gadget_configure_ep(struct usb_gadget *gadget, + u8 type, struct usb_endpoint_descriptor *desc) +{ + struct musb *musb = gadget_to_musb(gadget); + + return musb_platform_configure_ep(musb, type, desc); +} + static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, .wakeup = musb_gadget_wakeup, @@ -1762,6 +1770,7 @@ static const struct usb_gadget_ops musb_gadget_operations = { .pullup = musb_gadget_pullup, .udc_start = musb_gadget_start, .udc_stop = musb_gadget_stop, + .configure_ep = musb_gadget_configure_ep, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index dcff9c93653..ae6be2eaa09 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -369,10 +369,34 @@ 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 struct usb_ep *ux500_musb_configure_endpoints(struct musb *musb, + u8 type, struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep = NULL; + struct usb_gadget *gadget = &musb->g; + char name[4]; + + if (USB_ENDPOINT_XFER_INT == type) { + list_for_each_entry(ep, &gadget->ep_list, ep_list) { + if (ep->maxpacket == 512) + continue; + if (NULL == ep->driver_data) { + strncpy(name, (ep->name + 3), 4); + if (USB_DIR_IN & desc->bEndpointAddress) + if (strcmp("in", name) == 0) + return ep; + } + } + } + return ep; +} + static int ux500_musb_init(struct musb *musb) { int status; @@ -418,6 +442,7 @@ static const struct musb_platform_ops ux500_ops = { .try_idle = ux500_musb_try_idle, .enable = ux500_musb_enable, + .configure_endpoints = ux500_musb_configure_endpoints, }; /** diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 9517466abab..51c97812bf4 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -476,6 +476,8 @@ struct usb_gadget_ops { int (*start)(struct usb_gadget_driver *, int (*bind)(struct usb_gadget *)); int (*stop)(struct usb_gadget_driver *); + struct usb_ep* (*configure_ep)(struct usb_gadget *, u8 type, + struct usb_endpoint_descriptor *); }; /** -- cgit v1.2.3 From 751b08002d52e0790075f02413b434cac0ab7504 Mon Sep 17 00:00:00 2001 From: Ravikant Singh Date: Fri, 21 Oct 2011 14:46:35 +0530 Subject: u5500: usb: notification for dedicated charger platform fix for usb dedicated charger. usb sends appropriate notificaition for dedicated charger case. ST-Ericsson ID: 362951 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Ravikant Singh Change-Id: I3f4f48db8f6ef2e8bb5a3ed33c8b5894734381f6 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/34866 Reviewed-by: QATOOLS Reviewed-by: Praveena NADAHALLY Tested-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index 2f3c48a8336..fcee8a1a144 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -258,6 +258,10 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) ab->otg.default_a = true; event = USB_EVENT_ID; + break; + case USB_LINK_DEDICATED_CHG: + /* TODO: vbus_draw */ + event = USB_EVENT_CHARGER; break; default: break; -- cgit v1.2.3 From 6dfb7bff0f0da151f93f716038269f3c1fd3745d Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Mon, 7 Nov 2011 16:37:31 +0530 Subject: ux500:USB:Updating is_compatible with class checks Current checks in is_compatible doesn't handle all the needed DMA cases. In case of Ethernet out transactions data size is not known and we cannot use the dma effectively in such cases. So,Using class names to accurately handle all the musb dma limitations/features.Hence, only for mass storage and ACM classes, data will be transfered over DMA. ST-Ericsson Linux next: NA ST-Ericsson ID: 373086 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: If83db00286bdc04c3d8e65e272b3ed586390ecfb Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/36991 Reviewed-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/musb/ux500_dma.c | 50 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 389bf8890a5..cb86beb8ec2 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -32,6 +32,11 @@ #include #include #include "musb_core.h" +#undef DBG +#undef WARNING +#undef INFO +#include +#define U8500_USB_DMA_MIN_TRANSFER_SIZE 512 struct ux500_dma_channel { struct dma_channel channel; @@ -205,13 +210,44 @@ 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) || - ((int)buf & 0x3) || - (length < 512) || - (length & 0x3)) - return false; - else - return true; + struct ux500_dma_channel *ux500_channel = channel->private_data; + struct musb_hw_ep *hw_ep = ux500_channel->hw_ep; + struct musb *musb = hw_ep->musb; + struct usb_descriptor_header **descriptors; + struct usb_function *f; + struct usb_gadget *gadget = &musb->g; + struct usb_composite_dev *cdev = get_gadget_data(gadget); + + if (length < U8500_USB_DMA_MIN_TRANSFER_SIZE) + return 0; + + list_for_each_entry(f, &cdev->config->functions, list) { + if (!strcmp(f->name, "cdc_ethernet") || + !strcmp(f->name, "rndis") || + !strcmp(f->name, "phonet") || + !strcmp(f->name, "adb")) { + if (gadget->speed == USB_SPEED_HIGH) + descriptors = f->hs_descriptors; + else + descriptors = f->descriptors; + + for (; *descriptors; ++descriptors) { + struct usb_endpoint_descriptor *ep; + + if ((*descriptors)->bDescriptorType != + USB_DT_ENDPOINT) + continue; + + ep = (struct usb_endpoint_descriptor *) + *descriptors; + if (ep->bEndpointAddress == + ux500_channel->hw_ep->epnum) + return 0; + } + } + } + + return 1; } /** -- cgit v1.2.3 From 2185d914ee565f064a8a579bf815edf54271b814 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Wed, 9 Nov 2011 19:13:53 +0530 Subject: ux500:USB:Call is_compatible only in gadget mode DMA channel program is called both in host and device modes. We are checking is_compatible in channel program.is_compatible should be used only by the gadget mode. So removing is_compatible in channel program and keeping generic checks. ST-Ericsson Linux next: NA ST-Ericsson ID: 373086 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I9c4d8dcaa93dd46d035c9060eeb437c15950bff2 Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/37188 Reviewed-by: QABUILD Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/ux500_dma.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index cb86beb8ec2..db657104292 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -36,7 +36,7 @@ #undef WARNING #undef INFO #include -#define U8500_USB_DMA_MIN_TRANSFER_SIZE 512 +#define Ux500_USB_DMA_MIN_TRANSFER_SIZE 512 struct ux500_dma_channel { struct dma_channel channel; @@ -218,7 +218,7 @@ static int ux500_dma_is_compatible(struct dma_channel *channel, struct usb_gadget *gadget = &musb->g; struct usb_composite_dev *cdev = get_gadget_data(gadget); - if (length < U8500_USB_DMA_MIN_TRANSFER_SIZE) + if (length < Ux500_USB_DMA_MIN_TRANSFER_SIZE) return 0; list_for_each_entry(f, &cdev->config->functions, list) { @@ -265,12 +265,15 @@ static int ux500_dma_channel_program(struct dma_channel *channel, dma_addr_t dma_addr, u32 len) { int ret; + struct ux500_dma_channel *ux500_dma_channel = channel->private_data; BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || channel->status == MUSB_DMA_STATUS_BUSY); - if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len)) - return false; + if (len < Ux500_USB_DMA_MIN_TRANSFER_SIZE) + return 0; + if (!ux500_dma_channel->is_tx && len < packet_sz) + return 0; channel->status = MUSB_DMA_STATUS_BUSY; channel->actual_len = 0; -- cgit v1.2.3 From a63e647dd201e8b1f43aabec43993ce8a87dccb1 Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Fri, 11 Nov 2011 13:09:51 +0530 Subject: usb: ab5500-usb: Do not enumerate while in charge only mode When in charge only mode, usb enumeration is not to be enabled. To achieve this turn on status and the reset reason is checked. ST-Ericsson Linux next: NA ST-Ericsson ID: 362951 ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Arun Murthy Change-Id: Idbbb13d7ecf8fb3423459a85b4ddebcce1a8404c Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/37398 Reviewed-by: Supriya s KARANTH Tested-by: Supriya s KARANTH Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/otg/ab5500-usb.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index fcee8a1a144..8164ccb4195 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -20,6 +20,7 @@ #include #include #include +#include /* AB5500 USB macros */ @@ -523,7 +524,17 @@ static int ab5500_usb_boot_detect(struct ab5500_usb *ab) case USB_LINK_HOST_CHG_NM: case USB_LINK_HOST_CHG_HS: case USB_LINK_HOST_CHG_HS_CHIRP: - + /* + * If Power on key was not pressed then enter charge only + * mode and dont enumerate + */ + if ((!(ab5500_get_turn_on_status() & + (P_ON_KEY1_EVENT | P_ON_KEY2_EVENT))) && + (prcmu_get_reset_code() != + SW_RESET_CHGONLY_EXIT)) { + dev_dbg(ab->dev, "USB entered charge only mode"); + return 0; + } ab5500_usb_peri_phy_en(ab); /* enable usb chip Select */ -- cgit v1.2.3 From 4342282398add40291a8542bd51e770948819899 Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Tue, 22 Nov 2011 10:02:14 +0530 Subject: usb: ab5500-usb: Check proper reset reason for charge only mode For charge only mode block enumeration only in the coldboot case.If a reboot happens due to any other reason then USB should enumerate. ST-Ericsson Linux next: NA ST-Ericsson ID: 375372 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I8fd33894945454da1be589b38bc6364ff324f820 Signed-off-by: supriya karanth Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/39079 Reviewed-by: Arun MURTHY Reviewed-by: QABUILD Reviewed-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index 8164ccb4195..b1b3b21b22d 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -530,8 +530,8 @@ static int ab5500_usb_boot_detect(struct ab5500_usb *ab) */ if ((!(ab5500_get_turn_on_status() & (P_ON_KEY1_EVENT | P_ON_KEY2_EVENT))) && - (prcmu_get_reset_code() != - SW_RESET_CHGONLY_EXIT)) { + (prcmu_get_reset_code() == + SW_RESET_COLDSTART)) { dev_dbg(ab->dev, "USB entered charge only mode"); return 0; } -- cgit v1.2.3 From 23cd36b39f99de25aecd25af14a48ba3348dcffd Mon Sep 17 00:00:00 2001 From: maheswarudu Date: Thu, 1 Dec 2011 11:16:45 +0100 Subject: ux500: USB: platform specific musb fifo cfg Pass the musb fifo configuration through ux500 platform file. ST-Ericsson ID: 367200 ST-Ericsson FOSS-OUT ID: NA ST-Ericsson Linux next: NA Signed-off-by: maheswarudu Change-Id: If7aaddeb85198dc9edce605efec9a87bbfb6658c Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/40604 Reviewed-by: QATOOLS Reviewed-by: QABUILD Tested-by: Tobias ANDERSON Reviewed-by: Rajaram REGUPATHY Reviewed-by: Rabin VINCENT Conflicts: drivers/usb/musb/musb_core.c --- arch/arm/mach-ux500/usb.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/musb_core.c | 3 --- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 0a8929bd58b..50d6f6d3788 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -98,7 +98,47 @@ static u64 ux500_musb_dmamask = DMA_BIT_MASK(0); #endif static struct ux500_pins *usb_gpio_pins; +/** + * Fifo mode + * Sum of maxpacket <= 12 KB + * As ux500 provides 12 KB buffer size only + * + * Enable Double buffer for Mass Storage Class + * endpoint. + */ +static struct musb_fifo_cfg ux500_mode_cfg[] = { +{ .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, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 32, }, +{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 32, }, +{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 32, }, +{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 32, }, +{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 32, }, +{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 32, }, +{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 32, }, +{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 32, }, +{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 32, }, +{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 32, }, +{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 32, }, +{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 32, }, +{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 32, }, +{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 32, }, +{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 512, }, +{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, }, +{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, +}; + static struct musb_hdrc_config musb_hdrc_config = { + .fifo_cfg = ux500_mode_cfg, /* Fifo configuration */ + .fifo_cfg_size = ARRAY_SIZE(ux500_mode_cfg), .multipoint = true, .dyn_fifo = true, .num_eps = 16, diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 2f0f8a48d1a..5faac98ca30 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1036,9 +1036,6 @@ static void musb_shutdown(struct platform_device *pdev) || defined(CONFIG_USB_MUSB_AM35X) \ || defined(CONFIG_USB_MUSB_AM35X_MODULE) static ushort __devinitdata fifo_mode = 4; -#elif defined(CONFIG_USB_MUSB_UX500) \ - || defined(CONFIG_USB_MUSB_UX500_MODULE) -static ushort __devinitdata fifo_mode = 5; #else static ushort __devinitdata fifo_mode = 2; #endif -- cgit v1.2.3 From 7da22d45b0365c8249fd801770aa50aa72e12054 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 13 Jan 2012 09:50:10 +0100 Subject: usb: u5500: support AB5500 v2.1 Signed-off-by: Rabin Vincent --- drivers/usb/otg/ab5500-usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index b1b3b21b22d..d0f59e5b55a 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -206,7 +206,7 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) (void)abx500_get_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &val); - if (ab->rev == AB5500_2_0) + 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; @@ -222,7 +222,7 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) break; case USB_LINK_HM_IDGND: - if (ab->rev == AB5500_2_0) + if (ab->rev >= AB5500_2_0) break; /* enable usb chip Select */ @@ -242,7 +242,7 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) break; case USB_LINK_HM_IDGND_V2: - if (!(ab->rev == AB5500_2_0)) + if (!(ab->rev >= AB5500_2_0)) break; /* enable usb chip Select */ @@ -511,7 +511,7 @@ static int ab5500_usb_boot_detect(struct ab5500_usb *ab) (void)abx500_get_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &usb_status); - if (ab->rev == AB5500_2_0) + 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; -- cgit v1.2.3 From f2ab5db5edc7db17a74ab95a746e24aaa041ea28 Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Tue, 6 Dec 2011 16:34:10 +0530 Subject: usb: musb: TXMAXP,TXCSR setting in Device mode The TXMAXP and TXCSR registers were not set correctly for the BULK IN endpoints causing issues in Full speed in device mode. ST-Ericsson Linux next: NA ST-Ericsson ID: 362969 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I9942821702e5f78b5bcf2439a378eb1a244cb86f Signed-off-by: supriya karanth Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/39173 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Rajaram REGUPATHY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/musb_gadget.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index c2d0e4bfa67..461b5f2d889 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -401,7 +401,21 @@ static void txstate(struct musb *musb, struct musb_request *req) csr |= (MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE); - if (!musb_ep->hb_mult) + /* + * Enable Autoset according to table + * below + * ************************************ + * bulk_split hb_mult Autoset_Enable + * ************************************ + * 0 0 Yes(Normal) + * 0 >0 No(High BW ISO) + * 1 0 Yes(HS bulk) + * 1 >0 Yes(FS bulk) + */ + if (!musb_ep->hb_mult || + (musb_ep->hb_mult && + can_bulk_split(musb, + musb_ep->type))) csr |= MUSB_TXCSR_AUTOSET; } csr &= ~MUSB_TXCSR_P_UNDERRUN; @@ -1097,6 +1111,12 @@ static int musb_gadget_enable(struct usb_ep *ep, /* REVISIT if can_bulk_split(), use by updating "tmp"; * likewise high bandwidth periodic tx */ + /* Set the TXMAXP register correctly for Bulk IN + * endpoints in device mode + */ + if (can_bulk_split(musb, musb_ep->type)) + musb_ep->hb_mult = (hw_ep->max_packet_sz_tx / + musb_ep->packet_sz) - 1; /* Set TXMAXP with the FIFO size of the endpoint * to disable double buffering mode. */ -- cgit v1.2.3 From 12f0f51f80cc6d0f9e05dbc9e640a8a5f2ad8633 Mon Sep 17 00:00:00 2001 From: Avinash Kumar Date: Tue, 13 Dec 2011 16:51:14 +0530 Subject: u5500: USB: Add context save and restore callbacks adding support for usb registers save restore context support in usb driver. ST-Ericsson ID: 350108 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Id373d0600413adeac5ac8603acc51f721500eafb Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/42338 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Praveena NADAHALLY Reviewed-by: Jonas ABERG Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index d0f59e5b55a..4219c56848e 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -162,6 +162,7 @@ static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) msecs_to_jiffies(USB_PROBE_DELAY)); } + ux500_restore_context(); abx500_mask_and_set_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_PHY_CTRL_REG, @@ -219,6 +220,9 @@ 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: + + ab5500_usb_peri_phy_en(ab); + break; case USB_LINK_HM_IDGND: @@ -302,8 +306,6 @@ static irqreturn_t ab5500_usb_device_insert_irq(int irq, void *data) 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); @@ -314,8 +316,6 @@ 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; } -- cgit v1.2.3 From b302109f5b0d2832ce45f3337df5b8f47dc1ff2f Mon Sep 17 00:00:00 2001 From: Ravikant Singh Date: Tue, 20 Dec 2011 15:36:03 +0530 Subject: u5500:Ignored link interrupt not to post usb event The ABB link status interrupt is coming twice for LinkStatus = 18 and 13 ,one of them is to be ignored depending on the current ABB hardware version. However for the ignored one too, the ABB driver is sending a spurious USB_EVENT_NONE notification event ,which is thus shutting down the vbus needed for enumerating the device. Hence 5500 usb host is not enumerating any devices. Solution is not to post the event USB_EVENT_NONE for the ignored link status interrupt. ST-Ericsson ID: 401855 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I7a7d8a19a5431e21661a0875061d51ba0129f25e Signed-off-by: Ravikant Singh Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/43042 Reviewed-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index 4219c56848e..aa439f6d4e2 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -202,7 +202,7 @@ 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 = USB_IDLE; + enum usb_xceiv_events event = USB_EVENT_NONE; (void)abx500_get_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &val); @@ -227,7 +227,7 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) case USB_LINK_HM_IDGND: if (ab->rev >= AB5500_2_0) - break; + return -1; /* enable usb chip Select */ ret = gpio_direction_output(ab->usb_cs_gpio, gpioval); @@ -247,7 +247,7 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) case USB_LINK_HM_IDGND_V2: if (!(ab->rev >= AB5500_2_0)) - break; + return -1; /* enable usb chip Select */ ret = gpio_direction_output(ab->usb_cs_gpio, gpioval); -- cgit v1.2.3 From bd06bae5c7ad2a9a9e1523aa17e00c929c20c3e0 Mon Sep 17 00:00:00 2001 From: Ajay Jawade Date: Tue, 20 Dec 2011 20:47:45 +0530 Subject: usb:musb:ux500: Disable DMA for MTP Disable DMA for MTP. ST-Ericsson ID: 325587 ST-Ericsson FOSS-OUT ID: Trivial ST-Ericsson Linux next: NA Change-Id: I950aca1233e76f79a547f6d928f2203e064e924e Signed-off-by: Ajay Jawade Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/43316 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Praveena NADAHALLY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/ux500_dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index db657104292..7bf0c289ef5 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -224,6 +224,7 @@ static int ux500_dma_is_compatible(struct dma_channel *channel, list_for_each_entry(f, &cdev->config->functions, list) { if (!strcmp(f->name, "cdc_ethernet") || !strcmp(f->name, "rndis") || + !strcmp(f->name, "mtp") || !strcmp(f->name, "phonet") || !strcmp(f->name, "adb")) { if (gadget->speed == USB_SPEED_HIGH) -- cgit v1.2.3 From e5fcaa745d3026864a00544d8db6e260076a359a Mon Sep 17 00:00:00 2001 From: Thirupathi Date: Wed, 21 Dec 2011 19:26:35 +0530 Subject: usb:Move double buffering to MSC interface EP For windows driver installation requirment, Mass-storage interface moved from first to third. Moved double buffering to mass-storage interface EP. ST-Ericsson ID: 406266 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: I8c0e70a62bf3436a7725cc10d6c50834d6963284 Signed-off-by: Thirupathi Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/43477 Reviewed-by: Praveena NADAHALLY Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Srinidhi KASAGAR --- arch/arm/mach-ux500/usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 50d6f6d3788..ca84e040e99 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -107,12 +107,12 @@ static struct ux500_pins *usb_gpio_pins; * endpoint. */ static struct musb_fifo_cfg ux500_mode_cfg[] = { -{ .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, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .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, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, -- cgit v1.2.3 From 348bfbaa94a066473de98cd4431193ff398d8ecd Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Fri, 30 Dec 2011 15:22:08 +0530 Subject: [Android]:USB:ab5500 sysfs entry for serial number Read serial number from Backup Ram and write it to the sysfs. ST-Ericsson Linux next: NA ST-Ericsson ID: 406526 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I5ba0ba326d33c70be3af1c42309237552cfcd4dc Signed-off-by: supriya karanth Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/43847 Reviewed-by: Praveena NADAHALLY Reviewed-by: QATOOLS Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index aa439f6d4e2..1f54ef4a356 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -47,6 +47,9 @@ #define USB_PROBE_DELAY 1000 /* 1 seconds */ +#define PUBLIC_ID_BACKUPRAM1 (U5500_BACKUPRAM1_BASE + 0x0FC0) +#define MAX_USB_SERIAL_NUMBER_LEN 31 + /* UsbLineStatus register - usb types */ enum ab8500_usb_link_status { USB_LINK_NOT_CONFIGURED, @@ -466,6 +469,55 @@ irq_fail: return err; } +/* Sys interfaces */ +static ssize_t +serial_number_show(struct device *dev, + struct device_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 + dev_err(dev, "$$\n"); + + return strlen(buf); +} + + +static DEVICE_ATTR(serial_number, 0644, serial_number_show, NULL); + +static struct attribute *ab5500_usb_attributes[] = { + &dev_attr_serial_number.attr, + NULL +}; +static const struct attribute_group ab5500_attr_group = { + .attrs = ab5500_usb_attributes, +}; + +static int ab5500_create_sysfsentries(struct ab5500_usb *ab) +{ + int err; + + err = sysfs_create_group(&ab->dev->kobj, &ab5500_attr_group); + if (err) + sysfs_remove_group(&ab->dev->kobj, &ab5500_attr_group); + + return err; +} + /** * ab5500_usb_boot_detect : detect the USB cable during boot time. * @mode: value for mode. @@ -708,6 +760,10 @@ static int __devinit ab5500_usb_probe(struct platform_device *pdev) if (err < 0) goto fail1; + err = ab5500_create_sysfsentries(ab); + if (err < 0) + dev_err(ab->dev, "usb create sysfs entries failed\n"); + return 0; fail1: -- cgit v1.2.3 From fffc899e629292f3759c637047d4b5dada79795b Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Wed, 4 Jan 2012 15:33:52 +0530 Subject: u5500:USB:ab5500 Send Correct usb event For the device detection case we send a wrong USB event in the vbus_draw notifier ST-Ericsson ID: 405507 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ibbc48a2b2e3ca89127370e4ccef682ab6ca3bb38 Signed-off-by: supriya karanth Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/44296 Reviewed-by: Praveena NADAHALLY Reviewed-by: QATOOLS Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index 1f54ef4a356..c57234d92be 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -224,6 +224,7 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) case USB_LINK_HOST_CHG_HS: case USB_LINK_HOST_CHG_HS_CHIRP: + event = USB_EVENT_VBUS; ab5500_usb_peri_phy_en(ab); break; -- cgit v1.2.3 From d392ee8d592fa53fc12e34ececcf566e9dfd8d85 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 2 Feb 2012 16:42:40 +0100 Subject: musb: Kconfig: enable by default USB_MUSB_UX500 on ux500 plaforms Workaround to force musb_ux500 driver to be built-in. Signed-off-by: Philippe Langlais --- drivers/usb/musb/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index ac26a4f8545..f9e42041b5f 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -34,6 +34,8 @@ if USB_MUSB_HDRC choice prompt "Platform Glue Layer" + bool + default USB_MUSB_UX500 if ARCH_U8500 || ARCH_U5500 config USB_MUSB_DAVINCI tristate "DaVinci" -- cgit v1.2.3 From 7182586f3896bef6679c90e1bcf8a0903c09b06a Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Thu, 12 Jan 2012 16:56:40 +0530 Subject: u5500:USB: prevent sleep while usb host audio While playing audio in usb host mode noise is observed, The system wake up latency from sleep adds an extra overhead when transferring ISO packets in host mode. Prevent CPU from going to idle state when when there is high usb activity in host mode. ST-Ericsson ID: 373230 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ie60e21e58cdffce0e83b10ac50b4fbb5890c19cd Signed-off-by: supriya karanth Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/44999 Reviewed-by: QATOOLS Reviewed-by: Praveena NADAHALLY Reviewed-by: QABUILD Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index c57234d92be..1d38576a8f4 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -21,6 +21,7 @@ #include #include #include +#include /* AB5500 USB macros */ @@ -46,6 +47,10 @@ #define AB5500_USB_LINK_STATUS_MASK_V2 0xF8 #define USB_PROBE_DELAY 1000 /* 1 seconds */ +#define USB_LIMIT (200) /* If we have more than 200 irqs per second */ + +static struct pm_qos_request_list usb_pm_qos_latency; +static bool usb_pm_qos_is_latency_0; #define PUBLIC_ID_BACKUPRAM1 (U5500_BACKUPRAM1_BASE + 0x0FC0) #define MAX_USB_SERIAL_NUMBER_LEN 31 @@ -145,6 +150,42 @@ static void ab5500_usb_wd_workaround(struct ab5500_usb *ab) udelay(AB5500_WATCHDOG_DELAY_US); } +static void ab5500_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 ab5500_usb *ab = container_of(work_usb_workaround, + struct ab5500_usb, work_usb_workaround); + + for_each_online_cpu(cpu) + num_irqs += kstat_irqs_cpu(IRQ_DB5500_USBOTG, cpu); + + if ((num_irqs > old_num_irqs) && + (num_irqs - old_num_irqs) > USB_LIMIT) { + + if (!usb_pm_qos_is_latency_0) { + + pm_qos_add_request(&usb_pm_qos_latency, + PM_QOS_CPU_DMA_LATENCY, 0); + usb_pm_qos_is_latency_0 = true; + } + } else { + + if (usb_pm_qos_is_latency_0) { + + pm_qos_remove_request(&usb_pm_qos_latency); + usb_pm_qos_is_latency_0 = false; + } + } + old_num_irqs = num_irqs; + + schedule_delayed_work_on(0, + &ab->work_usb_workaround, + msecs_to_jiffies(USB_PROBE_DELAY)); +} + static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) { u8 bit; @@ -166,6 +207,11 @@ static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) } ux500_restore_context(); + 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, @@ -191,6 +237,15 @@ static void ab5500_usb_phy_disable(struct ab5500_usb *ab, bool sel_host) clk_disable(ab->sysclk); regulator_disable(ab->v_ape); ab->usb_gpio->disable(); + + if (sel_host) { + if (usb_pm_qos_is_latency_0) { + + pm_qos_remove_request(&usb_pm_qos_latency); + usb_pm_qos_is_latency_0 = false; + } + cancel_delayed_work_sync(&ab->work_usb_workaround); + } } #define ab5500_usb_peri_phy_en(ab) ab5500_usb_phy_enable(ab, false) @@ -724,6 +779,9 @@ static int __devinit ab5500_usb_probe(struct platform_device *pdev) */ INIT_DELAYED_WORK(&ab->dwork, ab5500_usb_delayed_work); + INIT_DELAYED_WORK_DEFERRABLE(&ab->work_usb_workaround, + ab5500_usb_load); + err = otg_set_transceiver(&ab->otg); if (err) dev_err(&pdev->dev, "Can't register transceiver\n"); -- cgit v1.2.3 From fe1dfffb67f528bccf0fb5eda7638e08d068f6eb Mon Sep 17 00:00:00 2001 From: Ravikant Singh Date: Wed, 18 Jan 2012 16:42:01 +0530 Subject: u5500: usb: AB5500 USB correct initialisation U5500 USB intialisation sequence updated as per the AB HW requirement It is taken care for : 1. Usb device cable plugin - plugout usecase (with cable plugin before and after target boot) 2. Usb host cable plugin - plugout usecase (with cable plugin before and after target boot) 3. Usb dedicated charger plugin - plugout usecase (with charger plugin before and after target boot) For AB5500 usb phy is to be enabled by setting the USB Chip Select (CS) gpio pin as 1 and usb phy is to be disabled by setting the USB Chip Select (CS) gpio pin as 0. For cable/charger plugin after target boot ========================================== Sequence for 1.Usb device cable plugin - plugout usecase - on cable plugin, linkstatus interrupt = 1 - enable usb phy - on cable plugout, link status interrupt = 16 - disable usb phy - linkstatus interrupt = 0 Sequence for 2. Usb host cable plugin - plugout usecase (with - on cable plugin, linkstatus interrupt = 18 - enable usb phy - link status interrupt = 13 -> host mode enable done - on cable plugout, link status interrupt= 17 - disable usb phy - linkstatus interrupt = 0 Sequence for 3. Usb dedicated charger plugin - plugout usecase - on charger plugin, linkstatus interrupt = 7 - on charger plugout, link status interrupt= 0 For cable/charger plugin before target boot ========================================== Sequence for 1.Usb device cable plugin - plugout usecase - on target boot,in boot detect function read linkstatus = 1 - enable usb phy - on cable plugout, link status interrupt = 16 - disable usb phy - linkstatus interrupt = 0 Sequence for 2. Usb host cable plugin - plugout usecase (with - on target boot,in boot detect function read linkstatus = 18 - enable usb phy - link status interrupt = 13 -> host mode enable done - on cable plugout, link status interrupt= 17 - disable usb phy - linkstatus interrupt = 0 Sequence for 3. Usb dedicated charger plugin - plugout usecase - on target boot,in boot detect function read linkstatus = 7 - on charger plugout, link status interrupt= 0 ST-Ericsson ID: 410872 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I4e50ca6041ea645aa878f72d55694143449490a1 Signed-off-by: Ravikant Singh Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/45674 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Supriya s KARANTH Tested-by: Supriya s KARANTH Reviewed-by: Praveena NADAHALLY Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab5500-usb.c | 240 ++++++------------------------------------- 1 file changed, 30 insertions(+), 210 deletions(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index 1d38576a8f4..ae2c2127598 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -2,6 +2,8 @@ * Copyright (C) ST-Ericsson SA 2011 * * Author: Avinash Kumar for ST-Ericsson + * Author: Ravi Kant SINGH for ST-Ericsson + * Author: Supriya s KARANTH for ST-Ericsson * License terms: GNU General Public License (GPL) version 2 */ @@ -25,8 +27,6 @@ /* AB5500 USB macros */ -#define AB5500_USB_HOST_ENABLE 0x1 -#define AB5500_USB_DEVICE_ENABLE 0x2 #define AB5500_MAIN_WATCHDOG_ENABLE 0x1 #define AB5500_MAIN_WATCHDOG_KICK 0x2 #define AB5500_MAIN_WATCHDOG_DISABLE 0x0 @@ -56,7 +56,7 @@ static bool usb_pm_qos_is_latency_0; #define MAX_USB_SERIAL_NUMBER_LEN 31 /* UsbLineStatus register - usb types */ -enum ab8500_usb_link_status { +enum ab5500_usb_link_status { USB_LINK_NOT_CONFIGURED, USB_LINK_STD_HOST_NC, USB_LINK_STD_HOST_C_NS, @@ -73,7 +73,9 @@ enum ab8500_usb_link_status { USB_LINK_HM_IDGND, USB_LINK_OTG_HOST_NO_CURRENT, USB_LINK_NOT_VALID_LINK, - USB_LINK_HM_IDGND_V2 = 18, + USB_LINK_PHY_EN_NO_VBUS_NO_IDGND, + USB_LINK_STD_UPSTREAM_NO_VBUS_NO_IDGND, + USB_LINK_HM_IDGND_V2 }; /** @@ -114,6 +116,7 @@ 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 void ab5500_usb_phy_disable(struct ab5500_usb *ab, bool sel_host); static inline struct ab5500_usb *xceiv_to_ab(struct otg_transceiver *x) { @@ -188,55 +191,44 @@ static void ab5500_usb_load(struct work_struct *work) static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) { - u8 bit; + int ret = 0; /* 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; 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)); - } - ux500_restore_context(); + ret = gpio_direction_output(ab->usb_cs_gpio, 0); + if (ret < 0) { + dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); + gpio_free(ab->usb_cs_gpio); + return; + } + gpio_set_value(ab->usb_cs_gpio, 1); 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); } 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_mask_and_set_register_interruptible(ab->dev, - AB5500_BANK_USB, - AB5500_USB_PHY_CTRL_REG, - bit, 0); /* Needed to disable the phy.*/ ab5500_usb_wd_workaround(ab); clk_disable(ab->sysclk); regulator_disable(ab->v_ape); ab->usb_gpio->disable(); + gpio_set_value(ab->usb_cs_gpio, 0); if (sel_host) { if (usb_pm_qos_is_latency_0) { @@ -257,9 +249,7 @@ static void ab5500_usb_phy_disable(struct ab5500_usb *ab, bool sel_host) 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 ab5500_usb_link_status lsts; enum usb_xceiv_events event = USB_EVENT_NONE; (void)abx500_get_register_interruptible(ab->dev, @@ -283,49 +273,41 @@ static int ab5500_usb_link_status_update(struct ab5500_usb *ab) ab5500_usb_peri_phy_en(ab); break; + case USB_LINK_DEDICATED_CHG: + /* TODO: vbus_draw */ + event = USB_EVENT_CHARGER; + break; case USB_LINK_HM_IDGND: if (ab->rev >= AB5500_2_0) return -1; - /* 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); ab->otg.default_a = true; event = USB_EVENT_ID; + break; + case USB_LINK_PHY_EN_NO_VBUS_NO_IDGND: + ab5500_usb_peri_phy_dis(ab); + + break; + case USB_LINK_STD_UPSTREAM_NO_VBUS_NO_IDGND: + ab5500_usb_host_phy_dis(ab); + break; case USB_LINK_HM_IDGND_V2: if (!(ab->rev >= AB5500_2_0)) return -1; - /* 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); ab->otg.default_a = true; event = USB_EVENT_ID; - break; - case USB_LINK_DEDICATED_CHG: - /* TODO: vbus_draw */ - event = USB_EVENT_CHARGER; break; default: break; @@ -356,66 +338,11 @@ static irqreturn_t ab5500_usb_link_status_irq(int irq, void *data) 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; - - enum usb_xceiv_events event; - - ab->mode = USB_DEVICE; - - /* 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"); - 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 irqreturn_t 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_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); } @@ -435,31 +362,6 @@ static int ab5500_usb_irq_setup(struct platform_device *pdev, 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) { @@ -481,42 +383,6 @@ static int ab5500_usb_irq_setup(struct platform_device *pdev, 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; @@ -582,40 +448,11 @@ static int ab5500_create_sysfsentries(struct ab5500_usb *ab) */ 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; + enum ab5500_usb_link_status lsts; if (!ab->dev) return -EINVAL; - 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_mask_and_set_register_interruptible(ab->dev, - AB5500_BANK_USB, - AB5500_USB_PHY_CTRL_REG, - AB5500_USB_DEVICE_ENABLE, 0); - - 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_mask_and_set_register_interruptible(ab->dev, - AB5500_BANK_USB, - AB5500_USB_PHY_CTRL_REG, - AB5500_USB_HOST_ENABLE, 0); - (void)abx500_get_register_interruptible(ab->dev, AB5500_BANK_USB, AB5500_USB_LINE_STAT_REG, &usb_status); @@ -645,27 +482,10 @@ static int ab5500_usb_boot_detect(struct ab5500_usb *ab) } 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; -- cgit v1.2.3 From 395aea0fb7e8317b35530551cbb03d9e2fc962b7 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 17 Jan 2012 19:31:16 +0530 Subject: Ux500:USB:Adding new otg transceiver events Adding two new events to handle the CPU idle. USB_EVENT_PREPARE would restore the context and make the MUSB ready for enumeration of a new device. USB_EVENT_CLEAN would remove the clocks and handle the USB state machine when the cable is removed ST-Ericsson Linux next: NA ST-Ericsson ID: 373930 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I12c6c16567a460981cedf40192bc321889f3fe05 Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/45730 Reviewed-by: Praveena NADAHALLY --- include/linux/usb/otg.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index c3b77fcdce7..3583bd09d38 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -44,6 +44,8 @@ enum usb_phy_events { USB_EVENT_RIDA, USB_EVENT_RIDB, USB_EVENT_RIDC, + USB_EVENT_PREPARE, /* restore context and clocks */ + USB_EVENT_CLEAN, /* disable clocks */ }; struct usb_phy; -- cgit v1.2.3 From 30600535dfe60c8092d799fdfa3fc16f47393861 Mon Sep 17 00:00:00 2001 From: Jonas Aberg Date: Tue, 24 Jan 2012 11:08:39 +0530 Subject: u8500: musb: Add pm runtime support Add pm runtime support for musb, including both pin and clock handling. ST-Ericsson Linux next: - ST-Ericsson ID: 370128, 375498 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Idf72a6f226d1309d5a13b358e653ee97469e5ae6 Signed-off-by: Jonas Aaberg Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/44709 Reviewed-by: Srinidhi KASAGAR --- arch/arm/mach-ux500/board-mop500.c | 2 - arch/arm/mach-ux500/include/mach/usb.h | 6 +- arch/arm/mach-ux500/usb.c | 4 ++ drivers/usb/musb/musb_core.c | 6 +- drivers/usb/musb/ux500.c | 117 ++++++++++++++++++++++++++------- drivers/usb/otg/ab8500-usb.c | 35 ++++------ 6 files changed, 119 insertions(+), 51 deletions(-) diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 5c1da28427b..77d03c1fbd0 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -53,7 +53,6 @@ #include "devices-db8500.h" #include "board-mop500.h" #include "board-mop500-regulators.h" -#include "board-ux500-usb.h" static struct gpio_led snowball_led_array[] = { { @@ -195,7 +194,6 @@ static struct ab8500_platform_data ab8500_platdata = { .regulator = ab8500_regulators, .num_regulator = ARRAY_SIZE(ab8500_regulators), .gpio = &ab8500_gpio_pdata, - .usb = &abx500_usbgpio_plat_data, }; static struct resource ab8500_resources[] = { diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h index 2d1e54070f2..700d9dbb1be 100644 --- a/arch/arm/mach-ux500/include/mach/usb.h +++ b/arch/arm/mach-ux500/include/mach/usb.h @@ -12,6 +12,8 @@ #define UX500_MUSB_DMA_NUM_RX_CHANNELS 8 #define UX500_MUSB_DMA_NUM_TX_CHANNELS 8 +struct musb; + struct ux500_musb_board_data { void **dma_rx_param_array; void **dma_tx_param_array; @@ -23,6 +25,7 @@ struct ux500_musb_board_data { void ux500_add_usb(struct device *parent, resource_size_t base, int irq, int *dma_rx_cfg, int *dma_tx_cfg); +/* Only used for u5500 */ struct abx500_usbgpio_platform_data { int (*get)(struct device *device); void (*enable)(void); @@ -30,6 +33,5 @@ struct abx500_usbgpio_platform_data { void (*put)(void); int usb_cs; }; - -void ux500_restore_context(void); +void ux500_restore_context(struct musb *musb); #endif diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index ca84e040e99..fb1f6775154 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "pins.h" #include "board-ux500-usb.h" @@ -170,6 +171,9 @@ struct platform_device ux500_musb_device = { .platform_data = &musb_platform_data, .dma_mask = &ux500_musb_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), +#ifdef CONFIG_UX500_SOC_DB8500 + .pm_domain = &ux500_dev_power_domain, +#endif }, .num_resources = ARRAY_SIZE(usb_resources), .resource = usb_resources, diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 5faac98ca30..c5bf28afd86 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2371,8 +2371,12 @@ static const struct dev_pm_ops musb_dev_pm_ops = { .runtime_suspend = musb_runtime_suspend, .runtime_resume = musb_runtime_resume, }; - +#ifdef CONFIG_UX500_SOC_DB8500 +#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) +#else #define MUSB_DEV_PM_OPS NULL +#endif + #else #define MUSB_DEV_PM_OPS NULL #endif diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index ae6be2eaa09..5d0c5eda128 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include "musb_core.h" @@ -40,19 +42,23 @@ struct ux500_glue { #define glue_to_musb(g) platform_get_drvdata(g->musb) static struct timer_list notify_timer; -struct musb_context_registers context; +static struct musb_context_registers context; +static bool context_stored; struct musb *_musb; -void ux500_store_context(struct musb *musb) + +static void ux500_store_context(struct musb *musb) { #ifdef CONFIG_PM int i; void __iomem *musb_base; void __iomem *epio; - if (musb != NULL) - _musb = musb; - else - return; + if (cpu_is_u5500()) { + if (musb != NULL) + _musb = musb; + else + return; + } musb_base = musb->mregs; @@ -124,17 +130,21 @@ void ux500_store_context(struct musb *musb) musb_read_rxhubport(musb_base, i); } } + context_stored = true; #endif } -void ux500_restore_context(void) + +void ux500_restore_context(struct musb *musb) { #ifdef CONFIG_PM int i; - struct musb *musb; void __iomem *musb_base; void __iomem *ep_target_regs; void __iomem *epio; + if (!context_stored) + return; + if (_musb != NULL) musb = _musb; else @@ -222,7 +232,8 @@ static void musb_notify_idle(unsigned long _musb) unsigned long flags; u8 devctl; - + dev_dbg(musb->controller, "musb_notify_idle %s", + otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); @@ -235,6 +246,10 @@ static void musb_notify_idle(unsigned long _musb) musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } + if (cpu_is_u8500()) { + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); + } break; case OTG_STATE_A_SUSPEND: @@ -250,7 +265,14 @@ static int musb_otg_notifications(struct notifier_block *nb, { struct musb *musb = container_of(nb, struct musb, nb); + dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n", + event, otg_state_string(musb->xceiv->state)); switch (event) { + + case USB_EVENT_PREPARE: + pm_runtime_get_sync(musb->controller); + ux500_restore_context(musb); + break; case USB_EVENT_ID: case USB_EVENT_RIDA: dev_dbg(musb->controller, "ID GND\n"); @@ -263,12 +285,17 @@ static int musb_otg_notifications(struct notifier_block *nb, dev_dbg(musb->controller, "VBUS Connect\n"); break; - +/* case USB_EVENT_RIDB: FIXME, not yet managed */ case USB_EVENT_NONE: dev_dbg(musb->controller, "VBUS Disconnect\n"); - if (is_otg_enabled(musb)) + if (is_otg_enabled(musb) && musb->is_host) ux500_musb_set_vbus(musb, 0); - + else + musb->xceiv->state = OTG_STATE_B_IDLE; + break; + case USB_EVENT_CLEAN: + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); break; default: dev_dbg(musb->controller, "ID float\n"); @@ -321,11 +348,9 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) /* 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); @@ -400,12 +425,13 @@ static struct usb_ep *ux500_musb_configure_endpoints(struct musb *musb, static int ux500_musb_init(struct musb *musb) { int status; + musb->xceiv = usb_get_transceiver(); if (!musb->xceiv) { pr_err("HS USB OTG: no transceiver configured\n"); return -ENODEV; } - + pm_runtime_get_noresume(musb->controller); musb->nb.notifier_call = musb_otg_notifications; status = otg_register_notifier(musb->xceiv, &musb->nb); @@ -418,6 +444,7 @@ static int ux500_musb_init(struct musb *musb) return 0; err1: + pm_runtime_disable(musb->controller); return status; } @@ -516,12 +543,12 @@ static int __devinit ux500_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register musb device\n"); goto err4; } + pm_runtime_enable(&pdev->dev); return 0; - err4: - clk_disable(clk); - + if (cpu_is_u5500()) + clk_disable(clk); err3: clk_put(clk); @@ -541,8 +568,12 @@ static int __devexit ux500_remove(struct platform_device *pdev) platform_device_del(glue->musb); platform_device_put(glue->musb); - clk_disable(glue->clk); + if (cpu_is_u5500()) + clk_disable(glue->clk); clk_put(glue->clk); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + kfree(glue); return 0; @@ -562,8 +593,15 @@ static int ux500_suspend(struct device *dev) struct musb *musb = glue_to_musb(glue); usb_phy_set_suspend(musb->xceiv, 1); - clk_disable(glue->clk); + if (cpu_is_u5500()) + /* + * Since this clock is in the APE domain, it will + * automatically be disabled on suspend. + * (And enabled on resume automatically.) + */ + clk_disable(glue->clk); + dev_dbg(dev, "ux500_suspend\n"); return 0; } @@ -578,20 +616,51 @@ static int ux500_resume(struct device *dev) { struct ux500_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); - int ret; + + if (cpu_is_u5500()) + /* No point in propagating errors on resume */ + (void) clk_enable(glue->clk); + dev_dbg(dev, "ux500_resume\n"); + + usb_phy_set_suspend(musb->xceiv, 0); + + return 0; +} +#ifdef CONFIG_UX500_SOC_DB8500 +static int ux500_musb_runtime_resume(struct device *dev) +{ + struct ux500_glue *glue = dev_get_drvdata(dev); + int ret; + + if (cpu_is_u5500()) + return 0; ret = clk_enable(glue->clk); if (ret) { - dev_err(dev, "failed to enable clock\n"); + dev_dbg(dev, "Unable to enable clk\n"); return ret; } + dev_dbg(dev, "ux500_musb_runtime_resume\n"); + return 0; +} - usb_phy_set_suspend(musb->xceiv, 0); +static int ux500_musb_runtime_suspend(struct device *dev) +{ + struct ux500_glue *glue = dev_get_drvdata(dev); + if (cpu_is_u5500()) + return 0; + + clk_disable(glue->clk); + dev_dbg(dev, "ux500_musb_runtime_suspend\n"); return 0; } - +#endif static const struct dev_pm_ops ux500_pm_ops = { +#ifdef CONFIG_UX500_SOC_DB8500 + SET_RUNTIME_PM_OPS(ux500_musb_runtime_suspend, + ux500_musb_runtime_resume, NULL) +#endif .suspend = ux500_suspend, .resume = ux500_resume, }; diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 5c5b6a9dcdb..659fca15976 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -29,19 +29,15 @@ #include #include #include +#include #include #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 @@ -126,7 +122,6 @@ struct ab8500_usb { struct regulator *v_ape; struct regulator *v_musb; struct regulator *v_ulpi; - struct abx500_usbgpio_platform_data *usb_gpio; struct delayed_work work_usb_workaround; bool sysfs_flag; }; @@ -245,7 +240,6 @@ 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); @@ -299,8 +293,6 @@ 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_update_requirement(PRCMU_QOS_APE_OPP, (char *)dev_name(ab->dev), 50); @@ -360,12 +352,16 @@ 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(); + atomic_notifier_call_chain(&ab->otg.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); ab8500_usb_peri_phy_en(ab); } if (ab->mode == USB_IDLE) { ab->mode = USB_PERIPHERAL; - ux500_restore_context(); + atomic_notifier_call_chain(&ab->otg.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); ab8500_usb_peri_phy_en(ab); } if (event != USB_EVENT_RIDC) @@ -378,12 +374,16 @@ 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(); + atomic_notifier_call_chain(&ab->otg.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); ab8500_usb_host_phy_en(ab); } if (ab->mode == USB_IDLE) { ab->mode = USB_HOST; - ux500_restore_context(); + atomic_notifier_call_chain(&ab->otg.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); ab8500_usb_host_phy_en(ab); } ab->phy.otg->default_a = true; @@ -794,8 +794,6 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) { struct ab8500_usb *ab; struct usb_otg *otg; - struct ab8500_platform_data *ab8500_pdata = - dev_get_platdata(pdev->dev.parent); int err; int rev; int ret = -1; @@ -831,7 +829,6 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) otg->phy = &ab->phy; otg->set_host = ab8500_usb_set_host; otg->set_peripheral = ab8500_usb_set_peripheral; - ab->usb_gpio = ab8500_pdata->usb; ab->sysfs_flag = true; platform_set_drvdata(pdev, ab); @@ -917,10 +914,6 @@ 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); dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", ab->rev); @@ -969,8 +962,6 @@ 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->phy.otg); -- cgit v1.2.3 From deb13f80a02e4a0d5e6e03950a743d7325ae6ef1 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 24 Jan 2012 11:19:19 +0530 Subject: u8500:USB:Notifying DB using new xcieve events Platform specific changes for runtime powermanagement. Using two new events to notify the DB driver to enable/disable clock and to restore the context. ST-Ericsson Linux next: NA ST-Ericsson ID: 373930 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: If3b236b92a47f8778321b4464b0ad84f98471414 Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/44619 Reviewed-by: Srinidhi KASAGAR --- drivers/usb/otg/ab8500-usb.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 659fca15976..355dfc55ffb 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -322,6 +322,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) lsts = (reg >> 3) & 0x0F; + dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts); if (!(ab->sysfs_flag)) { switch (lsts) { case USB_LINK_ACA_RID_B: @@ -329,10 +330,10 @@ 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: - if (ab->mode == USB_HOST) - ab8500_usb_host_phy_dis(ab); - else if (ab->mode == USB_PERIPHERAL) - ab8500_usb_peri_phy_dis(ab); + if (ab->mode == USB_PERIPHERAL) + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_CLEAN, + &ab->vbus_draw); ab->mode = USB_IDLE; ab->phy.otg.default_a = false; ab->vbus_draw = 0; @@ -352,14 +353,14 @@ 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); - atomic_notifier_call_chain(&ab->otg.notifier, + atomic_notifier_call_chain(&ab->phy.notifier, USB_EVENT_PREPARE, &ab->vbus_draw); ab8500_usb_peri_phy_en(ab); } if (ab->mode == USB_IDLE) { ab->mode = USB_PERIPHERAL; - atomic_notifier_call_chain(&ab->otg.notifier, + atomic_notifier_call_chain(&ab->phy.notifier, USB_EVENT_PREPARE, &ab->vbus_draw); ab8500_usb_peri_phy_en(ab); @@ -374,14 +375,14 @@ 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); - atomic_notifier_call_chain(&ab->otg.notifier, + atomic_notifier_call_chain(&ab->phy.notifier, USB_EVENT_PREPARE, &ab->vbus_draw); ab8500_usb_host_phy_en(ab); } if (ab->mode == USB_IDLE) { ab->mode = USB_HOST; - atomic_notifier_call_chain(&ab->otg.notifier, + atomic_notifier_call_chain(&ab->phy.notifier, USB_EVENT_PREPARE, &ab->vbus_draw); ab8500_usb_host_phy_en(ab); @@ -389,16 +390,20 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab) ab->phy.otg->default_a = true; if (event != USB_EVENT_RIDA) event = USB_EVENT_ID; + atomic_notifier_call_chain(&ab->phy.notifier, + event, + &ab->vbus_draw); break; case USB_LINK_DEDICATED_CHG: /* TODO: vbus_draw */ ab->mode = USB_DEDICATED_CHG; event = USB_EVENT_CHARGER; + atomic_notifier_call_chain(&ab->phy.notifier, + event, + &ab->vbus_draw); break; } - atomic_notifier_call_chain(&ab->phy.notifier, event, - &ab->vbus_draw); } return 0; @@ -415,20 +420,22 @@ static void ab8500_usb_delayed_work(struct work_struct *work) static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; - enum usb_xceiv_events event; + enum usb_xceiv_events event = USB_EVENT_NONE; /* Link status will not be updated till phy is disabled. */ if (ab->mode == USB_HOST) { - event = USB_EVENT_NONE; ab->otg.default_a = false; ab->vbus_draw = 0; atomic_notifier_call_chain(&ab->otg.notifier, event, &ab->vbus_draw); ab8500_usb_host_phy_dis(ab); } - else if (ab->mode == USB_PERIPHERAL) + if (ab->mode == USB_PERIPHERAL) { + atomic_notifier_call_chain(&ab->phy.notifier, + event, &ab->vbus_draw); ab8500_usb_peri_phy_dis(ab); - else if (ab->mode == USB_DEDICATED_CHG && ab->rev == 0x20) { + } + 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, @@ -436,7 +443,6 @@ static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) AB8500_BIT_PHY_CTRL_DEVICE_EN, 0); } - ab->mode = USB_IDLE; return IRQ_HANDLED; } -- cgit v1.2.3 From 23e602604281f9bbf80a5b0d87f7c826e3c6a9de Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Tue, 17 Jan 2012 19:55:42 +0530 Subject: Ux500:USB:Handling Host state machine Host state machine is being updated at the time of switching off the vbus.It should be handled as part of timer call back from the Disconnect interrupt. ST-Ericsson Linux next: NA ST-Ericsson ID: 373930 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I0a7d35591edcc8e42d4c35f714c76b6f751d932e Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/45731 Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/ux500.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 5d0c5eda128..77454c6ead2 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -349,7 +349,6 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) * 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); } -- cgit v1.2.3 From fc38da7233c9a91e2a3bbf30115b31ad1c8bbd75 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Thu, 5 Jan 2012 20:00:48 +0530 Subject: u8500:USB:Spurious Session Request Interrupts On 8500 we get spurious session request interrupts when the DUT is in B-device.We need to ignore the interrupts when DUT is in B-device. Hence ignoring the interrupt. ST-Ericsson Linux next: NA ST-Ericsson ID: 373930 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I8899d37b22f4db4532e3987fce09230f1643f4a6 Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/44621 Reviewed-by: Srinidhi KASAGAR --- drivers/usb/musb/musb_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index c5bf28afd86..840afb3b8a0 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -520,9 +520,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, /* see manual for the order of the tests */ if (int_usb & MUSB_INTR_SESSREQ) { void __iomem *mbase = musb->mregs; - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS - && (devctl & MUSB_DEVCTL_BDEVICE)) { + || (devctl & MUSB_DEVCTL_BDEVICE)) { dev_dbg(musb->controller, "SessReq while on B state\n"); return IRQ_HANDLED; } -- cgit v1.2.3 From c25e434e1c5495d75747d0021ca9b1dadefdda88 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Wed, 25 Jan 2012 16:55:23 +0530 Subject: ux500:USB: Use proper musb structure for 8500 On 8500 _musb is always NULL hence it will not restore the context._musb is required only on 5500 and hence adding a 5500 check ST-Ericsson Linux next: NA ST-Ericsson ID: 373930 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ic806d6983c97e632188a6ff568efe67bb86b1baa Signed-off-by: Sakethram Bommisetti Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/46486 Reviewed-by: Praveena NADAHALLY Reviewed-by: Jonas ABERG Reviewed-by: Rabin VINCENT --- drivers/usb/musb/ux500.c | 10 ++++++---- drivers/usb/otg/ab5500-usb.c | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 77454c6ead2..fe322cf541c 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -145,10 +145,12 @@ void ux500_restore_context(struct musb *musb) if (!context_stored) return; - if (_musb != NULL) - musb = _musb; - else - return; + if (cpu_is_u5500()) { + if (_musb != NULL) + musb = _musb; + else + return; + } musb_base = musb->mregs; if (is_host_enabled(musb)) { diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index ae2c2127598..d37529f7f0a 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -201,7 +201,8 @@ static void ab5500_usb_phy_enable(struct ab5500_usb *ab, bool sel_host) clk_enable(ab->sysclk); regulator_enable(ab->v_ape); - ux500_restore_context(); + /* TODO: Remove ux500_resotore_context and handle similar to ab8500 */ + ux500_restore_context(NULL); ret = gpio_direction_output(ab->usb_cs_gpio, 0); if (ret < 0) { dev_err(ab->dev, "usb_cs_gpio: gpio direction failed\n"); -- cgit v1.2.3 From c72b95939fcd6b09dad197c1dd63965be2f23ac0 Mon Sep 17 00:00:00 2001 From: rajaram Date: Thu, 16 Feb 2012 18:46:34 +0530 Subject: usb:mass storage: Allow caching during write commands In the new kernel, mass storage driver disables caching by setting FUA bit in write10 command. This feature is made configurable through DEVATTR nofua. To improve performance we are enabling caching by setting nofua bit T-Ericsson ID: 413786 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: rajaram Change-Id: Ieed0205965c2abcd71542ef924d09d0d1b9809c4 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/49235 Tested-by: Rajaram REGUPATHY Reviewed-by: Srinidhi KASAGAR --- drivers/usb/gadget/f_mass_storage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index cb8c162cae5..8473424e31f 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2786,6 +2786,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) { curlun->cdrom = !!lcfg->cdrom; curlun->ro = lcfg->cdrom || lcfg->ro; + curlun->nofua = 1; curlun->initially_ro = curlun->ro; curlun->removable = lcfg->removable; curlun->dev.release = fsg_lun_release; -- cgit v1.2.3 From 8bf2cb67f4a2b543294a3cdef05bb8e84ad0bc79 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Tue, 14 Feb 2012 11:06:51 +0100 Subject: ab8500: usb: Update check for old AB8500 HW ST-Ericsson ID: 366316 ST-Ericsson Linux next: - ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I3c93a20d024201f8e09809a1dc770765ee480f4c Signed-off-by: Bengt Jonsson Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/49033 Reviewed-by: QABUILD Reviewed-by: QATEST Reviewed-by: Rabin VINCENT --- drivers/usb/otg/ab8500-usb.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 355dfc55ffb..a698165135e 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -107,6 +107,7 @@ enum ab8500_usb_mode { struct ab8500_usb { struct usb_phy phy; struct device *dev; + struct ab8500 *ab8500; int irq_num_id_rise; int irq_num_id_fall; int irq_num_vbus_rise; @@ -116,7 +117,6 @@ struct ab8500_usb { struct delayed_work dwork; 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; @@ -146,7 +146,7 @@ static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) (AB8500_BIT_WD_CTRL_ENABLE | AB8500_BIT_WD_CTRL_KICK)); - if (ab->rev > 0x10) /* v2.0 v3.0 */ + if (!is_ab8500_1p0_or_earlier(ab->ab8500)) udelay(AB8500_WD_V11_DISABLE_DELAY_US); abx500_set_register_interruptible(ab->dev, @@ -203,7 +203,7 @@ static void ab8500_usb_regulator_ctrl(struct ab8500_usb *ab, bool sel_host, if (enable) { regulator_enable(ab->v_ape); - if (ab->rev >= 0x30) { + if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000); if (ret < 0) @@ -217,7 +217,7 @@ static void ab8500_usb_regulator_ctrl(struct ab8500_usb *ab, bool sel_host, } regulator_enable(ab->v_ulpi); - if (ab->rev >= 0x30) { + if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { volt = regulator_get_voltage(ab->v_ulpi); if ((volt != 1300000) && (volt != 1350000)) dev_err(ab->dev, "Vintcore is not" @@ -261,8 +261,8 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab,u8 bit) { - /* Wrokaround for v2.0 bug # 31952 */ - if (ab->rev == 0x20) { + /* Workaround for v2.0 bug # 31952 */ + if (is_ab8500_2p0(ab->ab8500)) { abx500_mask_and_set_register_interruptible(ab->dev, AB8500_USB, AB8500_USB_PHY_CTRL_REG, @@ -435,13 +435,15 @@ static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) event, &ab->vbus_draw); ab8500_usb_peri_phy_dis(ab); } - 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, + if (is_ab8500_2p0(ab->ab8500)) { + if (ab->mode == USB_DEDICATED_CHG) { + 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); + } } return IRQ_HANDLED; @@ -475,8 +477,9 @@ static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) * than 100mA from VBUS.So setting charging current * to 100mA in case of standard host */ - if ((ab->rev < 0x30) && (mA > 100)) - mA = 100; + if (is_ab8500_2p0_or_earlier(ab->ab8500)) + if (mA > 100) + mA = 100; return mA; } @@ -659,7 +662,7 @@ static int ab8500_usb_irq_setup(struct platform_device *pdev, int err; int irq; - if (ab->rev > 0x10) { /* 0x20 0x30 */ + if (!is_ab8500_1p0_or_earlier(ab->ab8500)) { irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS"); if (irq < 0) { err = irq; @@ -799,16 +802,16 @@ static int ab8500_create_sysfsentries(struct ab8500_usb *ab) static int __devinit ab8500_usb_probe(struct platform_device *pdev) { struct ab8500_usb *ab; + struct ab8500 *ab8500; struct usb_otg *otg; int err; int rev; int ret = -1; + ab8500 = dev_get_drvdata(pdev->dev.parent); rev = abx500_get_chip_id(&pdev->dev); - if (rev < 0) { - dev_err(&pdev->dev, "Chip id read failed\n"); - return rev; - } else if (rev < 0x20) { + + if (is_ab8500_1p1_or_earlier(ab8500)) { dev_err(&pdev->dev, "Unsupported AB8500 chip rev=%d\n", rev); return -ENODEV; } @@ -824,7 +827,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) } ab->dev = &pdev->dev; - ab->rev = rev; + ab->ab8500 = ab8500; ab->phy.dev = ab->dev; ab->phy.otg = otg; ab->phy.label = "ab8500"; @@ -872,7 +875,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) } /* Write Phy tuning values */ - if (ab->rev >= 0x30) { + if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { /* Enable the PBT/Bank 0x12 access */ ret = abx500_set_register_interruptible(ab->dev, AB8500_DEVELOPMENT, @@ -922,7 +925,7 @@ 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); + dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev); prcmu_qos_add_requirement(PRCMU_QOS_ARM_OPP, "usb", 25); -- cgit v1.2.3 From bdb74d8442ca934d2a06a35379cd5315d76c7888 Mon Sep 17 00:00:00 2001 From: Avinash Kumar Date: Mon, 13 Feb 2012 18:48:47 +0530 Subject: USB: core: OTG Supplement Revision 2.0 updates OTG supplement revision 2.0 spec introduces Attach Detection Protocol (ADP) for detecting peripheral connection without applying power on VBUS. ADP is optional and is included in the OTG descriptor along with SRP and HNP. HNP polling is introduced for peripheral to notify its wish to become host. Host polls (GET_STATUS on DEVICE) peripheral for host_request and suspend the bus when peripheral returns host_request TRUE. The spec insists the polling frequency to be in 1-2 sec range and bus should be suspended with in 2 sec from host_request is set. a_alt_hnp_support feature is obsolete and a_hnp_support feature is limited to only legacy OTG B-device. The newly introduced bcdOTG field in the OTG descriptor is used for identifying the 2.0 compliant B-device. ST-Ericsson ID: 401192 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: I01ea82656e3ea0302613562354521ed4fae5ac5e Signed-off-by: Pavankumar Kondeti Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/48747 Reviewed-by: Praveena NADAHALLY Reviewed-by: QATOOLS Reviewed-by: QABUILD --- drivers/usb/core/driver.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/hcd.c | 3 +++ drivers/usb/core/hub.c | 47 ++++++++++++++++++++++++++++++++++++-------- drivers/usb/core/usb.h | 4 +++- include/linux/usb.h | 4 ++++ include/linux/usb/ch9.h | 12 ++++++++++-- 6 files changed, 109 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 9a56635dc19..b3948206024 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1211,6 +1211,19 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) * and flush any outstanding URBs. */ } else { +#ifdef CONFIG_USB_OTG + /* According to OTG supplement Rev 2.0 section 6.3 + * Unless an A-device enables b_hnp_enable before entering + * suspend it shall also continue polling while the bus is + * suspended. + * + * We don't have to perform HNP polling, as we are going to + * enable b_hnp_enable before suspending. + */ + if (udev->bus->hnp_support && + udev->portnum == udev->bus->otg_port) + cancel_delayed_work(&udev->bus->hnp_polling); +#endif udev->can_submit = 0; for (i = 0; i < 16; ++i) { usb_hcd_flush_endpoint(udev, udev->ep_out[i]); @@ -1274,6 +1287,43 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) return status; } +#ifdef CONFIG_USB_OTG +void usb_hnp_polling_work(struct work_struct *work) +{ + int ret; + struct usb_bus *bus = + container_of(work, struct usb_bus, hnp_polling.work); + struct usb_device *udev = bus->root_hub->children[bus->otg_port - 1]; + u8 *status = kmalloc(sizeof(*status), GFP_KERNEL); + + if (!status) + return; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE, + 0, OTG_STATUS_SELECTOR, status, sizeof(*status), + USB_CTRL_GET_TIMEOUT); + if (ret < 0) { + /* Peripheral may not be supporting HNP polling */ + dev_vdbg(&udev->dev, "HNP polling failed. status %d\n", ret); + goto out; + } + + /* Spec says host must suspend the bus with in 2 sec. */ + if (*status & (1 << HOST_REQUEST_FLAG)) { + do_unbind_rebind(udev, DO_UNBIND); + ret = usb_suspend_both(udev, PMSG_USER_SUSPEND); + if (ret) + dev_info(&udev->dev, "suspend failed\n"); + } else { + schedule_delayed_work(&bus->hnp_polling, + msecs_to_jiffies(THOST_REQ_POLL)); + } +out: + kfree(status); +} +#endif + static void choose_wakeup(struct usb_device *udev, pm_message_t msg) { int w; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 140d3e11f21..f4f78a30b1d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -897,6 +897,9 @@ static void usb_bus_init (struct usb_bus *bus) bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD (&bus->bus_list); +#ifdef CONFIG_USB_OTG + INIT_DELAYED_WORK(&bus->hnp_polling, usb_hnp_polling_work); +#endif } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 87c938adbc7..abb0084795c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1693,6 +1693,12 @@ void usb_disconnect(struct usb_device **pdev) dev_info(&udev->dev, "USB disconnect, device number %d\n", udev->devnum); +#ifdef CONFIG_USB_OTG + if (udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) { + cancel_delayed_work_sync(&udev->bus->hnp_polling); + udev->bus->hnp_support = 0; + } +#endif usb_lock_device(udev); /* Free up all the children before we remove this device */ @@ -1797,15 +1803,10 @@ static int usb_enumerate_device_otg(struct usb_device *udev) (port1 == bus->otg_port) ? "" : "non-"); - /* enable HNP before suspend, it's simpler */ - if (port1 == bus->otg_port) - bus->b_hnp_enable = 1; err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, 0, - bus->b_hnp_enable - ? USB_DEVICE_B_HNP_ENABLE - : USB_DEVICE_A_ALT_HNP_SUPPORT, + USB_DEVICE_A_HNP_SUPPORT, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (err < 0) { /* OTG MESSAGE: report errors here, @@ -1814,24 +1815,34 @@ static int usb_enumerate_device_otg(struct usb_device *udev) dev_info(&udev->dev, "can't set HNP mode: %d\n", err); - bus->b_hnp_enable = 0; + bus->hnp_support = 0; } } } } +out: if (!is_targeted(udev)) { /* Maybe it can talk to us, though we can't talk to it. * (Includes HNP test device.) */ - if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { + if (udev->bus->hnp_support) { err = usb_port_suspend(udev, PMSG_SUSPEND); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); } err = -ENOTSUPP; goto fail; + } else if (udev->bus->hnp_support && + udev->portnum == udev->bus->otg_port) { + /* HNP polling is introduced in OTG supplement Rev 2.0 + * and older devices does not support. Work is not + * re-armed if device returns STALL. B-Host also performs + * HNP polling. + */ + schedule_delayed_work(&udev->bus->hnp_polling, + msecs_to_jiffies(THOST_REQ_POLL)); } fail: #endif @@ -2497,6 +2508,20 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); +#ifdef CONFIG_USB_OTG + if (!udev->bus->is_b_host && udev->bus->hnp_support && + udev->portnum == udev->bus->otg_port) { + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_B_HNP_ENABLE, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + if (status < 0) + dev_dbg(&udev->dev, "can't enable HNP on port %d, " + "status %d\n", port1, status); + else + udev->bus->b_hnp_enable = 1; + } +#endif /* see 7.1.7.6 */ if (hub_is_superspeed(hub->hdev)) status = set_port_feature(hub->hdev, @@ -2651,6 +2676,12 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) int status; u16 portchange, portstatus; +#ifdef CONFIG_USB_OTG + if (!udev->bus->is_b_host && udev->bus->hnp_support && + udev->portnum == udev->bus->otg_port) + udev->bus->b_hnp_enable = 0; +#endif + /* Skip the initial Clear-Suspend step for a remote wakeup */ status = hub_port_status(hub, port1, &portstatus, &portchange); if (status == 0 && !port_is_suspended(hub, portstatus)) diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 5994cef4d2d..f7962567c1b 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -78,7 +78,9 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg) } #endif - +#ifdef CONFIG_USB_OTG +extern void usb_hnp_polling_work(struct work_struct *work); +#endif #ifdef CONFIG_USB_SUSPEND extern void usb_autosuspend_device(struct usb_device *udev); diff --git a/include/linux/usb.h b/include/linux/usb.h index 33488200c17..3645e63e029 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -331,6 +331,10 @@ struct usb_bus { u8 otg_port; /* 0, or number of OTG/HNP port */ unsigned is_b_host:1; /* true during some HNP roleswitches */ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ +#ifdef CONFIG_USB_OTG + unsigned hnp_support:1; /* OTG: HNP is supported on OTG port */ + struct delayed_work hnp_polling;/* OTG: HNP polling work */ +#endif unsigned sg_tablesize; /* 0 or largest number of sg list entries */ int devnum_next; /* Next open device number in diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index af21f311591..1ed2af81975 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -152,6 +152,12 @@ #define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ +#ifdef CONFIG_USB_OTG +/* OTG 2.0 spec 6.2 and 6.3 sections */ +#define OTG_STATUS_SELECTOR 0xF000 +#define THOST_REQ_POLL 1500 /* 1000 - 2000 msec */ +#define HOST_REQUEST_FLAG 0 +#endif /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */ #define USB_DEV_STAT_U1_ENABLED 2 /* transition into U1 state */ #define USB_DEV_STAT_U2_ENABLED 3 /* transition into U2 state */ @@ -651,8 +657,10 @@ struct usb_qualifier_descriptor { struct usb_otg_descriptor { __u8 bLength; __u8 bDescriptorType; - - __u8 bmAttributes; /* support for HNP, SRP, etc */ +#ifdef CONFIG_USB_OTG + __u8 bmAttributes; /* support for HNP, SRP, ADP etc */ + __le16 bcdOTG; +#endif } __attribute__ ((packed)); /* from usb_otg_descriptor.bmAttributes */ -- cgit v1.2.3 From 56d0696232fa2ba60006fcd05888e933ef9dc085 Mon Sep 17 00:00:00 2001 From: Avinash Kumar Date: Tue, 14 Feb 2012 14:33:12 +0530 Subject: USB: USB Electrical Test Mode Support Added the Test device VID/PID in TPL list for OTG 2.0 Removed the is_host_active check while setting the test mode. OTG Test Mode support is added.An OTG device shall support the test device that initiates these test modes. Upon enumeration by the host, the test device presents a VID/PID pair that defines a test mode or operation to execute. Upon enumerating the test device with VID of 0x1A0A, the Targeted Host shall perform the following operations based on the PID presented. PID Test Mode 0x0101 Test_SE0_NAK 0x0102 Test_J 0x0103 Test_K 0x0104 Test_Packet 0x0105 Reserved. 0x0106 HS_HOST_PORT_SUSPEND_RESUME 0x0107 SINGLE_STEP_GET_DEV_DESC 0x0108 SINGLE_STEP_ GET_DEV_DESC_DATA ST-Ericsson ID: 401192 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-10054 Change-Id: I63525228da242419ceb54198f117795bf44df483 Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/48813 Reviewed-by: Praveena NADAHALLY Reviewed-by: QABUILD Reviewed-by: QATEST --- drivers/usb/core/hub.c | 95 ++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/otg_whitelist.h | 68 ++++++++++++++++++++++++++++ drivers/usb/gadget/Kconfig | 11 +++++ drivers/usb/musb/musb_virthub.c | 2 +- 4 files changed, 175 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index abb0084795c..f4038c53b61 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3569,6 +3569,101 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (status) dev_dbg(hub_dev, "%dmA power budget left\n", status); +#ifdef CONFIG_USB_OTG_20 + + u16 idVendor = le16_to_cpu(udev->descriptor.idVendor); + if (idVendor == USB_OTG_TEST_MODE_VID) { + u16 wValue, typeReq, wIndex; + u32 set_feature = 0; + int err = 0; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + u16 idProduct = le16_to_cpu( + udev->descriptor.idProduct); + /* Convert the Test Mode Request + * to control request + */ + wValue = USB_PORT_FEAT_TEST; + typeReq = SetPortFeature; + wIndex = 1; + + switch (idProduct) { + case USB_OTG_TEST_SE0_NAK_PID: + wIndex |= USB_OTG_TEST_SE0_NAK << 8; + set_feature = 1; + break; + case USB_OTG_TEST_J_PID: + wIndex |= USB_OTG_TEST_J << 8; + set_feature = 1; + break; + case USB_OTG_TEST_K_PID: + wIndex |= USB_OTG_TEST_K << 8; + set_feature = 1; + break; + case USB_OTG_TEST_PACKET_PID: + wIndex |= USB_OTG_TEST_PACKET << 8; + set_feature = 1; + break; + case USB_OTG_TEST_HS_HOST_PORT_SUSPEND_RESUME_PID: + /* Sleep for 15 sec. Suspend + * for 15 Sec, Then Resume + */ + ssleep(15); + + err = usb_port_suspend(udev, + PMSG_SUSPEND); + if (err < 0) { + dev_err(&udev->dev, "OTG TEST_MODE:" + "Suspend Fail, %d\n", err); + goto loop_disable; + } + ssleep(15); + err = usb_port_resume(udev, PMSG_RESUME); + if (err < 0) { + dev_err(&udev->dev, + "can't resume for" + "OTG TEST_MODE: %d\n", err); + goto loop_disable; + } + break; + case USB_OTG_TEST_SINGLE_STEP_GET_DEV_DESC_PID: + /* Sleep for 15 Sec. Issue the GetDeviceDescriptor */ + ssleep(15); + err = usb_get_device_descriptor(udev, + sizeof(udev->descriptor)); + if (err < 0) { + dev_err(&udev->dev, "can't re-read" + "device descriptor for " + "OTG TEST MODE: %d\n", err); + goto loop_disable; + } + break; + case USB_OTG_TEST_SINGLE_STEP_GET_DEV_DESC_DATA_PID: + /* Issue GetDeviceDescriptor, Sleep for 15 Sec. */ + err = usb_get_device_descriptor(udev, + sizeof(udev->descriptor)); + if (err < 0) { + dev_err(&udev->dev, "can't re-read" + "device descriptor for " + "OTG TEST MODE: %d\n", err); + goto loop_disable; + } + ssleep(15); + break; + default: + /* is_targeted() will take care for wrong PID */ + dev_dbg(&udev->dev, "OTG TEST_MODE:Wrong + PID %d\n" idProduct); + break; + } + + if (set_feature) { + err = hcd->driver->hub_control(hcd, + typeReq, wValue, wIndex, + NULL, 0); + } + } + +#endif return; loop_disable: diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index e8cdce571bb..86a09972836 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -43,12 +43,50 @@ static struct usb_device_id whitelist_table [] = { { USB_DEVICE(0x0525, 0xa4a0), }, #endif +#ifdef CONFIG_USB_OTG_20 +{ USB_DEVICE_INFO(8, 6, 80) },/* Mass Storage Devices */ +{ USB_DEVICE_INFO(1, 1, 0) },/* Audio Devices */ +{ USB_DEVICE_INFO(3, 0, 0) },/* keyboard Devices */ +{ USB_DEVICE_INFO(3, 1, 2) },/* Mouse Devices */ + +/* Test Devices */ +{ USB_DEVICE(0x1A0A, 0x0101), },/* Test_SE0_NAK */ +{ USB_DEVICE(0x1A0A, 0x0102), },/* Test_J */ +{ USB_DEVICE(0x1A0A, 0x0103), },/* Test_K */ +{ USB_DEVICE(0x1A0A, 0x0104), },/* Test_Packet */ +{ USB_DEVICE(0x1A0A, 0x0106), },/* HS_HOST_PORT_SUSPEND_RESUME */ +{ USB_DEVICE(0x1A0A, 0x0107), },/* SINGLE_STEP_GET_DEV_DESC */ +{ USB_DEVICE(0x1A0A, 0x0108), },/* SINGLE_STEP_ GET_DEV_DESC_DATA*/ +{ USB_DEVICE(0x1A0A, 0x0201), },/* OTG 2 TEST DEVICE*/ +#endif { } /* Terminating entry */ }; +/* The TEST_MODE Definition for OTG as per 6.4 of OTG Rev 2.0 */ + +#ifdef CONFIG_USB_OTG_20 +#define USB_OTG_TEST_MODE_VID 0x1A0A +#define USB_OTG_TEST_SE0_NAK_PID 0x0101 +#define USB_OTG_TEST_J_PID 0x0102 +#define USB_OTG_TEST_K_PID 0x0103 +#define USB_OTG_TEST_PACKET_PID 0x0104 +#define USB_OTG_TEST_HS_HOST_PORT_SUSPEND_RESUME_PID 0x0106 +#define USB_OTG_TEST_SINGLE_STEP_GET_DEV_DESC_PID 0x0107 +#define USB_OTG_TEST_SINGLE_STEP_GET_DEV_DESC_DATA_PID 0x0108 + +#define USB_OTG_TEST_SE0_NAK 0x01 +#define USB_OTG_TEST_J 0x02 +#define USB_OTG_TEST_K 0x03 +#define USB_OTG_TEST_PACKET 0x04 +#endif + static int is_targeted(struct usb_device *dev) { struct usb_device_id *id = whitelist_table; +#ifdef CONFIG_USB_OTG_20 + u8 number_configs = 0; + u8 number_interface = 0; +#endif /* possible in developer configs only! */ if (!dev->bus->otg_port) @@ -98,6 +136,36 @@ static int is_targeted(struct usb_device *dev) /* add other match criteria here ... */ +#ifdef CONFIG_USB_OTG_20 + + /* Checking class,subclass and protocal at interface level */ + for (number_configs = dev->descriptor.bNumConfigurations; + number_configs > 0; number_configs--) + for (number_interface = dev->config->desc.bNumInterfaces; + number_interface > 0; + number_interface--) + for (id = whitelist_table; id->match_flags; id++) { + if ((id->match_flags & + USB_DEVICE_ID_MATCH_DEV_CLASS) && + (id->bDeviceClass != + dev->config->intf_cache[number_interface-1] + ->altsetting[0].desc.bInterfaceClass)) + continue; + if ((id->match_flags & + USB_DEVICE_ID_MATCH_DEV_SUBCLASS) + && (id->bDeviceSubClass != + dev->config->intf_cache[number_interface-1] + ->altsetting[0].desc.bInterfaceSubClass)) + continue; + if ((id->match_flags & + USB_DEVICE_ID_MATCH_DEV_PROTOCOL) + && (id->bDeviceProtocol != + dev->config->intf_cache[number_interface-1] + ->altsetting[0].desc.bInterfaceProtocol)) + continue; + return 1; + } +#endif /* OTG MESSAGE: report errors here, customize to match your product */ dev_err(&dev->dev, "device v%04x p%04x is not supported\n", diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2633f759511..7e99677b81b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -977,4 +977,15 @@ config USB_G_WEBCAM endchoice +config USB_OTG_20 + bool "OTG 2.0 USB SUPPORT" + select USB_OTG + select PM_RUNTIME + select USB_OTG_WHITELIST + select USB_SUSPEND + default n + help + Enabling the whitelist (Target Peripheral List-TPL) and runtime power + management at system level and usb level for OTG 2.0. + endif # USB_GADGET diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 22ec3e37998..702d5efe9ef 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -379,7 +379,7 @@ int musb_hub_control( musb_port_suspend(musb, true); break; case USB_PORT_FEAT_TEST: - if (unlikely(is_host_active(musb))) + if (unlikely(!is_host_active(musb))) goto error; wIndex >>= 8; -- cgit v1.2.3 From 1d46676256fe722fc11c266728f1f09de0943aa8 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 16 Mar 2012 10:45:50 +0100 Subject: USB: Add support for USB OTG 2.0 OTG 2.0 support is provided in Kernel 3.0. Srp related modifications are done in ab8500-usb. ST-Ericsson ID: 401192 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-10054 Change-Id: I1bf52c8d6f6c4b0bedf5e51004dc72bf52a68020 Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/49006 Reviewed-by: QATOOLS Reviewed-by: Praveena NADAHALLY Conflicts: drivers/usb/otg/ab8500-usb.c --- drivers/usb/core/driver.c | 1 + drivers/usb/core/hub.c | 135 ++++++++++++++++++++++++++++++++----- drivers/usb/musb/musb_core.c | 7 +- drivers/usb/musb/musb_core.h | 6 +- drivers/usb/musb/musb_gadget.c | 2 + drivers/usb/musb/musb_gadget_ep0.c | 54 ++++++++++++--- drivers/usb/musb/musb_regs.h | 4 +- drivers/usb/musb/ux500.c | 9 ++- drivers/usb/otg/ab8500-usb.c | 23 +++++++ include/linux/usb/gadget.h | 5 ++ 10 files changed, 213 insertions(+), 33 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index b3948206024..7ce5080df46 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1306,6 +1306,7 @@ void usb_hnp_polling_work(struct work_struct *work) if (ret < 0) { /* Peripheral may not be supporting HNP polling */ dev_vdbg(&udev->dev, "HNP polling failed. status %d\n", ret); + ret = usb_suspend_both(udev, PMSG_USER_SUSPEND); goto out; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f4038c53b61..f78df1d3163 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -639,7 +639,7 @@ static int hub_hub_status(struct usb_hub *hub, "%s failed (err = %d)\n", __func__, ret); else { *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); + *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } mutex_unlock(&hub->status_mutex); @@ -1693,7 +1693,7 @@ void usb_disconnect(struct usb_device **pdev) dev_info(&udev->dev, "USB disconnect, device number %d\n", udev->devnum); -#ifdef CONFIG_USB_OTG +#ifdef CONFIG_USB_OTG_20 if (udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) { cancel_delayed_work_sync(&udev->bus->hnp_polling); udev->bus->hnp_support = 0; @@ -1775,11 +1775,13 @@ static inline void announce_device(struct usb_device *udev) { } * * Finish enumeration for On-The-Go devices */ + +#ifdef CONFIG_USB_OTG_20 + static int usb_enumerate_device_otg(struct usb_device *udev) { int err = 0; -#ifdef CONFIG_USB_OTG /* * OTG-aware devices on OTG-capable root hubs may be able to use SRP, * to wake us after we've powered off VBUS; and HNP, switching roles @@ -1803,6 +1805,10 @@ static int usb_enumerate_device_otg(struct usb_device *udev) (port1 == bus->otg_port) ? "" : "non-"); + if (port1 != bus->otg_port) + goto out; + bus->hnp_support = 1; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, 0, @@ -1832,8 +1838,6 @@ out: if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); } - err = -ENOTSUPP; - goto fail; } else if (udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) { /* HNP polling is introduced in OTG supplement Rev 2.0 @@ -1845,10 +1849,82 @@ out: msecs_to_jiffies(THOST_REQ_POLL)); } fail: + + return err; +} + +#else + +static int usb_enumerate_device_otg(struct usb_device *udev) +{ + int err = 0; + +#ifdef CONFIG_USB_OTG + /* + * OTG-aware devices on OTG-capable root hubs may be able to use SRP, + * to wake us after we've powered off VBUS; and HNP, switching roles + * "host" to "peripheral". The OTG descriptor helps figure this out. + */ + if (!udev->bus->is_b_host + && udev->config + && udev->parent == udev->bus->root_hub) { + struct usb_otg_descriptor *desc = NULL; + struct usb_bus *bus = udev->bus; + + /* descriptor may appear anywhere in config */ + if (__usb_get_extra_descriptor(udev->rawdescriptors[0], + le16_to_cpu(udev->config[0].desc.wTotalLength), + USB_DT_OTG, (void **) &desc) == 0) { + if (desc->bmAttributes & USB_OTG_HNP) { + unsigned port1 = udev->portnum; + + dev_info(&udev->dev, + "Dual-Role OTG device on %sHNP port\n", + (port1 == bus->otg_port) + ? "" : "non-"); + + /* enable HNP before suspend, it's simpler */ + if (port1 == bus->otg_port) + bus->b_hnp_enable = 1; + err = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + bus->b_hnp_enable + ? USB_DEVICE_B_HNP_ENABLE + : USB_DEVICE_A_ALT_HNP_SUPPORT, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + if (err < 0) { + /* OTG MESSAGE: report errors here, + * customize to match your product. + */ + dev_info(&udev->dev, + "can't set HNP mode: %d\n", + err); + bus->b_hnp_enable = 0; + } + } + } + } + + if (!is_targeted(udev)) { + + /* Maybe it can talk to us, though we can't talk to it. + * (Includes HNP test device.) + */ + if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { + err = usb_port_suspend(udev, PMSG_SUSPEND); + if (err < 0) + dev_dbg(&udev->dev, "HNP fail, %d\n", err); + } + err = -ENOTSUPP; + goto fail; + } +fail: #endif return err; } +#endif /** * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal) @@ -2508,7 +2584,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); -#ifdef CONFIG_USB_OTG +#ifdef CONFIG_USB_OTG_20 if (!udev->bus->is_b_host && udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -2522,6 +2598,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) udev->bus->b_hnp_enable = 1; } #endif + /* see 7.1.7.6 */ if (hub_is_superspeed(hub->hdev)) status = set_port_feature(hub->hdev, @@ -2676,7 +2753,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) int status; u16 portchange, portstatus; -#ifdef CONFIG_USB_OTG +#ifdef CONFIG_USB_OTG_20 if (!udev->bus->is_b_host && udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) udev->bus->b_hnp_enable = 0; @@ -2885,7 +2962,7 @@ EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); * Between connect detection and reset signaling there must be a delay * of 100ms at least for debounce and power-settling. The corresponding * timer shall restart whenever the downstream port detects a disconnect. - * + * * Apparently there are some bluetooth and irda-dongles and a number of * low-speed devices for which this debounce period may last over a second. * Not covered by the spec - but easy to deal with. @@ -3083,7 +3160,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->tt = &hub->tt; udev->ttport = port1; } - + /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? * Because device hardware and firmware is sometimes buggy in * this area, and this is how Linux has done it for ages. @@ -3243,7 +3320,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); usb_ep0_reinit(udev); } - + retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); if (retval < (signed)sizeof(udev->descriptor)) { dev_err(&udev->dev, "device descriptor read/all, error %d\n", @@ -3528,7 +3605,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, goto loop_disable; } } - + /* check for devices running slower than they could */ if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 && udev->speed == USB_SPEED_FULL @@ -3570,6 +3647,20 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, dev_dbg(hub_dev, "%dmA power budget left\n", status); #ifdef CONFIG_USB_OTG_20 + struct usb_otg_descriptor *desc = NULL; + int ret; + /* descriptor may appear anywhere in config */ + __usb_get_extra_descriptor(udev->rawdescriptors[0], + le16_to_cpu(udev->config[0].desc.wTotalLength), + USB_DT_OTG, (void **) &desc); + + ret = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_B_HNP_ENABLE, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0) + dev_dbg(hub_dev, "set feature error\n"); u16 idVendor = le16_to_cpu(udev->descriptor.idVendor); if (idVendor == USB_OTG_TEST_MODE_VID) { @@ -3651,8 +3742,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, break; default: /* is_targeted() will take care for wrong PID */ - dev_dbg(&udev->dev, "OTG TEST_MODE:Wrong - PID %d\n" idProduct); + dev_dbg(&udev->dev, "OTG TEST_MODE:Wrong" + "PID %d\n", idProduct); break; } @@ -3681,7 +3772,7 @@ loop: !(hcd->driver->port_handed_over)(hcd, port1)) dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); - + done: hub_port_disable(hub, port1, 1); if (hcd->driver->relinquish_port && !hub->hdev->parent) @@ -3848,7 +3939,7 @@ static void hub_events(void) * EM interference sometimes causes badly * shielded USB devices to be shutdown by * the hub, this hack enables them again. - * Works at least with mouse driver. + * Works at least with mouse driver. */ if (!(portstatus & USB_PORT_STAT_ENABLE) && !connect_change @@ -4188,7 +4279,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (ret < 0) goto re_enumerate; - + /* Device might have changed firmware (DFU or similar) */ if (descriptors_changed(udev, &descriptor)) { dev_info(&udev->dev, "device firmware changed\n"); @@ -4221,6 +4312,16 @@ static int usb_reset_and_verify_device(struct usb_device *udev) goto re_enumerate; } mutex_unlock(hcd->bandwidth_mutex); + +#ifdef CONFIG_USB_OTG_20 + ret = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_A_HNP_SUPPORT, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0) + dev_err(&udev->dev, "set feature error\n"); +#endif usb_set_device_state(udev, USB_STATE_CONFIGURED); /* Put interfaces back into the same altsettings as before. @@ -4261,7 +4362,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: return 0; - + re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 840afb3b8a0..1ab2fd8c3e9 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -714,6 +714,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, b_host: musb->xceiv->state = OTG_STATE_B_HOST; hcd->self.is_b_host = 1; +#ifdef CONFIG_USB_OTG_20 + musb->g.otg_hnp_reqd = 0; +#endif musb->ignore_disconnect = 0; del_timer(&musb->otg_timer); break; @@ -1748,7 +1751,9 @@ musb_srp_store(struct device *dev, struct device_attribute *attr, { struct musb *musb = dev_to_musb(dev); unsigned short srp; - +#ifdef CONFIG_USB_OTG_20 + musb->xceiv->start_srp(musb->xceiv); +#endif if (sscanf(buf, "%hu", &srp) != 1 || (srp != 1)) { dev_err(dev, "SRP: Value must be 1\n"); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index f7a37fa1bfe..2d52530d3e4 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -153,7 +153,10 @@ enum musb_g_ep0_state { #define OTG_TIME_A_WAIT_BCON 1100 /* min 1 second */ #define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */ #define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */ - +#ifdef CONFIG_USB_OTG_20 +#define USB_SUSP_DET_DURATION 5 /* suspend time 5ms */ +#define TTST_SRP 3000 /* max 5 sec */ +#endif /*************************** REGISTER ACCESS ********************************/ @@ -432,7 +435,6 @@ struct musb { unsigned set_address:1; unsigned test_mode:1; unsigned softconnect:1; - u8 address; u8 test_mode_nr; u16 ackpend; /* ep0 */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 461b5f2d889..b2abef69dc3 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1662,7 +1662,9 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) } spin_unlock_irqrestore(&musb->lock, flags); +#ifndef CONFIG_USB_OTG_20 otg_start_srp(musb->xceiv->otg); +#endif spin_lock_irqsave(&musb->lock, flags); /* Block idling for at least 1s */ diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index e40d7647caf..631aab86240 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -45,6 +45,11 @@ /* ep0 is always musb->endpoints[0].ep_in */ #define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) +/* OTG 2.0 Specification 6.2.3 GetStatus commands */ +#ifdef CONFIG_USB_OTG_20 +#define OTG_STATUS_SELECT 0xF +#endif + /* * locking note: we use only the controller lock, for simpler correctness. * It's always held with IRQs blocked. @@ -80,21 +85,33 @@ static int service_tx_status_request( int handled = 1; u8 result[2], epnum = 0; const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; - +#ifdef CONFIG_USB_OTG_20 + unsigned int otg_recip = ctrlrequest->wIndex >> 12; +#endif result[1] = 0; switch (recip) { case USB_RECIP_DEVICE: - result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED; - result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; - if (musb->g.is_otg) { - result[0] |= musb->g.b_hnp_enable - << USB_DEVICE_B_HNP_ENABLE; - result[0] |= musb->g.a_alt_hnp_support - << USB_DEVICE_A_ALT_HNP_SUPPORT; - result[0] |= musb->g.a_hnp_support - << USB_DEVICE_A_HNP_SUPPORT; +#ifdef CONFIG_USB_OTG_20 + if (!(otg_recip == OTG_STATUS_SELECT)) { +#endif + result[0] = musb->is_self_powered << + USB_DEVICE_SELF_POWERED; + result[0] |= musb->may_wakeup << + USB_DEVICE_REMOTE_WAKEUP; + if (musb->g.is_otg) { + result[0] |= musb->g.b_hnp_enable + << USB_DEVICE_B_HNP_ENABLE; + result[0] |= musb->g.a_alt_hnp_support + << USB_DEVICE_A_ALT_HNP_SUPPORT; + result[0] |= musb->g.a_hnp_support + << USB_DEVICE_A_HNP_SUPPORT; + } +#ifdef CONFIG_USB_OTG_20 + } else { + result[0] = 1 & musb->g.otg_hnp_reqd; } +#endif break; case USB_RECIP_INTERFACE: @@ -356,7 +373,22 @@ __acquires(musb->lock) musb->test_mode_nr = MUSB_TEST_PACKET; break; - +#ifdef CONFIG_USB_OTG_20 + case 6: + if (!musb->g.is_otg) + goto stall; + musb->g.otg_srp_reqd = 1; + + mod_timer(&musb->otg_timer, + jiffies + + msecs_to_jiffies(TTST_SRP)); + break; + case 7: + if (!musb->g.is_otg) + goto stall; + musb->g.otg_hnp_reqd = 1; + break; +#endif case 0xc0: /* TEST_FORCE_HS */ pr_debug("TEST_FORCE_HS\n"); diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 03f2655af29..1c96cf60907 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -246,7 +246,9 @@ */ #define MUSB_DEVCTL 0x60 /* 8 bit */ - +#ifdef CONFIG_USB_OTG_20 +#define MUSB_MISC 0x61 /* 8 bit */ +#endif /* These are always controlled through the INDEX register */ #define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */ #define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */ diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index fe322cf541c..89ef846d32c 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -311,11 +311,18 @@ 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; +#ifdef CONFIG_USB_OTG_20 + int val = 0; +#endif /* HDRC controls CPEN, but beware current surges during device * connect. They can trigger transient overcurrent conditions * that must be ignored. */ - +#ifdef CONFIG_USB_OTG_20 + val = musb_readb(musb->mregs, MUSB_MISC); + val |= 0x1C; + musb_writeb(musb->mregs, MUSB_MISC, val); +#endif devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index a698165135e..7efd64b3bc5 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -484,6 +484,26 @@ static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) return mA; } +#ifdef CONFIG_USB_OTG_20 +static int ab8500_usb_start_srp(struct usb_phy *phy, unsigned mA) +{ + struct ab8500_usb *ab; + + if (!phy) + return -ENODEV; + + ab = phy_to_ab(phy); + + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); + + ab8500_usb_peri_phy_en(ab); + + return 0; +} +#endif + static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) { struct ab8500_usb *ab; @@ -838,6 +858,9 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) otg->phy = &ab->phy; otg->set_host = ab8500_usb_set_host; otg->set_peripheral = ab8500_usb_set_peripheral; +#ifdef CONFIG_USB_OTG_20 + ab->otg.start_srp = ab8500_usb_start_srp; +#endif ab->sysfs_flag = true; platform_set_drvdata(pdev, ab); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 51c97812bf4..164c9a03052 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -536,6 +536,11 @@ struct usb_gadget { unsigned b_hnp_enable:1; unsigned a_hnp_support:1; unsigned a_alt_hnp_support:1; +#ifdef CONFIG_USB_OTG_20 + unsigned host_request:1; + unsigned otg_hnp_reqd:1; + unsigned otg_srp_reqd:1; +#endif const char *name; struct device dev; }; -- cgit v1.2.3 From 13c8bfd54cb90efe68d9c8f3b9e47e7bf950b8f4 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Wed, 29 Feb 2012 10:58:49 +0530 Subject: USB:Enabling autosuspend in Host audio Allowing to suspend the usb bus if the connected device is a USB Audio device. ST-Ericsson ID: 415876 Signed-off-by: Sakethram Bommisetti --- drivers/usb/core/driver.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 7ce5080df46..c90174ee4c1 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1671,7 +1671,7 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume); /* Internal routine to check whether we may autosuspend a device. */ static int autosuspend_check(struct usb_device *udev) { - int w, i; + int w, i, audio_class = 0; struct usb_interface *intf; /* Fail if autosuspend is disabled, or any interfaces are in use, or @@ -1705,13 +1705,28 @@ static int autosuspend_check(struct usb_device *udev) intf->needs_remote_wakeup) return -EOPNOTSUPP; } + + if (intf->cur_altsetting->desc.bInterfaceClass + == USB_CLASS_AUDIO) { + dev_dbg(&udev->dev, + "audio interface class present\n"); + audio_class = 1; + } } + if (audio_class) { + dev_dbg(&udev->dev, + "disabling remote wakeup for audio class\n"); + udev->do_remote_wakeup = 0; + } else { + if (w && !device_can_wakeup(&udev->dev)) { + dev_dbg(&udev->dev, + "remote wakeup needed for autosuspend\n"); + return -EOPNOTSUPP; + } + udev->do_remote_wakeup = w; + } + } - if (w && !device_can_wakeup(&udev->dev)) { - dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n"); - return -EOPNOTSUPP; - } - udev->do_remote_wakeup = w; return 0; } -- cgit v1.2.3 From ed05cf27f9ad74b62780fd38487ee33fd6eb97b5 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 16 Mar 2012 10:54:45 +0100 Subject: AB8505: USB: AB8505 support Code is added to support the following items: (1) Identifying AB8500 and AB8505 USB drivers at run-time (2) Handling new Link status values (3) Coverity errors ST-Ericsson ID: 370818 ST-Ericsson FOSS-OUT ID: Trivial ST-Ericsson Linux next: NA Change-Id: I3f6c6a5894a4f9f43a86a39e35bf17b36eb46448 Signed-off-by: Megha Dey Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/49184 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Praveena NADAHALLY --- drivers/usb/otg/ab8500-usb.c | 363 +++++++++++++++++++++++++++++-------------- 1 file changed, 249 insertions(+), 114 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 7efd64b3bc5..de6de506b44 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -76,25 +76,57 @@ static bool usb_pm_qos_is_latency_0; #define PUBLIC_ID_BACKUPRAM1 (U8500_BACKUPRAM1_BASE + 0x0FC0) #define MAX_USB_SERIAL_NUMBER_LEN 31 +#define AB8505_USB_LINE_STAT_REG 0x94 /* Usb line status register */ enum ab8500_usb_link_status { - USB_LINK_NOT_CONFIGURED = 0, - 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_RESERVED, - USB_LINK_NOT_VALID_LINK + USB_LINK_NOT_CONFIGURED_8500 = 0, + USB_LINK_STD_HOST_NC_8500, + USB_LINK_STD_HOST_C_NS_8500, + USB_LINK_STD_HOST_C_S_8500, + USB_LINK_HOST_CHG_NM_8500, + USB_LINK_HOST_CHG_HS_8500, + USB_LINK_HOST_CHG_HS_CHIRP_8500, + USB_LINK_DEDICATED_CHG_8500, + USB_LINK_ACA_RID_A_8500, + USB_LINK_ACA_RID_B_8500, + USB_LINK_ACA_RID_C_NM_8500, + USB_LINK_ACA_RID_C_HS_8500, + USB_LINK_ACA_RID_C_HS_CHIRP_8500, + USB_LINK_HM_IDGND_8500, + USB_LINK_RESERVED_8500, + USB_LINK_NOT_VALID_LINK_8500, +}; + +enum ab8505_usb_link_status { + USB_LINK_NOT_CONFIGURED_8505 = 0, + USB_LINK_STD_HOST_NC_8505, + USB_LINK_STD_HOST_C_NS_8505, + USB_LINK_STD_HOST_C_S_8505, + USB_LINK_CDP_8505, + USB_LINK_RESERVED0_8505, + USB_LINK_RESERVED1_8505, + USB_LINK_DEDICATED_CHG_8505, + USB_LINK_ACA_RID_A_8505, + USB_LINK_ACA_RID_B_8505, + USB_LINK_ACA_RID_C_NM_8505, + USB_LINK_RESERVED2_8505, + USB_LINK_RESERVED3_8505, + USB_LINK_HM_IDGND_8505, + USB_LINK_CHARGERPORT_NOT_OK_8505, + USB_LINK_CHARGER_DM_HIGH_8505, + USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505, + USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505, + USB_LINK_STD_UPSTREAM_8505, + USB_LINK_CHARGER_SE1_8505, + USB_LINK_CARKIT_CHGR_1_8505, + USB_LINK_CARKIT_CHGR_2_8505, + USB_LINK_ACA_DOCK_CHGR_8505, + USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505, + USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505, + USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505, + USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505, + USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505, }; enum ab8500_usb_mode { @@ -309,112 +341,219 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) #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) +static int ab8505_usb_link_status_update(struct ab8500_usb *ab, + enum ab8505_usb_link_status lsts) { - u8 reg; - enum ab8500_usb_link_status lsts; - enum usb_phy_events event; - - abx500_get_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_LINE_STAT_REG, - ®); - - lsts = (reg >> 3) & 0x0F; - - dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts); - if (!(ab->sysfs_flag)) { - switch (lsts) { - case USB_LINK_ACA_RID_B: - event = USB_EVENT_RIDB; - case USB_LINK_NOT_CONFIGURED: - case USB_LINK_RESERVED: - case USB_LINK_NOT_VALID_LINK: - if (ab->mode == USB_PERIPHERAL) - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_CLEAN, + enum usb_phy_events event=0; + + dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts); + + switch (lsts) { + case USB_LINK_ACA_RID_B_8505: + event = USB_EVENT_RIDB; + case USB_LINK_NOT_CONFIGURED_8505: + case USB_LINK_RESERVED0_8505: + case USB_LINK_RESERVED1_8505: + case USB_LINK_RESERVED2_8505: + case USB_LINK_RESERVED3_8505: + if (ab->mode == USB_PERIPHERAL) + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_CLEAN, + &ab->vbus_draw); + ab->mode = USB_IDLE; + ab->phy.otg->default_a = false; + ab->vbus_draw = 0; + if (event != USB_EVENT_RIDB) + event = USB_EVENT_NONE; + break; + + case USB_LINK_ACA_RID_C_NM_8505: + event = USB_EVENT_RIDC; + case USB_LINK_STD_HOST_NC_8505: + case USB_LINK_STD_HOST_C_NS_8505: + case USB_LINK_STD_HOST_C_S_8505: + if (ab->mode == USB_HOST) { + ab->mode = USB_PERIPHERAL; + ab8500_usb_host_phy_dis(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_CLEAN, + &ab->vbus_draw); + ab8500_usb_peri_phy_en(ab); + } + if (ab->mode == USB_IDLE) { + ab->mode = USB_PERIPHERAL; + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_PREPARE, &ab->vbus_draw); - ab->mode = USB_IDLE; - ab->phy.otg.default_a = false; - ab->vbus_draw = 0; - if (event != USB_EVENT_RIDB) - event = USB_EVENT_NONE; - break; - case USB_LINK_ACA_RID_C_NM: - case USB_LINK_ACA_RID_C_HS: - case USB_LINK_ACA_RID_C_HS_CHIRP: - event = USB_EVENT_RIDC; - 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->mode == USB_HOST) { - ab->mode = USB_PERIPHERAL; - ab8500_usb_host_phy_dis(ab); - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_PREPARE, - &ab->vbus_draw); - ab8500_usb_peri_phy_en(ab); - } - if (ab->mode == USB_IDLE) { - ab->mode = USB_PERIPHERAL; - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_PREPARE, - &ab->vbus_draw); - ab8500_usb_peri_phy_en(ab); - } - if (event != USB_EVENT_RIDC) - event = USB_EVENT_VBUS; - break; - - case USB_LINK_ACA_RID_A: - event = USB_EVENT_RIDA; - case USB_LINK_HM_IDGND: - if (ab->mode == USB_PERIPHERAL) { - ab->mode = USB_HOST; - ab8500_usb_peri_phy_dis(ab); - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_PREPARE, - &ab->vbus_draw); - ab8500_usb_host_phy_en(ab); - } - if (ab->mode == USB_IDLE) { - ab->mode = USB_HOST; - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_PREPARE, - &ab->vbus_draw); - ab8500_usb_host_phy_en(ab); - } - ab->phy.otg->default_a = true; - if (event != USB_EVENT_RIDA) - event = USB_EVENT_ID; + ab8500_usb_peri_phy_en(ab); + } + if (event != USB_EVENT_RIDC) + event = USB_EVENT_VBUS; + break; + case USB_LINK_ACA_RID_A_8505: + event = USB_EVENT_RIDA; + case USB_LINK_HM_IDGND_8505: + if (ab->mode == USB_PERIPHERAL) { + ab->mode = USB_HOST; + ab8500_usb_peri_phy_dis(ab); atomic_notifier_call_chain(&ab->phy.notifier, - event, - &ab->vbus_draw); - break; - - case USB_LINK_DEDICATED_CHG: - /* TODO: vbus_draw */ + USB_EVENT_PREPARE, + &ab->vbus_draw); + ab8500_usb_host_phy_en(ab); + } + if (ab->mode == USB_IDLE) { + ab->mode = USB_HOST; + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); + ab8500_usb_host_phy_en(ab); + } + ab->phy.otg->default_a = true; + if (event != USB_EVENT_RIDA) + event = USB_EVENT_ID; + atomic_notifier_call_chain(&ab->phy.notifier, + event, + &ab->vbus_draw); + break; + + case USB_LINK_DEDICATED_CHG_8505: ab->mode = USB_DEDICATED_CHG; event = USB_EVENT_CHARGER; atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); - break; - } + break; + + default: + break; } + return 0; +} + +static int ab8500_usb_link_status_update(struct ab8500_usb *ab, + enum ab8500_usb_link_status lsts) +{ + enum usb_phy_events event=0; + + dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts); + + switch (lsts) { + case USB_LINK_ACA_RID_B_8500: + event = USB_EVENT_RIDB; + case USB_LINK_NOT_CONFIGURED_8500: + case USB_LINK_RESERVED_8500: + case USB_LINK_NOT_VALID_LINK_8500: + if (ab->mode == USB_PERIPHERAL) + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_CLEAN, + &ab->vbus_draw); + ab->mode = USB_IDLE; + ab->phy.otg->default_a = false; + ab->vbus_draw = 0; + if (event != USB_EVENT_RIDB) + event = USB_EVENT_NONE; + break; + case USB_LINK_ACA_RID_C_NM_8500: + case USB_LINK_ACA_RID_C_HS_8500: + case USB_LINK_ACA_RID_C_HS_CHIRP_8500: + event = USB_EVENT_RIDC; + case USB_LINK_STD_HOST_NC_8500: + case USB_LINK_STD_HOST_C_NS_8500: + case USB_LINK_STD_HOST_C_S_8500: + case USB_LINK_HOST_CHG_NM_8500: + case USB_LINK_HOST_CHG_HS_8500: + case USB_LINK_HOST_CHG_HS_CHIRP_8500: + if (ab->mode == USB_HOST) { + ab->mode = USB_PERIPHERAL; + ab8500_usb_host_phy_dis(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); + ab8500_usb_peri_phy_en(ab); + } + if (ab->mode == USB_IDLE) { + ab->mode = USB_PERIPHERAL; + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); + ab8500_usb_peri_phy_en(ab); + } + if (event != USB_EVENT_RIDC) + event = USB_EVENT_VBUS; + break; + + case USB_LINK_ACA_RID_A_8500: + event = USB_EVENT_RIDA; + case USB_LINK_HM_IDGND_8500: + if (ab->mode == USB_PERIPHERAL) { + ab->mode = USB_HOST; + ab8500_usb_peri_phy_dis(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); + ab8500_usb_host_phy_en(ab); + } + if (ab->mode == USB_IDLE) { + ab->mode = USB_HOST; + atomic_notifier_call_chain(&ab->phy.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); + ab8500_usb_host_phy_en(ab); + } + ab->phy.otg->default_a = true; + if (event != USB_EVENT_RIDA) + event = USB_EVENT_ID; + atomic_notifier_call_chain(&ab->phy.notifier, + event, + &ab->vbus_draw); + break; + case USB_LINK_DEDICATED_CHG_8500: + ab->mode = USB_DEDICATED_CHG; + event = USB_EVENT_CHARGER; + atomic_notifier_call_chain(&ab->phy.notifier, + event, + &ab->vbus_draw); + break; + } return 0; } +static int abx500_usb_link_status_update(struct ab8500_usb *ab) +{ + u8 reg; + int ret = 0; + + if (!(ab->sysfs_flag)) { + if (is_ab8500(ab->ab8500)) { + enum ab8500_usb_link_status lsts; + + abx500_get_register_interruptible(ab->dev, + AB8500_USB, + AB8500_USB_LINE_STAT_REG, + ®); + lsts = (reg >> 3) & 0x0F; + ret = ab8500_usb_link_status_update(ab, lsts); + } + if (is_ab8505(ab->ab8500)) { + enum ab8505_usb_link_status lsts; + + abx500_get_register_interruptible(ab->dev, + AB8500_USB, + AB8505_USB_LINE_STAT_REG, + ®); + lsts = (reg >> 3) & 0x1F; + ret = ab8505_usb_link_status_update(ab, lsts); + } + } + return ret; +} + static void ab8500_usb_delayed_work(struct work_struct *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); + abx500_usb_link_status_update(ab); } static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) @@ -453,7 +592,7 @@ static irqreturn_t ab8500_usb_v20_link_status_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; - ab8500_usb_link_status_update(ab); + abx500_usb_link_status_update(ab); return IRQ_HANDLED; } @@ -634,28 +773,24 @@ static int ab8500_usb_regulator_get(struct ab8500_usb *ab) 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; + return err; } 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; + return err; } 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 err; } return 0; - -reg_error: - ab8500_usb_regulator_put(ab); - return err; } static void ab8500_usb_irq_free(struct ab8500_usb *ab) @@ -791,7 +926,7 @@ boot_time_device_store(struct device *dev, struct device_attribute *attr, ab->sysfs_flag = false; - ab8500_usb_link_status_update(ab); + abx500_usb_link_status_update(ab); return n; } -- cgit v1.2.3 From 9bb10417670288e04dfa32317bbf4614b3a0a15f Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 16 Mar 2012 11:30:04 +0100 Subject: usb: ab5500-usb: Porting to new pm interface Signed-off-by: Philippe Langlais --- drivers/usb/otg/ab5500-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/otg/ab5500-usb.c b/drivers/usb/otg/ab5500-usb.c index d37529f7f0a..e8c06e694a6 100644 --- a/drivers/usb/otg/ab5500-usb.c +++ b/drivers/usb/otg/ab5500-usb.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include /* AB5500 USB macros */ @@ -49,7 +49,7 @@ #define USB_PROBE_DELAY 1000 /* 1 seconds */ #define USB_LIMIT (200) /* If we have more than 200 irqs per second */ -static struct pm_qos_request_list usb_pm_qos_latency; +static struct pm_qos_request usb_pm_qos_latency; static bool usb_pm_qos_is_latency_0; #define PUBLIC_ID_BACKUPRAM1 (U5500_BACKUPRAM1_BASE + 0x0FC0) -- cgit v1.2.3 From bdc10765dc58316db60d2e1d8f2ff48ceaf9396c Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 19 Apr 2012 11:52:32 +0200 Subject: usb: core: Fix in ST-E changes after 3.4 porting This fix must be verified Signed-off-by: Philippe Langlais --- drivers/usb/core/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index c90174ee4c1..b3eeb3e1d60 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1312,7 +1312,7 @@ void usb_hnp_polling_work(struct work_struct *work) /* Spec says host must suspend the bus with in 2 sec. */ if (*status & (1 << HOST_REQUEST_FLAG)) { - do_unbind_rebind(udev, DO_UNBIND); + unbind_no_pm_drivers_interfaces(udev); ret = usb_suspend_both(udev, PMSG_USER_SUSPEND); if (ret) dev_info(&udev->dev, "suspend failed\n"); -- cgit v1.2.3 From 1a89bd0dbcc8af5990b2ad309633062e20de4d5e Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 19 Apr 2012 11:55:54 +0200 Subject: musb: Fix ST-E changes after 3.4 porting Signed-off-by: Philippe Langlais --- drivers/usb/musb/ux500.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 89ef846d32c..2f089ddcd46 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -346,7 +346,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) } else { musb->is_active = 1; - musb->xceiv->default_a = 1; + musb->xceiv->otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; MUSB_HST_MODE(musb); @@ -357,7 +357,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and * jumping right to B_IDLE... */ - musb->xceiv->default_a = 0; + musb->xceiv->otg->default_a = 0; devctl &= ~MUSB_DEVCTL_SESSION; MUSB_DEV_MODE(musb); } @@ -441,7 +441,7 @@ static int ux500_musb_init(struct musb *musb) } pm_runtime_get_noresume(musb->controller); musb->nb.notifier_call = musb_otg_notifications; - status = otg_register_notifier(musb->xceiv, &musb->nb); + status = usb_register_notifier(musb->xceiv, &musb->nb); if (status < 0) { dev_dbg(musb->controller, "notification register failed\n"); -- cgit v1.2.3 From 49ad144fbf2abcc415847975e79f0ef9bb5e78c6 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 19 Apr 2012 13:59:48 +0200 Subject: usb: otg8500: Fixes after 3.4 porting Signed-off-by: Philippe Langlais --- drivers/usb/otg/ab8500-usb.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index de6de506b44..49c5d31c150 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -559,13 +559,13 @@ static void ab8500_usb_delayed_work(struct work_struct *work) static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) { struct ab8500_usb *ab = (struct ab8500_usb *) data; - enum usb_xceiv_events event = USB_EVENT_NONE; + enum usb_phy_events event = USB_EVENT_NONE; /* Link status will not be updated till phy is disabled. */ if (ab->mode == USB_HOST) { - ab->otg.default_a = false; + ab->phy.otg->default_a = false; ab->vbus_draw = 0; - atomic_notifier_call_chain(&ab->otg.notifier, + atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); ab8500_usb_host_phy_dis(ab); } @@ -661,10 +661,6 @@ static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) return 0; } -/* TODO: Implement some way for charging or other drivers to read - * ab->vbus_draw. - */ - static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend) { /* TODO */ @@ -681,7 +677,7 @@ static int ab8500_usb_set_peripheral(struct usb_otg *otg, ab = phy_to_ab(otg->phy); - ab->otg.gadget = gadget; + ab->phy.otg->gadget = gadget; /* Some drivers call this function in atomic context. * Do not update ab8500 registers directly till this * is fixed. @@ -701,7 +697,7 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) ab = phy_to_ab(otg->phy); - ab->otg.host = host; + ab->phy.otg->host = host; /* Some drivers call this function in atomic context. * Do not update ab8500 registers directly till this -- cgit v1.2.3 From 2b85348ec0be48a89fb2689bc59d943fbee8a625 Mon Sep 17 00:00:00 2001 From: supriya karanth Date: Tue, 22 May 2012 09:37:00 +0200 Subject: usb: musb: SW workaround for USB host issue For snowball in HOST mode, the eye diagram is facing high distortion in high speed use cases. This patch allows the user to use an external charge pump instead of the internal one to generate the Vbus voltage. This can be done by setting a sysfs entry. The external VBUS is OFF by default and can be made ON by setting the sysfs entry inorder to enumerate high speed devices. Signed-off-by: supriya karanth --- drivers/usb/musb/musb_core.c | 35 +++++++++++++++++++++++++++++++++++ drivers/usb/musb/musb_debugfs.c | 1 + drivers/usb/musb/ux500.c | 12 ++++++++++++ 3 files changed, 48 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 1ab2fd8c3e9..2923752b858 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1767,10 +1767,45 @@ musb_srp_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); +static ssize_t +ux500_set_extvbus(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + unsigned short extvbus; + + if (sscanf(buf, "%hu", &extvbus) != 1 + || ((extvbus != 1) && (extvbus != 0))) { + dev_err(dev, "Invalid value EXTVBUS must be 1 or 0\n"); + return -EINVAL; + } + + plat->extvbus = extvbus; + + return n; +} + +static ssize_t +ux500_get_extvbus(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + int extvbus; + + /* FIXME get_vbus_status() is normally #defined as false... + * and is effectively TUSB-specific. + */ + extvbus = plat->extvbus; + + return sprintf(buf, "EXTVBUS is %s\n", + extvbus ? "on" : "off"); +} +static DEVICE_ATTR(extvbus, 0644, ux500_get_extvbus, ux500_set_extvbus); + static struct attribute *musb_attributes[] = { &dev_attr_mode.attr, &dev_attr_vbus.attr, &dev_attr_srp.attr, + &dev_attr_extvbus.attr, NULL }; diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 40a37c91cc1..19e3c91c22e 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -68,6 +68,7 @@ static const struct musb_register_map musb_regmap[] = { { "RxFIFOadd", 0x66, 16 }, { "VControl", 0x68, 32 }, { "HWVers", 0x6C, 16 }, + { "EXTVBUS", 0x70, 8 }, { "EPInfo", 0x78, 8 }, { "RAMInfo", 0x79, 8 }, { "LinkInfo", 0x7A, 8 }, diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 2f089ddcd46..c1a205cd5e3 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -311,6 +311,7 @@ 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; + struct musb_hdrc_platform_data *plat = musb->controller->platform_data; #ifdef CONFIG_USB_OTG_20 int val = 0; #endif @@ -323,6 +324,17 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) val |= 0x1C; musb_writeb(musb->mregs, MUSB_MISC, val); #endif + + /* Use EXTVBUS */ + u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); + if (plat->extvbus) { + busctl |= MUSB_ULPI_USE_EXTVBUS; + musb_write_ulpi_buscontrol(musb->mregs, busctl); + } else { + busctl &= ~MUSB_ULPI_USE_EXTVBUS; + musb_write_ulpi_buscontrol(musb->mregs, busctl); + } + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { -- cgit v1.2.3