static void detect_work_f(struct work_struct *work) { int rc; struct pm8058_othc *dd = container_of(work, struct pm8058_othc, detect_work.work); if (dd->othc_ir_state) { /* inserted */ rc = pm8058_accessory_report(dd, 1); if (rc) pr_err("Accessory could not be detected\n"); } else { /* removed */ rc = pm8058_accessory_report(dd, 0); if (rc) pr_err("Accessory could not be detected\n"); /* Clear existing switch state */ dd->othc_sw_state = false; } enable_irq(dd->othc_irq_ir); }
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("Unable to register switch device\n"); return rc; } ipd = input_allocate_device(); if (ipd == NULL) { pr_err("Unable to allocate memory\n"); 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 || dd->othc_irq_sw < 0) { pr_err("othc resource:IRQs absent\n"); rc = -ENXIO; goto fail_micbias_config; } if (pdata->hsed_name != NULL) ipd->name = pdata->hsed_name; else ipd->name = "pmic8058_othc"; ipd->phys = "pmic8058_othc/input0"; ipd->dev.parent = &pd->dev; dd->othc_ipd = ipd; dd->othc_sw_state = false; dd->switch_debounce_ms = hsed_config->switch_debounce_ms; dd->othc_support_n_switch = hsed_config->othc_support_n_switch; dd->accessory_support = pdata->hsed_config->accessories_support; dd->detection_delay_ms = pdata->hsed_config->detection_delay_ms; if (dd->othc_support_n_switch == true) dd->switch_config = hsed_config->switch_config; if (dd->accessory_support == true) { dd->accessory_info = pdata->hsed_config->accessories; dd->num_accessories = pdata->hsed_config->othc_num_accessories; dd->accessories_adc_support = pdata->hsed_config->accessories_adc_support; dd->accessories_adc_channel = pdata->hsed_config->accessories_adc_channel; dd->video_out_gpio = pdata->hsed_config->video_out_gpio; } /* Configure the MIC_BIAS line for headset detection */ rc = pm8058_configure_micbias(dd); if (rc < 0) goto fail_micbias_config; /* Configure for the switch events */ rc = pm8058_configure_switch(dd); if (rc < 0) goto fail_micbias_config; /* Configure the accessory */ if (dd->accessory_support == true) { rc = pm8058_configure_accessory(dd); if (rc < 0) goto fail_micbias_config; } input_set_drvdata(ipd, dd); spin_lock_init(&dd->lock); rc = input_register_device(ipd); if (rc) { pr_err("Unable to register OTHC device\n"); goto fail_micbias_config; } hrtimer_init(&dd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); dd->timer.function = pm8058_othc_timer; /* Request the HEADSET IR interrupt */ 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("Unable to request pm8058_othc_ir IRQ\n"); goto fail_ir_irq; } /* Request the SWITCH press/release interrupt */ 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("Unable to request pm8058_othc_sw IRQ\n"); goto fail_sw_irq; } /* Check if the accessory is already inserted during boot up */ rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir); if (rc < 0) { pr_err("Unable to get accessory status at boot\n"); goto fail_ir_irq; } if (rc) { pr_debug("Accessory inserted during boot up\n"); /* process the data and report the inserted accessory */ rc = pm8058_accessory_report(dd, 1); if (rc) pr_debug("Unabele to detect accessory at boot up\n"); } device_init_wakeup(&pd->dev, hsed_config->hsed_bias_config->othc_wakeup); INIT_DELAYED_WORK(&dd->detect_work, detect_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_micbias_config: input_free_device(ipd); fail_input_alloc: switch_dev_unregister(&dd->othc_sdev); return rc; }