static int bq2415x_probe()

in supply/bq2415x_charger.c [1523:1695]


static int bq2415x_probe(struct i2c_client *client,
			 const struct i2c_device_id *id)
{
	int ret;
	int num;
	char *name = NULL;
	struct bq2415x_device *bq;
	struct device_node *np = client->dev.of_node;
	struct bq2415x_platform_data *pdata = client->dev.platform_data;
	const struct acpi_device_id *acpi_id = NULL;
	struct power_supply *notify_psy = NULL;
	union power_supply_propval prop;

	if (!np && !pdata && !ACPI_HANDLE(&client->dev)) {
		dev_err(&client->dev, "Neither devicetree, nor platform data, nor ACPI support\n");
		return -ENODEV;
	}

	/* Get new ID for the new device */
	mutex_lock(&bq2415x_id_mutex);
	num = idr_alloc(&bq2415x_id, client, 0, 0, GFP_KERNEL);
	mutex_unlock(&bq2415x_id_mutex);
	if (num < 0)
		return num;

	if (id) {
		name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
	} else if (ACPI_HANDLE(&client->dev)) {
		acpi_id =
			acpi_match_device(client->dev.driver->acpi_match_table,
					  &client->dev);
		if (!acpi_id) {
			dev_err(&client->dev, "failed to match device name\n");
			ret = -ENODEV;
			goto error_1;
		}
		name = kasprintf(GFP_KERNEL, "%s-%d", acpi_id->id, num);
	}
	if (!name) {
		dev_err(&client->dev, "failed to allocate device name\n");
		ret = -ENOMEM;
		goto error_1;
	}

	bq = devm_kzalloc(&client->dev, sizeof(*bq), GFP_KERNEL);
	if (!bq) {
		ret = -ENOMEM;
		goto error_2;
	}

	i2c_set_clientdata(client, bq);

	bq->id = num;
	bq->dev = &client->dev;
	if (id)
		bq->chip = id->driver_data;
	else if (ACPI_HANDLE(bq->dev))
		bq->chip = acpi_id->driver_data;
	bq->name = name;
	bq->mode = BQ2415X_MODE_OFF;
	bq->reported_mode = BQ2415X_MODE_OFF;
	bq->autotimer = 0;
	bq->automode = 0;

	if (np || ACPI_HANDLE(bq->dev)) {
		ret = device_property_read_u32(bq->dev,
					       "ti,current-limit",
					       &bq->init_data.current_limit);
		if (ret)
			goto error_2;
		ret = device_property_read_u32(bq->dev,
					"ti,weak-battery-voltage",
					&bq->init_data.weak_battery_voltage);
		if (ret)
			goto error_2;
		ret = device_property_read_u32(bq->dev,
				"ti,battery-regulation-voltage",
				&bq->init_data.battery_regulation_voltage);
		if (ret)
			goto error_2;
		ret = device_property_read_u32(bq->dev,
					       "ti,charge-current",
					       &bq->init_data.charge_current);
		if (ret)
			goto error_2;
		ret = device_property_read_u32(bq->dev,
				"ti,termination-current",
				&bq->init_data.termination_current);
		if (ret)
			goto error_2;
		ret = device_property_read_u32(bq->dev,
					       "ti,resistor-sense",
					       &bq->init_data.resistor_sense);
		if (ret)
			goto error_2;
		if (np)
			bq->notify_node = of_parse_phandle(np,
						"ti,usb-charger-detection", 0);
	} else {
		memcpy(&bq->init_data, pdata, sizeof(bq->init_data));
	}

	bq2415x_reset_chip(bq);

	ret = bq2415x_power_supply_init(bq);
	if (ret) {
		dev_err(bq->dev, "failed to register power supply: %d\n", ret);
		goto error_2;
	}

	ret = bq2415x_set_defaults(bq);
	if (ret) {
		dev_err(bq->dev, "failed to set default values: %d\n", ret);
		goto error_3;
	}

	if (bq->notify_node || bq->init_data.notify_device) {
		bq->nb.notifier_call = bq2415x_notifier_call;
		ret = power_supply_reg_notifier(&bq->nb);
		if (ret) {
			dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
			goto error_3;
		}

		bq->automode = 1;
		dev_info(bq->dev, "automode supported, waiting for events\n");
	} else {
		bq->automode = -1;
		dev_info(bq->dev, "automode not supported\n");
	}

	/* Query for initial reported_mode and set it */
	if (bq->nb.notifier_call) {
		if (np) {
			notify_psy = power_supply_get_by_phandle(np,
						"ti,usb-charger-detection");
			if (IS_ERR(notify_psy))
				notify_psy = NULL;
		} else if (bq->init_data.notify_device) {
			notify_psy = power_supply_get_by_name(
						bq->init_data.notify_device);
		}
	}
	if (notify_psy) {
		ret = power_supply_get_property(notify_psy,
					POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
		power_supply_put(notify_psy);

		if (ret == 0) {
			bq2415x_update_reported_mode(bq, prop.intval);
			bq2415x_set_mode(bq, bq->reported_mode);
		}
	}

	INIT_DELAYED_WORK(&bq->work, bq2415x_timer_work);
	bq2415x_set_autotimer(bq, 1);

	dev_info(bq->dev, "driver registered\n");
	return 0;

error_3:
	bq2415x_power_supply_exit(bq);
error_2:
	if (bq)
		of_node_put(bq->notify_node);
	kfree(name);
error_1:
	mutex_lock(&bq2415x_id_mutex);
	idr_remove(&bq2415x_id, num);
	mutex_unlock(&bq2415x_id_mutex);

	return ret;
}