Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 268ef4b7 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dsa-abstract-PHY-access'



Vivien Didelot says:

====================
net: dsa: abstract PHY accesses

The Marvell 88E6xxx switch chips have different way to access the PHY
devices registers.

Old chips use a direct access to the PHY registers. Next chips have a
PHY Polling Unit (PPU) which needs to be disabled before accessing PHY
registers. Newer chips have an indirect access to the PHY devices so
that disabling the PPU is not necessary.

This patchset abstracts these accesses behind a new mv88e6xxx_phy_* API.

It also has the side effect to fix the temperature access code for
88E61xx chips which were using the wrong PHY access functions.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 45d33930 9c93829c
Loading
Loading
Loading
Loading
+294 −247
Original line number Diff line number Diff line
@@ -216,6 +216,118 @@ static int mv88e6xxx_write(struct mv88e6xxx_chip *chip,
	return 0;
}

static int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy,
			      int reg, u16 *val)
{
	int addr = phy; /* PHY devices addresses start at 0x0 */

	if (!chip->phy_ops)
		return -EOPNOTSUPP;

	return chip->phy_ops->read(chip, addr, reg, val);
}

static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy,
			       int reg, u16 val)
{
	int addr = phy; /* PHY devices addresses start at 0x0 */

	if (!chip->phy_ops)
		return -EOPNOTSUPP;

	return chip->phy_ops->write(chip, addr, reg, val);
}

static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
{
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE))
		return -EOPNOTSUPP;

	return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
}

static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
{
	int err;

	/* Restore PHY page Copper 0x0 for access via the registered MDIO bus */
	err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER);
	if (unlikely(err)) {
		dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n",
			phy, err);
	}
}

static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
				   u8 page, int reg, u16 *val)
{
	int err;

	/* There is no paging for registers 22 */
	if (reg == PHY_PAGE)
		return -EINVAL;

	err = mv88e6xxx_phy_page_get(chip, phy, page);
	if (!err) {
		err = mv88e6xxx_phy_read(chip, phy, reg, val);
		mv88e6xxx_phy_page_put(chip, phy);
	}

	return err;
}

static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
				    u8 page, int reg, u16 val)
{
	int err;

	/* There is no paging for registers 22 */
	if (reg == PHY_PAGE)
		return -EINVAL;

	err = mv88e6xxx_phy_page_get(chip, phy, page);
	if (!err) {
		err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
		mv88e6xxx_phy_page_put(chip, phy);
	}

	return err;
}

static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
{
	return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
				       reg, val);
}

static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
{
	return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
					reg, val);
}

static int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg,
			  u16 mask)
{
	unsigned long timeout = jiffies + HZ / 10;

	while (time_before(jiffies, timeout)) {
		u16 val;
		int err;

		err = mv88e6xxx_read(chip, addr, reg, &val);
		if (err)
			return err;

		if (!(val & mask))
			return 0;

		usleep_range(1000, 2000);
	}

	return -ETIMEDOUT;
}

/* Indirect write to single pointer-data register with an Update bit */
static int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg,
			    u16 update)
@@ -260,22 +372,6 @@ static int _mv88e6xxx_reg_write(struct mv88e6xxx_chip *chip, int addr,
	return mv88e6xxx_write(chip, addr, reg, val);
}

static int mv88e6xxx_mdio_read_direct(struct mv88e6xxx_chip *chip,
				      int addr, int regnum)
{
	if (addr >= 0)
		return _mv88e6xxx_reg_read(chip, addr, regnum);
	return 0xffff;
}

static int mv88e6xxx_mdio_write_direct(struct mv88e6xxx_chip *chip,
				       int addr, int regnum, u16 val)
{
	if (addr >= 0)
		return _mv88e6xxx_reg_write(chip, addr, regnum, val);
	return 0;
}

static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
{
	int ret;
@@ -400,34 +496,39 @@ static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip)
	chip->ppu_timer.function = mv88e6xxx_ppu_reenable_timer;
}

static int mv88e6xxx_mdio_read_ppu(struct mv88e6xxx_chip *chip, int addr,
				   int regnum)
