Skip to content

Commit a87e699

Browse files
kmaincentkuba-moo
authored andcommitted
net: pse-pd: pd692x0: Enhance with new current limit and voltage read callbacks
This patch expands PSE callbacks with newly introduced pi_get/set_current_limit() and pi_get_voltage() callback. It also add the power limit ranges description in the status returned. The only way to set ps692x0 port power limit is by configure the power class plus a small power supplement which maximum depends on each class. Acked-by: Oleksij Rempel <[email protected]> Signed-off-by: Kory Maincent <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent dac3de1 commit a87e699

File tree

1 file changed

+216
-2
lines changed

1 file changed

+216
-2
lines changed

drivers/net/pse-pd/pd692x0.c

Lines changed: 216 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ enum {
7474
PD692X0_MSG_GET_PORT_STATUS,
7575
PD692X0_MSG_DOWNLOAD_CMD,
7676
PD692X0_MSG_GET_PORT_CLASS,
77+
PD692X0_MSG_GET_PORT_MEAS,
78+
PD692X0_MSG_GET_PORT_PARAM,
7779

7880
/* add new message above here */
7981
PD692X0_MSG_CNT
@@ -135,7 +137,7 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
135137
[PD692X0_MSG_SET_PORT_PARAM] = {
136138
.key = PD692X0_KEY_CMD,
137139
.sub = {0x05, 0xc0},
138-
.data = { 0, 0xff, 0xff, 0xff,
140+
.data = { 0xf, 0xff, 0xff, 0xff,
139141
0x4e, 0x4e, 0x4e, 0x4e},
140142
},
141143
[PD692X0_MSG_GET_PORT_STATUS] = {
@@ -156,6 +158,18 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
156158
.data = {0x4e, 0x4e, 0x4e, 0x4e,
157159
0x4e, 0x4e, 0x4e, 0x4e},
158160
},
161+
[PD692X0_MSG_GET_PORT_MEAS] = {
162+
.key = PD692X0_KEY_REQ,
163+
.sub = {0x05, 0xc5},
164+
.data = {0x4e, 0x4e, 0x4e, 0x4e,
165+
0x4e, 0x4e, 0x4e, 0x4e},
166+
},
167+
[PD692X0_MSG_GET_PORT_PARAM] = {
168+
.key = PD692X0_KEY_REQ,
169+
.sub = {0x05, 0xc0},
170+
.data = {0x4e, 0x4e, 0x4e, 0x4e,
171+
0x4e, 0x4e, 0x4e, 0x4e},
172+
},
159173
};
160174

161175
static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo)
@@ -520,6 +534,106 @@ pd692x0_get_ext_state(struct ethtool_c33_pse_ext_state_info *c33_ext_state_info,
520534
}
521535
}
522536

