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(struct samsung_usbphy *sphy, bool on)
78 void __iomem *reg = NULL;
83 dev_warn(sphy->dev, "Can't set pmu isolation\n");
87 switch (sphy->drv_data->cpu_type) {
90 * Do nothing: We will add here once S3C64xx goes for DT support
95 * Fall through since exynos4210 and exynos5250 have similar
96 * register architecture: two separate registers for host and
97 * device phy control with enable bit at position 0.
100 if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
101 reg = sphy->pmuregs +
102 sphy->drv_data->devphy_reg_offset;
103 en_mask = sphy->drv_data->devphy_en_mask;
104 } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
105 reg = sphy->pmuregs +
106 sphy->drv_data->hostphy_reg_offset;
107 en_mask = sphy->drv_data->hostphy_en_mask;
111 dev_err(sphy->dev, "Invalid SoC type\n");
115 reg_val = readl(reg);
122 writel(reg_val, reg);
124 EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation);
127 * Configure the mode of working of usb-phy here: HOST/DEVICE.
129 void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
134 dev_warn(sphy->dev, "Can't configure specified phy mode\n");
138 reg = readl(sphy->sysreg);
140 if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
141 reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
142 else if (sphy->phy_type == USB_PHY_TYPE_HOST)
143 reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
145 writel(reg, sphy->sysreg);
147 EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
150 * PHYs are different for USB Device and USB Host.
151 * This make sure that correct PHY type is selected before
152 * any operation on PHY.
154 int samsung_usbphy_set_type(struct usb_phy *phy,
155 enum samsung_usb_phy_type phy_type)
157 struct samsung_usbphy *sphy = phy_to_sphy(phy);
159 sphy->phy_type = phy_type;
163 EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
166 * Returns reference clock frequency selection value
168 int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
174 * In exynos5250 USB host and device PHY use
175 * external crystal clock XXTI
177 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
178 ref_clk = devm_clk_get(sphy->dev, "ext_xtal");
180 ref_clk = devm_clk_get(sphy->dev, "xusbxti");
181 if (IS_ERR(ref_clk)) {
182 dev_err(sphy->dev, "Failed to get reference clock\n");
183 return PTR_ERR(ref_clk);
186 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
187 /* set clock frequency for PLL */
188 switch (clk_get_rate(ref_clk)) {
190 refclk_freq = FSEL_CLKSEL_9600K;
193 refclk_freq = FSEL_CLKSEL_10M;
196 refclk_freq = FSEL_CLKSEL_12M;
199 refclk_freq = FSEL_CLKSEL_19200K;
202 refclk_freq = FSEL_CLKSEL_20M;
205 refclk_freq = FSEL_CLKSEL_50M;
209 /* default reference clock */
210 refclk_freq = FSEL_CLKSEL_24M;
214 switch (clk_get_rate(ref_clk)) {
216 refclk_freq = PHYCLK_CLKSEL_12M;
219 refclk_freq = PHYCLK_CLKSEL_24M;
222 refclk_freq = PHYCLK_CLKSEL_48M;
225 if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
226 refclk_freq = PHYCLK_CLKSEL_48M;
228 refclk_freq = PHYCLK_CLKSEL_24M;
236 EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);