blob: c40ea321ae46ca0bfcd2fb5095373f589b959497 [file] [log] [blame]
Vivek Gautamdc2377d2013-03-14 15:59:10 +05301/* linux/drivers/usb/phy/phy-samsung-usb.c
Praveen Paneri337dc3a2012-11-23 16:03:06 +05302 *
3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Author: Praveen Paneri <p.paneri@samsung.com>
7 *
Vivek Gautamdc2377d2013-03-14 15:59:10 +05308 * 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.
Praveen Paneri337dc3a2012-11-23 16:03:06 +053011 *
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>
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053025#include <linux/device.h>
Praveen Paneri337dc3a2012-11-23 16:03:06 +053026#include <linux/err.h>
27#include <linux/io.h>
28#include <linux/of.h>
Vivek Gautam69f09462013-01-15 11:40:25 +053029#include <linux/of_address.h>
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053030#include <linux/usb/samsung_usb_phy.h>
Praveen Paneri337dc3a2012-11-23 16:03:06 +053031
Vivek Gautamdc2377d2013-03-14 15:59:10 +053032#include "phy-samsung-usb.h"
Praveen Paneri337dc3a2012-11-23 16:03:06 +053033
Vivek Gautamdc2377d2013-03-14 15:59:10 +053034int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
Vivek Gautam69f09462013-01-15 11:40:25 +053035{
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
Vivek Gautam69f09462013-01-15 11:40:25 +053047 if (sphy->pmuregs == NULL) {
48 dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053049 goto err0;
Vivek Gautam69f09462013-01-15 11:40:25 +053050 }
51
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053052 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
Vivek Gautam69f09462013-01-15 11:40:25 +053063 return 0;
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053064
65err0:
66 of_node_put(usbphy_sys);
67 return -ENXIO;
Vivek Gautam69f09462013-01-15 11:40:25 +053068}
Vivek Gautamdc2377d2013-03-14 15:59:10 +053069EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
Vivek Gautam69f09462013-01-15 11:40:25 +053070
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 */
Vivek Gautamdc2377d2013-03-14 15:59:10 +053076void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
Vivek Gautam69f09462013-01-15 11:40:25 +053077{
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053078 void __iomem *reg = NULL;
Vivek Gautam69f09462013-01-15 11:40:25 +053079 u32 reg_val;
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053080 u32 en_mask = 0;
Vivek Gautam69f09462013-01-15 11:40:25 +053081
82 if (!sphy->pmuregs) {
83 dev_warn(sphy->dev, "Can't set pmu isolation\n");
84 return;
85 }
86
Vivek Gautam8c1b3e12013-01-22 18:30:41 +053087 switch (sphy->drv_data->cpu_type) {
88 case TYPE_S3C64XX:
89 /*
90 * Do nothing: We will add here once S3C64xx goes for DT support
91 */
92 break;
93 case TYPE_EXYNOS4210:
94 /*
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.
98 */
99 case TYPE_EXYNOS5250:
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;
108 }
109 break;
110 default:
111 dev_err(sphy->dev, "Invalid SoC type\n");
112 return;
113 }
Vivek Gautam69f09462013-01-15 11:40:25 +0530114
115 reg_val = readl(reg);
116
117 if (on)
118 reg_val &= ~en_mask;
119 else
120 reg_val |= en_mask;
121
122 writel(reg_val, reg);
123}
Vivek Gautamdc2377d2013-03-14 15:59:10 +0530124EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation);
Vivek Gautam69f09462013-01-15 11:40:25 +0530125
Praveen Paneri337dc3a2012-11-23 16:03:06 +0530126/*
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530127 * Configure the mode of working of usb-phy here: HOST/DEVICE.
128 */
Vivek Gautamdc2377d2013-03-14 15:59:10 +0530129void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530130{
131 u32 reg;
132
133 if (!sphy->sysreg) {
134 dev_warn(sphy->dev, "Can't configure specified phy mode\n");
135 return;
136 }
137
138 reg = readl(sphy->sysreg);
139
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;
144
145 writel(reg, sphy->sysreg);
146}
Vivek Gautamdc2377d2013-03-14 15:59:10 +0530147EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530148
149/*
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.
153 */
Vivek Gautamdc2377d2013-03-14 15:59:10 +0530154int samsung_usbphy_set_type(struct usb_phy *phy,
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530155 enum samsung_usb_phy_type phy_type)
156{
157 struct samsung_usbphy *sphy = phy_to_sphy(phy);
158
159 sphy->phy_type = phy_type;
160
161 return 0;
162}
Vivek Gautamdc2377d2013-03-14 15:59:10 +0530163EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530164
Tomasz Figa0aa823a2013-05-16 11:57:08 +0200165int samsung_usbphy_rate_to_clksel_64xx(struct samsung_usbphy *sphy,
166 unsigned long rate)
167{
168 unsigned int clksel;
169
170 switch (rate) {
171 case 12 * MHZ:
172 clksel = PHYCLK_CLKSEL_12M;
173 break;
174 case 24 * MHZ:
175 clksel = PHYCLK_CLKSEL_24M;
176 break;
177 case 48 * MHZ:
178 clksel = PHYCLK_CLKSEL_48M;
179 break;
180 default:
181 dev_err(sphy->dev,
182 "Invalid reference clock frequency: %lu\n", rate);
183 return -EINVAL;
184 }
185
186 return clksel;
187}
188EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_64xx);
189
190int samsung_usbphy_rate_to_clksel_4x12(struct samsung_usbphy *sphy,
191 unsigned long rate)
192{
193 unsigned int clksel;
194
195 switch (rate) {
196 case 9600 * KHZ:
197 clksel = FSEL_CLKSEL_9600K;
198 break;
199 case 10 * MHZ:
200 clksel = FSEL_CLKSEL_10M;
201 break;
202 case 12 * MHZ:
203 clksel = FSEL_CLKSEL_12M;
204 break;
205 case 19200 * KHZ:
206 clksel = FSEL_CLKSEL_19200K;
207 break;
208 case 20 * MHZ:
209 clksel = FSEL_CLKSEL_20M;
210 break;
211 case 24 * MHZ:
212 clksel = FSEL_CLKSEL_24M;
213 break;
214 case 50 * MHZ:
215 clksel = FSEL_CLKSEL_50M;
216 break;
217 default:
218 dev_err(sphy->dev,
219 "Invalid reference clock frequency: %lu\n", rate);
220 return -EINVAL;
221 }
222
223 return clksel;
224}
225EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_4x12);
226
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530227/*
Praveen Paneri337dc3a2012-11-23 16:03:06 +0530228 * Returns reference clock frequency selection value
229 */
Vivek Gautamdc2377d2013-03-14 15:59:10 +0530230int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
Praveen Paneri337dc3a2012-11-23 16:03:06 +0530231{
232 struct clk *ref_clk;
Tomasz Figa0aa823a2013-05-16 11:57:08 +0200233 unsigned long rate;
234 int refclk_freq;
Praveen Paneri337dc3a2012-11-23 16:03:06 +0530235
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530236 /*
237 * In exynos5250 USB host and device PHY use
238 * external crystal clock XXTI
239 */
240 if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
Tomasz Figa87331b02013-05-16 11:57:07 +0200241 ref_clk = clk_get(sphy->dev, "ext_xtal");
Vivek Gautam8c1b3e12013-01-22 18:30:41 +0530242 else
Tomasz Figa87331b02013-05-16 11:57:07 +0200243 ref_clk = clk_get(sphy->dev, "xusbxti");
Praveen Paneri337dc3a2012-11-23 16:03:06 +0530244 if (IS_ERR(ref_clk)) {
245 dev_err(sphy->dev, "Failed to get reference clock\n");
246 return PTR_ERR(ref_clk);
247 }
248
Tomasz Figa0aa823a2013-05-16 11:57:08 +0200249 rate = clk_get_rate(ref_clk);
250 refclk_freq = sphy->drv_data->rate_to_clksel(sphy, rate);
251
Praveen Paneri337dc3a2012-11-23 16:03:06 +0530252 clk_put(ref_clk);
253
254 return refclk_freq;
255}
Vivek Gautamdc2377d2013-03-14 15:59:10 +0530256EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);