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

drivers: phy: add calibrate method

Some quirky UDCs (like dwc3 on Exynos) need to have their phys calibrated e.g.
for using super speed. This patch adds a new phy_calibrate() method.
When the calibration should be used is dependent on actual chip.

In case of dwc3 on Exynos the calibration must happen after usb_add_hcd()
(while in host mode), because certain phy parameters like Tx LOS levels
and boost levels need to be calibrated further post initialization of xHCI
controller, to get SuperSpeed operations working. But an hcd must be
prepared first in order to pass it to usb_add_hcd(), so, in particular, dwc3
registers must be available first, and in order for the latter to happen
the phys must be initialized. This poses a chicken and egg problem if
the calibration were to be performed in phy_init(). To break the circular
dependency a separate method is added which can be called at a desired
moment after phy intialization.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Andrzej Pietrasiewicz and committed by
Kishon Vijay Abraham I
36914111 052553af

+25
+15
drivers/phy/phy-core.c
··· 372 372 } 373 373 EXPORT_SYMBOL_GPL(phy_reset); 374 374 375 + int phy_calibrate(struct phy *phy) 376 + { 377 + int ret; 378 + 379 + if (!phy || !phy->ops->calibrate) 380 + return 0; 381 + 382 + mutex_lock(&phy->mutex); 383 + ret = phy->ops->calibrate(phy); 384 + mutex_unlock(&phy->mutex); 385 + 386 + return ret; 387 + } 388 + EXPORT_SYMBOL_GPL(phy_calibrate); 389 + 375 390 /** 376 391 * _of_phy_get() - lookup and obtain a reference to a phy by phandle 377 392 * @np: device_node for which to get the phy
+10
include/linux/phy/phy.h
··· 41 41 * @power_off: powering off the phy 42 42 * @set_mode: set the mode of the phy 43 43 * @reset: resetting the phy 44 + * @calibrate: calibrate the phy 44 45 * @owner: the module owner containing the ops 45 46 */ 46 47 struct phy_ops { ··· 51 50 int (*power_off)(struct phy *phy); 52 51 int (*set_mode)(struct phy *phy, enum phy_mode mode); 53 52 int (*reset)(struct phy *phy); 53 + int (*calibrate)(struct phy *phy); 54 54 struct module *owner; 55 55 }; 56 56 ··· 145 143 int phy_power_off(struct phy *phy); 146 144 int phy_set_mode(struct phy *phy, enum phy_mode mode); 147 145 int phy_reset(struct phy *phy); 146 + int phy_calibrate(struct phy *phy); 148 147 static inline int phy_get_bus_width(struct phy *phy) 149 148 { 150 149 return phy->attrs.bus_width; ··· 261 258 } 262 259 263 260 static inline int phy_reset(struct phy *phy) 261 + { 262 + if (!phy) 263 + return 0; 264 + return -ENOSYS; 265 + } 266 + 267 + static inline int phy_calibrate(struct phy *phy) 264 268 { 265 269 if (!phy) 266 270 return 0;