Skip to content

Commit 56cfc97

Browse files
kmaincentkuba-moo
authored andcommitted
net: pse-pd: tps23881: Add support for static port priority feature
This patch enhances PSE callbacks by introducing support for the static port priority feature. It extends interrupt management to handle and report detection, classification, and disconnection events. Additionally, it introduces the pi_get_pw_req() callback, which provides information about the power requested by the Powered Devices. Interrupt support is essential for the proper functioning of the TPS23881 controller. Without it, after a power-on (PWON), the controller will no longer perform detection and classification. This could lead to potential hazards, such as connecting a non-PoE device after a PoE device, which might result in magic smoke. Signed-off-by: Kory Maincent (Dent Project) <kory.maincent@bootlin.com> Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de> Link: https://patch.msgid.link/20250617-feature_poe_port_prio-v14-12-78a1a645e2ee@bootlin.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 2903001 commit 56cfc97

File tree

1 file changed

+228
-16
lines changed

1 file changed

+228
-16
lines changed

drivers/net/pse-pd/tps23881.c

Lines changed: 228 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,30 @@
2020

2121
#define TPS23881_REG_IT 0x0
2222
#define TPS23881_REG_IT_MASK 0x1
23+
#define TPS23881_REG_IT_DISF BIT(2)
24+
#define TPS23881_REG_IT_DETC BIT(3)
25+
#define TPS23881_REG_IT_CLASC BIT(4)
2326
#define TPS23881_REG_IT_IFAULT BIT(5)
2427
#define TPS23881_REG_IT_SUPF BIT(7)
28+
#define TPS23881_REG_DET_EVENT 0x5
2529
#define TPS23881_REG_FAULT 0x7
2630
#define TPS23881_REG_SUPF_EVENT 0xb
2731
#define TPS23881_REG_TSD BIT(7)
32+
#define TPS23881_REG_DISC 0xc
2833
#define TPS23881_REG_PW_STATUS 0x10
2934
#define TPS23881_REG_OP_MODE 0x12
35+
#define TPS23881_REG_DISC_EN 0x13
3036
#define TPS23881_OP_MODE_SEMIAUTO 0xaaaa
3137
#define TPS23881_REG_DIS_EN 0x13
3238
#define TPS23881_REG_DET_CLA_EN 0x14
3339
#define TPS23881_REG_GEN_MASK 0x17
40+
#define TPS23881_REG_CLCHE BIT(2)
41+
#define TPS23881_REG_DECHE BIT(3)
3442
#define TPS23881_REG_NBITACC BIT(5)
3543
#define TPS23881_REG_INTEN BIT(7)
3644
#define TPS23881_REG_PW_EN 0x19
45+
#define TPS23881_REG_RESET 0x1a
46+
#define TPS23881_REG_CLRAIN BIT(7)
3747
#define TPS23881_REG_2PAIR_POL1 0x1e
3848
#define TPS23881_REG_PORT_MAP 0x26
3949
#define TPS23881_REG_PORT_POWER 0x29
@@ -178,6 +188,7 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
178188
struct i2c_client *client = priv->client;
179189
u8 chan;
180190
u16 val;
191+
int ret;
181192

182193
if (id >= TPS23881_MAX_CHANS)
183194
return -ERANGE;
@@ -191,7 +202,22 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
191202
BIT(chan % 4));
192203
}
193204

194-
return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
205+
ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
206+
if (ret)
207+
return ret;
208+
209+
/* Enable DC disconnect*/
210+
chan = priv->port[id].chan[0];
211+
ret = i2c_smbus_read_word_data(client, TPS23881_REG_DISC_EN);
212+
if (ret < 0)
213+
return ret;
214+
215+
val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
216+
ret = i2c_smbus_write_word_data(client, TPS23881_REG_DISC_EN, val);
217+
if (ret)
218+
return ret;
219+
220+
return 0;
195221
}
196222

197223
static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
@@ -224,6 +250,17 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
224250
*/
225251
mdelay(5);
226252