537+
struct pd692x0_class_pw {
538+
int class;
539+
int class_cfg_value;
540+
int class_pw;
541+
int max_added_class_pw;
542+
};
543+
544+
#define PD692X0_CLASS_PW_TABLE_SIZE 4
545+
/* 4/2 pairs class configuration power table in compliance mode.
546+
* Need to be arranged in ascending order of power support.
547+
*/
548+
static const struct pd692x0_class_pw
549+
pd692x0_class_pw_table[PD692X0_CLASS_PW_TABLE_SIZE] = {
550+
{.class = 3, .class_cfg_value = 0x3, .class_pw = 15000, .max_added_class_pw = 3100},
551+
{.class = 4, .class_cfg_value = 0x2, .class_pw = 30000, .max_added_class_pw = 8000},
552+
{.class = 6, .class_cfg_value = 0x1, .class_pw = 60000, .max_added_class_pw = 5000},
553+
{.class = 8, .class_cfg_value = 0x0, .class_pw = 90000, .max_added_class_pw = 7500},
554+
};
555+
556+
static int pd692x0_pi_get_pw_from_table(int op_mode, int added_pw)
557+
{
558+
const struct pd692x0_class_pw *pw_table;
559+
int i;
560+
561+
pw_table = pd692x0_class_pw_table;
562+
for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
563+
if (pw_table->class_cfg_value == op_mode)
564+
return pw_table->class_pw + added_pw * 100;
565+
}
566+
567+
return -ERANGE;
568+
}
569+
570+
static int pd692x0_pi_set_pw_from_table(struct device *dev,
571+
struct pd692x0_msg *msg, int pw)
572+
{
573+
const struct pd692x0_class_pw *pw_table;
574+
int i;
575+
576+
pw_table = pd692x0_class_pw_table;
577+
if (pw < pw_table->class_pw) {
578+
dev_err(dev,
579+
"Power limit %dmW not supported. Ranges minimal available: [%d-%d]\n",
580+
pw,
581+
pw_table->class_pw,
582+
pw_table->class_pw + pw_table->max_added_class_pw);
583+
return -ERANGE;
584+
}
585+
586+
for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
587+
if (pw > (pw_table->class_pw + pw_table->max_added_class_pw))
588+
continue;
589+
590+
if (pw < pw_table->class_pw) {
591+
dev_err(dev,
592+
"Power limit %dmW not supported. Ranges availables: [%d-%d] or [%d-%d]\n",
593+
pw,
594+
(pw_table - 1)->class_pw,
595+
(pw_table - 1)->class_pw + (pw_table - 1)->max_added_class_pw,
596+
pw_table->class_pw,
597+
pw_table->class_pw + pw_table->max_added_class_pw);
598+
return -ERANGE;
599+
}
600+
601+
msg->data[2] = pw_table->class_cfg_value;
602+
msg->data[3] = (pw - pw_table->class_pw) / 100;
603+
return 0;
604+
}
605+
606+
pw_table--;
607+
dev_warn(dev,
608+
"Power limit %dmW not supported. Set to highest power limit %dmW\n",
609+
pw, pw_table->class_pw + pw_table->max_added_class_pw);
610+
msg->data[2] = pw_table->class_cfg_value;
611+
msg->data[3] = pw_table->max_added_class_pw / 100;
612+
return 0;
613+
}
614+
615+
static int
616+
pd692x0_pi_get_pw_ranges(struct pse_control_status *st)
617+
{
618+
const struct pd692x0_class_pw *pw_table;
619+
int i;
620+
621+
pw_table = pd692x0_class_pw_table;
622+
st->c33_pw_limit_ranges = kcalloc(PD692X0_CLASS_PW_TABLE_SIZE,
623+
sizeof(struct ethtool_c33_pse_pw_limit_range),
624+
GFP_KERNEL);
625+
if (!st->c33_pw_limit_ranges)
626+
return -ENOMEM;
627+
628+
for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
629+
st->c33_pw_limit_ranges[i].min = pw_table->class_pw;
630+
st->c33_pw_limit_ranges[i].max = pw_table->class_pw + pw_table->max_added_class_pw;
631+
}
632+
633+
st->c33_pw_limit_nb_ranges = i;
634+
return 0;
635+
}
636+
523637
static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
524638
unsigned long id,
525639
struct netlink_ext_ack *extack,
@@ -558,9 +672,20 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
558672
priv->admin_state[id] = status->c33_admin_state;
559673

560674
pd692x0_get_ext_state(&status->c33_ext_state_info, buf.sub[0]);
561-
562675
status->c33_actual_pw = (buf.data[0] << 4 | buf.data[1]) * 100;
563676

677+
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
678+
msg.sub[2] = id;
679+
memset(&buf, 0, sizeof(buf));
680+
ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
681+
if (ret < 0)
682+
return ret;
683+
684+
ret = pd692x0_pi_get_pw_from_table(buf.data[0], buf.data[1]);
685+
if (ret < 0)
686+
return ret;
687+
status->c33_avail_pw_limit = ret;
688+
564689
memset(&buf, 0, sizeof(buf));
565690
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_CLASS];
566691
msg.sub[2] = id;
@@ -572,6 +697,10 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
572697
if (class <= 8)
573698
status->c33_pw_class = class;
574699

