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

phy: add Marvell HSIC 28nm PHY

Add PHY driver for the Marvell HSIC 28nm PHY. This PHY is found in PXA1928
SOC.

Signed-off-by: Rob Herring <robh@kernel.org>
Cc: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Rob Herring and committed by
Greg Kroah-Hartman
10d9029b 603c5f9d

+231
+10
drivers/phy/Kconfig
··· 54 54 Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P 55 55 and EXYNOS SoCs. 56 56 57 + config PHY_PXA_28NM_HSIC 58 + tristate "Marvell USB HSIC 28nm PHY Driver" 59 + select GENERIC_PHY 60 + help 61 + Enable this to support Marvell USB HSIC PHY driver for Marvell 62 + SoC. This driver will do the PHY initialization and shutdown. 63 + The PHY driver will be used by Marvell ehci driver. 64 + 65 + To compile this driver as a module, choose M here. 66 + 57 67 config PHY_PXA_28NM_USB2 58 68 tristate "Marvell USB 2.0 28nm PHY Driver" 59 69 select GENERIC_PHY
+1
drivers/phy/Makefile
··· 11 11 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o 12 12 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o 13 13 obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o 14 + obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o 14 15 obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o 15 16 obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o 16 17 obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o
+220
drivers/phy/phy-pxa-28nm-hsic.c
··· 1 + /* 2 + * Copyright (C) 2015 Linaro, Ltd. 3 + * Rob Herring <robh@kernel.org> 4 + * 5 + * Based on vendor driver: 6 + * Copyright (C) 2013 Marvell Inc. 7 + * Author: Chao Xie <xiechao.mail@gmail.com> 8 + * 9 + * This software is licensed under the terms of the GNU General Public 10 + * License version 2, as published by the Free Software Foundation, and 11 + * may be copied, distributed, and modified under those terms. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + */ 19 + 20 + #include <linux/delay.h> 21 + #include <linux/slab.h> 22 + #include <linux/of.h> 23 + #include <linux/io.h> 24 + #include <linux/err.h> 25 + #include <linux/clk.h> 26 + #include <linux/module.h> 27 + #include <linux/platform_device.h> 28 + #include <linux/phy/phy.h> 29 + 30 + #define PHY_28NM_HSIC_CTRL 0x08 31 + #define PHY_28NM_HSIC_IMPCAL_CAL 0x18 32 + #define PHY_28NM_HSIC_PLL_CTRL01 0x1c 33 + #define PHY_28NM_HSIC_PLL_CTRL2 0x20 34 + #define PHY_28NM_HSIC_INT 0x28 35 + 36 + #define PHY_28NM_HSIC_PLL_SELLPFR_SHIFT 26 37 + #define PHY_28NM_HSIC_PLL_FBDIV_SHIFT 0 38 + #define PHY_28NM_HSIC_PLL_REFDIV_SHIFT 9 39 + 40 + #define PHY_28NM_HSIC_S2H_PU_PLL BIT(10) 41 + #define PHY_28NM_HSIC_H2S_PLL_LOCK BIT(15) 42 + #define PHY_28NM_HSIC_S2H_HSIC_EN BIT(7) 43 + #define S2H_DRV_SE0_4RESUME BIT(14) 44 + #define PHY_28NM_HSIC_H2S_IMPCAL_DONE BIT(27) 45 + 46 + #define PHY_28NM_HSIC_CONNECT_INT BIT(1) 47 + #define PHY_28NM_HSIC_HS_READY_INT BIT(2) 48 + 49 + struct mv_hsic_phy { 50 + struct phy *phy; 51 + struct platform_device *pdev; 52 + void __iomem *base; 53 + struct clk *clk; 54 + }; 55 + 56 + static bool wait_for_reg(void __iomem *reg, u32 mask, unsigned long timeout) 57 + { 58 + timeout += jiffies; 59 + while (time_is_after_eq_jiffies(timeout)) { 60 + if ((readl(reg) & mask) == mask) 61 + return true; 62 + msleep(1); 63 + } 64 + return false; 65 + } 66 + 67 + static int mv_hsic_phy_init(struct phy *phy) 68 + { 69 + struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy); 70 + struct platform_device *pdev = mv_phy->pdev; 71 + void __iomem *base = mv_phy->base; 72 + 73 + clk_prepare_enable(mv_phy->clk); 74 + 75 + /* Set reference clock */ 76 + writel(0x1 << PHY_28NM_HSIC_PLL_SELLPFR_SHIFT | 77 + 0xf0 << PHY_28NM_HSIC_PLL_FBDIV_SHIFT | 78 + 0xd << PHY_28NM_HSIC_PLL_REFDIV_SHIFT, 79 + base + PHY_28NM_HSIC_PLL_CTRL01); 80 + 81 + /* Turn on PLL */ 82 + writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) | 83 + PHY_28NM_HSIC_S2H_PU_PLL, 84 + base + PHY_28NM_HSIC_PLL_CTRL2); 85 + 86 + /* Make sure PHY PLL is locked */ 87 + if (!wait_for_reg(base + PHY_28NM_HSIC_PLL_CTRL2, 88 + PHY_28NM_HSIC_H2S_PLL_LOCK, HZ / 10)) { 89 + dev_err(&pdev->dev, "HSIC PHY PLL not locked after 100mS."); 90 + clk_disable_unprepare(mv_phy->clk); 91 + return -ETIMEDOUT; 92 + } 93 + 94 + return 0; 95 + } 96 + 97 + static int mv_hsic_phy_power_on(struct phy *phy) 98 + { 99 + struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy); 100 + struct platform_device *pdev = mv_phy->pdev; 101 + void __iomem *base = mv_phy->base; 102 + u32 reg; 103 + 104 + reg = readl(base + PHY_28NM_HSIC_CTRL); 105 + /* Avoid SE0 state when resume for some device will take it as reset */ 106 + reg &= ~S2H_DRV_SE0_4RESUME; 107 + reg |= PHY_28NM_HSIC_S2H_HSIC_EN; /* Enable HSIC PHY */ 108 + writel(reg, base + PHY_28NM_HSIC_CTRL); 109 + 110 + /* 111 + * Calibration Timing 112 + * ____________________________ 113 + * CAL START ___| 114 + * ____________________ 115 + * CAL_DONE ___________| 116 + * | 400us | 117 + */ 118 + 119 + /* Make sure PHY Calibration is ready */ 120 + if (!wait_for_reg(base + PHY_28NM_HSIC_IMPCAL_CAL, 121 + PHY_28NM_HSIC_H2S_IMPCAL_DONE, HZ / 10)) { 122 + dev_warn(&pdev->dev, "HSIC PHY READY not set after 100mS."); 123 + return -ETIMEDOUT; 124 + } 125 + 126 + /* Waiting for HSIC connect int*/ 127 + if (!wait_for_reg(base + PHY_28NM_HSIC_INT, 128 + PHY_28NM_HSIC_CONNECT_INT, HZ / 5)) { 129 + dev_warn(&pdev->dev, "HSIC wait for connect interrupt timeout."); 130 + return -ETIMEDOUT; 131 + } 132 + 133 + return 0; 134 + } 135 + 136 + static int mv_hsic_phy_power_off(struct phy *phy) 137 + { 138 + struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy); 139 + void __iomem *base = mv_phy->base; 140 + 141 + writel(readl(base + PHY_28NM_HSIC_CTRL) & ~PHY_28NM_HSIC_S2H_HSIC_EN, 142 + base + PHY_28NM_HSIC_CTRL); 143 + 144 + return 0; 145 + } 146 + 147 + static int mv_hsic_phy_exit(struct phy *phy) 148 + { 149 + struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy); 150 + void __iomem *base = mv_phy->base; 151 + 152 + /* Turn off PLL */ 153 + writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) & 154 + ~PHY_28NM_HSIC_S2H_PU_PLL, 155 + base + PHY_28NM_HSIC_PLL_CTRL2); 156 + 157 + clk_disable_unprepare(mv_phy->clk); 158 + return 0; 159 + } 160 + 161 + 162 + static const struct phy_ops hsic_ops = { 163 + .init = mv_hsic_phy_init, 164 + .power_on = mv_hsic_phy_power_on, 165 + .power_off = mv_hsic_phy_power_off, 166 + .exit = mv_hsic_phy_exit, 167 + .owner = THIS_MODULE, 168 + }; 169 + 170 + static int mv_hsic_phy_probe(struct platform_device *pdev) 171 + { 172 + struct phy_provider *phy_provider; 173 + struct mv_hsic_phy *mv_phy; 174 + struct resource *r; 175 + 176 + mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL); 177 + if (!mv_phy) 178 + return -ENOMEM; 179 + 180 + mv_phy->pdev = pdev; 181 + 182 + mv_phy->clk = devm_clk_get(&pdev->dev, NULL); 183 + if (IS_ERR(mv_phy->clk)) { 184 + dev_err(&pdev->dev, "failed to get clock.\n"); 185 + return PTR_ERR(mv_phy->clk); 186 + } 187 + 188 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 189 + mv_phy->base = devm_ioremap_resource(&pdev->dev, r); 190 + if (IS_ERR(mv_phy->base)) 191 + return PTR_ERR(mv_phy->base); 192 + 193 + mv_phy->phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &hsic_ops); 194 + if (IS_ERR(mv_phy->phy)) 195 + return PTR_ERR(mv_phy->phy); 196 + 197 + phy_set_drvdata(mv_phy->phy, mv_phy); 198 + 199 + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); 200 + return PTR_ERR_OR_ZERO(phy_provider); 201 + } 202 + 203 + static const struct of_device_id mv_hsic_phy_dt_match[] = { 204 + { .compatible = "marvell,pxa1928-hsic-phy", }, 205 + {}, 206 + }; 207 + MODULE_DEVICE_TABLE(of, mv_hsic_phy_dt_match); 208 + 209 + static struct platform_driver mv_hsic_phy_driver = { 210 + .probe = mv_hsic_phy_probe, 211 + .driver = { 212 + .name = "mv-hsic-phy", 213 + .of_match_table = of_match_ptr(mv_hsic_phy_dt_match), 214 + }, 215 + }; 216 + module_platform_driver(mv_hsic_phy_driver); 217 + 218 + MODULE_AUTHOR("Rob Herring <robh@kernel.org>"); 219 + MODULE_DESCRIPTION("Marvell HSIC phy driver"); 220 + MODULE_LICENSE("GPL v2");