aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2011-04-28 03:41:20 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-04-29 20:24:35 -0400
commitb002ff6e268b6024d6927a1ce330a14ca162b6ab (patch)
tree83bd5dde6f872396cd42762b59f96cf9c024d30a
parentbc57381e634782009b1cb2e86b18013699ada576 (diff)
usb: renesas_usbhs: add autonomy mode
Current renesas_usbhs was designed to save power when USB is not connected. And it assumed platform uses callback to notify connection/disconnection by external interrupt. But some SuperH / platform board doesn't have such feature. This patch adds autonomy mode which detect USB connection/disconnection by internal interrupt. But power will be always ON when autonomy mode is selected. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/renesas_usbhs/common.c36
-rw-r--r--drivers/usb/renesas_usbhs/common.h3
-rw-r--r--drivers/usb/renesas_usbhs/mod.c48
-rw-r--r--drivers/usb/renesas_usbhs/mod.h15
4 files changed, 95 insertions, 7 deletions
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 9a75a45687b..34e68e0205c 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -21,6 +21,14 @@
21#include <linux/sysfs.h> 21#include <linux/sysfs.h>
22#include "./common.h" 22#include "./common.h"
23 23
24#define USBHSF_RUNTIME_PWCTRL (1 << 0)
25
26/* status */
27#define usbhsc_flags_init(p) do {(p)->flags = 0; } while (0)
28#define usbhsc_flags_set(p, b) ((p)->flags |= (b))
29#define usbhsc_flags_clr(p, b) ((p)->flags &= ~(b))
30#define usbhsc_flags_has(p, b) ((p)->flags & (b))
31
24/* 32/*
25 * platform call back 33 * platform call back
26 * 34 *
@@ -203,7 +211,8 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
203 dev_dbg(&pdev->dev, "%s enable\n", __func__); 211 dev_dbg(&pdev->dev, "%s enable\n", __func__);
204 212
205 /* power on */ 213 /* power on */
206 usbhsc_power_ctrl(priv, enable); 214 if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
215 usbhsc_power_ctrl(priv, enable);
207 216
208 /* module start */ 217 /* module start */
209 usbhs_mod_call(priv, start, priv); 218 usbhs_mod_call(priv, start, priv);
@@ -215,7 +224,8 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
215 usbhs_mod_call(priv, stop, priv); 224 usbhs_mod_call(priv, stop, priv);
216 225
217 /* power off */ 226 /* power off */
218 usbhsc_power_ctrl(priv, enable); 227 if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
228 usbhsc_power_ctrl(priv, enable);
219 229
220 usbhs_mod_change(priv, -1); 230 usbhs_mod_change(priv, -1);
221 231
@@ -252,8 +262,7 @@ static int __devinit usbhs_probe(struct platform_device *pdev)
252 262
253 /* check platform information */ 263 /* check platform information */
254 if (!info || 264 if (!info ||
255 !info->platform_callback.get_id || 265 !info->platform_callback.get_id) {
256 !info->platform_callback.get_vbus) {
257 dev_err(&pdev->dev, "no platform information\n"); 266 dev_err(&pdev->dev, "no platform information\n");
258 return -EINVAL; 267 return -EINVAL;
259 } 268 }
@@ -296,6 +305,11 @@ static int __devinit usbhs_probe(struct platform_device *pdev)
296 priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); 305 priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type);
297 } 306 }
298 307
308 /* FIXME */
309 /* runtime power control ? */
310 if (priv->pfunc->get_vbus)
311 usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL);
312
299 /* 313 /*
300 * priv settings 314 * priv settings
301 */ 315 */
@@ -338,10 +352,16 @@ static int __devinit usbhs_probe(struct platform_device *pdev)
338 /* reset phy for connection */ 352 /* reset phy for connection */
339 usbhs_platform_call(priv, phy_reset, pdev); 353 usbhs_platform_call(priv, phy_reset, pdev);
340 354
355 /* power control */
356 pm_runtime_enable(&pdev->dev);
357 if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
358 usbhsc_power_ctrl(priv, 1);
359 usbhs_mod_autonomy_mode(priv);
360 }
361
341 /* 362 /*
342 * manual call notify_hotplug for cold plug 363 * manual call notify_hotplug for cold plug
343 */ 364 */
344 pm_runtime_enable(&pdev->dev);
345 ret = usbhsc_drvcllbck_notify_hotplug(pdev); 365 ret = usbhsc_drvcllbck_notify_hotplug(pdev);
346 if (ret < 0) 366 if (ret < 0)
347 goto probe_end_call_remove; 367 goto probe_end_call_remove;
@@ -376,9 +396,11 @@ static int __devexit usbhs_remove(struct platform_device *pdev)
376 396
377 dfunc->notify_hotplug = NULL; 397 dfunc->notify_hotplug = NULL;
378 398
379 pm_runtime_disable(&pdev->dev); 399 /* power off */
400 if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
401 usbhsc_power_ctrl(priv, 0);
380 402
381 usbhsc_bus_ctrl(priv, 0); 403 pm_runtime_disable(&pdev->dev);
382 404
383 usbhs_platform_call(priv, hardware_exit, pdev); 405 usbhs_platform_call(priv, hardware_exit, pdev);
384 usbhs_pipe_remove(priv); 406 usbhs_pipe_remove(priv);
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 0157eb805cf..0aadcb40276 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -105,6 +105,7 @@ struct usbhs_priv;
105#define SACKE (1 << 4) /* Setup Transaction ACK Interrupt Enable */ 105#define SACKE (1 << 4) /* Setup Transaction ACK Interrupt Enable */
106 106
107/* INTSTS0 */ 107/* INTSTS0 */
108#define VBINT (1 << 15) /* VBUS0_0 and VBUS1_0 Interrupt Status */
108#define DVST (1 << 12) /* Device State Transition Interrupt Status */ 109#define DVST (1 << 12) /* Device State Transition Interrupt Status */
109#define CTRT (1 << 11) /* Control Stage Interrupt Status */ 110#define CTRT (1 << 11) /* Control Stage Interrupt Status */
110#define BEMP (1 << 10) /* Buffer Empty Interrupt Status */ 111#define BEMP (1 << 10) /* Buffer Empty Interrupt Status */
@@ -182,6 +183,8 @@ struct usbhs_priv {
182 183
183 spinlock_t lock; 184 spinlock_t lock;
184 185
186 u32 flags;
187
185 /* 188 /*
186 * module control 189 * module control
187 */ 190 */
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index d0f5f67e074..a577f8f4064 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -20,6 +20,48 @@
20#include "./mod.h" 20#include "./mod.h"
21 21
22#define usbhs_priv_to_modinfo(priv) (&priv->mod_info) 22#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
23#define usbhs_mod_info_call(priv, func, param...) \
24({ \
25 struct usbhs_mod_info *info; \
26 info = usbhs_priv_to_modinfo(priv); \
27 !info->func ? 0 : \
28 info->func(param); \
29})
30
31/*
32 * autonomy
33 *
34 * these functions are used if platform doesn't have external phy.
35 * -> there is no "notify_hotplug" callback from platform
36 * -> call "notify_hotplug" by itself
37 * -> use own interrupt to connect/disconnect
38 * -> it mean module clock is always ON
39 * ~~~~~~~~~~~~~~~~~~~~~~~~~
40 */
41static int usbhsm_autonomy_get_vbus(struct platform_device *pdev)
42{
43 struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
44
45 return VBSTS & usbhs_read(priv, INTSTS0);
46}
47
48static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,
49 struct usbhs_irq_state *irq_state)
50{
51 struct platform_device *pdev = usbhs_priv_to_pdev(priv);
52
53 return usbhsc_drvcllbck_notify_hotplug(pdev);
54}
55
56void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
57{
58 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
59
60 info->irq_vbus = usbhsm_autonomy_irq_vbus;
61 priv->pfunc->get_vbus = usbhsm_autonomy_get_vbus;
62
63 usbhs_irq_callback_update(priv, NULL);
64}
23 65
24/* 66/*
25 * host / gadget functions 67 * host / gadget functions
@@ -227,6 +269,9 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
227 * see also 269 * see also
228 * usbhs_irq_setting_update 270 * usbhs_irq_setting_update
229 */ 271 */
272 if (irq_state.intsts0 & VBINT)
273 usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state);
274
230 if (irq_state.intsts0 & DVST) 275 if (irq_state.intsts0 & DVST)
231 usbhs_mod_call(priv, irq_dev_state, priv, &irq_state); 276 usbhs_mod_call(priv, irq_dev_state, priv, &irq_state);
232 277
@@ -245,6 +290,7 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
245void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) 290void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
246{ 291{
247 u16 intenb0 = 0; 292 u16 intenb0 = 0;
293 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
248 294
249 usbhs_write(priv, INTENB0, 0); 295 usbhs_write(priv, INTENB0, 0);
250 296
@@ -260,6 +306,8 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
260 * it don't enable DVSE (intenb0) here 306 * it don't enable DVSE (intenb0) here
261 * but "mod->irq_dev_state" will be called. 307 * but "mod->irq_dev_state" will be called.
262 */ 308 */
309 if (info->irq_vbus)
310 intenb0 |= VBSE;
263 311
264 if (mod) { 312 if (mod) {
265 if (mod->irq_ctrl_stage) 313 if (mod->irq_ctrl_stage)
diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h
index 8644191e164..5c845a28a21 100644
--- a/drivers/usb/renesas_usbhs/mod.h
+++ b/drivers/usb/renesas_usbhs/mod.h
@@ -68,6 +68,19 @@ struct usbhs_mod {
68struct usbhs_mod_info { 68struct usbhs_mod_info {
69 struct usbhs_mod *mod[USBHS_MAX]; 69 struct usbhs_mod *mod[USBHS_MAX];
70 struct usbhs_mod *curt; /* current mod */ 70 struct usbhs_mod *curt; /* current mod */
71
72 /*
73 * INTSTS0 :: VBINT
74 *
75 * This function will be used as autonomy mode
76 * when platform cannot call notify_hotplug.
77 *
78 * This callback cannot be member of "struct usbhs_mod"
79 * because it will be used even though
80 * host/gadget has not been selected.
81 */
82 int (*irq_vbus)(struct usbhs_priv *priv,
83 struct usbhs_irq_state *irq_state);
71}; 84};
72 85
73/* 86/*
@@ -81,6 +94,8 @@ int usbhs_mod_change(struct usbhs_priv *priv, int id);
81int usbhs_mod_probe(struct usbhs_priv *priv); 94int usbhs_mod_probe(struct usbhs_priv *priv);
82void usbhs_mod_remove(struct usbhs_priv *priv); 95void usbhs_mod_remove(struct usbhs_priv *priv);
83 96
97void usbhs_mod_autonomy_mode(struct usbhs_priv *priv);
98
84/* 99/*
85 * status functions 100 * status functions
86 */ 101 */