diff options
author | Peter Chen <peter.chen@freescale.com> | 2015-02-10 23:44:46 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-18 11:19:09 -0400 |
commit | f636cec559c6c01d6a262123446a142e1ae66890 (patch) | |
tree | 464ca8463152e13f0ce9101722bf40deec87916a | |
parent | 1f874edcb7318c5dd71025df9f3849715b4e4f71 (diff) |
usb: chipidea: usbmisc_imx: add .set_wakeup interface
This API is used to enable/disable usb wakeup, only imx6 series are
added, since I don't have other imx hardware on hand. Other imx users
can add their API according to reference manual after testing.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/chipidea/ci_hdrc_imx.h | 1 | ||||
-rw-r--r-- | drivers/usb/chipidea/usbmisc_imx.c | 52 |
2 files changed, 53 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 4ed828f75a1e..635717e9354a 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h | |||
@@ -22,5 +22,6 @@ struct imx_usbmisc_data { | |||
22 | 22 | ||
23 | int imx_usbmisc_init(struct imx_usbmisc_data *); | 23 | int imx_usbmisc_init(struct imx_usbmisc_data *); |
24 | int imx_usbmisc_init_post(struct imx_usbmisc_data *); | 24 | int imx_usbmisc_init_post(struct imx_usbmisc_data *); |
25 | int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *, bool); | ||
25 | 26 | ||
26 | #endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */ | 27 | #endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */ |
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index eb77e3285c8a..90b7d7f3c81b 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c | |||
@@ -55,6 +55,10 @@ | |||
55 | #define MX53_USB_PLL_DIV_24_MHZ 0x01 | 55 | #define MX53_USB_PLL_DIV_24_MHZ 0x01 |
56 | 56 | ||
57 | #define MX6_BM_OVER_CUR_DIS BIT(7) | 57 | #define MX6_BM_OVER_CUR_DIS BIT(7) |
58 | #define MX6_BM_WAKEUP_ENABLE BIT(10) | ||
59 | #define MX6_BM_ID_WAKEUP BIT(16) | ||
60 | #define MX6_BM_VBUS_WAKEUP BIT(17) | ||
61 | #define MX6_BM_WAKEUP_INTR BIT(31) | ||
58 | 62 | ||
59 | #define VF610_OVER_CUR_DIS BIT(7) | 63 | #define VF610_OVER_CUR_DIS BIT(7) |
60 | 64 | ||
@@ -63,6 +67,8 @@ struct usbmisc_ops { | |||
63 | int (*init)(struct imx_usbmisc_data *data); | 67 | int (*init)(struct imx_usbmisc_data *data); |
64 | /* It's called once after adding a usb device */ | 68 | /* It's called once after adding a usb device */ |
65 | int (*post)(struct imx_usbmisc_data *data); | 69 | int (*post)(struct imx_usbmisc_data *data); |
70 | /* It's called when we need to enable/disable usb wakeup */ | ||
71 | int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled); | ||
66 | }; | 72 | }; |
67 | 73 | ||
68 | struct imx_usbmisc { | 74 | struct imx_usbmisc { |
@@ -202,6 +208,35 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data) | |||
202 | return 0; | 208 | return 0; |
203 | } | 209 | } |
204 | 210 | ||
211 | static int usbmisc_imx6q_set_wakeup | ||
212 | (struct imx_usbmisc_data *data, bool enabled) | ||
213 | { | ||
214 | struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | ||
215 | unsigned long flags; | ||
216 | u32 val; | ||
217 | u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE | | ||
218 | MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP); | ||
219 | int ret = 0; | ||
220 | |||
221 | if (data->index > 3) | ||
222 | return -EINVAL; | ||
223 | |||
224 | spin_lock_irqsave(&usbmisc->lock, flags); | ||
225 | val = readl(usbmisc->base + data->index * 4); | ||
226 | if (enabled) { | ||
227 | val |= wakeup_setting; | ||
228 | writel(val, usbmisc->base + data->index * 4); | ||
229 | } else { | ||
230 | if (val & MX6_BM_WAKEUP_INTR) | ||
231 | pr_debug("wakeup int at ci_hdrc.%d\n", data->index); | ||
232 | val &= ~wakeup_setting; | ||
233 | writel(val, usbmisc->base + data->index * 4); | ||
234 | } | ||
235 | spin_unlock_irqrestore(&usbmisc->lock, flags); | ||
236 | |||
237 | return ret; | ||
238 | } | ||
239 | |||
205 | static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) | 240 | static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) |
206 | { | 241 | { |
207 | struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 242 | struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); |
@@ -219,6 +254,8 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) | |||
219 | spin_unlock_irqrestore(&usbmisc->lock, flags); | 254 | spin_unlock_irqrestore(&usbmisc->lock, flags); |
220 | } | 255 | } |
221 | 256 | ||
257 | usbmisc_imx6q_set_wakeup(data, false); | ||
258 | |||
222 | return 0; | 259 | return 0; |
223 | } | 260 | } |
224 | 261 | ||
@@ -256,6 +293,7 @@ static const struct usbmisc_ops imx53_usbmisc_ops = { | |||
256 | }; | 293 | }; |
257 | 294 | ||
258 | static const struct usbmisc_ops imx6q_usbmisc_ops = { | 295 | static const struct usbmisc_ops imx6q_usbmisc_ops = { |
296 | .set_wakeup = usbmisc_imx6q_set_wakeup, | ||
259 | .init = usbmisc_imx6q_init, | 297 | .init = usbmisc_imx6q_init, |
260 | }; | 298 | }; |
261 | 299 | ||
@@ -291,6 +329,20 @@ int imx_usbmisc_init_post(struct imx_usbmisc_data *data) | |||
291 | } | 329 | } |
292 | EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); | 330 | EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); |
293 | 331 | ||
332 | int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled) | ||
333 | { | ||
334 | struct imx_usbmisc *usbmisc; | ||
335 | |||
336 | if (!data) | ||
337 | return 0; | ||
338 | |||
339 | usbmisc = dev_get_drvdata(data->dev); | ||
340 | if (!usbmisc->ops->set_wakeup) | ||
341 | return 0; | ||
342 | return usbmisc->ops->set_wakeup(data, enabled); | ||
343 | } | ||
344 | EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup); | ||
345 | |||
294 | static const struct of_device_id usbmisc_imx_dt_ids[] = { | 346 | static const struct of_device_id usbmisc_imx_dt_ids[] = { |
295 | { | 347 | { |
296 | .compatible = "fsl,imx25-usbmisc", | 348 | .compatible = "fsl,imx25-usbmisc", |