1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Power Supply for UCSI 4 * 5 * Copyright (C) 2020, Intel Corporation 6 * Author: K V, Abhilash <abhilash.k.v@intel.com> 7 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 8 */ 9 10 #include <linux/property.h> 11 #include <linux/usb/pd.h> 12 13 #include "ucsi.h" 14 15 /* Power Supply access to expose source power information */ 16 enum ucsi_psy_online_states { 17 UCSI_PSY_OFFLINE = 0, 18 UCSI_PSY_FIXED_ONLINE, 19 UCSI_PSY_PROG_ONLINE, 20 }; 21 22 static enum power_supply_property ucsi_psy_props[] = { 23 POWER_SUPPLY_PROP_CHARGE_TYPE, 24 POWER_SUPPLY_PROP_USB_TYPE, 25 POWER_SUPPLY_PROP_ONLINE, 26 POWER_SUPPLY_PROP_VOLTAGE_MIN, 27 POWER_SUPPLY_PROP_VOLTAGE_MAX, 28 POWER_SUPPLY_PROP_VOLTAGE_NOW, 29 POWER_SUPPLY_PROP_CURRENT_MAX, 30 POWER_SUPPLY_PROP_CURRENT_NOW, 31 POWER_SUPPLY_PROP_SCOPE, 32 }; 33 34 static int ucsi_psy_get_scope(struct ucsi_connector *con, 35 union power_supply_propval *val) 36 { 37 u8 scope = POWER_SUPPLY_SCOPE_UNKNOWN; 38 struct device *dev = con->ucsi->dev; 39 40 device_property_read_u8(dev, "scope", &scope); 41 if (scope == POWER_SUPPLY_SCOPE_UNKNOWN) { 42 u32 mask = UCSI_CAP_ATTR_POWER_AC_SUPPLY | 43 UCSI_CAP_ATTR_BATTERY_CHARGING; 44 45 if (con->ucsi->cap.attributes & mask) 46 scope = POWER_SUPPLY_SCOPE_SYSTEM; 47 else 48 scope = POWER_SUPPLY_SCOPE_DEVICE; 49 } 50 val->intval = scope; 51 return 0; 52 } 53 54 static int ucsi_psy_get_online(struct ucsi_connector *con, 55 union power_supply_propval *val) 56 { 57 val->intval = UCSI_PSY_OFFLINE; 58 if (UCSI_CONSTAT(con, CONNECTED) && 59 (UCSI_CONSTAT(con, PWR_DIR) == TYPEC_SINK)) 60 val->intval = UCSI_PSY_FIXED_ONLINE; 61 return 0; 62 } 63 64 static int ucsi_psy_get_voltage_min(struct ucsi_connector *con, 65 union power_supply_propval *val) 66 { 67 u32 pdo; 68 69 switch (UCSI_CONSTAT(con, PWR_OPMODE)) { 70 case UCSI_CONSTAT_PWR_OPMODE_PD: 71 pdo = con->src_pdos[0]; 72 val->intval = pdo_fixed_voltage(pdo) * 1000; 73 break; 74 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: 75 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: 76 case UCSI_CONSTAT_PWR_OPMODE_BC: 77 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: 78 val->intval = UCSI_TYPEC_VSAFE5V * 1000; 79 break; 80 default: 81 val->intval = 0; 82 break; 83 } 84 return 0; 85 } 86 87 static int ucsi_psy_get_voltage_max(struct ucsi_connector *con, 88 union power_supply_propval *val) 89 { 90 u32 pdo; 91 92 switch (UCSI_CONSTAT(con, PWR_OPMODE)) { 93 case UCSI_CONSTAT_PWR_OPMODE_PD: 94 if (con->num_pdos > 0) { 95 pdo = con->src_pdos[con->num_pdos - 1]; 96 val->intval = pdo_fixed_voltage(pdo) * 1000; 97 } else { 98 val->intval = 0; 99 } 100 break; 101 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: 102 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: 103 case UCSI_CONSTAT_PWR_OPMODE_BC: 104 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: 105 val->intval = UCSI_TYPEC_VSAFE5V * 1000; 106 break; 107 default: 108 val->intval = 0; 109 break; 110 } 111 return 0; 112 } 113 114 static int ucsi_psy_get_voltage_now(struct ucsi_connector *con, 115 union power_supply_propval *val) 116 { 117 int index; 118 u32 pdo; 119 120 switch (UCSI_CONSTAT(con, PWR_OPMODE)) { 121 case UCSI_CONSTAT_PWR_OPMODE_PD: 122 index = rdo_index(con->rdo); 123 if (index > 0) { 124 pdo = con->src_pdos[index - 1]; 125 val->intval = pdo_fixed_voltage(pdo) * 1000; 126 } else { 127 val->intval = 0; 128 } 129 break; 130 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: 131 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: 132 case UCSI_CONSTAT_PWR_OPMODE_BC: 133 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: 134 val->intval = UCSI_TYPEC_VSAFE5V * 1000; 135 break; 136 default: 137 val->intval = 0; 138 break; 139 } 140 return 0; 141 } 142 143 static int ucsi_psy_get_current_max(struct ucsi_connector *con, 144 union power_supply_propval *val) 145 { 146 u32 pdo; 147 148 switch (UCSI_CONSTAT(con, PWR_OPMODE)) { 149 case UCSI_CONSTAT_PWR_OPMODE_PD: 150 if (con->num_pdos > 0) { 151 pdo = con->src_pdos[con->num_pdos - 1]; 152 val->intval = pdo_max_current(pdo) * 1000; 153 } else { 154 val->intval = 0; 155 } 156 break; 157 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: 158 val->intval = UCSI_TYPEC_1_5_CURRENT * 1000; 159 break; 160 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: 161 val->intval = UCSI_TYPEC_3_0_CURRENT * 1000; 162 break; 163 case UCSI_CONSTAT_PWR_OPMODE_BC: 164 case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: 165 /* UCSI can't tell b/w DCP/CDP or USB2/3x1/3x2 SDP chargers */ 166 default: 167 val->intval = 0; 168 break; 169 } 170 return 0; 171 } 172 173 static int ucsi_psy_get_current_now(struct ucsi_connector *con, 174 union power_supply_propval *val) 175 { 176 if (UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) 177 val->intval = rdo_op_current(con->rdo) * 1000; 178 else 179 val->intval = 0; 180 return 0; 181 } 182 183 static int ucsi_psy_get_usb_type(struct ucsi_connector *con, 184 union power_supply_propval *val) 185 { 186 val->intval = POWER_SUPPLY_USB_TYPE_C; 187 if (UCSI_CONSTAT(con, CONNECTED) && 188 UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) 189 val->intval = POWER_SUPPLY_USB_TYPE_PD; 190 191 return 0; 192 } 193 194 static int ucsi_psy_get_charge_type(struct ucsi_connector *con, union power_supply_propval *val) 195 { 196 if (!(UCSI_CONSTAT(con, CONNECTED))) { 197 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 198 return 0; 199 } 200 201 /* The Battery Charging Cabability Status field is only valid in sink role. */ 202 if (UCSI_CONSTAT(con, PWR_DIR) != TYPEC_SINK) { 203 val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 204 return 0; 205 } 206 207 switch (UCSI_CONSTAT(con, BC_STATUS)) { 208 case UCSI_CONSTAT_BC_NOMINAL_CHARGING: 209 val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 210 break; 211 case UCSI_CONSTAT_BC_SLOW_CHARGING: 212 case UCSI_CONSTAT_BC_TRICKLE_CHARGING: 213 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 214 break; 215 default: 216 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 217 break; 218 } 219 220 return 0; 221 } 222 223 static int ucsi_psy_get_prop(struct power_supply *psy, 224 enum power_supply_property psp, 225 union power_supply_propval *val) 226 { 227 struct ucsi_connector *con = power_supply_get_drvdata(psy); 228 229 switch (psp) { 230 case POWER_SUPPLY_PROP_CHARGE_TYPE: 231 return ucsi_psy_get_charge_type(con, val); 232 case POWER_SUPPLY_PROP_USB_TYPE: 233 return ucsi_psy_get_usb_type(con, val); 234 case POWER_SUPPLY_PROP_ONLINE: 235 return ucsi_psy_get_online(con, val); 236 case POWER_SUPPLY_PROP_VOLTAGE_MIN: 237 return ucsi_psy_get_voltage_min(con, val); 238 case POWER_SUPPLY_PROP_VOLTAGE_MAX: 239 return ucsi_psy_get_voltage_max(con, val); 240 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 241 return ucsi_psy_get_voltage_now(con, val); 242 case POWER_SUPPLY_PROP_CURRENT_MAX: 243 return ucsi_psy_get_current_max(con, val); 244 case POWER_SUPPLY_PROP_CURRENT_NOW: 245 return ucsi_psy_get_current_now(con, val); 246 case POWER_SUPPLY_PROP_SCOPE: 247 return ucsi_psy_get_scope(con, val); 248 default: 249 return -EINVAL; 250 } 251 } 252 253 int ucsi_register_port_psy(struct ucsi_connector *con) 254 { 255 struct power_supply_config psy_cfg = {}; 256 struct device *dev = con->ucsi->dev; 257 char *psy_name; 258 259 psy_cfg.drv_data = con; 260 psy_cfg.fwnode = dev_fwnode(dev); 261 262 psy_name = devm_kasprintf(dev, GFP_KERNEL, "ucsi-source-psy-%s%d", 263 dev_name(dev), con->num); 264 if (!psy_name) 265 return -ENOMEM; 266 267 con->psy_desc.name = psy_name; 268 con->psy_desc.type = POWER_SUPPLY_TYPE_USB; 269 con->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | 270 BIT(POWER_SUPPLY_USB_TYPE_PD) | 271 BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); 272 con->psy_desc.properties = ucsi_psy_props; 273 con->psy_desc.num_properties = ARRAY_SIZE(ucsi_psy_props); 274 con->psy_desc.get_property = ucsi_psy_get_prop; 275 276 con->psy = power_supply_register(dev, &con->psy_desc, &psy_cfg); 277 278 return PTR_ERR_OR_ZERO(con->psy); 279 } 280 281 void ucsi_unregister_port_psy(struct ucsi_connector *con) 282 { 283 if (IS_ERR_OR_NULL(con->psy)) 284 return; 285 286 power_supply_unregister(con->psy); 287 con->psy = NULL; 288 } 289 290 void ucsi_port_psy_changed(struct ucsi_connector *con) 291 { 292 if (IS_ERR_OR_NULL(con->psy)) 293 return; 294 295 power_supply_changed(con->psy); 296 } 297