Save sram context after changing MPU, DSP or core clocks
[linux-ginger.git] / drivers / cbus / tahvo-usb.c
blobc08f08de710543623258f538b597f926a030f6c6
1 /**
2 * drivers/cbus/tahvo-usb.c
4 * Tahvo USB transeiver
6 * Copyright (C) 2005-2006 Nokia Corporation
8 * Parts copied from drivers/i2c/chips/isp1301_omap.c
9 * Copyright (C) 2004 Texas Instruments
10 * Copyright (C) 2004 David Brownell
12 * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
13 * Tony Lindgren <tony@atomide.com>, and
14 * Timo Teräs <timo.teras@nokia.com>
16 * This file is subject to the terms and conditions of the GNU General
17 * Public License. See the file "COPYING" in the main directory of this
18 * archive for more details.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/init.h>
33 #include <linux/slab.h>
34 #include <linux/io.h>
35 #include <linux/interrupt.h>
36 #include <linux/platform_device.h>
37 #include <linux/usb/ch9.h>
38 #include <linux/usb/gadget.h>
39 #include <linux/usb.h>
40 #include <linux/usb/otg.h>
41 #include <linux/i2c.h>
42 #include <linux/workqueue.h>
43 #include <linux/kobject.h>
44 #include <linux/clk.h>
45 #include <linux/mutex.h>
47 #include <asm/irq.h>
48 #include <plat/usb.h>
50 #include "cbus.h"
51 #include "tahvo.h"
53 #define DRIVER_NAME "tahvo-usb"
55 #define USBR_SLAVE_CONTROL (1 << 8)
56 #define USBR_VPPVIO_SW (1 << 7)
57 #define USBR_SPEED (1 << 6)
58 #define USBR_REGOUT (1 << 5)
59 #define USBR_MASTER_SW2 (1 << 4)
60 #define USBR_MASTER_SW1 (1 << 3)
61 #define USBR_SLAVE_SW (1 << 2)
62 #define USBR_NSUSPEND (1 << 1)
63 #define USBR_SEMODE (1 << 0)
65 /* bits in OTG_CTRL */
67 /* Bits that are controlled by OMAP OTG and are read-only */
68 #define OTG_CTRL_OMAP_MASK (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|\
69 OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
70 /* Bits that are controlled by transceiver */
71 #define OTG_CTRL_XCVR_MASK (OTG_ASESSVLD|OTG_BSESSEND|\
72 OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
73 /* Bits that are controlled by system */
74 #define OTG_CTRL_SYS_MASK (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|\
75 OTG_B_HNPEN|OTG_BUSDROP)
77 #if defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OTG)
78 #error tahvo-otg.c does not work with OCHI yet!
79 #endif
81 #define TAHVO_MODE_HOST 0
82 #define TAHVO_MODE_PERIPHERAL 1
84 #ifdef CONFIG_USB_OTG
85 #define TAHVO_MODE(tu) (tu)->tahvo_mode
86 #elif defined(CONFIG_USB_GADGET_OMAP)
87 #define TAHVO_MODE(tu) TAHVO_MODE_PERIPHERAL
88 #else
89 #define TAHVO_MODE(tu) TAHVO_MODE_HOST
90 #endif
92 struct tahvo_usb {
93 struct platform_device *pt_dev;
94 struct otg_transceiver otg;
95 int vbus_state;
96 struct work_struct irq_work;
97 struct mutex serialize;
98 #ifdef CONFIG_USB_OTG
99 int tahvo_mode;
100 #endif
102 static struct platform_device tahvo_usb_device;
105 * ---------------------------------------------------------------------------
106 * OTG related functions
108 * These shoud be separated into omap-otg.c driver module, as they are used
109 * by various transceivers. These functions are needed in the UDC-only case
110 * as well. These functions are copied from GPL isp1301_omap.c
111 * ---------------------------------------------------------------------------
113 static struct platform_device *tahvo_otg_dev;
115 static irqreturn_t omap_otg_irq(int irq, void *arg)
117 struct platform_device *otg_dev = (struct platform_device *) arg;
118 struct tahvo_usb *tu = (struct tahvo_usb *) otg_dev->dev.driver_data;
119 u16 otg_irq;
121 otg_irq = omap_readw(OTG_IRQ_SRC);
122 if (otg_irq & OPRT_CHG) {
123 omap_writew(OPRT_CHG, OTG_IRQ_SRC);
124 } else if (otg_irq & B_SRP_TMROUT) {
125 omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
126 } else if (otg_irq & B_HNP_FAIL) {
127 omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
128 } else if (otg_irq & A_SRP_DETECT) {
129 omap_writew(A_SRP_DETECT, OTG_IRQ_SRC);
130 } else if (otg_irq & A_REQ_TMROUT) {
131 omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
132 } else if (otg_irq & A_VBUS_ERR) {
133 omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
134 } else if (otg_irq & DRIVER_SWITCH) {
135 if ((!(omap_readl(OTG_CTRL) & OTG_DRIVER_SEL)) &&
136 tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) {
137 /* role is host */
138 usb_bus_start_enum(tu->otg.host,
139 tu->otg.host->otg_port);
141 omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC);
142 } else
143 return IRQ_NONE;
145 return IRQ_HANDLED;
149 static int omap_otg_init(void)
151 u32 l;
153 #ifdef CONFIG_USB_OTG
154 if (!tahvo_otg_dev) {
155 printk("tahvo-usb: no tahvo_otg_dev\n");
156 return -ENODEV;
158 #endif
160 l = omap_readl(OTG_SYSCON_1);
161 l &= ~OTG_IDLE_EN;
162 omap_writel(l, OTG_SYSCON_1);
163 udelay(100);
165 /* some of these values are board-specific... */
166 l = omap_readl(OTG_SYSCON_2);
167 l |= OTG_EN
168 /* for B-device: */
169 | SRP_GPDATA /* 9msec Bdev D+ pulse */
170 | SRP_GPDVBUS /* discharge after VBUS pulse */
171 // | (3 << 24) /* 2msec VBUS pulse */
172 /* for A-device: */
173 | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */
174 | SRP_DPW /* detect 167+ns SRP pulses */
175 | SRP_DATA | SRP_VBUS; /* accept both kinds of SRP pulse */
176 omap_writel(l, OTG_SYSCON_2);
178 omap_writew(DRIVER_SWITCH | OPRT_CHG
179 | B_SRP_TMROUT | B_HNP_FAIL
180 | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT,
181 OTG_IRQ_EN);
182 l = omap_readl(OTG_SYSCON_2);
183 l |= OTG_EN;
184 omap_writel(l, OTG_SYSCON_2);
186 return 0;
189 static int omap_otg_probe(struct device *dev)
191 int ret;
193 tahvo_otg_dev = to_platform_device(dev);
194 ret = omap_otg_init();
195 if (ret != 0) {
196 printk(KERN_ERR "tahvo-usb: omap_otg_init failed\n");
197 return ret;
200 return request_irq(tahvo_otg_dev->resource[1].start,
201 omap_otg_irq, IRQF_DISABLED, DRIVER_NAME,
202 &tahvo_usb_device);
205 static int omap_otg_remove(struct device *dev)
207 free_irq(tahvo_otg_dev->resource[1].start, &tahvo_usb_device);
208 tahvo_otg_dev = NULL;
210 return 0;
213 struct device_driver omap_otg_driver = {
214 .name = "omap_otg",
215 .bus = &platform_bus_type,
216 .probe = omap_otg_probe,
217 .remove = omap_otg_remove,
221 * ---------------------------------------------------------------------------
222 * Tahvo related functions
223 * These are Nokia proprietary code, except for the OTG register settings,
224 * which are copied from isp1301.c
225 * ---------------------------------------------------------------------------
227 static ssize_t vbus_state_show(struct device *device,
228 struct device_attribute *attr, char *buf)
230 struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
231 return sprintf(buf, "%d\n", tu->vbus_state);
233 static DEVICE_ATTR(vbus_state, 0444, vbus_state_show, NULL);
235 int vbus_active = 0;
237 #if 0
239 static int host_suspend(struct tahvo_usb *tu)
241 struct device *dev;
243 if (!tu->otg.host)
244 return -ENODEV;
246 /* Currently ASSUMES only the OTG port matters;
247 * other ports could be active...
249 dev = tu->otg.host->controller;
250 return dev->driver->suspend(dev, PMSG_SUSPEND);
253 static int host_resume(struct tahvo_usb *tu)
255 struct device *dev;
257 if (!tu->otg.host)
258 return -ENODEV;
260 dev = tu->otg.host->controller;
261 return dev->driver->resume(dev);
264 #else
266 static int host_suspend(struct tahvo_usb *tu)
268 return 0;
271 static int host_resume(struct tahvo_usb *tu)
273 return 0;
276 #endif
278 static void check_vbus_state(struct tahvo_usb *tu)
280 int reg, prev_state;
282 reg = tahvo_read_reg(TAHVO_REG_IDSR);
283 if (reg & 0x01) {
284 u32 l;
286 vbus_active = 1;
287 switch (tu->otg.state) {
288 case OTG_STATE_B_IDLE:
289 /* Enable the gadget driver */
290 if (tu->otg.gadget)
291 usb_gadget_vbus_connect(tu->otg.gadget);
292 /* Set B-session valid and not B-sessio ended to indicate
293 * Vbus to be ok. */
294 l = omap_readl(OTG_CTRL);
295 l &= ~OTG_BSESSEND;
296 l |= OTG_BSESSVLD;
297 omap_writel(l, OTG_CTRL);
299 tu->otg.state = OTG_STATE_B_PERIPHERAL;
300 break;
301 case OTG_STATE_A_IDLE:
302 /* Session is now valid assuming the USB hub is driving Vbus */
303 tu->otg.state = OTG_STATE_A_HOST;
304 host_resume(tu);
305 break;
306 default:
307 break;
309 printk("USB cable connected\n");
310 } else {
311 switch (tu->otg.state) {
312 case OTG_STATE_B_PERIPHERAL:
313 if (tu->otg.gadget)
314 usb_gadget_vbus_disconnect(tu->otg.gadget);
315 tu->otg.state = OTG_STATE_B_IDLE;
316 break;
317 case OTG_STATE_A_HOST:
318 tu->otg.state = OTG_STATE_A_IDLE;
319 break;
320 default:
321 break;
323 printk("USB cable disconnected\n");
324 vbus_active = 0;
327 prev_state = tu->vbus_state;
328 tu->vbus_state = reg & 0x01;
329 if (prev_state != tu->vbus_state)
330 sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state");
333 static void tahvo_usb_become_host(struct tahvo_usb *tu)
335 u32 l;
337 /* Clear system and transceiver controlled bits
338 * also mark the A-session is always valid */
339 omap_otg_init();
341 l = omap_readl(OTG_CTRL);
342 l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK);
343 l |= OTG_ASESSVLD;
344 omap_writel(l, OTG_CTRL);
346 /* Power up the transceiver in USB host mode */
347 tahvo_write_reg(TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
348 USBR_MASTER_SW2 | USBR_MASTER_SW1);
349 tu->otg.state = OTG_STATE_A_IDLE;
351 check_vbus_state(tu);
354 static void tahvo_usb_stop_host(struct tahvo_usb *tu)
356 host_suspend(tu);
357 tu->otg.state = OTG_STATE_A_IDLE;
360 static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
362 u32 l;
364 /* Clear system and transceiver controlled bits
365 * and enable ID to mark peripheral mode and
366 * BSESSEND to mark no Vbus */
367 omap_otg_init();
368 l = omap_readl(OTG_CTRL);
369 l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
370 l |= OTG_ID | OTG_BSESSEND;
371 omap_writel(l, OTG_CTRL);
373 /* Power up transceiver and set it in USB perhiperal mode */
374 tahvo_write_reg(TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | USBR_NSUSPEND | USBR_SLAVE_SW);
375 tu->otg.state = OTG_STATE_B_IDLE;
377 check_vbus_state(tu);
380 static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
382 u32 l;
384 l = omap_readl(OTG_CTRL);
385 l &= ~OTG_BSESSVLD;
386 l |= OTG_BSESSEND;
387 omap_writel(l, OTG_CTRL);
389 if (tu->otg.gadget)
390 usb_gadget_vbus_disconnect(tu->otg.gadget);
391 tu->otg.state = OTG_STATE_B_IDLE;
395 static void tahvo_usb_power_off(struct tahvo_usb *tu)
397 u32 l;
398 int id;
400 /* Disable gadget controller if any */
401 if (tu->otg.gadget)
402 usb_gadget_vbus_disconnect(tu->otg.gadget);
404 host_suspend(tu);
406 /* Disable OTG and interrupts */
407 if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
408 id = OTG_ID;
409 else
410 id = 0;
411 l = omap_readl(OTG_CTRL);
412 l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
413 l |= id | OTG_BSESSEND;
414 omap_writel(l, OTG_CTRL);
415 omap_writew(0, OTG_IRQ_EN);
417 l = omap_readl(OTG_SYSCON_2);
418 l &= ~OTG_EN;
419 omap_writel(l, OTG_SYSCON_2);
421 l = omap_readl(OTG_SYSCON_1);
422 l |= OTG_IDLE_EN;
423 omap_writel(l, OTG_SYSCON_1);
425 /* Power off transceiver */
426 tahvo_write_reg(TAHVO_REG_USBR, 0);
427 tu->otg.state = OTG_STATE_UNDEFINED;
431 static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA)
433 struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
435 dev_dbg(&tu->pt_dev->dev, "set_power %d mA\n", mA);
437 if (dev->state == OTG_STATE_B_PERIPHERAL) {
438 /* REVISIT: Can Tahvo charge battery from VBUS? */
440 return 0;
443 static int tahvo_usb_set_suspend(struct otg_transceiver *dev, int suspend)
445 struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
446 u16 w;
448 dev_dbg(&tu->pt_dev->dev, "set_suspend\n");
450 w = tahvo_read_reg(TAHVO_REG_USBR);
451 if (suspend)
452 w &= ~USBR_NSUSPEND;
453 else
454 w |= USBR_NSUSPEND;
455 tahvo_write_reg(TAHVO_REG_USBR, w);
457 return 0;
460 static int tahvo_usb_start_srp(struct otg_transceiver *dev)
462 struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
463 u32 otg_ctrl;
465 dev_dbg(&tu->pt_dev->dev, "start_srp\n");
467 if (!dev || tu->otg.state != OTG_STATE_B_IDLE)
468 return -ENODEV;
470 otg_ctrl = omap_readl(OTG_CTRL);
471 if (!(otg_ctrl & OTG_BSESSEND))
472 return -EINVAL;
474 otg_ctrl |= OTG_B_BUSREQ;
475 otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_SYS_MASK;
476 omap_writel(otg_ctrl, OTG_CTRL);
477 tu->otg.state = OTG_STATE_B_SRP_INIT;
479 return 0;
482 static int tahvo_usb_start_hnp(struct otg_transceiver *otg)
484 struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
486 dev_dbg(&tu->pt_dev->dev, "start_hnp\n");
487 #ifdef CONFIG_USB_OTG
488 /* REVISIT: Add this for OTG */
489 #endif
490 return -EINVAL;
493 static int tahvo_usb_set_host(struct otg_transceiver *otg, struct usb_bus *host)
495 struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
496 u32 l;
498 dev_dbg(&tu->pt_dev->dev, "set_host %p\n", host);
500 if (otg == NULL)
501 return -ENODEV;
503 #if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP)
505 mutex_lock(&tu->serialize);
507 if (host == NULL) {
508 if (TAHVO_MODE(tu) == TAHVO_MODE_HOST)
509 tahvo_usb_power_off(tu);
510 tu->otg.host = NULL;
511 mutex_unlock(&tu->serialize);
512 return 0;
515 l = omap_readl(OTG_SYSCON_1);
516 l &= ~(OTG_IDLE_EN | HST_IDLE_EN | DEV_IDLE_EN);
517 omap_writel(l, OTG_SYSCON_1);
519 if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) {
520 tu->otg.host = NULL;
521 tahvo_usb_become_host(tu);
522 } else
523 host_suspend(tu);
525 tu->otg.host = host;
527 mutex_unlock(&tu->serialize);
528 #else
529 /* No host mode configured, so do not allow host controlled to be set */
530 return -EINVAL;
531 #endif
533 return 0;
536 static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
538 struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
540 dev_dbg(&tu->pt_dev->dev, "set_peripheral %p\n", gadget);
542 if (!otg)
543 return -ENODEV;
545 #if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_GADGET_OMAP)
547 mutex_lock(&tu->serialize);
549 if (!gadget) {
550 if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
551 tahvo_usb_power_off(tu);
552 tu->otg.gadget = NULL;
553 mutex_unlock(&tu->serialize);
554 return 0;
557 tu->otg.gadget = gadget;
558 if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
559 tahvo_usb_become_peripheral(tu);
561 mutex_unlock(&tu->serialize);
562 #else
563 /* No gadget mode configured, so do not allow host controlled to be set */
564 return -EINVAL;
565 #endif
567 return 0;
570 static void tahvo_usb_irq_work(struct work_struct *work)
572 struct tahvo_usb *tu = container_of(work, struct tahvo_usb, irq_work);
574 mutex_lock(&tu->serialize);
575 check_vbus_state(tu);
576 mutex_unlock(&tu->serialize);
579 static void tahvo_usb_vbus_interrupt(unsigned long arg)
581 struct tahvo_usb *tu = (struct tahvo_usb *) arg;
583 tahvo_ack_irq(TAHVO_INT_VBUSON);
584 /* Seems we need this to acknowledge the interrupt */
585 tahvo_read_reg(TAHVO_REG_IDSR);
586 schedule_work(&tu->irq_work);
589 #ifdef CONFIG_USB_OTG
590 static ssize_t otg_mode_show(struct device *device,
591 struct device_attribute *attr, char *buf)
593 struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
594 switch (tu->tahvo_mode) {
595 case TAHVO_MODE_HOST:
596 return sprintf(buf, "host\n");
597 case TAHVO_MODE_PERIPHERAL:
598 return sprintf(buf, "peripheral\n");
600 return sprintf(buf, "unknown\n");
603 static ssize_t otg_mode_store(struct device *device,
604 struct device_attribute *attr,
605 const char *buf, size_t count)
607 struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
608 int r;
610 r = strlen(buf);
611 mutex_lock(&tu->serialize);
612 if (strncmp(buf, "host", 4) == 0) {
613 if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
614 tahvo_usb_stop_peripheral(tu);
615 tu->tahvo_mode = TAHVO_MODE_HOST;
616 if (tu->otg.host) {
617 printk(KERN_INFO "Selected HOST mode: host controller present.\n");
618 tahvo_usb_become_host(tu);
619 } else {
620 printk(KERN_INFO "Selected HOST mode: no host controller, powering off.\n");
621 tahvo_usb_power_off(tu);
623 } else if (strncmp(buf, "peripheral", 10) == 0) {
624 if (tu->tahvo_mode == TAHVO_MODE_HOST)
625 tahvo_usb_stop_host(tu);
626 tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
627 if (tu->otg.gadget) {
628 printk(KERN_INFO "Selected PERIPHERAL mode: gadget driver present.\n");
629 tahvo_usb_become_peripheral(tu);
630 } else {
631 printk(KERN_INFO "Selected PERIPHERAL mode: no gadget driver, powering off.\n");
632 tahvo_usb_power_off(tu);
634 } else
635 r = -EINVAL;
637 mutex_unlock(&tu->serialize);
638 return r;
641 static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store);
642 #endif
644 static int tahvo_usb_probe(struct device *dev)
646 struct tahvo_usb *tu;
647 int ret;
649 dev_dbg(dev, "probe\n");
651 /* Create driver data */
652 tu = kmalloc(sizeof(*tu), GFP_KERNEL);
653 if (!tu)
654 return -ENOMEM;
655 memset(tu, 0, sizeof(*tu));
656 tu->pt_dev = container_of(dev, struct platform_device, dev);
657 #ifdef CONFIG_USB_OTG
658 /* Default mode */
659 #ifdef CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT
660 tu->tahvo_mode = TAHVO_MODE_HOST;
661 #else
662 tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
663 #endif
664 #endif
666 INIT_WORK(&tu->irq_work, tahvo_usb_irq_work);
667 mutex_init(&tu->serialize);
669 /* Set initial state, so that we generate kevents only on
670 * state changes */
671 tu->vbus_state = tahvo_read_reg(TAHVO_REG_IDSR) & 0x01;
673 /* We cannot enable interrupt until omap_udc is initialized */
674 ret = tahvo_request_irq(TAHVO_INT_VBUSON, tahvo_usb_vbus_interrupt,
675 (unsigned long) tu, "vbus_interrupt");
676 if (ret != 0) {
677 kfree(tu);
678 printk(KERN_ERR "Could not register Tahvo interrupt for VBUS\n");
679 return ret;
682 /* Attributes */
683 ret = device_create_file(dev, &dev_attr_vbus_state);
684 #ifdef CONFIG_USB_OTG
685 ret |= device_create_file(dev, &dev_attr_otg_mode);
686 #endif
687 if (ret)
688 printk(KERN_ERR "attribute creation failed: %d\n", ret);
690 /* Create OTG interface */
691 tahvo_usb_power_off(tu);
692 tu->otg.state = OTG_STATE_UNDEFINED;
693 tu->otg.label = DRIVER_NAME;
694 tu->otg.set_host = tahvo_usb_set_host;
695 tu->otg.set_peripheral = tahvo_usb_set_peripheral;
696 tu->otg.set_power = tahvo_usb_set_power;
697 tu->otg.set_suspend = tahvo_usb_set_suspend;
698 tu->otg.start_srp = tahvo_usb_start_srp;
699 tu->otg.start_hnp = tahvo_usb_start_hnp;
701 ret = otg_set_transceiver(&tu->otg);
702 if (ret < 0) {
703 printk(KERN_ERR "Cannot register USB transceiver\n");
704 kfree(tu);
705 tahvo_free_irq(TAHVO_INT_VBUSON);
706 return ret;
709 dev->driver_data = tu;
711 /* Act upon current vbus state once at startup. A vbus state irq may or
712 * may not be generated in addition to this. */
713 schedule_work(&tu->irq_work);
714 return 0;
717 static int tahvo_usb_remove(struct device *dev)
719 dev_dbg(dev, "remove\n");
721 tahvo_free_irq(TAHVO_INT_VBUSON);
722 flush_scheduled_work();
723 otg_set_transceiver(0);
724 device_remove_file(dev, &dev_attr_vbus_state);
725 #ifdef CONFIG_USB_OTG
726 device_remove_file(dev, &dev_attr_otg_mode);
727 #endif
728 return 0;
731 static struct device_driver tahvo_usb_driver = {
732 .name = "tahvo-usb",
733 .bus = &platform_bus_type,
734 .probe = tahvo_usb_probe,
735 .remove = tahvo_usb_remove,
738 static struct platform_device tahvo_usb_device = {
739 .name = "tahvo-usb",
740 .id = -1,
743 static int __init tahvo_usb_init(void)
745 int ret = 0;
747 printk(KERN_INFO "Tahvo USB transceiver driver initializing\n");
748 ret = driver_register(&tahvo_usb_driver);
749 if (ret)
750 return ret;
751 ret = platform_device_register(&tahvo_usb_device);
752 if (ret < 0) {
753 driver_unregister(&tahvo_usb_driver);
754 return ret;
756 ret = driver_register(&omap_otg_driver);
757 if (ret) {
758 platform_device_unregister(&tahvo_usb_device);
759 driver_unregister(&tahvo_usb_driver);
760 return ret;
762 return 0;
765 subsys_initcall(tahvo_usb_init);
767 static void __exit tahvo_usb_exit(void)
769 driver_unregister(&omap_otg_driver);
770 platform_device_unregister(&tahvo_usb_device);
771 driver_unregister(&tahvo_usb_driver);
773 module_exit(tahvo_usb_exit);
775 MODULE_DESCRIPTION("Tahvo USB OTG Transceiver Driver");
776 MODULE_LICENSE("GPL");
777 MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs");