static int ucs1002_probe()

in supply/ucs1002_power.c [535:671]


static int ucs1002_probe(struct i2c_client *client,
			 const struct i2c_device_id *dev_id)
{
	struct device *dev = &client->dev;
	struct power_supply_config charger_config = {};
	const struct regmap_config regmap_config = {
		.reg_bits = 8,
		.val_bits = 8,
	};
	struct regulator_config regulator_config = {};
	int irq_a_det, irq_alert, ret;
	struct ucs1002_info *info;
	unsigned int regval;

	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	info->regmap = devm_regmap_init_i2c(client, &regmap_config);
	ret = PTR_ERR_OR_ZERO(info->regmap);
	if (ret) {
		dev_err(dev, "Regmap initialization failed: %d\n", ret);
		return ret;
	}

	info->client = client;

	irq_a_det = of_irq_get_byname(dev->of_node, "a_det");
	irq_alert = of_irq_get_byname(dev->of_node, "alert");

	charger_config.of_node = dev->of_node;
	charger_config.drv_data = info;

	ret = regmap_read(info->regmap, UCS1002_REG_PRODUCT_ID, &regval);
	if (ret) {
		dev_err(dev, "Failed to read product ID: %d\n", ret);
		return ret;
	}

	if (regval != UCS1002_PRODUCT_ID) {
		dev_err(dev,
			"Product ID does not match (0x%02x != 0x%02x)\n",
			regval, UCS1002_PRODUCT_ID);
		return -ENODEV;
	}

	/* Enable charge rationing by default */
	ret = regmap_update_bits(info->regmap, UCS1002_REG_GENERAL_CFG,
				 F_RATION_EN, F_RATION_EN);
	if (ret) {
		dev_err(dev, "Failed to read general config: %d\n", ret);
		return ret;
	}

	/*
	 * Ignore the M1, M2, PWR_EN, and EM_EN pin states. Set active
	 * mode selection to BC1.2 CDP.
	 */
	ret = regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG,
				 V_SET_ACTIVE_MODE_MASK | F_PIN_IGNORE,
				 V_SET_ACTIVE_MODE_BC12_CDP | F_PIN_IGNORE);
	if (ret) {
		dev_err(dev, "Failed to configure default mode: %d\n", ret);
		return ret;
	}
	/*
	 * Be safe and set initial current limit to 500mA
	 */
	ret = ucs1002_set_max_current(info, 500000);
	if (ret) {
		dev_err(dev, "Failed to set max current default: %d\n", ret);
		return ret;
	}

	info->charger = devm_power_supply_register(dev, &ucs1002_charger_desc,
						   &charger_config);
	ret = PTR_ERR_OR_ZERO(info->charger);
	if (ret) {
		dev_err(dev, "Failed to register power supply: %d\n", ret);
		return ret;
	}

	ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, &regval);
	if (ret) {
		dev_err(dev, "Failed to read pin status: %d\n", ret);
		return ret;
	}

	info->regulator_descriptor =
		devm_kmemdup(dev, &ucs1002_regulator_descriptor,
			     sizeof(ucs1002_regulator_descriptor),
			     GFP_KERNEL);
	if (!info->regulator_descriptor)
		return -ENOMEM;

	info->regulator_descriptor->enable_is_inverted = !(regval & F_SEL_PIN);

	regulator_config.dev = dev;
	regulator_config.of_node = dev->of_node;
	regulator_config.regmap = info->regmap;
	regulator_config.driver_data = info;

	info->rdev = devm_regulator_register(dev, info->regulator_descriptor,
				       &regulator_config);
	ret = PTR_ERR_OR_ZERO(info->rdev);
	if (ret) {
		dev_err(dev, "Failed to register VBUS regulator: %d\n", ret);
		return ret;
	}

	info->health = POWER_SUPPLY_HEALTH_GOOD;
	INIT_DELAYED_WORK(&info->health_poll, ucs1002_health_poll);

	if (irq_a_det > 0) {
		ret = devm_request_threaded_irq(dev, irq_a_det, NULL,
						ucs1002_charger_irq,
						IRQF_ONESHOT,
						"ucs1002-a_det", info);
		if (ret) {
			dev_err(dev, "Failed to request A_DET threaded irq: %d\n",
				ret);
			return ret;
		}
	}

	if (irq_alert > 0) {
		ret = devm_request_irq(dev, irq_alert, ucs1002_alert_irq,
				       0,"ucs1002-alert", info);
		if (ret) {
			dev_err(dev, "Failed to request ALERT threaded irq: %d\n",
				ret);
			return ret;
		}
	}

	return 0;
}