Lines Matching +full:am3352 +full:- +full:phy +full:- +full:gmii +full:- +full:sel
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>
16 #include <linux/phy.h>
17 #include <linux/phy/phy.h>
31 #define PHY_GMII_PORT(n) BIT((n) - 1)
43 struct phy *if_phy;
70 static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) in phy_gmii_sel_mode() argument
72 struct phy_gmii_sel_phy_priv *if_phy = phy_get_drvdata(phy); in phy_gmii_sel_mode()
73 const struct phy_gmii_sel_soc_data *soc_data = if_phy->priv->soc_data; in phy_gmii_sel_mode()
74 struct device *dev = if_phy->priv->dev; in phy_gmii_sel_mode()
80 return -EINVAL; in phy_gmii_sel_mode()
104 if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_QSGMII))) in phy_gmii_sel_mode()
106 if (if_phy->priv->qsgmii_main_ports & BIT(if_phy->id - 1)) in phy_gmii_sel_mode()
113 if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_SGMII))) in phy_gmii_sel_mode()
120 if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_USXGMII))) in phy_gmii_sel_mode()
130 if_phy->phy_if_mode = submode; in phy_gmii_sel_mode()
133 __func__, if_phy->id, submode, rgmii_id, in phy_gmii_sel_mode()
134 if_phy->rmii_clock_external); in phy_gmii_sel_mode()
136 regfield = if_phy->fields[PHY_GMII_SEL_PORT_MODE]; in phy_gmii_sel_mode()
139 dev_err(dev, "port%u: set mode fail %d", if_phy->id, ret); in phy_gmii_sel_mode()
143 if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE) && in phy_gmii_sel_mode()
144 if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]) { in phy_gmii_sel_mode()
145 regfield = if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]; in phy_gmii_sel_mode()
151 if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && in phy_gmii_sel_mode()
152 if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]) { in phy_gmii_sel_mode()
153 regfield = if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]; in phy_gmii_sel_mode()
155 if_phy->rmii_clock_external); in phy_gmii_sel_mode()
162 if_phy->id, phy_modes(submode)); in phy_gmii_sel_mode()
163 return -EINVAL; in phy_gmii_sel_mode()
259 .compatible = "ti,am3352-phy-gmii-sel",
263 .compatible = "ti,dra7xx-phy-gmii-sel",
267 .compatible = "ti,am43xx-phy-gmii-sel",
271 .compatible = "ti,dm814-phy-gmii-sel",
275 .compatible = "ti,am654-phy-gmii-sel",
279 .compatible = "ti,j7200-cpsw5g-phy-gmii-sel",
283 .compatible = "ti,j721e-cpsw9g-phy-gmii-sel",
287 .compatible = "ti,j784s4-cpsw9g-phy-gmii-sel",
299 static struct phy *phy_gmii_sel_of_xlate(struct device *dev, in phy_gmii_sel_of_xlate()
303 int phy_id = args->args[0]; in phy_gmii_sel_of_xlate()
305 if (args->args_count < 1) in phy_gmii_sel_of_xlate()
306 return ERR_PTR(-EINVAL); in phy_gmii_sel_of_xlate()
307 if (!priv || !priv->if_phys) in phy_gmii_sel_of_xlate()
308 return ERR_PTR(-ENODEV); in phy_gmii_sel_of_xlate()
309 if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && in phy_gmii_sel_of_xlate()
310 args->args_count < 2) in phy_gmii_sel_of_xlate()
311 return ERR_PTR(-EINVAL); in phy_gmii_sel_of_xlate()
312 if (phy_id > priv->num_ports) in phy_gmii_sel_of_xlate()
313 return ERR_PTR(-EINVAL); in phy_gmii_sel_of_xlate()
314 if (phy_id != priv->if_phys[phy_id - 1].id) in phy_gmii_sel_of_xlate()
315 return ERR_PTR(-EINVAL); in phy_gmii_sel_of_xlate()
317 phy_id--; in phy_gmii_sel_of_xlate()
318 if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) in phy_gmii_sel_of_xlate()
319 priv->if_phys[phy_id].rmii_clock_external = args->args[1]; in phy_gmii_sel_of_xlate()
321 priv->if_phys[phy_id].id, args->args[1]); in phy_gmii_sel_of_xlate()
323 return priv->if_phys[phy_id].if_phy; in phy_gmii_sel_of_xlate()
329 const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data; in phy_gmii_init_phy()
330 struct device *dev = priv->dev; in phy_gmii_init_phy()
336 if_phy->id = port; in phy_gmii_init_phy()
337 if_phy->priv = priv; in phy_gmii_init_phy()
339 fields = soc_data->regfields[port - 1]; in phy_gmii_init_phy()
341 field.reg += priv->reg_offset; in phy_gmii_init_phy()
345 regfield = devm_regmap_field_alloc(dev, priv->regmap, field); in phy_gmii_init_phy()
348 if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield; in phy_gmii_init_phy()
351 field.reg += priv->reg_offset; in phy_gmii_init_phy()
352 if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) { in phy_gmii_init_phy()
354 priv->regmap, in phy_gmii_init_phy()
358 if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE] = regfield; in phy_gmii_init_phy()
364 field.reg += priv->reg_offset; in phy_gmii_init_phy()
365 if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) { in phy_gmii_init_phy()
367 priv->regmap, in phy_gmii_init_phy()
371 if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN] = regfield; in phy_gmii_init_phy()
376 if_phy->if_phy = devm_phy_create(dev, in phy_gmii_init_phy()
377 priv->dev->of_node, in phy_gmii_init_phy()
379 if (IS_ERR(if_phy->if_phy)) { in phy_gmii_init_phy()
380 ret = PTR_ERR(if_phy->if_phy); in phy_gmii_init_phy()
381 dev_err(dev, "Failed to create phy%d %d\n", port, ret); in phy_gmii_init_phy()
384 phy_set_drvdata(if_phy->if_phy, if_phy); in phy_gmii_init_phy()
391 const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data; in phy_gmii_sel_init_ports()
393 struct device *dev = priv->dev; in phy_gmii_sel_init_ports()
396 if (soc_data->use_of_data) { in phy_gmii_sel_init_ports()
400 offset = of_get_address(dev->of_node, 0, &size, NULL); in phy_gmii_sel_init_ports()
402 return -EINVAL; in phy_gmii_sel_init_ports()
403 priv->num_ports = size / sizeof(u32); in phy_gmii_sel_init_ports()
404 if (!priv->num_ports) in phy_gmii_sel_init_ports()
405 return -EINVAL; in phy_gmii_sel_init_ports()
406 if (!priv->no_offset) in phy_gmii_sel_init_ports()
407 priv->reg_offset = __be32_to_cpu(*offset); in phy_gmii_sel_init_ports()
410 if_phys = devm_kcalloc(dev, priv->num_ports, in phy_gmii_sel_init_ports()
413 return -ENOMEM; in phy_gmii_sel_init_ports()
414 dev_dbg(dev, "%s %d\n", __func__, priv->num_ports); in phy_gmii_sel_init_ports()
416 for (i = 0; i < priv->num_ports; i++) { in phy_gmii_sel_init_ports()
422 priv->if_phys = if_phys; in phy_gmii_sel_init_ports()
428 struct device *dev = &pdev->dev; in phy_gmii_sel_probe()
430 struct device_node *node = dev->of_node; in phy_gmii_sel_probe()
437 of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node); in phy_gmii_sel_probe()
439 return -EINVAL; in phy_gmii_sel_probe()
441 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in phy_gmii_sel_probe()
443 return -ENOMEM; in phy_gmii_sel_probe()
445 priv->dev = &pdev->dev; in phy_gmii_sel_probe()
446 priv->soc_data = of_id->data; in phy_gmii_sel_probe()
447 soc_data = priv->soc_data; in phy_gmii_sel_probe()
448 priv->num_ports = priv->soc_data->num_ports; in phy_gmii_sel_probe()
449 priv->qsgmii_main_ports = 0; in phy_gmii_sel_probe()
453 * QSGMII main ports from the "ti,qsgmii-main-ports" property from in phy_gmii_sel_probe()
454 * the device-tree node. in phy_gmii_sel_probe()
456 for (i = 0; i < soc_data->num_qsgmii_main_ports; i++) { in phy_gmii_sel_probe()
457 of_property_read_u32_index(node, "ti,qsgmii-main-ports", i, &main_ports); in phy_gmii_sel_probe()
461 if (main_ports < 1 || main_ports > soc_data->num_ports) { in phy_gmii_sel_probe()
463 return -EINVAL; in phy_gmii_sel_probe()
465 priv->qsgmii_main_ports |= PHY_GMII_PORT(main_ports); in phy_gmii_sel_probe()
468 priv->regmap = syscon_node_to_regmap(node->parent); in phy_gmii_sel_probe()
469 if (IS_ERR(priv->regmap)) { in phy_gmii_sel_probe()
470 priv->regmap = device_node_to_regmap(node); in phy_gmii_sel_probe()
471 if (IS_ERR(priv->regmap)) in phy_gmii_sel_probe()
472 return dev_err_probe(dev, PTR_ERR(priv->regmap), in phy_gmii_sel_probe()
474 priv->no_offset = true; in phy_gmii_sel_probe()
481 dev_set_drvdata(&pdev->dev, priv); in phy_gmii_sel_probe()
483 priv->phy_provider = in phy_gmii_sel_probe()
486 if (IS_ERR(priv->phy_provider)) in phy_gmii_sel_probe()
487 return dev_err_probe(dev, PTR_ERR(priv->phy_provider), in phy_gmii_sel_probe()
488 "Failed to create phy provider\n"); in phy_gmii_sel_probe()
496 struct phy_gmii_sel_phy_priv *if_phys = priv->if_phys; in phy_gmii_sel_resume_noirq()
499 for (i = 0; i < priv->num_ports; i++) { in phy_gmii_sel_resume_noirq()
505 if_phys[i].if_phy->id, ret); in phy_gmii_sel_resume_noirq()
519 .name = "phy-gmii-sel",
528 MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver");