static int rt9455_probe()

in supply/rt9455_charger.c [1584:1699]


static int rt9455_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct i2c_adapter *adapter = client->adapter;
	struct device *dev = &client->dev;
	struct rt9455_info *info;
	struct power_supply_config rt9455_charger_config = {};
	/*
	 * Mandatory device-specific data values. Also, VOREG and boost output
	 * voltage are mandatory values, but they are stored in rt9455_info
	 * structure.
	 */
	u32 ichrg, ieoc_percentage;
	/* Optional device-specific data values. */
	u32 mivr = -1, iaicr = -1;
	int i, ret;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
		return -ENODEV;
	}
	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	info->client = client;
	i2c_set_clientdata(client, info);

	info->regmap = devm_regmap_init_i2c(client,
					    &rt9455_regmap_config);
	if (IS_ERR(info->regmap)) {
		dev_err(dev, "Failed to initialize register map\n");
		return -EINVAL;
	}

	for (i = 0; i < F_MAX_FIELDS; i++) {
		info->regmap_fields[i] =
			devm_regmap_field_alloc(dev, info->regmap,
						rt9455_reg_fields[i]);
		if (IS_ERR(info->regmap_fields[i])) {
			dev_err(dev,
				"Failed to allocate regmap field = %d\n", i);
			return PTR_ERR(info->regmap_fields[i]);
		}
	}

	ret = rt9455_discover_charger(info, &ichrg, &ieoc_percentage,
				      &mivr, &iaicr);
	if (ret) {
		dev_err(dev, "Failed to discover charger\n");
		return ret;
	}

#if IS_ENABLED(CONFIG_USB_PHY)
	info->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
	if (IS_ERR(info->usb_phy)) {
		dev_err(dev, "Failed to get USB transceiver\n");
	} else {
		info->nb.notifier_call = rt9455_usb_event;
		ret = usb_register_notifier(info->usb_phy, &info->nb);
		if (ret) {
			dev_err(dev, "Failed to register USB notifier\n");
			/*
			 * If usb_register_notifier() fails, set notifier_call
			 * to NULL, to avoid calling usb_unregister_notifier().
			 */
			info->nb.notifier_call = NULL;
		}
	}
#endif

	INIT_DEFERRABLE_WORK(&info->pwr_rdy_work, rt9455_pwr_rdy_work_callback);
	INIT_DEFERRABLE_WORK(&info->max_charging_time_work,
			     rt9455_max_charging_time_work_callback);
	INIT_DEFERRABLE_WORK(&info->batt_presence_work,
			     rt9455_batt_presence_work_callback);

	rt9455_charger_config.of_node		= dev->of_node;
	rt9455_charger_config.drv_data		= info;
	rt9455_charger_config.supplied_to	= rt9455_charger_supplied_to;
	rt9455_charger_config.num_supplicants	=
					ARRAY_SIZE(rt9455_charger_supplied_to);
	ret = devm_request_threaded_irq(dev, client->irq, NULL,
					rt9455_irq_handler_thread,
					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
					RT9455_DRIVER_NAME, info);
	if (ret) {
		dev_err(dev, "Failed to register IRQ handler\n");
		goto put_usb_notifier;
	}

	ret = rt9455_hw_init(info, ichrg, ieoc_percentage, mivr, iaicr);
	if (ret) {
		dev_err(dev, "Failed to set charger to its default values\n");
		goto put_usb_notifier;
	}

	info->charger = devm_power_supply_register(dev, &rt9455_charger_desc,
						   &rt9455_charger_config);
	if (IS_ERR(info->charger)) {
		dev_err(dev, "Failed to register charger\n");
		ret = PTR_ERR(info->charger);
		goto put_usb_notifier;
	}

	return 0;

put_usb_notifier:
#if IS_ENABLED(CONFIG_USB_PHY)
	if (info->nb.notifier_call)  {
		usb_unregister_notifier(info->usb_phy, &info->nb);
		info->nb.notifier_call = NULL;
	}
#endif
	return ret;
}