phy-exynos5250-usb2.c (13631B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support 4 * 5 * Copyright (C) 2013 Samsung Electronics Co., Ltd. 6 * Author: Kamil Debski <k.debski@samsung.com> 7 */ 8 9#include <linux/delay.h> 10#include <linux/io.h> 11#include <linux/phy/phy.h> 12#include <linux/regmap.h> 13#include "phy-samsung-usb2.h" 14 15/* Exynos USB PHY registers */ 16#define EXYNOS_5250_REFCLKSEL_CRYSTAL 0x0 17#define EXYNOS_5250_REFCLKSEL_XO 0x1 18#define EXYNOS_5250_REFCLKSEL_CLKCORE 0x2 19 20#define EXYNOS_5250_FSEL_9MHZ6 0x0 21#define EXYNOS_5250_FSEL_10MHZ 0x1 22#define EXYNOS_5250_FSEL_12MHZ 0x2 23#define EXYNOS_5250_FSEL_19MHZ2 0x3 24#define EXYNOS_5250_FSEL_20MHZ 0x4 25#define EXYNOS_5250_FSEL_24MHZ 0x5 26#define EXYNOS_5250_FSEL_50MHZ 0x7 27 28/* Normal host */ 29#define EXYNOS_5250_HOSTPHYCTRL0 0x0 30 31#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL BIT(31) 32#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT 19 33#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK \ 34 (0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT) 35#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT 16 36#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \ 37 (0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT) 38#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN BIT(11) 39#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE BIT(10) 40#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N BIT(9) 41#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK (0x3 << 7) 42#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL (0x0 << 7) 43#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0 (0x1 << 7) 44#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST (0x2 << 7) 45#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ BIT(6) 46#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP BIT(5) 47#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND BIT(4) 48#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE BIT(3) 49#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST BIT(2) 50#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST BIT(1) 51#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST BIT(0) 52 53/* HSIC0 & HSIC1 */ 54#define EXYNOS_5250_HSICPHYCTRL1 0x10 55#define EXYNOS_5250_HSICPHYCTRL2 0x20 56 57#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_MASK (0x3 << 23) 58#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT (0x2 << 23) 59#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_MASK (0x7f << 16) 60#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 (0x24 << 16) 61#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_15 (0x1c << 16) 62#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_16 (0x1a << 16) 63#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_19_2 (0x15 << 16) 64#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_20 (0x14 << 16) 65#define EXYNOS_5250_HSICPHYCTRLX_SIDDQ BIT(6) 66#define EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP BIT(5) 67#define EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND BIT(4) 68#define EXYNOS_5250_HSICPHYCTRLX_WORDINTERFACE BIT(3) 69#define EXYNOS_5250_HSICPHYCTRLX_UTMISWRST BIT(2) 70#define EXYNOS_5250_HSICPHYCTRLX_PHYSWRST BIT(0) 71 72/* EHCI control */ 73#define EXYNOS_5250_HOSTEHCICTRL 0x30 74#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN BIT(29) 75#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 BIT(28) 76#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 BIT(27) 77#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16 BIT(26) 78#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN BIT(25) 79#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT 19 80#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \ 81 (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT) 82#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT 13 83#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK \ 84 (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT) 85#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT 7 86#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \ 87 (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT) 88#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT 1 89#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \ 90 (0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT) 91#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE BIT(0) 92 93/* OHCI control */ 94#define EXYNOS_5250_HOSTOHCICTRL 0x34 95#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT 1 96#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \ 97 (0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT) 98#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN BIT(0) 99 100/* USBOTG */ 101#define EXYNOS_5250_USBOTGSYS 0x38 102#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET BIT(14) 103#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG BIT(13) 104#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST BIT(12) 105#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT 9 106#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \ 107 (0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT) 108#define EXYNOS_5250_USBOTGSYS_ID_PULLUP BIT(8) 109#define EXYNOS_5250_USBOTGSYS_COMMON_ON BIT(7) 110#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT 4 111#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \ 112 (0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT) 113#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP BIT(3) 114#define EXYNOS_5250_USBOTGSYS_OTGDISABLE BIT(2) 115#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG BIT(1) 116#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND BIT(0) 117 118/* Isolation, configured in the power management unit */ 119#define EXYNOS_5250_USB_ISOL_OTG_OFFSET 0x704 120#define EXYNOS_5250_USB_ISOL_HOST_OFFSET 0x708 121#define EXYNOS_5420_USB_ISOL_HOST_OFFSET 0x70C 122#define EXYNOS_5250_USB_ISOL_ENABLE BIT(0) 123 124/* Mode swtich register */ 125#define EXYNOS_5250_MODE_SWITCH_OFFSET 0x230 126#define EXYNOS_5250_MODE_SWITCH_MASK 1 127#define EXYNOS_5250_MODE_SWITCH_DEVICE 0 128#define EXYNOS_5250_MODE_SWITCH_HOST 1 129 130enum exynos4x12_phy_id { 131 EXYNOS5250_DEVICE, 132 EXYNOS5250_HOST, 133 EXYNOS5250_HSIC0, 134 EXYNOS5250_HSIC1, 135}; 136 137/* 138 * exynos5250_rate_to_clk() converts the supplied clock rate to the value that 139 * can be written to the phy register. 140 */ 141static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg) 142{ 143 /* EXYNOS_5250_FSEL_MASK */ 144 145 switch (rate) { 146 case 9600 * KHZ: 147 *reg = EXYNOS_5250_FSEL_9MHZ6; 148 break; 149 case 10 * MHZ: 150 *reg = EXYNOS_5250_FSEL_10MHZ; 151 break; 152 case 12 * MHZ: 153 *reg = EXYNOS_5250_FSEL_12MHZ; 154 break; 155 case 19200 * KHZ: 156 *reg = EXYNOS_5250_FSEL_19MHZ2; 157 break; 158 case 20 * MHZ: 159 *reg = EXYNOS_5250_FSEL_20MHZ; 160 break; 161 case 24 * MHZ: 162 *reg = EXYNOS_5250_FSEL_24MHZ; 163 break; 164 case 50 * MHZ: 165 *reg = EXYNOS_5250_FSEL_50MHZ; 166 break; 167 default: 168 return -EINVAL; 169 } 170 171 return 0; 172} 173 174static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on) 175{ 176 struct samsung_usb2_phy_driver *drv = inst->drv; 177 u32 offset; 178 u32 mask = EXYNOS_5250_USB_ISOL_ENABLE; 179 180 if (drv->cfg == &exynos5250_usb2_phy_config && 181 inst->cfg->id == EXYNOS5250_DEVICE) 182 offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET; 183 else if (drv->cfg == &exynos5250_usb2_phy_config && 184 inst->cfg->id == EXYNOS5250_HOST) 185 offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET; 186 else if (drv->cfg == &exynos5420_usb2_phy_config && 187 inst->cfg->id == EXYNOS5250_HOST) 188 offset = EXYNOS_5420_USB_ISOL_HOST_OFFSET; 189 else 190 return; 191 192 regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); 193} 194 195static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst) 196{ 197 struct samsung_usb2_phy_driver *drv = inst->drv; 198 u32 ctrl0; 199 u32 otg; 200 u32 ehci; 201 u32 ohci; 202 u32 hsic; 203 204 switch (inst->cfg->id) { 205 case EXYNOS5250_DEVICE: 206 regmap_update_bits(drv->reg_sys, 207 EXYNOS_5250_MODE_SWITCH_OFFSET, 208 EXYNOS_5250_MODE_SWITCH_MASK, 209 EXYNOS_5250_MODE_SWITCH_DEVICE); 210 211 /* OTG configuration */ 212 otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS); 213 /* The clock */ 214 otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK; 215 otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT; 216 /* Reset */ 217 otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND | 218 EXYNOS_5250_USBOTGSYS_FORCE_SLEEP | 219 EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG); 220 otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST | 221 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET | 222 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG | 223 EXYNOS_5250_USBOTGSYS_OTGDISABLE; 224 /* Ref clock */ 225 otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK; 226 otg |= EXYNOS_5250_REFCLKSEL_CLKCORE << 227 EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT; 228 writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS); 229 udelay(100); 230 otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST | 231 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG | 232 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET | 233 EXYNOS_5250_USBOTGSYS_OTGDISABLE); 234 writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS); 235 236 237 break; 238 case EXYNOS5250_HOST: 239 case EXYNOS5250_HSIC0: 240 case EXYNOS5250_HSIC1: 241 /* Host registers configuration */ 242 ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0); 243 /* The clock */ 244 ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK; 245 ctrl0 |= drv->ref_reg_val << 246 EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT; 247 248 /* Reset */ 249 ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST | 250 EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL | 251 EXYNOS_5250_HOSTPHYCTRL0_SIDDQ | 252 EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND | 253 EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP); 254 ctrl0 |= EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST | 255 EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST | 256 EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N; 257 writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0); 258 udelay(10); 259 ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST | 260 EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST); 261 writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0); 262 263 /* OTG configuration */ 264 otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS); 265 /* The clock */ 266 otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK; 267 otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT; 268 /* Reset */ 269 otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND | 270 EXYNOS_5250_USBOTGSYS_FORCE_SLEEP | 271 EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG); 272 otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST | 273 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET | 274 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG | 275 EXYNOS_5250_USBOTGSYS_OTGDISABLE; 276 /* Ref clock */ 277 otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK; 278 otg |= EXYNOS_5250_REFCLKSEL_CLKCORE << 279 EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT; 280 writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS); 281 udelay(10); 282 otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST | 283 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG | 284 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET); 285 286 /* HSIC phy configuration */ 287 hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 | 288 EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT | 289 EXYNOS_5250_HSICPHYCTRLX_PHYSWRST); 290 writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1); 291 writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2); 292 udelay(10); 293 hsic &= ~EXYNOS_5250_HSICPHYCTRLX_PHYSWRST; 294 writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1); 295 writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2); 296 /* The following delay is necessary for the reset sequence to be 297 * completed */ 298 udelay(80); 299 300 /* Enable EHCI DMA burst */ 301 ehci = readl(drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL); 302 ehci |= EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN | 303 EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 | 304 EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 | 305 EXYNOS_5250_HOSTEHCICTRL_ENAINCR16; 306 writel(ehci, drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL); 307 308 /* OHCI settings */ 309 ohci = readl(drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL); 310 /* Following code is based on the old driver */ 311 ohci |= 0x1 << 3; 312 writel(ohci, drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL); 313 314 break; 315 } 316 exynos5250_isol(inst, 0); 317 318 return 0; 319} 320 321static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst) 322{ 323 struct samsung_usb2_phy_driver *drv = inst->drv; 324 u32 ctrl0; 325 u32 otg; 326 u32 hsic; 327 328 exynos5250_isol(inst, 1); 329 330 switch (inst->cfg->id) { 331 case EXYNOS5250_DEVICE: 332 otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS); 333 otg |= (EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND | 334 EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG | 335 EXYNOS_5250_USBOTGSYS_FORCE_SLEEP); 336 writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS); 337 break; 338 case EXYNOS5250_HOST: 339 ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0); 340 ctrl0 |= (EXYNOS_5250_HOSTPHYCTRL0_SIDDQ | 341 EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND | 342 EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP | 343 EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST | 344 EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL); 345 writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0); 346 break; 347 case EXYNOS5250_HSIC0: 348 case EXYNOS5250_HSIC1: 349 hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 | 350 EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT | 351 EXYNOS_5250_HSICPHYCTRLX_SIDDQ | 352 EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP | 353 EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND 354 ); 355 writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1); 356 writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2); 357 break; 358 } 359 360 return 0; 361} 362 363 364static const struct samsung_usb2_common_phy exynos5250_phys[] = { 365 { 366 .label = "device", 367 .id = EXYNOS5250_DEVICE, 368 .power_on = exynos5250_power_on, 369 .power_off = exynos5250_power_off, 370 }, 371 { 372 .label = "host", 373 .id = EXYNOS5250_HOST, 374 .power_on = exynos5250_power_on, 375 .power_off = exynos5250_power_off, 376 }, 377 { 378 .label = "hsic0", 379 .id = EXYNOS5250_HSIC0, 380 .power_on = exynos5250_power_on, 381 .power_off = exynos5250_power_off, 382 }, 383 { 384 .label = "hsic1", 385 .id = EXYNOS5250_HSIC1, 386 .power_on = exynos5250_power_on, 387 .power_off = exynos5250_power_off, 388 }, 389}; 390 391static const struct samsung_usb2_common_phy exynos5420_phys[] = { 392 { 393 .label = "host", 394 .id = EXYNOS5250_HOST, 395 .power_on = exynos5250_power_on, 396 .power_off = exynos5250_power_off, 397 }, 398 { 399 .label = "hsic", 400 .id = EXYNOS5250_HSIC0, 401 .power_on = exynos5250_power_on, 402 .power_off = exynos5250_power_off, 403 }, 404}; 405 406const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = { 407 .has_mode_switch = 1, 408 .num_phys = ARRAY_SIZE(exynos5250_phys), 409 .phys = exynos5250_phys, 410 .rate_to_clk = exynos5250_rate_to_clk, 411}; 412 413const struct samsung_usb2_phy_config exynos5420_usb2_phy_config = { 414 .has_mode_switch = 1, 415 .num_phys = ARRAY_SIZE(exynos5420_phys), 416 .phys = exynos5420_phys, 417 .rate_to_clk = exynos5250_rate_to_clk, 418};