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

phy: phy-pxa-usb: add a new driver

Turned from arch/arm/mach-mmp/devices.c into a proper PHY driver, so
that in can be instantiated from a DT.

Acked-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Lubomir Rintel and committed by
Greg Kroah-Hartman
644930cb 89303c7e

+357
+11
drivers/phy/marvell/Kconfig
··· 59 59 The PHY driver will be used by Marvell udc/ehci/otg driver. 60 60 61 61 To compile this driver as a module, choose M here. 62 + 63 + config PHY_PXA_USB 64 + tristate "Marvell PXA USB PHY Driver" 65 + depends on ARCH_PXA || ARCH_MMP 66 + select GENERIC_PHY 67 + help 68 + Enable this to support Marvell PXA USB PHY driver for Marvell 69 + SoC. This driver will do the PHY initialization and shutdown. 70 + The PHY driver will be used by Marvell udc/ehci/otg driver. 71 + 72 + To compile this driver as a module, choose M here.
+1
drivers/phy/marvell/Makefile
··· 6 6 obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o 7 7 obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o 8 8 obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o 9 + obj-$(CONFIG_PHY_PXA_USB) += phy-pxa-usb.o
+345
drivers/phy/marvell/phy-pxa-usb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. 4 + * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk> 5 + */ 6 + 7 + #include <dt-bindings/phy/phy.h> 8 + #include <linux/clk.h> 9 + #include <linux/delay.h> 10 + #include <linux/io.h> 11 + #include <linux/module.h> 12 + #include <linux/of_address.h> 13 + #include <linux/phy/phy.h> 14 + #include <linux/platform_device.h> 15 + 16 + /* phy regs */ 17 + #define UTMI_REVISION 0x0 18 + #define UTMI_CTRL 0x4 19 + #define UTMI_PLL 0x8 20 + #define UTMI_TX 0xc 21 + #define UTMI_RX 0x10 22 + #define UTMI_IVREF 0x14 23 + #define UTMI_T0 0x18 24 + #define UTMI_T1 0x1c 25 + #define UTMI_T2 0x20 26 + #define UTMI_T3 0x24 27 + #define UTMI_T4 0x28 28 + #define UTMI_T5 0x2c 29 + #define UTMI_RESERVE 0x30 30 + #define UTMI_USB_INT 0x34 31 + #define UTMI_DBG_CTL 0x38 32 + #define UTMI_OTG_ADDON 0x3c 33 + 34 + /* For UTMICTRL Register */ 35 + #define UTMI_CTRL_USB_CLK_EN (1 << 31) 36 + /* pxa168 */ 37 + #define UTMI_CTRL_SUSPEND_SET1 (1 << 30) 38 + #define UTMI_CTRL_SUSPEND_SET2 (1 << 29) 39 + #define UTMI_CTRL_RXBUF_PDWN (1 << 24) 40 + #define UTMI_CTRL_TXBUF_PDWN (1 << 11) 41 + 42 + #define UTMI_CTRL_INPKT_DELAY_SHIFT 30 43 + #define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28 44 + #define UTMI_CTRL_PU_REF_SHIFT 20 45 + #define UTMI_CTRL_ARC_PULLDN_SHIFT 12 46 + #define UTMI_CTRL_PLL_PWR_UP_SHIFT 1 47 + #define UTMI_CTRL_PWR_UP_SHIFT 0 48 + 49 + /* For UTMI_PLL Register */ 50 + #define UTMI_PLL_PLLCALI12_SHIFT 29 51 + #define UTMI_PLL_PLLCALI12_MASK (0x3 << 29) 52 + 53 + #define UTMI_PLL_PLLVDD18_SHIFT 27 54 + #define UTMI_PLL_PLLVDD18_MASK (0x3 << 27) 55 + 56 + #define UTMI_PLL_PLLVDD12_SHIFT 25 57 + #define UTMI_PLL_PLLVDD12_MASK (0x3 << 25) 58 + 59 + #define UTMI_PLL_CLK_BLK_EN_SHIFT 24 60 + #define CLK_BLK_EN (0x1 << 24) 61 + #define PLL_READY (0x1 << 23) 62 + #define KVCO_EXT (0x1 << 22) 63 + #define VCOCAL_START (0x1 << 21) 64 + 65 + #define UTMI_PLL_KVCO_SHIFT 15 66 + #define UTMI_PLL_KVCO_MASK (0x7 << 15) 67 + 68 + #define UTMI_PLL_ICP_SHIFT 12 69 + #define UTMI_PLL_ICP_MASK (0x7 << 12) 70 + 71 + #define UTMI_PLL_FBDIV_SHIFT 4 72 + #define UTMI_PLL_FBDIV_MASK (0xFF << 4) 73 + 74 + #define UTMI_PLL_REFDIV_SHIFT 0 75 + #define UTMI_PLL_REFDIV_MASK (0xF << 0) 76 + 77 + /* For UTMI_TX Register */ 78 + #define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27 79 + #define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27) 80 + 81 + #define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26 82 + #define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26) 83 + 84 + #define UTMI_TX_TXVDD12_SHIFT 22 85 + #define UTMI_TX_TXVDD12_MASK (0x3 << 22) 86 + 87 + #define UTMI_TX_CK60_PHSEL_SHIFT 17 88 + #define UTMI_TX_CK60_PHSEL_MASK (0xf << 17) 89 + 90 + #define UTMI_TX_IMPCAL_VTH_SHIFT 14 91 + #define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14) 92 + 93 + #define REG_RCAL_START (0x1 << 12) 94 + 95 + #define UTMI_TX_LOW_VDD_EN_SHIFT 11 96 + 97 + #define UTMI_TX_AMP_SHIFT 0 98 + #define UTMI_TX_AMP_MASK (0x7 << 0) 99 + 100 + /* For UTMI_RX Register */ 101 + #define UTMI_REG_SQ_LENGTH_SHIFT 15 102 + #define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15) 103 + 104 + #define UTMI_RX_SQ_THRESH_SHIFT 4 105 + #define UTMI_RX_SQ_THRESH_MASK (0xf << 4) 106 + 107 + #define UTMI_OTG_ADDON_OTG_ON (1 << 0) 108 + 109 + enum pxa_usb_phy_version { 110 + PXA_USB_PHY_MMP2, 111 + PXA_USB_PHY_PXA910, 112 + PXA_USB_PHY_PXA168, 113 + }; 114 + 115 + struct pxa_usb_phy { 116 + struct phy *phy; 117 + void __iomem *base; 118 + enum pxa_usb_phy_version version; 119 + }; 120 + 121 + /***************************************************************************** 122 + * The registers read/write routines 123 + *****************************************************************************/ 124 + 125 + static unsigned int u2o_get(void __iomem *base, unsigned int offset) 126 + { 127 + return readl_relaxed(base + offset); 128 + } 129 + 130 + static void u2o_set(void __iomem *base, unsigned int offset, 131 + unsigned int value) 132 + { 133 + u32 reg; 134 + 135 + reg = readl_relaxed(base + offset); 136 + reg |= value; 137 + writel_relaxed(reg, base + offset); 138 + readl_relaxed(base + offset); 139 + } 140 + 141 + static void u2o_clear(void __iomem *base, unsigned int offset, 142 + unsigned int value) 143 + { 144 + u32 reg; 145 + 146 + reg = readl_relaxed(base + offset); 147 + reg &= ~value; 148 + writel_relaxed(reg, base + offset); 149 + readl_relaxed(base + offset); 150 + } 151 + 152 + static void u2o_write(void __iomem *base, unsigned int offset, 153 + unsigned int value) 154 + { 155 + writel_relaxed(value, base + offset); 156 + readl_relaxed(base + offset); 157 + } 158 + 159 + static int pxa_usb_phy_init(struct phy *phy) 160 + { 161 + struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy); 162 + void __iomem *base = pxa_usb_phy->base; 163 + int loops; 164 + 165 + dev_info(&phy->dev, "initializing Marvell PXA USB PHY"); 166 + 167 + /* Initialize the USB PHY power */ 168 + if (pxa_usb_phy->version == PXA_USB_PHY_PXA910) { 169 + u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT) 170 + | (1<<UTMI_CTRL_PU_REF_SHIFT)); 171 + } 172 + 173 + u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT); 174 + u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT); 175 + 176 + /* UTMI_PLL settings */ 177 + u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK 178 + | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK 179 + | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK 180 + | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK); 181 + 182 + u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT 183 + | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT 184 + | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT 185 + | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT); 186 + 187 + /* UTMI_TX */ 188 + u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK 189 + | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK 190 + | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK 191 + | UTMI_TX_AMP_MASK); 192 + u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT 193 + | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT 194 + | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT); 195 + 196 + /* UTMI_RX */ 197 + u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK 198 + | UTMI_REG_SQ_LENGTH_MASK); 199 + u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT 200 + | 2<<UTMI_REG_SQ_LENGTH_SHIFT); 201 + 202 + /* UTMI_IVREF */ 203 + if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) { 204 + /* 205 + * fixing Microsoft Altair board interface with NEC hub issue - 206 + * Set UTMI_IVREF from 0x4a3 to 0x4bf 207 + */ 208 + u2o_write(base, UTMI_IVREF, 0x4bf); 209 + } 210 + 211 + /* toggle VCOCAL_START bit of UTMI_PLL */ 212 + udelay(200); 213 + u2o_set(base, UTMI_PLL, VCOCAL_START); 214 + udelay(40); 215 + u2o_clear(base, UTMI_PLL, VCOCAL_START); 216 + 217 + /* toggle REG_RCAL_START bit of UTMI_TX */ 218 + udelay(400); 219 + u2o_set(base, UTMI_TX, REG_RCAL_START); 220 + udelay(40); 221 + u2o_clear(base, UTMI_TX, REG_RCAL_START); 222 + udelay(400); 223 + 224 + /* Make sure PHY PLL is ready */ 225 + loops = 0; 226 + while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) { 227 + mdelay(1); 228 + loops++; 229 + if (loops > 100) { 230 + dev_warn(&phy->dev, "calibrate timeout, UTMI_PLL %x\n", 231 + u2o_get(base, UTMI_PLL)); 232 + break; 233 + } 234 + } 235 + 236 + if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) { 237 + u2o_set(base, UTMI_RESERVE, 1 << 5); 238 + /* Turn on UTMI PHY OTG extension */ 239 + u2o_write(base, UTMI_OTG_ADDON, 1); 240 + } 241 + 242 + return 0; 243 + 244 + } 245 + 246 + static int pxa_usb_phy_exit(struct phy *phy) 247 + { 248 + struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy); 249 + void __iomem *base = pxa_usb_phy->base; 250 + 251 + dev_info(&phy->dev, "deinitializing Marvell PXA USB PHY"); 252 + 253 + if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) 254 + u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON); 255 + 256 + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN); 257 + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN); 258 + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN); 259 + u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT); 260 + u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT); 261 + 262 + return 0; 263 + } 264 + 265 + static const struct phy_ops pxa_usb_phy_ops = { 266 + .init = pxa_usb_phy_init, 267 + .exit = pxa_usb_phy_exit, 268 + .owner = THIS_MODULE, 269 + }; 270 + 271 + static const struct of_device_id pxa_usb_phy_of_match[] = { 272 + { 273 + .compatible = "marvell,mmp2-usb-phy", 274 + .data = (void *)PXA_USB_PHY_MMP2, 275 + }, { 276 + .compatible = "marvell,pxa910-usb-phy", 277 + .data = (void *)PXA_USB_PHY_PXA910, 278 + }, { 279 + .compatible = "marvell,pxa168-usb-phy", 280 + .data = (void *)PXA_USB_PHY_PXA168, 281 + }, 282 + { }, 283 + }; 284 + MODULE_DEVICE_TABLE(of, pxa_usb_phy_of_match); 285 + 286 + static int pxa_usb_phy_probe(struct platform_device *pdev) 287 + { 288 + struct device *dev = &pdev->dev; 289 + struct resource *resource; 290 + struct pxa_usb_phy *pxa_usb_phy; 291 + struct phy_provider *provider; 292 + const struct of_device_id *of_id; 293 + 294 + pxa_usb_phy = devm_kzalloc(dev, sizeof(struct pxa_usb_phy), GFP_KERNEL); 295 + if (!pxa_usb_phy) 296 + return -ENOMEM; 297 + 298 + of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node); 299 + if (of_id) 300 + pxa_usb_phy->version = (enum pxa_usb_phy_version)of_id->data; 301 + else 302 + pxa_usb_phy->version = PXA_USB_PHY_MMP2; 303 + 304 + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 305 + pxa_usb_phy->base = devm_ioremap_resource(dev, resource); 306 + if (IS_ERR(pxa_usb_phy->base)) { 307 + dev_err(dev, "failed to remap PHY regs\n"); 308 + return PTR_ERR(pxa_usb_phy->base); 309 + } 310 + 311 + pxa_usb_phy->phy = devm_phy_create(dev, NULL, &pxa_usb_phy_ops); 312 + if (IS_ERR(pxa_usb_phy->phy)) { 313 + dev_err(dev, "failed to create PHY\n"); 314 + return PTR_ERR(pxa_usb_phy->phy); 315 + } 316 + 317 + phy_set_drvdata(pxa_usb_phy->phy, pxa_usb_phy); 318 + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 319 + if (IS_ERR(provider)) { 320 + dev_err(dev, "failed to register PHY provider\n"); 321 + return PTR_ERR(provider); 322 + } 323 + 324 + if (!dev->of_node) { 325 + phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-udc"); 326 + phy_create_lookup(pxa_usb_phy->phy, "usb", "pxa-u2oehci"); 327 + phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-otg"); 328 + } 329 + 330 + dev_info(dev, "Marvell PXA USB PHY"); 331 + return 0; 332 + } 333 + 334 + static struct platform_driver pxa_usb_phy_driver = { 335 + .probe = pxa_usb_phy_probe, 336 + .driver = { 337 + .name = "pxa-usb-phy", 338 + .of_match_table = pxa_usb_phy_of_match, 339 + }, 340 + }; 341 + module_platform_driver(pxa_usb_phy_driver); 342 + 343 + MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); 344 + MODULE_DESCRIPTION("Marvell PXA USB PHY Driver"); 345 + MODULE_LICENSE("GPL v2");