162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT)
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for the MDIO interface of Microsemi network switches.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
662306a36Sopenharmony_ci * Copyright (c) 2017 Microsemi Corporation
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/iopoll.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/mdio/mdio-mscc-miim.h>
1562306a36Sopenharmony_ci#include <linux/mfd/ocelot.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/of_mdio.h>
1862306a36Sopenharmony_ci#include <linux/phy.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/property.h>
2162306a36Sopenharmony_ci#include <linux/regmap.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define MSCC_MIIM_REG_STATUS		0x0
2462306a36Sopenharmony_ci#define		MSCC_MIIM_STATUS_STAT_PENDING	BIT(2)
2562306a36Sopenharmony_ci#define		MSCC_MIIM_STATUS_STAT_BUSY	BIT(3)
2662306a36Sopenharmony_ci#define MSCC_MIIM_REG_CMD		0x8
2762306a36Sopenharmony_ci#define		MSCC_MIIM_CMD_OPR_WRITE		BIT(1)
2862306a36Sopenharmony_ci#define		MSCC_MIIM_CMD_OPR_READ		BIT(2)
2962306a36Sopenharmony_ci#define		MSCC_MIIM_CMD_WRDATA_SHIFT	4
3062306a36Sopenharmony_ci#define		MSCC_MIIM_CMD_REGAD_SHIFT	20
3162306a36Sopenharmony_ci#define		MSCC_MIIM_CMD_PHYAD_SHIFT	25
3262306a36Sopenharmony_ci#define		MSCC_MIIM_CMD_VLD		BIT(31)
3362306a36Sopenharmony_ci#define MSCC_MIIM_REG_DATA		0xC
3462306a36Sopenharmony_ci#define		MSCC_MIIM_DATA_ERROR		(BIT(16) | BIT(17))
3562306a36Sopenharmony_ci#define MSCC_MIIM_REG_CFG		0x10
3662306a36Sopenharmony_ci#define		MSCC_MIIM_CFG_PRESCALE_MASK	GENMASK(7, 0)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define MSCC_PHY_REG_PHY_CFG	0x0
3962306a36Sopenharmony_ci#define		PHY_CFG_PHY_ENA		(BIT(0) | BIT(1) | BIT(2) | BIT(3))
4062306a36Sopenharmony_ci#define		PHY_CFG_PHY_COMMON_RESET BIT(4)
4162306a36Sopenharmony_ci#define		PHY_CFG_PHY_RESET	(BIT(5) | BIT(6) | BIT(7) | BIT(8))
4262306a36Sopenharmony_ci#define MSCC_PHY_REG_PHY_STATUS	0x4
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define LAN966X_CUPHY_COMMON_CFG	0x0
4562306a36Sopenharmony_ci#define		CUPHY_COMMON_CFG_RESET_N	BIT(0)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct mscc_miim_info {
4862306a36Sopenharmony_ci	unsigned int phy_reset_offset;
4962306a36Sopenharmony_ci	unsigned int phy_reset_bits;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct mscc_miim_dev {
5362306a36Sopenharmony_ci	struct regmap *regs;
5462306a36Sopenharmony_ci	int mii_status_offset;
5562306a36Sopenharmony_ci	bool ignore_read_errors;
5662306a36Sopenharmony_ci	struct regmap *phy_regs;
5762306a36Sopenharmony_ci	const struct mscc_miim_info *info;
5862306a36Sopenharmony_ci	struct clk *clk;
5962306a36Sopenharmony_ci	u32 bus_freq;
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* When high resolution timers aren't built-in: we can't use usleep_range() as
6362306a36Sopenharmony_ci * we would sleep way too long. Use udelay() instead.
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci#define mscc_readx_poll_timeout(op, addr, val, cond, delay_us, timeout_us)\
6662306a36Sopenharmony_ci({									  \
6762306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_HIGH_RES_TIMERS))			  \
6862306a36Sopenharmony_ci		readx_poll_timeout_atomic(op, addr, val, cond, delay_us,  \
6962306a36Sopenharmony_ci					  timeout_us);			  \
7062306a36Sopenharmony_ci	readx_poll_timeout(op, addr, val, cond, delay_us, timeout_us);	  \
7162306a36Sopenharmony_ci})
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int mscc_miim_status(struct mii_bus *bus)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct mscc_miim_dev *miim = bus->priv;
7662306a36Sopenharmony_ci	int val, ret;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	ret = regmap_read(miim->regs,
7962306a36Sopenharmony_ci			  MSCC_MIIM_REG_STATUS + miim->mii_status_offset, &val);
8062306a36Sopenharmony_ci	if (ret < 0) {
8162306a36Sopenharmony_ci		WARN_ONCE(1, "mscc miim status read error %d\n", ret);
8262306a36Sopenharmony_ci		return ret;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return val;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int mscc_miim_wait_ready(struct mii_bus *bus)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	u32 val;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return mscc_readx_poll_timeout(mscc_miim_status, bus, val,
9362306a36Sopenharmony_ci				       !(val & MSCC_MIIM_STATUS_STAT_BUSY), 50,
9462306a36Sopenharmony_ci				       10000);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int mscc_miim_wait_pending(struct mii_bus *bus)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	u32 val;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return mscc_readx_poll_timeout(mscc_miim_status, bus, val,
10262306a36Sopenharmony_ci				       !(val & MSCC_MIIM_STATUS_STAT_PENDING),
10362306a36Sopenharmony_ci				       50, 10000);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct mscc_miim_dev *miim = bus->priv;
10962306a36Sopenharmony_ci	u32 val;
11062306a36Sopenharmony_ci	int ret;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	ret = mscc_miim_wait_pending(bus);
11362306a36Sopenharmony_ci	if (ret)
11462306a36Sopenharmony_ci		goto out;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	ret = regmap_write(miim->regs,
11762306a36Sopenharmony_ci			   MSCC_MIIM_REG_CMD + miim->mii_status_offset,
11862306a36Sopenharmony_ci			   MSCC_MIIM_CMD_VLD |
11962306a36Sopenharmony_ci			   (mii_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
12062306a36Sopenharmony_ci			   (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
12162306a36Sopenharmony_ci			   MSCC_MIIM_CMD_OPR_READ);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (ret < 0) {
12462306a36Sopenharmony_ci		WARN_ONCE(1, "mscc miim write cmd reg error %d\n", ret);
12562306a36Sopenharmony_ci		goto out;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	ret = mscc_miim_wait_ready(bus);
12962306a36Sopenharmony_ci	if (ret)
13062306a36Sopenharmony_ci		goto out;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	ret = regmap_read(miim->regs,
13362306a36Sopenharmony_ci			  MSCC_MIIM_REG_DATA + miim->mii_status_offset, &val);
13462306a36Sopenharmony_ci	if (ret < 0) {
13562306a36Sopenharmony_ci		WARN_ONCE(1, "mscc miim read data reg error %d\n", ret);
13662306a36Sopenharmony_ci		goto out;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (!miim->ignore_read_errors && !!(val & MSCC_MIIM_DATA_ERROR)) {
14062306a36Sopenharmony_ci		ret = -EIO;
14162306a36Sopenharmony_ci		goto out;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ret = val & 0xFFFF;
14562306a36Sopenharmony_ciout:
14662306a36Sopenharmony_ci	return ret;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int mscc_miim_write(struct mii_bus *bus, int mii_id,
15062306a36Sopenharmony_ci			   int regnum, u16 value)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct mscc_miim_dev *miim = bus->priv;
15362306a36Sopenharmony_ci	int ret;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ret = mscc_miim_wait_pending(bus);
15662306a36Sopenharmony_ci	if (ret < 0)
15762306a36Sopenharmony_ci		goto out;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	ret = regmap_write(miim->regs,
16062306a36Sopenharmony_ci			   MSCC_MIIM_REG_CMD + miim->mii_status_offset,
16162306a36Sopenharmony_ci			   MSCC_MIIM_CMD_VLD |
16262306a36Sopenharmony_ci			   (mii_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
16362306a36Sopenharmony_ci			   (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
16462306a36Sopenharmony_ci			   (value << MSCC_MIIM_CMD_WRDATA_SHIFT) |
16562306a36Sopenharmony_ci			   MSCC_MIIM_CMD_OPR_WRITE);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (ret < 0)
16862306a36Sopenharmony_ci		WARN_ONCE(1, "mscc miim write error %d\n", ret);
16962306a36Sopenharmony_ciout:
17062306a36Sopenharmony_ci	return ret;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int mscc_miim_reset(struct mii_bus *bus)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct mscc_miim_dev *miim = bus->priv;
17662306a36Sopenharmony_ci	unsigned int offset, bits;
17762306a36Sopenharmony_ci	int ret;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (!miim->phy_regs)
18062306a36Sopenharmony_ci		return 0;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	offset = miim->info->phy_reset_offset;
18362306a36Sopenharmony_ci	bits = miim->info->phy_reset_bits;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	ret = regmap_update_bits(miim->phy_regs, offset, bits, 0);
18662306a36Sopenharmony_ci	if (ret < 0) {
18762306a36Sopenharmony_ci		WARN_ONCE(1, "mscc reset set error %d\n", ret);
18862306a36Sopenharmony_ci		return ret;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	ret = regmap_update_bits(miim->phy_regs, offset, bits, bits);
19262306a36Sopenharmony_ci	if (ret < 0) {
19362306a36Sopenharmony_ci		WARN_ONCE(1, "mscc reset clear error %d\n", ret);
19462306a36Sopenharmony_ci		return ret;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	mdelay(500);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return 0;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic const struct regmap_config mscc_miim_regmap_config = {
20362306a36Sopenharmony_ci	.reg_bits	= 32,
20462306a36Sopenharmony_ci	.val_bits	= 32,
20562306a36Sopenharmony_ci	.reg_stride	= 4,
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic const struct regmap_config mscc_miim_phy_regmap_config = {
20962306a36Sopenharmony_ci	.reg_bits	= 32,
21062306a36Sopenharmony_ci	.val_bits	= 32,
21162306a36Sopenharmony_ci	.reg_stride	= 4,
21262306a36Sopenharmony_ci	.name		= "phy",
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ciint mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name,
21662306a36Sopenharmony_ci		    struct regmap *mii_regmap, int status_offset,
21762306a36Sopenharmony_ci		    bool ignore_read_errors)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct mscc_miim_dev *miim;
22062306a36Sopenharmony_ci	struct mii_bus *bus;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	bus = devm_mdiobus_alloc_size(dev, sizeof(*miim));
22362306a36Sopenharmony_ci	if (!bus)
22462306a36Sopenharmony_ci		return -ENOMEM;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	bus->name = name;
22762306a36Sopenharmony_ci	bus->read = mscc_miim_read;
22862306a36Sopenharmony_ci	bus->write = mscc_miim_write;
22962306a36Sopenharmony_ci	bus->reset = mscc_miim_reset;
23062306a36Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
23162306a36Sopenharmony_ci	bus->parent = dev;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	miim = bus->priv;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	*pbus = bus;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	miim->regs = mii_regmap;
23862306a36Sopenharmony_ci	miim->mii_status_offset = status_offset;
23962306a36Sopenharmony_ci	miim->ignore_read_errors = ignore_read_errors;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	*pbus = bus;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ciEXPORT_SYMBOL(mscc_miim_setup);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int mscc_miim_clk_set(struct mii_bus *bus)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct mscc_miim_dev *miim = bus->priv;
25062306a36Sopenharmony_ci	unsigned long rate;
25162306a36Sopenharmony_ci	u32 div;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Keep the current settings */
25462306a36Sopenharmony_ci	if (!miim->bus_freq)
25562306a36Sopenharmony_ci		return 0;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	rate = clk_get_rate(miim->clk);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	div = DIV_ROUND_UP(rate, 2 * miim->bus_freq) - 1;
26062306a36Sopenharmony_ci	if (div == 0 || div & ~MSCC_MIIM_CFG_PRESCALE_MASK) {
26162306a36Sopenharmony_ci		dev_err(&bus->dev, "Incorrect MDIO clock frequency\n");
26262306a36Sopenharmony_ci		return -EINVAL;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return regmap_update_bits(miim->regs, MSCC_MIIM_REG_CFG,
26662306a36Sopenharmony_ci				  MSCC_MIIM_CFG_PRESCALE_MASK, div);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int mscc_miim_probe(struct platform_device *pdev)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
27262306a36Sopenharmony_ci	struct regmap *mii_regmap, *phy_regmap;
27362306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
27462306a36Sopenharmony_ci	struct mscc_miim_dev *miim;
27562306a36Sopenharmony_ci	struct mii_bus *bus;
27662306a36Sopenharmony_ci	int ret;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	mii_regmap = ocelot_regmap_from_resource(pdev, 0,
27962306a36Sopenharmony_ci						 &mscc_miim_regmap_config);
28062306a36Sopenharmony_ci	if (IS_ERR(mii_regmap))
28162306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(mii_regmap),
28262306a36Sopenharmony_ci				     "Unable to create MIIM regmap\n");
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* This resource is optional */
28562306a36Sopenharmony_ci	phy_regmap = ocelot_regmap_from_resource_optional(pdev, 1,
28662306a36Sopenharmony_ci						 &mscc_miim_phy_regmap_config);
28762306a36Sopenharmony_ci	if (IS_ERR(phy_regmap))
28862306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(phy_regmap),
28962306a36Sopenharmony_ci				     "Unable to create phy register regmap\n");
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	ret = mscc_miim_setup(dev, &bus, "mscc_miim", mii_regmap, 0, false);
29262306a36Sopenharmony_ci	if (ret < 0) {
29362306a36Sopenharmony_ci		dev_err(dev, "Unable to setup the MDIO bus\n");
29462306a36Sopenharmony_ci		return ret;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	miim = bus->priv;
29862306a36Sopenharmony_ci	miim->phy_regs = phy_regmap;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	miim->info = device_get_match_data(dev);
30162306a36Sopenharmony_ci	if (!miim->info)
30262306a36Sopenharmony_ci		return -EINVAL;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	miim->clk = devm_clk_get_optional(dev, NULL);
30562306a36Sopenharmony_ci	if (IS_ERR(miim->clk))
30662306a36Sopenharmony_ci		return PTR_ERR(miim->clk);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	of_property_read_u32(np, "clock-frequency", &miim->bus_freq);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (miim->bus_freq && !miim->clk) {
31162306a36Sopenharmony_ci		dev_err(dev, "cannot use clock-frequency without a clock\n");
31262306a36Sopenharmony_ci		return -EINVAL;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	ret = clk_prepare_enable(miim->clk);
31662306a36Sopenharmony_ci	if (ret)
31762306a36Sopenharmony_ci		return ret;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	ret = mscc_miim_clk_set(bus);
32062306a36Sopenharmony_ci	if (ret)
32162306a36Sopenharmony_ci		goto out_disable_clk;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	ret = of_mdiobus_register(bus, np);
32462306a36Sopenharmony_ci	if (ret < 0) {
32562306a36Sopenharmony_ci		dev_err(dev, "Cannot register MDIO bus (%d)\n", ret);
32662306a36Sopenharmony_ci		goto out_disable_clk;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	platform_set_drvdata(pdev, bus);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	return 0;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciout_disable_clk:
33462306a36Sopenharmony_ci	clk_disable_unprepare(miim->clk);
33562306a36Sopenharmony_ci	return ret;
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic int mscc_miim_remove(struct platform_device *pdev)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct mii_bus *bus = platform_get_drvdata(pdev);
34162306a36Sopenharmony_ci	struct mscc_miim_dev *miim = bus->priv;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	clk_disable_unprepare(miim->clk);
34462306a36Sopenharmony_ci	mdiobus_unregister(bus);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic const struct mscc_miim_info mscc_ocelot_miim_info = {
35062306a36Sopenharmony_ci	.phy_reset_offset = MSCC_PHY_REG_PHY_CFG,
35162306a36Sopenharmony_ci	.phy_reset_bits = PHY_CFG_PHY_ENA | PHY_CFG_PHY_COMMON_RESET |
35262306a36Sopenharmony_ci			  PHY_CFG_PHY_RESET,
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic const struct mscc_miim_info microchip_lan966x_miim_info = {
35662306a36Sopenharmony_ci	.phy_reset_offset = LAN966X_CUPHY_COMMON_CFG,
35762306a36Sopenharmony_ci	.phy_reset_bits = CUPHY_COMMON_CFG_RESET_N,
35862306a36Sopenharmony_ci};
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic const struct of_device_id mscc_miim_match[] = {
36162306a36Sopenharmony_ci	{
36262306a36Sopenharmony_ci		.compatible = "mscc,ocelot-miim",
36362306a36Sopenharmony_ci		.data = &mscc_ocelot_miim_info
36462306a36Sopenharmony_ci	}, {
36562306a36Sopenharmony_ci		.compatible = "microchip,lan966x-miim",
36662306a36Sopenharmony_ci		.data = &microchip_lan966x_miim_info
36762306a36Sopenharmony_ci	},
36862306a36Sopenharmony_ci	{ }
36962306a36Sopenharmony_ci};
37062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mscc_miim_match);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic struct platform_driver mscc_miim_driver = {
37362306a36Sopenharmony_ci	.probe = mscc_miim_probe,
37462306a36Sopenharmony_ci	.remove = mscc_miim_remove,
37562306a36Sopenharmony_ci	.driver = {
37662306a36Sopenharmony_ci		.name = "mscc-miim",
37762306a36Sopenharmony_ci		.of_match_table = mscc_miim_match,
37862306a36Sopenharmony_ci	},
37962306a36Sopenharmony_ci};
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cimodule_platform_driver(mscc_miim_driver);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ciMODULE_DESCRIPTION("Microsemi MIIM driver");
38462306a36Sopenharmony_ciMODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
38562306a36Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL");
386