static int axp288_extcon_probe()

in extcon-axp288.c [363:477]


static int axp288_extcon_probe(struct platform_device *pdev)
{
	struct axp288_extcon_info *info;
	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
	struct device *dev = &pdev->dev;
	struct acpi_device *adev;
	int ret, i, pirq;

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

	info->dev = &pdev->dev;
	info->regmap = axp20x->regmap;
	info->regmap_irqc = axp20x->regmap_irqc;
	info->previous_cable = EXTCON_NONE;
	INIT_WORK(&info->role_work, axp288_usb_role_work);
	info->id_nb.notifier_call = axp288_extcon_id_evt;

	platform_set_drvdata(pdev, info);

	ret = axp288_extcon_find_role_sw(info);
	if (ret)
		return ret;

	if (info->role_sw) {
		ret = devm_add_action_or_reset(dev, axp288_put_role_sw, info);
		if (ret)
			return ret;

		adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1);
		if (adev) {
			info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev));
			put_device(&adev->dev);
			if (!info->id_extcon)
				return -EPROBE_DEFER;

			dev_info(dev, "controlling USB role\n");
		} else {
			dev_info(dev, "controlling USB role based on Vbus presence\n");
		}
	}

	ret = iosf_mbi_block_punit_i2c_access();
	if (ret < 0)
		return ret;

	info->vbus_attach = axp288_get_vbus_attach(info);

	axp288_extcon_log_rsi(info);

	iosf_mbi_unblock_punit_i2c_access();

	/* Initialize extcon device */
	info->edev = devm_extcon_dev_allocate(&pdev->dev,
					      axp288_extcon_cables);
	if (IS_ERR(info->edev)) {
		dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
		return PTR_ERR(info->edev);
	}

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

	for (i = 0; i < EXTCON_IRQ_END; i++) {
		pirq = platform_get_irq(pdev, i);
		if (pirq < 0)
			return pirq;

		info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
		if (info->irq[i] < 0) {
			dev_err(&pdev->dev,
				"failed to get virtual interrupt=%d\n", pirq);
			ret = info->irq[i];
			return ret;
		}

		ret = devm_request_threaded_irq(&pdev->dev, info->irq[i],
				NULL, axp288_extcon_isr,
				IRQF_ONESHOT | IRQF_NO_SUSPEND,
				pdev->name, info);
		if (ret) {
			dev_err(&pdev->dev, "failed to request interrupt=%d\n",
							info->irq[i]);
			return ret;
		}
	}

	if (info->id_extcon) {
		ret = devm_extcon_register_notifier_all(dev, info->id_extcon,
							&info->id_nb);
		if (ret)
			return ret;
	}

	/* Make sure the role-sw is set correctly before doing BC detection */
	if (info->role_sw) {
		queue_work(system_long_wq, &info->role_work);
		flush_work(&info->role_work);
	}

	/* Start charger cable type detection */
	ret = axp288_extcon_enable(info);
	if (ret < 0)
		return ret;

	device_init_wakeup(dev, true);
	platform_set_drvdata(pdev, info);

	return 0;
}