static int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, int addr,
				  int reg, u16 *val)
{
	int ret;
	int err;

	ret = mv88e6xxx_ppu_access_get(chip);
	if (ret >= 0) {
		ret = _mv88e6xxx_reg_read(chip, addr, regnum);
	err = mv88e6xxx_ppu_access_get(chip);
	if (!err) {
		err = mv88e6xxx_read(chip, addr, reg, val);
		mv88e6xxx_ppu_access_put(chip);
	}

	return ret;
	return err;
}

static int mv88e6xxx_mdio_write_ppu(struct mv88e6xxx_chip *chip, int addr,
				    int regnum, u16 val)
static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, int addr,
				   int reg, u16 val)
{
	int ret;
	int err;

	ret = mv88e6xxx_ppu_access_get(chip);
	if (ret >= 0) {
		ret = _mv88e6xxx_reg_write(chip, addr, regnum, val);
	err = mv88e6xxx_ppu_access_get(chip);
	if (!err) {
		err = mv88e6xxx_write(chip, addr, reg, val);
		mv88e6xxx_ppu_access_put(chip);
	}

	return ret;
	return err;
}

static const struct mv88e6xxx_ops mv88e6xxx_phy_ppu_ops = {
	.read = mv88e6xxx_phy_ppu_read,
	.write = mv88e6xxx_phy_ppu_write,
};

static bool mv88e6xxx_6065_family(struct mv88e6xxx_chip *chip)
{
	return chip->info->family == MV88E6XXX_FAMILY_6065;
@@ -819,130 +920,69 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
	mutex_unlock(&chip->reg_lock);
}

static int _mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int reg, int offset,
			   u16 mask)
{
	unsigned long timeout = jiffies + HZ / 10;

	while (time_before(jiffies, timeout)) {
		int ret;

		ret = _mv88e6xxx_reg_read(chip, reg, offset);
		if (ret < 0)
			return ret;
		if (!(ret & mask))
			return 0;

		usleep_range(1000, 2000);
	}
	return -ETIMEDOUT;
}

static int mv88e6xxx_mdio_wait(struct mv88e6xxx_chip *chip)
{
	return _mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_SMI_OP,
			       GLOBAL2_SMI_OP_BUSY);
}

static int _mv88e6xxx_atu_wait(struct mv88e6xxx_chip *chip)
{
	return _mv88e6xxx_wait(chip, REG_GLOBAL, GLOBAL_ATU_OP,
	return mv88e6xxx_wait(chip, REG_GLOBAL, GLOBAL_ATU_OP,
			      GLOBAL_ATU_OP_BUSY);
}

static int mv88e6xxx_mdio_read_indirect(struct mv88e6xxx_chip *chip,
					int addr, int regnum)
{
	int ret;

	ret = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_SMI_OP,
				   GLOBAL2_SMI_OP_22_READ | (addr << 5) |
				   regnum);
	if (ret < 0)
		return ret;

	ret = mv88e6xxx_mdio_wait(chip);
	if (ret < 0)
		return ret;

	ret = _mv88e6xxx_reg_read(chip, REG_GLOBAL2, GLOBAL2_SMI_DATA);

	return ret;
}

static int mv88e6xxx_mdio_write_indirect(struct mv88e6xxx_chip *chip,
					 int addr, int regnum, u16 val)
{
	int ret;

	ret = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
	if (ret < 0)
		return ret;

	ret = _mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_SMI_OP,
				   GLOBAL2_SMI_OP_22_WRITE | (addr << 5) |
				   regnum);

	return mv88e6xxx_mdio_wait(chip);
}

static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port,
			     struct ethtool_eee *e)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int reg;
	u16 reg;
	int err;

	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
		return -EOPNOTSUPP;

	mutex_lock(&chip->reg_lock);

	reg = mv88e6xxx_mdio_read_indirect(chip, port, 16);
	if (reg < 0)
	err = mv88e6xxx_phy_read(chip, port, 16, &reg);
	if (err)
		goto out;

	e->eee_enabled = !!(reg & 0x0200);
	e->tx_lpi_enabled = !!(reg & 0x0100);

	reg = _mv88e6xxx_reg_read(chip, REG_PORT(port), PORT_STATUS);
	if (reg < 0)
	err = mv88e6xxx_read(chip, REG_PORT(port), PORT_STATUS, &reg);
	if (err)
		goto out;

	e->eee_active = !!(reg & PORT_STATUS_EEE);
	reg = 0;

