2 * Lantiq XWAY SoC RCU module based USB 1.1/2.0 PHY driver
4 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
5 * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/clk.h>
13 #include <linux/delay.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/module.h>
17 #include <linux/of_address.h>
18 #include <linux/of_device.h>
19 #include <linux/phy/phy.h>
20 #include <linux/platform_device.h>
21 #include <linux/property.h>
22 #include <linux/regmap.h>
23 #include <linux/reset.h>
25 /* Transmitter HS Pre-Emphasis Enable */
26 #define RCU_CFG1_TX_PEE BIT(0)
27 /* Disconnect Threshold */
28 #define RCU_CFG1_DIS_THR_MASK 0x00038000
29 #define RCU_CFG1_DIS_THR_SHIFT 15
31 struct ltq_rcu_usb2_bits
{
38 struct ltq_rcu_usb2_priv
{
39 struct regmap
*regmap
;
40 unsigned int phy_reg_offset
;
41 unsigned int ana_cfg1_reg_offset
;
42 const struct ltq_rcu_usb2_bits
*reg_bits
;
45 struct clk
*phy_gate_clk
;
46 struct reset_control
*ctrl_reset
;
47 struct reset_control
*phy_reset
;
50 static const struct ltq_rcu_usb2_bits xway_rcu_usb2_reg_bits
= {
52 .slave_endianness
= 9,
53 .host_endianness
= 10,
54 .have_ana_cfg
= false,
57 static const struct ltq_rcu_usb2_bits xrx100_rcu_usb2_reg_bits
= {
59 .slave_endianness
= 17,
60 .host_endianness
= 10,
61 .have_ana_cfg
= false,
64 static const struct ltq_rcu_usb2_bits xrx200_rcu_usb2_reg_bits
= {
66 .slave_endianness
= 9,
67 .host_endianness
= 10,
71 static const struct of_device_id ltq_rcu_usb2_phy_of_match
[] = {
73 .compatible
= "lantiq,ase-usb2-phy",
74 .data
= &xway_rcu_usb2_reg_bits
,
77 .compatible
= "lantiq,danube-usb2-phy",
78 .data
= &xway_rcu_usb2_reg_bits
,
81 .compatible
= "lantiq,xrx100-usb2-phy",
82 .data
= &xrx100_rcu_usb2_reg_bits
,
85 .compatible
= "lantiq,xrx200-usb2-phy",
86 .data
= &xrx200_rcu_usb2_reg_bits
,
89 .compatible
= "lantiq,xrx300-usb2-phy",
90 .data
= &xrx200_rcu_usb2_reg_bits
,
94 MODULE_DEVICE_TABLE(of
, ltq_rcu_usb2_phy_of_match
);
96 static int ltq_rcu_usb2_phy_init(struct phy
*phy
)
98 struct ltq_rcu_usb2_priv
*priv
= phy_get_drvdata(phy
);
100 if (priv
->reg_bits
->have_ana_cfg
) {
101 regmap_update_bits(priv
->regmap
, priv
->ana_cfg1_reg_offset
,
102 RCU_CFG1_TX_PEE
, RCU_CFG1_TX_PEE
);
103 regmap_update_bits(priv
->regmap
, priv
->ana_cfg1_reg_offset
,
104 RCU_CFG1_DIS_THR_MASK
, 7 << RCU_CFG1_DIS_THR_SHIFT
);
107 /* Configure core to host mode */
108 regmap_update_bits(priv
->regmap
, priv
->phy_reg_offset
,
109 BIT(priv
->reg_bits
->hostmode
), 0);
111 /* Select DMA endianness (Host-endian: big-endian) */
112 regmap_update_bits(priv
->regmap
, priv
->phy_reg_offset
,
113 BIT(priv
->reg_bits
->slave_endianness
), 0);
114 regmap_update_bits(priv
->regmap
, priv
->phy_reg_offset
,
115 BIT(priv
->reg_bits
->host_endianness
),
116 BIT(priv
->reg_bits
->host_endianness
));
121 static int ltq_rcu_usb2_phy_power_on(struct phy
*phy
)
123 struct ltq_rcu_usb2_priv
*priv
= phy_get_drvdata(phy
);
124 struct device
*dev
= priv
->dev
;
127 reset_control_deassert(priv
->phy_reset
);
129 ret
= clk_prepare_enable(priv
->phy_gate_clk
);
131 dev_err(dev
, "failed to enable PHY gate\n");
136 static int ltq_rcu_usb2_phy_power_off(struct phy
*phy
)
138 struct ltq_rcu_usb2_priv
*priv
= phy_get_drvdata(phy
);
140 reset_control_assert(priv
->phy_reset
);
142 clk_disable_unprepare(priv
->phy_gate_clk
);
147 static struct phy_ops ltq_rcu_usb2_phy_ops
= {
148 .init
= ltq_rcu_usb2_phy_init
,
149 .power_on
= ltq_rcu_usb2_phy_power_on
,
150 .power_off
= ltq_rcu_usb2_phy_power_off
,
151 .owner
= THIS_MODULE
,
154 static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv
*priv
,
155 struct platform_device
*pdev
)
157 struct device
*dev
= priv
->dev
;
158 const __be32
*offset
;
161 priv
->reg_bits
= of_device_get_match_data(dev
);
163 priv
->regmap
= syscon_node_to_regmap(dev
->of_node
->parent
);
164 if (IS_ERR(priv
->regmap
)) {
165 dev_err(dev
, "Failed to lookup RCU regmap\n");
166 return PTR_ERR(priv
->regmap
);
169 offset
= of_get_address(dev
->of_node
, 0, NULL
, NULL
);
171 dev_err(dev
, "Failed to get RCU PHY reg offset\n");
174 priv
->phy_reg_offset
= __be32_to_cpu(*offset
);
176 if (priv
->reg_bits
->have_ana_cfg
) {
177 offset
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
179 dev_err(dev
, "Failed to get RCU ANA CFG1 reg offset\n");
182 priv
->ana_cfg1_reg_offset
= __be32_to_cpu(*offset
);
185 priv
->phy_gate_clk
= devm_clk_get(dev
, "phy");
186 if (IS_ERR(priv
->phy_gate_clk
)) {
187 dev_err(dev
, "Unable to get USB phy gate clk\n");
188 return PTR_ERR(priv
->phy_gate_clk
);
191 priv
->ctrl_reset
= devm_reset_control_get_shared(dev
, "ctrl");
192 if (IS_ERR(priv
->ctrl_reset
)) {
193 if (PTR_ERR(priv
->ctrl_reset
) != -EPROBE_DEFER
)
194 dev_err(dev
, "failed to get 'ctrl' reset\n");
195 return PTR_ERR(priv
->ctrl_reset
);
198 priv
->phy_reset
= devm_reset_control_get_optional(dev
, "phy");
199 if (IS_ERR(priv
->phy_reset
))
200 return PTR_ERR(priv
->phy_reset
);
205 static int ltq_rcu_usb2_phy_probe(struct platform_device
*pdev
)
207 struct device
*dev
= &pdev
->dev
;
208 struct ltq_rcu_usb2_priv
*priv
;
209 struct phy_provider
*provider
;
212 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
218 ret
= ltq_rcu_usb2_of_parse(priv
, pdev
);
222 /* Reset USB core through reset controller */
223 reset_control_deassert(priv
->ctrl_reset
);
225 reset_control_assert(priv
->phy_reset
);
227 priv
->phy
= devm_phy_create(dev
, dev
->of_node
, <q_rcu_usb2_phy_ops
);
228 if (IS_ERR(priv
->phy
)) {
229 dev_err(dev
, "failed to create PHY\n");
230 return PTR_ERR(priv
->phy
);
233 phy_set_drvdata(priv
->phy
, priv
);
235 provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
236 if (IS_ERR(provider
))
237 return PTR_ERR(provider
);
239 dev_set_drvdata(priv
->dev
, priv
);
243 static struct platform_driver ltq_rcu_usb2_phy_driver
= {
244 .probe
= ltq_rcu_usb2_phy_probe
,
246 .name
= "lantiq-rcu-usb2-phy",
247 .of_match_table
= ltq_rcu_usb2_phy_of_match
,
250 module_platform_driver(ltq_rcu_usb2_phy_driver
);
252 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
253 MODULE_DESCRIPTION("Lantiq XWAY USB2 PHY driver");
254 MODULE_LICENSE("GPL v2");