Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: miphy365x: Provide support for the MiPHY356x Generic PHY

The MiPHY365x is a Generic PHY which can serve various SATA or PCIe
devices. It has 2 ports which it can use for either; both SATA, both
PCIe or one of each in any configuration.

Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Alexandre Torgue <alexandre.torgue@st.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Lee Jones and committed by
Kishon Vijay Abraham I
6e877fed f5c9f3be

+627
+10
drivers/phy/Kconfig
··· 38 38 depends on OF 39 39 select GENERIC_PHY 40 40 41 + config PHY_MIPHY365X 42 + tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series" 43 + depends on ARCH_STI 44 + depends on GENERIC_PHY 45 + depends on HAS_IOMEM 46 + depends on OF 47 + help 48 + Enable this to support the miphy transceiver (for SATA/PCIE) 49 + that is part of STMicroelectronics STiH41x SoC series. 50 + 41 51 config OMAP_CONTROL_PHY 42 52 tristate "OMAP CONTROL PHY Driver" 43 53 depends on ARCH_OMAP2PLUS || COMPILE_TEST
+1
drivers/phy/Makefile
··· 8 8 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o 9 9 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o 10 10 obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o 11 + obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o 11 12 obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o 12 13 obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o 13 14 obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
+616
drivers/phy/phy-miphy365x.c
··· 1 + /* 2 + * Copyright (C) 2014 STMicroelectronics – All Rights Reserved 3 + * 4 + * STMicroelectronics PHY driver MiPHY365 (for SoC STiH416). 5 + * 6 + * Authors: Alexandre Torgue <alexandre.torgue@st.com> 7 + * Lee Jones <lee.jones@linaro.org> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2, as 11 + * published by the Free Software Foundation. 12 + * 13 + */ 14 + 15 + #include <linux/platform_device.h> 16 + #include <linux/io.h> 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/of.h> 20 + #include <linux/of_platform.h> 21 + #include <linux/clk.h> 22 + #include <linux/phy/phy.h> 23 + #include <linux/delay.h> 24 + #include <linux/mfd/syscon.h> 25 + #include <linux/regmap.h> 26 + 27 + #include <dt-bindings/phy/phy-miphy365x.h> 28 + 29 + #define HFC_TIMEOUT 100 30 + 31 + #define SYSCFG_2521 0x824 32 + #define SYSCFG_2522 0x828 33 + #define SYSCFG_PCIE_SATA_MASK BIT(1) 34 + #define SYSCFG_PCIE_SATA_POS 1 35 + 36 + /* MiPHY365x register definitions */ 37 + #define RESET_REG 0x00 38 + #define RST_PLL BIT(1) 39 + #define RST_PLL_CAL BIT(2) 40 + #define RST_RX BIT(4) 41 + #define RST_MACRO BIT(7) 42 + 43 + #define STATUS_REG 0x01 44 + #define IDLL_RDY BIT(0) 45 + #define PLL_RDY BIT(1) 46 + #define DES_BIT_LOCK BIT(2) 47 + #define DES_SYMBOL_LOCK BIT(3) 48 + 49 + #define CTRL_REG 0x02 50 + #define TERM_EN BIT(0) 51 + #define PCI_EN BIT(2) 52 + #define DES_BIT_LOCK_EN BIT(3) 53 + #define TX_POL BIT(5) 54 + 55 + #define INT_CTRL_REG 0x03 56 + 57 + #define BOUNDARY1_REG 0x10 58 + #define SPDSEL_SEL BIT(0) 59 + 60 + #define BOUNDARY3_REG 0x12 61 + #define TX_SPDSEL_GEN1_VAL 0 62 + #define TX_SPDSEL_GEN2_VAL 0x01 63 + #define TX_SPDSEL_GEN3_VAL 0x02 64 + #define RX_SPDSEL_GEN1_VAL 0 65 + #define RX_SPDSEL_GEN2_VAL (0x01 << 3) 66 + #define RX_SPDSEL_GEN3_VAL (0x02 << 3) 67 + 68 + #define PCIE_REG 0x16 69 + 70 + #define BUF_SEL_REG 0x20 71 + #define CONF_GEN_SEL_GEN3 0x02 72 + #define CONF_GEN_SEL_GEN2 0x01 73 + #define PD_VDDTFILTER BIT(4) 74 + 75 + #define TXBUF1_REG 0x21 76 + #define SWING_VAL 0x04 77 + #define SWING_VAL_GEN1 0x03 78 + #define PREEMPH_VAL (0x3 << 5) 79 + 80 + #define TXBUF2_REG 0x22 81 + #define TXSLEW_VAL 0x2 82 + #define TXSLEW_VAL_GEN1 0x4 83 + 84 + #define RXBUF_OFFSET_CTRL_REG 0x23 85 + 86 + #define RXBUF_REG 0x25 87 + #define SDTHRES_VAL 0x01 88 + #define EQ_ON3 (0x03 << 4) 89 + #define EQ_ON1 (0x01 << 4) 90 + 91 + #define COMP_CTRL1_REG 0x40 92 + #define START_COMSR BIT(0) 93 + #define START_COMZC BIT(1) 94 + #define COMSR_DONE BIT(2) 95 + #define COMZC_DONE BIT(3) 96 + #define COMP_AUTO_LOAD BIT(4) 97 + 98 + #define COMP_CTRL2_REG 0x41 99 + #define COMP_2MHZ_RAT_GEN1 0x1e 100 + #define COMP_2MHZ_RAT 0xf 101 + 102 + #define COMP_CTRL3_REG 0x42 103 + #define COMSR_COMP_REF 0x33 104 + 105 + #define COMP_IDLL_REG 0x47 106 + #define COMZC_IDLL 0x2a 107 + 108 + #define PLL_CTRL1_REG 0x50 109 + #define PLL_START_CAL BIT(0) 110 + #define BUF_EN BIT(2) 111 + #define SYNCHRO_TX BIT(3) 112 + #define SSC_EN BIT(6) 113 + #define CONFIG_PLL BIT(7) 114 + 115 + #define PLL_CTRL2_REG 0x51 116 + #define BYPASS_PLL_CAL BIT(1) 117 + 118 + #define PLL_RAT_REG 0x52 119 + 120 + #define PLL_SSC_STEP_MSB_REG 0x56 121 + #define PLL_SSC_STEP_MSB_VAL 0x03 122 + 123 + #define PLL_SSC_STEP_LSB_REG 0x57 124 + #define PLL_SSC_STEP_LSB_VAL 0x63 125 + 126 + #define PLL_SSC_PER_MSB_REG 0x58 127 + #define PLL_SSC_PER_MSB_VAL 0 128 + 129 + #define PLL_SSC_PER_LSB_REG 0x59 130 + #define PLL_SSC_PER_LSB_VAL 0xf1 131 + 132 + #define IDLL_TEST_REG 0x72 133 + #define START_CLK_HF BIT(6) 134 + 135 + #define DES_BITLOCK_REG 0x86 136 + #define BIT_LOCK_LEVEL 0x01 137 + #define BIT_LOCK_CNT_512 (0x03 << 5) 138 + 139 + static u8 ports[] = { MIPHY_PORT_0, MIPHY_PORT_1 }; 140 + 141 + struct miphy365x_phy { 142 + struct phy *phy; 143 + void __iomem *base; 144 + void __iomem *sata; 145 + void __iomem *pcie; 146 + u8 type; 147 + u8 port; 148 + }; 149 + 150 + struct miphy365x_dev { 151 + struct device *dev; 152 + struct regmap *regmap; 153 + struct mutex miphy_mutex; 154 + struct miphy365x phys[ARRAY_SIZE(ports)]; 155 + bool pcie_tx_pol_inv; 156 + bool sata_tx_pol_inv; 157 + u32 sata_gen; 158 + }; 159 + 160 + /* 161 + * These values are represented in Device tree. They are considered to be ABI 162 + * and although they can be extended any existing values must not change. 163 + */ 164 + enum miphy_sata_gen { 165 + SATA_GEN1 = 1, 166 + SATA_GEN2, 167 + SATA_GEN3 168 + }; 169 + 170 + static u8 rx_tx_spd[] = { 171 + TX_SPDSEL_GEN1_VAL | RX_SPDSEL_GEN1_VAL, 172 + TX_SPDSEL_GEN2_VAL | RX_SPDSEL_GEN2_VAL, 173 + TX_SPDSEL_GEN3_VAL | RX_SPDSEL_GEN3_VAL 174 + }; 175 + 176 + /* 177 + * This function selects the system configuration, 178 + * either two SATA, one SATA and one PCIe, or two PCIe lanes. 179 + */ 180 + static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, 181 + struct miphy365x_dev *miphy_dev) 182 + { 183 + u8 config = miphy_phy->type | miphy_phy->port; 184 + u32 mask = SYSCFG_PCIE_SATA_MASK; 185 + u32 reg; 186 + bool sata; 187 + 188 + switch (config) { 189 + case MIPHY_SATA_PORT0: 190 + reg = SYSCFG_2521; 191 + sata = true; 192 + break; 193 + case MIPHY_PCIE_PORT1: 194 + reg = SYSCFG_2522; 195 + sata = false; 196 + break; 197 + default: 198 + dev_err(miphy_dev->dev, "Configuration not supported\n"); 199 + return -EINVAL; 200 + } 201 + 202 + return regmap_update_bits(miphy_dev->regmap, reg, mask, 203 + sata << SYSCFG_PCIE_SATA_POS); 204 + } 205 + 206 + static int miphy365x_init_pcie_port(struct miphy365x_phy *miphy_phy, 207 + struct miphy365x_dev *miphy_dev) 208 + { 209 + u8 val; 210 + 211 + if (miphy_phy->pcie_tx_pol_inv) { 212 + /* Invert Tx polarity and clear pci_txdetect_pol bit */ 213 + val = TERM_EN | PCI_EN | DES_BIT_LOCK_EN | TX_POL; 214 + writeb_relaxed(val, miphy_phy->base + CTRL_REG); 215 + writeb_relaxed(0x00, miphy_phy->base + PCIE_REG); 216 + } 217 + 218 + return 0; 219 + } 220 + 221 + static inline int miphy365x_hfc_not_rdy(struct miphy365x_phy *miphy_phy, 222 + struct miphy365x_dev *miphy_dev) 223 + { 224 + unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT); 225 + u8 mask = IDLL_RDY | PLL_RDY; 226 + u8 regval; 227 + 228 + do { 229 + regval = readb_relaxed(miphy_phy->base + STATUS_REG); 230 + if (!(regval & mask)) 231 + return 0; 232 + 233 + usleep_range(2000, 2500); 234 + } while (time_before(jiffies, timeout)); 235 + 236 + dev_err(miphy_dev->dev, "HFC ready timeout!\n"); 237 + return -EBUSY; 238 + } 239 + 240 + static inline int miphy365x_rdy(struct miphy365x_phy *miphy_phy, 241 + struct miphy365x_dev *miphy_dev) 242 + { 243 + unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT); 244 + u8 mask = IDLL_RDY | PLL_RDY; 245 + u8 regval; 246 + 247 + do { 248 + regval = readb_relaxed(miphy_phy->base + STATUS_REG); 249 + if ((regval & mask) == mask) 250 + return 0; 251 + 252 + usleep_range(2000, 2500); 253 + } while (time_before(jiffies, timeout)); 254 + 255 + dev_err(miphy_dev->dev, "PHY not ready timeout!\n"); 256 + return -EBUSY; 257 + } 258 + 259 + static inline void miphy365x_set_comp(struct miphy365x_phy *miphy_phy, 260 + struct miphy365x_dev *miphy_dev) 261 + { 262 + u8 val, mask; 263 + 264 + if (miphy_dev->sata_gen == SATA_GEN1) 265 + writeb_relaxed(COMP_2MHZ_RAT_GEN1, 266 + miphy_phy->base + COMP_CTRL2_REG); 267 + else 268 + writeb_relaxed(COMP_2MHZ_RAT, 269 + miphy_phy->base + COMP_CTRL2_REG); 270 + 271 + if (miphy_dev->sata_gen != SATA_GEN3) { 272 + writeb_relaxed(COMSR_COMP_REF, 273 + miphy_phy->base + COMP_CTRL3_REG); 274 + /* 275 + * Force VCO current to value defined by address 0x5A 276 + * and disable PCIe100Mref bit 277 + * Enable auto load compensation for pll_i_bias 278 + */ 279 + writeb_relaxed(BYPASS_PLL_CAL, miphy_phy->base + PLL_CTRL2_REG); 280 + writeb_relaxed(COMZC_IDLL, miphy_phy->base + COMP_IDLL_REG); 281 + } 282 + 283 + /* 284 + * Force restart compensation and enable auto load 285 + * for Comzc_Tx, Comzc_Rx and Comsr on macro 286 + */ 287 + val = START_COMSR | START_COMZC | COMP_AUTO_LOAD; 288 + writeb_relaxed(val, miphy_phy->base + COMP_CTRL1_REG); 289 + 290 + mask = COMSR_DONE | COMZC_DONE; 291 + while ((readb_relaxed(miphy_phy->base + COMP_CTRL1_REG) & mask) != mask) 292 + cpu_relax(); 293 + } 294 + 295 + static inline void miphy365x_set_ssc(struct miphy365x_phy *miphy_phy, 296 + struct miphy365x_dev *miphy_dev) 297 + { 298 + u8 val; 299 + 300 + /* 301 + * SSC Settings. SSC will be enabled through Link 302 + * SSC Ampl. = 0.4% 303 + * SSC Freq = 31KHz 304 + */ 305 + writeb_relaxed(PLL_SSC_STEP_MSB_VAL, 306 + miphy_phy->base + PLL_SSC_STEP_MSB_REG); 307 + writeb_relaxed(PLL_SSC_STEP_LSB_VAL, 308 + miphy_phy->base + PLL_SSC_STEP_LSB_REG); 309 + writeb_relaxed(PLL_SSC_PER_MSB_VAL, 310 + miphy_phy->base + PLL_SSC_PER_MSB_REG); 311 + writeb_relaxed(PLL_SSC_PER_LSB_VAL, 312 + miphy_phy->base + PLL_SSC_PER_LSB_REG); 313 + 314 + /* SSC Settings complete */ 315 + if (miphy_dev->sata_gen == SATA_GEN1) { 316 + val = PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL; 317 + writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG); 318 + } else { 319 + val = SSC_EN | PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL; 320 + writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG); 321 + } 322 + } 323 + 324 + static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy, 325 + struct miphy365x_dev *miphy_dev) 326 + { 327 + int ret; 328 + u8 val; 329 + 330 + /* 331 + * Force PHY macro reset, PLL calibration reset, PLL reset 332 + * and assert Deserializer Reset 333 + */ 334 + val = RST_PLL | RST_PLL_CAL | RST_RX | RST_MACRO; 335 + writeb_relaxed(val, miphy_phy->base + RESET_REG); 336 + 337 + if (miphy_dev->sata_tx_pol_inv) 338 + writeb_relaxed(TX_POL, miphy_phy->base + CTRL_REG); 339 + 340 + /* 341 + * Force macro1 to use rx_lspd, tx_lspd 342 + * Force Rx_Clock on first I-DLL phase 343 + * Force Des in HP mode on macro, rx_lspd, tx_lspd for Gen2/3 344 + */ 345 + writeb_relaxed(SPDSEL_SEL, miphy_phy->base + BOUNDARY1_REG); 346 + writeb_relaxed(START_CLK_HF, miphy_phy->base + IDLL_TEST_REG); 347 + val = rx_tx_spd[miphy_dev->sata_gen]; 348 + writeb_relaxed(val, miphy_phy->base + BOUNDARY3_REG); 349 + 350 + /* Wait for HFC_READY = 0 */ 351 + ret = miphy365x_hfc_not_rdy(miphy_phy, miphy_dev); 352 + if (ret) 353 + return ret; 354 + 355 + /* Compensation Recalibration */ 356 + miphy365x_set_comp(miphy_phy, miphy_dev); 357 + 358 + switch (miphy_dev->sata_gen) { 359 + case SATA_GEN3: 360 + /* 361 + * TX Swing target 550-600mv peak to peak diff 362 + * Tx Slew target 90-110ps rising/falling time 363 + * Rx Eq ON3, Sigdet threshold SDTH1 364 + */ 365 + val = PD_VDDTFILTER | CONF_GEN_SEL_GEN3; 366 + writeb_relaxed(val, miphy_phy->base + BUF_SEL_REG); 367 + val = SWING_VAL | PREEMPH_VAL; 368 + writeb_relaxed(val, miphy_phy->base + TXBUF1_REG); 369 + writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG); 370 + writeb_relaxed(0x00, miphy_phy->base + RXBUF_OFFSET_CTRL_REG); 371 + val = SDTHRES_VAL | EQ_ON3; 372 + writeb_relaxed(val, miphy_phy->base + RXBUF_REG); 373 + break; 374 + case SATA_GEN2: 375 + /* 376 + * conf gen sel=0x1 to program Gen2 banked registers 377 + * VDDT filter ON 378 + * Tx Swing target 550-600mV peak-to-peak diff 379 + * Tx Slew target 90-110 ps rising/falling time 380 + * RX Equalization ON1, Sigdet threshold SDTH1 381 + */ 382 + writeb_relaxed(CONF_GEN_SEL_GEN2, 383 + miphy_phy->base + BUF_SEL_REG); 384 + writeb_relaxed(SWING_VAL, miphy_phy->base + TXBUF1_REG); 385 + writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG); 386 + val = SDTHRES_VAL | EQ_ON1; 387 + writeb_relaxed(val, miphy_phy->base + RXBUF_REG); 388 + break; 389 + case SATA_GEN1: 390 + /* 391 + * conf gen sel = 00b to program Gen1 banked registers 392 + * VDDT filter ON 393 + * Tx Swing target 500-550mV peak-to-peak diff 394 + * Tx Slew target120-140 ps rising/falling time 395 + */ 396 + writeb_relaxed(PD_VDDTFILTER, miphy_phy->base + BUF_SEL_REG); 397 + writeb_relaxed(SWING_VAL_GEN1, miphy_phy->base + TXBUF1_REG); 398 + writeb_relaxed(TXSLEW_VAL_GEN1, miphy_phy->base + TXBUF2_REG); 399 + break; 400 + default: 401 + break; 402 + } 403 + 404 + /* Force Macro1 in partial mode & release pll cal reset */ 405 + writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG); 406 + usleep_range(100, 150); 407 + 408 + miphy365x_set_ssc(miphy_phy, miphy_dev); 409 + 410 + /* Wait for phy_ready */ 411 + ret = miphy365x_rdy(miphy_phy, miphy_dev); 412 + if (ret) 413 + return ret; 414 + 415 + /* 416 + * Enable macro1 to use rx_lspd & tx_lspd 417 + * Release Rx_Clock on first I-DLL phase on macro1 418 + * Assert deserializer reset 419 + * des_bit_lock_en is set 420 + * bit lock detection strength 421 + * Deassert deserializer reset 422 + */ 423 + writeb_relaxed(0x00, miphy_phy->base + BOUNDARY1_REG); 424 + writeb_relaxed(0x00, miphy_phy->base + IDLL_TEST_REG); 425 + writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG); 426 + val = miphy_dev->sata_tx_pol_inv ? 427 + (TX_POL | DES_BIT_LOCK_EN) : DES_BIT_LOCK_EN; 428 + writeb_relaxed(val, miphy_phy->base + CTRL_REG); 429 + 430 + val = BIT_LOCK_CNT_512 | BIT_LOCK_LEVEL; 431 + writeb_relaxed(val, miphy_phy->base + DES_BITLOCK_REG); 432 + writeb_relaxed(0x00, miphy_phy->base + RESET_REG); 433 + 434 + return 0; 435 + } 436 + 437 + static int miphy365x_init(struct phy *phy) 438 + { 439 + struct miphy365x_phy *miphy_phy = phy_get_drvdata(phy); 440 + struct miphy365x_dev *miphy_dev = dev_get_drvdata(phy->dev.parent); 441 + int ret = 0; 442 + 443 + mutex_lock(&miphy_dev->miphy_mutex); 444 + 445 + ret = miphy365x_set_path(miphy_phy, miphy_dev); 446 + if (ret) { 447 + mutex_unlock(&miphy_dev->miphy_mutex); 448 + return ret; 449 + } 450 + 451 + /* Initialise Miphy for PCIe or SATA */ 452 + if (miphy_phy->type == MIPHY_TYPE_PCIE) 453 + ret = miphy365x_init_pcie_port(miphy_phy, miphy_dev); 454 + else 455 + ret = miphy365x_init_sata_port(miphy_phy, miphy_dev); 456 + 457 + mutex_unlock(&miphy_dev->miphy_mutex); 458 + 459 + return ret; 460 + } 461 + 462 + static struct phy *miphy365x_xlate(struct device *dev, 463 + struct of_phandle_args *args) 464 + { 465 + struct miphy365x_dev *state = dev_get_drvdata(dev); 466 + u8 port, type; 467 + 468 + if (args->count != 2) { 469 + dev_err(dev, "Invalid number of cells in 'phy' property\n"); 470 + return ERR_PTR(-EINVAL); 471 + } 472 + 473 + if (args->args[0] & 0xFFFFFF00 || args->args[1] & 0xFFFFFF00) { 474 + dev_err(dev, "Unsupported flags set in 'phy' property\n"); 475 + return ERR_PTR(-EINVAL); 476 + } 477 + 478 + port = args->args[0]; 479 + type = args->args[1]; 480 + 481 + if (WARN_ON(port >= ARRAY_SIZE(ports))) 482 + return ERR_PTR(-EINVAL); 483 + 484 + if (type == MIPHY_TYPE_SATA) 485 + state->phys[port].base = state->phys[port].sata; 486 + else if (type == MIPHY_TYPE_PCIE) 487 + state->phys[port].base = state->phys[port].pcie; 488 + else { 489 + WARN(1, "Invalid type specified in DT"); 490 + return ERR_PTR(-EINVAL); 491 + } 492 + 493 + state->phys[port].type = type; 494 + 495 + return state->phys[port].phy; 496 + } 497 + 498 + static struct phy_ops miphy365x_ops = { 499 + .init = miphy365x_init, 500 + .owner = THIS_MODULE, 501 + }; 502 + 503 + static int miphy365x_get_base_addr(struct platform_device *pdev, 504 + struct miphy365x_phy *phy, u8 port) 505 + { 506 + struct resource *res; 507 + char type[6]; 508 + 509 + sprintf(type, "sata%d", port); 510 + 511 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, type); 512 + phy->sata = devm_ioremap_resource(&pdev->dev, res)); 513 + if (!phy->sata) 514 + return -ENOMEM; 515 + 516 + sprintf(type, "pcie%d", port); 517 + 518 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, type); 519 + phy->pcie = devm_ioremap_resource(&pdev->dev, res)); 520 + if (!phy->pcie) 521 + return -ENOMEM; 522 + 523 + return 0; 524 + } 525 + 526 + static int miphy365x_of_probe(struct device_node *np, 527 + struct miphy365x_dev *phy_dev) 528 + { 529 + phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); 530 + if (IS_ERR(phy_dev->regmap)) { 531 + dev_err(phy_dev->dev, "No syscfg phandle specified\n"); 532 + return PTR_ERR(phy_dev->regmap); 533 + } 534 + 535 + of_property_read_u32(np, "st,sata-gen", &phy_dev->sata_gen); 536 + if (!phy_dev->sata_gen) 537 + phy_dev->sata_gen = SATA_GEN1; 538 + 539 + phy_dev->pcie_tx_pol_inv = 540 + of_property_read_bool(np, "st,pcie-tx-pol-inv"); 541 + 542 + phy_dev->sata_tx_pol_inv = 543 + of_property_read_bool(np, "st,sata-tx-pol-inv"); 544 + 545 + return 0; 546 + } 547 + 548 + static int miphy365x_probe(struct platform_device *pdev) 549 + { 550 + struct device_node *np = pdev->dev.of_node; 551 + struct miphy365x_dev *phy_dev; 552 + struct device *dev = &pdev->dev; 553 + struct phy_provider *provider; 554 + u8 port; 555 + int ret; 556 + 557 + phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL); 558 + if (!phy_dev) 559 + return -ENOMEM; 560 + 561 + ret = miphy365x_of_probe(np, phy_dev); 562 + if (ret) 563 + return ret; 564 + 565 + phy_dev->dev = dev; 566 + 567 + dev_set_drvdata(dev, phy_dev); 568 + 569 + mutex_init(&phy_dev->miphy_mutex); 570 + 571 + for (port = 0; port < ARRAY_SIZE(ports); port++) { 572 + struct phy *phy; 573 + 574 + phy = devm_phy_create(dev, &miphy365x_ops, NULL); 575 + if (IS_ERR(phy)) { 576 + dev_err(dev, "failed to create PHY on port %d\n", port); 577 + return PTR_ERR(phy); 578 + } 579 + 580 + phy_dev->phys[port].phy = phy; 581 + phy_dev->phys[port].port = port; 582 + 583 + ret = miphy365x_get_base_addr(pdev, 584 + &phy_dev->phys[port], port); 585 + if (ret) 586 + return ret; 587 + 588 + phy_set_drvdata(phy, &phy_dev->phys[port]); 589 + } 590 + 591 + provider = devm_of_phy_provider_register(dev, miphy365x_xlate); 592 + if (IS_ERR(provider)) 593 + return PTR_ERR(provider); 594 + 595 + return 0; 596 + } 597 + 598 + static const struct of_device_id miphy365x_of_match[] = { 599 + { .compatible = "st,miphy365x-phy", }, 600 + { }, 601 + }; 602 + MODULE_DEVICE_TABLE(of, miphy365x_of_match); 603 + 604 + static struct platform_driver miphy365x_driver = { 605 + .probe = miphy365x_probe, 606 + .driver = { 607 + .name = "miphy365x-phy", 608 + .owner = THIS_MODULE, 609 + .of_match_table = miphy365x_of_match, 610 + } 611 + }; 612 + module_platform_driver(miphy365x_driver); 613 + 614 + MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>"); 615 + MODULE_DESCRIPTION("STMicroelectronics miphy365x driver"); 616 + MODULE_LICENSE("GPL v2");