out:
	mutex_unlock(&chip->reg_lock);
	return reg;

	return err;
}

static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
			     struct phy_device *phydev, struct ethtool_eee *e)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int reg;
	int ret;
	u16 reg;
	int err;

	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
		return -EOPNOTSUPP;

	mutex_lock(&chip->reg_lock);

	ret = mv88e6xxx_mdio_read_indirect(chip, port, 16);
	if (ret < 0)
	err = mv88e6xxx_phy_read(chip, port, 16, &reg);
	if (err)
		goto out;

	reg = ret & ~0x0300;
	reg &= ~0x0300;
	if (e->eee_enabled)
		reg |= 0x0200;
	if (e->tx_lpi_enabled)
		reg |= 0x0100;

	ret = mv88e6xxx_mdio_write_indirect(chip, port, 16, reg);
	err = mv88e6xxx_phy_write(chip, port, 16, reg);
out:
	mutex_unlock(&chip->reg_lock);

	return ret;
	return err;
}

static int _mv88e6xxx_atu_cmd(struct mv88e6xxx_chip *chip, u16 fid, u16 cmd)
@@ -1227,7 +1267,7 @@ static int _mv88e6xxx_port_pvid_set(struct mv88e6xxx_chip *chip,

static int _mv88e6xxx_vtu_wait(struct mv88e6xxx_chip *chip)
{
	return _mv88e6xxx_wait(chip, REG_GLOBAL, GLOBAL_VTU_OP,
	return mv88e6xxx_wait(chip, REG_GLOBAL, GLOBAL_VTU_OP,
			      GLOBAL_VTU_OP_BUSY);
}

@@ -2302,38 +2342,6 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
	mutex_unlock(&chip->reg_lock);
}

static int _mv88e6xxx_mdio_page_write(struct mv88e6xxx_chip *chip,
				      int port, int page, int reg, int val)
{
	int ret;

	ret = mv88e6xxx_mdio_write_indirect(chip, port, 0x16, page);
	if (ret < 0)
		goto restore_page_0;

	ret = mv88e6xxx_mdio_write_indirect(chip, port, reg, val);
restore_page_0:
	mv88e6xxx_mdio_write_indirect(chip, port, 0x16, 0x0);

	return ret;
}

static int _mv88e6xxx_mdio_page_read(struct mv88e6xxx_chip *chip,
				     int port, int page, int reg)
{
	int ret;

	ret = mv88e6xxx_mdio_write_indirect(chip, port, 0x16, page);
	if (ret < 0)
		goto restore_page_0;

	ret = mv88e6xxx_mdio_read_indirect(chip, port, reg);
restore_page_0:
	mv88e6xxx_mdio_write_indirect(chip, port, 0x16, 0x0);

	return ret;
}

static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
{
	bool ppu_active = mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU_ACTIVE);
@@ -2396,23 +2404,22 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
	return ret;
}

static int mv88e6xxx_power_on_serdes(struct mv88e6xxx_chip *chip)
static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
{
	int ret;
	u16 val;
	int err;

	ret = _mv88e6xxx_mdio_page_read(chip, REG_FIBER_SERDES,
					PAGE_FIBER_SERDES, MII_BMCR);
	if (ret < 0)
		return ret;
	/* Clear Power Down bit */
	err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val);
	if (err)
		return err;

	if (ret & BMCR_PDOWN) {
		ret &= ~BMCR_PDOWN;
		ret = _mv88e6xxx_mdio_page_write(chip, REG_FIBER_SERDES,
						 PAGE_FIBER_SERDES, MII_BMCR,
						 ret);
	if (val & BMCR_PDOWN) {
		val &= ~BMCR_PDOWN;
		err = mv88e6xxx_serdes_write(chip, MII_BMCR, val);
	}

	return ret;
	return err;
}

