diff options
Diffstat (limited to 'drivers/phy/phy-core.c')
-rw-r--r-- | drivers/phy/phy-core.c | 120 |
1 files changed, 98 insertions, 22 deletions
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 58e0e9739028..6c738376daff 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c | |||
@@ -94,19 +94,31 @@ static struct phy_provider *of_phy_provider_lookup(struct device_node *node) | |||
94 | 94 | ||
95 | int phy_pm_runtime_get(struct phy *phy) | 95 | int phy_pm_runtime_get(struct phy *phy) |
96 | { | 96 | { |
97 | int ret; | ||
98 | |||
97 | if (!pm_runtime_enabled(&phy->dev)) | 99 | if (!pm_runtime_enabled(&phy->dev)) |
98 | return -ENOTSUPP; | 100 | return -ENOTSUPP; |
99 | 101 | ||
100 | return pm_runtime_get(&phy->dev); | 102 | ret = pm_runtime_get(&phy->dev); |
103 | if (ret < 0 && ret != -EINPROGRESS) | ||
104 | pm_runtime_put_noidle(&phy->dev); | ||
105 | |||
106 | return ret; | ||
101 | } | 107 | } |
102 | EXPORT_SYMBOL_GPL(phy_pm_runtime_get); | 108 | EXPORT_SYMBOL_GPL(phy_pm_runtime_get); |
103 | 109 | ||
104 | int phy_pm_runtime_get_sync(struct phy *phy) | 110 | int phy_pm_runtime_get_sync(struct phy *phy) |
105 | { | 111 | { |
112 | int ret; | ||
113 | |||
106 | if (!pm_runtime_enabled(&phy->dev)) | 114 | if (!pm_runtime_enabled(&phy->dev)) |
107 | return -ENOTSUPP; | 115 | return -ENOTSUPP; |
108 | 116 | ||
109 | return pm_runtime_get_sync(&phy->dev); | 117 | ret = pm_runtime_get_sync(&phy->dev); |
118 | if (ret < 0) | ||
119 | pm_runtime_put_sync(&phy->dev); | ||
120 | |||
121 | return ret; | ||
110 | } | 122 | } |
111 | EXPORT_SYMBOL_GPL(phy_pm_runtime_get_sync); | 123 | EXPORT_SYMBOL_GPL(phy_pm_runtime_get_sync); |
112 | 124 | ||
@@ -150,18 +162,24 @@ int phy_init(struct phy *phy) | |||
150 | { | 162 | { |
151 | int ret; | 163 | int ret; |
152 | 164 | ||
165 | if (!phy) | ||
166 | return 0; | ||
167 | |||
153 | ret = phy_pm_runtime_get_sync(phy); | 168 | ret = phy_pm_runtime_get_sync(phy); |
154 | if (ret < 0 && ret != -ENOTSUPP) | 169 | if (ret < 0 && ret != -ENOTSUPP) |
155 | return ret; | 170 | return ret; |
156 | 171 | ||
157 | mutex_lock(&phy->mutex); | 172 | mutex_lock(&phy->mutex); |
158 | if (phy->init_count++ == 0 && phy->ops->init) { | 173 | if (phy->init_count == 0 && phy->ops->init) { |
159 | ret = phy->ops->init(phy); | 174 | ret = phy->ops->init(phy); |
160 | if (ret < 0) { | 175 | if (ret < 0) { |
161 | dev_err(&phy->dev, "phy init failed --> %d\n", ret); | 176 | dev_err(&phy->dev, "phy init failed --> %d\n", ret); |
162 | goto out; | 177 | goto out; |
163 | } | 178 | } |
179 | } else { | ||
180 | ret = 0; /* Override possible ret == -ENOTSUPP */ | ||
164 | } | 181 | } |
182 | ++phy->init_count; | ||
165 | 183 | ||
166 | out: | 184 | out: |
167 | mutex_unlock(&phy->mutex); | 185 | mutex_unlock(&phy->mutex); |
@@ -174,18 +192,22 @@ int phy_exit(struct phy *phy) | |||
174 | { | 192 | { |
175 | int ret; | 193 | int ret; |
176 | 194 | ||
195 | if (!phy) | ||
196 | return 0; | ||
197 | |||
177 | ret = phy_pm_runtime_get_sync(phy); | 198 | ret = phy_pm_runtime_get_sync(phy); |
178 | if (ret < 0 && ret != -ENOTSUPP) | 199 | if (ret < 0 && ret != -ENOTSUPP) |
179 | return ret; | 200 | return ret; |
180 | 201 | ||
181 | mutex_lock(&phy->mutex); | 202 | mutex_lock(&phy->mutex); |
182 | if (--phy->init_count == 0 && phy->ops->exit) { | 203 | if (phy->init_count == 1 && phy->ops->exit) { |
183 | ret = phy->ops->exit(phy); | 204 | ret = phy->ops->exit(phy); |
184 | if (ret < 0) { | 205 | if (ret < 0) { |
185 | dev_err(&phy->dev, "phy exit failed --> %d\n", ret); | 206 | dev_err(&phy->dev, "phy exit failed --> %d\n", ret); |
186 | goto out; | 207 | goto out; |
187 | } | 208 | } |
188 | } | 209 | } |
210 | --phy->init_count; | ||
189 | 211 | ||
190 | out: | 212 | out: |
191 | mutex_unlock(&phy->mutex); | 213 | mutex_unlock(&phy->mutex); |
@@ -196,23 +218,32 @@ EXPORT_SYMBOL_GPL(phy_exit); | |||
196 | 218 | ||
197 | int phy_power_on(struct phy *phy) | 219 | int phy_power_on(struct phy *phy) |
198 | { | 220 | { |
199 | int ret = -ENOTSUPP; | 221 | int ret; |
222 | |||
223 | if (!phy) | ||
224 | return 0; | ||
200 | 225 | ||
201 | ret = phy_pm_runtime_get_sync(phy); | 226 | ret = phy_pm_runtime_get_sync(phy); |
202 | if (ret < 0 && ret != -ENOTSUPP) | 227 | if (ret < 0 && ret != -ENOTSUPP) |
203 | return ret; | 228 | return ret; |
204 | 229 | ||
205 | mutex_lock(&phy->mutex); | 230 | mutex_lock(&phy->mutex); |
206 | if (phy->power_count++ == 0 && phy->ops->power_on) { | 231 | if (phy->power_count == 0 && phy->ops->power_on) { |
207 | ret = phy->ops->power_on(phy); | 232 | ret = phy->ops->power_on(phy); |
208 | if (ret < 0) { | 233 | if (ret < 0) { |
209 | dev_err(&phy->dev, "phy poweron failed --> %d\n", ret); | 234 | dev_err(&phy->dev, "phy poweron failed --> %d\n", ret); |
210 | goto out; | 235 | goto out; |
211 | } | 236 | } |
237 | } else { | ||
238 | ret = 0; /* Override possible ret == -ENOTSUPP */ | ||
212 | } | 239 | } |
240 | ++phy->power_count; | ||
241 | mutex_unlock(&phy->mutex); | ||
242 | return 0; | ||
213 | 243 | ||
214 | out: | 244 | out: |
215 | mutex_unlock(&phy->mutex); | 245 | mutex_unlock(&phy->mutex); |
246 | phy_pm_runtime_put_sync(phy); | ||
216 | 247 | ||
217 | return ret; | 248 | return ret; |
218 | } | 249 | } |
@@ -220,22 +251,25 @@ EXPORT_SYMBOL_GPL(phy_power_on); | |||
220 | 251 | ||
221 | int phy_power_off(struct phy *phy) | 252 | int phy_power_off(struct phy *phy) |
222 | { | 253 | { |
223 | int ret = -ENOTSUPP; | 254 | int ret; |
255 | |||
256 | if (!phy) | ||
257 | return 0; | ||
224 | 258 | ||
225 | mutex_lock(&phy->mutex); | 259 | mutex_lock(&phy->mutex); |
226 | if (--phy->power_count == 0 && phy->ops->power_off) { | 260 | if (phy->power_count == 1 && phy->ops->power_off) { |
227 | ret = phy->ops->power_off(phy); | 261 | ret = phy->ops->power_off(phy); |
228 | if (ret < 0) { | 262 | if (ret < 0) { |
229 | dev_err(&phy->dev, "phy poweroff failed --> %d\n", ret); | 263 | dev_err(&phy->dev, "phy poweroff failed --> %d\n", ret); |
230 | goto out; | 264 | mutex_unlock(&phy->mutex); |
265 | return ret; | ||
231 | } | 266 | } |
232 | } | 267 | } |
233 | 268 | --phy->power_count; | |
234 | out: | ||
235 | mutex_unlock(&phy->mutex); | 269 | mutex_unlock(&phy->mutex); |
236 | phy_pm_runtime_put(phy); | 270 | phy_pm_runtime_put(phy); |
237 | 271 | ||
238 | return ret; | 272 | return 0; |
239 | } | 273 | } |
240 | EXPORT_SYMBOL_GPL(phy_power_off); | 274 | EXPORT_SYMBOL_GPL(phy_power_off); |
241 | 275 | ||
@@ -290,7 +324,7 @@ err0: | |||
290 | */ | 324 | */ |
291 | void phy_put(struct phy *phy) | 325 | void phy_put(struct phy *phy) |
292 | { | 326 | { |
293 | if (IS_ERR(phy)) | 327 | if (!phy || IS_ERR(phy)) |
294 | return; | 328 | return; |
295 | 329 | ||
296 | module_put(phy->ops->owner); | 330 | module_put(phy->ops->owner); |
@@ -310,6 +344,9 @@ void devm_phy_put(struct device *dev, struct phy *phy) | |||
310 | { | 344 | { |
311 | int r; | 345 | int r; |
312 | 346 | ||
347 | if (!phy) | ||
348 | return; | ||
349 | |||
313 | r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy); | 350 | r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy); |
314 | dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); | 351 | dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); |
315 | } | 352 | } |
@@ -360,7 +397,7 @@ EXPORT_SYMBOL_GPL(of_phy_simple_xlate); | |||
360 | struct phy *phy_get(struct device *dev, const char *string) | 397 | struct phy *phy_get(struct device *dev, const char *string) |
361 | { | 398 | { |
362 | int index = 0; | 399 | int index = 0; |
363 | struct phy *phy = NULL; | 400 | struct phy *phy; |
364 | 401 | ||
365 | if (string == NULL) { | 402 | if (string == NULL) { |
366 | dev_WARN(dev, "missing string\n"); | 403 | dev_WARN(dev, "missing string\n"); |
@@ -371,17 +408,11 @@ struct phy *phy_get(struct device *dev, const char *string) | |||
371 | index = of_property_match_string(dev->of_node, "phy-names", | 408 | index = of_property_match_string(dev->of_node, "phy-names", |
372 | string); | 409 | string); |
373 | phy = of_phy_get(dev, index); | 410 | phy = of_phy_get(dev, index); |
374 | if (IS_ERR(phy)) { | ||
375 | dev_err(dev, "unable to find phy\n"); | ||
376 | return phy; | ||
377 | } | ||
378 | } else { | 411 | } else { |
379 | phy = phy_lookup(dev, string); | 412 | phy = phy_lookup(dev, string); |
380 | if (IS_ERR(phy)) { | ||
381 | dev_err(dev, "unable to find phy\n"); | ||
382 | return phy; | ||
383 | } | ||
384 | } | 413 | } |
414 | if (IS_ERR(phy)) | ||
415 | return phy; | ||
385 | 416 | ||
386 | if (!try_module_get(phy->ops->owner)) | 417 | if (!try_module_get(phy->ops->owner)) |
387 | return ERR_PTR(-EPROBE_DEFER); | 418 | return ERR_PTR(-EPROBE_DEFER); |
@@ -393,6 +424,27 @@ struct phy *phy_get(struct device *dev, const char *string) | |||
393 | EXPORT_SYMBOL_GPL(phy_get); | 424 | EXPORT_SYMBOL_GPL(phy_get); |
394 | 425 | ||
395 | /** | 426 | /** |
427 | * phy_optional_get() - lookup and obtain a reference to an optional phy. | ||
428 | * @dev: device that requests this phy | ||
429 | * @string: the phy name as given in the dt data or the name of the controller | ||
430 | * port for non-dt case | ||
431 | * | ||
432 | * Returns the phy driver, after getting a refcount to it; or | ||
433 | * NULL if there is no such phy. The caller is responsible for | ||
434 | * calling phy_put() to release that count. | ||
435 | */ | ||
436 | struct phy *phy_optional_get(struct device *dev, const char *string) | ||
437 | { | ||
438 | struct phy *phy = phy_get(dev, string); | ||
439 | |||
440 | if (PTR_ERR(phy) == -ENODEV) | ||
441 | phy = NULL; | ||
442 | |||
443 | return phy; | ||
444 | } | ||
445 | EXPORT_SYMBOL_GPL(phy_optional_get); | ||
446 | |||
447 | /** | ||
396 | * devm_phy_get() - lookup and obtain a reference to a phy. | 448 | * devm_phy_get() - lookup and obtain a reference to a phy. |
397 | * @dev: device that requests this phy | 449 | * @dev: device that requests this phy |
398 | * @string: the phy name as given in the dt data or phy device name | 450 | * @string: the phy name as given in the dt data or phy device name |
@@ -423,6 +475,30 @@ struct phy *devm_phy_get(struct device *dev, const char *string) | |||
423 | EXPORT_SYMBOL_GPL(devm_phy_get); | 475 | EXPORT_SYMBOL_GPL(devm_phy_get); |
424 | 476 | ||
425 | /** | 477 | /** |
478 | * devm_phy_optional_get() - lookup and obtain a reference to an optional phy. | ||
479 | * @dev: device that requests this phy | ||
480 | * @string: the phy name as given in the dt data or phy device name | ||
481 | * for non-dt case | ||
482 | * | ||
483 | * Gets the phy using phy_get(), and associates a device with it using | ||
484 | * devres. On driver detach, release function is invoked on the devres | ||
485 | * data, then, devres data is freed. This differs to devm_phy_get() in | ||
486 | * that if the phy does not exist, it is not considered an error and | ||
487 | * -ENODEV will not be returned. Instead the NULL phy is returned, | ||
488 | * which can be passed to all other phy consumer calls. | ||
489 | */ | ||
490 | struct phy *devm_phy_optional_get(struct device *dev, const char *string) | ||
491 | { | ||
492 | struct phy *phy = devm_phy_get(dev, string); | ||
493 | |||
494 | if (PTR_ERR(phy) == -ENODEV) | ||
495 | phy = NULL; | ||
496 | |||
497 | return phy; | ||
498 | } | ||
499 | EXPORT_SYMBOL_GPL(devm_phy_optional_get); | ||
500 | |||
501 | /** | ||
426 | * phy_create() - create a new phy | 502 | * phy_create() - create a new phy |
427 | * @dev: device that is creating the new phy | 503 | * @dev: device that is creating the new phy |
428 | * @ops: function pointers for performing phy operations | 504 | * @ops: function pointers for performing phy operations |