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
161175static 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+
523637static 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+
8531064static 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