0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "chip.h"
0011 #include "smi.h"
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 static int mv88e6xxx_smi_direct_read(struct mv88e6xxx_chip *chip,
0030 int dev, int reg, u16 *data)
0031 {
0032 int ret;
0033
0034 ret = mdiobus_read_nested(chip->bus, dev, reg);
0035 if (ret < 0)
0036 return ret;
0037
0038 *data = ret & 0xffff;
0039
0040 return 0;
0041 }
0042
0043 static int mv88e6xxx_smi_direct_write(struct mv88e6xxx_chip *chip,
0044 int dev, int reg, u16 data)
0045 {
0046 int ret;
0047
0048 ret = mdiobus_write_nested(chip->bus, dev, reg, data);
0049 if (ret < 0)
0050 return ret;
0051
0052 return 0;
0053 }
0054
0055 static int mv88e6xxx_smi_direct_wait(struct mv88e6xxx_chip *chip,
0056 int dev, int reg, int bit, int val)
0057 {
0058 const unsigned long timeout = jiffies + msecs_to_jiffies(50);
0059 u16 data;
0060 int err;
0061 int i;
0062
0063
0064
0065
0066 for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) {
0067 err = mv88e6xxx_smi_direct_read(chip, dev, reg, &data);
0068 if (err)
0069 return err;
0070
0071 if (!!(data & BIT(bit)) == !!val)
0072 return 0;
0073
0074 if (i < 2)
0075 cpu_relax();
0076 else
0077 usleep_range(1000, 2000);
0078 }
0079
0080 return -ETIMEDOUT;
0081 }
0082
0083 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {
0084 .read = mv88e6xxx_smi_direct_read,
0085 .write = mv88e6xxx_smi_direct_write,
0086 };
0087
0088 static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,
0089 int dev, int reg, u16 *data)
0090 {
0091 return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);
0092 }
0093
0094 static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,
0095 int dev, int reg, u16 data)
0096 {
0097 return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);
0098 }
0099
0100 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {
0101 .read = mv88e6xxx_smi_dual_direct_read,
0102 .write = mv88e6xxx_smi_dual_direct_write,
0103 };
0104
0105
0106
0107
0108
0109 static int mv88e6xxx_smi_indirect_read(struct mv88e6xxx_chip *chip,
0110 int dev, int reg, u16 *data)
0111 {
0112 int err;
0113
0114 err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
0115 MV88E6XXX_SMI_CMD,
0116 MV88E6XXX_SMI_CMD_BUSY |
0117 MV88E6XXX_SMI_CMD_MODE_22 |
0118 MV88E6XXX_SMI_CMD_OP_22_READ |
0119 (dev << 5) | reg);
0120 if (err)
0121 return err;
0122
0123 err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
0124 MV88E6XXX_SMI_CMD, 15, 0);
0125 if (err)
0126 return err;
0127
0128 return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,
0129 MV88E6XXX_SMI_DATA, data);
0130 }
0131
0132 static int mv88e6xxx_smi_indirect_write(struct mv88e6xxx_chip *chip,
0133 int dev, int reg, u16 data)
0134 {
0135 int err;
0136
0137 err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
0138 MV88E6XXX_SMI_DATA, data);
0139 if (err)
0140 return err;
0141
0142 err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
0143 MV88E6XXX_SMI_CMD,
0144 MV88E6XXX_SMI_CMD_BUSY |
0145 MV88E6XXX_SMI_CMD_MODE_22 |
0146 MV88E6XXX_SMI_CMD_OP_22_WRITE |
0147 (dev << 5) | reg);
0148 if (err)
0149 return err;
0150
0151 return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
0152 MV88E6XXX_SMI_CMD, 15, 0);
0153 }
0154
0155 static int mv88e6xxx_smi_indirect_init(struct mv88e6xxx_chip *chip)
0156 {
0157
0158
0159
0160
0161 return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
0162 MV88E6XXX_SMI_CMD, 15, 0);
0163 }
0164
0165 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
0166 .read = mv88e6xxx_smi_indirect_read,
0167 .write = mv88e6xxx_smi_indirect_write,
0168 .init = mv88e6xxx_smi_indirect_init,
0169 };
0170
0171 int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
0172 struct mii_bus *bus, int sw_addr)
0173 {
0174 if (chip->info->dual_chip)
0175 chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
0176 else if (sw_addr == 0)
0177 chip->smi_ops = &mv88e6xxx_smi_direct_ops;
0178 else if (chip->info->multi_chip)
0179 chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
0180 else
0181 return -EINVAL;
0182
0183 chip->bus = bus;
0184 chip->sw_addr = sw_addr;
0185
0186 if (chip->smi_ops->init)
0187 return chip->smi_ops->init(chip);
0188
0189 return 0;
0190 }