1a9770eacSAndrew Lunn // SPDX-License-Identifier: GPL-2.0
2a9770eacSAndrew Lunn /*
3a9770eacSAndrew Lunn * MDIO I2C bridge
4a9770eacSAndrew Lunn *
5a9770eacSAndrew Lunn * Copyright (C) 2015-2016 Russell King
609bbedacSMarek Behún * Copyright (C) 2021 Marek Behun
7a9770eacSAndrew Lunn *
8a9770eacSAndrew Lunn * Network PHYs can appear on I2C buses when they are part of SFP module.
9a9770eacSAndrew Lunn * This driver exposes these PHYs to the networking PHY code, allowing
10a9770eacSAndrew Lunn * our PHY drivers access to these PHYs, and so allowing configuration
11a9770eacSAndrew Lunn * of their settings.
12a9770eacSAndrew Lunn */
13a9770eacSAndrew Lunn #include <linux/i2c.h>
14a9770eacSAndrew Lunn #include <linux/mdio/mdio-i2c.h>
15a9770eacSAndrew Lunn #include <linux/phy.h>
1609bbedacSMarek Behún #include <linux/sfp.h>
17a9770eacSAndrew Lunn
18a9770eacSAndrew Lunn /*
19a9770eacSAndrew Lunn * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
20a9770eacSAndrew Lunn * specified to be present in SFP modules. These correspond with PHY
21a9770eacSAndrew Lunn * addresses 16 and 17. Disallow access to these "phy" addresses.
22a9770eacSAndrew Lunn */
i2c_mii_valid_phy_id(int phy_id)23a9770eacSAndrew Lunn static bool i2c_mii_valid_phy_id(int phy_id)
24a9770eacSAndrew Lunn {
25a9770eacSAndrew Lunn return phy_id != 0x10 && phy_id != 0x11;
26a9770eacSAndrew Lunn }
27a9770eacSAndrew Lunn
i2c_mii_phy_addr(int phy_id)28a9770eacSAndrew Lunn static unsigned int i2c_mii_phy_addr(int phy_id)
29a9770eacSAndrew Lunn {
30a9770eacSAndrew Lunn return phy_id + 0x40;
31a9770eacSAndrew Lunn }
32a9770eacSAndrew Lunn
i2c_mii_read_default_c45(struct mii_bus * bus,int phy_id,int devad,int reg)3387e3bee0SAndrew Lunn static int i2c_mii_read_default_c45(struct mii_bus *bus, int phy_id, int devad,
3487e3bee0SAndrew Lunn int reg)
35a9770eacSAndrew Lunn {
36a9770eacSAndrew Lunn struct i2c_adapter *i2c = bus->priv;
37a9770eacSAndrew Lunn struct i2c_msg msgs[2];
38a9770eacSAndrew Lunn u8 addr[3], data[2], *p;
39a9770eacSAndrew Lunn int bus_addr, ret;
40a9770eacSAndrew Lunn
41a9770eacSAndrew Lunn if (!i2c_mii_valid_phy_id(phy_id))
42a9770eacSAndrew Lunn return 0xffff;
43a9770eacSAndrew Lunn
44a9770eacSAndrew Lunn p = addr;
4587e3bee0SAndrew Lunn if (devad >= 0) {
4687e3bee0SAndrew Lunn *p++ = 0x20 | devad;
47a9770eacSAndrew Lunn *p++ = reg >> 8;
48a9770eacSAndrew Lunn }
49a9770eacSAndrew Lunn *p++ = reg;
50a9770eacSAndrew Lunn
51a9770eacSAndrew Lunn bus_addr = i2c_mii_phy_addr(phy_id);
52a9770eacSAndrew Lunn msgs[0].addr = bus_addr;
53a9770eacSAndrew Lunn msgs[0].flags = 0;
54a9770eacSAndrew Lunn msgs[0].len = p - addr;
55a9770eacSAndrew Lunn msgs[0].buf = addr;
56a9770eacSAndrew Lunn msgs[1].addr = bus_addr;
57a9770eacSAndrew Lunn msgs[1].flags = I2C_M_RD;
58a9770eacSAndrew Lunn msgs[1].len = sizeof(data);
59a9770eacSAndrew Lunn msgs[1].buf = data;
60a9770eacSAndrew Lunn
61a9770eacSAndrew Lunn ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
62a9770eacSAndrew Lunn if (ret != ARRAY_SIZE(msgs))
63a9770eacSAndrew Lunn return 0xffff;
64a9770eacSAndrew Lunn
65a9770eacSAndrew Lunn return data[0] << 8 | data[1];
66a9770eacSAndrew Lunn }
67a9770eacSAndrew Lunn
i2c_mii_write_default_c45(struct mii_bus * bus,int phy_id,int devad,int reg,u16 val)6887e3bee0SAndrew Lunn static int i2c_mii_write_default_c45(struct mii_bus *bus, int phy_id,
6987e3bee0SAndrew Lunn int devad, int reg, u16 val)
70a9770eacSAndrew Lunn {
71a9770eacSAndrew Lunn struct i2c_adapter *i2c = bus->priv;
72a9770eacSAndrew Lunn struct i2c_msg msg;
73a9770eacSAndrew Lunn int ret;
74a9770eacSAndrew Lunn u8 data[5], *p;
75a9770eacSAndrew Lunn
76a9770eacSAndrew Lunn if (!i2c_mii_valid_phy_id(phy_id))
77a9770eacSAndrew Lunn return 0;
78a9770eacSAndrew Lunn
79a9770eacSAndrew Lunn p = data;
8087e3bee0SAndrew Lunn if (devad >= 0) {
8187e3bee0SAndrew Lunn *p++ = devad;
82a9770eacSAndrew Lunn *p++ = reg >> 8;
83a9770eacSAndrew Lunn }
84a9770eacSAndrew Lunn *p++ = reg;
85a9770eacSAndrew Lunn *p++ = val >> 8;
86a9770eacSAndrew Lunn *p++ = val;
87a9770eacSAndrew Lunn
88a9770eacSAndrew Lunn msg.addr = i2c_mii_phy_addr(phy_id);
89a9770eacSAndrew Lunn msg.flags = 0;
90a9770eacSAndrew Lunn msg.len = p - data;
91a9770eacSAndrew Lunn msg.buf = data;
92a9770eacSAndrew Lunn
93a9770eacSAndrew Lunn ret = i2c_transfer(i2c, &msg, 1);
94a9770eacSAndrew Lunn
95a9770eacSAndrew Lunn return ret < 0 ? ret : 0;
96a9770eacSAndrew Lunn }
97a9770eacSAndrew Lunn
i2c_mii_read_default_c22(struct mii_bus * bus,int phy_id,int reg)9887e3bee0SAndrew Lunn static int i2c_mii_read_default_c22(struct mii_bus *bus, int phy_id, int reg)
9987e3bee0SAndrew Lunn {
10087e3bee0SAndrew Lunn return i2c_mii_read_default_c45(bus, phy_id, -1, reg);
10187e3bee0SAndrew Lunn }
10287e3bee0SAndrew Lunn
i2c_mii_write_default_c22(struct mii_bus * bus,int phy_id,int reg,u16 val)10387e3bee0SAndrew Lunn static int i2c_mii_write_default_c22(struct mii_bus *bus, int phy_id, int reg,
10487e3bee0SAndrew Lunn u16 val)
10587e3bee0SAndrew Lunn {
10687e3bee0SAndrew Lunn return i2c_mii_write_default_c45(bus, phy_id, -1, reg, val);
10787e3bee0SAndrew Lunn }
10887e3bee0SAndrew Lunn
10909bbedacSMarek Behún /* RollBall SFPs do not access internal PHY via I2C address 0x56, but
11009bbedacSMarek Behún * instead via address 0x51, when SFP page is set to 0x03 and password to
11109bbedacSMarek Behún * 0xffffffff.
11209bbedacSMarek Behún *
11309bbedacSMarek Behún * address size contents description
11409bbedacSMarek Behún * ------- ---- -------- -----------
11509bbedacSMarek Behún * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done
11609bbedacSMarek Behún * 0x81 1 DEV Clause 45 device
11709bbedacSMarek Behún * 0x82 2 REG Clause 45 register
11809bbedacSMarek Behún * 0x84 2 VAL Register value
11909bbedacSMarek Behún */
12009bbedacSMarek Behún #define ROLLBALL_PHY_I2C_ADDR 0x51
12109bbedacSMarek Behún
12209bbedacSMarek Behún #define ROLLBALL_PASSWORD (SFP_VSL + 3)
12309bbedacSMarek Behún
12409bbedacSMarek Behún #define ROLLBALL_CMD_ADDR 0x80
12509bbedacSMarek Behún #define ROLLBALL_DATA_ADDR 0x81
12609bbedacSMarek Behún
12709bbedacSMarek Behún #define ROLLBALL_CMD_WRITE 0x01
12809bbedacSMarek Behún #define ROLLBALL_CMD_READ 0x02
12909bbedacSMarek Behún #define ROLLBALL_CMD_DONE 0x04
13009bbedacSMarek Behún
13109bbedacSMarek Behún #define SFP_PAGE_ROLLBALL_MDIO 3
13209bbedacSMarek Behún
__i2c_transfer_err(struct i2c_adapter * i2c,struct i2c_msg * msgs,int num)13309bbedacSMarek Behún static int __i2c_transfer_err(struct i2c_adapter *i2c, struct i2c_msg *msgs,
13409bbedacSMarek Behún int num)
13509bbedacSMarek Behún {
13609bbedacSMarek Behún int ret;
13709bbedacSMarek Behún
13809bbedacSMarek Behún ret = __i2c_transfer(i2c, msgs, num);
13909bbedacSMarek Behún if (ret < 0)
14009bbedacSMarek Behún return ret;
14109bbedacSMarek Behún else if (ret != num)
14209bbedacSMarek Behún return -EIO;
14309bbedacSMarek Behún else
14409bbedacSMarek Behún return 0;
14509bbedacSMarek Behún }
14609bbedacSMarek Behún
__i2c_rollball_get_page(struct i2c_adapter * i2c,int bus_addr,u8 * page)14709bbedacSMarek Behún static int __i2c_rollball_get_page(struct i2c_adapter *i2c, int bus_addr,
14809bbedacSMarek Behún u8 *page)
14909bbedacSMarek Behún {
15009bbedacSMarek Behún struct i2c_msg msgs[2];
15109bbedacSMarek Behún u8 addr = SFP_PAGE;
15209bbedacSMarek Behún
15309bbedacSMarek Behún msgs[0].addr = bus_addr;
15409bbedacSMarek Behún msgs[0].flags = 0;
15509bbedacSMarek Behún msgs[0].len = 1;
15609bbedacSMarek Behún msgs[0].buf = &addr;
15709bbedacSMarek Behún
15809bbedacSMarek Behún msgs[1].addr = bus_addr;
15909bbedacSMarek Behún msgs[1].flags = I2C_M_RD;
16009bbedacSMarek Behún msgs[1].len = 1;
16109bbedacSMarek Behún msgs[1].buf = page;
16209bbedacSMarek Behún
16309bbedacSMarek Behún return __i2c_transfer_err(i2c, msgs, 2);
16409bbedacSMarek Behún }
16509bbedacSMarek Behún
__i2c_rollball_set_page(struct i2c_adapter * i2c,int bus_addr,u8 page)16609bbedacSMarek Behún static int __i2c_rollball_set_page(struct i2c_adapter *i2c, int bus_addr,
16709bbedacSMarek Behún u8 page)
16809bbedacSMarek Behún {
16909bbedacSMarek Behún struct i2c_msg msg;
17009bbedacSMarek Behún u8 buf[2];
17109bbedacSMarek Behún
17209bbedacSMarek Behún buf[0] = SFP_PAGE;
17309bbedacSMarek Behún buf[1] = page;
17409bbedacSMarek Behún
17509bbedacSMarek Behún msg.addr = bus_addr;
17609bbedacSMarek Behún msg.flags = 0;
17709bbedacSMarek Behún msg.len = 2;
17809bbedacSMarek Behún msg.buf = buf;
17909bbedacSMarek Behún
18009bbedacSMarek Behún return __i2c_transfer_err(i2c, &msg, 1);
18109bbedacSMarek Behún }
18209bbedacSMarek Behún
18309bbedacSMarek Behún /* In order to not interfere with other SFP code (which possibly may manipulate
18409bbedacSMarek Behún * SFP_PAGE), for every transfer we do this:
18509bbedacSMarek Behún * 1. lock the bus
18609bbedacSMarek Behún * 2. save content of SFP_PAGE
18709bbedacSMarek Behún * 3. set SFP_PAGE to 3
18809bbedacSMarek Behún * 4. do the transfer
18909bbedacSMarek Behún * 5. restore original SFP_PAGE
19009bbedacSMarek Behún * 6. unlock the bus
19109bbedacSMarek Behún * Note that one might think that steps 2 to 5 could be theoretically done all
19209bbedacSMarek Behún * in one call to i2c_transfer (by constructing msgs array in such a way), but
19309bbedacSMarek Behún * unfortunately tests show that this does not work :-( Changed SFP_PAGE does
19409bbedacSMarek Behún * not take into account until i2c_transfer() is done.
19509bbedacSMarek Behún */
i2c_transfer_rollball(struct i2c_adapter * i2c,struct i2c_msg * msgs,int num)19609bbedacSMarek Behún static int i2c_transfer_rollball(struct i2c_adapter *i2c,
19709bbedacSMarek Behún struct i2c_msg *msgs, int num)
19809bbedacSMarek Behún {
19909bbedacSMarek Behún int ret, main_err = 0;
20009bbedacSMarek Behún u8 saved_page;
20109bbedacSMarek Behún
20209bbedacSMarek Behún i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
20309bbedacSMarek Behún
20409bbedacSMarek Behún /* save original page */
20509bbedacSMarek Behún ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
20609bbedacSMarek Behún if (ret)
20709bbedacSMarek Behún goto unlock;
20809bbedacSMarek Behún
20909bbedacSMarek Behún /* change to RollBall MDIO page */
21009bbedacSMarek Behún ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
21109bbedacSMarek Behún if (ret)
21209bbedacSMarek Behún goto unlock;
21309bbedacSMarek Behún
21409bbedacSMarek Behún /* do the transfer; we try to restore original page if this fails */
21509bbedacSMarek Behún ret = __i2c_transfer_err(i2c, msgs, num);
21609bbedacSMarek Behún if (ret)
21709bbedacSMarek Behún main_err = ret;
21809bbedacSMarek Behún
21909bbedacSMarek Behún /* restore original page */
22009bbedacSMarek Behún ret = __i2c_rollball_set_page(i2c, msgs->addr, saved_page);
22109bbedacSMarek Behún
22209bbedacSMarek Behún unlock:
22309bbedacSMarek Behún i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
22409bbedacSMarek Behún
22509bbedacSMarek Behún return main_err ? : ret;
22609bbedacSMarek Behún }
22709bbedacSMarek Behún
i2c_rollball_mii_poll(struct mii_bus * bus,int bus_addr,u8 * buf,size_t len)22809bbedacSMarek Behún static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf,
22909bbedacSMarek Behún size_t len)
23009bbedacSMarek Behún {
23109bbedacSMarek Behún struct i2c_adapter *i2c = bus->priv;
23209bbedacSMarek Behún struct i2c_msg msgs[2];
23309bbedacSMarek Behún u8 cmd_addr, tmp, *res;
23409bbedacSMarek Behún int i, ret;
23509bbedacSMarek Behún
23609bbedacSMarek Behún cmd_addr = ROLLBALL_CMD_ADDR;
23709bbedacSMarek Behún
23809bbedacSMarek Behún res = buf ? buf : &tmp;
23909bbedacSMarek Behún len = buf ? len : 1;
24009bbedacSMarek Behún
24109bbedacSMarek Behún msgs[0].addr = bus_addr;
24209bbedacSMarek Behún msgs[0].flags = 0;
24309bbedacSMarek Behún msgs[0].len = 1;
24409bbedacSMarek Behún msgs[0].buf = &cmd_addr;
24509bbedacSMarek Behún
24609bbedacSMarek Behún msgs[1].addr = bus_addr;
24709bbedacSMarek Behún msgs[1].flags = I2C_M_RD;
24809bbedacSMarek Behún msgs[1].len = len;
24909bbedacSMarek Behún msgs[1].buf = res;
25009bbedacSMarek Behún
25109bbedacSMarek Behún /* By experiment it takes up to 70 ms to access a register for these
25209bbedacSMarek Behún * SFPs. Sleep 20ms between iterations and try 10 times.
25309bbedacSMarek Behún */
25409bbedacSMarek Behún i = 10;
25509bbedacSMarek Behún do {
25609bbedacSMarek Behún msleep(20);
25709bbedacSMarek Behún
25809bbedacSMarek Behún ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
25909bbedacSMarek Behún if (ret)
26009bbedacSMarek Behún return ret;
26109bbedacSMarek Behún
26209bbedacSMarek Behún if (*res == ROLLBALL_CMD_DONE)
26309bbedacSMarek Behún return 0;
26409bbedacSMarek Behún } while (i-- > 0);
26509bbedacSMarek Behún
26609bbedacSMarek Behún dev_dbg(&bus->dev, "poll timed out\n");
26709bbedacSMarek Behún
26809bbedacSMarek Behún return -ETIMEDOUT;
26909bbedacSMarek Behún }
27009bbedacSMarek Behún
i2c_rollball_mii_cmd(struct mii_bus * bus,int bus_addr,u8 cmd,u8 * data,size_t len)27109bbedacSMarek Behún static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd,
27209bbedacSMarek Behún u8 *data, size_t len)
27309bbedacSMarek Behún {
27409bbedacSMarek Behún struct i2c_adapter *i2c = bus->priv;
27509bbedacSMarek Behún struct i2c_msg msgs[2];
27609bbedacSMarek Behún u8 cmdbuf[2];
27709bbedacSMarek Behún
27809bbedacSMarek Behún cmdbuf[0] = ROLLBALL_CMD_ADDR;
27909bbedacSMarek Behún cmdbuf[1] = cmd;
28009bbedacSMarek Behún
28109bbedacSMarek Behún msgs[0].addr = bus_addr;
28209bbedacSMarek Behún msgs[0].flags = 0;
28309bbedacSMarek Behún msgs[0].len = len;
28409bbedacSMarek Behún msgs[0].buf = data;
28509bbedacSMarek Behún
28609bbedacSMarek Behún msgs[1].addr = bus_addr;
28709bbedacSMarek Behún msgs[1].flags = 0;
28809bbedacSMarek Behún msgs[1].len = sizeof(cmdbuf);
28909bbedacSMarek Behún msgs[1].buf = cmdbuf;
29009bbedacSMarek Behún
29109bbedacSMarek Behún return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
29209bbedacSMarek Behún }
29309bbedacSMarek Behún
i2c_mii_read_rollball(struct mii_bus * bus,int phy_id,int devad,int reg)294*b48a1864SRussell King (Oracle) static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int devad,
295*b48a1864SRussell King (Oracle) int reg)
29609bbedacSMarek Behún {
29709bbedacSMarek Behún u8 buf[4], res[6];
29809bbedacSMarek Behún int bus_addr, ret;
29909bbedacSMarek Behún u16 val;
30009bbedacSMarek Behún
30109bbedacSMarek Behún bus_addr = i2c_mii_phy_addr(phy_id);
30209bbedacSMarek Behún if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
30309bbedacSMarek Behún return 0xffff;
30409bbedacSMarek Behún
30509bbedacSMarek Behún buf[0] = ROLLBALL_DATA_ADDR;
306*b48a1864SRussell King (Oracle) buf[1] = devad;
30709bbedacSMarek Behún buf[2] = (reg >> 8) & 0xff;
30809bbedacSMarek Behún buf[3] = reg & 0xff;
30909bbedacSMarek Behún
31009bbedacSMarek Behún ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_READ, buf,
31109bbedacSMarek Behún sizeof(buf));
31209bbedacSMarek Behún if (ret < 0)
31309bbedacSMarek Behún return ret;
31409bbedacSMarek Behún
31509bbedacSMarek Behún ret = i2c_rollball_mii_poll(bus, bus_addr, res, sizeof(res));
31609bbedacSMarek Behún if (ret == -ETIMEDOUT)
31709bbedacSMarek Behún return 0xffff;
31809bbedacSMarek Behún else if (ret < 0)
31909bbedacSMarek Behún return ret;
32009bbedacSMarek Behún
32109bbedacSMarek Behún val = res[4] << 8 | res[5];
32209bbedacSMarek Behún
32309bbedacSMarek Behún return val;
32409bbedacSMarek Behún }
32509bbedacSMarek Behún
i2c_mii_write_rollball(struct mii_bus * bus,int phy_id,int devad,int reg,u16 val)326*b48a1864SRussell King (Oracle) static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad,
327*b48a1864SRussell King (Oracle) int reg, u16 val)
32809bbedacSMarek Behún {
32909bbedacSMarek Behún int bus_addr, ret;
33009bbedacSMarek Behún u8 buf[6];
33109bbedacSMarek Behún
33209bbedacSMarek Behún bus_addr = i2c_mii_phy_addr(phy_id);
33309bbedacSMarek Behún if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
33409bbedacSMarek Behún return 0;
33509bbedacSMarek Behún
33609bbedacSMarek Behún buf[0] = ROLLBALL_DATA_ADDR;
337*b48a1864SRussell King (Oracle) buf[1] = devad;
33809bbedacSMarek Behún buf[2] = (reg >> 8) & 0xff;
33909bbedacSMarek Behún buf[3] = reg & 0xff;
34009bbedacSMarek Behún buf[4] = val >> 8;
34109bbedacSMarek Behún buf[5] = val & 0xff;
34209bbedacSMarek Behún
34309bbedacSMarek Behún ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_WRITE, buf,
34409bbedacSMarek Behún sizeof(buf));
34509bbedacSMarek Behún if (ret < 0)
34609bbedacSMarek Behún return ret;
34709bbedacSMarek Behún
34809bbedacSMarek Behún ret = i2c_rollball_mii_poll(bus, bus_addr, NULL, 0);
34909bbedacSMarek Behún if (ret < 0)
35009bbedacSMarek Behún return ret;
35109bbedacSMarek Behún
35209bbedacSMarek Behún return 0;
35309bbedacSMarek Behún }
35409bbedacSMarek Behún
i2c_mii_init_rollball(struct i2c_adapter * i2c)35509bbedacSMarek Behún static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
35609bbedacSMarek Behún {
35709bbedacSMarek Behún struct i2c_msg msg;
35809bbedacSMarek Behún u8 pw[5];
35909bbedacSMarek Behún int ret;
36009bbedacSMarek Behún
36109bbedacSMarek Behún pw[0] = ROLLBALL_PASSWORD;
36209bbedacSMarek Behún pw[1] = 0xff;
36309bbedacSMarek Behún pw[2] = 0xff;
36409bbedacSMarek Behún pw[3] = 0xff;
36509bbedacSMarek Behún pw[4] = 0xff;
36609bbedacSMarek Behún
36709bbedacSMarek Behún msg.addr = ROLLBALL_PHY_I2C_ADDR;
36809bbedacSMarek Behún msg.flags = 0;
36909bbedacSMarek Behún msg.len = sizeof(pw);
37009bbedacSMarek Behún msg.buf = pw;
37109bbedacSMarek Behún
37209bbedacSMarek Behún ret = i2c_transfer(i2c, &msg, 1);
37309bbedacSMarek Behún if (ret < 0)
37409bbedacSMarek Behún return ret;
37509bbedacSMarek Behún else if (ret != 1)
37609bbedacSMarek Behún return -EIO;
37709bbedacSMarek Behún else
37809bbedacSMarek Behún return 0;
37909bbedacSMarek Behún }
38009bbedacSMarek Behún
mdio_i2c_alloc(struct device * parent,struct i2c_adapter * i2c,enum mdio_i2c_proto protocol)38109bbedacSMarek Behún struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
38209bbedacSMarek Behún enum mdio_i2c_proto protocol)
383a9770eacSAndrew Lunn {
384a9770eacSAndrew Lunn struct mii_bus *mii;
38509bbedacSMarek Behún int ret;
386a9770eacSAndrew Lunn
387a9770eacSAndrew Lunn if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
388a9770eacSAndrew Lunn return ERR_PTR(-EINVAL);
389a9770eacSAndrew Lunn
390a9770eacSAndrew Lunn mii = mdiobus_alloc();
391a9770eacSAndrew Lunn if (!mii)
392a9770eacSAndrew Lunn return ERR_PTR(-ENOMEM);
393a9770eacSAndrew Lunn
394a9770eacSAndrew Lunn snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent));
395a9770eacSAndrew Lunn mii->parent = parent;
396a9770eacSAndrew Lunn mii->priv = i2c;
397a9770eacSAndrew Lunn
39809bbedacSMarek Behún switch (protocol) {
39909bbedacSMarek Behún case MDIO_I2C_ROLLBALL:
40009bbedacSMarek Behún ret = i2c_mii_init_rollball(i2c);
40109bbedacSMarek Behún if (ret < 0) {
40209bbedacSMarek Behún dev_err(parent,
40309bbedacSMarek Behún "Cannot initialize RollBall MDIO I2C protocol: %d\n",
40409bbedacSMarek Behún ret);
40509bbedacSMarek Behún mdiobus_free(mii);
40609bbedacSMarek Behún return ERR_PTR(ret);
40709bbedacSMarek Behún }
40809bbedacSMarek Behún
409*b48a1864SRussell King (Oracle) mii->read_c45 = i2c_mii_read_rollball;
410*b48a1864SRussell King (Oracle) mii->write_c45 = i2c_mii_write_rollball;
41109bbedacSMarek Behún break;
41209bbedacSMarek Behún default:
41387e3bee0SAndrew Lunn mii->read = i2c_mii_read_default_c22;
41487e3bee0SAndrew Lunn mii->write = i2c_mii_write_default_c22;
41587e3bee0SAndrew Lunn mii->read_c45 = i2c_mii_read_default_c45;
41687e3bee0SAndrew Lunn mii->write_c45 = i2c_mii_write_default_c45;
41709bbedacSMarek Behún break;
41809bbedacSMarek Behún }
41909bbedacSMarek Behún
420a9770eacSAndrew Lunn return mii;
421a9770eacSAndrew Lunn }
422a9770eacSAndrew Lunn EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
423a9770eacSAndrew Lunn
424a9770eacSAndrew Lunn MODULE_AUTHOR("Russell King");
425a9770eacSAndrew Lunn MODULE_DESCRIPTION("MDIO I2C bridge library");
426a9770eacSAndrew Lunn MODULE_LICENSE("GPL v2");
427