static int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port,
@@ -2535,7 +2542,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
	/* If this port is connected to a SerDes, make sure the SerDes is not
	 * powered down.
	 */
	if (mv88e6xxx_6352_family(chip)) {
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) {
		ret = _mv88e6xxx_reg_read(chip, REG_PORT(port), PORT_STATUS);
		if (ret < 0)
			return ret;
@@ -2543,7 +2550,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
		if ((ret == PORT_STATUS_CMODE_100BASE_X) ||
		    (ret == PORT_STATUS_CMODE_1000BASE_X) ||
		    (ret == PORT_STATUS_CMODE_SGMII)) {
			ret = mv88e6xxx_power_on_serdes(chip);
			ret = mv88e6xxx_serdes_power_on(chip);
			if (ret < 0)
				return ret;
		}
@@ -2949,7 +2956,7 @@ static int mv88e6xxx_g2_clear_irl(struct mv88e6xxx_chip *chip)
			break;

		/* Wait for the operation to complete */
		err = _mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_IRL_CMD,
		err = mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_IRL_CMD,
				     GLOBAL2_IRL_CMD_BUSY);
		if (err)
			break;
@@ -3004,7 +3011,7 @@ static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip)

static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
{
	return _mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD,
	return mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD,
			      GLOBAL2_EEPROM_CMD_BUSY |
			      GLOBAL2_EEPROM_CMD_RUNNING);
}
@@ -3054,6 +3061,62 @@ static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
	return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
}

static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_CMD,
			      GLOBAL2_SMI_PHY_CMD_BUSY);
}

static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
{
	int err;

	err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_CMD, cmd);
	if (err)
		return err;

	return mv88e6xxx_g2_smi_phy_wait(chip);
}

static int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, int addr,
				     int reg, u16 *val)
{
	u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA | (addr << 5) | reg;
	int err;

	err = mv88e6xxx_g2_smi_phy_wait(chip);
	if (err)
		return err;

	err = mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
	if (err)
		return err;

	return mv88e6xxx_read(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_DATA, val);
}

static int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, int addr,
				      int reg, u16 val)
{
	u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA | (addr << 5) | reg;
	int err;

	err = mv88e6xxx_g2_smi_phy_wait(chip);
	if (err)
		return err;

	err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_DATA, val);
	if (err)
		return err;

	return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
}

static const struct mv88e6xxx_ops mv88e6xxx_g2_smi_phy_ops = {
	.read = mv88e6xxx_g2_smi_phy_read,
	.write = mv88e6xxx_g2_smi_phy_write,
};

static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
{
	u16 reg;
@@ -3187,82 +3250,35 @@ static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr)
	return err;
}

static int mv88e6xxx_mdio_page_read(struct dsa_switch *ds, int port, int page,
				    int reg)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int ret;

	mutex_lock(&chip->reg_lock);
	ret = _mv88e6xxx_mdio_page_read(chip, port, page, reg);
	mutex_unlock(&chip->reg_lock);

	return ret;
}

static int mv88e6xxx_mdio_page_write(struct dsa_switch *ds, int port, int page,
				     int reg, int val)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int ret;

	mutex_lock(&chip->reg_lock);
	ret = _mv88e6xxx_mdio_page_write(chip, port, page, reg, val);
	mutex_unlock(&chip->reg_lock);

	return ret;
}

static int mv88e6xxx_port_to_mdio_addr(struct mv88e6xxx_chip *chip, int port)
{
	if (port >= 0 && port < chip->info->num_ports)
		return port;
	return -EINVAL;
}

