Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: improved lookup method

Separates registration of the phy and the lookup. The method
is copied from clkdev.c,

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Heikki Krogerus and committed by
Kishon Vijay Abraham I
b7bc15b9 d4510574

+112 -42
+13 -41
Documentation/phy.txt
··· 54 54 to make use of it. The PHY framework provides 2 APIs to create the PHY. 55 55 56 56 struct phy *phy_create(struct device *dev, struct device_node *node, 57 - const struct phy_ops *ops, 58 - struct phy_init_data *init_data); 57 + const struct phy_ops *ops); 59 58 struct phy *devm_phy_create(struct device *dev, struct device_node *node, 60 - const struct phy_ops *ops, 61 - struct phy_init_data *init_data); 59 + const struct phy_ops *ops); 62 60 63 61 The PHY drivers can use one of the above 2 APIs to create the PHY by passing 64 - the device pointer, phy ops and init_data. 62 + the device pointer and phy ops. 65 63 phy_ops is a set of function pointers for performing PHY operations such as 66 - init, exit, power_on and power_off. *init_data* is mandatory to get a reference 67 - to the PHY in the case of non-dt boot. See section *Board File Initialization* 68 - on how init_data should be used. 64 + init, exit, power_on and power_off. 69 65 70 66 Inorder to dereference the private data (in phy_ops), the phy provider driver 71 67 can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in ··· 133 137 phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and 134 138 phy_pm_runtime_forbid for performing PM operations. 135 139 136 - 8. Board File Initialization 140 + 8. PHY Mappings 137 141 138 - Certain board file initialization is necessary in order to get a reference 139 - to the PHY in the case of non-dt boot. 140 - Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe, 141 - then in the board file the following initialization should be done. 142 + In order to get reference to a PHY without help from DeviceTree, the framework 143 + offers lookups which can be compared to clkdev that allow clk structures to be 144 + bound to devices. A lookup can be made be made during runtime when a handle to 145 + the struct phy already exists. 142 146 143 - struct phy_consumer consumers[] = { 144 - PHY_CONSUMER("dwc3.0", "usb"), 145 - PHY_CONSUMER("pcie.0", "pcie"), 146 - PHY_CONSUMER("sata.0", "sata"), 147 - }; 148 - PHY_CONSUMER takes 2 parameters, first is the device name of the controller 149 - (PHY consumer) and second is the port name. 147 + The framework offers the following API for registering and unregistering the 148 + lookups. 150 149 151 - struct phy_init_data init_data = { 152 - .consumers = consumers, 153 - .num_consumers = ARRAY_SIZE(consumers), 154 - }; 155 - 156 - static const struct platform_device pipe3_phy_dev = { 157 - .name = "pipe3-phy", 158 - .id = -1, 159 - .dev = { 160 - .platform_data = { 161 - .init_data = &init_data, 162 - }, 163 - }, 164 - }; 165 - 166 - then, while doing phy_create, the PHY driver should pass this init_data 167 - phy_create(dev, ops, pdata->init_data); 168 - 169 - and the controller driver (phy consumer) should pass the port name along with 170 - the device to get a reference to the PHY 171 - phy_get(dev, "pcie"); 150 + int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id); 151 + void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id); 172 152 173 153 9. DeviceTree Binding 174 154
+83 -1
drivers/phy/phy-core.c
··· 26 26 static struct class *phy_class; 27 27 static DEFINE_MUTEX(phy_provider_mutex); 28 28 static LIST_HEAD(phy_provider_list); 29 + static LIST_HEAD(phys); 29 30 static DEFINE_IDA(phy_ida); 30 31 31 32 static void devm_phy_release(struct device *dev, void *res) ··· 83 82 84 83 class_dev_iter_exit(&iter); 85 84 return ERR_PTR(-ENODEV); 85 + } 86 + 87 + /** 88 + * phy_create_lookup() - allocate and register PHY/device association 89 + * @phy: the phy of the association 90 + * @con_id: connection ID string on device 91 + * @dev_id: the device of the association 92 + * 93 + * Creates and registers phy_lookup entry. 94 + */ 95 + int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id) 96 + { 97 + struct phy_lookup *pl; 98 + 99 + if (!phy || !dev_id || !con_id) 100 + return -EINVAL; 101 + 102 + pl = kzalloc(sizeof(*pl), GFP_KERNEL); 103 + if (!pl) 104 + return -ENOMEM; 105 + 106 + pl->dev_id = dev_id; 107 + pl->con_id = con_id; 108 + pl->phy = phy; 109 + 110 + mutex_lock(&phy_provider_mutex); 111 + list_add_tail(&pl->node, &phys); 112 + mutex_unlock(&phy_provider_mutex); 113 + 114 + return 0; 115 + } 116 + EXPORT_SYMBOL_GPL(phy_create_lookup); 117 + 118 + /** 119 + * phy_remove_lookup() - find and remove PHY/device association 120 + * @phy: the phy of the association 121 + * @con_id: connection ID string on device 122 + * @dev_id: the device of the association 123 + * 124 + * Finds and unregisters phy_lookup entry that was created with 125 + * phy_create_lookup(). 126 + */ 127 + void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id) 128 + { 129 + struct phy_lookup *pl; 130 + 131 + if (!phy || !dev_id || !con_id) 132 + return; 133 + 134 + mutex_lock(&phy_provider_mutex); 135 + list_for_each_entry(pl, &phys, node) 136 + if (pl->phy == phy && !strcmp(pl->dev_id, dev_id) && 137 + !strcmp(pl->con_id, con_id)) { 138 + list_del(&pl->node); 139 + kfree(pl); 140 + break; 141 + } 142 + mutex_unlock(&phy_provider_mutex); 143 + } 144 + EXPORT_SYMBOL_GPL(phy_remove_lookup); 145 + 146 + static struct phy *phy_find(struct device *dev, const char *con_id) 147 + { 148 + const char *dev_id = dev_name(dev); 149 + struct phy_lookup *p, *pl = NULL; 150 + struct phy *phy; 151 + 152 + mutex_lock(&phy_provider_mutex); 153 + list_for_each_entry(p, &phys, node) 154 + if (!strcmp(p->dev_id, dev_id) && !strcmp(p->con_id, con_id)) { 155 + pl = p; 156 + break; 157 + } 158 + mutex_unlock(&phy_provider_mutex); 159 + 160 + phy = pl ? pl->phy : ERR_PTR(-ENODEV); 161 + 162 + /* fall-back to the old lookup method for now */ 163 + if (IS_ERR(phy)) 164 + phy = phy_lookup(dev, con_id); 165 + return phy; 86 166 } 87 167 88 168 static struct phy_provider *of_phy_provider_lookup(struct device_node *node) ··· 537 455 string); 538 456 phy = _of_phy_get(dev->of_node, index); 539 457 } else { 540 - phy = phy_lookup(dev, string); 458 + phy = phy_find(dev, string); 541 459 } 542 460 if (IS_ERR(phy)) 543 461 return phy;
+16
include/linux/phy/phy.h
··· 110 110 .port = _port, \ 111 111 } 112 112 113 + struct phy_lookup { 114 + struct list_head node; 115 + const char *dev_id; 116 + const char *con_id; 117 + struct phy *phy; 118 + }; 119 + 113 120 #define to_phy(a) (container_of((a), struct phy, dev)) 114 121 115 122 #define of_phy_provider_register(dev, xlate) \ ··· 181 174 void of_phy_provider_unregister(struct phy_provider *phy_provider); 182 175 void devm_of_phy_provider_unregister(struct device *dev, 183 176 struct phy_provider *phy_provider); 177 + int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id); 178 + void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id); 184 179 #else 185 180 static inline int phy_pm_runtime_get(struct phy *phy) 186 181 { ··· 354 345 struct phy_provider *phy_provider) 355 346 { 356 347 } 348 + static inline int 349 + phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id) 350 + { 351 + return 0; 352 + } 353 + static inline void phy_remove_lookup(struct phy *phy, const char *con_id, 354 + const char *dev_id) { } 357 355 #endif 358 356 359 357 #endif /* __DRIVERS_PHY_H */