static int cros_usbpd_charger_probe()

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;
}