253+
/* Disable DC disconnect*/
254+
chan = priv->port[id].chan[0];
255+
ret = i2c_smbus_read_word_data(client, TPS23881_REG_DISC_EN);
256+
if (ret < 0)
257+
return ret;
258+
259+
val = tps23881_set_val(ret, chan, 0, 0, BIT(chan % 4));
260+
ret = i2c_smbus_write_word_data(client, TPS23881_REG_DISC_EN, val);
261+
if (ret)
262+
return ret;
263+
227264
/* Enable detection and classification */
228265
ret = i2c_smbus_read_word_data(client, TPS23881_REG_DET_CLA_EN);
229266
if (ret < 0)
@@ -919,6 +956,47 @@ static int tps23881_setup_pi_matrix(struct pse_controller_dev *pcdev)
919956
return ret;
920957
}
921958

959+
static int tps23881_power_class_table[] = {
960+
-ERANGE,
961+
4000,
962+
7000,
963+
15500,
964+
30000,
965+
15500,
966+
15500,
967+
-ERANGE,
968+
45000,
969+
60000,
970+
75000,
971+
90000,
972+
15500,
973+
45000,
974+
-ERANGE,
975+
-ERANGE,
976+
};
977+
978+
static int tps23881_pi_get_pw_req(struct pse_controller_dev *pcdev, int id)
979+
{
980+
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
981+
struct i2c_client *client = priv->client;
982+
u8 reg, chan;
983+
int ret;
984+
u16 val;
985+
986+
/* For a 4-pair the classification need 5ms to be completed */
987+
if (priv->port[id].is_4p)
988+
mdelay(5);
989+
990+
chan = priv->port[id].chan[0];
991+
reg = TPS23881_REG_DISC + (chan % 4);
992+
ret = i2c_smbus_read_word_data(client, reg);
993+
if (ret < 0)
994+
return ret;
995+
996+
val = tps23881_calc_val(ret, chan, 4, 0xf);
997+
return tps23881_power_class_table[val];
998+
}
999+
9221000
static const struct pse_controller_ops tps23881_ops = {
9231001
.setup_pi_matrix = tps23881_setup_pi_matrix,
9241002
.pi_enable = tps23881_pi_enable,
@@ -931,6 +1009,7 @@ static const struct pse_controller_ops tps23881_ops = {
9311009
.pi_get_pw_limit = tps23881_pi_get_pw_limit,
9321010
.pi_set_pw_limit = tps23881_pi_set_pw_limit,
9331011
.pi_get_pw_limit_ranges = tps23881_pi_get_pw_limit_ranges,
1012+
.pi_get_pw_req = tps23881_pi_get_pw_req,
9341013
};
9351014

9361015
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
@@ -1088,25 +1167,121 @@ static void tps23881_irq_event_over_temp(struct tps23881_priv *priv,
10881167
}
10891168
}
10901169

