Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Amlogic AXG MIPI + PCIE analog PHY driver
  4 *
  5 * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
  6 */
  7#include <linux/module.h>
  8#include <linux/phy/phy.h>
  9#include <linux/regmap.h>
 10#include <linux/platform_device.h>
 11#include <dt-bindings/phy/phy.h>
 12
 13#define HHI_MIPI_CNTL0 0x00
 14#define		HHI_MIPI_CNTL0_COMMON_BLOCK	GENMASK(31, 28)
 15#define		HHI_MIPI_CNTL0_ENABLE		BIT(29)
 16#define		HHI_MIPI_CNTL0_BANDGAP		BIT(26)
 17#define		HHI_MIPI_CNTL0_DECODE_TO_RTERM	GENMASK(15, 12)
 18#define		HHI_MIPI_CNTL0_OUTPUT_EN	BIT(3)
 19
 20#define HHI_MIPI_CNTL1 0x01
 21#define		HHI_MIPI_CNTL1_CH0_CML_PDR_EN	BIT(12)
 22#define		HHI_MIPI_CNTL1_LP_ABILITY	GENMASK(5, 4)
 23#define		HHI_MIPI_CNTL1_LP_RESISTER	BIT(3)
 24#define		HHI_MIPI_CNTL1_INPUT_SETTING	BIT(2)
 25#define		HHI_MIPI_CNTL1_INPUT_SEL	BIT(1)
 26#define		HHI_MIPI_CNTL1_PRBS7_EN		BIT(0)
 27
 28#define HHI_MIPI_CNTL2 0x02
 29#define		HHI_MIPI_CNTL2_CH_PU		GENMASK(31, 25)
 30#define		HHI_MIPI_CNTL2_CH_CTL		GENMASK(24, 19)
 31#define		HHI_MIPI_CNTL2_CH0_DIGDR_EN	BIT(18)
 32#define		HHI_MIPI_CNTL2_CH_DIGDR_EN	BIT(17)
 33#define		HHI_MIPI_CNTL2_LPULPS_EN	BIT(16)
 34#define		HHI_MIPI_CNTL2_CH_EN(n)		BIT(15 - (n))
 35#define		HHI_MIPI_CNTL2_CH0_LP_CTL	GENMASK(10, 1)
 36
 37struct phy_axg_mipi_pcie_analog_priv {
 38	struct phy *phy;
 39	unsigned int mode;
 40	struct regmap *regmap;
 41};
 42
 43static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
 44	.reg_bits = 8,
 45	.val_bits = 32,
 46	.reg_stride = 4,
 47	.max_register = HHI_MIPI_CNTL2,
 48};
 49
 50static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
 51{
 52	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
 53
 54	/* MIPI not supported yet */
 55	if (priv->mode != PHY_TYPE_PCIE)
 56		return -EINVAL;
 57
 58	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
 59			   HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
 60
 61	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
 62			   HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
 63	return 0;
 64}
 65
 66static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
 67{
 68	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
 69
 70	/* MIPI not supported yet */
 71	if (priv->mode != PHY_TYPE_PCIE)
 72		return -EINVAL;
 73
 74	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
 75			   HHI_MIPI_CNTL0_BANDGAP, 0);
 76	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
 77			   HHI_MIPI_CNTL0_ENABLE, 0);
 78	return 0;
 79}
 80
 81static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
 82{
 83	return 0;
 84}
 85
 86static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
 87{
 88	return 0;
 89}
 90
 91static const struct phy_ops phy_axg_mipi_pcie_analog_ops = {
 92	.init = phy_axg_mipi_pcie_analog_init,
 93	.exit = phy_axg_mipi_pcie_analog_exit,
 94	.power_on = phy_axg_mipi_pcie_analog_power_on,
 95	.power_off = phy_axg_mipi_pcie_analog_power_off,
 96	.owner = THIS_MODULE,
 97};
 98
 99static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev,
100						  struct of_phandle_args *args)
101{
102	struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev);
103	unsigned int mode;
104
105	if (args->args_count != 1) {
106		dev_err(dev, "invalid number of arguments\n");
107		return ERR_PTR(-EINVAL);
108	}
109
110	mode = args->args[0];
111
112	/* MIPI mode is not supported yet */
113	if (mode != PHY_TYPE_PCIE) {
114		dev_err(dev, "invalid phy mode select argument\n");
115		return ERR_PTR(-EINVAL);
116	}
117
118	priv->mode = mode;
119	return priv->phy;
120}
121
122static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
123{
124	struct phy_provider *phy;
125	struct device *dev = &pdev->dev;
126	struct phy_axg_mipi_pcie_analog_priv *priv;
127	struct device_node *np = dev->of_node;
128	struct regmap *map;
129	struct resource *res;
130	void __iomem *base;
131	int ret;
132
133	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
134	if (!priv)
135		return -ENOMEM;
136
137	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
138	base = devm_ioremap_resource(dev, res);
139	if (IS_ERR(base)) {
140		dev_err(dev, "failed to get regmap base\n");
141		return PTR_ERR(base);
142	}
143
144	map = devm_regmap_init_mmio(dev, base,
145				    &phy_axg_mipi_pcie_analog_regmap_conf);
146	if (IS_ERR(map)) {
147		dev_err(dev, "failed to get HHI regmap\n");
148		return PTR_ERR(map);
149	}
150	priv->regmap = map;
151
152	priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
153	if (IS_ERR(priv->phy)) {
154		ret = PTR_ERR(priv->phy);
155		if (ret != -EPROBE_DEFER)
156			dev_err(dev, "failed to create PHY\n");
157		return ret;
158	}
159
160	phy_set_drvdata(priv->phy, priv);
161	dev_set_drvdata(dev, priv);
162
163	phy = devm_of_phy_provider_register(dev,
164					    phy_axg_mipi_pcie_analog_xlate);
165
166	return PTR_ERR_OR_ZERO(phy);
167}
168
169static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = {
170	{
171		.compatible = "amlogic,axg-mipi-pcie-analog-phy",
172	},
173	{ },
174};
175MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match);
176
177static struct platform_driver phy_axg_mipi_pcie_analog_driver = {
178	.probe = phy_axg_mipi_pcie_analog_probe,
179	.driver = {
180		.name = "phy-axg-mipi-pcie-analog",
181		.of_match_table = phy_axg_mipi_pcie_analog_of_match,
182	},
183};
184module_platform_driver(phy_axg_mipi_pcie_analog_driver);
185
186MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
187MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
188MODULE_LICENSE("GPL v2");