static int mv88e6xxx_mdio_read(struct mii_bus *bus, int port, int regnum)
static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
{
	struct mv88e6xxx_chip *chip = bus->priv;
	int addr = mv88e6xxx_port_to_mdio_addr(chip, port);
	int ret;
	u16 val;
	int err;

	if (addr < 0)
	if (phy >= chip->info->num_ports)
		return 0xffff;

	mutex_lock(&chip->reg_lock);

	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU))
		ret = mv88e6xxx_mdio_read_ppu(chip, addr, regnum);
	else if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_SMI_PHY))
		ret = mv88e6xxx_mdio_read_indirect(chip, addr, regnum);
	else
		ret = mv88e6xxx_mdio_read_direct(chip, addr, regnum);

	err = mv88e6xxx_phy_read(chip, phy, reg, &val);
	mutex_unlock(&chip->reg_lock);
	return ret;

	return err ? err : val;
}

static int mv88e6xxx_mdio_write(struct mii_bus *bus, int port, int regnum,
				u16 val)
static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
{
	struct mv88e6xxx_chip *chip = bus->priv;
	int addr = mv88e6xxx_port_to_mdio_addr(chip, port);
	int ret;
	int err;

	if (addr < 0)
	if (phy >= chip->info->num_ports)
		return 0xffff;

	mutex_lock(&chip->reg_lock);

	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU))
		ret = mv88e6xxx_mdio_write_ppu(chip, addr, regnum, val);
	else if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_SMI_PHY))
		ret = mv88e6xxx_mdio_write_indirect(chip, addr, regnum, val);
	else
		ret = mv88e6xxx_mdio_write_direct(chip, addr, regnum, val);

	err = mv88e6xxx_phy_write(chip, phy, reg, val);
	mutex_unlock(&chip->reg_lock);
	return ret;

	return err;
}

static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
@@ -3272,9 +3288,6 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
	struct mii_bus *bus;
	int err;

	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU))
		mv88e6xxx_ppu_state_init(chip);

	if (np)
		chip->mdio_np = of_get_child_by_name(np, "mdio");

@@ -3330,44 +3343,42 @@ static void mv88e6xxx_mdio_unregister(struct mv88e6xxx_chip *chip)
static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	u16 val;
	int ret;
	int val;

	*temp = 0;

	mutex_lock(&chip->reg_lock);

	ret = mv88e6xxx_mdio_write_direct(chip, 0x0, 0x16, 0x6);
	ret = mv88e6xxx_phy_write(chip, 0x0, 0x16, 0x6);
	if (ret < 0)
		goto error;

	/* Enable temperature sensor */
	ret = mv88e6xxx_mdio_read_direct(chip, 0x0, 0x1a);
	ret = mv88e6xxx_phy_read(chip, 0x0, 0x1a, &val);
	if (ret < 0)
		goto error;

	ret = mv88e6xxx_mdio_write_direct(chip, 0x0, 0x1a, ret | (1 << 5));
	ret = mv88e6xxx_phy_write(chip, 0x0, 0x1a, val | (1 << 5));
	if (ret < 0)
		goto error;

	/* Wait for temperature to stabilize */
	usleep_range(10000, 12000);

	val = mv88e6xxx_mdio_read_direct(chip, 0x0, 0x1a);
	if (val < 0) {
		ret = val;
	ret = mv88e6xxx_phy_read(chip, 0x0, 0x1a, &val);
	if (ret < 0)
		goto error;
	}

	/* Disable temperature sensor */
	ret = mv88e6xxx_mdio_write_direct(chip, 0x0, 0x1a, ret & ~(1 << 5));
	ret = mv88e6xxx_phy_write(chip, 0x0, 0x1a, val & ~(1 << 5));
	if (ret < 0)
		goto error;

	*temp = ((val & 0x1f) - 5) * 5;

error:
	mv88e6xxx_mdio_write_direct(chip, 0x0, 0x16, 0x0);
	mv88e6xxx_phy_write(chip, 0x0, 0x16, 0x0);
	mutex_unlock(&chip->reg_lock);
	return ret;
}
@@ -3376,15 +3387,18 @@ static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int phy = mv88e6xxx_6320_family(chip) ? 3 : 0;
	u16 val;
	int ret;

	*temp = 0;

	ret = mv88e6xxx_mdio_page_read(ds, phy, 6, 27);
	mutex_lock(&chip->reg_lock);
	ret = mv88e6xxx_phy_page_read(chip, phy, 6, 27, &val);
	mutex_unlock(&chip->reg_lock);
	if (ret < 0)
		return ret;

	*temp = (ret & 0xff) - 25;
	*temp = (val & 0xff) - 25;

	return 0;
}
@@ -3406,6 +3420,7 @@ static int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int phy = mv88e6xxx_6320_family(chip) ? 3 : 0;
	u16 val;
	int ret;

	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_TEMP_LIMIT))
