1 // SPDX-License-Identifier: GPL-2.0
3 * Texas Instruments CPSW Port's PHY Interface Mode selection Driver
5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
7 * Based on cpsw-phy-sel.c driver created by Mugunthan V N <mugunthanvnm@ti.com>
10 #include <linux/platform_device.h>
11 #include <linux/module.h>
12 #include <linux/mfd/syscon.h>
14 #include <linux/of_net.h>
15 #include <linux/phy.h>
16 #include <linux/phy/phy.h>
17 #include <linux/regmap.h>
19 /* AM33xx SoC specific definitions for the CONTROL port */
20 #define AM33XX_GMII_SEL_MODE_MII 0
21 #define AM33XX_GMII_SEL_MODE_RMII 1
22 #define AM33XX_GMII_SEL_MODE_RGMII 2
25 PHY_GMII_SEL_PORT_MODE
,
26 PHY_GMII_SEL_RGMII_ID_MODE
,
27 PHY_GMII_SEL_RMII_IO_CLK_EN
,
31 struct phy_gmii_sel_phy_priv
{
32 struct phy_gmii_sel_priv
*priv
;
35 int rmii_clock_external
;
37 struct regmap_field
*fields
[PHY_GMII_SEL_LAST
];
40 struct phy_gmii_sel_soc_data
{
43 const struct reg_field (*regfields
)[PHY_GMII_SEL_LAST
];
46 struct phy_gmii_sel_priv
{
48 const struct phy_gmii_sel_soc_data
*soc_data
;
49 struct regmap
*regmap
;
50 struct phy_provider
*phy_provider
;
51 struct phy_gmii_sel_phy_priv
*if_phys
;
54 static int phy_gmii_sel_mode(struct phy
*phy
, enum phy_mode mode
, int submode
)
56 struct phy_gmii_sel_phy_priv
*if_phy
= phy_get_drvdata(phy
);
57 const struct phy_gmii_sel_soc_data
*soc_data
= if_phy
->priv
->soc_data
;
58 struct device
*dev
= if_phy
->priv
->dev
;
59 struct regmap_field
*regfield
;
60 int ret
, rgmii_id
= 0;
61 u32 gmii_sel_mode
= 0;
63 if (mode
!= PHY_MODE_ETHERNET
)
67 case PHY_INTERFACE_MODE_RMII
:
68 gmii_sel_mode
= AM33XX_GMII_SEL_MODE_RMII
;
71 case PHY_INTERFACE_MODE_RGMII
:
72 case PHY_INTERFACE_MODE_RGMII_RXID
:
73 gmii_sel_mode
= AM33XX_GMII_SEL_MODE_RGMII
;
76 case PHY_INTERFACE_MODE_RGMII_ID
:
77 case PHY_INTERFACE_MODE_RGMII_TXID
:
78 gmii_sel_mode
= AM33XX_GMII_SEL_MODE_RGMII
;
82 case PHY_INTERFACE_MODE_MII
:
83 mode
= AM33XX_GMII_SEL_MODE_MII
;
88 "port%u: unsupported mode: \"%s\". Defaulting to MII.\n",
89 if_phy
->id
, phy_modes(rgmii_id
));
93 if_phy
->phy_if_mode
= submode
;
95 dev_dbg(dev
, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n",
96 __func__
, if_phy
->id
, mode
, rgmii_id
,
97 if_phy
->rmii_clock_external
);
99 regfield
= if_phy
->fields
[PHY_GMII_SEL_PORT_MODE
];
100 ret
= regmap_field_write(regfield
, gmii_sel_mode
);
102 dev_err(dev
, "port%u: set mode fail %d", if_phy
->id
, ret
);
106 if (soc_data
->features
& BIT(PHY_GMII_SEL_RGMII_ID_MODE
) &&
107 if_phy
->fields
[PHY_GMII_SEL_RGMII_ID_MODE
]) {
108 regfield
= if_phy
->fields
[PHY_GMII_SEL_RGMII_ID_MODE
];
109 ret
= regmap_field_write(regfield
, rgmii_id
);
114 if (soc_data
->features
& BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
) &&
115 if_phy
->fields
[PHY_GMII_SEL_RMII_IO_CLK_EN
]) {
116 regfield
= if_phy
->fields
[PHY_GMII_SEL_RMII_IO_CLK_EN
];
117 ret
= regmap_field_write(regfield
,
118 if_phy
->rmii_clock_external
);
125 struct reg_field phy_gmii_sel_fields_am33xx
[][PHY_GMII_SEL_LAST
] = {
127 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x650, 0, 1),
128 [PHY_GMII_SEL_RGMII_ID_MODE
] = REG_FIELD(0x650, 4, 4),
129 [PHY_GMII_SEL_RMII_IO_CLK_EN
] = REG_FIELD(0x650, 6, 6),
132 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x650, 2, 3),
133 [PHY_GMII_SEL_RGMII_ID_MODE
] = REG_FIELD(0x650, 5, 5),
134 [PHY_GMII_SEL_RMII_IO_CLK_EN
] = REG_FIELD(0x650, 7, 7),
139 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am33xx
= {
141 .features
= BIT(PHY_GMII_SEL_RGMII_ID_MODE
) |
142 BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
),
143 .regfields
= phy_gmii_sel_fields_am33xx
,
147 struct reg_field phy_gmii_sel_fields_dra7
[][PHY_GMII_SEL_LAST
] = {
149 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x554, 0, 1),
150 [PHY_GMII_SEL_RGMII_ID_MODE
] = REG_FIELD((~0), 0, 0),
151 [PHY_GMII_SEL_RMII_IO_CLK_EN
] = REG_FIELD((~0), 0, 0),
154 [PHY_GMII_SEL_PORT_MODE
] = REG_FIELD(0x554, 4, 5),
155 [PHY_GMII_SEL_RGMII_ID_MODE
] = REG_FIELD((~0), 0, 0),
156 [PHY_GMII_SEL_RMII_IO_CLK_EN
] = REG_FIELD((~0), 0, 0),
161 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dra7
= {
163 .regfields
= phy_gmii_sel_fields_dra7
,
167 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814
= {
169 .features
= BIT(PHY_GMII_SEL_RGMII_ID_MODE
),
170 .regfields
= phy_gmii_sel_fields_am33xx
,
173 static const struct of_device_id phy_gmii_sel_id_table
[] = {
175 .compatible
= "ti,am3352-phy-gmii-sel",
176 .data
= &phy_gmii_sel_soc_am33xx
,
179 .compatible
= "ti,dra7xx-phy-gmii-sel",
180 .data
= &phy_gmii_sel_soc_dra7
,
183 .compatible
= "ti,am43xx-phy-gmii-sel",
184 .data
= &phy_gmii_sel_soc_am33xx
,
187 .compatible
= "ti,dm814-phy-gmii-sel",
188 .data
= &phy_gmii_sel_soc_dm814
,
192 MODULE_DEVICE_TABLE(of
, phy_gmii_sel_id_table
);
194 static const struct phy_ops phy_gmii_sel_ops
= {
195 .set_mode
= phy_gmii_sel_mode
,
196 .owner
= THIS_MODULE
,
199 static struct phy
*phy_gmii_sel_of_xlate(struct device
*dev
,
200 struct of_phandle_args
*args
)
202 struct phy_gmii_sel_priv
*priv
= dev_get_drvdata(dev
);
203 int phy_id
= args
->args
[0];
205 if (args
->args_count
< 1)
206 return ERR_PTR(-EINVAL
);
207 if (!priv
|| !priv
->if_phys
)
208 return ERR_PTR(-ENODEV
);
209 if (priv
->soc_data
->features
& BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
) &&
210 args
->args_count
< 2)
211 return ERR_PTR(-EINVAL
);
212 if (phy_id
> priv
->soc_data
->num_ports
)
213 return ERR_PTR(-EINVAL
);
214 if (phy_id
!= priv
->if_phys
[phy_id
- 1].id
)
215 return ERR_PTR(-EINVAL
);
218 if (priv
->soc_data
->features
& BIT(PHY_GMII_SEL_RMII_IO_CLK_EN
))
219 priv
->if_phys
[phy_id
].rmii_clock_external
= args
->args
[1];
220 dev_dbg(dev
, "%s id:%u ext:%d\n", __func__
,
221 priv
->if_phys
[phy_id
].id
, args
->args
[1]);
223 return priv
->if_phys
[phy_id
].if_phy
;
226 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv
*priv
)
228 const struct phy_gmii_sel_soc_data
*soc_data
= priv
->soc_data
;
229 struct device
*dev
= priv
->dev
;
230 struct phy_gmii_sel_phy_priv
*if_phys
;
231 int i
, num_ports
, ret
;
233 num_ports
= priv
->soc_data
->num_ports
;
235 if_phys
= devm_kcalloc(priv
->dev
, num_ports
,
236 sizeof(*if_phys
), GFP_KERNEL
);
239 dev_dbg(dev
, "%s %d\n", __func__
, num_ports
);
241 for (i
= 0; i
< num_ports
; i
++) {
242 const struct reg_field
*field
;
243 struct regmap_field
*regfield
;
245 if_phys
[i
].id
= i
+ 1;
246 if_phys
[i
].priv
= priv
;
248 field
= &soc_data
->regfields
[i
][PHY_GMII_SEL_PORT_MODE
];
249 dev_dbg(dev
, "%s field %x %d %d\n", __func__
,
250 field
->reg
, field
->msb
, field
->lsb
);
252 regfield
= devm_regmap_field_alloc(dev
, priv
->regmap
, *field
);
253 if (IS_ERR(regfield
))
254 return PTR_ERR(regfield
);
255 if_phys
[i
].fields
[PHY_GMII_SEL_PORT_MODE
] = regfield
;
257 field
= &soc_data
->regfields
[i
][PHY_GMII_SEL_RGMII_ID_MODE
];
258 if (field
->reg
!= (~0)) {
259 regfield
= devm_regmap_field_alloc(dev
,
262 if (IS_ERR(regfield
))
263 return PTR_ERR(regfield
);
264 if_phys
[i
].fields
[PHY_GMII_SEL_RGMII_ID_MODE
] =
268 field
= &soc_data
->regfields
[i
][PHY_GMII_SEL_RMII_IO_CLK_EN
];
269 if (field
->reg
!= (~0)) {
270 regfield
= devm_regmap_field_alloc(dev
,
273 if (IS_ERR(regfield
))
274 return PTR_ERR(regfield
);
275 if_phys
[i
].fields
[PHY_GMII_SEL_RMII_IO_CLK_EN
] =
279 if_phys
[i
].if_phy
= devm_phy_create(dev
,
282 if (IS_ERR(if_phys
[i
].if_phy
)) {
283 ret
= PTR_ERR(if_phys
[i
].if_phy
);
284 dev_err(dev
, "Failed to create phy%d %d\n", i
, ret
);
287 phy_set_drvdata(if_phys
[i
].if_phy
, &if_phys
[i
]);
290 priv
->if_phys
= if_phys
;
294 static int phy_gmii_sel_probe(struct platform_device
*pdev
)
296 struct device
*dev
= &pdev
->dev
;
297 struct device_node
*node
= dev
->of_node
;
298 const struct of_device_id
*of_id
;
299 struct phy_gmii_sel_priv
*priv
;
302 of_id
= of_match_node(phy_gmii_sel_id_table
, pdev
->dev
.of_node
);
306 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
310 priv
->dev
= &pdev
->dev
;
311 priv
->soc_data
= of_id
->data
;
313 priv
->regmap
= syscon_node_to_regmap(node
->parent
);
314 if (IS_ERR(priv
->regmap
)) {
315 ret
= PTR_ERR(priv
->regmap
);
316 dev_err(dev
, "Failed to get syscon %d\n", ret
);
320 ret
= phy_gmii_sel_init_ports(priv
);
324 dev_set_drvdata(&pdev
->dev
, priv
);
327 devm_of_phy_provider_register(dev
,
328 phy_gmii_sel_of_xlate
);
329 if (IS_ERR(priv
->phy_provider
)) {
330 ret
= PTR_ERR(priv
->phy_provider
);
331 dev_err(dev
, "Failed to create phy provider %d\n", ret
);
338 static struct platform_driver phy_gmii_sel_driver
= {
339 .probe
= phy_gmii_sel_probe
,
341 .name
= "phy-gmii-sel",
342 .of_match_table
= phy_gmii_sel_id_table
,
345 module_platform_driver(phy_gmii_sel_driver
);
347 MODULE_LICENSE("GPL v2");
348 MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>");
349 MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver");