static int ptn5150_i2c_probe()

in extcon-ptn5150.c [197:296]


static int ptn5150_i2c_probe(struct i2c_client *i2c)
{
	struct device *dev = &i2c->dev;
	struct device_node *np = i2c->dev.of_node;
	struct ptn5150_info *info;
	int ret;

	if (!np)
		return -EINVAL;

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

	info->dev = &i2c->dev;
	info->i2c = i2c;
	info->vbus_gpiod = devm_gpiod_get(&i2c->dev, "vbus", GPIOD_OUT_LOW);
	if (IS_ERR(info->vbus_gpiod)) {
		ret = PTR_ERR(info->vbus_gpiod);
		if (ret == -ENOENT) {
			dev_info(dev, "No VBUS GPIO, ignoring VBUS control\n");
			info->vbus_gpiod = NULL;
		} else {
			return dev_err_probe(dev, ret, "failed to get VBUS GPIO\n");
		}
	}

	mutex_init(&info->mutex);

	INIT_WORK(&info->irq_work, ptn5150_irq_work);

	info->regmap = devm_regmap_init_i2c(i2c, &ptn5150_regmap_config);
	if (IS_ERR(info->regmap)) {
		return dev_err_probe(info->dev, PTR_ERR(info->regmap),
				     "failed to allocate register map\n");
	}

	if (i2c->irq > 0) {
		info->irq = i2c->irq;
	} else {
		info->int_gpiod = devm_gpiod_get(&i2c->dev, "int", GPIOD_IN);
		if (IS_ERR(info->int_gpiod)) {
			return dev_err_probe(dev, PTR_ERR(info->int_gpiod),
					     "failed to get INT GPIO\n");
		}

		info->irq = gpiod_to_irq(info->int_gpiod);
		if (info->irq < 0) {
			dev_err(dev, "failed to get INTB IRQ\n");
			return info->irq;
		}
	}

	ret = devm_request_threaded_irq(dev, info->irq, NULL,
					ptn5150_irq_handler,
					IRQF_TRIGGER_FALLING |
					IRQF_ONESHOT,
					i2c->name, info);
	if (ret < 0) {
		dev_err(dev, "failed to request handler for INTB IRQ\n");
		return ret;
	}

	/* Allocate extcon device */
	info->edev = devm_extcon_dev_allocate(info->dev, ptn5150_extcon_cable);
	if (IS_ERR(info->edev)) {
		dev_err(info->dev, "failed to allocate memory for extcon\n");
		return -ENOMEM;
	}

	/* Register extcon device */
	ret = devm_extcon_dev_register(info->dev, info->edev);
	if (ret) {
		dev_err(info->dev, "failed to register extcon device\n");
		return ret;
	}

	extcon_set_property_capability(info->edev, EXTCON_USB,
					EXTCON_PROP_USB_VBUS);
	extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
					EXTCON_PROP_USB_VBUS);
	extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
					EXTCON_PROP_USB_TYPEC_POLARITY);

	/* Initialize PTN5150 device and print vendor id and version id */
	ret = ptn5150_init_dev_type(info);
	if (ret)
		return -EINVAL;

	/*
	 * Update current extcon state if for example OTG connection was there
	 * before the probe
	 */
	mutex_lock(&info->mutex);
	ptn5150_check_state(info);
	mutex_unlock(&info->mutex);

	return 0;
}