aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Grzeschik <m.grzeschik@pengutronix.de>2014-10-12 21:53:03 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-03 18:34:00 -0500
commit11a7e59405148c855e0a9d13588930ccec02c150 (patch)
treea8e21a87496d8ec3fee589dfea21766d2813d58f
parente28e2f2f7c42e5b9dd4c965a0245267e44a8a7ae (diff)
usb: ehci: add ehci_port_power interface
The current EHCI implementation is prepared to toggle the PORT_POWER bit to enable or disable a USB-Port. In some cases this port power can not be just toggled by the PORT_POWER bit, and the gpio-regulator is needed to be toggled too. This patch defines a port power control interface ehci_port_power for ehci core use, it toggles PORT_POWER bit as well as calls platform defined .port_power if it is defined. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Signed-off-by: Peter Chen <peter.chen@freescale.com> Acked-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/ehci-hcd.c9
-rw-r--r--drivers/usb/host/ehci-hub.c45
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--include/linux/usb/hcd.h3
4 files changed, 45 insertions, 14 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 15feaf924b71..df75b8e7d157 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -311,6 +311,7 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci);
311static void ehci_work(struct ehci_hcd *ehci); 311static void ehci_work(struct ehci_hcd *ehci);
312static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); 312static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
313static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); 313static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
314static int ehci_port_power(struct ehci_hcd *ehci, int portnum, bool enable);
314 315
315#include "ehci-timer.c" 316#include "ehci-timer.c"
316#include "ehci-hub.c" 317#include "ehci-hub.c"
@@ -329,9 +330,13 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
329{ 330{
330 int port = HCS_N_PORTS(ehci->hcs_params); 331 int port = HCS_N_PORTS(ehci->hcs_params);
331 332
332 while (port--) 333 while (port--) {
333 ehci_writel(ehci, PORT_RWC_BITS, 334 ehci_writel(ehci, PORT_RWC_BITS,
334 &ehci->regs->port_status[port]); 335 &ehci->regs->port_status[port]);
336 spin_unlock_irq(&ehci->lock);
337 ehci_port_power(ehci, port, false);
338 spin_lock_irq(&ehci->lock);
339 }
335} 340}
336 341
337/* 342/*
@@ -1233,6 +1238,8 @@ void ehci_init_driver(struct hc_driver *drv,
1233 drv->hcd_priv_size += over->extra_priv_size; 1238 drv->hcd_priv_size += over->extra_priv_size;
1234 if (over->reset) 1239 if (over->reset)
1235 drv->reset = over->reset; 1240 drv->reset = over->reset;
1241 if (over->port_power)
1242 drv->port_power = over->port_power;
1236 } 1243 }
1237} 1244}
1238EXPORT_SYMBOL_GPL(ehci_init_driver); 1245EXPORT_SYMBOL_GPL(ehci_init_driver);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 5728829cf6ef..118edb7bdca2 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -69,10 +69,8 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
69 if (test_bit(port, &ehci->owned_ports)) { 69 if (test_bit(port, &ehci->owned_ports)) {
70 reg = &ehci->regs->port_status[port]; 70 reg = &ehci->regs->port_status[port];
71 status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 71 status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
72 if (!(status & PORT_POWER)) { 72 if (!(status & PORT_POWER))
73 status |= PORT_POWER; 73 ehci_port_power(ehci, port, true);
74 ehci_writel(ehci, status, reg);
75 }
76 } 74 }
77 } 75 }
78 76
@@ -952,9 +950,11 @@ int ehci_hub_control(
952 clear_bit(wIndex, &ehci->port_c_suspend); 950 clear_bit(wIndex, &ehci->port_c_suspend);
953 break; 951 break;
954 case USB_PORT_FEAT_POWER: 952 case USB_PORT_FEAT_POWER:
955 if (HCS_PPC (ehci->hcs_params)) 953 if (HCS_PPC(ehci->hcs_params)) {
956 ehci_writel(ehci, temp & ~PORT_POWER, 954 spin_unlock_irqrestore(&ehci->lock, flags);
957 status_reg); 955 ehci_port_power(ehci, wIndex, false);
956 spin_lock_irqsave(&ehci->lock, flags);
957 }
958 break; 958 break;
959 case USB_PORT_FEAT_C_CONNECTION: 959 case USB_PORT_FEAT_C_CONNECTION:
960 ehci_writel(ehci, temp | PORT_CSC, status_reg); 960 ehci_writel(ehci, temp | PORT_CSC, status_reg);
@@ -1004,9 +1004,9 @@ int ehci_hub_control(
1004 */ 1004 */
1005 if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle)) 1005 if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle))
1006 && HCS_PPC(ehci->hcs_params)) { 1006 && HCS_PPC(ehci->hcs_params)) {
1007 ehci_writel(ehci, 1007 spin_unlock_irqrestore(&ehci->lock, flags);
1008 temp & ~(PORT_RWC_BITS | PORT_POWER), 1008 ehci_port_power(ehci, wIndex, false);
1009 status_reg); 1009 spin_lock_irqsave(&ehci->lock, flags);
1010 temp = ehci_readl(ehci, status_reg); 1010 temp = ehci_readl(ehci, status_reg);
1011 } 1011 }
1012 } 1012 }
@@ -1187,9 +1187,11 @@ int ehci_hub_control(
1187 set_bit(wIndex, &ehci->suspended_ports); 1187 set_bit(wIndex, &ehci->suspended_ports);
1188 break; 1188 break;
1189 case USB_PORT_FEAT_POWER: 1189 case USB_PORT_FEAT_POWER:
1190 if (HCS_PPC (ehci->hcs_params)) 1190 if (HCS_PPC(ehci->hcs_params)) {
1191 ehci_writel(ehci, temp | PORT_POWER, 1191 spin_unlock_irqrestore(&ehci->lock, flags);
1192 status_reg); 1192 ehci_port_power(ehci, wIndex, true);
1193 spin_lock_irqsave(&ehci->lock, flags);
1194 }
1193 break; 1195 break;
1194 case USB_PORT_FEAT_RESET: 1196 case USB_PORT_FEAT_RESET:
1195 if (temp & (PORT_SUSPEND|PORT_RESUME)) 1197 if (temp & (PORT_SUSPEND|PORT_RESUME))
@@ -1297,3 +1299,20 @@ static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
1297 reg = &ehci->regs->port_status[portnum - 1]; 1299 reg = &ehci->regs->port_status[portnum - 1];
1298 return ehci_readl(ehci, reg) & PORT_OWNER; 1300 return ehci_readl(ehci, reg) & PORT_OWNER;
1299} 1301}
1302
1303static int ehci_port_power(struct ehci_hcd *ehci, int portnum, bool enable)
1304{
1305 struct usb_hcd *hcd = ehci_to_hcd(ehci);
1306 u32 __iomem *status_reg = &ehci->regs->port_status[portnum];
1307 u32 temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
1308
1309 if (enable)
1310 ehci_writel(ehci, temp | PORT_POWER, status_reg);
1311 else
1312 ehci_writel(ehci, temp & ~PORT_POWER, status_reg);
1313
1314 if (hcd->driver->port_power)
1315 hcd->driver->port_power(hcd, portnum, enable);
1316
1317 return 0;
1318}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index eee228a26a0e..6f0577b0a5ae 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -859,6 +859,8 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
859struct ehci_driver_overrides { 859struct ehci_driver_overrides {
860 size_t extra_priv_size; 860 size_t extra_priv_size;
861 int (*reset)(struct usb_hcd *hcd); 861 int (*reset)(struct usb_hcd *hcd);
862 int (*port_power)(struct usb_hcd *hcd,
863 int portnum, bool enable);
862}; 864};
863 865
864extern void ehci_init_driver(struct hc_driver *drv, 866extern void ehci_init_driver(struct hc_driver *drv,
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index cd96a2bc3388..9cf7e3594609 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -379,6 +379,9 @@ struct hc_driver {
379 int (*disable_usb3_lpm_timeout)(struct usb_hcd *, 379 int (*disable_usb3_lpm_timeout)(struct usb_hcd *,
380 struct usb_device *, enum usb3_link_state state); 380 struct usb_device *, enum usb3_link_state state);
381 int (*find_raw_port_number)(struct usb_hcd *, int); 381 int (*find_raw_port_number)(struct usb_hcd *, int);
382 /* Call for power on/off the port if necessary */
383 int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable);
384
382}; 385};
383 386
384static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) 387static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)