700+
ret = pd692x0_pi_get_pw_ranges(status);
701+
if (ret < 0)
702+
return ret;
703+
575704
return 0;
576705
}
577706

@@ -850,12 +979,97 @@ static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev)
850979
return ret;
851980
}
852981

982+
static int pd692x0_pi_get_voltage(struct pse_controller_dev *pcdev, int id)
983+
{
984+
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
985+
struct pd692x0_msg msg, buf = {0};
986+
int ret;
987+
988+
ret = pd692x0_fw_unavailable(priv);
989+
if (ret)
990+
return ret;
991+
992+
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_MEAS];
993+
msg.sub[2] = id;
994+
ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
995+
if (ret < 0)
996+
return ret;
997+
998+
/* Convert 0.1V unit to uV */
999+
return (buf.sub[0] << 8 | buf.sub[1]) * 100000;
1000+
}
1001+
1002+
static int pd692x0_pi_get_current_limit(struct pse_controller_dev *pcdev,
1003+
int id)
1004+
{
1005+
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
1006+
struct pd692x0_msg msg, buf = {0};
1007+
int mW, uV, uA, ret;
1008+
s64 tmp_64;
1009+
1010+
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
1011+
msg.sub[2] = id;
1012+
ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
1013+
if (ret < 0)
1014+
return ret;
1015+
1016+
ret = pd692x0_pi_get_pw_from_table(buf.data[2], buf.data[3]);
1017+
if (ret < 0)
1018+
return ret;
1019+
mW = ret;
1020+
1021+
ret = pd692x0_pi_get_voltage(pcdev, id);
1022+
if (ret < 0)
1023+
return ret;
1024+
uV = ret;
1025+
1026+
tmp_64 = mW;
1027+
tmp_64 *= 1000000000ull;
1028+
/* uA = mW * 1000000000 / uV */
1029+
uA = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
1030+
return uA;
1031+
}
1032+
1033+
static int pd692x0_pi_set_current_limit(struct pse_controller_dev *pcdev,
1034+
int id, int max_uA)
1035+
{
1036+
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
1037+
struct device *dev = &priv->client->dev;
1038+
struct pd692x0_msg msg, buf = {0};
1039+
int uV, ret, mW;
1040+
s64 tmp_64;
1041+
1042+
ret = pd692x0_fw_unavailable(priv);
1043+
if (ret)
1044+
return ret;
1045+
1046+
ret = pd692x0_pi_get_voltage(pcdev, id);
1047+
if (ret < 0)
1048+
return ret;
1049+
uV = ret;
1050+
1051+
msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
1052+
msg.sub[2] = id;
1053+
tmp_64 = uV;
1054+
tmp_64 *= max_uA;
1055+
/* mW = uV * uA / 1000000000 */
1056+
mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
1057+
ret = pd692x0_pi_set_pw_from_table(dev, &msg, mW);
1058+
if (ret)
1059+
return ret;
1060+
1061+
return pd692x0_sendrecv_msg(priv, &msg, &buf);
1062+
}
1063+
8531064
static const struct pse_controller_ops pd692x0_ops = {
8541065
.setup_pi_matrix = pd692x0_setup_pi_matrix,
8551066
.ethtool_get_status = pd692x0_ethtool_get_status,
8561067
.pi_enable = pd692x0_pi_enable,
8571068
.pi_disable = pd692x0_pi_disable,
8581069
.pi_is_enabled = pd692x0_pi_is_enabled,
1070+
.pi_get_voltage = pd692x0_pi_get_voltage,
1071+
.pi_get_current_limit = pd692x0_pi_get_current_limit,
1072+
.pi_set_current_limit = pd692x0_pi_set_current_limit,
8591073
};
8601074

8611075
#define PD692X0_FW_LINE_MAX_SZ 0xff

0 commit comments

Comments
 (0)