344 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 0x018#define UTMI_CTRL 0x419#define UTMI_PLL 0x820#define UTMI_TX 0xc21#define UTMI_RX 0x1022#define UTMI_IVREF 0x1423#define UTMI_T0 0x1824#define UTMI_T1 0x1c25#define UTMI_T2 0x2026#define UTMI_T3 0x2427#define UTMI_T4 0x2828#define UTMI_T5 0x2c29#define UTMI_RESERVE 0x3030#define UTMI_USB_INT 0x3431#define UTMI_DBG_CTL 0x3832#define UTMI_OTG_ADDON 0x3c33 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 3043#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 2844#define UTMI_CTRL_PU_REF_SHIFT 2045#define UTMI_CTRL_ARC_PULLDN_SHIFT 1246#define UTMI_CTRL_PLL_PWR_UP_SHIFT 147#define UTMI_CTRL_PWR_UP_SHIFT 048 49/* For UTMI_PLL Register */50#define UTMI_PLL_PLLCALI12_SHIFT 2951#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)52 53#define UTMI_PLL_PLLVDD18_SHIFT 2754#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)55 56#define UTMI_PLL_PLLVDD12_SHIFT 2557#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)58 59#define UTMI_PLL_CLK_BLK_EN_SHIFT 2460#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 1566#define UTMI_PLL_KVCO_MASK (0x7 << 15)67 68#define UTMI_PLL_ICP_SHIFT 1269#define UTMI_PLL_ICP_MASK (0x7 << 12)70 71#define UTMI_PLL_FBDIV_SHIFT 472#define UTMI_PLL_FBDIV_MASK (0xFF << 4)73 74#define UTMI_PLL_REFDIV_SHIFT 075#define UTMI_PLL_REFDIV_MASK (0xF << 0)76 77/* For UTMI_TX Register */78#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 2779#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)80 81#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 2682#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26)83 84#define UTMI_TX_TXVDD12_SHIFT 2285#define UTMI_TX_TXVDD12_MASK (0x3 << 22)86 87#define UTMI_TX_CK60_PHSEL_SHIFT 1788#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)89 90#define UTMI_TX_IMPCAL_VTH_SHIFT 1491#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 1196 97#define UTMI_TX_AMP_SHIFT 098#define UTMI_TX_AMP_MASK (0x7 << 0)99 100/* For UTMI_RX Register */101#define UTMI_REG_SQ_LENGTH_SHIFT 15102#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)103 104#define UTMI_RX_SQ_THRESH_SHIFT 4105#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)106 107#define UTMI_OTG_ADDON_OTG_ON (1 << 0)108 109enum pxa_usb_phy_version {110 PXA_USB_PHY_MMP2,111 PXA_USB_PHY_PXA910,112 PXA_USB_PHY_PXA168,113};114 115struct 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 routines123 *****************************************************************************/124 125static unsigned int u2o_get(void __iomem *base, unsigned int offset)126{127 return readl_relaxed(base + offset);128}129 130static 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 141static 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 152static 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 159static 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_MASK178 | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK179 | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK180 | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);181 182 u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT183 | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT184 | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT185 | 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_MASK189 | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK190 | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK191 | UTMI_TX_AMP_MASK);192 u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT193 | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT194 | 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_MASK198 | UTMI_REG_SQ_LENGTH_MASK);199 u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT200 | 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 0x4bf207 */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 246static 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 265static 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 271static 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};284MODULE_DEVICE_TABLE(of, pxa_usb_phy_of_match);285 286static int pxa_usb_phy_probe(struct platform_device *pdev)287{288 struct device *dev = &pdev->dev;289 struct pxa_usb_phy *pxa_usb_phy;290 struct phy_provider *provider;291 const struct of_device_id *of_id;292 293 pxa_usb_phy = devm_kzalloc(dev, sizeof(struct pxa_usb_phy), GFP_KERNEL);294 if (!pxa_usb_phy)295 return -ENOMEM;296 297 of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node);298 if (of_id)299 pxa_usb_phy->version = (uintptr_t)of_id->data;300 else301 pxa_usb_phy->version = PXA_USB_PHY_MMP2;302 303 pxa_usb_phy->base = devm_platform_ioremap_resource(pdev, 0);304 if (IS_ERR(pxa_usb_phy->base)) {305 dev_err(dev, "failed to remap PHY regs\n");306 return PTR_ERR(pxa_usb_phy->base);307 }308 309 pxa_usb_phy->phy = devm_phy_create(dev, NULL, &pxa_usb_phy_ops);310 if (IS_ERR(pxa_usb_phy->phy)) {311 dev_err(dev, "failed to create PHY\n");312 return PTR_ERR(pxa_usb_phy->phy);313 }314 315 phy_set_drvdata(pxa_usb_phy->phy, pxa_usb_phy);316 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);317 if (IS_ERR(provider)) {318 dev_err(dev, "failed to register PHY provider\n");319 return PTR_ERR(provider);320 }321 322 if (!dev->of_node) {323 phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-udc");324 phy_create_lookup(pxa_usb_phy->phy, "usb", "pxa-u2oehci");325 phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-otg");326 }327 328 dev_info(dev, "Marvell PXA USB PHY");329 return 0;330}331 332static struct platform_driver pxa_usb_phy_driver = {333 .probe = pxa_usb_phy_probe,334 .driver = {335 .name = "pxa-usb-phy",336 .of_match_table = pxa_usb_phy_of_match,337 },338};339module_platform_driver(pxa_usb_phy_driver);340 341MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");342MODULE_DESCRIPTION("Marvell PXA USB PHY Driver");343MODULE_LICENSE("GPL v2");344