brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 82f1ffc Raw
256 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Lantiq XWAY SoC RCU module based USB 1.1/2.0 PHY driver4 *5 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>6 * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>7 */8 9#include <linux/clk.h>10#include <linux/delay.h>11#include <linux/mfd/syscon.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/of_address.h>15#include <linux/phy/phy.h>16#include <linux/platform_device.h>17#include <linux/property.h>18#include <linux/regmap.h>19#include <linux/reset.h>20 21/* Transmitter HS Pre-Emphasis Enable */22#define RCU_CFG1_TX_PEE		BIT(0)23/* Disconnect Threshold */24#define RCU_CFG1_DIS_THR_MASK	0x0003800025#define RCU_CFG1_DIS_THR_SHIFT	1526 27struct ltq_rcu_usb2_bits {28	u8 hostmode;29	u8 slave_endianness;30	u8 host_endianness;31	bool have_ana_cfg;32};33 34struct ltq_rcu_usb2_priv {35	struct regmap			*regmap;36	unsigned int			phy_reg_offset;37	unsigned int			ana_cfg1_reg_offset;38	const struct ltq_rcu_usb2_bits	*reg_bits;39	struct device			*dev;40	struct phy			*phy;41	struct clk			*phy_gate_clk;42	struct reset_control		*ctrl_reset;43	struct reset_control		*phy_reset;44};45 46static const struct ltq_rcu_usb2_bits xway_rcu_usb2_reg_bits = {47	.hostmode = 11,48	.slave_endianness = 9,49	.host_endianness = 10,50	.have_ana_cfg = false,51};52 53static const struct ltq_rcu_usb2_bits xrx100_rcu_usb2_reg_bits = {54	.hostmode = 11,55	.slave_endianness = 17,56	.host_endianness = 10,57	.have_ana_cfg = false,58};59 60static const struct ltq_rcu_usb2_bits xrx200_rcu_usb2_reg_bits = {61	.hostmode = 11,62	.slave_endianness = 9,63	.host_endianness = 10,64	.have_ana_cfg = true,65};66 67static const struct of_device_id ltq_rcu_usb2_phy_of_match[] = {68	{69		.compatible = "lantiq,ase-usb2-phy",70		.data = &xway_rcu_usb2_reg_bits,71	},72	{73		.compatible = "lantiq,danube-usb2-phy",74		.data = &xway_rcu_usb2_reg_bits,75	},76	{77		.compatible = "lantiq,xrx100-usb2-phy",78		.data = &xrx100_rcu_usb2_reg_bits,79	},80	{81		.compatible = "lantiq,xrx200-usb2-phy",82		.data = &xrx200_rcu_usb2_reg_bits,83	},84	{85		.compatible = "lantiq,xrx300-usb2-phy",86		.data = &xrx200_rcu_usb2_reg_bits,87	},88	{ },89};90MODULE_DEVICE_TABLE(of, ltq_rcu_usb2_phy_of_match);91 92static int ltq_rcu_usb2_phy_init(struct phy *phy)93{94	struct ltq_rcu_usb2_priv *priv = phy_get_drvdata(phy);95 96	if (priv->reg_bits->have_ana_cfg) {97		regmap_update_bits(priv->regmap, priv->ana_cfg1_reg_offset,98			RCU_CFG1_TX_PEE, RCU_CFG1_TX_PEE);99		regmap_update_bits(priv->regmap, priv->ana_cfg1_reg_offset,100			RCU_CFG1_DIS_THR_MASK, 7 << RCU_CFG1_DIS_THR_SHIFT);101	}102 103	/* Configure core to host mode */104	regmap_update_bits(priv->regmap, priv->phy_reg_offset,105			   BIT(priv->reg_bits->hostmode), 0);106 107	/* Select DMA endianness (Host-endian: big-endian) */108	regmap_update_bits(priv->regmap, priv->phy_reg_offset,109		BIT(priv->reg_bits->slave_endianness), 0);110	regmap_update_bits(priv->regmap, priv->phy_reg_offset,111		BIT(priv->reg_bits->host_endianness),112		BIT(priv->reg_bits->host_endianness));113 114	return 0;115}116 117static int ltq_rcu_usb2_phy_power_on(struct phy *phy)118{119	struct ltq_rcu_usb2_priv *priv = phy_get_drvdata(phy);120	struct device *dev = priv->dev;121	int ret;122 123	reset_control_deassert(priv->phy_reset);124 125	ret = clk_prepare_enable(priv->phy_gate_clk);126	if (ret) {127		dev_err(dev, "failed to enable PHY gate\n");128		return ret;129	}130 131	/*132	 * at least the xrx200 usb2 phy requires some extra time to be133	 * operational after enabling the clock134	 */135	usleep_range(100, 200);136 137	return ret;138}139 140static int ltq_rcu_usb2_phy_power_off(struct phy *phy)141{142	struct ltq_rcu_usb2_priv *priv = phy_get_drvdata(phy);143 144	reset_control_assert(priv->phy_reset);145 146	clk_disable_unprepare(priv->phy_gate_clk);147 148	return 0;149}150 151static const struct phy_ops ltq_rcu_usb2_phy_ops = {152	.init		= ltq_rcu_usb2_phy_init,153	.power_on	= ltq_rcu_usb2_phy_power_on,154	.power_off	= ltq_rcu_usb2_phy_power_off,155	.owner		= THIS_MODULE,156};157 158static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv,159				 struct platform_device *pdev)160{161	struct device *dev = priv->dev;162	const __be32 *offset;163 164	priv->reg_bits = of_device_get_match_data(dev);165 166	priv->regmap = syscon_node_to_regmap(dev->of_node->parent);167	if (IS_ERR(priv->regmap)) {168		dev_err(dev, "Failed to lookup RCU regmap\n");169		return PTR_ERR(priv->regmap);170	}171 172	offset = of_get_address(dev->of_node, 0, NULL, NULL);173	if (!offset) {174		dev_err(dev, "Failed to get RCU PHY reg offset\n");175		return -ENOENT;176	}177	priv->phy_reg_offset = __be32_to_cpu(*offset);178 179	if (priv->reg_bits->have_ana_cfg) {180		offset = of_get_address(dev->of_node, 1, NULL, NULL);181		if (!offset) {182			dev_err(dev, "Failed to get RCU ANA CFG1 reg offset\n");183			return -ENOENT;184		}185		priv->ana_cfg1_reg_offset = __be32_to_cpu(*offset);186	}187 188	priv->phy_gate_clk = devm_clk_get(dev, "phy");189	if (IS_ERR(priv->phy_gate_clk)) {190		dev_err(dev, "Unable to get USB phy gate clk\n");191		return PTR_ERR(priv->phy_gate_clk);192	}193 194	priv->ctrl_reset = devm_reset_control_get_shared(dev, "ctrl");195	if (IS_ERR(priv->ctrl_reset)) {196		if (PTR_ERR(priv->ctrl_reset) != -EPROBE_DEFER)197			dev_err(dev, "failed to get 'ctrl' reset\n");198		return PTR_ERR(priv->ctrl_reset);199	}200 201	priv->phy_reset = devm_reset_control_get_optional(dev, "phy");202 203	return PTR_ERR_OR_ZERO(priv->phy_reset);204}205 206static int ltq_rcu_usb2_phy_probe(struct platform_device *pdev)207{208	struct device *dev = &pdev->dev;209	struct ltq_rcu_usb2_priv *priv;210	struct phy_provider *provider;211	int ret;212 213	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);214	if (!priv)215		return -ENOMEM;216 217	priv->dev = dev;218 219	ret = ltq_rcu_usb2_of_parse(priv, pdev);220	if (ret)221		return ret;222 223	/* Reset USB core through reset controller */224	reset_control_deassert(priv->ctrl_reset);225 226	reset_control_assert(priv->phy_reset);227 228	priv->phy = devm_phy_create(dev, dev->of_node, &ltq_rcu_usb2_phy_ops);229	if (IS_ERR(priv->phy)) {230		dev_err(dev, "failed to create PHY\n");231		return PTR_ERR(priv->phy);232	}233 234	phy_set_drvdata(priv->phy, priv);235 236	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);237	if (IS_ERR(provider))238		return PTR_ERR(provider);239 240	dev_set_drvdata(priv->dev, priv);241	return 0;242}243 244static struct platform_driver ltq_rcu_usb2_phy_driver = {245	.probe	= ltq_rcu_usb2_phy_probe,246	.driver = {247		.name	= "lantiq-rcu-usb2-phy",248		.of_match_table	= ltq_rcu_usb2_phy_of_match,249	}250};251module_platform_driver(ltq_rcu_usb2_phy_driver);252 253MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");254MODULE_DESCRIPTION("Lantiq XWAY USB2 PHY driver");255MODULE_LICENSE("GPL v2");256