summaryrefslogtreecommitdiffstats
path: root/drivers/phy/allwinner
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2017-08-03 10:14:06 +0200
committerKishon Vijay Abraham I <kishon@ti.com>2017-08-22 06:41:17 +0200
commitf0152c58c68f94f86bee8d91c4e4835e0c43ada7 (patch)
tree3ae9fd7bc83fe1f50ad2797682bc00b7c0b863fd /drivers/phy/allwinner
parentdt-bindings: phy: sun4i-usb-phy: Add compatible string for A83T (diff)
downloadlinux-f0152c58c68f94f86bee8d91c4e4835e0c43ada7.tar.xz
linux-f0152c58c68f94f86bee8d91c4e4835e0c43ada7.zip
phy: sun4i-usb: Support secondary clock for HSIC PHY
On the Allwinner A83T SoC, the last USB PHY is an HSIC PHY. It requires two clocks instead of one. On all Allwinner SoCs that share the common USB PHY design supported by the phy-sun4i-usb driver, the first PHY is always tied to OTG, and there is at most one HSIC PHY, typically the last. In this patch we take advantage of these known constraints and store an index in the compatible-string-related config structure describing which PHY is HSIC, needing the extra hsic_12M clock. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Diffstat (limited to 'drivers/phy/allwinner')
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index 3bea17b9405a..d259fdc6d7df 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -107,6 +107,7 @@ enum sun4i_usb_phy_type {
struct sun4i_usb_phy_cfg {
int num_phys;
+ int hsic_index;
enum sun4i_usb_phy_type type;
u32 disc_thresh;
u8 phyctl_offset;
@@ -126,6 +127,7 @@ struct sun4i_usb_phy_data {
struct regulator *vbus;
struct reset_control *reset;
struct clk *clk;
+ struct clk *clk2;
bool regulator_on;
int index;
} phys[MAX_PHYS];
@@ -261,8 +263,15 @@ static int sun4i_usb_phy_init(struct phy *_phy)
if (ret)
return ret;
+ ret = clk_prepare_enable(phy->clk2);
+ if (ret) {
+ clk_disable_unprepare(phy->clk);
+ return ret;
+ }
+
ret = reset_control_deassert(phy->reset);
if (ret) {
+ clk_disable_unprepare(phy->clk2);
clk_disable_unprepare(phy->clk);
return ret;
}
@@ -315,6 +324,7 @@ static int sun4i_usb_phy_exit(struct phy *_phy)
sun4i_usb_phy_passby(phy, 0);
reset_control_assert(phy->reset);
+ clk_disable_unprepare(phy->clk2);
clk_disable_unprepare(phy->clk);
return 0;
@@ -719,6 +729,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->clk);
}
+ /* The first PHY is always tied to OTG, and never HSIC */
+ if (data->cfg->hsic_index && i == data->cfg->hsic_index) {
+ /* HSIC needs secondary clock */
+ snprintf(name, sizeof(name), "usb%d_hsic_12M", i);
+ phy->clk2 = devm_clk_get(dev, name);
+ if (IS_ERR(phy->clk2)) {
+ dev_err(dev, "failed to get clock %s\n", name);
+ return PTR_ERR(phy->clk2);
+ }
+ }
+
snprintf(name, sizeof(name), "usb%d_reset", i);
phy->reset = devm_reset_control_get(dev, name);
if (IS_ERR(phy->reset)) {