File Index
Files and directories
Sign in
FILE

phy-meson8b-usb2.c

File preview with syntax highlighting.

linux-6.19.14/drivers/phy/amlogic/phy-meson8b-usb2.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Meson8, Meson8b and GXBB USB2 PHY driver
  4 *
  5 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
  6 */
  7
  8#include <linux/bitfield.h>
  9#include <linux/clk.h>
 10#include <linux/delay.h>
 11#include <linux/io.h>
 12#include <linux/mod_devicetable.h>
 13#include <linux/module.h>
 14#include <linux/property.h>
 15#include <linux/regmap.h>
 16#include <linux/reset.h>
 17#include <linux/phy/phy.h>
 18#include <linux/platform_device.h>
 19#include <linux/usb/of.h>
 20
 21#define REG_CONFIG					0x00
 22	#define REG_CONFIG_CLK_EN			BIT(0)
 23	#define REG_CONFIG_CLK_SEL_MASK			GENMASK(3, 1)
 24	#define REG_CONFIG_CLK_DIV_MASK			GENMASK(10, 4)
 25	#define REG_CONFIG_CLK_32k_ALTSEL		BIT(15)
 26	#define REG_CONFIG_TEST_TRIG			BIT(31)
 27
 28#define REG_CTRL					0x04
 29	#define REG_CTRL_SOFT_PRST			BIT(0)
 30	#define REG_CTRL_SOFT_HRESET			BIT(1)
 31	#define REG_CTRL_SS_SCALEDOWN_MODE_MASK		GENMASK(3, 2)
 32	#define REG_CTRL_CLK_DET_RST			BIT(4)
 33	#define REG_CTRL_INTR_SEL			BIT(5)
 34	#define REG_CTRL_CLK_DETECTED			BIT(8)
 35	#define REG_CTRL_SOF_SENT_RCVD_TGL		BIT(9)
 36	#define REG_CTRL_SOF_TOGGLE_OUT			BIT(10)
 37	#define REG_CTRL_POWER_ON_RESET			BIT(15)
 38	#define REG_CTRL_SLEEPM				BIT(16)
 39	#define REG_CTRL_TX_BITSTUFF_ENN_H		BIT(17)
 40	#define REG_CTRL_TX_BITSTUFF_ENN		BIT(18)
 41	#define REG_CTRL_COMMON_ON			BIT(19)
 42	#define REG_CTRL_REF_CLK_SEL_MASK		GENMASK(21, 20)
 43	#define REG_CTRL_FSEL_MASK			GENMASK(24, 22)
 44	#define REG_CTRL_PORT_RESET			BIT(25)
 45	#define REG_CTRL_THREAD_ID_MASK			GENMASK(31, 26)
 46
 47#define REG_ENDP_INTR					0x08
 48
 49/* bits [31:26], [24:21] and [15:3] seem to be read-only */
 50#define REG_ADP_BC					0x0c
 51	#define REG_ADP_BC_VBUS_VLD_EXT_SEL		BIT(0)
 52	#define REG_ADP_BC_VBUS_VLD_EXT			BIT(1)
 53	#define REG_ADP_BC_OTG_DISABLE			BIT(2)
 54	#define REG_ADP_BC_ID_PULLUP			BIT(3)
 55	#define REG_ADP_BC_DRV_VBUS			BIT(4)
 56	#define REG_ADP_BC_ADP_PRB_EN			BIT(5)
 57	#define REG_ADP_BC_ADP_DISCHARGE		BIT(6)
 58	#define REG_ADP_BC_ADP_CHARGE			BIT(7)
 59	#define REG_ADP_BC_SESS_END			BIT(8)
 60	#define REG_ADP_BC_DEVICE_SESS_VLD		BIT(9)
 61	#define REG_ADP_BC_B_VALID			BIT(10)
 62	#define REG_ADP_BC_A_VALID			BIT(11)
 63	#define REG_ADP_BC_ID_DIG			BIT(12)
 64	#define REG_ADP_BC_VBUS_VALID			BIT(13)
 65	#define REG_ADP_BC_ADP_PROBE			BIT(14)
 66	#define REG_ADP_BC_ADP_SENSE			BIT(15)
 67	#define REG_ADP_BC_ACA_ENABLE			BIT(16)
 68	#define REG_ADP_BC_DCD_ENABLE			BIT(17)
 69	#define REG_ADP_BC_VDAT_DET_EN_B		BIT(18)
 70	#define REG_ADP_BC_VDAT_SRC_EN_B		BIT(19)
 71	#define REG_ADP_BC_CHARGE_SEL			BIT(20)
 72	#define REG_ADP_BC_CHARGE_DETECT		BIT(21)
 73	#define REG_ADP_BC_ACA_PIN_RANGE_C		BIT(22)
 74	#define REG_ADP_BC_ACA_PIN_RANGE_B		BIT(23)
 75	#define REG_ADP_BC_ACA_PIN_RANGE_A		BIT(24)
 76	#define REG_ADP_BC_ACA_PIN_GND			BIT(25)
 77	#define REG_ADP_BC_ACA_PIN_FLOAT		BIT(26)
 78
 79#define REG_DBG_UART					0x10
 80	#define REG_DBG_UART_BYPASS_SEL			BIT(0)
 81	#define REG_DBG_UART_BYPASS_DM_EN		BIT(1)
 82	#define REG_DBG_UART_BYPASS_DP_EN		BIT(2)
 83	#define REG_DBG_UART_BYPASS_DM_DATA		BIT(3)
 84	#define REG_DBG_UART_BYPASS_DP_DATA		BIT(4)
 85	#define REG_DBG_UART_FSV_MINUS			BIT(5)
 86	#define REG_DBG_UART_FSV_PLUS			BIT(6)
 87	#define REG_DBG_UART_FSV_BURN_IN_TEST		BIT(7)
 88	#define REG_DBG_UART_LOOPBACK_EN_B		BIT(8)
 89	#define REG_DBG_UART_SET_IDDQ			BIT(9)
 90	#define REG_DBG_UART_ATE_RESET			BIT(10)
 91
 92#define REG_TEST					0x14
 93	#define REG_TEST_DATA_IN_MASK			GENMASK(3, 0)
 94	#define REG_TEST_EN_MASK			GENMASK(7, 4)
 95	#define REG_TEST_ADDR_MASK			GENMASK(11, 8)
 96	#define REG_TEST_DATA_OUT_SEL			BIT(12)
 97	#define REG_TEST_CLK				BIT(13)
 98	#define REG_TEST_VA_TEST_EN_B_MASK		GENMASK(15, 14)
 99	#define REG_TEST_DATA_OUT_MASK			GENMASK(19, 16)
