summaryrefslogtreecommitdiff
path: root/drivers/usb/musb/tusb6010.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/musb/tusb6010.c')
-rw-r--r--drivers/usb/musb/tusb6010.c92
1 files changed, 57 insertions, 35 deletions
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 4eb640c54f2c..1d9571f24a56 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1,19 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* TUSB6010 USB 2.0 OTG Dual Role controller
*
* Copyright (C) 2006 Nokia Corporation
* Tony Lindgren <tony@atomide.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Notes:
* - Driver assumes that interface to external host (main CPU) is
* configured for NOR FLASH interface instead of VLYNQ serial
* interface.
*/
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -22,6 +21,7 @@
#include <linux/usb.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
@@ -33,6 +33,8 @@ struct tusb6010_glue {
struct device *dev;
struct platform_device *musb;
struct platform_device *phy;
+ struct gpio_desc *enable;
+ struct gpio_desc *intpin;
};
static void tusb_musb_set_vbus(struct musb *musb, int is_on);
@@ -145,7 +147,7 @@ static void tusb_ep_select(void __iomem *mbase, u8 epnum)
/*
* TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
*/
-static u8 tusb_readb(const void __iomem *addr, unsigned offset)
+static u8 tusb_readb(void __iomem *addr, u32 offset)
{
u16 tmp;
u8 val;
@@ -159,7 +161,7 @@ static u8 tusb_readb(const void __iomem *addr, unsigned offset)
return val;
}
-static void tusb_writeb(void __iomem *addr, unsigned offset, u8 data)
+static void tusb_writeb(void __iomem *addr, u32 offset, u8 data)
{
u16 tmp;
@@ -193,6 +195,7 @@ tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len)
}
if (len > 0) {
/* Write the rest 1 - 3 bytes to FIFO */
+ val = 0;
memcpy(&val, buf, len);
musb_writel(fifo, 0, val);
}
@@ -452,11 +455,9 @@ static int tusb_musb_vbus_status(struct musb *musb)
return ret;
}
-static struct timer_list musb_idle_timer;
-
-static void musb_do_idle(unsigned long _musb)
+static void musb_do_idle(struct timer_list *t)
{
- struct musb *musb = (void *)_musb;
+ struct musb *musb = timer_container_of(musb, t, dev_timer);
unsigned long flags;
spin_lock_irqsave(&musb->lock, flags);
@@ -469,9 +470,10 @@ static void musb_do_idle(unsigned long _musb)
dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n",
usb_otg_state_string(musb->xceiv->otg->state));
}
- /* FALLTHROUGH */
+ fallthrough;
case OTG_STATE_A_IDLE:
tusb_musb_set_vbus(musb, 0);
+ break;
default:
break;
}
@@ -498,7 +500,7 @@ done:
}
/*
- * Maybe put TUSB6010 into idle mode mode depending on USB link status,
+ * Maybe put TUSB6010 into idle mode depending on USB link status,
* like "disconnected" or "suspended". We'll be woken out of it by
* connect, resume, or disconnect.
*
@@ -523,13 +525,13 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
&& (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
usb_otg_state_string(musb->xceiv->otg->state));
- del_timer(&musb_idle_timer);
+ timer_delete(&musb->dev_timer);
last_timer = jiffies;
return;
}
if (time_after(last_timer, timeout)) {
- if (!timer_pending(&musb_idle_timer))
+ if (!timer_pending(&musb->dev_timer))
last_timer = timeout;
else {
dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
@@ -541,7 +543,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
usb_otg_state_string(musb->xceiv->otg->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
- mod_timer(&musb_idle_timer, timeout);
+ mod_timer(&musb->dev_timer, timeout);
}
/* ticks of 60 MHz clock */
@@ -873,7 +875,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)
}
if (int_src & TUSB_INT_SRC_USB_IP_CONN)
- del_timer(&musb_idle_timer);
+ timer_delete(&musb->dev_timer);
/* OTG state change reports (annoyingly) not issued by Mentor core */
if (int_src & (TUSB_INT_SRC_VBUS_SENSE_CHNG
@@ -982,7 +984,7 @@ static void tusb_musb_disable(struct musb *musb)
musb_writel(tbase, TUSB_DMA_INT_MASK, 0x7fffffff);
musb_writel(tbase, TUSB_GPIO_INT_MASK, 0x1ff);
- del_timer(&musb_idle_timer);
+ timer_delete(&musb->dev_timer);
if (is_dma_capable() && !dma_off) {
printk(KERN_WARNING "%s %s: dma still active\n",
@@ -1024,15 +1026,24 @@ static void tusb_setup_cpu_interface(struct musb *musb)
static int tusb_musb_start(struct musb *musb)
{
+ struct tusb6010_glue *glue = dev_get_drvdata(musb->controller->parent);
void __iomem *tbase = musb->ctrl_base;
- int ret = 0;
unsigned long flags;
u32 reg;
+ int ret;
- if (musb->board_set_power)
- ret = musb->board_set_power(1);
- if (ret != 0) {
- printk(KERN_ERR "tusb: Cannot enable TUSB6010\n");
+ /*
+ * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
+ * 1.5 V voltage regulators of PM companion chip. Companion chip will then
+ * provide then PGOOD signal to TUSB6010 which will release it from reset.
+ */
+ gpiod_set_value(glue->enable, 1);
+
+ /* Wait for 100ms until TUSB6010 pulls INT pin down */
+ ret = read_poll_timeout(gpiod_get_value, reg, !reg, 5000, 100000, true,
+ glue->intpin);
+ if (ret) {
+ pr_err("tusb: Powerup response failed\n");
return ret;
}
@@ -1086,8 +1097,8 @@ static int tusb_musb_start(struct musb *musb)
err:
spin_unlock_irqrestore(&musb->lock, flags);
- if (musb->board_set_power)
- musb->board_set_power(0);
+ gpiod_set_value(glue->enable, 0);
+ msleep(10);
return -ENODEV;
}
@@ -1107,6 +1118,11 @@ static int tusb_musb_init(struct musb *musb)
/* dma address for async dma */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ pr_debug("no async dma resource?\n");
+ ret = -ENODEV;
+ goto done;
+ }
musb->async = mem->start;
/* dma address for sync dma */
@@ -1142,7 +1158,7 @@ static int tusb_musb_init(struct musb *musb)
musb->xceiv->set_power = tusb_draw_power;
the_musb = musb;
- setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+ timer_setup(&musb->dev_timer, musb_do_idle, 0);
done:
if (ret < 0) {
@@ -1156,11 +1172,13 @@ done:
static int tusb_musb_exit(struct musb *musb)
{
- del_timer_sync(&musb_idle_timer);
+ struct tusb6010_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ timer_delete_sync(&musb->dev_timer);
the_musb = NULL;
- if (musb->board_set_power)
- musb->board_set_power(0);
+ gpiod_set_value(glue->enable, 0);
+ msleep(10);
iounmap(musb->sync_va);
@@ -1216,6 +1234,15 @@ static int tusb_probe(struct platform_device *pdev)
glue->dev = &pdev->dev;
+ glue->enable = devm_gpiod_get(glue->dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(glue->enable))
+ return dev_err_probe(glue->dev, PTR_ERR(glue->enable),
+ "could not obtain power on/off GPIO\n");
+ glue->intpin = devm_gpiod_get(glue->dev, "int", GPIOD_IN);
+ if (IS_ERR(glue->intpin))
+ return dev_err_probe(glue->dev, PTR_ERR(glue->intpin),
+ "could not obtain INT GPIO\n");
+
pdata->platform_ops = &tusb_ops;
usb_phy_generic_register();
@@ -1234,10 +1261,7 @@ static int tusb_probe(struct platform_device *pdev)
musb_resources[1].end = pdev->resource[1].end;
musb_resources[1].flags = pdev->resource[1].flags;
- musb_resources[2].name = pdev->resource[2].name;
- musb_resources[2].start = pdev->resource[2].start;
- musb_resources[2].end = pdev->resource[2].end;
- musb_resources[2].flags = pdev->resource[2].flags;
+ musb_resources[2] = DEFINE_RES_IRQ_NAMED(gpiod_to_irq(glue->intpin), "mc");
pinfo = tusb_dev_info;
pinfo.parent = &pdev->dev;
@@ -1256,14 +1280,12 @@ static int tusb_probe(struct platform_device *pdev)
return 0;
}
-static int tusb_remove(struct platform_device *pdev)
+static void tusb_remove(struct platform_device *pdev)
{
struct tusb6010_glue *glue = platform_get_drvdata(pdev);
platform_device_unregister(glue->musb);
usb_phy_generic_unregister(glue->phy);
-
- return 0;
}
static struct platform_driver tusb_driver = {