Merge remote-tracking branch 'asoc/topic/tegra' into asoc-next
[deliverable/linux.git] / drivers / usb / phy / phy-samsung-usb.c
CommitLineData
dc2377d0 1/* linux/drivers/usb/phy/phy-samsung-usb.c
337dc3a7
PP
2 *
3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Author: Praveen Paneri <p.paneri@samsung.com>
7 *
dc2377d0
VG
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.
337dc3a7
PP
11 *
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.
15 *
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.
20 */
21
22#include <linux/module.h>
23#include <linux/platform_device.h>
24#include <linux/clk.h>
8c1b3e16 25#include <linux/device.h>
337dc3a7
PP
26#include <linux/err.h>
27#include <linux/io.h>
28#include <linux/of.h>
69f0946a 29#include <linux/of_address.h>
8c1b3e16 30#include <linux/usb/samsung_usb_phy.h>
337dc3a7 31
dc2377d0 32#include "phy-samsung-usb.h"
337dc3a7 33
dc2377d0 34int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
69f0946a
VG
35{
36 struct device_node *usbphy_sys;
37
38 /* Getting node for system controller interface for usb-phy */
39 usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
40 if (!usbphy_sys) {
41 dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
42 return -ENODEV;
43 }
44
45 sphy->pmuregs = of_iomap(usbphy_sys, 0);
46
69f0946a
VG
47 if (sphy->pmuregs == NULL) {
48 dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
8c1b3e16 49 goto err0;
69f0946a
VG
50 }
51
8c1b3e16
VG
52 sphy->sysreg = of_iomap(usbphy_sys, 1);
53
54 /*
55 * Not returning error code here, since this situation is not fatal.
56 * Few SoCs may not have this switch available
57 */
58 if (sphy->sysreg == NULL)
59 dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
60
61 of_node_put(usbphy_sys);
62
69f0946a 63 return 0;
8c1b3e16
VG
64
65err0:
66 of_node_put(usbphy_sys);
67 return -ENXIO;
69f0946a 68}
dc2377d0 69EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
69f0946a
VG
70
71/*
72 * Set isolation here for phy.
73 * Here 'on = true' would mean USB PHY block is isolated, hence
74 * de-activated and vice-versa.
75 */
3f339074 76void samsung_usbphy_set_isolation_4210(struct samsung_usbphy *sphy, bool on)
69f0946a 77{
8c1b3e16 78 void __iomem *reg = NULL;
69f0946a 79 u32 reg_val;
8c1b3e16 80 u32 en_mask = 0;
69f0946a
VG
81
82 if (!sphy->pmuregs) {
83 dev_warn(sphy->dev, "Can't set pmu isolation\n");
84 return;
85 }
86
3f339074
TF
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;
8c1b3e16 93 }
69f0946a
VG
94
95 reg_val = readl(reg);
96
97 if (on)
98 reg_val &= ~en_mask;
99 else
100 reg_val |= en_mask;
101
102 writel(reg_val, reg);
6d3d61f8
DK
103
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);
107 }
69f0946a 108}
3f339074 109EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation_4210);
69f0946a 110
8c1b3e16
VG
111/*
112 * Configure the mode of working of usb-phy here: HOST/DEVICE.
113 */
dc2377d0 114void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
8c1b3e16
VG
115{
116 u32 reg;
117
118 if (!sphy->sysreg) {
119 dev_warn(sphy->dev, "Can't configure specified phy mode\n");
120 return;
121 }
122
123 reg = readl(sphy->sysreg);
124
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;
129
130 writel(reg, sphy->sysreg);
131}
dc2377d0 132EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
8c1b3e16
VG
133
134/*
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.
138 */
dc2377d0 139int samsung_usbphy_set_type(struct usb_phy *phy,
8c1b3e16
VG
140 enum samsung_usb_phy_type phy_type)
141{
142 struct samsung_usbphy *sphy = phy_to_sphy(phy);
143
144 sphy->phy_type = phy_type;
145
146 return 0;
147}
dc2377d0 148EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
8c1b3e16 149
0aa823a2
TF
150int samsung_usbphy_rate_to_clksel_64xx(struct samsung_usbphy *sphy,
151 unsigned long rate)
152{
153 unsigned int clksel;
154
155 switch (rate) {
156 case 12 * MHZ:
157 clksel = PHYCLK_CLKSEL_12M;
158 break;
159 case 24 * MHZ:
160 clksel = PHYCLK_CLKSEL_24M;
161 break;
162 case 48 * MHZ:
163 clksel = PHYCLK_CLKSEL_48M;
164 break;
165 default:
166 dev_err(sphy->dev,
167 "Invalid reference clock frequency: %lu\n", rate);
168 return -EINVAL;
169 }
170
171 return clksel;
172}
173EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_64xx);
174
175int samsung_usbphy_rate_to_clksel_4x12(struct samsung_usbphy *sphy,
176 unsigned long rate)
177{
178 unsigned int clksel;
179
180 switch (rate) {
181 case 9600 * KHZ:
182 clksel = FSEL_CLKSEL_9600K;
183 break;
184 case 10 * MHZ:
185 clksel = FSEL_CLKSEL_10M;
186 break;
187 case 12 * MHZ:
188 clksel = FSEL_CLKSEL_12M;
189 break;
190 case 19200 * KHZ:
191 clksel = FSEL_CLKSEL_19200K;
192 break;
193 case 20 * MHZ:
194 clksel = FSEL_CLKSEL_20M;
195 break;
196 case 24 * MHZ:
197 clksel = FSEL_CLKSEL_24M;
198 break;
199 case 50 * MHZ:
200 clksel = FSEL_CLKSEL_50M;
201 break;
202 default:
203 dev_err(sphy->dev,
204 "Invalid reference clock frequency: %lu\n", rate);
205 return -EINVAL;
206 }
207
208 return clksel;
209}
210EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_4x12);
211
337dc3a7
PP
212/*
213 * Returns reference clock frequency selection value
214 */
dc2377d0 215int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
337dc3a7
PP
216{
217 struct clk *ref_clk;
0aa823a2
TF
218 unsigned long rate;
219 int refclk_freq;
337dc3a7 220
8c1b3e16
VG
221 /*
222 * In exynos5250 USB host and device PHY use
223 * external crystal clock XXTI
224 */
225 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
87331b06 226 ref_clk = clk_get(sphy->dev, "ext_xtal");
8c1b3e16 227 else
87331b06 228 ref_clk = clk_get(sphy->dev, "xusbxti");
337dc3a7
PP
229 if (IS_ERR(ref_clk)) {
230 dev_err(sphy->dev, "Failed to get reference clock\n");
231 return PTR_ERR(ref_clk);
232 }
233
0aa823a2
TF
234 rate = clk_get_rate(ref_clk);
235 refclk_freq = sphy->drv_data->rate_to_clksel(sphy, rate);
236
337dc3a7
PP
237 clk_put(ref_clk);
238
239 return refclk_freq;
240}
dc2377d0 241EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);
This page took 0.089433 seconds and 5 git commands to generate.