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

phy: add driver for Freescale i.MX8MQ USB3 PHY

This is a cleaned up port of the downstream i.MX8MQ USB3 PHY driver.

Signed-off-by: Li Jun <jun.li@nxp.com>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Li Jun and committed by
Kishon Vijay Abraham I
efe81bea 3c2ce40b

+135
+1
drivers/phy/Kconfig
··· 44 44 source "drivers/phy/amlogic/Kconfig" 45 45 source "drivers/phy/broadcom/Kconfig" 46 46 source "drivers/phy/cadence/Kconfig" 47 + source "drivers/phy/freescale/Kconfig" 47 48 source "drivers/phy/hisilicon/Kconfig" 48 49 source "drivers/phy/lantiq/Kconfig" 49 50 source "drivers/phy/marvell/Kconfig"
+1
drivers/phy/Makefile
··· 16 16 obj-$(CONFIG_ARCH_TEGRA) += tegra/ 17 17 obj-y += broadcom/ \ 18 18 cadence/ \ 19 + freescale/ \ 19 20 hisilicon/ \ 20 21 marvell/ \ 21 22 motorola/ \
+5
drivers/phy/freescale/Kconfig
··· 1 + config PHY_FSL_IMX8MQ_USB 2 + tristate "Freescale i.MX8M USB3 PHY" 3 + depends on OF && HAS_IOMEM 4 + select GENERIC_PHY 5 + default SOC_IMX8MQ
+1
drivers/phy/freescale/Makefile
··· 1 + obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o
+127
drivers/phy/freescale/phy-fsl-imx8mq-usb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* Copyright (c) 2017 NXP. */ 3 + 4 + #include <linux/clk.h> 5 + #include <linux/io.h> 6 + #include <linux/module.h> 7 + #include <linux/phy/phy.h> 8 + #include <linux/platform_device.h> 9 + 10 + #define PHY_CTRL0 0x0 11 + #define PHY_CTRL0_REF_SSP_EN BIT(2) 12 + 13 + #define PHY_CTRL1 0x4 14 + #define PHY_CTRL1_RESET BIT(0) 15 + #define PHY_CTRL1_COMMONONN BIT(1) 16 + #define PHY_CTRL1_ATERESET BIT(3) 17 + #define PHY_CTRL1_VDATSRCENB0 BIT(19) 18 + #define PHY_CTRL1_VDATDETENB0 BIT(20) 19 + 20 + #define PHY_CTRL2 0x8 21 + #define PHY_CTRL2_TXENABLEN0 BIT(8) 22 + 23 + struct imx8mq_usb_phy { 24 + struct phy *phy; 25 + struct clk *clk; 26 + void __iomem *base; 27 + }; 28 + 29 + static int imx8mq_usb_phy_init(struct phy *phy) 30 + { 31 + struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 32 + u32 value; 33 + 34 + value = readl(imx_phy->base + PHY_CTRL1); 35 + value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 | 36 + PHY_CTRL1_COMMONONN); 37 + value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; 38 + writel(value, imx_phy->base + PHY_CTRL1); 39 + 40 + value = readl(imx_phy->base + PHY_CTRL0); 41 + value |= PHY_CTRL0_REF_SSP_EN; 42 + writel(value, imx_phy->base + PHY_CTRL0); 43 + 44 + value = readl(imx_phy->base + PHY_CTRL2); 45 + value |= PHY_CTRL2_TXENABLEN0; 46 + writel(value, imx_phy->base + PHY_CTRL2); 47 + 48 + value = readl(imx_phy->base + PHY_CTRL1); 49 + value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); 50 + writel(value, imx_phy->base + PHY_CTRL1); 51 + 52 + return 0; 53 + } 54 + 55 + static int imx8mq_phy_power_on(struct phy *phy) 56 + { 57 + struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 58 + 59 + return clk_prepare_enable(imx_phy->clk); 60 + } 61 + 62 + static int imx8mq_phy_power_off(struct phy *phy) 63 + { 64 + struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); 65 + 66 + clk_disable_unprepare(imx_phy->clk); 67 + 68 + return 0; 69 + } 70 + 71 + static struct phy_ops imx8mq_usb_phy_ops = { 72 + .init = imx8mq_usb_phy_init, 73 + .power_on = imx8mq_phy_power_on, 74 + .power_off = imx8mq_phy_power_off, 75 + .owner = THIS_MODULE, 76 + }; 77 + 78 + static int imx8mq_usb_phy_probe(struct platform_device *pdev) 79 + { 80 + struct phy_provider *phy_provider; 81 + struct device *dev = &pdev->dev; 82 + struct imx8mq_usb_phy *imx_phy; 83 + struct resource *res; 84 + 85 + imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL); 86 + if (!imx_phy) 87 + return -ENOMEM; 88 + 89 + imx_phy->clk = devm_clk_get(dev, "phy"); 90 + if (IS_ERR(imx_phy->clk)) { 91 + dev_err(dev, "failed to get imx8mq usb phy clock\n"); 92 + return PTR_ERR(imx_phy->clk); 93 + } 94 + 95 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 96 + imx_phy->base = devm_ioremap_resource(dev, res); 97 + if (IS_ERR(imx_phy->base)) 98 + return PTR_ERR(imx_phy->base); 99 + 100 + imx_phy->phy = devm_phy_create(dev, NULL, &imx8mq_usb_phy_ops); 101 + if (IS_ERR(imx_phy->phy)) 102 + return PTR_ERR(imx_phy->phy); 103 + 104 + phy_set_drvdata(imx_phy->phy, imx_phy); 105 + 106 + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 107 + 108 + return PTR_ERR_OR_ZERO(phy_provider); 109 + } 110 + 111 + static const struct of_device_id imx8mq_usb_phy_of_match[] = { 112 + {.compatible = "fsl,imx8mq-usb-phy",}, 113 + { }, 114 + }; 115 + MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match); 116 + 117 + static struct platform_driver imx8mq_usb_phy_driver = { 118 + .probe = imx8mq_usb_phy_probe, 119 + .driver = { 120 + .name = "imx8mq-usb-phy", 121 + .of_match_table = imx8mq_usb_phy_of_match, 122 + } 123 + }; 124 + module_platform_driver(imx8mq_usb_phy_driver); 125 + 126 + MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver"); 127 + MODULE_LICENSE("GPL");