aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy/phy-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy/phy-core.c')
-rw-r--r--drivers/phy/phy-core.c120
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
95int phy_pm_runtime_get(struct phy *phy) 95int 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}
102EXPORT_SYMBOL_GPL(phy_pm_runtime_get); 108EXPORT_SYMBOL_GPL(phy_pm_runtime_get);
103 109
104int phy_pm_runtime_get_sync(struct phy *phy) 110int 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}
111EXPORT_SYMBOL_GPL(phy_pm_runtime_get_sync); 123EXPORT_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
166out: 184out:
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
190out: 212out:
191 mutex_unlock(&phy->mutex); 213 mutex_unlock(&phy->mutex);
@@ -196,23 +218,32 @@ EXPORT_SYMBOL_GPL(phy_exit);
196 218
197int phy_power_on(struct phy *phy) 219int 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
214out: 244out:
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
221int phy_power_off(struct phy *phy) 252int 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;
234out:
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}
240EXPORT_SYMBOL_GPL(phy_power_off); 274EXPORT_SYMBOL_GPL(phy_power_off);
241 275
@@ -290,7 +324,7 @@ err0:
290 */ 324 */
291void phy_put(struct phy *phy) 325void 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);
360struct phy *phy_get(struct device *dev, const char *string) 397struct 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)
393EXPORT_SYMBOL_GPL(phy_get); 424EXPORT_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 */
436struct 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}
445EXPORT_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)
423EXPORT_SYMBOL_GPL(devm_phy_get); 475EXPORT_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 */
490struct 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}
499EXPORT_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