brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 60be5cd Raw
192 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Amlogic AXG PCIE PHY driver4 *5 * Copyright (C) 2020 Remi Pommarel <repk@triplefau.lt>6 */7#include <linux/mod_devicetable.h>8#include <linux/module.h>9#include <linux/phy/phy.h>10#include <linux/regmap.h>11#include <linux/reset.h>12#include <linux/platform_device.h>13#include <linux/bitfield.h>14#include <dt-bindings/phy/phy.h>15 16#define MESON_PCIE_REG0 0x0017#define		MESON_PCIE_COMMON_CLK	BIT(4)18#define		MESON_PCIE_PORT_SEL	GENMASK(3, 2)19#define		MESON_PCIE_CLK		BIT(1)20#define		MESON_PCIE_POWERDOWN	BIT(0)21 22#define MESON_PCIE_TWO_X1		FIELD_PREP(MESON_PCIE_PORT_SEL, 0x3)23#define MESON_PCIE_COMMON_REF_CLK	FIELD_PREP(MESON_PCIE_COMMON_CLK, 0x1)24#define MESON_PCIE_PHY_INIT		(MESON_PCIE_TWO_X1 |		\25					 MESON_PCIE_COMMON_REF_CLK)26#define MESON_PCIE_RESET_DELAY		50027 28struct phy_axg_pcie_priv {29	struct phy *phy;30	struct phy *analog;31	struct regmap *regmap;32	struct reset_control *reset;33};34 35static const struct regmap_config phy_axg_pcie_regmap_conf = {36	.reg_bits = 8,37	.val_bits = 32,38	.reg_stride = 4,39	.max_register = MESON_PCIE_REG0,40};41 42static int phy_axg_pcie_power_on(struct phy *phy)43{44	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);45	int ret;46 47	ret = phy_power_on(priv->analog);48	if (ret != 0)49		return ret;50 51	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,52			   MESON_PCIE_POWERDOWN, 0);53	return 0;54}55 56static int phy_axg_pcie_power_off(struct phy *phy)57{58	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);59	int ret;60 61	ret = phy_power_off(priv->analog);62	if (ret != 0)63		return ret;64 65	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,66			   MESON_PCIE_POWERDOWN, 1);67	return 0;68}69 70static int phy_axg_pcie_init(struct phy *phy)71{72	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);73	int ret;74 75	ret = phy_init(priv->analog);76	if (ret != 0)77		return ret;78 79	regmap_write(priv->regmap, MESON_PCIE_REG0, MESON_PCIE_PHY_INIT);80	return reset_control_reset(priv->reset);81}82 83static int phy_axg_pcie_exit(struct phy *phy)84{85	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);86	int ret;87 88	ret = phy_exit(priv->analog);89	if (ret != 0)90		return ret;91 92	return reset_control_reset(priv->reset);93}94 95static int phy_axg_pcie_reset(struct phy *phy)96{97	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);98	int ret = 0;99 100	ret = phy_reset(priv->analog);101	if (ret != 0)102		goto out;103 104	ret = reset_control_assert(priv->reset);105	if (ret != 0)106		goto out;107	udelay(MESON_PCIE_RESET_DELAY);108 109	ret = reset_control_deassert(priv->reset);110	if (ret != 0)111		goto out;112	udelay(MESON_PCIE_RESET_DELAY);113 114out:115	return ret;116}117 118static const struct phy_ops phy_axg_pcie_ops = {119	.init = phy_axg_pcie_init,120	.exit = phy_axg_pcie_exit,121	.power_on = phy_axg_pcie_power_on,122	.power_off = phy_axg_pcie_power_off,123	.reset = phy_axg_pcie_reset,124	.owner = THIS_MODULE,125};126 127static int phy_axg_pcie_probe(struct platform_device *pdev)128{129	struct phy_provider *pphy;130	struct device *dev = &pdev->dev;131	struct phy_axg_pcie_priv *priv;132	struct device_node *np = dev->of_node;133	void __iomem *base;134	int ret;135 136	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);137	if (!priv)138		return -ENOMEM;139 140	priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);141	if (IS_ERR(priv->phy)) {142		ret = PTR_ERR(priv->phy);143		if (ret != -EPROBE_DEFER)144			dev_err(dev, "failed to create PHY\n");145		return ret;146	}147 148	base = devm_platform_ioremap_resource(pdev, 0);149	if (IS_ERR(base))150		return PTR_ERR(base);151 152	priv->regmap = devm_regmap_init_mmio(dev, base,153					     &phy_axg_pcie_regmap_conf);154	if (IS_ERR(priv->regmap))155		return PTR_ERR(priv->regmap);156 157	priv->reset = devm_reset_control_array_get_exclusive(dev);158	if (IS_ERR(priv->reset))159		return PTR_ERR(priv->reset);160 161	priv->analog = devm_phy_get(dev, "analog");162	if (IS_ERR(priv->analog))163		return PTR_ERR(priv->analog);164 165	phy_set_drvdata(priv->phy, priv);166	dev_set_drvdata(dev, priv);167	pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);168 169	return PTR_ERR_OR_ZERO(pphy);170}171 172static const struct of_device_id phy_axg_pcie_of_match[] = {173	{174		.compatible = "amlogic,axg-pcie-phy",175	},176	{ },177};178MODULE_DEVICE_TABLE(of, phy_axg_pcie_of_match);179 180static struct platform_driver phy_axg_pcie_driver = {181	.probe = phy_axg_pcie_probe,182	.driver = {183		.name = "phy-axg-pcie",184		.of_match_table = phy_axg_pcie_of_match,185	},186};187module_platform_driver(phy_axg_pcie_driver);188 189MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");190MODULE_DESCRIPTION("Amlogic AXG PCIE PHY driver");191MODULE_LICENSE("GPL v2");192