0001
0002
0003
0004
0005
0006
0007 #include <linux/bitfield.h>
0008 #include <linux/brcmphy.h>
0009 #include <linux/hwmon.h>
0010 #include <linux/module.h>
0011 #include <linux/phy.h>
0012
0013 #include "bcm-phy-lib.h"
0014
0015
0016
0017 #define BCM54140_RDB_ISR 0x00a
0018 #define BCM54140_RDB_IMR 0x00b
0019 #define BCM54140_RDB_INT_LINK BIT(1)
0020 #define BCM54140_RDB_INT_SPEED BIT(2)
0021 #define BCM54140_RDB_INT_DUPLEX BIT(3)
0022 #define BCM54140_RDB_SPARE1 0x012
0023 #define BCM54140_RDB_SPARE1_LSLM BIT(2)
0024 #define BCM54140_RDB_SPARE2 0x014
0025 #define BCM54140_RDB_SPARE2_WS_RTRY_DIS BIT(8)
0026 #define BCM54140_RDB_SPARE2_WS_RTRY_LIMIT GENMASK(4, 2)
0027 #define BCM54140_RDB_SPARE3 0x015
0028 #define BCM54140_RDB_SPARE3_BIT0 BIT(0)
0029 #define BCM54140_RDB_LED_CTRL 0x019
0030 #define BCM54140_RDB_LED_CTRL_ACTLINK0 BIT(4)
0031 #define BCM54140_RDB_LED_CTRL_ACTLINK1 BIT(8)
0032 #define BCM54140_RDB_C_APWR 0x01a
0033 #define BCM54140_RDB_C_APWR_SINGLE_PULSE BIT(8)
0034 #define BCM54140_RDB_C_APWR_APD_MODE_DIS 0
0035 #define BCM54140_RDB_C_APWR_APD_MODE_EN 1
0036 #define BCM54140_RDB_C_APWR_APD_MODE_DIS2 2
0037 #define BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG 3
0038 #define BCM54140_RDB_C_APWR_APD_MODE_MASK GENMASK(6, 5)
0039 #define BCM54140_RDB_C_APWR_SLP_TIM_MASK BIT(4)
0040 #define BCM54140_RDB_C_APWR_SLP_TIM_2_7 0
0041 #define BCM54140_RDB_C_APWR_SLP_TIM_5_4 1
0042 #define BCM54140_RDB_C_PWR 0x02a
0043 #define BCM54140_RDB_C_PWR_ISOLATE BIT(5)
0044 #define BCM54140_RDB_C_MISC_CTRL 0x02f
0045 #define BCM54140_RDB_C_MISC_CTRL_WS_EN BIT(4)
0046
0047
0048
0049 #define BCM54140_RDB_TOP_IMR 0x82d
0050 #define BCM54140_RDB_TOP_IMR_PORT0 BIT(4)
0051 #define BCM54140_RDB_TOP_IMR_PORT1 BIT(5)
0052 #define BCM54140_RDB_TOP_IMR_PORT2 BIT(6)
0053 #define BCM54140_RDB_TOP_IMR_PORT3 BIT(7)
0054 #define BCM54140_RDB_MON_CTRL 0x831
0055 #define BCM54140_RDB_MON_CTRL_V_MODE BIT(3)
0056 #define BCM54140_RDB_MON_CTRL_SEL_MASK GENMASK(2, 1)
0057 #define BCM54140_RDB_MON_CTRL_SEL_TEMP 0
0058 #define BCM54140_RDB_MON_CTRL_SEL_1V0 1
0059 #define BCM54140_RDB_MON_CTRL_SEL_3V3 2
0060 #define BCM54140_RDB_MON_CTRL_SEL_RR 3
0061 #define BCM54140_RDB_MON_CTRL_PWR_DOWN BIT(0)
0062 #define BCM54140_RDB_MON_TEMP_VAL 0x832
0063 #define BCM54140_RDB_MON_TEMP_MAX 0x833
0064 #define BCM54140_RDB_MON_TEMP_MIN 0x834
0065 #define BCM54140_RDB_MON_TEMP_DATA_MASK GENMASK(9, 0)
0066 #define BCM54140_RDB_MON_1V0_VAL 0x835
0067 #define BCM54140_RDB_MON_1V0_MAX 0x836
0068 #define BCM54140_RDB_MON_1V0_MIN 0x837
0069 #define BCM54140_RDB_MON_1V0_DATA_MASK GENMASK(10, 0)
0070 #define BCM54140_RDB_MON_3V3_VAL 0x838
0071 #define BCM54140_RDB_MON_3V3_MAX 0x839
0072 #define BCM54140_RDB_MON_3V3_MIN 0x83a
0073 #define BCM54140_RDB_MON_3V3_DATA_MASK GENMASK(11, 0)
0074 #define BCM54140_RDB_MON_ISR 0x83b
0075 #define BCM54140_RDB_MON_ISR_3V3 BIT(2)
0076 #define BCM54140_RDB_MON_ISR_1V0 BIT(1)
0077 #define BCM54140_RDB_MON_ISR_TEMP BIT(0)
0078
0079
0080
0081
0082 #define BCM54140_HWMON_TO_TEMP(v) (413350L - (v) * 491)
0083 #define BCM54140_HWMON_FROM_TEMP(v) DIV_ROUND_CLOSEST_ULL(413350L - (v), 491)
0084
0085
0086
0087
0088
0089
0090
0091 #define BCM54140_HWMON_TO_IN_1V0(v) ((v) * 2514 >> 11)
0092 #define BCM54140_HWMON_FROM_IN_1V0(v) DIV_ROUND_CLOSEST_ULL(((v) << 11), 2514)
0093
0094
0095
0096
0097
0098
0099
0100 #define BCM54140_HWMON_TO_IN_3V3(v) ((v) * 4400 >> 12)
0101 #define BCM54140_HWMON_FROM_IN_3V3(v) DIV_ROUND_CLOSEST_ULL(((v) << 12), 4400)
0102
0103 #define BCM54140_HWMON_TO_IN(ch, v) ((ch) ? BCM54140_HWMON_TO_IN_3V3(v) \
0104 : BCM54140_HWMON_TO_IN_1V0(v))
0105 #define BCM54140_HWMON_FROM_IN(ch, v) ((ch) ? BCM54140_HWMON_FROM_IN_3V3(v) \
0106 : BCM54140_HWMON_FROM_IN_1V0(v))
0107 #define BCM54140_HWMON_IN_MASK(ch) ((ch) ? BCM54140_RDB_MON_3V3_DATA_MASK \
0108 : BCM54140_RDB_MON_1V0_DATA_MASK)
0109 #define BCM54140_HWMON_IN_VAL_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_VAL \
0110 : BCM54140_RDB_MON_1V0_VAL)
0111 #define BCM54140_HWMON_IN_MIN_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_MIN \
0112 : BCM54140_RDB_MON_1V0_MIN)
0113 #define BCM54140_HWMON_IN_MAX_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_MAX \
0114 : BCM54140_RDB_MON_1V0_MAX)
0115 #define BCM54140_HWMON_IN_ALARM_BIT(ch) ((ch) ? BCM54140_RDB_MON_ISR_3V3 \
0116 : BCM54140_RDB_MON_ISR_1V0)
0117
0118
0119
0120
0121
0122
0123 #define BCM54140_PHY_ID_MASK 0xffffffe8
0124
0125 #define BCM54140_PHY_ID_REV(phy_id) ((phy_id) & 0x7)
0126 #define BCM54140_REV_B0 1
0127
0128 #define BCM54140_DEFAULT_DOWNSHIFT 5
0129 #define BCM54140_MAX_DOWNSHIFT 9
0130
0131 struct bcm54140_priv {
0132 int port;
0133 int base_addr;
0134 #if IS_ENABLED(CONFIG_HWMON)
0135
0136 struct mutex alarm_lock;
0137 u16 alarm;
0138 #endif
0139 };
0140
0141 #if IS_ENABLED(CONFIG_HWMON)
0142 static umode_t bcm54140_hwmon_is_visible(const void *data,
0143 enum hwmon_sensor_types type,
0144 u32 attr, int channel)
0145 {
0146 switch (type) {
0147 case hwmon_in:
0148 switch (attr) {
0149 case hwmon_in_min:
0150 case hwmon_in_max:
0151 return 0644;
0152 case hwmon_in_label:
0153 case hwmon_in_input:
0154 case hwmon_in_alarm:
0155 return 0444;
0156 default:
0157 return 0;
0158 }
0159 case hwmon_temp:
0160 switch (attr) {
0161 case hwmon_temp_min:
0162 case hwmon_temp_max:
0163 return 0644;
0164 case hwmon_temp_input:
0165 case hwmon_temp_alarm:
0166 return 0444;
0167 default:
0168 return 0;
0169 }
0170 default:
0171 return 0;
0172 }
0173 }
0174
0175 static int bcm54140_hwmon_read_alarm(struct device *dev, unsigned int bit,
0176 long *val)
0177 {
0178 struct phy_device *phydev = dev_get_drvdata(dev);
0179 struct bcm54140_priv *priv = phydev->priv;
0180 int tmp, ret = 0;
0181
0182 mutex_lock(&priv->alarm_lock);
0183
0184
0185 tmp = bcm_phy_read_rdb(phydev, BCM54140_RDB_MON_ISR);
0186 if (tmp < 0) {
0187 ret = tmp;
0188 goto out;
0189 }
0190 priv->alarm |= tmp;
0191
0192 *val = !!(priv->alarm & bit);
0193 priv->alarm &= ~bit;
0194
0195 out:
0196 mutex_unlock(&priv->alarm_lock);
0197 return ret;
0198 }
0199
0200 static int bcm54140_hwmon_read_temp(struct device *dev, u32 attr, long *val)
0201 {
0202 struct phy_device *phydev = dev_get_drvdata(dev);
0203 u16 reg;
0204 int tmp;
0205
0206 switch (attr) {
0207 case hwmon_temp_input:
0208 reg = BCM54140_RDB_MON_TEMP_VAL;
0209 break;
0210 case hwmon_temp_min:
0211 reg = BCM54140_RDB_MON_TEMP_MIN;
0212 break;
0213 case hwmon_temp_max:
0214 reg = BCM54140_RDB_MON_TEMP_MAX;
0215 break;
0216 case hwmon_temp_alarm:
0217 return bcm54140_hwmon_read_alarm(dev,
0218 BCM54140_RDB_MON_ISR_TEMP,
0219 val);
0220 default:
0221 return -EOPNOTSUPP;
0222 }
0223
0224 tmp = bcm_phy_read_rdb(phydev, reg);
0225 if (tmp < 0)
0226 return tmp;
0227
0228 *val = BCM54140_HWMON_TO_TEMP(tmp & BCM54140_RDB_MON_TEMP_DATA_MASK);
0229
0230 return 0;
0231 }
0232
0233 static int bcm54140_hwmon_read_in(struct device *dev, u32 attr,
0234 int channel, long *val)
0235 {
0236 struct phy_device *phydev = dev_get_drvdata(dev);
0237 u16 bit, reg;
0238 int tmp;
0239
0240 switch (attr) {
0241 case hwmon_in_input:
0242 reg = BCM54140_HWMON_IN_VAL_REG(channel);
0243 break;
0244 case hwmon_in_min:
0245 reg = BCM54140_HWMON_IN_MIN_REG(channel);
0246 break;
0247 case hwmon_in_max:
0248 reg = BCM54140_HWMON_IN_MAX_REG(channel);
0249 break;
0250 case hwmon_in_alarm:
0251 bit = BCM54140_HWMON_IN_ALARM_BIT(channel);
0252 return bcm54140_hwmon_read_alarm(dev, bit, val);
0253 default:
0254 return -EOPNOTSUPP;
0255 }
0256
0257 tmp = bcm_phy_read_rdb(phydev, reg);
0258 if (tmp < 0)
0259 return tmp;
0260
0261 tmp &= BCM54140_HWMON_IN_MASK(channel);
0262 *val = BCM54140_HWMON_TO_IN(channel, tmp);
0263
0264 return 0;
0265 }
0266
0267 static int bcm54140_hwmon_read(struct device *dev,
0268 enum hwmon_sensor_types type, u32 attr,
0269 int channel, long *val)
0270 {
0271 switch (type) {
0272 case hwmon_temp:
0273 return bcm54140_hwmon_read_temp(dev, attr, val);
0274 case hwmon_in:
0275 return bcm54140_hwmon_read_in(dev, attr, channel, val);
0276 default:
0277 return -EOPNOTSUPP;
0278 }
0279 }
0280
0281 static const char *const bcm54140_hwmon_in_labels[] = {
0282 "AVDDL",
0283 "AVDDH",
0284 };
0285
0286 static int bcm54140_hwmon_read_string(struct device *dev,
0287 enum hwmon_sensor_types type, u32 attr,
0288 int channel, const char **str)
0289 {
0290 switch (type) {
0291 case hwmon_in:
0292 switch (attr) {
0293 case hwmon_in_label:
0294 *str = bcm54140_hwmon_in_labels[channel];
0295 return 0;
0296 default:
0297 return -EOPNOTSUPP;
0298 }
0299 default:
0300 return -EOPNOTSUPP;
0301 }
0302 }
0303
0304 static int bcm54140_hwmon_write_temp(struct device *dev, u32 attr,
0305 int channel, long val)
0306 {
0307 struct phy_device *phydev = dev_get_drvdata(dev);
0308 u16 mask = BCM54140_RDB_MON_TEMP_DATA_MASK;
0309 u16 reg;
0310
0311 val = clamp_val(val, BCM54140_HWMON_TO_TEMP(mask),
0312 BCM54140_HWMON_TO_TEMP(0));
0313
0314 switch (attr) {
0315 case hwmon_temp_min:
0316 reg = BCM54140_RDB_MON_TEMP_MIN;
0317 break;
0318 case hwmon_temp_max:
0319 reg = BCM54140_RDB_MON_TEMP_MAX;
0320 break;
0321 default:
0322 return -EOPNOTSUPP;
0323 }
0324
0325 return bcm_phy_modify_rdb(phydev, reg, mask,
0326 BCM54140_HWMON_FROM_TEMP(val));
0327 }
0328
0329 static int bcm54140_hwmon_write_in(struct device *dev, u32 attr,
0330 int channel, long val)
0331 {
0332 struct phy_device *phydev = dev_get_drvdata(dev);
0333 u16 mask = BCM54140_HWMON_IN_MASK(channel);
0334 u16 reg;
0335
0336 val = clamp_val(val, 0, BCM54140_HWMON_TO_IN(channel, mask));
0337
0338 switch (attr) {
0339 case hwmon_in_min:
0340 reg = BCM54140_HWMON_IN_MIN_REG(channel);
0341 break;
0342 case hwmon_in_max:
0343 reg = BCM54140_HWMON_IN_MAX_REG(channel);
0344 break;
0345 default:
0346 return -EOPNOTSUPP;
0347 }
0348
0349 return bcm_phy_modify_rdb(phydev, reg, mask,
0350 BCM54140_HWMON_FROM_IN(channel, val));
0351 }
0352
0353 static int bcm54140_hwmon_write(struct device *dev,
0354 enum hwmon_sensor_types type, u32 attr,
0355 int channel, long val)
0356 {
0357 switch (type) {
0358 case hwmon_temp:
0359 return bcm54140_hwmon_write_temp(dev, attr, channel, val);
0360 case hwmon_in:
0361 return bcm54140_hwmon_write_in(dev, attr, channel, val);
0362 default:
0363 return -EOPNOTSUPP;
0364 }
0365 }
0366
0367 static const struct hwmon_channel_info *bcm54140_hwmon_info[] = {
0368 HWMON_CHANNEL_INFO(temp,
0369 HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
0370 HWMON_T_ALARM),
0371 HWMON_CHANNEL_INFO(in,
0372 HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
0373 HWMON_I_ALARM | HWMON_I_LABEL,
0374 HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
0375 HWMON_I_ALARM | HWMON_I_LABEL),
0376 NULL
0377 };
0378
0379 static const struct hwmon_ops bcm54140_hwmon_ops = {
0380 .is_visible = bcm54140_hwmon_is_visible,
0381 .read = bcm54140_hwmon_read,
0382 .read_string = bcm54140_hwmon_read_string,
0383 .write = bcm54140_hwmon_write,
0384 };
0385
0386 static const struct hwmon_chip_info bcm54140_chip_info = {
0387 .ops = &bcm54140_hwmon_ops,
0388 .info = bcm54140_hwmon_info,
0389 };
0390
0391 static int bcm54140_enable_monitoring(struct phy_device *phydev)
0392 {
0393 u16 mask, set;
0394
0395
0396 set = BCM54140_RDB_MON_CTRL_V_MODE;
0397
0398
0399 mask = BCM54140_RDB_MON_CTRL_SEL_MASK;
0400 set |= FIELD_PREP(BCM54140_RDB_MON_CTRL_SEL_MASK,
0401 BCM54140_RDB_MON_CTRL_SEL_RR);
0402
0403
0404 mask |= BCM54140_RDB_MON_CTRL_PWR_DOWN;
0405
0406 return bcm_phy_modify_rdb(phydev, BCM54140_RDB_MON_CTRL, mask, set);
0407 }
0408
0409 static int bcm54140_probe_once(struct phy_device *phydev)
0410 {
0411 struct device *hwmon;
0412 int ret;
0413
0414
0415 ret = bcm54140_enable_monitoring(phydev);
0416 if (ret)
0417 return ret;
0418
0419 hwmon = devm_hwmon_device_register_with_info(&phydev->mdio.dev,
0420 "BCM54140", phydev,
0421 &bcm54140_chip_info,
0422 NULL);
0423 return PTR_ERR_OR_ZERO(hwmon);
0424 }
0425 #endif
0426
0427 static int bcm54140_base_read_rdb(struct phy_device *phydev, u16 rdb)
0428 {
0429 int ret;
0430
0431 phy_lock_mdio_bus(phydev);
0432 ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
0433 if (ret < 0)
0434 goto out;
0435
0436 ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
0437
0438 out:
0439 phy_unlock_mdio_bus(phydev);
0440 return ret;
0441 }
0442
0443 static int bcm54140_base_write_rdb(struct phy_device *phydev,
0444 u16 rdb, u16 val)
0445 {
0446 int ret;
0447
0448 phy_lock_mdio_bus(phydev);
0449 ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
0450 if (ret < 0)
0451 goto out;
0452
0453 ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
0454
0455 out:
0456 phy_unlock_mdio_bus(phydev);
0457 return ret;
0458 }
0459
0460
0461
0462
0463
0464 static int bcm54140_b0_workaround(struct phy_device *phydev)
0465 {
0466 int spare3;
0467 int ret;
0468
0469 spare3 = bcm_phy_read_rdb(phydev, BCM54140_RDB_SPARE3);
0470 if (spare3 < 0)
0471 return spare3;
0472
0473 spare3 &= ~BCM54140_RDB_SPARE3_BIT0;
0474
0475 ret = bcm_phy_write_rdb(phydev, BCM54140_RDB_SPARE3, spare3);
0476 if (ret)
0477 return ret;
0478
0479 ret = phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN);
0480 if (ret)
0481 return ret;
0482
0483 ret = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
0484 if (ret)
0485 return ret;
0486
0487 spare3 |= BCM54140_RDB_SPARE3_BIT0;
0488
0489 return bcm_phy_write_rdb(phydev, BCM54140_RDB_SPARE3, spare3);
0490 }
0491
0492
0493
0494
0495
0496 static int bcm54140_get_base_addr_and_port(struct phy_device *phydev)
0497 {
0498 struct bcm54140_priv *priv = phydev->priv;
0499 struct mii_bus *bus = phydev->mdio.bus;
0500 int addr, min_addr, max_addr;
0501 int step = 1;
0502 u32 phy_id;
0503 int tmp;
0504
0505 min_addr = phydev->mdio.addr;
0506 max_addr = phydev->mdio.addr;
0507 addr = phydev->mdio.addr;
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519 while (1) {
0520 if (step == 3) {
0521 break;
0522 } else if (step == 1) {
0523 max_addr = addr;
0524 addr++;
0525 } else {
0526 min_addr = addr;
0527 addr--;
0528 }
0529
0530 if (addr < 0 || addr >= PHY_MAX_ADDR) {
0531 addr = phydev->mdio.addr;
0532 step++;
0533 continue;
0534 }
0535
0536
0537 tmp = mdiobus_read(bus, addr, MII_PHYSID1);
0538 if (tmp < 0)
0539 return tmp;
0540 phy_id = tmp << 16;
0541 tmp = mdiobus_read(bus, addr, MII_PHYSID2);
0542 if (tmp < 0)
0543 return tmp;
0544 phy_id |= tmp;
0545
0546
0547 if ((phy_id & phydev->drv->phy_id_mask) !=
0548 (phydev->drv->phy_id & phydev->drv->phy_id_mask)) {
0549 addr = phydev->mdio.addr;
0550 step++;
0551 }
0552 }
0553
0554
0555
0556
0557
0558 if ((max_addr - min_addr + 1) % 4) {
0559 dev_err(&phydev->mdio.dev,
0560 "Detected Quad PHY IDs %d..%d doesn't make sense.\n",
0561 min_addr, max_addr);
0562 return -EINVAL;
0563 }
0564
0565 priv->port = (phydev->mdio.addr - min_addr) % 4;
0566 priv->base_addr = phydev->mdio.addr - priv->port;
0567
0568 return 0;
0569 }
0570
0571 static int bcm54140_probe(struct phy_device *phydev)
0572 {
0573 struct bcm54140_priv *priv;
0574 int ret;
0575
0576 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
0577 if (!priv)
0578 return -ENOMEM;
0579
0580 phydev->priv = priv;
0581
0582 ret = bcm54140_get_base_addr_and_port(phydev);
0583 if (ret)
0584 return ret;
0585
0586 devm_phy_package_join(&phydev->mdio.dev, phydev, priv->base_addr, 0);
0587
0588 #if IS_ENABLED(CONFIG_HWMON)
0589 mutex_init(&priv->alarm_lock);
0590
0591 if (phy_package_init_once(phydev)) {
0592 ret = bcm54140_probe_once(phydev);
0593 if (ret)
0594 return ret;
0595 }
0596 #endif
0597
0598 phydev_dbg(phydev, "probed (port %d, base PHY address %d)\n",
0599 priv->port, priv->base_addr);
0600
0601 return 0;
0602 }
0603
0604 static int bcm54140_config_init(struct phy_device *phydev)
0605 {
0606 u16 reg = 0xffff;
0607 int ret;
0608
0609
0610 if (BCM54140_PHY_ID_REV(phydev->phy_id) == BCM54140_REV_B0) {
0611 ret = bcm54140_b0_workaround(phydev);
0612 if (ret)
0613 return ret;
0614 }
0615
0616
0617 reg &= ~(BCM54140_RDB_INT_DUPLEX |
0618 BCM54140_RDB_INT_SPEED |
0619 BCM54140_RDB_INT_LINK);
0620 ret = bcm_phy_write_rdb(phydev, BCM54140_RDB_IMR, reg);
0621 if (ret)
0622 return ret;
0623
0624
0625 ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_SPARE1,
0626 0, BCM54140_RDB_SPARE1_LSLM);
0627 if (ret)
0628 return ret;
0629
0630 ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_LED_CTRL,
0631 0, BCM54140_RDB_LED_CTRL_ACTLINK0);
0632 if (ret)
0633 return ret;
0634
0635
0636 return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_PWR,
0637 BCM54140_RDB_C_PWR_ISOLATE, 0);
0638 }
0639
0640 static irqreturn_t bcm54140_handle_interrupt(struct phy_device *phydev)
0641 {
0642 int irq_status, irq_mask;
0643
0644 irq_status = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
0645 if (irq_status < 0) {
0646 phy_error(phydev);
0647 return IRQ_NONE;
0648 }
0649
0650 irq_mask = bcm_phy_read_rdb(phydev, BCM54140_RDB_IMR);
0651 if (irq_mask < 0) {
0652 phy_error(phydev);
0653 return IRQ_NONE;
0654 }
0655 irq_mask = ~irq_mask;
0656
0657 if (!(irq_status & irq_mask))
0658 return IRQ_NONE;
0659
0660 phy_trigger_machine(phydev);
0661
0662 return IRQ_HANDLED;
0663 }
0664
0665 static int bcm54140_ack_intr(struct phy_device *phydev)
0666 {
0667 int reg;
0668
0669
0670 reg = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
0671 if (reg < 0)
0672 return reg;
0673
0674 return 0;
0675 }
0676
0677 static int bcm54140_config_intr(struct phy_device *phydev)
0678 {
0679 struct bcm54140_priv *priv = phydev->priv;
0680 static const u16 port_to_imr_bit[] = {
0681 BCM54140_RDB_TOP_IMR_PORT0, BCM54140_RDB_TOP_IMR_PORT1,
0682 BCM54140_RDB_TOP_IMR_PORT2, BCM54140_RDB_TOP_IMR_PORT3,
0683 };
0684 int reg, err;
0685
0686 if (priv->port >= ARRAY_SIZE(port_to_imr_bit))
0687 return -EINVAL;
0688
0689 reg = bcm54140_base_read_rdb(phydev, BCM54140_RDB_TOP_IMR);
0690 if (reg < 0)
0691 return reg;
0692
0693 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0694 err = bcm54140_ack_intr(phydev);
0695 if (err)
0696 return err;
0697
0698 reg &= ~port_to_imr_bit[priv->port];
0699 err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
0700 } else {
0701 reg |= port_to_imr_bit[priv->port];
0702 err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
0703 if (err)
0704 return err;
0705
0706 err = bcm54140_ack_intr(phydev);
0707 }
0708
0709 return err;
0710 }
0711
0712 static int bcm54140_get_downshift(struct phy_device *phydev, u8 *data)
0713 {
0714 int val;
0715
0716 val = bcm_phy_read_rdb(phydev, BCM54140_RDB_C_MISC_CTRL);
0717 if (val < 0)
0718 return val;
0719
0720 if (!(val & BCM54140_RDB_C_MISC_CTRL_WS_EN)) {
0721 *data = DOWNSHIFT_DEV_DISABLE;
0722 return 0;
0723 }
0724
0725 val = bcm_phy_read_rdb(phydev, BCM54140_RDB_SPARE2);
0726 if (val < 0)
0727 return val;
0728
0729 if (val & BCM54140_RDB_SPARE2_WS_RTRY_DIS)
0730 *data = 1;
0731 else
0732 *data = FIELD_GET(BCM54140_RDB_SPARE2_WS_RTRY_LIMIT, val) + 2;
0733
0734 return 0;
0735 }
0736
0737 static int bcm54140_set_downshift(struct phy_device *phydev, u8 cnt)
0738 {
0739 u16 mask, set;
0740 int ret;
0741
0742 if (cnt > BCM54140_MAX_DOWNSHIFT && cnt != DOWNSHIFT_DEV_DEFAULT_COUNT)
0743 return -EINVAL;
0744
0745 if (!cnt)
0746 return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_MISC_CTRL,
0747 BCM54140_RDB_C_MISC_CTRL_WS_EN, 0);
0748
0749 if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
0750 cnt = BCM54140_DEFAULT_DOWNSHIFT;
0751
0752 if (cnt == 1) {
0753 mask = 0;
0754 set = BCM54140_RDB_SPARE2_WS_RTRY_DIS;
0755 } else {
0756 mask = BCM54140_RDB_SPARE2_WS_RTRY_DIS;
0757 mask |= BCM54140_RDB_SPARE2_WS_RTRY_LIMIT;
0758 set = FIELD_PREP(BCM54140_RDB_SPARE2_WS_RTRY_LIMIT, cnt - 2);
0759 }
0760 ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_SPARE2,
0761 mask, set);
0762 if (ret)
0763 return ret;
0764
0765 return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_MISC_CTRL,
0766 0, BCM54140_RDB_C_MISC_CTRL_WS_EN);
0767 }
0768
0769 static int bcm54140_get_edpd(struct phy_device *phydev, u16 *tx_interval)
0770 {
0771 int val;
0772
0773 val = bcm_phy_read_rdb(phydev, BCM54140_RDB_C_APWR);
0774 if (val < 0)
0775 return val;
0776
0777 switch (FIELD_GET(BCM54140_RDB_C_APWR_APD_MODE_MASK, val)) {
0778 case BCM54140_RDB_C_APWR_APD_MODE_DIS:
0779 case BCM54140_RDB_C_APWR_APD_MODE_DIS2:
0780 *tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
0781 break;
0782 case BCM54140_RDB_C_APWR_APD_MODE_EN:
0783 case BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG:
0784 switch (FIELD_GET(BCM54140_RDB_C_APWR_SLP_TIM_MASK, val)) {
0785 case BCM54140_RDB_C_APWR_SLP_TIM_2_7:
0786 *tx_interval = 2700;
0787 break;
0788 case BCM54140_RDB_C_APWR_SLP_TIM_5_4:
0789 *tx_interval = 5400;
0790 break;
0791 }
0792 }
0793
0794 return 0;
0795 }
0796
0797 static int bcm54140_set_edpd(struct phy_device *phydev, u16 tx_interval)
0798 {
0799 u16 mask, set;
0800
0801 mask = BCM54140_RDB_C_APWR_APD_MODE_MASK;
0802 if (tx_interval == ETHTOOL_PHY_EDPD_DISABLE)
0803 set = FIELD_PREP(BCM54140_RDB_C_APWR_APD_MODE_MASK,
0804 BCM54140_RDB_C_APWR_APD_MODE_DIS);
0805 else
0806 set = FIELD_PREP(BCM54140_RDB_C_APWR_APD_MODE_MASK,
0807 BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG);
0808
0809
0810 set |= BCM54140_RDB_C_APWR_SINGLE_PULSE;
0811
0812
0813 mask |= BCM54140_RDB_C_APWR_SLP_TIM_MASK;
0814 switch (tx_interval) {
0815 case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:
0816 case ETHTOOL_PHY_EDPD_DISABLE:
0817 case 2700:
0818 set |= BCM54140_RDB_C_APWR_SLP_TIM_2_7;
0819 break;
0820 case 5400:
0821 set |= BCM54140_RDB_C_APWR_SLP_TIM_5_4;
0822 break;
0823 default:
0824 return -EINVAL;
0825 }
0826
0827 return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_APWR, mask, set);
0828 }
0829
0830 static int bcm54140_get_tunable(struct phy_device *phydev,
0831 struct ethtool_tunable *tuna, void *data)
0832 {
0833 switch (tuna->id) {
0834 case ETHTOOL_PHY_DOWNSHIFT:
0835 return bcm54140_get_downshift(phydev, data);
0836 case ETHTOOL_PHY_EDPD:
0837 return bcm54140_get_edpd(phydev, data);
0838 default:
0839 return -EOPNOTSUPP;
0840 }
0841 }
0842
0843 static int bcm54140_set_tunable(struct phy_device *phydev,
0844 struct ethtool_tunable *tuna, const void *data)
0845 {
0846 switch (tuna->id) {
0847 case ETHTOOL_PHY_DOWNSHIFT:
0848 return bcm54140_set_downshift(phydev, *(const u8 *)data);
0849 case ETHTOOL_PHY_EDPD:
0850 return bcm54140_set_edpd(phydev, *(const u16 *)data);
0851 default:
0852 return -EOPNOTSUPP;
0853 }
0854 }
0855
0856 static struct phy_driver bcm54140_drivers[] = {
0857 {
0858 .phy_id = PHY_ID_BCM54140,
0859 .phy_id_mask = BCM54140_PHY_ID_MASK,
0860 .name = "Broadcom BCM54140",
0861 .flags = PHY_POLL_CABLE_TEST,
0862 .features = PHY_GBIT_FEATURES,
0863 .config_init = bcm54140_config_init,
0864 .handle_interrupt = bcm54140_handle_interrupt,
0865 .config_intr = bcm54140_config_intr,
0866 .probe = bcm54140_probe,
0867 .suspend = genphy_suspend,
0868 .resume = genphy_resume,
0869 .soft_reset = genphy_soft_reset,
0870 .get_tunable = bcm54140_get_tunable,
0871 .set_tunable = bcm54140_set_tunable,
0872 .cable_test_start = bcm_phy_cable_test_start_rdb,
0873 .cable_test_get_status = bcm_phy_cable_test_get_status_rdb,
0874 },
0875 };
0876 module_phy_driver(bcm54140_drivers);
0877
0878 static struct mdio_device_id __maybe_unused bcm54140_tbl[] = {
0879 { PHY_ID_BCM54140, BCM54140_PHY_ID_MASK },
0880 { }
0881 };
0882
0883 MODULE_AUTHOR("Michael Walle");
0884 MODULE_DESCRIPTION("Broadcom BCM54140 PHY driver");
0885 MODULE_DEVICE_TABLE(mdio, bcm54140_tbl);
0886 MODULE_LICENSE("GPL");