0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/device.h>
0011 #include <linux/list.h>
0012 #include <linux/phy/phy.h>
0013 #include <linux/of.h>
0014
0015 #include "phy.h"
0016
0017 struct usb_phy_roothub {
0018 struct phy *phy;
0019 struct list_head list;
0020 };
0021
0022 static int usb_phy_roothub_add_phy(struct device *dev, int index,
0023 struct list_head *list)
0024 {
0025 struct usb_phy_roothub *roothub_entry;
0026 struct phy *phy;
0027
0028 phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
0029 if (IS_ERR(phy)) {
0030 if (PTR_ERR(phy) == -ENODEV)
0031 return 0;
0032 else
0033 return PTR_ERR(phy);
0034 }
0035
0036 roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
0037 if (!roothub_entry)
0038 return -ENOMEM;
0039
0040 INIT_LIST_HEAD(&roothub_entry->list);
0041
0042 roothub_entry->phy = phy;
0043
0044 list_add_tail(&roothub_entry->list, list);
0045
0046 return 0;
0047 }
0048
0049 struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
0050 {
0051 struct usb_phy_roothub *phy_roothub;
0052 int i, num_phys, err;
0053
0054 if (!IS_ENABLED(CONFIG_GENERIC_PHY))
0055 return NULL;
0056
0057 num_phys = of_count_phandle_with_args(dev->of_node, "phys",
0058 "#phy-cells");
0059 if (num_phys <= 0)
0060 return NULL;
0061
0062 phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
0063 if (!phy_roothub)
0064 return ERR_PTR(-ENOMEM);
0065
0066 INIT_LIST_HEAD(&phy_roothub->list);
0067
0068 for (i = 0; i < num_phys; i++) {
0069 err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
0070 if (err)
0071 return ERR_PTR(err);
0072 }
0073
0074 return phy_roothub;
0075 }
0076 EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
0077
0078 int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub)
0079 {
0080 struct usb_phy_roothub *roothub_entry;
0081 struct list_head *head;
0082 int err;
0083
0084 if (!phy_roothub)
0085 return 0;
0086
0087 head = &phy_roothub->list;
0088
0089 list_for_each_entry(roothub_entry, head, list) {
0090 err = phy_init(roothub_entry->phy);
0091 if (err)
0092 goto err_exit_phys;
0093 }
0094
0095 return 0;
0096
0097 err_exit_phys:
0098 list_for_each_entry_continue_reverse(roothub_entry, head, list)
0099 phy_exit(roothub_entry->phy);
0100
0101 return err;
0102 }
0103 EXPORT_SYMBOL_GPL(usb_phy_roothub_init);
0104
0105 int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
0106 {
0107 struct usb_phy_roothub *roothub_entry;
0108 struct list_head *head;
0109 int err, ret = 0;
0110
0111 if (!phy_roothub)
0112 return 0;
0113
0114 head = &phy_roothub->list;
0115
0116 list_for_each_entry(roothub_entry, head, list) {
0117 err = phy_exit(roothub_entry->phy);
0118 if (err)
0119 ret = err;
0120 }
0121
0122 return ret;
0123 }
0124 EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
0125
0126 int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
0127 enum phy_mode mode)
0128 {
0129 struct usb_phy_roothub *roothub_entry;
0130 struct list_head *head;
0131 int err;
0132
0133 if (!phy_roothub)
0134 return 0;
0135
0136 head = &phy_roothub->list;
0137
0138 list_for_each_entry(roothub_entry, head, list) {
0139 err = phy_set_mode(roothub_entry->phy, mode);
0140 if (err)
0141 goto err_out;
0142 }
0143
0144 return 0;
0145
0146 err_out:
0147 list_for_each_entry_continue_reverse(roothub_entry, head, list)
0148 phy_power_off(roothub_entry->phy);
0149
0150 return err;
0151 }
0152 EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
0153
0154 int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub)
0155 {
0156 struct usb_phy_roothub *roothub_entry;
0157 struct list_head *head;
0158 int err;
0159
0160 if (!phy_roothub)
0161 return 0;
0162
0163 head = &phy_roothub->list;
0164
0165 list_for_each_entry(roothub_entry, head, list) {
0166 err = phy_calibrate(roothub_entry->phy);
0167 if (err)
0168 return err;
0169 }
0170
0171 return 0;
0172 }
0173 EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate);
0174
0175 int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
0176 {
0177 struct usb_phy_roothub *roothub_entry;
0178 struct list_head *head;
0179 int err;
0180
0181 if (!phy_roothub)
0182 return 0;
0183
0184 head = &phy_roothub->list;
0185
0186 list_for_each_entry(roothub_entry, head, list) {
0187 err = phy_power_on(roothub_entry->phy);
0188 if (err)
0189 goto err_out;
0190 }
0191
0192 return 0;
0193
0194 err_out:
0195 list_for_each_entry_continue_reverse(roothub_entry, head, list)
0196 phy_power_off(roothub_entry->phy);
0197
0198 return err;
0199 }
0200 EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on);
0201
0202 void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
0203 {
0204 struct usb_phy_roothub *roothub_entry;
0205
0206 if (!phy_roothub)
0207 return;
0208
0209 list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list)
0210 phy_power_off(roothub_entry->phy);
0211 }
0212 EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
0213
0214 int usb_phy_roothub_suspend(struct device *controller_dev,
0215 struct usb_phy_roothub *phy_roothub)
0216 {
0217 usb_phy_roothub_power_off(phy_roothub);
0218
0219
0220 if (device_may_wakeup(controller_dev))
0221 return 0;
0222
0223 return usb_phy_roothub_exit(phy_roothub);
0224 }
0225 EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend);
0226
0227 int usb_phy_roothub_resume(struct device *controller_dev,
0228 struct usb_phy_roothub *phy_roothub)
0229 {
0230 int err;
0231
0232
0233 if (!device_may_wakeup(controller_dev)) {
0234 err = usb_phy_roothub_init(phy_roothub);
0235 if (err)
0236 return err;
0237 }
0238
0239 err = usb_phy_roothub_power_on(phy_roothub);
0240
0241
0242 if (err && !device_may_wakeup(controller_dev))
0243 usb_phy_roothub_exit(phy_roothub);
0244
0245 return err;
0246 }
0247 EXPORT_SYMBOL_GPL(usb_phy_roothub_resume);