/* * The pm8058_nc_ir detects insert / remove of the headset (for NO), * The current state of the headset is maintained in othc_ir_state variable. * Due to a hardware bug, false switch interrupts are seen during headset * insert. This is handled in the software by rejecting the switch interrupts * for a small period of time after the headset has been inserted. */ static irqreturn_t pm8058_nc_ir(int irq, void *dev_id) { unsigned long flags, rc; struct pm8058_othc *dd = dev_id; spin_lock_irqsave(&dd->lock, flags); /* Enable the switch reject flag */ dd->switch_reject = true; spin_unlock_irqrestore(&dd->lock, flags); /* Start the HR timer if one is not active */ if (hrtimer_active(&dd->timer)) hrtimer_cancel(&dd->timer); hrtimer_start(&dd->timer, ktime_set((dd->switch_debounce_ms / 1000), (dd->switch_debounce_ms % 1000) * 1000000), HRTIMER_MODE_REL); /* disable irq, this gets enabled in the workqueue */ disable_irq_nosync(dd->othc_irq_ir); /* Check the MIC_BIAS status, to check if inserted or removed */ rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir); if (rc < 0) { pr_err("Unable to read IR status\n"); goto fail_ir; } dd->othc_ir_state = rc; schedule_delayed_work(&dd->detect_work, msecs_to_jiffies(dd->detection_delay_ms)); fail_ir: return IRQ_HANDLED; }
/* * The pm8058_no_sw detects the switch press and release operation. * The odd number call is press and even number call is release. * The current state of the button is maintained in othc_sw_state variable. * This isr gets called only for NO type headsets. */ static irqreturn_t pm8058_no_sw(int irq, void *dev_id) { int level; struct pm8058_othc *dd = dev_id; unsigned long flags; #if defined(CONFIG_HTC_HEADSET_8X60) hs_8x60_notify_key_event(); #endif /* CONFIG_HTC_HEADSET_8X60 */ spin_lock_irqsave(&dd->lock, flags); if (dd->switch_reject == true) { spin_unlock_irqrestore(&dd->lock, flags); return IRQ_HANDLED; } spin_unlock_irqrestore(&dd->lock, flags); level = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_sw); if (level < 0) { pr_err("Unable to read IRQ status register\n"); return IRQ_HANDLED; } if (dd->othc_support_n_switch == true) { #if !defined(CONFIG_HTC_HEADSET_8X60) if (level == 0) { dd->othc_sw_state = false; input_report_key(dd->othc_ipd, dd->sw_key_code, 0); input_sync(dd->othc_ipd); } else { disable_irq_nosync(dd->othc_irq_sw); schedule_work(&dd->switch_work); } #endif /* CONFIG_HTC_HEADSET_8X60 */ return IRQ_HANDLED; } /* * It is necessary to check the software state and the hardware state * to make sure that the residual interrupt after the debounce time does * not disturb the software state machine. */ if (level == 1 && dd->othc_sw_state == false) { /* Switch has been pressed */ dd->othc_sw_state = true; input_report_key(dd->othc_ipd, KEY_MEDIA, 1); } else if (level == 0 && dd->othc_sw_state == true) { /* Switch has been released */ dd->othc_sw_state = false; input_report_key(dd->othc_ipd, KEY_MEDIA, 0); } input_sync(dd->othc_ipd); return IRQ_HANDLED; }
static int pm8058_mpp_get(struct gpio_chip *chip, unsigned mpp) { struct pm8058_gpio_platform_data *pdata; struct pm8058_chip *pm_chip; if (mpp >= PM8058_MPPS || chip == NULL) return -EINVAL; pdata = chip->dev->platform_data; pm_chip = dev_get_drvdata(chip->dev); return pm8058_irq_get_rt_status(pm_chip, pdata->irq_base + mpp); }
static irqreturn_t max_valid_handler(int irq, void *dev_id) { struct max8903_struct *max_chg; struct platform_device *pdev; struct pm8058_chip *chip; int state; pdev = (struct platform_device *)dev_id; max_chg = platform_get_drvdata(pdev); chip = get_irq_data(irq); #if 0 /* Dock insert, think it as AC charger */ if (gpio_get_value_cansleep(max_chg->dock_det) && (BOARD_NUM(hw_ver) != BOARD_NUM_V11)) max_chg->adapter_hw_chg.type = CHG_TYPE_USB; else max_chg->adapter_hw_chg.type = CHG_TYPE_AC; #endif /* reinitialize charger type */ if ((BOARD_NUM(hw_ver) == BOARD_NUM_V11)) max_chg->adapter_hw_chg.type = CHG_TYPE_AC; else max_chg->adapter_hw_chg.type = CHG_TYPE_USB; state = pm8058_irq_get_rt_status(chip, irq); pr_info("%s:charge state=%d, hw_chg_type=%d\n", __func__, state, max_chg->adapter_hw_chg.type); if(state){ /* delay to queue charge insert envent when charger inserted, * need to detect if it is an ac charger */ //msm_charger_notify_event(&max_chg->adapter_hw_chg, // CHG_INSERTED_EVENT); delay_ac_charger_detect = 1; pr_info("%s:delay_ac_charger_detect=%d start ac charger delay work\n", __func__, delay_ac_charger_detect); schedule_delayed_work(&max_chg->ac_charger, AC_CHARGER_DETECT_DELAY); max_chg->present = 1; wake_lock(&max_chg->wl); }else{ delay_ac_charger_detect = 0; pr_info("%s:delay_ac_charger_detect=%d cancel ac charger delay work\n", __func__, delay_ac_charger_detect); cancel_delayed_work(&saved_msm_chg->ac_charger); msm_charger_notify_event(&max_chg->adapter_hw_chg, CHG_REMOVED_EVENT); max_chg->present = 0; wake_unlock(&max_chg->wl); } return IRQ_HANDLED; }
static int pm_chg_get_rt_status(int irq) { int count = 3; int ret; while ((ret = pm8058_irq_get_rt_status(pm8058_chg.pm_chip, irq)) == -EAGAIN && count--) { dev_info(pm8058_chg.dev, "%s trycount=%d\n", __func__, count); cpu_relax(); } if (ret == -EAGAIN) return 0; else return ret; }
/* * The pm8058_no_sw detects the switch press and release operation. * The odd number call is press and even number call is release. * The current state of the button is maintained in othc_sw_state variable. * This isr gets called only for NO type headsets. */ static irqreturn_t pm8058_no_sw(int irq, void *dev_id) { int level; struct pm8058_othc *dd = dev_id; unsigned long flags; spin_lock_irqsave(&dd->lock, flags); if (dd->switch_reject == true) { spin_unlock_irqrestore(&dd->lock, flags); return IRQ_HANDLED; } spin_unlock_irqrestore(&dd->lock, flags); level = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_sw); if (level < 0) { pr_err("%s: Unable to read IRQ status register\n", __func__); return IRQ_HANDLED; } /* * It is necessary to check the software state and the hardware state * to make sure that the residual interrupt after the debounce time does * not disturb the software state machine. */ if (level == 1 && dd->othc_sw_state == false) { /* Switch has been pressed */ dd->othc_sw_state = true; input_report_key(dd->othc_ipd, KEY_MEDIA, 1); } else if (level == 0 && dd->othc_sw_state == true) { /* Switch has been released */ dd->othc_sw_state = false; input_report_key(dd->othc_ipd, KEY_MEDIA, 0); } input_sync(dd->othc_ipd); return IRQ_HANDLED; }
static ssize_t pmic8058_kp_pressed_show(struct device *dev, struct device_attribute *attr, char *buf) { int row, col; int keystate = 0; int pwrkeystate = 0; struct pmic8058_kp *kp = dev_get_drvdata(dev); for (row = 0; row < kp->pdata->num_rows; row++) { for (col = 0; col < kp->pdata->num_cols; col++) { if(!(kp->keystate[row] & (1 << col))) { keystate = 1; } } } pwrkeystate = pm8058_irq_get_rt_status(kp->pm_chip, PM8058_PWRKEY_PRESS_IRQ(PM8058_IRQ_BASE)); if (keystate || pwrkeystate) sprintf(buf, "PRESS"); else sprintf(buf, "RELEASE"); return strlen(buf); }
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; }
static int __devinit kp_probe(struct platform_device *pdev) { struct keypad_pmic_mogami_platform_data *pdata = pdev->dev.platform_data; struct kp_data *dt; struct pm8058_chip *pm_chip = platform_get_drvdata(pdev); int rc, i; if (pm_chip == NULL) { dev_err(&pdev->dev, "no parent pm8058\n"); return -EINVAL; } if (pdata == NULL) { dev_err(&pdev->dev, "no pdata\n"); return -EINVAL; } dt = kzalloc(sizeof(struct kp_data), GFP_KERNEL); if (dt == NULL) return -ENOMEM; dt->pm_chip = pm_chip; dt->num_keys = pdata->keymap_size; dt->pm_gpio_config = pdata->pm_gpio_config; dt->keys = kzalloc(dt->num_keys * sizeof(struct kp_key), GFP_KERNEL); if (dt->keys == NULL) { rc = -ENOMEM; goto err_key_alloc_failed; } platform_set_drvdata(pdev, dt); dt->dev = &pdev->dev; dt->input = input_allocate_device(); if (dt->input == NULL) { dev_err(&pdev->dev, "unable to allocate input device\n"); rc = -ENOMEM; goto err_input_alloc_failed; } for (i = 0; i < dt->num_keys; ++i) { dt->keys[i].irq = pdata->keymap[i].irq; dt->keys[i].gpio = pdata->keymap[i].gpio; dt->keys[i].code = pdata->keymap[i].code; dt->keys[i].wake = pdata->keymap[i].wake; /* our irq status will be a bitmask of the block which * contains a certain gpio. since a block is only eight bits * we need to find the correct bit in the block which * reflects the requested gpio */ dt->keys[i].id = (pdata->keymap[i].gpio - 1) % 8; set_bit(dt->keys[i].code, dt->input->keybit); rc = kp_pm_gpio_config(dt, pm_chip, dt->keys[i].gpio); if (rc) goto err_bad_gpio_config; } dt->input->name = pdata->input_name; dt->input->phys = KP_DEVICE; dt->input->dev.parent = &pdev->dev; dt->input->open = kp_device_open; dt->input->close = kp_device_close; dt->input->id.bustype = BUS_HOST; dt->input->id.version = 0x0001; dt->input->id.product = 0x0001; dt->input->id.vendor = 0x0001; set_bit(EV_KEY, dt->input->evbit); input_set_drvdata(dt->input, dt); rc = input_register_device(dt->input); if (rc < 0) { dev_err(&pdev->dev, "unable to register keypad input device\n"); input_free_device(dt->input); goto err_input_register_failed; } for (i = 0; i < dt->num_keys; ++i) { rc = pm8058_irq_get_rt_status(dt->pm_chip, dt->keys[i].irq); if (rc < 0) { dev_err(&dt->input->dev, "unable to get irq status\n"); /* non-fatal */ } else { dt->keys[i].state = !rc; input_report_key(dt->input, dt->keys[i].code, !rc); } rc = request_threaded_irq(dt->keys[i].irq, NULL, kp_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED, KP_NAME, &dt->input->dev); if (rc < 0) { dev_err(&dt->input->dev, "unable to request irq\n"); goto err_request_irq; } if (!dt->keys[i].wake) disable_irq(dt->keys[i].irq); else enable_irq_wake(dt->keys[i].irq); } return 0; err_request_irq: for (--i; i >= 0; --i) free_irq(dt->keys[i].irq, &dt->input->dev); input_unregister_device(dt->input); err_input_register_failed: err_bad_gpio_config: err_input_alloc_failed: kfree(dt->keys); err_key_alloc_failed: kfree(dt); 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("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; }
static int pm8058_accessory_report(struct pm8058_othc *dd, int status) { #if 0 int i, rc, detected = 0; u8 micbias_status, switch_status; if (dd->accessory_support == false) { /* Report default headset */ switch_set_state(&dd->othc_sdev, !!status); input_report_switch(dd->othc_ipd, SW_HEADPHONE_INSERT, !!status); input_sync(dd->othc_ipd); return 0; } /* For accessory */ if (dd->accessory_support == true && status == 0) { /* Report removal of the accessory. */ /* * If the current accessory is video cable, reject the removal * interrupt. */ pr_info("Accessory [%d] removed\n", dd->curr_accessory); if (dd->curr_accessory == OTHC_SVIDEO_OUT) return 0; switch_set_state(&dd->othc_sdev, 0); input_report_switch(dd->othc_ipd, dd->curr_accessory_code, 0); input_sync(dd->othc_ipd); return 0; } /* Check the MIC_BIAS status */ rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir); if (rc < 0) { pr_err("Unable to read IR status\n"); goto fail_ir_accessory; } micbias_status = !!rc; /* Check the switch status */ rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_sw); if (rc < 0) { pr_err("Unable to read SWITCH status\n"); goto fail_ir_accessory; } switch_status = !!rc; /* Loop through to check which accessory is connected */ for (i = 0; i < dd->num_accessories; i++) { detected = 0; if (dd->accessory_info[i].enabled == false) continue; if (dd->accessory_info[i].detect_flags & OTHC_MICBIAS_DETECT) { if (micbias_status) detected = 1; else continue; } if (dd->accessory_info[i].detect_flags & OTHC_SWITCH_DETECT) { if (switch_status) detected = 1; else continue; } if (dd->accessory_info[i].detect_flags & OTHC_GPIO_DETECT) { rc = gpio_get_value_cansleep( dd->accessory_info[i].gpio); if (rc < 0) continue; if (rc ^ dd->accessory_info[i].active_low) detected = 1; else continue; } if (dd->accessory_info[i].detect_flags & OTHC_ADC_DETECT) detected = accessory_adc_detect(dd, i); if (detected) break; } if (detected) { dd->curr_accessory = dd->accessory_info[i].accessory; dd->curr_accessory_code = dd->accessory_info[i].key_code; /* if Video out cable detected enable the video path*/ if (dd->curr_accessory == OTHC_SVIDEO_OUT) { pm8058_othc_svideo_enable( dd->othc_pdata->micbias_select, true); } else { switch_set_state(&dd->othc_sdev, dd->curr_accessory); input_report_switch(dd->othc_ipd, dd->curr_accessory_code, 1); input_sync(dd->othc_ipd); } pr_info("Accessory [%d] inserted\n", dd->curr_accessory); } else pr_info("Unable to detect accessory. False interrupt!\n"); return 0; fail_ir_accessory: return rc; #endif return 0; }
static int __devinit max8903_probe(struct platform_device *pdev) { struct max8903_struct *max_chg; struct device *dev = &pdev->dev; struct max8903_platform_data *pdata = pdev->dev.platform_data; struct pm8058_chip *chip; int ret = 0; //printk("%s\n", __func__); max_chg = kzalloc(sizeof(struct max8903_struct), GFP_KERNEL); if (max_chg == NULL) { dev_err(dev, "Cannot allocate memory.\n"); return -ENOMEM; } saved_msm_chg = max_chg; if (pdata == NULL) { dev_err(&pdev->dev, "%s no platform data\n", __func__); ret = -EINVAL; goto out; } INIT_DELAYED_WORK(&max_chg->charge_work, max8903_charge); INIT_DELAYED_WORK(&max_chg->ac_charger, ac_charger_detect); wake_lock_init(&max_chg->wl, WAKE_LOCK_SUSPEND, "max8903"); max_chg->dev = &pdev->dev;; max_chg->irq = pdata->irq; max_chg->cen = pdata->cen; max_chg->chg = pdata->chg; max_chg->flt = pdata->flt; max_chg->usus = pdata->usus; max_chg->dock_det = pdata->dock_det; max_chg->usb_chg_enable = 1; /* enable usb charge */ if (BOARD_NUM(hw_ver) == BOARD_NUM_V11) max_chg->adapter_hw_chg.type = CHG_TYPE_AC; else max_chg->adapter_hw_chg.type = CHG_TYPE_USB; max_chg->adapter_hw_chg.rating = 2; max_chg->adapter_hw_chg.name = "max8903-charger"; max_chg->adapter_hw_chg.start_charging = max8903_start_charging; max_chg->adapter_hw_chg.stop_charging = max8903_stop_charging; max_chg->adapter_hw_chg.charging_switched = max8903_charging_switched; platform_set_drvdata(pdev, max_chg); ret = gpio_request(max_chg->cen, "CHARGER_CEN_N"); if (ret) { dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n", __func__, max_chg->cen, ret); goto free_max_chg; } ret = gpio_request(max_chg->chg, "CHARGER_STATUS"); if (ret) { dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n", __func__, max_chg->chg, ret); goto free_cen; } gpio_direction_input(max_chg->chg); ret = gpio_request(max_chg->flt, "CHARGER_FAULT_N"); if (ret) { dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n", __func__, max_chg->flt, ret); goto free_chg; } gpio_direction_input(max_chg->flt); ret = request_threaded_irq(gpio_to_irq(max_chg->flt), NULL, max8903_fault, IRQF_TRIGGER_FALLING ,"MAX8903 Fault", pdev); if (ret) { dev_err(dev, "Cannot request irq %d for Fault (%d)\n", gpio_to_irq(max_chg->flt), ret); goto free_flt; } ret = gpio_request(max_chg->usus, "USUS_CTRL"); if (ret) { dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n", __func__, max_chg->usus, ret); goto err_flt_irq; } ret = gpio_request(max_chg->dock_det, "DOCK_DET"); if (ret) { dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n", __func__, max_chg->dock_det, ret); goto free_usus; } gpio_direction_input(max_chg->dock_det); ret = msm_charger_register(&max_chg->adapter_hw_chg); if (ret) { dev_err(max_chg->dev, "%s msm_charger_register failed for ret =%d\n", __func__, ret); goto free_dock_det; } ret = device_create_file(max_chg->dev, &usb_chg_enable_attr); if (ret) { dev_err(max_chg->dev, "failed: create usb_chg_enable file\n"); } ret = request_threaded_irq(max_chg->irq, NULL, max_valid_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "max_valid_handler", pdev); if (ret) { dev_err(max_chg->dev, "%s request_threaded_irq failed for %d ret =%d\n", __func__, max_chg->irq, ret); goto unregister; } set_irq_wake(max_chg->irq, 1); chip = get_irq_data(max_chg->irq); ret = pm8058_irq_get_rt_status(chip, max_chg->irq); if (ret) { #if 0 if (!gpio_get_value_cansleep(max_chg->dock_det)) /* Dock insert, think it as AC charger */ max_chg->adapter_hw_chg.type = CHG_TYPE_AC; msm_charger_notify_event(&max_chg->adapter_hw_chg, CHG_INSERTED_EVENT); #else /* Charger inserted, but not a valid USB charger * think it as a AC charger */ if (USB_CHG_TYPE__INVALID == cur_chg_type) max_chg->adapter_hw_chg.type = CHG_TYPE_AC; msm_charger_notify_event(&max_chg->adapter_hw_chg, CHG_INSERTED_EVENT); #endif max_chg->present = 1; wake_lock(&max_chg->wl); } msm_register_usb_charger_state(max8903_usb_charger_state); pr_info("%s OK chg_present=%d\n", __func__, max_chg->present); return 0; unregister: msm_charger_unregister(&max_chg->adapter_hw_chg); free_dock_det: gpio_free(max_chg->dock_det); free_usus: gpio_free(max_chg->usus); err_flt_irq: free_irq(gpio_to_irq(max_chg->flt), pdev); free_flt: gpio_free(max_chg->flt); free_chg: gpio_free(max_chg->chg); free_cen: gpio_free(max_chg->cen); free_max_chg: kfree(max_chg); out: return ret; }