^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * MDIO I2C bridge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015-2016 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Network PHYs can appear on I2C buses when they are part of SFP module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This driver exposes these PHYs to the networking PHY code, allowing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * our PHY drivers access to these PHYs, and so allowing configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * of their settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mdio/mdio-i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * specified to be present in SFP modules. These correspond with PHY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * addresses 16 and 17. Disallow access to these "phy" addresses.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static bool i2c_mii_valid_phy_id(int phy_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) return phy_id != 0x10 && phy_id != 0x11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static unsigned int i2c_mii_phy_addr(int phy_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return phy_id + 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct i2c_adapter *i2c = bus->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct i2c_msg msgs[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u8 addr[3], data[2], *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int bus_addr, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!i2c_mii_valid_phy_id(phy_id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) p = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (reg & MII_ADDR_C45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *p++ = 0x20 | ((reg >> 16) & 31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *p++ = reg >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *p++ = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) bus_addr = i2c_mii_phy_addr(phy_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) msgs[0].addr = bus_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) msgs[0].flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) msgs[0].len = p - addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) msgs[0].buf = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) msgs[1].addr = bus_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) msgs[1].flags = I2C_M_RD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) msgs[1].len = sizeof(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) msgs[1].buf = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (ret != ARRAY_SIZE(msgs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return data[0] << 8 | data[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct i2c_adapter *i2c = bus->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct i2c_msg msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u8 data[5], *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!i2c_mii_valid_phy_id(phy_id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) p = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (reg & MII_ADDR_C45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *p++ = (reg >> 16) & 31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) *p++ = reg >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) *p++ = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) *p++ = val >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) *p++ = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) msg.addr = i2c_mii_phy_addr(phy_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) msg.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) msg.len = p - data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) msg.buf = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ret = i2c_transfer(i2c, &msg, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return ret < 0 ? ret : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct mii_bus *mii;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) mii = mdiobus_alloc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (!mii)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) mii->parent = parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) mii->read = i2c_mii_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) mii->write = i2c_mii_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) mii->priv = i2c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return mii;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) MODULE_AUTHOR("Russell King");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) MODULE_DESCRIPTION("MDIO I2C bridge library");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) MODULE_LICENSE("GPL v2");