100	#define REG_TEST_DISABLE_ID_PULLUP		BIT(20)
101
102#define REG_TUNE					0x18
103	#define REG_TUNE_TX_RES_TUNE_MASK		GENMASK(1, 0)
104	#define REG_TUNE_TX_HSXV_TUNE_MASK		GENMASK(3, 2)
105	#define REG_TUNE_TX_VREF_TUNE_MASK		GENMASK(7, 4)
106	#define REG_TUNE_TX_RISE_TUNE_MASK		GENMASK(9, 8)
107	#define REG_TUNE_TX_PREEMP_PULSE_TUNE		BIT(10)
108	#define REG_TUNE_TX_PREEMP_AMP_TUNE_MASK	GENMASK(12, 11)
109	#define REG_TUNE_TX_FSLS_TUNE_MASK		GENMASK(16, 13)
110	#define REG_TUNE_SQRX_TUNE_MASK			GENMASK(19, 17)
111	#define REG_TUNE_OTG_TUNE			GENMASK(22, 20)
112	#define REG_TUNE_COMP_DIS_TUNE			GENMASK(25, 23)
113	#define REG_TUNE_HOST_DM_PULLDOWN		BIT(26)
114	#define REG_TUNE_HOST_DP_PULLDOWN		BIT(27)
115
116#define RESET_COMPLETE_TIME				500
117#define ACA_ENABLE_COMPLETE_TIME			50
118
119struct phy_meson8b_usb2_match_data {
120	bool			host_enable_aca;
121};
122
123struct phy_meson8b_usb2_priv {
124	struct regmap					*regmap;
125	enum usb_dr_mode				dr_mode;
126	struct clk					*clk_usb_general;
127	struct clk					*clk_usb;
128	struct reset_control				*reset;
129	const struct phy_meson8b_usb2_match_data	*match;
130};
131
132static const struct regmap_config phy_meson8b_usb2_regmap_conf = {
133	.reg_bits = 8,
134	.val_bits = 32,
135	.reg_stride = 4,
136	.max_register = REG_TUNE,
137};
138
139static int phy_meson8b_usb2_power_on(struct phy *phy)
140{
141	struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
142	u32 reg;
143	int ret;
144
145	if (!IS_ERR_OR_NULL(priv->reset)) {
146		ret = reset_control_reset(priv->reset);
147		if (ret) {
148			dev_err(&phy->dev, "Failed to trigger USB reset\n");
149			return ret;
150		}
151	}
152
153	ret = clk_prepare_enable(priv->clk_usb_general);
154	if (ret) {
155		dev_err(&phy->dev, "Failed to enable USB general clock\n");
156		reset_control_rearm(priv->reset);
157		return ret;
158	}
159
160	ret = clk_prepare_enable(priv->clk_usb);
161	if (ret) {
162		dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
163		clk_disable_unprepare(priv->clk_usb_general);
164		reset_control_rearm(priv->reset);
165		return ret;
166	}
167
168	regmap_set_bits(priv->regmap, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL);
169
170	regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK,
171			   FIELD_PREP(REG_CTRL_REF_CLK_SEL_MASK, 0x2));
172
173	regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_FSEL_MASK,
174			   FIELD_PREP(REG_CTRL_FSEL_MASK, 0x5));
175
176	/* reset the PHY */
177	regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
178	udelay(RESET_COMPLETE_TIME);
179	regmap_clear_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
180	udelay(RESET_COMPLETE_TIME);
181
182	regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT);
183
184	if (priv->dr_mode == USB_DR_MODE_HOST) {
185		regmap_clear_bits(priv->regmap, REG_DBG_UART,
186				  REG_DBG_UART_SET_IDDQ);
187
188		if (priv->match->host_enable_aca) {
189			regmap_set_bits(priv->regmap, REG_ADP_BC,
190					REG_ADP_BC_ACA_ENABLE);
191
192			udelay(ACA_ENABLE_COMPLETE_TIME);
193
194			regmap_read(priv->regmap, REG_ADP_BC, &reg);
195			if (reg & REG_ADP_BC_ACA_PIN_FLOAT) {
196				dev_warn(&phy->dev, "USB ID detect failed!\n");
197				clk_disable_unprepare(priv->clk_usb);
198				clk_disable_unprepare(priv->clk_usb_general);
199				reset_control_rearm(priv->reset);
200				return -EINVAL;
201			}
202		}
203	}
204
205	return 0;
206}
207
208static int phy_meson8b_usb2_power_off(struct phy *phy)
209{
210	struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
211
212	if (priv->dr_mode == USB_DR_MODE_HOST)
213		regmap_set_bits(priv->regmap, REG_DBG_UART,
214				REG_DBG_UART_SET_IDDQ);
215
216	clk_disable_unprepare(priv->clk_usb);
217	clk_disable_unprepare(priv->clk_usb_general);
218	reset_control_rearm(priv->reset);
219
220	/* power off the PHY by putting it into reset mode */
221	regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
222
223	return 0;
224}
225
226static const struct phy_ops phy_meson8b_usb2_ops = {
227	.power_on	= phy_meson8b_usb2_power_on,
228	.power_off	= phy_meson8b_usb2_power_off,
229	.owner		= THIS_MODULE,
230};
231
232static int phy_meson8b_usb2_probe(struct platform_device *pdev)
233{
234	struct phy_meson8b_usb2_priv *priv;
235	struct phy *phy;
236	struct phy_provider *phy_provider;
237	void __iomem *base;
238
239	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
240	if (!priv)
241		return -ENOMEM;
242
243	base = devm_platform_ioremap_resource(pdev, 0);
244	if (IS_ERR(base))
245		return PTR_ERR(base);
246
247	priv->match = device_get_match_data(&pdev->dev);
248	if (!priv->match)
249		return -ENODEV;
250
251	priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
252					     &phy_meson8b_usb2_regmap_conf);
253	if (IS_ERR(priv->regmap))
254		return PTR_ERR(priv->regmap);
255
256	priv->clk_usb_general = devm_clk_get(&pdev->dev, "usb_general");
257	if (IS_ERR(priv->clk_usb_general))
258		return PTR_ERR(priv->clk_usb_general);
259
260	priv->clk_usb = devm_clk_get(&pdev->dev, "usb");
261	if (IS_ERR(priv->clk_usb))
262		return PTR_ERR(priv->clk_usb);
263
264	priv->reset = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
265	if (IS_ERR(priv->reset))
266		return dev_err_probe(&pdev->dev, PTR_ERR(priv->reset),
267				     "Failed to get the reset line");
268
269	priv->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1);
270	if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
271		dev_err(&pdev->dev,
272			"missing dual role configuration of the controller\n");
273		return -EINVAL;
274	}
275
276	phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops);
277	if (IS_ERR(phy)) {
278		return dev_err_probe(&pdev->dev, PTR_ERR(phy),
279				     "failed to create PHY\n");
280	}
281
282	phy_set_drvdata(phy, priv);
283
284	phy_provider =
285		devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
286
287	return PTR_ERR_OR_ZERO(phy_provider);
288}
289
290static const struct phy_meson8b_usb2_match_data phy_meson8_usb2_match_data = {
291	.host_enable_aca = false,
292};
293
294static const struct phy_meson8b_usb2_match_data phy_meson8b_usb2_match_data = {
295	.host_enable_aca = true,
296};
297
298static const struct of_device_id phy_meson8b_usb2_of_match[] = {
299	{
300		.compatible = "amlogic,meson8-usb2-phy",
301		.data = &phy_meson8_usb2_match_data
302	},
303	{
304		.compatible = "amlogic,meson8b-usb2-phy",
305		.data = &phy_meson8b_usb2_match_data
306	},
307	{
308		.compatible = "amlogic,meson8m2-usb2-phy",
309		.data = &phy_meson8b_usb2_match_data
310	},
311	{
312		.compatible = "amlogic,meson-gxbb-usb2-phy",
313		.data = &phy_meson8b_usb2_match_data
314	},
315	{ /* sentinel */ }
316};
317MODULE_DEVICE_TABLE(of, phy_meson8b_usb2_of_match);
318
319static struct platform_driver phy_meson8b_usb2_driver = {
320	.probe	= phy_meson8b_usb2_probe,
321	.driver	= {
322		.name		= "phy-meson-usb2",
323		.of_match_table	= phy_meson8b_usb2_of_match,
324	},
325};
326module_platform_driver(phy_meson8b_usb2_driver);
327
328MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
329MODULE_DESCRIPTION("Meson8, Meson8b, Meson8m2 and GXBB USB2 PHY driver");
330MODULE_LICENSE("GPL");
~/ Read-only file preview.