brintos

brintos / linux-shallow public Read only

0
0
Text · 5.2 KiB · eff6dd6 Raw
210 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2015 Linaro, Ltd.4 * Rob Herring <robh@kernel.org>5 *6 * Based on vendor driver:7 * Copyright (C) 2013 Marvell Inc.8 * Author: Chao Xie <xiechao.mail@gmail.com>9 */10 11#include <linux/delay.h>12#include <linux/slab.h>13#include <linux/of.h>14#include <linux/io.h>15#include <linux/iopoll.h>16#include <linux/err.h>17#include <linux/clk.h>18#include <linux/module.h>19#include <linux/platform_device.h>20#include <linux/phy/phy.h>21 22#define PHY_28NM_HSIC_CTRL			0x0823#define PHY_28NM_HSIC_IMPCAL_CAL		0x1824#define PHY_28NM_HSIC_PLL_CTRL01		0x1c25#define PHY_28NM_HSIC_PLL_CTRL2			0x2026#define PHY_28NM_HSIC_INT			0x2827 28#define PHY_28NM_HSIC_PLL_SELLPFR_SHIFT		2629#define PHY_28NM_HSIC_PLL_FBDIV_SHIFT		030#define PHY_28NM_HSIC_PLL_REFDIV_SHIFT		931 32#define PHY_28NM_HSIC_S2H_PU_PLL		BIT(10)33#define PHY_28NM_HSIC_H2S_PLL_LOCK		BIT(15)34#define PHY_28NM_HSIC_S2H_HSIC_EN		BIT(7)35#define S2H_DRV_SE0_4RESUME			BIT(14)36#define PHY_28NM_HSIC_H2S_IMPCAL_DONE		BIT(27)37 38#define PHY_28NM_HSIC_CONNECT_INT		BIT(1)39#define PHY_28NM_HSIC_HS_READY_INT		BIT(2)40 41struct mv_hsic_phy {42	struct phy		*phy;43	struct platform_device	*pdev;44	void __iomem		*base;45	struct clk		*clk;46};47 48static int wait_for_reg(void __iomem *reg, u32 mask, u32 ms)49{50	u32 val;51 52	return readl_poll_timeout(reg, val, ((val & mask) == mask),53				  1000, 1000 * ms);54}55 56static int mv_hsic_phy_init(struct phy *phy)57{58	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);59	struct platform_device *pdev = mv_phy->pdev;60	void __iomem *base = mv_phy->base;61	int ret;62 63	clk_prepare_enable(mv_phy->clk);64 65	/* Set reference clock */66	writel(0x1 << PHY_28NM_HSIC_PLL_SELLPFR_SHIFT |67		0xf0 << PHY_28NM_HSIC_PLL_FBDIV_SHIFT |68		0xd << PHY_28NM_HSIC_PLL_REFDIV_SHIFT,69		base + PHY_28NM_HSIC_PLL_CTRL01);70 71	/* Turn on PLL */72	writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) |73		PHY_28NM_HSIC_S2H_PU_PLL,74		base + PHY_28NM_HSIC_PLL_CTRL2);75 76	/* Make sure PHY PLL is locked */77	ret = wait_for_reg(base + PHY_28NM_HSIC_PLL_CTRL2,78			   PHY_28NM_HSIC_H2S_PLL_LOCK, 100);79	if (ret) {80		dev_err(&pdev->dev, "HSIC PHY PLL not locked after 100mS.");81		clk_disable_unprepare(mv_phy->clk);82	}83 84	return ret;85}86 87static int mv_hsic_phy_power_on(struct phy *phy)88{89	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);90	struct platform_device *pdev = mv_phy->pdev;91	void __iomem *base = mv_phy->base;92	u32 reg;93	int ret;94 95	reg = readl(base + PHY_28NM_HSIC_CTRL);96	/* Avoid SE0 state when resume for some device will take it as reset */97	reg &= ~S2H_DRV_SE0_4RESUME;98	reg |= PHY_28NM_HSIC_S2H_HSIC_EN;	/* Enable HSIC PHY */99	writel(reg, base + PHY_28NM_HSIC_CTRL);100 101	/*102	 *  Calibration Timing103	 *		   ____________________________104	 *  CAL START   ___|105	 *			   ____________________106	 *  CAL_DONE    ___________|107	 *		   | 400us |108	 */109 110	/* Make sure PHY Calibration is ready */111	ret = wait_for_reg(base + PHY_28NM_HSIC_IMPCAL_CAL,112			   PHY_28NM_HSIC_H2S_IMPCAL_DONE, 100);113	if (ret) {114		dev_warn(&pdev->dev, "HSIC PHY READY not set after 100mS.");115		return ret;116	}117 118	/* Waiting for HSIC connect int*/119	ret = wait_for_reg(base + PHY_28NM_HSIC_INT,120			   PHY_28NM_HSIC_CONNECT_INT, 200);121	if (ret)122		dev_warn(&pdev->dev, "HSIC wait for connect interrupt timeout.");123 124	return ret;125}126 127static int mv_hsic_phy_power_off(struct phy *phy)128{129	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);130	void __iomem *base = mv_phy->base;131 132	writel(readl(base + PHY_28NM_HSIC_CTRL) & ~PHY_28NM_HSIC_S2H_HSIC_EN,133		base + PHY_28NM_HSIC_CTRL);134 135	return 0;136}137 138static int mv_hsic_phy_exit(struct phy *phy)139{140	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);141	void __iomem *base = mv_phy->base;142 143	/* Turn off PLL */144	writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) &145		~PHY_28NM_HSIC_S2H_PU_PLL,146		base + PHY_28NM_HSIC_PLL_CTRL2);147 148	clk_disable_unprepare(mv_phy->clk);149	return 0;150}151 152 153static const struct phy_ops hsic_ops = {154	.init		= mv_hsic_phy_init,155	.power_on	= mv_hsic_phy_power_on,156	.power_off	= mv_hsic_phy_power_off,157	.exit		= mv_hsic_phy_exit,158	.owner		= THIS_MODULE,159};160 161static int mv_hsic_phy_probe(struct platform_device *pdev)162{163	struct phy_provider *phy_provider;164	struct mv_hsic_phy *mv_phy;165 166	mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);167	if (!mv_phy)168		return -ENOMEM;169 170	mv_phy->pdev = pdev;171 172	mv_phy->clk = devm_clk_get(&pdev->dev, NULL);173	if (IS_ERR(mv_phy->clk)) {174		dev_err(&pdev->dev, "failed to get clock.\n");175		return PTR_ERR(mv_phy->clk);176	}177 178	mv_phy->base = devm_platform_ioremap_resource(pdev, 0);179	if (IS_ERR(mv_phy->base))180		return PTR_ERR(mv_phy->base);181 182	mv_phy->phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &hsic_ops);183	if (IS_ERR(mv_phy->phy))184		return PTR_ERR(mv_phy->phy);185 186	phy_set_drvdata(mv_phy->phy, mv_phy);187 188	phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);189	return PTR_ERR_OR_ZERO(phy_provider);190}191 192static const struct of_device_id mv_hsic_phy_dt_match[] = {193	{ .compatible = "marvell,pxa1928-hsic-phy", },194	{},195};196MODULE_DEVICE_TABLE(of, mv_hsic_phy_dt_match);197 198static struct platform_driver mv_hsic_phy_driver = {199	.probe	= mv_hsic_phy_probe,200	.driver = {201		.name   = "mv-hsic-phy",202		.of_match_table = mv_hsic_phy_dt_match,203	},204};205module_platform_driver(mv_hsic_phy_driver);206 207MODULE_AUTHOR("Rob Herring <robh@kernel.org>");208MODULE_DESCRIPTION("Marvell HSIC phy driver");209MODULE_LICENSE("GPL v2");210