74
74
PD692X0_MSG_GET_PORT_STATUS ,
75
75
PD692X0_MSG_DOWNLOAD_CMD ,
76
76
PD692X0_MSG_GET_PORT_CLASS ,
77
+ PD692X0_MSG_GET_PORT_MEAS ,
78
+ PD692X0_MSG_GET_PORT_PARAM ,
77
79
78
80
/* add new message above here */
79
81
PD692X0_MSG_CNT
@@ -135,7 +137,7 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
135
137
[PD692X0_MSG_SET_PORT_PARAM ] = {
136
138
.key = PD692X0_KEY_CMD ,
137
139
.sub = {0x05 , 0xc0 },
138
- .data = { 0 , 0xff , 0xff , 0xff ,
140
+ .data = { 0xf , 0xff , 0xff , 0xff ,
139
141
0x4e , 0x4e , 0x4e , 0x4e },
140
142
},
141
143
[PD692X0_MSG_GET_PORT_STATUS ] = {
@@ -156,6 +158,18 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
156
158
.data = {0x4e , 0x4e , 0x4e , 0x4e ,
157
159
0x4e , 0x4e , 0x4e , 0x4e },
158
160
},
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
+ },
159
173
};
160
174
161
175
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,
520
534
}
521
535
}
522
536
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
+
523
637
static int pd692x0_ethtool_get_status (struct pse_controller_dev * pcdev ,
524
638
unsigned long id ,
525
639
struct netlink_ext_ack * extack ,
@@ -558,9 +672,20 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
558
672
priv -> admin_state [id ] = status -> c33_admin_state ;
559
673
560
674
pd692x0_get_ext_state (& status -> c33_ext_state_info , buf .sub [0 ]);
561
-
562
675
status -> c33_actual_pw = (buf .data [0 ] << 4 | buf .data [1 ]) * 100 ;
563
676
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
+
564
689
memset (& buf , 0 , sizeof (buf ));
565
690
msg = pd692x0_msg_template_list [PD692X0_MSG_GET_PORT_CLASS ];
566
691
msg .sub [2 ] = id ;
@@ -572,6 +697,10 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
572
697
if (class <= 8 )
573
698
status -> c33_pw_class = class ;
574
699
700
+ ret = pd692x0_pi_get_pw_ranges (status );
701
+ if (ret < 0 )
702
+ return ret ;
703
+
575
704
return 0 ;
576
705
}
577
706
@@ -850,12 +979,97 @@ static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev)
850
979
return ret ;
851
980
}
852
981
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
+
853
1064
static const struct pse_controller_ops pd692x0_ops = {
854
1065
.setup_pi_matrix = pd692x0_setup_pi_matrix ,
855
1066
.ethtool_get_status = pd692x0_ethtool_get_status ,
856
1067
.pi_enable = pd692x0_pi_enable ,
857
1068
.pi_disable = pd692x0_pi_disable ,
858
1069
.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 ,
859
1073
};
860
1074
861
1075
#define PD692X0_FW_LINE_MAX_SZ 0xff
0 commit comments