/* * This serves as both the GPIO IRQ handler and the debounce handler. When * called as the debounce handler, IRQs are probably not already disabled when * entering this function. */ static int ara_key_irqhandler(int irq, void *context) { struct ara_key_context *key = &the_ara_key; bool value, active; irqstate_t flags; flags = irqsave(); value = !!gpio_get_value(key->db.gpio); active = (value == key->rising_edge); dbg_insane("ara key press value: %u active: %u\n", value, active); if (!debounce_gpio(&key->db, active)) { goto out; } dbg_insane("ara key press value: %u active: %u (stable)\n", value, active); /* if something is pending, cancel it so we can pass the correct active */ if (!work_available(&key->irq_work)) { work_cancel(HPWORK, &key->irq_work); } work_queue(HPWORK, &key->irq_work, ara_key_irqworker, (void*)(uintptr_t)active, 0); out: irqrestore(flags); return OK; }
/** * @brief Configure all the GPIOs associated with a voltage regulator * to their default states. * @param vreg regulator to configure */ int vreg_config(struct vreg *vreg) { unsigned int i; int rc = 0; if (!vreg) { return -ENODEV; } dbg_verbose("%s %s\n", __func__, vreg->name ? vreg->name : "unknown"); for (i = 0; i < vreg->nr_vregs; i++) { if (!&vreg->vregs[i]) { rc = -EINVAL; break; } dbg_insane("%s: %s vreg, gpio %d\n", __func__, vreg->name ? vreg->name : "unknown", vreg->vregs[i].gpio); // First set default value then switch line to output mode gpio_set_value(vreg->vregs[i].gpio, vreg->vregs[i].def_val); gpio_direction_out(vreg->vregs[i].gpio, vreg->vregs[i].def_val); } atomic_init(&vreg->use_count, 0); vreg->power_state = false; return rc; }
/** * @brief Manage the regulator state; Turn it on when needed * @returns: 0 on success, <0 on error */ int vreg_get(struct vreg *vreg) { unsigned int i, rc = 0; if (!vreg) { return -ENODEV; } dbg_verbose("%s %s\n", __func__, vreg->name ? vreg->name : "unknown"); /* Enable the regulator on the first use; Update use count */ if (atomic_inc(&vreg->use_count) == 1) { for (i = 0; i < vreg->nr_vregs; i++) { if (!&vreg->vregs[i]) { rc = -EINVAL; break; } dbg_insane("%s: %s vreg, gpio %d to %d, hold %dus\n", __func__, vreg->name ? vreg->name : "unknown", vreg->vregs[i].gpio, !!vreg->vregs[i].active_high, vreg->vregs[i].hold_time); gpio_set_value(vreg->vregs[i].gpio, vreg->vregs[i].active_high); up_udelay(vreg->vregs[i].hold_time); } } /* Update state */ vreg->power_state = true; return rc; }
/** * @brief Manage the regulator state; Turn it off when unused * @returns: 0 on success, <0 on error */ int vreg_put(struct vreg *vreg) { unsigned int i, rc = 0; if (!vreg) { return -ENODEV; } dbg_verbose("%s %s\n", __func__, vreg->name ? vreg->name : "unknown"); /* If already disabled, do nothing */ if (!atomic_get(&vreg->use_count)) return rc; /* Disable the regulator on the last use; Update use count */ if (!atomic_dec(&vreg->use_count)) { for (i = 0; i < vreg->nr_vregs; i++) { if (!&vreg->vregs[i]) { rc = -EINVAL; break; } dbg_insane("%s: %s vreg, gpio %08x to %d\n", __func__, vreg->name ? vreg->name : "unknown", vreg->vregs[i].gpio, !vreg->vregs[i].active_high); gpio_set_value(vreg->vregs[i].gpio, !vreg->vregs[i].active_high); } /* Update state */ vreg->power_state = false; } return rc; }