diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-08-14 09:44:16 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-14 19:37:20 (GMT) |
commit | 05986ba9b025ae7742744e1108bd59b1f6e8f443 (patch) | |
tree | 4849fd683a155e70f98fea64dfe7d6ae9b361601 /drivers/usb/chipidea/usbmisc_imx.c | |
parent | 4a64783b66bbeed06a1f10ab56a1dd401dd5bfba (diff) | |
download | linux-05986ba9b025ae7742744e1108bd59b1f6e8f443.tar.xz |
USB: chipidea: i.MX: simplify usbmisc
The chipidea i.MX driver is split into two drivers. The ci_hdrc_imx driver
handles the chipidea cores and the usbmisc_imx driver handles the noncore
registers common to all chipidea cores (but SoC specific). Current flow is:
- usbmisc sets an ops pointer in the ci_hdrc_imx driver during probe
- ci_hdrc_imx checks if the pointer is valid during probe, if yes calls
the functions in the ops pointer.
- usbmisc_imx calls back into the ci_hdrc_imx driver to get additional
data
This is overly complicated and has problems if the drivers are compiled
as modules. In this case the usbmisc_imx driver can be unloaded even if
the ci_hdrc_imx driver still needs usbmisc functionality.
This patch changes this by letting the ci_hdrc_imx driver calling functions
from the usbmisc_imx driver. This way the symbol resolving during module
load makes sure the ci_hdrc_imx driver depends on the usbmisc_imx driver.
Also instead of letting the usbmisc_imx driver call back into the ci_hdrc_imx
driver, pass the needed data in the first place.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/chipidea/usbmisc_imx.c')
-rw-r--r-- | drivers/usb/chipidea/usbmisc_imx.c | 95 |
1 files changed, 42 insertions, 53 deletions
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index ac5a461..8a1094b 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -18,8 +18,6 @@ #include "ci_hdrc_imx.h" -#define USB_DEV_MAX 4 - #define MX25_USB_PHY_CTRL_OFFSET 0x08 #define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) @@ -32,51 +30,34 @@ #define MX6_BM_OVER_CUR_DIS BIT(7) +struct usbmisc_ops { + /* It's called once when probe a usb device */ + int (*init)(struct imx_usbmisc_data *data); + /* It's called once after adding a usb device */ + int (*post)(struct imx_usbmisc_data *data); +}; + struct imx_usbmisc { void __iomem *base; spinlock_t lock; struct clk *clk; - struct usbmisc_usb_device usbdev[USB_DEV_MAX]; const struct usbmisc_ops *ops; }; static struct imx_usbmisc *usbmisc; -static struct usbmisc_usb_device *get_usbdev(struct device *dev) -{ - int i, ret; - - for (i = 0; i < USB_DEV_MAX; i++) { - if (usbmisc->usbdev[i].dev == dev) - return &usbmisc->usbdev[i]; - else if (!usbmisc->usbdev[i].dev) - break; - } - - if (i >= USB_DEV_MAX) - return ERR_PTR(-EBUSY); - - ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]); - if (ret) - return ERR_PTR(ret); - - return &usbmisc->usbdev[i]; -} - -static int usbmisc_imx25_post(struct device *dev) +static int usbmisc_imx25_post(struct imx_usbmisc_data *data) { - struct usbmisc_usb_device *usbdev; void __iomem *reg; unsigned long flags; u32 val; - usbdev = get_usbdev(dev); - if (IS_ERR(usbdev)) - return PTR_ERR(usbdev); + if (data->index > 2) + return -EINVAL; reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; - if (usbdev->evdo) { + if (data->evdo) { spin_lock_irqsave(&usbmisc->lock, flags); val = readl(reg); writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); @@ -87,20 +68,18 @@ static int usbmisc_imx25_post(struct device *dev) return 0; } -static int usbmisc_imx53_init(struct device *dev) +static int usbmisc_imx53_init(struct imx_usbmisc_data *data) { - struct usbmisc_usb_device *usbdev; void __iomem *reg = NULL; unsigned long flags; u32 val = 0; - usbdev = get_usbdev(dev); - if (IS_ERR(usbdev)) - return PTR_ERR(usbdev); + if (data->index > 3) + return -EINVAL; - if (usbdev->disable_oc) { + if (data->disable_oc) { spin_lock_irqsave(&usbmisc->lock, flags); - switch (usbdev->index) { + switch (data->index) { case 0: reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; @@ -126,22 +105,19 @@ static int usbmisc_imx53_init(struct device *dev) return 0; } -static int usbmisc_imx6q_init(struct device *dev) +static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) { - - struct usbmisc_usb_device *usbdev; unsigned long flags; u32 reg; - usbdev = get_usbdev(dev); - if (IS_ERR(usbdev)) - return PTR_ERR(usbdev); + if (data->index > 3) + return -EINVAL; - if (usbdev->disable_oc) { + if (data->disable_oc) { spin_lock_irqsave(&usbmisc->lock, flags); - reg = readl(usbmisc->base + usbdev->index * 4); + reg = readl(usbmisc->base + data->index * 4); writel(reg | MX6_BM_OVER_CUR_DIS, - usbmisc->base + usbdev->index * 4); + usbmisc->base + data->index * 4); spin_unlock_irqrestore(&usbmisc->lock, flags); } @@ -160,6 +136,26 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = { .init = usbmisc_imx6q_init, }; +int imx_usbmisc_init(struct imx_usbmisc_data *data) +{ + if (!usbmisc) + return -EPROBE_DEFER; + if (!usbmisc->ops->init) + return 0; + return usbmisc->ops->init(data); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_init); + +int imx_usbmisc_init_post(struct imx_usbmisc_data *data) +{ + if (!usbmisc) + return -EPROBE_DEFER; + if (!usbmisc->ops->post) + return 0; + return usbmisc->ops->post(data); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); + static const struct of_device_id usbmisc_imx_dt_ids[] = { { .compatible = "fsl,imx25-usbmisc", @@ -216,19 +212,12 @@ static int usbmisc_imx_probe(struct platform_device *pdev) of_match_device(usbmisc_imx_dt_ids, &pdev->dev); data->ops = (const struct usbmisc_ops *)tmp_dev->data; usbmisc = data; - ret = usbmisc_set_ops(data->ops); - if (ret) { - usbmisc = NULL; - clk_disable_unprepare(data->clk); - return ret; - } return 0; } static int usbmisc_imx_remove(struct platform_device *pdev) { - usbmisc_unset_ops(usbmisc->ops); clk_disable_unprepare(usbmisc->clk); usbmisc = NULL; return 0; |