Skip to content

Commit d4bd3ac

Browse files
minimaxwellkuba-moo
authored andcommitted
net: mdio: mdio-i2c: Add support for single-byte SMBus operations
PHYs that are within copper SFP modules have their MDIO bus accessible through address 0x56 (usually) on the i2c bus. The MDIO-I2C bridge is desgned for 16 bits accesses, but we can also perform 8bits accesses by reading/writing the high and low bytes sequentially. This commit adds support for this type of accesses, thus supporting smbus controllers such as the one in the VSC8552. This was only tested on Copper SFP modules that embed a Marvell 88e1111 PHY. Tested-by: Sean Anderson <[email protected]> Signed-off-by: Maxime Chevallier <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 7662abf commit d4bd3ac

File tree

1 file changed

+78
-1
lines changed

1 file changed

+78
-1
lines changed

drivers/net/mdio/mdio-i2c.c

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,62 @@ static int i2c_mii_write_default_c22(struct mii_bus *bus, int phy_id, int reg,
106106
return i2c_mii_write_default_c45(bus, phy_id, -1, reg, val);
107107
}
108108

109+
static int smbus_byte_mii_read_default_c22(struct mii_bus *bus, int phy_id,
110+
int reg)
111+
{
112+
struct i2c_adapter *i2c = bus->priv;
113+
union i2c_smbus_data smbus_data;
114+
int val = 0, ret;
115+
116+
if (!i2c_mii_valid_phy_id(phy_id))
117+
return 0;
118+
119+
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
120+
I2C_SMBUS_READ, reg,
121+
I2C_SMBUS_BYTE_DATA, &smbus_data);
122+
if (ret < 0)
123+
return ret;
124+
125+
val = (smbus_data.byte & 0xff) << 8;
126+
127+
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
128+
I2C_SMBUS_READ, reg,
129+
I2C_SMBUS_BYTE_DATA, &smbus_data);
130+
if (ret < 0)
131+
return ret;
132+
133+
val |= smbus_data.byte & 0xff;
134+
135+
return val;
136+
}
137+
138+
static int smbus_byte_mii_write_default_c22(struct mii_bus *bus, int phy_id,
139+
int reg, u16 val)
140+
{
141+
struct i2c_adapter *i2c = bus->priv;
142+
union i2c_smbus_data smbus_data;
143+
int ret;
144+
145+
if (!i2c_mii_valid_phy_id(phy_id))
146+
return 0;
147+
148+
smbus_data.byte = (val & 0xff00) >> 8;
149+
150+
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
151+
I2C_SMBUS_WRITE, reg,
152+
I2C_SMBUS_BYTE_DATA, &smbus_data);
153+
if (ret < 0)
154+
return ret;
155+
156+
smbus_data.byte = val & 0xff;
157+
158+
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
159+
I2C_SMBUS_WRITE, reg,
160+
I2C_SMBUS_BYTE_DATA, &smbus_data);
161+
162+
return ret < 0 ? ret : 0;
163+
}
164+
109165
/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
110166
* instead via address 0x51, when SFP page is set to 0x03 and password to
111167
* 0xffffffff.
@@ -378,13 +434,26 @@ static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
378434
return 0;
379435
}
380436

437+
static bool mdio_i2c_check_functionality(struct i2c_adapter *i2c,
438+
enum mdio_i2c_proto protocol)
439+
{
440+
if (i2c_check_functionality(i2c, I2C_FUNC_I2C))
441+
return true;
442+
443+
if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA) &&
444+
protocol == MDIO_I2C_MARVELL_C22)
445+
return true;
446+
447+
return false;
448+
}
449+
381450
struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
382451
enum mdio_i2c_proto protocol)
383452
{
384453
struct mii_bus *mii;
385454
int ret;
386455

387-
if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
456+
if (!mdio_i2c_check_functionality(i2c, protocol))
388457
return ERR_PTR(-EINVAL);
389458

390459
mii = mdiobus_alloc();
@@ -395,6 +464,14 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
395464
mii->parent = parent;
396465
mii->priv = i2c;
397466

467+
/* Only use SMBus if we have no other choice */
468+
if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA) &&
469+
!i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
470+
mii->read = smbus_byte_mii_read_default_c22;
471+
mii->write = smbus_byte_mii_write_default_c22;
472+
return mii;
473+
}
474+
398475
switch (protocol) {
399476
case MDIO_I2C_ROLLBALL:
400477
ret = i2c_mii_init_rollball(i2c);

0 commit comments

Comments
 (0)