diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-08-14 05:44:16 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-14 15:37:20 -0400 |
commit | 05986ba9b025ae7742744e1108bd59b1f6e8f443 (patch) | |
tree | 4849fd683a155e70f98fea64dfe7d6ae9b361601 /drivers/usb/chipidea | |
parent | 4a64783b66bbeed06a1f10ab56a1dd401dd5bfba (diff) |
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')
-rw-r--r-- | drivers/usb/chipidea/ci_hdrc_imx.c | 71 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci_hdrc_imx.h | 17 | ||||
-rw-r--r-- | drivers/usb/chipidea/usbmisc_imx.c | 95 |
3 files changed, 76 insertions, 107 deletions
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index cc53e63c9ce9..74d998d9b45b 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c | |||
@@ -27,57 +27,48 @@ struct ci_hdrc_imx_data { | |||
27 | struct usb_phy *phy; | 27 | struct usb_phy *phy; |
28 | struct platform_device *ci_pdev; | 28 | struct platform_device *ci_pdev; |
29 | struct clk *clk; | 29 | struct clk *clk; |
30 | struct imx_usbmisc_data *usbmisc_data; | ||
30 | }; | 31 | }; |
31 | 32 | ||
32 | static const struct usbmisc_ops *usbmisc_ops; | ||
33 | |||
34 | /* Common functions shared by usbmisc drivers */ | 33 | /* Common functions shared by usbmisc drivers */ |
35 | 34 | ||
36 | int usbmisc_set_ops(const struct usbmisc_ops *ops) | 35 | static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) |
37 | { | ||
38 | if (usbmisc_ops) | ||
39 | return -EBUSY; | ||
40 | |||
41 | usbmisc_ops = ops; | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | EXPORT_SYMBOL_GPL(usbmisc_set_ops); | ||
46 | |||
47 | void usbmisc_unset_ops(const struct usbmisc_ops *ops) | ||
48 | { | ||
49 | usbmisc_ops = NULL; | ||
50 | } | ||
51 | EXPORT_SYMBOL_GPL(usbmisc_unset_ops); | ||
52 | |||
53 | int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) | ||
54 | { | 36 | { |
55 | struct device_node *np = dev->of_node; | 37 | struct device_node *np = dev->of_node; |
56 | struct of_phandle_args args; | 38 | struct of_phandle_args args; |
39 | struct imx_usbmisc_data *data; | ||
57 | int ret; | 40 | int ret; |
58 | 41 | ||
59 | usbdev->dev = dev; | 42 | /* |
43 | * In case the fsl,usbmisc property is not present this device doesn't | ||
44 | * need usbmisc. Return NULL (which is no error here) | ||
45 | */ | ||
46 | if (!of_get_property(np, "fsl,usbmisc", NULL)) | ||
47 | return NULL; | ||
48 | |||
49 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | ||
50 | if (!data) | ||
51 | return ERR_PTR(-ENOMEM); | ||
60 | 52 | ||
61 | ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", | 53 | ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", |
62 | 0, &args); | 54 | 0, &args); |
63 | if (ret) { | 55 | if (ret) { |
64 | dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", | 56 | dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", |
65 | ret); | 57 | ret); |
66 | memset(usbdev, 0, sizeof(*usbdev)); | 58 | return ERR_PTR(ret); |
67 | return ret; | ||
68 | } | 59 | } |
69 | usbdev->index = args.args[0]; | 60 | |
61 | data->index = args.args[0]; | ||
70 | of_node_put(args.np); | 62 | of_node_put(args.np); |
71 | 63 | ||
72 | if (of_find_property(np, "disable-over-current", NULL)) | 64 | if (of_find_property(np, "disable-over-current", NULL)) |
73 | usbdev->disable_oc = 1; | 65 | data->disable_oc = 1; |
74 | 66 | ||
75 | if (of_find_property(np, "external-vbus-divider", NULL)) | 67 | if (of_find_property(np, "external-vbus-divider", NULL)) |
76 | usbdev->evdo = 1; | 68 | data->evdo = 1; |
77 | 69 | ||
78 | return 0; | 70 | return data; |
79 | } | 71 | } |
80 | EXPORT_SYMBOL_GPL(usbmisc_get_init_data); | ||
81 | 72 | ||
82 | /* End of common functions shared by usbmisc drivers*/ | 73 | /* End of common functions shared by usbmisc drivers*/ |
83 | 74 | ||
@@ -92,16 +83,16 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) | |||
92 | }; | 83 | }; |
93 | int ret; | 84 | int ret; |
94 | 85 | ||
95 | if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL) | ||
96 | && !usbmisc_ops) | ||
97 | return -EPROBE_DEFER; | ||
98 | |||
99 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | 86 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); |
100 | if (!data) { | 87 | if (!data) { |
101 | dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n"); | 88 | dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n"); |
102 | return -ENOMEM; | 89 | return -ENOMEM; |
103 | } | 90 | } |
104 | 91 | ||
92 | data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); | ||
93 | if (IS_ERR(data->usbmisc_data)) | ||
94 | return PTR_ERR(data->usbmisc_data); | ||
95 | |||
105 | data->clk = devm_clk_get(&pdev->dev, NULL); | 96 | data->clk = devm_clk_get(&pdev->dev, NULL); |
106 | if (IS_ERR(data->clk)) { | 97 | if (IS_ERR(data->clk)) { |
107 | dev_err(&pdev->dev, | 98 | dev_err(&pdev->dev, |
@@ -135,11 +126,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) | |||
135 | if (!pdev->dev.coherent_dma_mask) | 126 | if (!pdev->dev.coherent_dma_mask) |
136 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | 127 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); |
137 | 128 | ||
138 | if (usbmisc_ops && usbmisc_ops->init) { | 129 | if (data->usbmisc_data) { |
139 | ret = usbmisc_ops->init(&pdev->dev); | 130 | ret = imx_usbmisc_init(data->usbmisc_data); |
140 | if (ret) { | 131 | if (ret) { |
141 | dev_err(&pdev->dev, | 132 | dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", |
142 | "usbmisc init failed, ret=%d\n", ret); | 133 | ret); |
143 | goto err_clk; | 134 | goto err_clk; |
144 | } | 135 | } |
145 | } | 136 | } |
@@ -155,11 +146,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) | |||
155 | goto err_clk; | 146 | goto err_clk; |
156 | } | 147 | } |
157 | 148 | ||
158 | if (usbmisc_ops && usbmisc_ops->post) { | 149 | if (data->usbmisc_data) { |
159 | ret = usbmisc_ops->post(&pdev->dev); | 150 | ret = imx_usbmisc_init_post(data->usbmisc_data); |
160 | if (ret) { | 151 | if (ret) { |
161 | dev_err(&pdev->dev, | 152 | dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", |
162 | "usbmisc post failed, ret=%d\n", ret); | 153 | ret); |
163 | goto disable_device; | 154 | goto disable_device; |
164 | } | 155 | } |
165 | } | 156 | } |
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 550bfa457620..c7271590dd0a 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h | |||
@@ -9,23 +9,12 @@ | |||
9 | * http://www.gnu.org/copyleft/gpl.html | 9 | * http://www.gnu.org/copyleft/gpl.html |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* Used to set SoC specific callbacks */ | 12 | struct imx_usbmisc_data { |
13 | struct usbmisc_ops { | ||
14 | /* It's called once when probe a usb device */ | ||
15 | int (*init)(struct device *dev); | ||
16 | /* It's called once after adding a usb device */ | ||
17 | int (*post)(struct device *dev); | ||
18 | }; | ||
19 | |||
20 | struct usbmisc_usb_device { | ||
21 | struct device *dev; /* usb controller device */ | ||
22 | int index; | 13 | int index; |
23 | 14 | ||
24 | unsigned int disable_oc:1; /* over current detect disabled */ | 15 | unsigned int disable_oc:1; /* over current detect disabled */ |
25 | unsigned int evdo:1; /* set external vbus divider option */ | 16 | unsigned int evdo:1; /* set external vbus divider option */ |
26 | }; | 17 | }; |
27 | 18 | ||
28 | int usbmisc_set_ops(const struct usbmisc_ops *ops); | 19 | int imx_usbmisc_init(struct imx_usbmisc_data *); |
29 | void usbmisc_unset_ops(const struct usbmisc_ops *ops); | 20 | int imx_usbmisc_init_post(struct imx_usbmisc_data *); |
30 | int | ||
31 | usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev); | ||
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index ac5a46155200..8a1094b1182f 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c | |||
@@ -18,8 +18,6 @@ | |||
18 | 18 | ||
19 | #include "ci_hdrc_imx.h" | 19 | #include "ci_hdrc_imx.h" |
20 | 20 | ||
21 | #define USB_DEV_MAX 4 | ||
22 | |||
23 | #define MX25_USB_PHY_CTRL_OFFSET 0x08 | 21 | #define MX25_USB_PHY_CTRL_OFFSET 0x08 |
24 | #define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) | 22 | #define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) |
25 | 23 | ||
@@ -32,51 +30,34 @@ | |||
32 | 30 | ||
33 | #define MX6_BM_OVER_CUR_DIS BIT(7) | 31 | #define MX6_BM_OVER_CUR_DIS BIT(7) |
34 | 32 | ||
33 | struct usbmisc_ops { | ||
34 | /* It's called once when probe a usb device */ | ||
35 | int (*init)(struct imx_usbmisc_data *data); | ||
36 | /* It's called once after adding a usb device */ | ||
37 | int (*post)(struct imx_usbmisc_data *data); | ||
38 | }; | ||
39 | |||
35 | struct imx_usbmisc { | 40 | struct imx_usbmisc { |
36 | void __iomem *base; | 41 | void __iomem *base; |
37 | spinlock_t lock; | 42 | spinlock_t lock; |
38 | struct clk *clk; | 43 | struct clk *clk; |
39 | struct usbmisc_usb_device usbdev[USB_DEV_MAX]; | ||
40 | const struct usbmisc_ops *ops; | 44 | const struct usbmisc_ops *ops; |
41 | }; | 45 | }; |
42 | 46 | ||
43 | static struct imx_usbmisc *usbmisc; | 47 | static struct imx_usbmisc *usbmisc; |
44 | 48 | ||
45 | static struct usbmisc_usb_device *get_usbdev(struct device *dev) | 49 | static int usbmisc_imx25_post(struct imx_usbmisc_data *data) |
46 | { | ||
47 | int i, ret; | ||
48 | |||
49 | for (i = 0; i < USB_DEV_MAX; i++) { | ||
50 | if (usbmisc->usbdev[i].dev == dev) | ||
51 | return &usbmisc->usbdev[i]; | ||
52 | else if (!usbmisc->usbdev[i].dev) | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | if (i >= USB_DEV_MAX) | ||
57 | return ERR_PTR(-EBUSY); | ||
58 | |||
59 | ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]); | ||
60 | if (ret) | ||
61 | return ERR_PTR(ret); | ||
62 | |||
63 | return &usbmisc->usbdev[i]; | ||
64 | } | ||
65 | |||
66 | static int usbmisc_imx25_post(struct device *dev) | ||
67 | { | 50 | { |
68 | struct usbmisc_usb_device *usbdev; | ||
69 | void __iomem *reg; | 51 | void __iomem *reg; |
70 | unsigned long flags; | 52 | unsigned long flags; |
71 | u32 val; | 53 | u32 val; |
72 | 54 | ||
73 | usbdev = get_usbdev(dev); | 55 | if (data->index > 2) |
74 | if (IS_ERR(usbdev)) | 56 | return -EINVAL; |
75 | return PTR_ERR(usbdev); | ||
76 | 57 | ||
77 | reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; | 58 | reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; |
78 | 59 | ||
79 | if (usbdev->evdo) { | 60 | if (data->evdo) { |
80 | spin_lock_irqsave(&usbmisc->lock, flags); | 61 | spin_lock_irqsave(&usbmisc->lock, flags); |
81 | val = readl(reg); | 62 | val = readl(reg); |
82 | writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); | 63 | writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); |
@@ -87,20 +68,18 @@ static int usbmisc_imx25_post(struct device *dev) | |||
87 | return 0; | 68 | return 0; |
88 | } | 69 | } |
89 | 70 | ||
90 | static int usbmisc_imx53_init(struct device *dev) | 71 | static int usbmisc_imx53_init(struct imx_usbmisc_data *data) |
91 | { | 72 | { |
92 | struct usbmisc_usb_device *usbdev; | ||
93 | void __iomem *reg = NULL; | 73 | void __iomem *reg = NULL; |
94 | unsigned long flags; | 74 | unsigned long flags; |
95 | u32 val = 0; | 75 | u32 val = 0; |
96 | 76 | ||
97 | usbdev = get_usbdev(dev); | 77 | if (data->index > 3) |
98 | if (IS_ERR(usbdev)) | 78 | return -EINVAL; |
99 | return PTR_ERR(usbdev); | ||
100 | 79 | ||
101 | if (usbdev->disable_oc) { | 80 | if (data->disable_oc) { |
102 | spin_lock_irqsave(&usbmisc->lock, flags); | 81 | spin_lock_irqsave(&usbmisc->lock, flags); |
103 | switch (usbdev->index) { | 82 | switch (data->index) { |
104 | case 0: | 83 | case 0: |
105 | reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; | 84 | reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; |
106 | val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; | 85 | val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; |
@@ -126,22 +105,19 @@ static int usbmisc_imx53_init(struct device *dev) | |||
126 | return 0; | 105 | return 0; |
127 | } | 106 | } |
128 | 107 | ||
129 | static int usbmisc_imx6q_init(struct device *dev) | 108 | static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) |
130 | { | 109 | { |
131 | |||
132 | struct usbmisc_usb_device *usbdev; | ||
133 | unsigned long flags; | 110 | unsigned long flags; |
134 | u32 reg; | 111 | u32 reg; |
135 | 112 | ||
136 | usbdev = get_usbdev(dev); | 113 | if (data->index > 3) |
137 | if (IS_ERR(usbdev)) | 114 | return -EINVAL; |
138 | return PTR_ERR(usbdev); | ||
139 | 115 | ||
140 | if (usbdev->disable_oc) { | 116 | if (data->disable_oc) { |
141 | spin_lock_irqsave(&usbmisc->lock, flags); | 117 | spin_lock_irqsave(&usbmisc->lock, flags); |
142 | reg = readl(usbmisc->base + usbdev->index * 4); | 118 | reg = readl(usbmisc->base + data->index * 4); |
143 | writel(reg | MX6_BM_OVER_CUR_DIS, | 119 | writel(reg | MX6_BM_OVER_CUR_DIS, |
144 | usbmisc->base + usbdev->index * 4); | 120 | usbmisc->base + data->index * 4); |
145 | spin_unlock_irqrestore(&usbmisc->lock, flags); | 121 | spin_unlock_irqrestore(&usbmisc->lock, flags); |
146 | } | 122 | } |
147 | 123 | ||
@@ -160,6 +136,26 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = { | |||
160 | .init = usbmisc_imx6q_init, | 136 | .init = usbmisc_imx6q_init, |
161 | }; | 137 | }; |
162 | 138 | ||
139 | int imx_usbmisc_init(struct imx_usbmisc_data *data) | ||
140 | { | ||
141 | if (!usbmisc) | ||
142 | return -EPROBE_DEFER; | ||
143 | if (!usbmisc->ops->init) | ||
144 | return 0; | ||
145 | return usbmisc->ops->init(data); | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(imx_usbmisc_init); | ||
148 | |||
149 | int imx_usbmisc_init_post(struct imx_usbmisc_data *data) | ||
150 | { | ||
151 | if (!usbmisc) | ||
152 | return -EPROBE_DEFER; | ||
153 | if (!usbmisc->ops->post) | ||
154 | return 0; | ||
155 | return usbmisc->ops->post(data); | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); | ||
158 | |||
163 | static const struct of_device_id usbmisc_imx_dt_ids[] = { | 159 | static const struct of_device_id usbmisc_imx_dt_ids[] = { |
164 | { | 160 | { |
165 | .compatible = "fsl,imx25-usbmisc", | 161 | .compatible = "fsl,imx25-usbmisc", |
@@ -216,19 +212,12 @@ static int usbmisc_imx_probe(struct platform_device *pdev) | |||
216 | of_match_device(usbmisc_imx_dt_ids, &pdev->dev); | 212 | of_match_device(usbmisc_imx_dt_ids, &pdev->dev); |
217 | data->ops = (const struct usbmisc_ops *)tmp_dev->data; | 213 | data->ops = (const struct usbmisc_ops *)tmp_dev->data; |
218 | usbmisc = data; | 214 | usbmisc = data; |
219 | ret = usbmisc_set_ops(data->ops); | ||
220 | if (ret) { | ||
221 | usbmisc = NULL; | ||
222 | clk_disable_unprepare(data->clk); | ||
223 | return ret; | ||
224 | } | ||
225 | 215 | ||
226 | return 0; | 216 | return 0; |
227 | } | 217 | } |
228 | 218 | ||
229 | static int usbmisc_imx_remove(struct platform_device *pdev) | 219 | static int usbmisc_imx_remove(struct platform_device *pdev) |
230 | { | 220 | { |
231 | usbmisc_unset_ops(usbmisc->ops); | ||
232 | clk_disable_unprepare(usbmisc->clk); | 221 | clk_disable_unprepare(usbmisc->clk); |
233 | usbmisc = NULL; | 222 | usbmisc = NULL; |
234 | return 0; | 223 | return 0; |