1091-
static void tps23881_irq_event_over_current(struct tps23881_priv *priv,
1092-
u16 reg_val,
1093-
unsigned long *notifs,
1094-
unsigned long *notifs_mask)
1170+
static int tps23881_irq_event_over_current(struct tps23881_priv *priv,
1171+
u16 reg_val,
1172+
unsigned long *notifs,
1173+
unsigned long *notifs_mask)
10951174
{
1175+
int i, ret;
10961176
u8 chans;
10971177

10981178
chans = tps23881_irq_export_chans_helper(reg_val, 0);
1179+
if (!chans)
1180+
return 0;
1181+
1182+
tps23881_set_notifs_helper(priv, chans, notifs, notifs_mask,
1183+
ETHTOOL_PSE_EVENT_OVER_CURRENT |
1184+
ETHTOOL_C33_PSE_EVENT_DISCONNECTION);
1185+
1186+
/* Over Current event resets the power limit registers so we need
1187+
* to configured it again.
1188+
*/
1189+
for_each_set_bit(i, notifs_mask, priv->pcdev.nr_lines) {
1190+
if (priv->port[i].pw_pol < 0)
1191+
continue;
1192+
1193+
ret = tps23881_pi_enable_manual_pol(priv, i);
1194+
if (ret < 0)
1195+
return ret;
1196+
1197+
/* Set power policy */
1198+
ret = tps23881_pi_set_pw_pol_limit(priv, i,
1199+
priv->port[i].pw_pol,
1200+
priv->port[i].is_4p);
1201+
if (ret < 0)
1202+
return ret;
1203+
}
1204+
1205+
return 0;
1206+
}
1207+
1208+
static void tps23881_irq_event_disconnection(struct tps23881_priv *priv,
1209+
u16 reg_val,
1210+
unsigned long *notifs,
1211+
unsigned long *notifs_mask)
1212+
{
1213+
u8 chans;
1214+
1215+
chans = tps23881_irq_export_chans_helper(reg_val, 4);
10991216
if (chans)
11001217
tps23881_set_notifs_helper(priv, chans, notifs, notifs_mask,
1101-
ETHTOOL_PSE_EVENT_OVER_CURRENT);
1218+
ETHTOOL_C33_PSE_EVENT_DISCONNECTION);
1219+
}
1220+
1221+
static int tps23881_irq_event_detection(struct tps23881_priv *priv,
1222+
u16 reg_val,
1223+
unsigned long *notifs,
1224+
unsigned long *notifs_mask)
1225+
{
1226+
enum ethtool_pse_event event;
1227+
int reg, ret, i, val;
1228+
unsigned long chans;
1229+
1230+
chans = tps23881_irq_export_chans_helper(reg_val, 0);
1231+
for_each_set_bit(i, &chans, TPS23881_MAX_CHANS) {
1232+
reg = TPS23881_REG_DISC + (i % 4);
1233+
ret = i2c_smbus_read_word_data(priv->client, reg);
1234+
if (ret < 0)
1235+
return ret;
1236+
1237+
val = tps23881_calc_val(ret, i, 0, 0xf);
1238+
/* If detection valid */
1239+
if (val == 0x4)
1240+
event = ETHTOOL_C33_PSE_EVENT_DETECTION;
1241+
else
1242+
event = ETHTOOL_C33_PSE_EVENT_DISCONNECTION;
1243+
1244+
tps23881_set_notifs_helper(priv, BIT(i), notifs,
1245+
notifs_mask, event);
1246+
}
1247+
1248+
return 0;
1249+
}
1250+
1251+
static int tps23881_irq_event_classification(struct tps23881_priv *priv,
1252+
u16 reg_val,
1253+
unsigned long *notifs,
1254+
unsigned long *notifs_mask)
1255+
{
1256+
int reg, ret, val, i;
1257+
unsigned long chans;
1258+
1259+
chans = tps23881_irq_export_chans_helper(reg_val, 4);
1260+
for_each_set_bit(i, &chans, TPS23881_MAX_CHANS) {
1261+
reg = TPS23881_REG_DISC + (i % 4);
1262+
ret = i2c_smbus_read_word_data(priv->client, reg);
1263+
if (ret < 0)
1264+
return ret;
1265+
1266+
val = tps23881_calc_val(ret, i, 4, 0xf);
1267+
/* Do not report classification event for unknown class */
1268+
if (!val || val == 0x8 || val == 0xf)
1269+
continue;
1270+
1271+
tps23881_set_notifs_helper(priv, BIT(i), notifs,
1272+
notifs_mask,
1273+
ETHTOOL_C33_PSE_EVENT_CLASSIFICATION);
1274+
}
1275+
1276+
return 0;
11021277
}
11031278

