The Marvell 6352 chip has a 8-bit address/16-bit data EEPROM access.
The Marvell 6390 chip has a 16-bit address/8-bit data EEPROM access.
This patch implements the 8-bit data EEPROM access in the mv88e6xxx
driver and adds its support to chips of the 6390 family.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
 
 static const struct mv88e6xxx_ops mv88e6190_ops = {
        /* MV88E6XXX_FAMILY_6390 */
+       .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+       .set_eeprom = mv88e6xxx_g2_set_eeprom8,
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
 
 static const struct mv88e6xxx_ops mv88e6190x_ops = {
        /* MV88E6XXX_FAMILY_6390 */
+       .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+       .set_eeprom = mv88e6xxx_g2_set_eeprom8,
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
 
 static const struct mv88e6xxx_ops mv88e6191_ops = {
        /* MV88E6XXX_FAMILY_6390 */
+       .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+       .set_eeprom = mv88e6xxx_g2_set_eeprom8,
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
 
 static const struct mv88e6xxx_ops mv88e6290_ops = {
        /* MV88E6XXX_FAMILY_6390 */
+       .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+       .set_eeprom = mv88e6xxx_g2_set_eeprom8,
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
 
 static const struct mv88e6xxx_ops mv88e6390_ops = {
        /* MV88E6XXX_FAMILY_6390 */
+       .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+       .set_eeprom = mv88e6xxx_g2_set_eeprom8,
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
 
 static const struct mv88e6xxx_ops mv88e6390x_ops = {
        /* MV88E6XXX_FAMILY_6390 */
+       .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+       .set_eeprom = mv88e6xxx_g2_set_eeprom8,
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
 
 static const struct mv88e6xxx_ops mv88e6391_ops = {
        /* MV88E6XXX_FAMILY_6390 */
+       .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+       .set_eeprom = mv88e6xxx_g2_set_eeprom8,
        .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
        .phy_read = mv88e6xxx_g2_smi_phy_read,
        .phy_write = mv88e6xxx_g2_smi_phy_write,
 
 }
 
 /* Offset 0x14: EEPROM Command
- * Offset 0x15: EEPROM Data
+ * Offset 0x15: EEPROM Data (for 16-bit data access)
+ * Offset 0x15: EEPROM Addr (for 8-bit data access)
  */
 
 static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
        return mv88e6xxx_g2_eeprom_wait(chip);
 }
 
+static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
+                                    u16 addr, u8 *data)
+{
+       u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ;
+       int err;
+
+       err = mv88e6xxx_g2_eeprom_wait(chip);
+       if (err)
+               return err;
+
+       err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_ADDR, addr);
+       if (err)
+               return err;
+
+       err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
+       if (err)
+               return err;
+
+       err = mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_CMD, &cmd);
+       if (err)
+               return err;
+
+       *data = cmd & 0xff;
+
+       return 0;
+}
+
+static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
+                                     u16 addr, u8 data)
+{
+       u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | GLOBAL2_EEPROM_CMD_WRITE_EN;
+       int err;
+
+       err = mv88e6xxx_g2_eeprom_wait(chip);
+       if (err)
+               return err;
+
+       err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_ADDR, addr);
+       if (err)
+               return err;
+
+       return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
+}
+
 static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
                                      u8 addr, u16 *data)
 {
        return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
 }
 
+int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
+                            struct ethtool_eeprom *eeprom, u8 *data)
+{
+       unsigned int offset = eeprom->offset;
+       unsigned int len = eeprom->len;
+       int err;
+
+       eeprom->len = 0;
+
+       while (len) {
+               err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
+               if (err)
+                       return err;
+
+               eeprom->len++;
+               offset++;
+               data++;
+               len--;
+       }
+
+       return 0;
+}
+
+int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
+                            struct ethtool_eeprom *eeprom, u8 *data)
+{
+       unsigned int offset = eeprom->offset;
+       unsigned int len = eeprom->len;
+       int err;
+
+       eeprom->len = 0;
+
+       while (len) {
+               err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
+               if (err)
+                       return err;
+
+               eeprom->len++;
+               offset++;
+               data++;
+               len--;
+       }
+
+       return 0;
+}
+
 int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
                              struct ethtool_eeprom *eeprom, u8 *data)
 {
 
 int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, int addr, int reg,
                               u16 val);
 int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr);
+
+int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
+                            struct ethtool_eeprom *eeprom, u8 *data);
+int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
+                            struct ethtool_eeprom *eeprom, u8 *data);
+
 int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
                              struct ethtool_eeprom *eeprom, u8 *data);
 int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
                              struct ethtool_eeprom *eeprom, u8 *data);
+
 int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip);
 int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip);
 void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip);
        return -EOPNOTSUPP;
 }
 
+static inline int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
+                                          struct ethtool_eeprom *eeprom,
+                                          u8 *data)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
+                                          struct ethtool_eeprom *eeprom,
+                                          u8 *data)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
                                            struct ethtool_eeprom *eeprom,
                                            u8 *data)
 
 #define GLOBAL2_EEPROM_CMD_WRITE_EN    BIT(10)
 #define GLOBAL2_EEPROM_CMD_ADDR_MASK   0xff
 #define GLOBAL2_EEPROM_DATA    0x15
+#define GLOBAL2_EEPROM_ADDR    0x15 /* 6390 */
 #define GLOBAL2_PTP_AVB_OP     0x16
 #define GLOBAL2_PTP_AVB_DATA   0x17
 #define GLOBAL2_SMI_PHY_CMD                    0x18