1 // SPDX-License-Identifier: GPL-2.0-only
3 * Lantiq XWAY SoC RCU module based USB 1.1/2.0 PHY driver
5 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
6 * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
10 #include <linux/delay.h>
11 #include <linux/mfd/syscon.h>
12 #include <linux/module.h>
14 #include <linux/of_address.h>
15 #include <linux/of_device.h>
16 #include <linux/phy/phy.h>
17 #include <linux/platform_device.h>
18 #include <linux/property.h>
19 #include <linux/regmap.h>
20 #include <linux/reset.h>
22 /* Transmitter HS Pre-Emphasis Enable */
23 #define RCU_CFG1_TX_PEE BIT(0)
24 /* Disconnect Threshold */
25 #define RCU_CFG1_DIS_THR_MASK 0x00038000
26 #define RCU_CFG1_DIS_THR_SHIFT 15
28 struct ltq_rcu_usb2_bits
{
35 struct ltq_rcu_usb2_priv
{
36 struct regmap
*regmap
;
37 unsigned int phy_reg_offset
;
38 unsigned int ana_cfg1_reg_offset
;
39 const struct ltq_rcu_usb2_bits
*reg_bits
;
42 struct clk
*phy_gate_clk
;
43 struct reset_control
*ctrl_reset
;
44 struct reset_control
*phy_reset
;
47 static const struct ltq_rcu_usb2_bits xway_rcu_usb2_reg_bits
= {
49 .slave_endianness
= 9,
50 .host_endianness
= 10,
51 .have_ana_cfg
= false,
54 static const struct ltq_rcu_usb2_bits xrx100_rcu_usb2_reg_bits
= {
56 .slave_endianness
= 17,
57 .host_endianness
= 10,
58 .have_ana_cfg
= false,
61 static const struct ltq_rcu_usb2_bits xrx200_rcu_usb2_reg_bits
= {
63 .slave_endianness
= 9,
64 .host_endianness
= 10,
68 static const struct of_device_id ltq_rcu_usb2_phy_of_match
[] = {
70 .compatible
= "lantiq,ase-usb2-phy",
71 .data
= &xway_rcu_usb2_reg_bits
,
74 .compatible
= "lantiq,danube-usb2-phy",
75 .data
= &xway_rcu_usb2_reg_bits
,
78 .compatible
= "lantiq,xrx100-usb2-phy",
79 .data
= &xrx100_rcu_usb2_reg_bits
,
82 .compatible
= "lantiq,xrx200-usb2-phy",
83 .data
= &xrx200_rcu_usb2_reg_bits
,
86 .compatible
= "lantiq,xrx300-usb2-phy",
87 .data
= &xrx200_rcu_usb2_reg_bits
,
91 MODULE_DEVICE_TABLE(of
, ltq_rcu_usb2_phy_of_match
);
93 static int ltq_rcu_usb2_phy_init(struct phy
*phy
)
95 struct ltq_rcu_usb2_priv
*priv
= phy_get_drvdata(phy
);
97 if (priv
->reg_bits
->have_ana_cfg
) {
98 regmap_update_bits(priv
->regmap
, priv
->ana_cfg1_reg_offset
,
99 RCU_CFG1_TX_PEE
, RCU_CFG1_TX_PEE
);
100 regmap_update_bits(priv
->regmap
, priv
->ana_cfg1_reg_offset
,
101 RCU_CFG1_DIS_THR_MASK
, 7 << RCU_CFG1_DIS_THR_SHIFT
);
104 /* Configure core to host mode */
105 regmap_update_bits(priv
->regmap
, priv
->phy_reg_offset
,
106 BIT(priv
->reg_bits
->hostmode
), 0);
108 /* Select DMA endianness (Host-endian: big-endian) */
109 regmap_update_bits(priv
->regmap
, priv
->phy_reg_offset
,
110 BIT(priv
->reg_bits
->slave_endianness
), 0);
111 regmap_update_bits(priv
->regmap
, priv
->phy_reg_offset
,
112 BIT(priv
->reg_bits
->host_endianness
),
113 BIT(priv
->reg_bits
->host_endianness
));
118 static int ltq_rcu_usb2_phy_power_on(struct phy
*phy
)
120 struct ltq_rcu_usb2_priv
*priv
= phy_get_drvdata(phy
);
121 struct device
*dev
= priv
->dev
;
124 reset_control_deassert(priv
->phy_reset
);
126 ret
= clk_prepare_enable(priv
->phy_gate_clk
);
128 dev_err(dev
, "failed to enable PHY gate\n");
133 static int ltq_rcu_usb2_phy_power_off(struct phy
*phy
)
135 struct ltq_rcu_usb2_priv
*priv
= phy_get_drvdata(phy
);
137 reset_control_assert(priv
->phy_reset
);
139 clk_disable_unprepare(priv
->phy_gate_clk
);
144 static const struct phy_ops ltq_rcu_usb2_phy_ops
= {
145 .init
= ltq_rcu_usb2_phy_init
,
146 .power_on
= ltq_rcu_usb2_phy_power_on
,
147 .power_off
= ltq_rcu_usb2_phy_power_off
,
148 .owner
= THIS_MODULE
,
151 static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv
*priv
,
152 struct platform_device
*pdev
)
154 struct device
*dev
= priv
->dev
;
155 const __be32
*offset
;
157 priv
->reg_bits
= of_device_get_match_data(dev
);
159 priv
->regmap
= syscon_node_to_regmap(dev
->of_node
->parent
);
160 if (IS_ERR(priv
->regmap
)) {
161 dev_err(dev
, "Failed to lookup RCU regmap\n");
162 return PTR_ERR(priv
->regmap
);
165 offset
= of_get_address(dev
->of_node
, 0, NULL
, NULL
);
167 dev_err(dev
, "Failed to get RCU PHY reg offset\n");
170 priv
->phy_reg_offset
= __be32_to_cpu(*offset
);
172 if (priv
->reg_bits
->have_ana_cfg
) {
173 offset
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
175 dev_err(dev
, "Failed to get RCU ANA CFG1 reg offset\n");
178 priv
->ana_cfg1_reg_offset
= __be32_to_cpu(*offset
);
181 priv
->phy_gate_clk
= devm_clk_get(dev
, "phy");
182 if (IS_ERR(priv
->phy_gate_clk
)) {
183 dev_err(dev
, "Unable to get USB phy gate clk\n");
184 return PTR_ERR(priv
->phy_gate_clk
);
187 priv
->ctrl_reset
= devm_reset_control_get_shared(dev
, "ctrl");
188 if (IS_ERR(priv
->ctrl_reset
)) {
189 if (PTR_ERR(priv
->ctrl_reset
) != -EPROBE_DEFER
)
190 dev_err(dev
, "failed to get 'ctrl' reset\n");
191 return PTR_ERR(priv
->ctrl_reset
);
194 priv
->phy_reset
= devm_reset_control_get_optional(dev
, "phy");
196 return PTR_ERR_OR_ZERO(priv
->phy_reset
);
199 static int ltq_rcu_usb2_phy_probe(struct platform_device
*pdev
)
201 struct device
*dev
= &pdev
->dev
;
202 struct ltq_rcu_usb2_priv
*priv
;
203 struct phy_provider
*provider
;
206 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
212 ret
= ltq_rcu_usb2_of_parse(priv
, pdev
);
216 /* Reset USB core through reset controller */
217 reset_control_deassert(priv
->ctrl_reset
);
219 reset_control_assert(priv
->phy_reset
);
221 priv
->phy
= devm_phy_create(dev
, dev
->of_node
, <q_rcu_usb2_phy_ops
);
222 if (IS_ERR(priv
->phy
)) {
223 dev_err(dev
, "failed to create PHY\n");
224 return PTR_ERR(priv
->phy
);
227 phy_set_drvdata(priv
->phy
, priv
);
229 provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
230 if (IS_ERR(provider
))
231 return PTR_ERR(provider
);
233 dev_set_drvdata(priv
->dev
, priv
);
237 static struct platform_driver ltq_rcu_usb2_phy_driver
= {
238 .probe
= ltq_rcu_usb2_phy_probe
,
240 .name
= "lantiq-rcu-usb2-phy",
241 .of_match_table
= ltq_rcu_usb2_phy_of_match
,
244 module_platform_driver(ltq_rcu_usb2_phy_driver
);
246 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
247 MODULE_DESCRIPTION("Lantiq XWAY USB2 PHY driver");
248 MODULE_LICENSE("GPL v2");