bnx2fc: do not add shared skbs to the fcoe_rx_list
[firefly-linux-kernel-4.4.55.git] / drivers / usb / phy / phy-samsung-usb.c
1 /* linux/drivers/usb/phy/phy-samsung-usb.c
2  *
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * Author: Praveen Paneri <p.paneri@samsung.com>
7  *
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.
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>
25 #include <linux/device.h>
26 #include <linux/err.h>
27 #include <linux/io.h>
28 #include <linux/of.h>
29 #include <linux/of_address.h>
30 #include <linux/usb/samsung_usb_phy.h>
31
32 #include "phy-samsung-usb.h"
33
34 int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
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
47         if (sphy->pmuregs == NULL) {
48                 dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
49                 goto err0;
50         }
51
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
63         return 0;
64
65 err0:
66         of_node_put(usbphy_sys);
67         return -ENXIO;
68 }
69 EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
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  */
76 void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
77 {
78         void __iomem *reg = NULL;
79         u32 reg_val;
80         u32 en_mask = 0;
81
82         if (!sphy->pmuregs) {
83                 dev_warn(sphy->dev, "Can't set pmu isolation\n");
84                 return;
85         }
86
87         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         }
114
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 }
124 EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation);
125
126 /*
127  * Configure the mode of working of usb-phy here: HOST/DEVICE.
128  */
129 void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
130 {
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 }
147 EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
148
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  */
154 int samsung_usbphy_set_type(struct usb_phy *phy,
155                                 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 }
163 EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
164
165 /*
166  * Returns reference clock frequency selection value
167  */
168 int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
169 {
170         struct clk *ref_clk;
171         int refclk_freq = 0;
172
173         /*
174          * In exynos5250 USB host and device PHY use
175          * external crystal clock XXTI
176          */
177         if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
178                 ref_clk = devm_clk_get(sphy->dev, "ext_xtal");
179         else
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);
184         }
185
186         if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
187                 /* set clock frequency for PLL */
188                 switch (clk_get_rate(ref_clk)) {
189                 case 9600 * KHZ:
190                         refclk_freq = FSEL_CLKSEL_9600K;
191                         break;
192                 case 10 * MHZ:
193                         refclk_freq = FSEL_CLKSEL_10M;
194                         break;
195                 case 12 * MHZ:
196                         refclk_freq = FSEL_CLKSEL_12M;
197                         break;
198                 case 19200 * KHZ:
199                         refclk_freq = FSEL_CLKSEL_19200K;
200                         break;
201                 case 20 * MHZ:
202                         refclk_freq = FSEL_CLKSEL_20M;
203                         break;
204                 case 50 * MHZ:
205                         refclk_freq = FSEL_CLKSEL_50M;
206                         break;
207                 case 24 * MHZ:
208                 default:
209                         /* default reference clock */
210                         refclk_freq = FSEL_CLKSEL_24M;
211                         break;
212                 }
213         } else {
214                 switch (clk_get_rate(ref_clk)) {
215                 case 12 * MHZ:
216                         refclk_freq = PHYCLK_CLKSEL_12M;
217                         break;
218                 case 24 * MHZ:
219                         refclk_freq = PHYCLK_CLKSEL_24M;
220                         break;
221                 case 48 * MHZ:
222                         refclk_freq = PHYCLK_CLKSEL_48M;
223                         break;
224                 default:
225                         if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
226                                 refclk_freq = PHYCLK_CLKSEL_48M;
227                         else
228                                 refclk_freq = PHYCLK_CLKSEL_24M;
229                         break;
230                 }
231         }
232         clk_put(ref_clk);
233
234         return refclk_freq;
235 }
236 EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);