Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Li Jun | 875 | 92.89% | 2 | 33.33% |
Lucas Stach | 62 | 6.58% | 1 | 16.67% |
Chunfeng Yun | 3 | 0.32% | 1 | 16.67% |
Rikard Falkeborn | 2 | 0.21% | 2 | 33.33% |
Total | 942 | 6 |
// SPDX-License-Identifier: GPL-2.0+ /* Copyright (c) 2017 NXP. */ #include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of_platform.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #define PHY_CTRL0 0x0 #define PHY_CTRL0_REF_SSP_EN BIT(2) #define PHY_CTRL0_FSEL_MASK GENMASK(10, 5) #define PHY_CTRL0_FSEL_24M 0x2a #define PHY_CTRL1 0x4 #define PHY_CTRL1_RESET BIT(0) #define PHY_CTRL1_COMMONONN BIT(1) #define PHY_CTRL1_ATERESET BIT(3) #define PHY_CTRL1_VDATSRCENB0 BIT(19) #define PHY_CTRL1_VDATDETENB0 BIT(20) #define PHY_CTRL2 0x8 #define PHY_CTRL2_TXENABLEN0 BIT(8) #define PHY_CTRL2_OTG_DISABLE BIT(9) #define PHY_CTRL6 0x18 #define PHY_CTRL6_ALT_CLK_EN BIT(1) #define PHY_CTRL6_ALT_CLK_SEL BIT(0) struct imx8mq_usb_phy { struct phy *phy; struct clk *clk; void __iomem *base; struct regulator *vbus; }; static int imx8mq_usb_phy_init(struct phy *phy) { struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); u32 value; value = readl(imx_phy->base + PHY_CTRL1); value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 | PHY_CTRL1_COMMONONN); value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; writel(value, imx_phy->base + PHY_CTRL1); value = readl(imx_phy->base + PHY_CTRL0); value |= PHY_CTRL0_REF_SSP_EN; writel(value, imx_phy->base + PHY_CTRL0); value = readl(imx_phy->base + PHY_CTRL2); value |= PHY_CTRL2_TXENABLEN0; writel(value, imx_phy->base + PHY_CTRL2); value = readl(imx_phy->base + PHY_CTRL1); value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); writel(value, imx_phy->base + PHY_CTRL1); return 0; } static int imx8mp_usb_phy_init(struct phy *phy) { struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); u32 value; /* USB3.0 PHY signal fsel for 24M ref */ value = readl(imx_phy->base + PHY_CTRL0); value &= ~PHY_CTRL0_FSEL_MASK; value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M); writel(value, imx_phy->base + PHY_CTRL0); /* Disable alt_clk_en and use internal MPLL clocks */ value = readl(imx_phy->base + PHY_CTRL6); value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN); writel(value, imx_phy->base + PHY_CTRL6); value = readl(imx_phy->base + PHY_CTRL1); value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0); value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; writel(value, imx_phy->base + PHY_CTRL1); value = readl(imx_phy->base + PHY_CTRL0); value |= PHY_CTRL0_REF_SSP_EN; writel(value, imx_phy->base + PHY_CTRL0); value = readl(imx_phy->base + PHY_CTRL2); value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE; writel(value, imx_phy->base + PHY_CTRL2); udelay(10); value = readl(imx_phy->base + PHY_CTRL1); value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); writel(value, imx_phy->base + PHY_CTRL1); return 0; } static int imx8mq_phy_power_on(struct phy *phy) { struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); int ret; ret = regulator_enable(imx_phy->vbus); if (ret) return ret; return clk_prepare_enable(imx_phy->clk); } static int imx8mq_phy_power_off(struct phy *phy) { struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); clk_disable_unprepare(imx_phy->clk); regulator_disable(imx_phy->vbus); return 0; } static const struct phy_ops imx8mq_usb_phy_ops = { .init = imx8mq_usb_phy_init, .power_on = imx8mq_phy_power_on, .power_off = imx8mq_phy_power_off, .owner = THIS_MODULE, }; static const struct phy_ops imx8mp_usb_phy_ops = { .init = imx8mp_usb_phy_init, .power_on = imx8mq_phy_power_on, .power_off = imx8mq_phy_power_off, .owner = THIS_MODULE, }; static const struct of_device_id imx8mq_usb_phy_of_match[] = { {.compatible = "fsl,imx8mq-usb-phy", .data = &imx8mq_usb_phy_ops,}, {.compatible = "fsl,imx8mp-usb-phy", .data = &imx8mp_usb_phy_ops,}, { } }; MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match); static int imx8mq_usb_phy_probe(struct platform_device *pdev) { struct phy_provider *phy_provider; struct device *dev = &pdev->dev; struct imx8mq_usb_phy *imx_phy; const struct phy_ops *phy_ops; imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL); if (!imx_phy) return -ENOMEM; imx_phy->clk = devm_clk_get(dev, "phy"); if (IS_ERR(imx_phy->clk)) { dev_err(dev, "failed to get imx8mq usb phy clock\n"); return PTR_ERR(imx_phy->clk); } imx_phy->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(imx_phy->base)) return PTR_ERR(imx_phy->base); phy_ops = of_device_get_match_data(dev); if (!phy_ops) return -EINVAL; imx_phy->phy = devm_phy_create(dev, NULL, phy_ops); if (IS_ERR(imx_phy->phy)) return PTR_ERR(imx_phy->phy); imx_phy->vbus = devm_regulator_get(dev, "vbus"); if (IS_ERR(imx_phy->vbus)) return PTR_ERR(imx_phy->vbus); phy_set_drvdata(imx_phy->phy, imx_phy); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); return PTR_ERR_OR_ZERO(phy_provider); } static struct platform_driver imx8mq_usb_phy_driver = { .probe = imx8mq_usb_phy_probe, .driver = { .name = "imx8mq-usb-phy", .of_match_table = imx8mq_usb_phy_of_match, } }; module_platform_driver(imx8mq_usb_phy_driver); MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver"); MODULE_LICENSE("GPL");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1