aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/pch_udc.c
diff options
context:
space:
mode:
authorTomoya MORINAGA <tomoya.rohm@gmail.com>2012-02-03 02:35:26 -0500
committerFelipe Balbi <balbi@ti.com>2012-02-09 02:56:53 -0500
commitdd63180b758d5972fc90621af0741d5bfae1a684 (patch)
tree0340c73c18cfac563b8b445cc79c74c2ab7d3ba7 /drivers/usb/gadget/pch_udc.c
parent20edfbb6a17f3007c1905e9849d8d306e318883b (diff)
usb: gadget: pch_udc: Detecting VBUS through GPIO
Problem: In USB Suspend, pch_udc handles 'disconnect'. Root cause: The current pch_udc is not monitoring VBUS. When USB cable is disconnected, USB Device Controller generates an interrupt of USB Suspend. pch_udc cannot distinguish it is USB Suspend or disconnect. Therefore, pch_udc handles 'disconnect' after an interrupt of USB Suspend happend. Solution: VBUS is detected through GPIO. After an interrupt produced USB Suspend, if VBUS is Low, pch_udc handles 'disconnect'. If VBUS is High, pch_udc handles 'suspend'. Signed-off-by: Tomoya MORINAGA <tomoya.rohm@gmail.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/pch_udc.c')
-rw-r--r--drivers/usb/gadget/pch_udc.c145
1 files changed, 142 insertions, 3 deletions
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 82416aae816..9c5ae2c1014 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -15,6 +15,13 @@
15#include <linux/interrupt.h> 15#include <linux/interrupt.h>
16#include <linux/usb/ch9.h> 16#include <linux/usb/ch9.h>
17#include <linux/usb/gadget.h> 17#include <linux/usb/gadget.h>
18#include <linux/gpio.h>
19
20/* GPIO port for VBUS detecting */
21static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */
22
23#define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */
24#define PCH_VBUS_INTERVAL 10 /* VBUS polling interval (msec) */
18 25
19/* Address offset of Registers */ 26/* Address offset of Registers */
20#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */ 27#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */
@@ -296,6 +303,17 @@ struct pch_udc_ep {
296}; 303};
297 304
298/** 305/**
306 * struct pch_vbus_gpio_data - Structure holding GPIO informaton
307 * for detecting VBUS
308 * @port: gpio port number
309 * @irq_work_fall Structure for WorkQueue
310 */
311struct pch_vbus_gpio_data {
312 int port;
313 struct work_struct irq_work_fall;
314};
315
316/**
299 * struct pch_udc_dev - Structure holding complete information 317 * struct pch_udc_dev - Structure holding complete information
300 * of the PCH USB device 318 * of the PCH USB device
301 * @gadget: gadget driver data 319 * @gadget: gadget driver data
@@ -323,6 +341,7 @@ struct pch_udc_ep {
323 * @base_addr: for mapped device memory 341 * @base_addr: for mapped device memory
324 * @irq: IRQ line for the device 342 * @irq: IRQ line for the device
325 * @cfg_data: current cfg, intf, and alt in use 343 * @cfg_data: current cfg, intf, and alt in use
344 * @vbus_gpio: GPIO informaton for detecting VBUS
326 */ 345 */
327struct pch_udc_dev { 346struct pch_udc_dev {
328 struct usb_gadget gadget; 347 struct usb_gadget gadget;
@@ -349,7 +368,8 @@ struct pch_udc_dev {
349 unsigned long phys_addr; 368 unsigned long phys_addr;
350 void __iomem *base_addr; 369 void __iomem *base_addr;
351 unsigned irq; 370 unsigned irq;
352 struct pch_udc_cfg_data cfg_data; 371 struct pch_udc_cfg_data cfg_data;
372 struct pch_vbus_gpio_data vbus_gpio;
353}; 373};
354 374
355#define PCH_UDC_PCI_BAR 1 375#define PCH_UDC_PCI_BAR 1
@@ -1226,6 +1246,115 @@ static const struct usb_gadget_ops pch_udc_ops = {
1226}; 1246};
1227 1247
1228/** 1248/**
1249 * pch_vbus_gpio_get_value() - This API gets value of GPIO port as VBUS status.
1250 * @dev: Reference to the driver structure
1251 *
1252 * Return value:
1253 * 1: VBUS is high
1254 * 0: VBUS is low
1255 * -1: It is not enable to detect VBUS using GPIO
1256 */
1257static int pch_vbus_gpio_get_value(struct pch_udc_dev *dev)
1258{
1259 int vbus = 0;
1260
1261 if (dev->vbus_gpio.port)
1262 vbus = gpio_get_value(dev->vbus_gpio.port) ? 1 : 0;
1263 else
1264 vbus = -1;
1265
1266 return vbus;
1267}
1268
1269/**
1270 * pch_vbus_gpio_work_fall() - This API keeps watch on VBUS becoming Low.
1271 * If VBUS is Low, disconnect is processed
1272 * @irq_work: Structure for WorkQueue
1273 *
1274 */
1275static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
1276{
1277 struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
1278 struct pch_vbus_gpio_data, irq_work_fall);
1279 struct pch_udc_dev *dev =
1280 container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
1281 int vbus_saved = -1;
1282 int vbus;
1283 int count;
1284
1285 if (!dev->vbus_gpio.port)
1286 return;
1287
1288 for (count = 0; count < (PCH_VBUS_PERIOD / PCH_VBUS_INTERVAL);
1289 count++) {
1290 vbus = pch_vbus_gpio_get_value(dev);
1291
1292 if ((vbus_saved == vbus) && (vbus == 0)) {
1293 dev_dbg(&dev->pdev->dev, "VBUS fell");
1294 if (dev->driver
1295 && dev->driver->disconnect) {
1296 dev->driver->disconnect(
1297 &dev->gadget);
1298 }
1299 pch_udc_reconnect(dev);
1300 dev_dbg(&dev->pdev->dev, "VBUS fell");
1301 return;
1302 }
1303 vbus_saved = vbus;
1304 mdelay(PCH_VBUS_INTERVAL);
1305 }
1306}
1307
1308/**
1309 * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
1310 * @dev: Reference to the driver structure
1311 * @vbus_gpio Number of GPIO port to detect gpio
1312 *
1313 * Return codes:
1314 * 0: Success
1315 * -EINVAL: GPIO port is invalid or can't be initialized.
1316 */
1317static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
1318{
1319 int err;
1320
1321 dev->vbus_gpio.port = 0;
1322
1323 if (vbus_gpio_port <= -1)
1324 return -EINVAL;
1325
1326 err = gpio_is_valid(vbus_gpio_port);
1327 if (!err) {
1328 pr_err("%s: gpio port %d is invalid\n",
1329 __func__, vbus_gpio_port);
1330 return -EINVAL;
1331 }
1332
1333 err = gpio_request(vbus_gpio_port, "pch_vbus");
1334 if (err) {
1335 pr_err("%s: can't request gpio port %d, err: %d\n",
1336 __func__, vbus_gpio_port, err);
1337 return -EINVAL;
1338 }
1339
1340 dev->vbus_gpio.port = vbus_gpio_port;
1341 gpio_direction_input(vbus_gpio_port);
1342 INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall);
1343
1344 return 0;
1345}
1346
1347/**
1348 * pch_vbus_gpio_free() - This API frees resources of GPIO port
1349 * @dev: Reference to the driver structure
1350 */
1351static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
1352{
1353 if (dev->vbus_gpio.port)
1354 gpio_free(dev->vbus_gpio.port);
1355}
1356
1357/**
1229 * complete_req() - This API is invoked from the driver when processing 1358 * complete_req() - This API is invoked from the driver when processing
1230 * of a request is complete 1359 * of a request is complete
1231 * @ep: Reference to the endpoint structure 1360 * @ep: Reference to the endpoint structure
@@ -2510,6 +2639,8 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
2510 */ 2639 */
2511static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr) 2640static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
2512{ 2641{
2642 int vbus;
2643
2513 /* USB Reset Interrupt */ 2644 /* USB Reset Interrupt */
2514 if (dev_intr & UDC_DEVINT_UR) { 2645 if (dev_intr & UDC_DEVINT_UR) {
2515 pch_udc_svc_ur_interrupt(dev); 2646 pch_udc_svc_ur_interrupt(dev);
@@ -2535,14 +2666,19 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
2535 spin_lock(&dev->lock); 2666 spin_lock(&dev->lock);
2536 } 2667 }
2537 2668
2538 if (dev->vbus_session == 0) { 2669 vbus = pch_vbus_gpio_get_value(dev);
2670 if ((dev->vbus_session == 0)
2671 && (vbus != 1)) {
2539 if (dev->driver && dev->driver->disconnect) { 2672 if (dev->driver && dev->driver->disconnect) {
2540 spin_unlock(&dev->lock); 2673 spin_unlock(&dev->lock);
2541 dev->driver->disconnect(&dev->gadget); 2674 dev->driver->disconnect(&dev->gadget);
2542 spin_lock(&dev->lock); 2675 spin_lock(&dev->lock);
2543 } 2676 }
2544 pch_udc_reconnect(dev); 2677 pch_udc_reconnect(dev);
2545 } 2678 } else if ((dev->vbus_session == 0)
2679 && (vbus == 1))
2680 schedule_work(&dev->vbus_gpio.irq_work_fall);
2681
2546 dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n"); 2682 dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
2547 } 2683 }
2548 /* Clear the SOF interrupt, if enabled */ 2684 /* Clear the SOF interrupt, if enabled */
@@ -2704,6 +2840,7 @@ static int pch_udc_pcd_init(struct pch_udc_dev *dev)
2704{ 2840{
2705 pch_udc_init(dev); 2841 pch_udc_init(dev);
2706 pch_udc_pcd_reinit(dev); 2842 pch_udc_pcd_reinit(dev);
2843 pch_vbus_gpio_init(dev, vbus_gpio_port);
2707 return 0; 2844 return 0;
2708} 2845}
2709 2846
@@ -2882,6 +3019,8 @@ static void pch_udc_remove(struct pci_dev *pdev)
2882 UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); 3019 UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
2883 kfree(dev->ep0out_buf); 3020 kfree(dev->ep0out_buf);
2884 3021
3022 pch_vbus_gpio_free(dev);
3023
2885 pch_udc_exit(dev); 3024 pch_udc_exit(dev);
2886 3025
2887 if (dev->irq_registered) 3026 if (dev->irq_registered)