1 // SPDX-License-Identifier: GPL-2.0
3 * OMAP OTG controller driver
5 * Based on code from tahvo-usb.c and isp1301_omap.c drivers.
7 * Copyright (C) 2005-2006 Nokia Corporation
8 * Copyright (C) 2004 Texas Instruments
9 * Copyright (C) 2004 David Brownell
13 #include <linux/err.h>
14 #include <linux/extcon.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/interrupt.h>
18 #include <linux/platform_device.h>
19 #include <linux/platform_data/usb-omap1.h>
25 struct extcon_dev
*extcon
;
26 struct notifier_block vbus_nb
;
27 struct notifier_block id_nb
;
30 #define OMAP_OTG_CTRL 0x0c
31 #define OMAP_OTG_ASESSVLD (1 << 20)
32 #define OMAP_OTG_BSESSEND (1 << 19)
33 #define OMAP_OTG_BSESSVLD (1 << 18)
34 #define OMAP_OTG_VBUSVLD (1 << 17)
35 #define OMAP_OTG_ID (1 << 16)
36 #define OMAP_OTG_XCEIV_OUTPUTS \
37 (OMAP_OTG_ASESSVLD | OMAP_OTG_BSESSEND | OMAP_OTG_BSESSVLD | \
38 OMAP_OTG_VBUSVLD | OMAP_OTG_ID)
40 static void omap_otg_ctrl(struct otg_device
*otg_dev
, u32 outputs
)
44 l
= readl(otg_dev
->base
+ OMAP_OTG_CTRL
);
45 l
&= ~OMAP_OTG_XCEIV_OUTPUTS
;
47 writel(l
, otg_dev
->base
+ OMAP_OTG_CTRL
);
50 static void omap_otg_set_mode(struct otg_device
*otg_dev
)
52 if (!otg_dev
->id
&& otg_dev
->vbus
)
53 /* Set B-session valid. */
54 omap_otg_ctrl(otg_dev
, OMAP_OTG_ID
| OMAP_OTG_BSESSVLD
);
55 else if (otg_dev
->vbus
)
56 /* Set A-session valid. */
57 omap_otg_ctrl(otg_dev
, OMAP_OTG_ASESSVLD
);
58 else if (!otg_dev
->id
)
59 /* Set B-session end to indicate no VBUS. */
60 omap_otg_ctrl(otg_dev
, OMAP_OTG_ID
| OMAP_OTG_BSESSEND
);
63 static int omap_otg_id_notifier(struct notifier_block
*nb
,
64 unsigned long event
, void *ptr
)
66 struct otg_device
*otg_dev
= container_of(nb
, struct otg_device
, id_nb
);
69 omap_otg_set_mode(otg_dev
);
74 static int omap_otg_vbus_notifier(struct notifier_block
*nb
,
75 unsigned long event
, void *ptr
)
77 struct otg_device
*otg_dev
= container_of(nb
, struct otg_device
,
80 otg_dev
->vbus
= event
;
81 omap_otg_set_mode(otg_dev
);
86 static int omap_otg_probe(struct platform_device
*pdev
)
88 const struct omap_usb_config
*config
= pdev
->dev
.platform_data
;
89 struct otg_device
*otg_dev
;
90 struct extcon_dev
*extcon
;
94 if (!config
|| !config
->extcon
)
97 extcon
= extcon_get_extcon_dev(config
->extcon
);
101 otg_dev
= devm_kzalloc(&pdev
->dev
, sizeof(*otg_dev
), GFP_KERNEL
);
105 otg_dev
->base
= devm_ioremap_resource(&pdev
->dev
, &pdev
->resource
[0]);
106 if (IS_ERR(otg_dev
->base
))
107 return PTR_ERR(otg_dev
->base
);
109 otg_dev
->extcon
= extcon
;
110 otg_dev
->id_nb
.notifier_call
= omap_otg_id_notifier
;
111 otg_dev
->vbus_nb
.notifier_call
= omap_otg_vbus_notifier
;
113 ret
= devm_extcon_register_notifier(&pdev
->dev
, extcon
,
114 EXTCON_USB_HOST
, &otg_dev
->id_nb
);
118 ret
= devm_extcon_register_notifier(&pdev
->dev
, extcon
,
119 EXTCON_USB
, &otg_dev
->vbus_nb
);
124 otg_dev
->id
= extcon_get_state(extcon
, EXTCON_USB_HOST
);
125 otg_dev
->vbus
= extcon_get_state(extcon
, EXTCON_USB
);
126 omap_otg_set_mode(otg_dev
);
128 rev
= readl(otg_dev
->base
);
131 "OMAP USB OTG controller rev %d.%d (%s, id=%d, vbus=%d)\n",
132 (rev
>> 4) & 0xf, rev
& 0xf, config
->extcon
, otg_dev
->id
,
135 platform_set_drvdata(pdev
, otg_dev
);
140 static struct platform_driver omap_otg_driver
= {
141 .probe
= omap_otg_probe
,
146 module_platform_driver(omap_otg_driver
);
148 MODULE_DESCRIPTION("OMAP USB OTG controller driver");
149 MODULE_LICENSE("GPL");
150 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");