Example #1
0
static int
othc_configure_hsed(struct pm8058_othc *dd, struct platform_device *pd)
{
	int rc, i;
	struct input_dev *ipd;
	struct pmic8058_othc_config_pdata *pdata = pd->dev.platform_data;
	struct othc_hsed_config *hsed_config = pdata->hsed_config;

	dd->othc_sdev.name = "h2w";
	dd->othc_sdev.print_name = othc_headset_print_name;

	rc = switch_dev_register(&dd->othc_sdev);
	if (rc) {
		pr_err("%s: Unable to register switch device \n", __func__);
		return rc;
	}

	ipd = input_allocate_device();
	if (ipd == NULL) {
		pr_err("%s: Unable to allocate memory \n", __func__);
		rc = -ENOMEM;
		goto fail_input_alloc;
	}

	/* Get the IRQ for Headset Insert-remove and Switch-press */
	dd->othc_irq_sw = platform_get_irq(pd, 0);
	dd->othc_irq_ir = platform_get_irq(pd, 1);
	if (dd->othc_irq_ir < 0) {
		pr_err("%s: othc resource:IRQ_IR absent \n", __func__);
		rc = -ENXIO;
		goto fail_othc_config;
	}
	if (dd->othc_irq_sw < 0) {
		pr_err("%s: othc resource:IRQ_SW absent\n", __func__);
		rc = -ENXIO;
		goto fail_othc_config;
	}

	ipd->name = "pmic8058_othc";
	ipd->phys = "pmic8058_othc/input0";
	ipd->dev.parent = &pd->dev;

	dd->othc_ipd = ipd;
	dd->othc_sw_state = false;
	dd->othc_ir_state = false;
	dd->switch_debounce_ms = hsed_config->switch_debounce_ms;
	dd->othc_support_n_switch = hsed_config->othc_support_n_switch;

	if (dd->othc_support_n_switch == true) {
		pr_debug("%s: OTHC 'n' switch supported\n", __func__);
		if (!hsed_config->switch_config ||
				!hsed_config->switch_config->switch_info) {
			rc = -EINVAL;
			pr_err("%s: Switch pdata absent!\n", __func__);
			goto fail_othc_config;
		}
		dd->switch_config = hsed_config->switch_config;
		for (i = 0; i < dd->switch_config->num_keys; i++) {
			input_set_capability(ipd, EV_KEY,
				dd->switch_config->switch_info[i].key_code);
		}
	} else
		input_set_capability(ipd, EV_KEY, KEY_MEDIA);

	input_set_capability(ipd, EV_SW, SW_HEADPHONE_INSERT);
	input_set_drvdata(ipd, dd);
	spin_lock_init(&dd->lock);

	rc = pm8058_configure_othc(dd);
	if (rc < 0)
		goto fail_othc_config;

	rc = input_register_device(ipd);
	if (rc) {
		pr_err("%s: Unable to register OTHC device \n", __func__);
		goto fail_othc_config;
	}

	/* Check if the headset is already inserted during boot up */
	rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
	if (rc < 0) {
		pr_err("%s: Unable to get headset status at boot\n", __func__);
		goto fail_ir_irq;
	}
	if (rc) {
		pr_debug("%s: Headset inserted during boot up\n", __func__);
		/* Headset present */
		dd->othc_ir_state = true;
		switch_set_state(&dd->othc_sdev, 1);
		input_report_switch(dd->othc_ipd, SW_HEADPHONE_INSERT, 1);
		input_sync(dd->othc_ipd);
	}

	hrtimer_init(&dd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	dd->timer.function = pm8058_othc_timer;

	rc = request_threaded_irq(dd->othc_irq_ir, NULL, pm8058_nc_ir,
		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED,
				"pm8058_othc_ir", dd);
	if (rc < 0) {
		pr_err("%s: Unable to request pm8058_othc_ir IRQ\n", __func__);
		goto fail_ir_irq;
	}

	/* This irq is used only for NO type headset */
	rc = request_threaded_irq(dd->othc_irq_sw, NULL, pm8058_no_sw,
	IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED,
			"pm8058_othc_sw", dd);
	if (rc < 0) {
		pr_err("%s: Unable to request pm8058_othc_sw IRQ\n",
							__func__);
		goto fail_sw_irq;
	}

	device_init_wakeup(&pd->dev, hsed_config->othc_wakeup);

	INIT_WORK(&dd->headset_work, headset_work_f);

	if (dd->othc_support_n_switch == true)
		INIT_WORK(&dd->switch_work, switch_work_f);

	return 0;

fail_sw_irq:
	free_irq(dd->othc_irq_ir, dd);
fail_ir_irq:
	input_unregister_device(ipd);
	dd->othc_ipd = NULL;
fail_othc_config:
	input_free_device(ipd);
fail_input_alloc:
	switch_dev_unregister(&dd->othc_sdev);
	return rc;
}
static int
othc_configure_hsed(struct pm8058_othc *dd, struct platform_device *pd)
{
	int rc;
	struct input_dev *ipd;
	struct pmic8058_othc_config_pdata *pdata = pd->dev.platform_data;
	struct othc_hsed_config *hsed_config = pdata->hsed_config;

	dd->othc_sdev.name = "h2w";
	dd->othc_sdev.print_name = othc_headset_print_name;

	rc = switch_dev_register(&dd->othc_sdev);
	if (rc) {
		pr_err("%s: Unable to register switch device \n", __func__);
		return rc;
	}

	ipd = input_allocate_device();
	if (ipd == NULL) {
		pr_err("%s: Unable to allocate memory \n", __func__);
		rc = -ENOMEM;
		goto fail_input_alloc;
	}

	/* Get the IRQ for Headset Insert-remove and Switch-press */
	dd->othc_irq_sw = platform_get_irq(pd, 0);
	dd->othc_irq_ir = platform_get_irq(pd, 1);
	if (dd->othc_irq_ir < 0) {
		pr_err("%s: othc resource:IRQ_IR absent \n", __func__);
		rc = -ENXIO;
		goto fail_othc_config;
	}
	if (hsed_config->othc_headset == OTHC_HEADSET_NO) {
		if (dd->othc_irq_sw < 0) {
			pr_err("%s: othc resource:IRQ_SW absent\n", __func__);
			rc = -ENXIO;
			goto fail_othc_config;
		}
	}

	ipd->name = "pmic8058_othc";
	ipd->phys = "pmic8058_othc/input0";
	ipd->dev.parent = &pd->dev;

	input_set_capability(ipd, EV_SW, SW_HEADPHONE_INSERT);
	input_set_capability(ipd, EV_KEY, KEY_MEDIA);

	input_set_drvdata(ipd, dd);

	dd->othc_ipd = ipd;
	dd->othc_sw_state = false;
	dd->othc_ir_state = false;

	if (hsed_config->othc_headset == OTHC_HEADSET_NC) {
		/* Check if NC specific pdata is present */
		if (!hsed_config->othc_nc_gpio_setup ||
					!hsed_config->othc_nc_gpio) {
			pr_err("%s: NC headset pdata missing \n", __func__);
			rc = -EINVAL;
			goto fail_othc_config;
		}
	}

	rc = pm8058_configure_othc(dd);
	if (rc < 0)
		goto fail_othc_config;

	rc = input_register_device(ipd);
	if (rc) {
		pr_err("%s: Unable to register OTHC device \n", __func__);
		goto fail_othc_config;
	}

	/* Check if the headset is already inserted during boot up */
	rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
	if (rc < 0) {
		pr_err("%s: Unable to get headset status at boot\n", __func__);
		goto fail_ir_irq;
	}
	if (rc) {
		pr_debug("%s: Headset inserted during boot up\n", __func__);
		/* Headset present */
		dd->othc_ir_state = true;
		switch_set_state(&dd->othc_sdev, 1);
		input_report_switch(dd->othc_ipd, SW_HEADPHONE_INSERT, 1);
		input_sync(dd->othc_ipd);
	}

	rc = request_irq(dd->othc_irq_ir, pm8058_nc_ir,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
				"pm8058_othc_ir", dd);
	if (rc < 0) {
		pr_err("%s: Unable to request pm8058_othc_ir IRQ\n", __func__);
		goto fail_ir_irq;
	}

	if (hsed_config->othc_headset == OTHC_HEADSET_NO) {
		/* This irq is used only for NO type headset */
		rc = request_irq(dd->othc_irq_sw, pm8058_no_sw,
			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
				"pm8058_othc_sw", dd);
		if (rc < 0) {
			pr_err("%s: Unable to request pm8058_othc_sw IRQ \n",
								__func__);
			goto fail_sw_irq;
		}
	} else {
		/* NC type of headset use GPIO for IR */
		rc = hsed_config->othc_nc_gpio_setup();
		if (rc < 0) {
			pr_err("%s: Unable to setup gpio for NC type \n",
								__func__);
			goto fail_sw_irq;
		}
	}

	device_init_wakeup(&pd->dev, hsed_config->othc_wakeup);

	INIT_WORK(&dd->switch_work, switch_work_f);

	return 0;

fail_sw_irq:
	free_irq(dd->othc_irq_ir, dd);
fail_ir_irq:
	input_unregister_device(ipd);
	dd->othc_ipd = NULL;
fail_othc_config:
	input_free_device(ipd);
fail_input_alloc:
	switch_dev_unregister(&dd->othc_sdev);
	return rc;
}