root/drivers/usb/core/phy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usb_phy_roothub_add_phy
  2. usb_phy_roothub_alloc
  3. usb_phy_roothub_init
  4. usb_phy_roothub_exit
  5. usb_phy_roothub_set_mode
  6. usb_phy_roothub_calibrate
  7. usb_phy_roothub_power_on
  8. usb_phy_roothub_power_off
  9. usb_phy_roothub_suspend
  10. usb_phy_roothub_resume

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * A wrapper for multiple PHYs which passes all phy_* function calls to
   4  * multiple (actual) PHY devices. This is comes handy when initializing
   5  * all PHYs on a HCD and to keep them all in the same state.
   6  *
   7  * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
   8  */
   9 
  10 #include <linux/device.h>
  11 #include <linux/list.h>
  12 #include <linux/phy/phy.h>
  13 #include <linux/of.h>
  14 
  15 #include "phy.h"
  16 
  17 struct usb_phy_roothub {
  18         struct phy              *phy;
  19         struct list_head        list;
  20 };
  21 
  22 static int usb_phy_roothub_add_phy(struct device *dev, int index,
  23                                    struct list_head *list)
  24 {
  25         struct usb_phy_roothub *roothub_entry;
  26         struct phy *phy;
  27 
  28         phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
  29         if (IS_ERR(phy)) {
  30                 if (PTR_ERR(phy) == -ENODEV)
  31                         return 0;
  32                 else
  33                         return PTR_ERR(phy);
  34         }
  35 
  36         roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
  37         if (!roothub_entry)
  38                 return -ENOMEM;
  39 
  40         INIT_LIST_HEAD(&roothub_entry->list);
  41 
  42         roothub_entry->phy = phy;
  43 
  44         list_add_tail(&roothub_entry->list, list);
  45 
  46         return 0;
  47 }
  48 
  49 struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
  50 {
  51         struct usb_phy_roothub *phy_roothub;
  52         int i, num_phys, err;
  53 
  54         if (!IS_ENABLED(CONFIG_GENERIC_PHY))
  55                 return NULL;
  56 
  57         num_phys = of_count_phandle_with_args(dev->of_node, "phys",
  58                                               "#phy-cells");
  59         if (num_phys <= 0)
  60                 return NULL;
  61 
  62         phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
  63         if (!phy_roothub)
  64                 return ERR_PTR(-ENOMEM);
  65 
  66         INIT_LIST_HEAD(&phy_roothub->list);
  67 
  68         for (i = 0; i < num_phys; i++) {
  69                 err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
  70                 if (err)
  71                         return ERR_PTR(err);
  72         }
  73 
  74         return phy_roothub;
  75 }
  76 EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
  77 
  78 int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub)
  79 {
  80         struct usb_phy_roothub *roothub_entry;
  81         struct list_head *head;
  82         int err;
  83 
  84         if (!phy_roothub)
  85                 return 0;
  86 
  87         head = &phy_roothub->list;
  88 
  89         list_for_each_entry(roothub_entry, head, list) {
  90                 err = phy_init(roothub_entry->phy);
  91                 if (err)
  92                         goto err_exit_phys;
  93         }
  94 
  95         return 0;
  96 
  97 err_exit_phys:
  98         list_for_each_entry_continue_reverse(roothub_entry, head, list)
  99                 phy_exit(roothub_entry->phy);
 100 
 101         return err;
 102 }
 103 EXPORT_SYMBOL_GPL(usb_phy_roothub_init);
 104 
 105 int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
 106 {
 107         struct usb_phy_roothub *roothub_entry;
 108         struct list_head *head;
 109         int err, ret = 0;
 110 
 111         if (!phy_roothub)
 112                 return 0;
 113 
 114         head = &phy_roothub->list;
 115 
 116         list_for_each_entry(roothub_entry, head, list) {
 117                 err = phy_exit(roothub_entry->phy);
 118                 if (err)
 119                         ret = err;
 120         }
 121 
 122         return ret;
 123 }
 124 EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
 125 
 126 int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
 127                              enum phy_mode mode)
 128 {
 129         struct usb_phy_roothub *roothub_entry;
 130         struct list_head *head;
 131         int err;
 132 
 133         if (!phy_roothub)
 134                 return 0;
 135 
 136         head = &phy_roothub->list;
 137 
 138         list_for_each_entry(roothub_entry, head, list) {
 139                 err = phy_set_mode(roothub_entry->phy, mode);
 140                 if (err)
 141                         goto err_out;
 142         }
 143 
 144         return 0;
 145 
 146 err_out:
 147         list_for_each_entry_continue_reverse(roothub_entry, head, list)
 148                 phy_power_off(roothub_entry->phy);
 149 
 150         return err;
 151 }
 152 EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
 153 
 154 int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub)
 155 {
 156         struct usb_phy_roothub *roothub_entry;
 157         struct list_head *head;
 158         int err;
 159 
 160         if (!phy_roothub)
 161                 return 0;
 162 
 163         head = &phy_roothub->list;
 164 
 165         list_for_each_entry(roothub_entry, head, list) {
 166                 err = phy_calibrate(roothub_entry->phy);
 167                 if (err)
 168                         return err;
 169         }
 170 
 171         return 0;
 172 }
 173 EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate);
 174 
 175 int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
 176 {
 177         struct usb_phy_roothub *roothub_entry;
 178         struct list_head *head;
 179         int err;
 180 
 181         if (!phy_roothub)
 182                 return 0;
 183 
 184         head = &phy_roothub->list;
 185 
 186         list_for_each_entry(roothub_entry, head, list) {
 187                 err = phy_power_on(roothub_entry->phy);
 188                 if (err)
 189                         goto err_out;
 190         }
 191 
 192         return 0;
 193 
 194 err_out:
 195         list_for_each_entry_continue_reverse(roothub_entry, head, list)
 196                 phy_power_off(roothub_entry->phy);
 197 
 198         return err;
 199 }
 200 EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on);
 201 
 202 void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
 203 {
 204         struct usb_phy_roothub *roothub_entry;
 205 
 206         if (!phy_roothub)
 207                 return;
 208 
 209         list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list)
 210                 phy_power_off(roothub_entry->phy);
 211 }
 212 EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
 213 
 214 int usb_phy_roothub_suspend(struct device *controller_dev,
 215                             struct usb_phy_roothub *phy_roothub)
 216 {
 217         usb_phy_roothub_power_off(phy_roothub);
 218 
 219         /* keep the PHYs initialized so the device can wake up the system */
 220         if (device_may_wakeup(controller_dev))
 221                 return 0;
 222 
 223         return usb_phy_roothub_exit(phy_roothub);
 224 }
 225 EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend);
 226 
 227 int usb_phy_roothub_resume(struct device *controller_dev,
 228                            struct usb_phy_roothub *phy_roothub)
 229 {
 230         int err;
 231 
 232         /* if the device can't wake up the system _exit was called */
 233         if (!device_may_wakeup(controller_dev)) {
 234                 err = usb_phy_roothub_init(phy_roothub);
 235                 if (err)
 236                         return err;
 237         }
 238 
 239         err = usb_phy_roothub_power_on(phy_roothub);
 240 
 241         /* undo _init if _power_on failed */
 242         if (err && !device_may_wakeup(controller_dev))
 243                 usb_phy_roothub_exit(phy_roothub);
 244 
 245         return err;
 246 }
 247 EXPORT_SYMBOL_GPL(usb_phy_roothub_resume);

/* [<][>][^][v][top][bottom][index][help] */