Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/dsa/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  mt7530-mdio.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/gpio/consumer.h>
#include <linux/mdio.h>
#include <linux/module.h>
#include <linux/pcs/pcs-mtk-lynxi.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/regulator/consumer.h>
#include <net/dsa.h>

#include "mt7530.h"

static int
mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
{
 struct mt7530_priv *priv = context;
 struct mii_bus *bus = priv->bus;
 u16 page, r, lo, hi;
 int ret;

 page = (reg >> 6) & 0x3ff;
 r  = (reg >> 2) & 0xf;
 lo = val & 0xffff;
 hi = val >> 16;

 ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
 if (ret < 0)
  return ret;

 ret = bus->write(bus, priv->mdiodev->addr, r, lo);
 if (ret < 0)
  return ret;

 ret = bus->write(bus, priv->mdiodev->addr, 0x10, hi);
 return ret;
}

static int
mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
{
 struct mt7530_priv *priv = context;
 struct mii_bus *bus = priv->bus;
 u16 page, r, lo, hi;
 int ret;

 page = (reg >> 6) & 0x3ff;
 r = (reg >> 2) & 0xf;

 ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
 if (ret < 0)
  return ret;

 lo = bus->read(bus, priv->mdiodev->addr, r);
 hi = bus->read(bus, priv->mdiodev->addr, 0x10);

 *val = (hi << 16) | (lo & 0xffff);

 return 0;
}

static void
mt7530_mdio_regmap_lock(void *mdio_lock)
{
 mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
}

static void
mt7530_mdio_regmap_unlock(void *mdio_lock)
{
 mutex_unlock(mdio_lock);
}

static const struct regmap_bus mt7530_regmap_bus = {
 .reg_write = mt7530_regmap_write,
 .reg_read = mt7530_regmap_read,
};

static int
mt7531_create_sgmii(struct mt7530_priv *priv)
{
 struct regmap_config *mt7531_pcs_config[2] = {};
 struct phylink_pcs *pcs;
 struct regmap *regmap;
 int i, ret = 0;

 for (i = priv->p5_sgmii ? 0 : 1; i < 2; i++) {
  mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
          sizeof(struct regmap_config),
          GFP_KERNEL);
  if (!mt7531_pcs_config[i]) {
   ret = -ENOMEM;
   break;
  }

  mt7531_pcs_config[i]->name = i ? "port6" : "port5";
  mt7531_pcs_config[i]->reg_bits = 16;
  mt7531_pcs_config[i]->val_bits = 32;
  mt7531_pcs_config[i]->reg_stride = 4;
  mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
  mt7531_pcs_config[i]->max_register = 0x17c;
  mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock;
  mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock;
  mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;

  regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
       mt7531_pcs_config[i]);
  if (IS_ERR(regmap)) {
   ret = PTR_ERR(regmap);
   break;
  }
  pcs = mtk_pcs_lynxi_create(priv->dev, regmap,
        MT7531_PHYA_CTRL_SIGNAL3, 0);
  if (!pcs) {
   ret = -ENXIO;
   break;
  }
  priv->ports[5 + i].sgmii_pcs = pcs;
 }

 if (ret && i)
  mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);

 return ret;
}

static const struct of_device_id mt7530_of_match[] = {
 { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
 { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
 { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
 { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mt7530_of_match);

static const struct regmap_config regmap_config = {
 .reg_bits = 16,
 .val_bits = 32,
 .reg_stride = 4,
 .max_register = MT7530_CREV,
 .disable_locking = true,
};

static int
mt7530_probe(struct mdio_device *mdiodev)
{
 struct mt7530_priv *priv;
 struct device_node *dn;
 int ret;

 dn = mdiodev->dev.of_node;

 priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
 if (!priv)
  return -ENOMEM;

 priv->bus = mdiodev->bus;
 priv->dev = &mdiodev->dev;
 priv->mdiodev = mdiodev;

 ret = mt7530_probe_common(priv);
 if (ret)
  return ret;

 /* Use medatek,mcm property to distinguish hardware type that would
 * cause a little bit differences on power-on sequence.
 * Not MCM that indicates switch works as the remote standalone
 * integrated circuit so the GPIO pin would be used to complete
 * the reset, otherwise memory-mapped register accessing used
 * through syscon provides in the case of MCM.
 */

 priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
 if (priv->mcm) {
  dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");

  priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
  if (IS_ERR(priv->rstc)) {
   dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
   return PTR_ERR(priv->rstc);
  }
 } else {
  priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
            GPIOD_OUT_LOW);
  if (IS_ERR(priv->reset)) {
   dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
   return PTR_ERR(priv->reset);
  }
 }

 if (priv->id == ID_MT7530) {
  priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
  if (IS_ERR(priv->core_pwr))
   return PTR_ERR(priv->core_pwr);

  priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
  if (IS_ERR(priv->io_pwr))
   return PTR_ERR(priv->io_pwr);
 }

 priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
     ®map_config);
 if (IS_ERR(priv->regmap))
  return PTR_ERR(priv->regmap);

 if (priv->id == ID_MT7531)
  priv->create_sgmii = mt7531_create_sgmii;

 return dsa_register_switch(priv->ds);
}

static void
mt7530_remove(struct mdio_device *mdiodev)
{
 struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
 int ret = 0, i;

 if (!priv)
  return;

 ret = regulator_disable(priv->core_pwr);
 if (ret < 0)
  dev_err(priv->dev,
   "Failed to disable core power: %d\n", ret);

 ret = regulator_disable(priv->io_pwr);
 if (ret < 0)
  dev_err(priv->dev, "Failed to disable io pwr: %d\n",
   ret);

 mt7530_remove_common(priv);

 for (i = 0; i < 2; ++i)
  mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
}

static void mt7530_shutdown(struct mdio_device *mdiodev)
{
 struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);

 if (!priv)
  return;

 dsa_switch_shutdown(priv->ds);

 dev_set_drvdata(&mdiodev->dev, NULL);
}

static struct mdio_driver mt7530_mdio_driver = {
 .probe  = mt7530_probe,
 .remove = mt7530_remove,
 .shutdown = mt7530_shutdown,
 .mdiodrv.driver = {
  .name = "mt7530-mdio",
  .of_match_table = mt7530_of_match,
 },
};

mdio_module_driver(mt7530_mdio_driver);

MODULE_AUTHOR("Sean Wang ");
MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MDIO)");
MODULE_LICENSE("GPL");

Messung V0.5
C=93 H=94 G=93

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.