11041279
static int tps23881_irq_event_handler(struct tps23881_priv *priv, u16 reg,
11051280
unsigned long *notifs,
11061281
unsigned long *notifs_mask)
11071282
{
11081283
struct i2c_client *client = priv->client;
1109-
int ret;
1284+
int ret, val;
11101285

11111286
/* The Supply event bit is repeated twice so we only need to read
11121287
* the one from the first byte.
@@ -1118,13 +1293,36 @@ static int tps23881_irq_event_handler(struct tps23881_priv *priv, u16 reg,
11181293
tps23881_irq_event_over_temp(priv, ret, notifs, notifs_mask);
11191294
}
11201295

1121-
if (reg & (TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_IFAULT << 8)) {
1296+
if (reg & (TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_IFAULT << 8 |
1297+
TPS23881_REG_IT_DISF | TPS23881_REG_IT_DISF << 8)) {
11221298
ret = i2c_smbus_read_word_data(client, TPS23881_REG_FAULT);
11231299
if (ret < 0)
11241300
return ret;
1125-
tps23881_irq_event_over_current(priv, ret, notifs, notifs_mask);
1301+
ret = tps23881_irq_event_over_current(priv, ret, notifs,
1302+
notifs_mask);
1303+
if (ret)
1304+
return ret;
1305+
1306+
tps23881_irq_event_disconnection(priv, ret, notifs, notifs_mask);
11261307
}
11271308

1309+
if (reg & (TPS23881_REG_IT_DETC | TPS23881_REG_IT_DETC << 8 |
1310+
TPS23881_REG_IT_CLASC | TPS23881_REG_IT_CLASC << 8)) {
1311+
ret = i2c_smbus_read_word_data(client, TPS23881_REG_DET_EVENT);
1312+
if (ret < 0)
1313+
return ret;
1314+
1315+
val = ret;
1316+
ret = tps23881_irq_event_detection(priv, val, notifs,
1317+
notifs_mask);
1318+
if (ret)
1319+
return ret;
1320+
1321+
ret = tps23881_irq_event_classification(priv, val, notifs,
1322+
notifs_mask);
1323+
if (ret)
1324+
return ret;
1325+
}
11281326
return 0;
11291327
}
11301328

@@ -1178,7 +1376,14 @@ static int tps23881_setup_irq(struct tps23881_priv *priv, int irq)
11781376
int ret;
11791377
u16 val;
11801378

1181-
val = TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_SUPF;
1379+
if (!irq) {
1380+
dev_err(&client->dev, "interrupt is missing");
1381+
return -EINVAL;
1382+
}
1383+
1384+
val = TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_SUPF |
1385+
TPS23881_REG_IT_DETC | TPS23881_REG_IT_CLASC |
1386+
TPS23881_REG_IT_DISF;
11821387
val |= val << 8;
11831388
ret = i2c_smbus_write_word_data(client, TPS23881_REG_IT_MASK, val);
11841389
if (ret)
@@ -1188,11 +1393,19 @@ static int tps23881_setup_irq(struct tps23881_priv *priv, int irq)
11881393
if (ret < 0)
11891394
return ret;
11901395

1191-
val = (u16)(ret | TPS23881_REG_INTEN | TPS23881_REG_INTEN << 8);
1396+
val = TPS23881_REG_INTEN | TPS23881_REG_CLCHE | TPS23881_REG_DECHE;
1397+
val |= val << 8;
1398+
val |= (u16)ret;
11921399
ret = i2c_smbus_write_word_data(client, TPS23881_REG_GEN_MASK, val);
11931400
if (ret < 0)
11941401
return ret;
11951402

1403+
/* Reset interrupts registers */
1404+
ret = i2c_smbus_write_word_data(client, TPS23881_REG_RESET,
1405+
TPS23881_REG_CLRAIN);
1406+
if (ret < 0)
1407+
return ret;
1408+
11961409
return devm_pse_irq_helper(&priv->pcdev, irq, 0, &irq_desc);
11971410
}
11981411

@@ -1270,17 +1483,16 @@ static int tps23881_i2c_probe(struct i2c_client *client)
12701483
priv->pcdev.dev = dev;
12711484
priv->pcdev.types = ETHTOOL_PSE_C33;
12721485
priv->pcdev.nr_lines = TPS23881_MAX_CHANS;
1486+
priv->pcdev.supp_budget_eval_strategies = PSE_BUDGET_EVAL_STRAT_STATIC;
12731487
ret = devm_pse_controller_register(dev, &priv->pcdev);
12741488
if (ret) {
12751489
return dev_err_probe(dev, ret,
12761490
"failed to register PSE controller\n");
12771491
}
12781492

1279-
if (client->irq) {
1280-
ret = tps23881_setup_irq(priv, client->irq);
1281-
if (ret)
1282-
return ret;
1283-
}
1493+
ret = tps23881_setup_irq(priv, client->irq);
1494+
if (ret)
1495+
return ret;
12841496

12851497
return ret;
12861498
}

0 commit comments

Comments
 (0)