Support switching of USB mode between host and device port Index: linux-2.6.20.4/arch/arm/mach-s3c2410/usb-modeswitch.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.20.4/arch/arm/mach-s3c2410/usb-modeswitch.c 2007-04-01 12:36:49.000000000 +0200 @@ -0,0 +1,33 @@ +/* + * linux/arch/arm/mach-s3c2410/usb-modeswitch.c + * + * S3C2410 USB Host/Device switch + * + * Copyright (C) 2007 by OpenMoko, Inc. + * Author: Harald Welte + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +void s3c2410_usb_enable_host(int on) +{ + s3c2410_modify_misccr(S3C2410_MISCCR_HSBHOST, + on ? S3C2410_MISCCR_USBHOST : 0); +} + + Index: linux-2.6.20.4/drivers/usb/host/ohci-s3c2410.c =================================================================== --- linux-2.6.20.4.orig/drivers/usb/host/ohci-s3c2410.c 2007-04-01 12:33:01.000000000 +0200 +++ linux-2.6.20.4/drivers/usb/host/ohci-s3c2410.c 2007-04-01 12:36:49.000000000 +0200 @@ -24,6 +24,7 @@ #include #include +#include #define valid_port(idx) ((idx) == 1 || (idx) == 2) @@ -308,6 +309,40 @@ local_irq_restore(flags); } +/* switching of USB pads */ +static ssize_t show_usb_mode(struct device *dev, struct device_attribute *attr, + char *buf) +{ + if (__raw_readl(S3C24XX_MISCCR) & S3C2410_MISCCR_USBHOST) + return sprintf(buf, "host\n"); + + return sprintf(buf, "device\n"); +} + +static ssize_t set_usb_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + if (!strncmp(buf, "host", 4)) { + printk("s3c2410: changing usb to host\n"); + s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, + S3C2410_MISCCR_USBHOST); + /* FIXME: + * - call machine-specific disable-pullup function i + * - enable +Vbus (if hardware supports it) + */ + s3c2410_gpio_setpin(S3C2410_GPE5, 0); + } else if (!strncmp(buf, "device", 6)) { + printk("s3c2410: changing usb to device\n"); + s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, 0); + s3c2410_gpio_setpin(S3C2410_GPE5, 1); + } else + printk("s3c2410: unknown mode\n"); + return -EINVAL; + return count; +} + +static DEVICE_ATTR(usb_mode, S_IRUGO | S_IWUSR, show_usb_mode, set_usb_mode); + /* may be called without controller electrically present */ /* may be called with controller, bus, and devices active */ @@ -325,6 +360,7 @@ static void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) { + device_remove_file(&dev->dev, &dev_attr_usb_mode); usb_remove_hcd(hcd); s3c2410_stop_hc(dev); iounmap(hcd->regs); @@ -392,8 +428,15 @@ if (retval != 0) goto err_ioremap; + retval = device_create_file(&dev->dev, &dev_attr_usb_mode); + if (retval != 0) + goto err_hcd; + return 0; + err_hcd: + usb_remove_hcd(hcd); + err_ioremap: s3c2410_stop_hc(dev); iounmap(hcd->regs);