|
@@ -43,6 +43,7 @@
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/of_device.h>
|
|
|
#include <linux/of_address.h>
|
|
|
+#include <linux/of_irq.h>
|
|
|
|
|
|
#include "musb_core.h"
|
|
|
|
|
@@ -105,10 +106,7 @@ struct dsps_musb_wrapper {
|
|
|
/* bit positions for mode */
|
|
|
unsigned iddig:5;
|
|
|
/* miscellaneous stuff */
|
|
|
- u32 musb_core_offset;
|
|
|
u8 poll_seconds;
|
|
|
- /* number of musb instances */
|
|
|
- u8 instances;
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -116,10 +114,10 @@ struct dsps_musb_wrapper {
|
|
|
*/
|
|
|
struct dsps_glue {
|
|
|
struct device *dev;
|
|
|
- struct platform_device *musb[2]; /* child musb pdev */
|
|
|
+ struct platform_device *musb; /* child musb pdev */
|
|
|
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
|
|
|
- struct timer_list timer[2]; /* otg_workaround timer */
|
|
|
- unsigned long last_timer[2]; /* last timer data for each instance */
|
|
|
+ struct timer_list timer; /* otg_workaround timer */
|
|
|
+ unsigned long last_timer; /* last timer data for each instance */
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -168,7 +166,6 @@ static void otg_timer(unsigned long _musb)
|
|
|
struct musb *musb = (void *)_musb;
|
|
|
void __iomem *mregs = musb->mregs;
|
|
|
struct device *dev = musb->controller;
|
|
|
- struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
|
|
|
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
|
|
u8 devctl;
|
|
@@ -205,7 +202,7 @@ static void otg_timer(unsigned long _musb)
|
|
|
case OTG_STATE_B_IDLE:
|
|
|
devctl = dsps_readb(mregs, MUSB_DEVCTL);
|
|
|
if (devctl & MUSB_DEVCTL_BDEVICE)
|
|
|
- mod_timer(&glue->timer[pdev->id],
|
|
|
+ mod_timer(&glue->timer,
|
|
|
jiffies + wrp->poll_seconds * HZ);
|
|
|
else
|
|
|
musb->xceiv->state = OTG_STATE_A_IDLE;
|
|
@@ -219,7 +216,6 @@ static void otg_timer(unsigned long _musb)
|
|
|
static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
|
|
|
{
|
|
|
struct device *dev = musb->controller;
|
|
|
- struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
|
|
|
|
|
|
if (timeout == 0)
|
|
@@ -230,23 +226,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
|
|
|
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
|
|
|
dev_dbg(musb->controller, "%s active, deleting timer\n",
|
|
|
usb_otg_state_string(musb->xceiv->state));
|
|
|
- del_timer(&glue->timer[pdev->id]);
|
|
|
- glue->last_timer[pdev->id] = jiffies;
|
|
|
+ del_timer(&glue->timer);
|
|
|
+ glue->last_timer = jiffies;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (time_after(glue->last_timer[pdev->id], timeout) &&
|
|
|
- timer_pending(&glue->timer[pdev->id])) {
|
|
|
+ if (time_after(glue->last_timer, timeout) &&
|
|
|
+ timer_pending(&glue->timer)) {
|
|
|
dev_dbg(musb->controller,
|
|
|
"Longer idle timer already pending, ignoring...\n");
|
|
|
return;
|
|
|
}
|
|
|
- glue->last_timer[pdev->id] = timeout;
|
|
|
+ glue->last_timer = timeout;
|
|
|
|
|
|
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
|
|
|
usb_otg_state_string(musb->xceiv->state),
|
|
|
jiffies_to_msecs(timeout - jiffies));
|
|
|
- mod_timer(&glue->timer[pdev->id], timeout);
|
|
|
+ mod_timer(&glue->timer, timeout);
|
|
|
}
|
|
|
|
|
|
static irqreturn_t dsps_interrupt(int irq, void *hci)
|
|
@@ -254,7 +250,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
|
|
|
struct musb *musb = hci;
|
|
|
void __iomem *reg_base = musb->ctrl_base;
|
|
|
struct device *dev = musb->controller;
|
|
|
- struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
|
|
|
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
|
|
unsigned long flags;
|
|
@@ -314,7 +309,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
|
|
|
*/
|
|
|
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
|
|
|
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
|
|
|
- mod_timer(&glue->timer[pdev->id],
|
|
|
+ mod_timer(&glue->timer,
|
|
|
jiffies + wrp->poll_seconds * HZ);
|
|
|
WARNING("VBUS error workaround (delay coming)\n");
|
|
|
} else if (drvvbus) {
|
|
@@ -322,7 +317,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
|
|
|
MUSB_HST_MODE(musb);
|
|
|
musb->xceiv->otg->default_a = 1;
|
|
|
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
|
|
- del_timer(&glue->timer[pdev->id]);
|
|
|
+ del_timer(&glue->timer);
|
|
|
} else {
|
|
|
musb->is_active = 0;
|
|
|
MUSB_DEV_MODE(musb);
|
|
@@ -344,8 +339,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
|
|
|
|
|
|
/* Poll for ID change */
|
|
|
if (musb->xceiv->state == OTG_STATE_B_IDLE)
|
|
|
- mod_timer(&glue->timer[pdev->id],
|
|
|
- jiffies + wrp->poll_seconds * HZ);
|
|
|
+ mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
|
|
|
out:
|
|
|
spin_unlock_irqrestore(&musb->lock, flags);
|
|
|
|
|
@@ -355,31 +349,34 @@ out:
|
|
|
static int dsps_musb_init(struct musb *musb)
|
|
|
{
|
|
|
struct device *dev = musb->controller;
|
|
|
- struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
|
|
|
+ struct platform_device *parent = to_platform_device(dev->parent);
|
|
|
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
|
|
- void __iomem *reg_base = musb->ctrl_base;
|
|
|
+ void __iomem *reg_base;
|
|
|
+ struct resource *r;
|
|
|
u32 rev, val;
|
|
|
- int status;
|
|
|
|
|
|
- /* mentor core register starts at offset of 0x400 from musb base */
|
|
|
- musb->mregs += wrp->musb_core_offset;
|
|
|
+ r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
|
|
|
+ if (!r)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ reg_base = devm_ioremap_resource(dev, r);
|
|
|
+ if (!musb->ctrl_base)
|
|
|
+ return -EINVAL;
|
|
|
+ musb->ctrl_base = reg_base;
|
|
|
|
|
|
/* NOP driver needs change if supporting dual instance */
|
|
|
- musb->xceiv = devm_usb_get_phy_by_phandle(glue->dev, "phys", 0);
|
|
|
- if (IS_ERR_OR_NULL(musb->xceiv))
|
|
|
- return -EPROBE_DEFER;
|
|
|
+ musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
|
|
|
+ if (IS_ERR(musb->xceiv))
|
|
|
+ return PTR_ERR(musb->xceiv);
|
|
|
|
|
|
/* Returns zero if e.g. not clocked */
|
|
|
rev = dsps_readl(reg_base, wrp->revision);
|
|
|
- if (!rev) {
|
|
|
- status = -ENODEV;
|
|
|
- goto err0;
|
|
|
- }
|
|
|
+ if (!rev)
|
|
|
+ return -ENODEV;
|
|
|
|
|
|
usb_phy_init(musb->xceiv);
|
|
|
-
|
|
|
- setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
|
|
|
+ setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
|
|
|
|
|
|
/* Reset the musb */
|
|
|
dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
|
|
@@ -392,17 +389,14 @@ static int dsps_musb_init(struct musb *musb)
|
|
|
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
|
|
|
|
|
|
return 0;
|
|
|
-err0:
|
|
|
- return status;
|
|
|
}
|
|
|
|
|
|
static int dsps_musb_exit(struct musb *musb)
|
|
|
{
|
|
|
struct device *dev = musb->controller;
|
|
|
- struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
|
|
|
|
|
|
- del_timer_sync(&glue->timer[pdev->id]);
|
|
|
+ del_timer_sync(&glue->timer);
|
|
|
|
|
|
usb_phy_shutdown(musb->xceiv);
|
|
|
return 0;
|
|
@@ -420,106 +414,98 @@ static struct musb_platform_ops dsps_ops = {
|
|
|
|
|
|
static u64 musb_dmamask = DMA_BIT_MASK(32);
|
|
|
|
|
|
-static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
|
|
|
+static int get_int_prop(struct device_node *dn, const char *s)
|
|
|
{
|
|
|
- struct device *dev = glue->dev;
|
|
|
- struct platform_device *pdev = to_platform_device(dev);
|
|
|
- struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
|
|
|
- struct device_node *np = pdev->dev.of_node;
|
|
|
- struct musb_hdrc_config *config;
|
|
|
- struct platform_device *musb;
|
|
|
- struct resource *res;
|
|
|
+ int ret;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ ret = of_property_read_u32(dn, s, &val);
|
|
|
+ if (ret)
|
|
|
+ return 0;
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
+static int dsps_create_musb_pdev(struct dsps_glue *glue,
|
|
|
+ struct platform_device *parent)
|
|
|
+{
|
|
|
+ struct musb_hdrc_platform_data pdata;
|
|
|
struct resource resources[2];
|
|
|
- char res_name[11];
|
|
|
+ struct device *dev = &parent->dev;
|
|
|
+ struct musb_hdrc_config *config;
|
|
|
+ struct platform_device *musb;
|
|
|
+ struct device_node *dn = parent->dev.of_node;
|
|
|
+ struct device_node *child_node;
|
|
|
int ret;
|
|
|
|
|
|
- /* first resource is for usbss, so start index from 1 */
|
|
|
- res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
|
|
|
- if (!res) {
|
|
|
- dev_err(dev, "failed to get memory for instance %d\n", id);
|
|
|
- ret = -ENODEV;
|
|
|
- goto err0;
|
|
|
+ child_node = of_get_child_by_name(dn, "usb");
|
|
|
+ if (!child_node)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ memset(resources, 0, sizeof(resources));
|
|
|
+ ret = of_address_to_resource(child_node, 0, &resources[0]);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "failed to get memory.\n");
|
|
|
+ return ret;
|
|
|
}
|
|
|
- res->parent = NULL;
|
|
|
- resources[0] = *res;
|
|
|
-
|
|
|
- /* first resource is for usbss, so start index from 1 */
|
|
|
- res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1);
|
|
|
- if (!res) {
|
|
|
- dev_err(dev, "failed to get irq for instance %d\n", id);
|
|
|
- ret = -ENODEV;
|
|
|
- goto err0;
|
|
|
+
|
|
|
+ ret = of_irq_to_resource(child_node, 0, &resources[1]);
|
|
|
+ if (ret == 0) {
|
|
|
+ dev_err(dev, "failed to get irq.\n");
|
|
|
+ ret = -EINVAL;
|
|
|
+ return ret;
|
|
|
}
|
|
|
- res->parent = NULL;
|
|
|
- resources[1] = *res;
|
|
|
- resources[1].name = "mc";
|
|
|
|
|
|
/* allocate the child platform device */
|
|
|
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
|
|
|
if (!musb) {
|
|
|
dev_err(dev, "failed to allocate musb device\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err0;
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
musb->dev.parent = dev;
|
|
|
musb->dev.dma_mask = &musb_dmamask;
|
|
|
musb->dev.coherent_dma_mask = musb_dmamask;
|
|
|
+ musb->dev.of_node = of_node_get(child_node);
|
|
|
|
|
|
- glue->musb[id] = musb;
|
|
|
+ glue->musb = musb;
|
|
|
|
|
|
- ret = platform_device_add_resources(musb, resources, 2);
|
|
|
+ ret = platform_device_add_resources(musb, resources,
|
|
|
+ ARRAY_SIZE(resources));
|
|
|
if (ret) {
|
|
|
dev_err(dev, "failed to add resources\n");
|
|
|
- goto err2;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
- if (np) {
|
|
|
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
- if (!pdata) {
|
|
|
- dev_err(&pdev->dev,
|
|
|
- "failed to allocate musb platform data\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err2;
|
|
|
- }
|
|
|
-
|
|
|
- config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
|
|
|
- if (!config) {
|
|
|
- dev_err(&pdev->dev,
|
|
|
- "failed to allocate musb hdrc config\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err2;
|
|
|
- }
|
|
|
-
|
|
|
- of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
|
|
|
- of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
|
|
|
- snprintf(res_name, sizeof(res_name), "port%d-mode", id);
|
|
|
- of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
|
|
|
- of_property_read_u32(np, "power", (u32 *)&pdata->power);
|
|
|
- config->multipoint = of_property_read_bool(np, "multipoint");
|
|
|
-
|
|
|
- pdata->config = config;
|
|
|
+ config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
|
|
|
+ if (!config) {
|
|
|
+ dev_err(dev, "failed to allocate musb hdrc config\n");
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err;
|
|
|
}
|
|
|
+ pdata.config = config;
|
|
|
+ pdata.platform_ops = &dsps_ops;
|
|
|
|
|
|
- pdata->platform_ops = &dsps_ops;
|
|
|
+ config->num_eps = get_int_prop(child_node, "num-eps");
|
|
|
+ config->ram_bits = get_int_prop(child_node, "ram-bits");
|
|
|
+ pdata.mode = get_int_prop(child_node, "port-mode");
|
|
|
+ pdata.power = get_int_prop(child_node, "power");
|
|
|
+ config->multipoint = of_property_read_bool(child_node, "multipoint");
|
|
|
|
|
|
- ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
|
|
+ ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
|
|
|
if (ret) {
|
|
|
dev_err(dev, "failed to add platform_data\n");
|
|
|
- goto err2;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
ret = platform_device_add(musb);
|
|
|
if (ret) {
|
|
|
dev_err(dev, "failed to register musb device\n");
|
|
|
- goto err2;
|
|
|
+ goto err;
|
|
|
}
|
|
|
-
|
|
|
return 0;
|
|
|
|
|
|
-err2:
|
|
|
+err:
|
|
|
platform_device_put(musb);
|
|
|
-err0:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -528,14 +514,12 @@ static int dsps_probe(struct platform_device *pdev)
|
|
|
const struct of_device_id *match;
|
|
|
const struct dsps_musb_wrapper *wrp;
|
|
|
struct dsps_glue *glue;
|
|
|
- struct resource *iomem;
|
|
|
- int ret, i;
|
|
|
+ int ret;
|
|
|
|
|
|
match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
|
|
|
if (!match) {
|
|
|
dev_err(&pdev->dev, "fail to get matching of_match struct\n");
|
|
|
- ret = -EINVAL;
|
|
|
- goto err0;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
wrp = match->data;
|
|
|
|
|
@@ -543,29 +527,13 @@ static int dsps_probe(struct platform_device *pdev)
|
|
|
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
|
|
if (!glue) {
|
|
|
dev_err(&pdev->dev, "unable to allocate glue memory\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err0;
|
|
|
- }
|
|
|
-
|
|
|
- /* get memory resource */
|
|
|
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
- if (!iomem) {
|
|
|
- dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
|
|
|
- ret = -ENODEV;
|
|
|
- goto err1;
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
glue->dev = &pdev->dev;
|
|
|
+ glue->wrp = wrp;
|
|
|
|
|
|
- glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
|
|
|
- if (!glue->wrp) {
|
|
|
- dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err1;
|
|
|
- }
|
|
|
platform_set_drvdata(pdev, glue);
|
|
|
-
|
|
|
- /* enable the usbss clocks */
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
|
|
|
ret = pm_runtime_get_sync(&pdev->dev);
|
|
@@ -574,17 +542,9 @@ static int dsps_probe(struct platform_device *pdev)
|
|
|
goto err2;
|
|
|
}
|
|
|
|
|
|
- /* create the child platform device for all instances of musb */
|
|
|
- for (i = 0; i < wrp->instances ; i++) {
|
|
|
- ret = dsps_create_musb_pdev(glue, i);
|
|
|
- if (ret != 0) {
|
|
|
- dev_err(&pdev->dev, "failed to create child pdev\n");
|
|
|
- /* release resources of previously created instances */
|
|
|
- for (i--; i >= 0 ; i--)
|
|
|
- platform_device_unregister(glue->musb[i]);
|
|
|
- goto err3;
|
|
|
- }
|
|
|
- }
|
|
|
+ ret = dsps_create_musb_pdev(glue, pdev);
|
|
|
+ if (ret)
|
|
|
+ goto err3;
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -592,26 +552,19 @@ err3:
|
|
|
pm_runtime_put(&pdev->dev);
|
|
|
err2:
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
- kfree(glue->wrp);
|
|
|
-err1:
|
|
|
kfree(glue);
|
|
|
-err0:
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
static int dsps_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
|
|
- const struct dsps_musb_wrapper *wrp = glue->wrp;
|
|
|
- int i;
|
|
|
|
|
|
- /* delete the child platform device */
|
|
|
- for (i = 0; i < wrp->instances ; i++)
|
|
|
- platform_device_unregister(glue->musb[i]);
|
|
|
+ platform_device_unregister(glue->musb);
|
|
|
|
|
|
/* disable usbss clocks */
|
|
|
pm_runtime_put(&pdev->dev);
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
- kfree(glue->wrp);
|
|
|
kfree(glue);
|
|
|
return 0;
|
|
|
}
|
|
@@ -641,9 +594,7 @@ static const struct dsps_musb_wrapper am33xx_driver_data = {
|
|
|
.rxep_shift = 16,
|
|
|
.rxep_mask = 0xfffe,
|
|
|
.rxep_bitmap = (0xfffe << 16),
|
|
|
- .musb_core_offset = 0x400,
|
|
|
.poll_seconds = 2,
|
|
|
- .instances = 1,
|
|
|
};
|
|
|
|
|
|
static const struct of_device_id musb_dsps_of_match[] = {
|
|
@@ -667,14 +618,4 @@ MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
|
|
|
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
|
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
|
|
-static int __init dsps_init(void)
|
|
|
-{
|
|
|
- return platform_driver_register(&dsps_usbss_driver);
|
|
|
-}
|
|
|
-subsys_initcall(dsps_init);
|
|
|
-
|
|
|
-static void __exit dsps_exit(void)
|
|
|
-{
|
|
|
- platform_driver_unregister(&dsps_usbss_driver);
|
|
|
-}
|
|
|
-module_exit(dsps_exit);
|
|
|
+module_platform_driver(dsps_usbss_driver);
|