1 /* linux/drivers/usb/phy/phy-samsung-usb.c
3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * Author: Praveen Paneri <p.paneri@samsung.com>
8 * Samsung USB-PHY helper driver with common function calls;
9 * interacts with Samsung USB 2.0 PHY controller driver and later
10 * with Samsung USB 3.0 PHY driver.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
22 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/clk.h>
25 #include <linux/device.h>
26 #include <linux/err.h>
29 #include <linux/of_address.h>
30 #include <linux/usb/samsung_usb_phy.h>
32 #include "phy-samsung-usb.h"
34 int samsung_usbphy_parse_dt(struct samsung_usbphy
*sphy
)
36 struct device_node
*usbphy_sys
;
38 /* Getting node for system controller interface for usb-phy */
39 usbphy_sys
= of_get_child_by_name(sphy
->dev
->of_node
, "usbphy-sys");
41 dev_err(sphy
->dev
, "No sys-controller interface for usb-phy\n");
45 sphy
->pmuregs
= of_iomap(usbphy_sys
, 0);
47 if (sphy
->pmuregs
== NULL
) {
48 dev_err(sphy
->dev
, "Can't get usb-phy pmu control register\n");
52 sphy
->sysreg
= of_iomap(usbphy_sys
, 1);
55 * Not returning error code here, since this situation is not fatal.
56 * Few SoCs may not have this switch available
58 if (sphy
->sysreg
== NULL
)
59 dev_warn(sphy
->dev
, "Can't get usb-phy sysreg cfg register\n");
61 of_node_put(usbphy_sys
);
66 of_node_put(usbphy_sys
);
69 EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt
);
72 * Set isolation here for phy.
73 * Here 'on = true' would mean USB PHY block is isolated, hence
74 * de-activated and vice-versa.
76 void samsung_usbphy_set_isolation_4210(struct samsung_usbphy
*sphy
, bool on
)
78 void __iomem
*reg
= NULL
;
83 dev_warn(sphy
->dev
, "Can't set pmu isolation\n");
87 if (sphy
->phy_type
== USB_PHY_TYPE_DEVICE
) {
88 reg
= sphy
->pmuregs
+ sphy
->drv_data
->devphy_reg_offset
;
89 en_mask
= sphy
->drv_data
->devphy_en_mask
;
90 } else if (sphy
->phy_type
== USB_PHY_TYPE_HOST
) {
91 reg
= sphy
->pmuregs
+ sphy
->drv_data
->hostphy_reg_offset
;
92 en_mask
= sphy
->drv_data
->hostphy_en_mask
;
102 writel(reg_val
, reg
);
104 if (sphy
->drv_data
->cpu_type
== TYPE_EXYNOS4X12
) {
105 writel(reg_val
, sphy
->pmuregs
+ EXYNOS4X12_PHY_HSIC_CTRL0
);
106 writel(reg_val
, sphy
->pmuregs
+ EXYNOS4X12_PHY_HSIC_CTRL1
);
109 EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation_4210
);
112 * Configure the mode of working of usb-phy here: HOST/DEVICE.
114 void samsung_usbphy_cfg_sel(struct samsung_usbphy
*sphy
)
119 dev_warn(sphy
->dev
, "Can't configure specified phy mode\n");
123 reg
= readl(sphy
->sysreg
);
125 if (sphy
->phy_type
== USB_PHY_TYPE_DEVICE
)
126 reg
&= ~EXYNOS_USB20PHY_CFG_HOST_LINK
;
127 else if (sphy
->phy_type
== USB_PHY_TYPE_HOST
)
128 reg
|= EXYNOS_USB20PHY_CFG_HOST_LINK
;
130 writel(reg
, sphy
->sysreg
);
132 EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel
);
135 * PHYs are different for USB Device and USB Host.
136 * This make sure that correct PHY type is selected before
137 * any operation on PHY.
139 int samsung_usbphy_set_type(struct usb_phy
*phy
,
140 enum samsung_usb_phy_type phy_type
)
142 struct samsung_usbphy
*sphy
= phy_to_sphy(phy
);
144 sphy
->phy_type
= phy_type
;
148 EXPORT_SYMBOL_GPL(samsung_usbphy_set_type
);
150 int samsung_usbphy_rate_to_clksel_64xx(struct samsung_usbphy
*sphy
,
157 clksel
= PHYCLK_CLKSEL_12M
;
160 clksel
= PHYCLK_CLKSEL_24M
;
163 clksel
= PHYCLK_CLKSEL_48M
;
167 "Invalid reference clock frequency: %lu\n", rate
);
173 EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_64xx
);
175 int samsung_usbphy_rate_to_clksel_4x12(struct samsung_usbphy
*sphy
,
182 clksel
= FSEL_CLKSEL_9600K
;
185 clksel
= FSEL_CLKSEL_10M
;
188 clksel
= FSEL_CLKSEL_12M
;
191 clksel
= FSEL_CLKSEL_19200K
;
194 clksel
= FSEL_CLKSEL_20M
;
197 clksel
= FSEL_CLKSEL_24M
;
200 clksel
= FSEL_CLKSEL_50M
;
204 "Invalid reference clock frequency: %lu\n", rate
);
210 EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_4x12
);
213 * Returns reference clock frequency selection value
215 int samsung_usbphy_get_refclk_freq(struct samsung_usbphy
*sphy
)
222 * In exynos5250 USB host and device PHY use
223 * external crystal clock XXTI
225 if (sphy
->drv_data
->cpu_type
== TYPE_EXYNOS5250
)
226 ref_clk
= clk_get(sphy
->dev
, "ext_xtal");
228 ref_clk
= clk_get(sphy
->dev
, "xusbxti");
229 if (IS_ERR(ref_clk
)) {
230 dev_err(sphy
->dev
, "Failed to get reference clock\n");
231 return PTR_ERR(ref_clk
);
234 rate
= clk_get_rate(ref_clk
);
235 refclk_freq
= sphy
->drv_data
->rate_to_clksel(sphy
, rate
);
241 EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq
);