aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKamil Debski <k.debski@samsung.com>2014-07-01 11:15:54 -0400
committerKishon Vijay Abraham I <kishon@ti.com>2014-07-22 03:16:10 -0400
commit57416c23e3ab57e65ba6e7c2e30fb40ba85035a6 (patch)
treea505c4b06e6c361f13bf46768abde3ebdea5d2dc
parentad6202b4d941c69e9154419bd3002fbcacccbb67 (diff)
phy: phy-samsung-usb2: Change phy power on/power off sequence
The Exynos4412 USB 2.0 PHY hardware differs from the description provided in the documentation. Some register bits have different function. This patch fixes the defines of register bits and changes the way how phys are powered on and off. Signed-off-by: Kamil Debski <k.debski@samsung.com> Tested-by: Daniel Drake <drake@endlessm.com> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
-rw-r--r--drivers/phy/phy-exynos4x12-usb2.c112
-rw-r--r--drivers/phy/phy-exynos5250-usb2.c2
-rw-r--r--drivers/phy/phy-samsung-usb2.h3
3 files changed, 77 insertions, 40 deletions
diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c
index d92a7cc5698a..63134d8bda08 100644
--- a/drivers/phy/phy-exynos4x12-usb2.c
+++ b/drivers/phy/phy-exynos4x12-usb2.c
@@ -86,13 +86,23 @@
86#define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1) 86#define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1)
87#define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2) 87#define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2)
88#define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3) 88#define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3)
89/* The following bit defines are presented in the
90 * order taken from the Exynos4412 reference manual.
91 *
92 * During experiments with the hardware and debugging
93 * it was determined that the hardware behaves contrary
94 * to the manual.
95 *
96 * The following bit values were chaned accordingly to the
97 * results of real hardware experiments.
98 */
89#define EXYNOS_4x12_URSTCON_PHY1 BIT(4) 99#define EXYNOS_4x12_URSTCON_PHY1 BIT(4)
90#define EXYNOS_4x12_URSTCON_HSIC0 BIT(5) 100#define EXYNOS_4x12_URSTCON_HSIC0 BIT(6)
91#define EXYNOS_4x12_URSTCON_HSIC1 BIT(6) 101#define EXYNOS_4x12_URSTCON_HSIC1 BIT(5)
92#define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7) 102#define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7)
93#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(8) 103#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(10)
94#define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9) 104#define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9)
95#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(10) 105#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(8)
96 106
97/* Isolation, configured in the power management unit */ 107/* Isolation, configured in the power management unit */
98#define EXYNOS_4x12_USB_ISOL_OFFSET 0x704 108#define EXYNOS_4x12_USB_ISOL_OFFSET 0x704
@@ -188,6 +198,7 @@ static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst)
188 clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK); 198 clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK);
189 clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK; 199 clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK;
190 clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET; 200 clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET;
201 clk |= EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON;
191 writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK); 202 writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK);
192} 203}
193 204
@@ -198,27 +209,22 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
198 u32 phypwr = 0; 209 u32 phypwr = 0;
199 u32 rst; 210 u32 rst;
200 u32 pwr; 211 u32 pwr;
201 u32 mode = 0;
202 u32 switch_mode = 0;
203 212
204 switch (inst->cfg->id) { 213 switch (inst->cfg->id) {
205 case EXYNOS4x12_DEVICE: 214 case EXYNOS4x12_DEVICE:
206 phypwr = EXYNOS_4x12_UPHYPWR_PHY0; 215 phypwr = EXYNOS_4x12_UPHYPWR_PHY0;
207 rstbits = EXYNOS_4x12_URSTCON_PHY0; 216 rstbits = EXYNOS_4x12_URSTCON_PHY0;
208 mode = EXYNOS_4x12_MODE_SWITCH_DEVICE;
209 switch_mode = 1;
210 break; 217 break;
211 case EXYNOS4x12_HOST: 218 case EXYNOS4x12_HOST:
212 phypwr = EXYNOS_4x12_UPHYPWR_PHY1; 219 phypwr = EXYNOS_4x12_UPHYPWR_PHY1;
213 rstbits = EXYNOS_4x12_URSTCON_HOST_PHY; 220 rstbits = EXYNOS_4x12_URSTCON_HOST_PHY |
214 mode = EXYNOS_4x12_MODE_SWITCH_HOST; 221 EXYNOS_4x12_URSTCON_PHY1 |
215 switch_mode = 1; 222 EXYNOS_4x12_URSTCON_HOST_LINK_P0;
216 break; 223 break;
217 case EXYNOS4x12_HSIC0: 224 case EXYNOS4x12_HSIC0:
218 phypwr = EXYNOS_4x12_UPHYPWR_HSIC0; 225 phypwr = EXYNOS_4x12_UPHYPWR_HSIC0;
219 rstbits = EXYNOS_4x12_URSTCON_HSIC1 | 226 rstbits = EXYNOS_4x12_URSTCON_HSIC0 |
220 EXYNOS_4x12_URSTCON_HOST_LINK_P0 | 227 EXYNOS_4x12_URSTCON_HOST_LINK_P1;
221 EXYNOS_4x12_URSTCON_HOST_PHY;
222 break; 228 break;
223 case EXYNOS4x12_HSIC1: 229 case EXYNOS4x12_HSIC1:
224 phypwr = EXYNOS_4x12_UPHYPWR_HSIC1; 230 phypwr = EXYNOS_4x12_UPHYPWR_HSIC1;
@@ -228,11 +234,6 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
228 }; 234 };
229 235
230 if (on) { 236 if (on) {
231 if (switch_mode)
232 regmap_update_bits(drv->reg_sys,
233 EXYNOS_4x12_MODE_SWITCH_OFFSET,
234 EXYNOS_4x12_MODE_SWITCH_MASK, mode);
235
236 pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR); 237 pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
237 pwr &= ~phypwr; 238 pwr &= ~phypwr;
238 writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR); 239 writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
@@ -253,41 +254,78 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
253 } 254 }
254} 255}
255 256
256static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) 257static void exynos4x12_power_on_int(struct samsung_usb2_phy_instance *inst)
257{ 258{
258 struct samsung_usb2_phy_driver *drv = inst->drv; 259 if (inst->int_cnt++ > 0)
260 return;
259 261
260 inst->enabled = 1;
261 exynos4x12_setup_clk(inst); 262 exynos4x12_setup_clk(inst);
262 exynos4x12_phy_pwr(inst, 1);
263 exynos4x12_isol(inst, 0); 263 exynos4x12_isol(inst, 0);
264 exynos4x12_phy_pwr(inst, 1);
265}
266
267static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst)
268{
269 struct samsung_usb2_phy_driver *drv = inst->drv;
270
271 if (inst->ext_cnt++ > 0)
272 return 0;
264 273
265 /* Power on the device, as it is necessary for HSIC to work */ 274 if (inst->cfg->id == EXYNOS4x12_HOST) {
266 if (inst->cfg->id == EXYNOS4x12_HSIC0) { 275 regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET,
267 struct samsung_usb2_phy_instance *device = 276 EXYNOS_4x12_MODE_SWITCH_MASK,
268 &drv->instances[EXYNOS4x12_DEVICE]; 277 EXYNOS_4x12_MODE_SWITCH_HOST);
269 exynos4x12_phy_pwr(device, 1); 278 exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]);
270 exynos4x12_isol(device, 0);
271 } 279 }
272 280
281 if (inst->cfg->id == EXYNOS4x12_DEVICE)
282 regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET,
283 EXYNOS_4x12_MODE_SWITCH_MASK,
284 EXYNOS_4x12_MODE_SWITCH_DEVICE);
285
286 if (inst->cfg->id == EXYNOS4x12_HSIC0 ||
287 inst->cfg->id == EXYNOS4x12_HSIC1) {
288 exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]);
289 exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_HOST]);
290 }
291
292 exynos4x12_power_on_int(inst);
293
273 return 0; 294 return 0;
274} 295}
275 296
276static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst) 297static void exynos4x12_power_off_int(struct samsung_usb2_phy_instance *inst)
277{ 298{
278 struct samsung_usb2_phy_driver *drv = inst->drv; 299 if (inst->int_cnt-- > 1)
279 struct samsung_usb2_phy_instance *device = 300 return;
280 &drv->instances[EXYNOS4x12_DEVICE];
281 301
282 inst->enabled = 0;
283 exynos4x12_isol(inst, 1); 302 exynos4x12_isol(inst, 1);
284 exynos4x12_phy_pwr(inst, 0); 303 exynos4x12_phy_pwr(inst, 0);
304}
285 305
286 if (inst->cfg->id == EXYNOS4x12_HSIC0 && !device->enabled) { 306static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst)
287 exynos4x12_isol(device, 1); 307{
288 exynos4x12_phy_pwr(device, 0); 308 struct samsung_usb2_phy_driver *drv = inst->drv;
309
310 if (inst->ext_cnt-- > 1)
311 return 0;
312
313 if (inst->cfg->id == EXYNOS4x12_DEVICE)
314 regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET,
315 EXYNOS_4x12_MODE_SWITCH_MASK,
316 EXYNOS_4x12_MODE_SWITCH_HOST);
317
318 if (inst->cfg->id == EXYNOS4x12_HOST)
319 exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_DEVICE]);
320
321 if (inst->cfg->id == EXYNOS4x12_HSIC0 ||
322 inst->cfg->id == EXYNOS4x12_HSIC1) {
323 exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_DEVICE]);
324 exynos4x12_power_off_int(&drv->instances[EXYNOS4x12_HOST]);
289 } 325 }
290 326
327 exynos4x12_power_off_int(inst);
328
291 return 0; 329 return 0;
292} 330}
293 331
diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c
index 94179afda951..1c139aa0d074 100644
--- a/drivers/phy/phy-exynos5250-usb2.c
+++ b/drivers/phy/phy-exynos5250-usb2.c
@@ -318,7 +318,6 @@ static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
318 318
319 break; 319 break;
320 } 320 }
321 inst->enabled = 1;
322 exynos5250_isol(inst, 0); 321 exynos5250_isol(inst, 0);
323 322
324 return 0; 323 return 0;
@@ -331,7 +330,6 @@ static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
331 u32 otg; 330 u32 otg;
332 u32 hsic; 331 u32 hsic;
333 332
334 inst->enabled = 0;
335 exynos5250_isol(inst, 1); 333 exynos5250_isol(inst, 1);
336 334
337 switch (inst->cfg->id) { 335 switch (inst->cfg->id) {
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
index 45b3170652bd..918847843a95 100644
--- a/drivers/phy/phy-samsung-usb2.h
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -29,7 +29,8 @@ struct samsung_usb2_phy_instance {
29 const struct samsung_usb2_common_phy *cfg; 29 const struct samsung_usb2_common_phy *cfg;
30 struct phy *phy; 30 struct phy *phy;
31 struct samsung_usb2_phy_driver *drv; 31 struct samsung_usb2_phy_driver *drv;
32 bool enabled; 32 int int_cnt;
33 int ext_cnt;
33}; 34};
34 35
35struct samsung_usb2_phy_driver { 36struct samsung_usb2_phy_driver {