diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-02-04 14:03:20 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-02-04 14:03:20 -0500 |
commit | 4d4bac4499e9955521af80198063ef9c2f2bd634 (patch) | |
tree | b02fb1f3d343d3a4a9864be18eec04e10f43d410 /drivers/usb/phy/phy-generic.c | |
parent | 7fa40910e0bf5ef32eca49595d950cb24f6402bf (diff) | |
parent | 9298b4aad37e8c6962edcdbd0b62620adb207d03 (diff) |
Merge tag 'usb-for-v3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
usb: patches for v3.20 merge window
Here's the big pull request for Gadgets and PHYs. It's
a total of 217 non-merge commits with pretty much everything
being touched.
The most important bits are a ton of new documentation for
almost all usb gadget functions, a new isp1760 UDC driver,
several improvements to the old net2280 UDC driver, and
some minor tracepoint improvements to dwc3.
Other than that, a big list of minor cleanups, smaller bugfixes
and new features all over the place.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy/phy-generic.c')
-rw-r--r-- | drivers/usb/phy/phy-generic.c | 150 |
1 files changed, 110 insertions, 40 deletions
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index f1b719b45a53..70be50b734b2 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/dma-mapping.h> | 29 | #include <linux/dma-mapping.h> |
30 | #include <linux/usb/gadget.h> | ||
30 | #include <linux/usb/otg.h> | 31 | #include <linux/usb/otg.h> |
31 | #include <linux/usb/usb_phy_generic.h> | 32 | #include <linux/usb/usb_phy_generic.h> |
32 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
@@ -39,6 +40,10 @@ | |||
39 | 40 | ||
40 | #include "phy-generic.h" | 41 | #include "phy-generic.h" |
41 | 42 | ||
43 | #define VBUS_IRQ_FLAGS \ | ||
44 | (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | \ | ||
45 | IRQF_ONESHOT) | ||
46 | |||
42 | struct platform_device *usb_phy_generic_register(void) | 47 | struct platform_device *usb_phy_generic_register(void) |
43 | { | 48 | { |
44 | return platform_device_register_simple("usb_phy_generic", | 49 | return platform_device_register_simple("usb_phy_generic", |
@@ -59,19 +64,79 @@ static int nop_set_suspend(struct usb_phy *x, int suspend) | |||
59 | 64 | ||
60 | static void nop_reset_set(struct usb_phy_generic *nop, int asserted) | 65 | static void nop_reset_set(struct usb_phy_generic *nop, int asserted) |
61 | { | 66 | { |
62 | int value; | 67 | if (!nop->gpiod_reset) |
68 | return; | ||
69 | |||
70 | gpiod_direction_output(nop->gpiod_reset, !asserted); | ||
71 | usleep_range(10000, 20000); | ||
72 | gpiod_set_value(nop->gpiod_reset, asserted); | ||
73 | } | ||
74 | |||
75 | /* interface to regulator framework */ | ||
76 | static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA) | ||
77 | { | ||
78 | struct regulator *vbus_draw = nop->vbus_draw; | ||
79 | int enabled; | ||
80 | int ret; | ||
63 | 81 | ||
64 | if (!gpio_is_valid(nop->gpio_reset)) | 82 | if (!vbus_draw) |
65 | return; | 83 | return; |
66 | 84 | ||
67 | value = asserted; | 85 | enabled = nop->vbus_draw_enabled; |
68 | if (nop->reset_active_low) | 86 | if (mA) { |
69 | value = !value; | 87 | regulator_set_current_limit(vbus_draw, 0, 1000 * mA); |
88 | if (!enabled) { | ||
89 | ret = regulator_enable(vbus_draw); | ||
90 | if (ret < 0) | ||
91 | return; | ||
92 | nop->vbus_draw_enabled = 1; | ||
93 | } | ||
94 | } else { | ||
95 | if (enabled) { | ||
96 | ret = regulator_disable(vbus_draw); | ||
97 | if (ret < 0) | ||
98 | return; | ||
99 | nop->vbus_draw_enabled = 0; | ||
100 | } | ||
101 | } | ||
102 | nop->mA = mA; | ||
103 | } | ||
104 | |||
105 | |||
106 | static irqreturn_t nop_gpio_vbus_thread(int irq, void *data) | ||
107 | { | ||
108 | struct usb_phy_generic *nop = data; | ||
109 | struct usb_otg *otg = nop->phy.otg; | ||
110 | int vbus, status; | ||
111 | |||
112 | vbus = gpiod_get_value(nop->gpiod_vbus); | ||
113 | if ((vbus ^ nop->vbus) == 0) | ||
114 | return IRQ_HANDLED; | ||
115 | nop->vbus = vbus; | ||
116 | |||
117 | if (vbus) { | ||
118 | status = USB_EVENT_VBUS; | ||
119 | otg->state = OTG_STATE_B_PERIPHERAL; | ||
120 | nop->phy.last_event = status; | ||
121 | usb_gadget_vbus_connect(otg->gadget); | ||
122 | |||
123 | /* drawing a "unit load" is *always* OK, except for OTG */ | ||
124 | nop_set_vbus_draw(nop, 100); | ||
125 | |||
126 | atomic_notifier_call_chain(&nop->phy.notifier, status, | ||
127 | otg->gadget); | ||
128 | } else { | ||
129 | nop_set_vbus_draw(nop, 0); | ||
70 | 130 | ||
71 | gpio_set_value_cansleep(nop->gpio_reset, value); | 131 | usb_gadget_vbus_disconnect(otg->gadget); |
132 | status = USB_EVENT_NONE; | ||
133 | otg->state = OTG_STATE_B_IDLE; | ||
134 | nop->phy.last_event = status; | ||
72 | 135 | ||
73 | if (!asserted) | 136 | atomic_notifier_call_chain(&nop->phy.notifier, status, |
74 | usleep_range(10000, 20000); | 137 | otg->gadget); |
138 | } | ||
139 | return IRQ_HANDLED; | ||
75 | } | 140 | } |
76 | 141 | ||
77 | int usb_gen_phy_init(struct usb_phy *phy) | 142 | int usb_gen_phy_init(struct usb_phy *phy) |
@@ -143,36 +208,47 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, | |||
143 | struct usb_phy_generic_platform_data *pdata) | 208 | struct usb_phy_generic_platform_data *pdata) |
144 | { | 209 | { |
145 | enum usb_phy_type type = USB_PHY_TYPE_USB2; | 210 | enum usb_phy_type type = USB_PHY_TYPE_USB2; |
146 | int err; | 211 | int err = 0; |
147 | 212 | ||
148 | u32 clk_rate = 0; | 213 | u32 clk_rate = 0; |
149 | bool needs_vcc = false; | 214 | bool needs_vcc = false; |
150 | 215 | ||
151 | nop->reset_active_low = true; /* default behaviour */ | ||
152 | |||
153 | if (dev->of_node) { | 216 | if (dev->of_node) { |
154 | struct device_node *node = dev->of_node; | 217 | struct device_node *node = dev->of_node; |
155 | enum of_gpio_flags flags = 0; | ||
156 | 218 | ||
157 | if (of_property_read_u32(node, "clock-frequency", &clk_rate)) | 219 | if (of_property_read_u32(node, "clock-frequency", &clk_rate)) |
158 | clk_rate = 0; | 220 | clk_rate = 0; |
159 | 221 | ||
160 | needs_vcc = of_property_read_bool(node, "vcc-supply"); | 222 | needs_vcc = of_property_read_bool(node, "vcc-supply"); |
161 | nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios", | 223 | nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset"); |
162 | 0, &flags); | 224 | err = PTR_ERR_OR_ZERO(nop->gpiod_reset); |
163 | if (nop->gpio_reset == -EPROBE_DEFER) | 225 | if (!err) { |
164 | return -EPROBE_DEFER; | 226 | nop->gpiod_vbus = devm_gpiod_get_optional(dev, |
165 | 227 | "vbus-detect"); | |
166 | nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW; | 228 | err = PTR_ERR_OR_ZERO(nop->gpiod_vbus); |
167 | 229 | } | |
168 | } else if (pdata) { | 230 | } else if (pdata) { |
169 | type = pdata->type; | 231 | type = pdata->type; |
170 | clk_rate = pdata->clk_rate; | 232 | clk_rate = pdata->clk_rate; |
171 | needs_vcc = pdata->needs_vcc; | 233 | needs_vcc = pdata->needs_vcc; |
172 | nop->gpio_reset = pdata->gpio_reset; | 234 | if (gpio_is_valid(pdata->gpio_reset)) { |
173 | } else { | 235 | err = devm_gpio_request_one(dev, pdata->gpio_reset, 0, |
174 | nop->gpio_reset = -1; | 236 | dev_name(dev)); |
237 | if (!err) | ||
238 | nop->gpiod_reset = | ||
239 | gpio_to_desc(pdata->gpio_reset); | ||
240 | } | ||
241 | nop->gpiod_vbus = pdata->gpiod_vbus; | ||
242 | } | ||
243 | |||
244 | if (err == -EPROBE_DEFER) | ||
245 | return -EPROBE_DEFER; | ||
246 | if (err) { | ||
247 | dev_err(dev, "Error requesting RESET or VBUS GPIO\n"); | ||
248 | return err; | ||
175 | } | 249 | } |
250 | if (nop->gpiod_reset) | ||
251 | gpiod_direction_output(nop->gpiod_reset, 1); | ||
176 | 252 | ||
177 | nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), | 253 | nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), |
178 | GFP_KERNEL); | 254 | GFP_KERNEL); |
@@ -201,24 +277,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, | |||
201 | return -EPROBE_DEFER; | 277 | return -EPROBE_DEFER; |
202 | } | 278 | } |
203 | 279 | ||
204 | if (gpio_is_valid(nop->gpio_reset)) { | ||
205 | unsigned long gpio_flags; | ||
206 | |||
207 | /* Assert RESET */ | ||
208 | if (nop->reset_active_low) | ||
209 | gpio_flags = GPIOF_OUT_INIT_LOW; | ||
210 | else | ||
211 | gpio_flags = GPIOF_OUT_INIT_HIGH; | ||
212 | |||
213 | err = devm_gpio_request_one(dev, nop->gpio_reset, | ||
214 | gpio_flags, dev_name(dev)); | ||
215 | if (err) { | ||
216 | dev_err(dev, "Error requesting RESET GPIO %d\n", | ||
217 | nop->gpio_reset); | ||
218 | return err; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | nop->dev = dev; | 280 | nop->dev = dev; |
223 | nop->phy.dev = nop->dev; | 281 | nop->phy.dev = nop->dev; |
224 | nop->phy.label = "nop-xceiv"; | 282 | nop->phy.label = "nop-xceiv"; |
@@ -247,6 +305,18 @@ static int usb_phy_generic_probe(struct platform_device *pdev) | |||
247 | err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev)); | 305 | err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev)); |
248 | if (err) | 306 | if (err) |
249 | return err; | 307 | return err; |
308 | if (nop->gpiod_vbus) { | ||
309 | err = devm_request_threaded_irq(&pdev->dev, | ||
310 | gpiod_to_irq(nop->gpiod_vbus), | ||
311 | NULL, nop_gpio_vbus_thread, | ||
312 | VBUS_IRQ_FLAGS, "vbus_detect", | ||
313 | nop); | ||
314 | if (err) { | ||
315 | dev_err(&pdev->dev, "can't request irq %i, err: %d\n", | ||
316 | gpiod_to_irq(nop->gpiod_vbus), err); | ||
317 | return err; | ||
318 | } | ||
319 | } | ||
250 | 320 | ||
251 | nop->phy.init = usb_gen_phy_init; | 321 | nop->phy.init = usb_gen_phy_init; |
252 | nop->phy.shutdown = usb_gen_phy_shutdown; | 322 | nop->phy.shutdown = usb_gen_phy_shutdown; |