static int bq24190_probe()

in supply/bq24190_charger.c [1707:1838]


static int bq24190_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	struct i2c_adapter *adapter = client->adapter;
	struct device *dev = &client->dev;
	struct power_supply_config charger_cfg = {}, battery_cfg = {};
	struct bq24190_dev_info *bdi;
	int ret;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
		return -ENODEV;
	}

	bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
	if (!bdi) {
		dev_err(dev, "Can't alloc bdi struct\n");
		return -ENOMEM;
	}

	bdi->client = client;
	bdi->dev = dev;
	strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
	mutex_init(&bdi->f_reg_lock);
	bdi->f_reg = 0;
	bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
	INIT_DELAYED_WORK(&bdi->input_current_limit_work,
			  bq24190_input_current_limit_work);

	i2c_set_clientdata(client, bdi);

	if (client->irq <= 0) {
		dev_err(dev, "Can't get irq info\n");
		return -EINVAL;
	}

	bdi->edev = devm_extcon_dev_allocate(dev, bq24190_usb_extcon_cable);
	if (IS_ERR(bdi->edev))
		return PTR_ERR(bdi->edev);

	ret = devm_extcon_dev_register(dev, bdi->edev);
	if (ret < 0)
		return ret;

	pm_runtime_enable(dev);
	pm_runtime_use_autosuspend(dev);
	pm_runtime_set_autosuspend_delay(dev, 600);
	ret = pm_runtime_get_sync(dev);
	if (ret < 0) {
		dev_err(dev, "pm_runtime_get failed: %i\n", ret);
		goto out_pmrt;
	}

#ifdef CONFIG_SYSFS
	bq24190_sysfs_init_attrs();
	charger_cfg.attr_grp = bq24190_sysfs_groups;
#endif

	charger_cfg.drv_data = bdi;
	charger_cfg.of_node = dev->of_node;
	charger_cfg.supplied_to = bq24190_charger_supplied_to;
	charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to);
	bdi->charger = power_supply_register(dev, &bq24190_charger_desc,
						&charger_cfg);
	if (IS_ERR(bdi->charger)) {
		dev_err(dev, "Can't register charger\n");
		ret = PTR_ERR(bdi->charger);
		goto out_pmrt;
	}

	/* the battery class is deprecated and will be removed. */
	/* in the interim, this property hides it.              */
	if (!device_property_read_bool(dev, "omit-battery-class")) {
		battery_cfg.drv_data = bdi;
		bdi->battery = power_supply_register(dev, &bq24190_battery_desc,
						     &battery_cfg);
		if (IS_ERR(bdi->battery)) {
			dev_err(dev, "Can't register battery\n");
			ret = PTR_ERR(bdi->battery);
			goto out_charger;
		}
	}

	ret = bq24190_get_config(bdi);
	if (ret < 0) {
		dev_err(dev, "Can't get devicetree config\n");
		goto out_charger;
	}

	ret = bq24190_hw_init(bdi);
	if (ret < 0) {
		dev_err(dev, "Hardware init failed\n");
		goto out_charger;
	}

	ret = bq24190_configure_usb_otg(bdi, bdi->ss_reg);
	if (ret < 0)
		goto out_charger;

	bdi->initialized = true;

	ret = devm_request_threaded_irq(dev, client->irq, NULL,
			bq24190_irq_handler_thread,
			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
			"bq24190-charger", bdi);
	if (ret < 0) {
		dev_err(dev, "Can't set up irq handler\n");
		goto out_charger;
	}

	ret = bq24190_register_vbus_regulator(bdi);
	if (ret < 0)
		goto out_charger;

	enable_irq_wake(client->irq);

	pm_runtime_mark_last_busy(dev);
	pm_runtime_put_autosuspend(dev);

	return 0;

out_charger:
	if (!IS_ERR_OR_NULL(bdi->battery))
		power_supply_unregister(bdi->battery);
	power_supply_unregister(bdi->charger);

out_pmrt:
	pm_runtime_put_sync(dev);
	pm_runtime_dont_use_autosuspend(dev);
	pm_runtime_disable(dev);
	return ret;
}