blob: 8e756d95a28f029b0db9c417d9b1dbdb6fa7df2e [file] [log] [blame]
Tony Lindgren3cb22d62008-11-24 12:02:21 -08001/*
2 * otg.c -- USB OTG utility code
3 *
4 * Copyright (C) 2004 Texas Instruments
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
Paul Gortmakerf940fcd2011-05-27 09:56:31 -040013#include <linux/export.h>
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +053014#include <linux/err.h>
Tony Lindgren3cb22d62008-11-24 12:02:21 -080015#include <linux/device.h>
Kishon Vijay Abraham I410219d2012-06-22 17:02:47 +053016#include <linux/slab.h>
Tony Lindgren3cb22d62008-11-24 12:02:21 -080017
18#include <linux/usb/otg.h>
19
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +053020static LIST_HEAD(phy_list);
Kishon Vijay Abraham Ib4a83e42013-01-25 08:03:21 +053021static LIST_HEAD(phy_bind_list);
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +053022static DEFINE_SPINLOCK(phy_lock);
23
24static struct usb_phy *__usb_find_phy(struct list_head *list,
25 enum usb_phy_type type)
26{
27 struct usb_phy *phy = NULL;
28
29 list_for_each_entry(phy, list, head) {
30 if (phy->type != type)
31 continue;
32
33 return phy;
34 }
35
36 return ERR_PTR(-ENODEV);
37}
Tony Lindgren3cb22d62008-11-24 12:02:21 -080038
Kishon Vijay Abraham I410219d2012-06-22 17:02:47 +053039static void devm_usb_phy_release(struct device *dev, void *res)
40{
41 struct usb_phy *phy = *(struct usb_phy **)res;
42
43 usb_put_phy(phy);
44}
45
46static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
47{
48 return res == match_data;
49}
50
51/**
52 * devm_usb_get_phy - find the USB PHY
53 * @dev - device that requests this phy
54 * @type - the type of the phy the controller requires
55 *
56 * Gets the phy using usb_get_phy(), and associates a device with it using
57 * devres. On driver detach, release function is invoked on the devres data,
58 * then, devres data is freed.
59 *
60 * For use by USB host and peripheral drivers.
61 */
62struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
63{
64 struct usb_phy **ptr, *phy;
65
66 ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
67 if (!ptr)
68 return NULL;
69
70 phy = usb_get_phy(type);
Kishon Vijay Abraham Ided017e2012-06-26 17:40:32 +053071 if (!IS_ERR(phy)) {
Kishon Vijay Abraham I410219d2012-06-22 17:02:47 +053072 *ptr = phy;
73 devres_add(dev, ptr);
74 } else
75 devres_free(ptr);
76
77 return phy;
78}
79EXPORT_SYMBOL(devm_usb_get_phy);
80
Tony Lindgren3cb22d62008-11-24 12:02:21 -080081/**
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +053082 * usb_get_phy - find the USB PHY
83 * @type - the type of the phy the controller requires
Tony Lindgren3cb22d62008-11-24 12:02:21 -080084 *
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +053085 * Returns the phy driver, after getting a refcount to it; or
Kishon Vijay Abraham Ided017e2012-06-26 17:40:32 +053086 * -ENODEV if there is no such phy. The caller is responsible for
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +053087 * calling usb_put_phy() to release that count.
Tony Lindgren3cb22d62008-11-24 12:02:21 -080088 *
89 * For use by USB host and peripheral drivers.
90 */
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +053091struct usb_phy *usb_get_phy(enum usb_phy_type type)
Tony Lindgren3cb22d62008-11-24 12:02:21 -080092{
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +053093 struct usb_phy *phy = NULL;
94 unsigned long flags;
95
96 spin_lock_irqsave(&phy_lock, flags);
97
98 phy = __usb_find_phy(&phy_list, type);
99 if (IS_ERR(phy)) {
100 pr_err("unable to find transceiver of type %s\n",
101 usb_phy_type_string(type));
Kishon Vijay Abraham If8ecf822012-07-02 12:20:24 +0530102 goto err0;
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530103 }
104
105 get_device(phy->dev);
106
Kishon Vijay Abraham If8ecf822012-07-02 12:20:24 +0530107err0:
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530108 spin_unlock_irqrestore(&phy_lock, flags);
109
Heikki Krogerus7a8a3a92012-02-13 13:24:04 +0200110 return phy;
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800111}
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530112EXPORT_SYMBOL(usb_get_phy);
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800113
114/**
Kishon Vijay Abraham I410219d2012-06-22 17:02:47 +0530115 * devm_usb_put_phy - release the USB PHY
116 * @dev - device that wants to release this phy
117 * @phy - the phy returned by devm_usb_get_phy()
118 *
119 * destroys the devres associated with this phy and invokes usb_put_phy
120 * to release the phy.
121 *
122 * For use by USB host and peripheral drivers.
123 */
124void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
125{
126 int r;
127
128 r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
129 dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
130}
131EXPORT_SYMBOL(devm_usb_put_phy);
132
133/**
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530134 * usb_put_phy - release the USB PHY
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530135 * @x: the phy returned by usb_get_phy()
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800136 *
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530137 * Releases a refcount the caller received from usb_get_phy().
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800138 *
139 * For use by USB host and peripheral drivers.
140 */
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530141void usb_put_phy(struct usb_phy *x)
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800142{
Robert Jarzmikecf85e42009-04-21 20:33:10 -0700143 if (x)
144 put_device(x->dev);
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800145}
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530146EXPORT_SYMBOL(usb_put_phy);
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800147
148/**
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530149 * usb_add_phy - declare the USB PHY
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530150 * @x: the USB phy to be used; or NULL
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530151 * @type - the type of this PHY
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800152 *
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530153 * This call is exclusively for use by phy drivers, which
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800154 * coordinate the activities of drivers for host and peripheral
155 * controllers, and in some cases for VBUS current regulation.
156 */
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530157int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800158{
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530159 int ret = 0;
160 unsigned long flags;
161 struct usb_phy *phy;
162
Shubhrajyoti Ddf6791d2012-08-07 19:56:30 +0530163 if (x->type != USB_PHY_TYPE_UNDEFINED) {
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530164 dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
165 return -EINVAL;
166 }
167
168 spin_lock_irqsave(&phy_lock, flags);
169
170 list_for_each_entry(phy, &phy_list, head) {
171 if (phy->type == type) {
172 ret = -EBUSY;
173 dev_err(x->dev, "transceiver type %s already exists\n",
174 usb_phy_type_string(type));
175 goto out;
176 }
177 }
178
179 x->type = type;
180 list_add_tail(&x->head, &phy_list);
181
182out:
183 spin_unlock_irqrestore(&phy_lock, flags);
184 return ret;
Tony Lindgren3cb22d62008-11-24 12:02:21 -0800185}
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +0530186EXPORT_SYMBOL(usb_add_phy);
Anatolij Gustschin3dacdf12011-04-15 16:18:38 +0200187
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +0530188/**
189 * usb_remove_phy - remove the OTG PHY
190 * @x: the USB OTG PHY to be removed;
191 *
192 * This reverts the effects of usb_add_phy
193 */
194void usb_remove_phy(struct usb_phy *x)
195{
196 unsigned long flags;
197
198 spin_lock_irqsave(&phy_lock, flags);
199 if (x)
200 list_del(&x->head);
201 spin_unlock_irqrestore(&phy_lock, flags);
202}
203EXPORT_SYMBOL(usb_remove_phy);
204
Kishon Vijay Abraham Ib4a83e42013-01-25 08:03:21 +0530205/**
206 * usb_bind_phy - bind the phy and the controller that uses the phy
207 * @dev_name: the device name of the device that will bind to the phy
208 * @index: index to specify the port number
209 * @phy_dev_name: the device name of the phy
210 *
211 * Fills the phy_bind structure with the dev_name and phy_dev_name. This will
212 * be used when the phy driver registers the phy and when the controller
213 * requests this phy.
214 *
215 * To be used by platform specific initialization code.
216 */
217int __init usb_bind_phy(const char *dev_name, u8 index,
218 const char *phy_dev_name)
219{
220 struct usb_phy_bind *phy_bind;
221 unsigned long flags;
222
223 phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL);
224 if (!phy_bind) {
225 pr_err("phy_bind(): No memory for phy_bind");
226 return -ENOMEM;
227 }
228
229 phy_bind->dev_name = dev_name;
230 phy_bind->phy_dev_name = phy_dev_name;
231 phy_bind->index = index;
232
233 spin_lock_irqsave(&phy_lock, flags);
234 list_add_tail(&phy_bind->list, &phy_bind_list);
235 spin_unlock_irqrestore(&phy_lock, flags);
236
237 return 0;
238}
239EXPORT_SYMBOL_GPL(usb_bind_phy);
240
Anatolij Gustschin3dacdf12011-04-15 16:18:38 +0200241const char *otg_state_string(enum usb_otg_state state)
242{
243 switch (state) {
244 case OTG_STATE_A_IDLE:
245 return "a_idle";
246 case OTG_STATE_A_WAIT_VRISE:
247 return "a_wait_vrise";
248 case OTG_STATE_A_WAIT_BCON:
249 return "a_wait_bcon";
250 case OTG_STATE_A_HOST:
251 return "a_host";
252 case OTG_STATE_A_SUSPEND:
253 return "a_suspend";
254 case OTG_STATE_A_PERIPHERAL:
255 return "a_peripheral";
256 case OTG_STATE_A_WAIT_VFALL:
257 return "a_wait_vfall";
258 case OTG_STATE_A_VBUS_ERR:
259 return "a_vbus_err";
260 case OTG_STATE_B_IDLE:
261 return "b_idle";
262 case OTG_STATE_B_SRP_INIT:
263 return "b_srp_init";
264 case OTG_STATE_B_PERIPHERAL:
265 return "b_peripheral";
266 case OTG_STATE_B_WAIT_ACON:
267 return "b_wait_acon";
268 case OTG_STATE_B_HOST:
269 return "b_host";
270 default:
271 return "UNDEFINED";
272 }
273}
274EXPORT_SYMBOL(otg_state_string);