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(+) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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(+) (limited to 'drivers/usb/otg') 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 (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(+) (limited to 'drivers/usb/otg') 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(+) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(+) (limited to 'drivers/usb/otg') 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 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 (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(+) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(+) (limited to 'drivers/usb/otg') 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(+) (limited to 'drivers/usb/otg') 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 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(+) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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(-) (limited to 'drivers/usb/otg') 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 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(-) (limited to 'drivers/usb/otg') 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