aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 {