0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/property.h>
0011 #include <linux/usb/pd.h>
0012
0013 #include "ucsi.h"
0014
0015
0016 enum ucsi_psy_online_states {
0017 UCSI_PSY_OFFLINE = 0,
0018 UCSI_PSY_FIXED_ONLINE,
0019 UCSI_PSY_PROG_ONLINE,
0020 };
0021
0022 static enum power_supply_property ucsi_psy_props[] = {
0023 POWER_SUPPLY_PROP_USB_TYPE,
0024 POWER_SUPPLY_PROP_ONLINE,
0025 POWER_SUPPLY_PROP_VOLTAGE_MIN,
0026 POWER_SUPPLY_PROP_VOLTAGE_MAX,
0027 POWER_SUPPLY_PROP_VOLTAGE_NOW,
0028 POWER_SUPPLY_PROP_CURRENT_MAX,
0029 POWER_SUPPLY_PROP_CURRENT_NOW,
0030 };
0031
0032 static int ucsi_psy_get_online(struct ucsi_connector *con,
0033 union power_supply_propval *val)
0034 {
0035 val->intval = UCSI_PSY_OFFLINE;
0036 if (con->status.flags & UCSI_CONSTAT_CONNECTED &&
0037 (con->status.flags & UCSI_CONSTAT_PWR_DIR) == TYPEC_SINK)
0038 val->intval = UCSI_PSY_FIXED_ONLINE;
0039 return 0;
0040 }
0041
0042 static int ucsi_psy_get_voltage_min(struct ucsi_connector *con,
0043 union power_supply_propval *val)
0044 {
0045 u32 pdo;
0046
0047 switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
0048 case UCSI_CONSTAT_PWR_OPMODE_PD:
0049 pdo = con->src_pdos[0];
0050 val->intval = pdo_fixed_voltage(pdo) * 1000;
0051 break;
0052 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
0053 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
0054 case UCSI_CONSTAT_PWR_OPMODE_BC:
0055 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT:
0056 val->intval = UCSI_TYPEC_VSAFE5V * 1000;
0057 break;
0058 default:
0059 val->intval = 0;
0060 break;
0061 }
0062 return 0;
0063 }
0064
0065 static int ucsi_psy_get_voltage_max(struct ucsi_connector *con,
0066 union power_supply_propval *val)
0067 {
0068 u32 pdo;
0069
0070 switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
0071 case UCSI_CONSTAT_PWR_OPMODE_PD:
0072 if (con->num_pdos > 0) {
0073 pdo = con->src_pdos[con->num_pdos - 1];
0074 val->intval = pdo_fixed_voltage(pdo) * 1000;
0075 } else {
0076 val->intval = 0;
0077 }
0078 break;
0079 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
0080 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
0081 case UCSI_CONSTAT_PWR_OPMODE_BC:
0082 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT:
0083 val->intval = UCSI_TYPEC_VSAFE5V * 1000;
0084 break;
0085 default:
0086 val->intval = 0;
0087 break;
0088 }
0089 return 0;
0090 }
0091
0092 static int ucsi_psy_get_voltage_now(struct ucsi_connector *con,
0093 union power_supply_propval *val)
0094 {
0095 int index;
0096 u32 pdo;
0097
0098 switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
0099 case UCSI_CONSTAT_PWR_OPMODE_PD:
0100 index = rdo_index(con->rdo);
0101 if (index > 0) {
0102 pdo = con->src_pdos[index - 1];
0103 val->intval = pdo_fixed_voltage(pdo) * 1000;
0104 } else {
0105 val->intval = 0;
0106 }
0107 break;
0108 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
0109 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
0110 case UCSI_CONSTAT_PWR_OPMODE_BC:
0111 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT:
0112 val->intval = UCSI_TYPEC_VSAFE5V * 1000;
0113 break;
0114 default:
0115 val->intval = 0;
0116 break;
0117 }
0118 return 0;
0119 }
0120
0121 static int ucsi_psy_get_current_max(struct ucsi_connector *con,
0122 union power_supply_propval *val)
0123 {
0124 u32 pdo;
0125
0126 switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
0127 case UCSI_CONSTAT_PWR_OPMODE_PD:
0128 if (con->num_pdos > 0) {
0129 pdo = con->src_pdos[con->num_pdos - 1];
0130 val->intval = pdo_max_current(pdo) * 1000;
0131 } else {
0132 val->intval = 0;
0133 }
0134 break;
0135 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
0136 val->intval = UCSI_TYPEC_1_5_CURRENT * 1000;
0137 break;
0138 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
0139 val->intval = UCSI_TYPEC_3_0_CURRENT * 1000;
0140 break;
0141 case UCSI_CONSTAT_PWR_OPMODE_BC:
0142 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT:
0143
0144 default:
0145 val->intval = 0;
0146 break;
0147 }
0148 return 0;
0149 }
0150
0151 static int ucsi_psy_get_current_now(struct ucsi_connector *con,
0152 union power_supply_propval *val)
0153 {
0154 u16 flags = con->status.flags;
0155
0156 if (UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD)
0157 val->intval = rdo_op_current(con->rdo) * 1000;
0158 else
0159 val->intval = 0;
0160 return 0;
0161 }
0162
0163 static int ucsi_psy_get_usb_type(struct ucsi_connector *con,
0164 union power_supply_propval *val)
0165 {
0166 u16 flags = con->status.flags;
0167
0168 val->intval = POWER_SUPPLY_USB_TYPE_C;
0169 if (flags & UCSI_CONSTAT_CONNECTED &&
0170 UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD)
0171 val->intval = POWER_SUPPLY_USB_TYPE_PD;
0172
0173 return 0;
0174 }
0175
0176 static int ucsi_psy_get_prop(struct power_supply *psy,
0177 enum power_supply_property psp,
0178 union power_supply_propval *val)
0179 {
0180 struct ucsi_connector *con = power_supply_get_drvdata(psy);
0181
0182 switch (psp) {
0183 case POWER_SUPPLY_PROP_USB_TYPE:
0184 return ucsi_psy_get_usb_type(con, val);
0185 case POWER_SUPPLY_PROP_ONLINE:
0186 return ucsi_psy_get_online(con, val);
0187 case POWER_SUPPLY_PROP_VOLTAGE_MIN:
0188 return ucsi_psy_get_voltage_min(con, val);
0189 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
0190 return ucsi_psy_get_voltage_max(con, val);
0191 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0192 return ucsi_psy_get_voltage_now(con, val);
0193 case POWER_SUPPLY_PROP_CURRENT_MAX:
0194 return ucsi_psy_get_current_max(con, val);
0195 case POWER_SUPPLY_PROP_CURRENT_NOW:
0196 return ucsi_psy_get_current_now(con, val);
0197 default:
0198 return -EINVAL;
0199 }
0200 }
0201
0202 static enum power_supply_usb_type ucsi_psy_usb_types[] = {
0203 POWER_SUPPLY_USB_TYPE_C,
0204 POWER_SUPPLY_USB_TYPE_PD,
0205 POWER_SUPPLY_USB_TYPE_PD_PPS,
0206 };
0207
0208 int ucsi_register_port_psy(struct ucsi_connector *con)
0209 {
0210 struct power_supply_config psy_cfg = {};
0211 struct device *dev = con->ucsi->dev;
0212 char *psy_name;
0213
0214 psy_cfg.drv_data = con;
0215 psy_cfg.fwnode = dev_fwnode(dev);
0216
0217 psy_name = devm_kasprintf(dev, GFP_KERNEL, "ucsi-source-psy-%s%d",
0218 dev_name(dev), con->num);
0219 if (!psy_name)
0220 return -ENOMEM;
0221
0222 con->psy_desc.name = psy_name;
0223 con->psy_desc.type = POWER_SUPPLY_TYPE_USB;
0224 con->psy_desc.usb_types = ucsi_psy_usb_types;
0225 con->psy_desc.num_usb_types = ARRAY_SIZE(ucsi_psy_usb_types);
0226 con->psy_desc.properties = ucsi_psy_props;
0227 con->psy_desc.num_properties = ARRAY_SIZE(ucsi_psy_props);
0228 con->psy_desc.get_property = ucsi_psy_get_prop;
0229
0230 con->psy = power_supply_register(dev, &con->psy_desc, &psy_cfg);
0231
0232 return PTR_ERR_OR_ZERO(con->psy);
0233 }
0234
0235 void ucsi_unregister_port_psy(struct ucsi_connector *con)
0236 {
0237 if (IS_ERR_OR_NULL(con->psy))
0238 return;
0239
0240 power_supply_unregister(con->psy);
0241 con->psy = NULL;
0242 }
0243
0244 void ucsi_port_psy_changed(struct ucsi_connector *con)
0245 {
0246 if (IS_ERR_OR_NULL(con->psy))
0247 return;
0248
0249 power_supply_changed(con->psy);
0250 }