@@ -3413,11 +3428,13 @@ static int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp)

	*temp = 0;

	ret = mv88e6xxx_mdio_page_read(ds, phy, 6, 26);
	mutex_lock(&chip->reg_lock);
	ret = mv88e6xxx_phy_page_read(chip, phy, 6, 26, &val);
	mutex_unlock(&chip->reg_lock);
	if (ret < 0)
		return ret;

	*temp = (((ret >> 8) & 0x1f) * 5) - 25;
	*temp = (((val >> 8) & 0x1f) * 5) - 25;

	return 0;
}
@@ -3426,23 +3443,30 @@ static int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int phy = mv88e6xxx_6320_family(chip) ? 3 : 0;
	int ret;
	u16 val;
	int err;

	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_TEMP_LIMIT))
		return -EOPNOTSUPP;

	ret = mv88e6xxx_mdio_page_read(ds, phy, 6, 26);
	if (ret < 0)
		return ret;
	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_phy_page_read(chip, phy, 6, 26, &val);
	if (err)
		goto unlock;
	temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
	return mv88e6xxx_mdio_page_write(ds, phy, 6, 26,
					 (ret & 0xe0ff) | (temp << 8));
	err = mv88e6xxx_phy_page_write(chip, phy, 6, 26,
				       (val & 0xe0ff) | (temp << 8));
unlock:
	mutex_unlock(&chip->reg_lock);

	return err;
}

static int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm)
{
	struct mv88e6xxx_chip *chip = ds_to_priv(ds);
	int phy = mv88e6xxx_6320_family(chip) ? 3 : 0;
	u16 val;
	int ret;

	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_TEMP_LIMIT))
@@ -3450,11 +3474,13 @@ static int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm)

	*alarm = false;

	ret = mv88e6xxx_mdio_page_read(ds, phy, 6, 26);
	mutex_lock(&chip->reg_lock);
	ret = mv88e6xxx_phy_page_read(chip, phy, 6, 26, &val);
	mutex_unlock(&chip->reg_lock);
	if (ret < 0)
		return ret;

	*alarm = !!(ret & 0x40);
	*alarm = !!(val & 0x40);

	return 0;
}
@@ -3871,6 +3897,23 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
	return chip;
}

static const struct mv88e6xxx_ops mv88e6xxx_phy_ops = {
	.read = mv88e6xxx_read,
	.write = mv88e6xxx_write,
};

static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
{
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SMI_PHY)) {
		chip->phy_ops = &mv88e6xxx_g2_smi_phy_ops;
	} else if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_PPU)) {
		chip->phy_ops = &mv88e6xxx_phy_ppu_ops;
		mv88e6xxx_ppu_state_init(chip);
	} else {
		chip->phy_ops = &mv88e6xxx_phy_ops;
	}
}

static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
			      struct mii_bus *bus, int sw_addr)
{
@@ -3880,7 +3923,7 @@ static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,

	if (sw_addr == 0)
		chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
	else if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_MULTI_CHIP))
	else if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_MULTI_CHIP))
		chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
	else
		return -EINVAL;
@@ -3918,6 +3961,8 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
	if (err)
		goto free;

	mv88e6xxx_phy_init(chip);

	err = mv88e6xxx_mdio_register(chip, NULL);
	if (err)
		goto free;
@@ -4019,6 +4064,8 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
	if (err)
		return err;

	mv88e6xxx_phy_init(chip);

	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
	if (IS_ERR(chip->reset))
		return PTR_ERR(chip->reset);
+75 −42

File changed.

Preview size limit exceeded, changes collapsed.