in supply/cros_usbpd-charger.c [538:690]
static int cros_usbpd_charger_probe(struct platform_device *pd)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
struct cros_ec_device *ec_device = ec_dev->ec_dev;
struct power_supply_desc *psy_desc;
struct device *dev = &pd->dev;
struct charger_data *charger;
struct power_supply *psy;
struct port_data *port;
int ret = -EINVAL;
int i;
charger = devm_kzalloc(dev, sizeof(struct charger_data),
GFP_KERNEL);
if (!charger)
return -ENOMEM;
charger->dev = dev;
charger->ec_dev = ec_dev;
charger->ec_device = ec_device;
platform_set_drvdata(pd, charger);
/*
* We need to know the number of USB PD ports in order to know whether
* there is a dedicated port. The dedicated port will always be
* after the USB PD ports, and there should be only one.
*/
charger->num_usbpd_ports =
cros_usbpd_charger_get_usbpd_num_ports(charger);
if (charger->num_usbpd_ports <= 0) {
/*
* This can happen on a system that doesn't support USB PD.
* Log a message, but no need to warn.
*/
dev_info(dev, "No USB PD charging ports found\n");
}
charger->num_charger_ports = cros_usbpd_charger_get_num_ports(charger);
if (charger->num_charger_ports < 0) {
/*
* This can happen on a system that doesn't support USB PD.
* Log a message, but no need to warn.
* Older ECs do not support the above command, in that case
* let's set up the number of charger ports equal to the number
* of USB PD ports
*/
dev_info(dev, "Could not get charger port count\n");
charger->num_charger_ports = charger->num_usbpd_ports;
}
if (charger->num_charger_ports <= 0) {
/*
* This can happen on a system that doesn't support USB PD and
* doesn't have a dedicated port.
* Log a message, but no need to warn.
*/
dev_info(dev, "No charging ports found\n");
ret = -ENODEV;
goto fail_nowarn;
}
/*
* Sanity checks on the number of ports:
* there should be at most 1 dedicated port
*/
if (charger->num_charger_ports < charger->num_usbpd_ports ||
charger->num_charger_ports > (charger->num_usbpd_ports + 1)) {
dev_err(dev, "Unexpected number of charge port count\n");
ret = -EPROTO;
goto fail_nowarn;
}
for (i = 0; i < charger->num_charger_ports; i++) {
struct power_supply_config psy_cfg = {};
port = devm_kzalloc(dev, sizeof(struct port_data), GFP_KERNEL);
if (!port) {
ret = -ENOMEM;
goto fail;
}
port->charger = charger;
port->port_number = i;
psy_desc = &port->psy_desc;
psy_desc->get_property = cros_usbpd_charger_get_prop;
psy_desc->set_property = cros_usbpd_charger_set_prop;
psy_desc->property_is_writeable =
cros_usbpd_charger_property_is_writeable;
psy_desc->external_power_changed =
cros_usbpd_charger_power_changed;
psy_cfg.drv_data = port;
if (cros_usbpd_charger_port_is_dedicated(port)) {
sprintf(port->name, CHARGER_DEDICATED_DIR_NAME);
psy_desc->type = POWER_SUPPLY_TYPE_MAINS;
psy_desc->properties =
cros_usbpd_dedicated_charger_props;
psy_desc->num_properties =
ARRAY_SIZE(cros_usbpd_dedicated_charger_props);
} else {
sprintf(port->name, CHARGER_USBPD_DIR_NAME, i);
psy_desc->type = POWER_SUPPLY_TYPE_USB;
psy_desc->properties = cros_usbpd_charger_props;
psy_desc->num_properties =
ARRAY_SIZE(cros_usbpd_charger_props);
psy_desc->usb_types = cros_usbpd_charger_usb_types;
psy_desc->num_usb_types =
ARRAY_SIZE(cros_usbpd_charger_usb_types);
}
psy_desc->name = port->name;
psy = devm_power_supply_register_no_ws(dev, psy_desc,
&psy_cfg);
if (IS_ERR(psy)) {
dev_err(dev, "Failed to register power supply\n");
continue;
}
port->psy = psy;
charger->ports[charger->num_registered_psy++] = port;
}
if (!charger->num_registered_psy) {
ret = -ENODEV;
dev_err(dev, "No power supplies registered\n");
goto fail;
}
/* Get PD events from the EC */
charger->notifier.notifier_call = cros_usbpd_charger_ec_event;
ret = cros_usbpd_register_notify(&charger->notifier);
if (ret < 0) {
dev_warn(dev, "failed to register notifier\n");
} else {
ret = devm_add_action_or_reset(dev,
cros_usbpd_charger_unregister_notifier,
charger);
if (ret < 0)
goto fail;
}
return 0;
fail:
WARN(1, "%s: Failing probe (err:0x%x)\n", dev_name(dev), ret);
fail_nowarn:
dev_info(dev, "Failing probe (err:0x%x)\n", ret);
return ret;
}