staticvoid omap_set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
{
bank->context.oe = omap_gpio_rmw(bank->base + bank->regs->direction,
BIT(gpio), is_input);
}
/* set data out value using dedicate set/clear register */ staticvoid omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset, int enable)
{ void __iomem *reg = bank->base;
u32 l = BIT(offset);
/* set data out value using mask register */ staticvoid omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset, int enable)
{
bank->context.dataout = omap_gpio_rmw(bank->base + bank->regs->dataout,
BIT(offset), enable);
}
staticinlinevoid omap_gpio_dbck_disable(struct gpio_bank *bank)
{ if (bank->dbck_enable_mask && bank->dbck_enabled) { /* * Disable debounce before cutting it's clock. If debounce is * enabled but the clock is not, GPIO module seems to be unable * to detect events and generate interrupts at least on OMAP3.
*/
writel_relaxed(0, bank->base + bank->regs->debounce_en);
/** * omap2_set_gpio_debounce - low level gpio debounce time * @bank: the gpio bank we're acting upon * @offset: the gpio number on this @bank * @debounce: debounce time to use * * OMAP's debounce time is in 31us steps * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 * so we need to convert and round up to the closest unit. * * Return: 0 on success, negative error otherwise.
*/ staticint omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, unsigned debounce)
{
u32 val;
u32 l; bool enable = !!debounce;
if (!bank->dbck_flag) return -ENOTSUPP;
if (enable) {
debounce = DIV_ROUND_UP(debounce, 31) - 1; if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce) return -EINVAL;
}
val = omap_gpio_rmw(bank->base + bank->regs->debounce_en, l, enable);
bank->dbck_enable_mask = val;
clk_disable(bank->dbck); /* * Enable debounce clock per module. * This call is mandatory because in omap_gpio_request() when * *_runtime_get_sync() is called, _gpio_dbck_enable() within * runtime callbck fails to turn on dbck because dbck_enable_mask * used within _gpio_dbck_enable() is still not initialized at * that point. Therefore we have to enable dbck here.
*/
omap_gpio_dbck_enable(bank); if (bank->dbck_enable_mask) {
bank->context.debounce = debounce;
bank->context.debounce_en = val;
}
return 0;
}
/** * omap_clear_gpio_debounce - clear debounce settings for a gpio * @bank: the gpio bank we're acting upon * @offset: the gpio number on this @bank * * If a gpio is using debounce, then clear the debounce enable bit and if * this is the only gpio in this bank using debounce, then clear the debounce * time too. The debounce clock will also be disabled when calling this function * if this is the only gpio in the bank using debounce.
*/ staticvoid omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
{
u32 gpio_bit = BIT(offset);
/* * Off mode wake-up capable GPIOs in bank(s) that are in the wakeup domain. * See TRM section for GPIO for "Wake-Up Generation" for the list of GPIOs * in wakeup domain. If bank->non_wakeup_gpios is not configured, assume none * are capable waking up the system from off mode.
*/ staticbool omap_gpio_is_off_wakeup_capable(struct gpio_bank *bank, u32 gpio_mask)
{
u32 no_wake = bank->non_wakeup_gpios;
/* * We need the edge detection enabled for to allow the GPIO block * to be woken from idle state. Set the appropriate edge detection * in addition to the level detection.
*/
omap_gpio_rmw(base + bank->regs->risingdetect, gpio_bit,
trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
omap_gpio_rmw(base + bank->regs->fallingdetect, gpio_bit,
trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
/* This part needs to be executed always for OMAP{34xx, 44xx} */ if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) { /* * Log the edge gpio and manually trigger the IRQ * after resume if the input level changes * to avoid irq lost during PER RET/OFF mode * Applies for omap2 non-wakeup gpio and all omap3 gpios
*/ if (trigger & IRQ_TYPE_EDGE_BOTH)
bank->enabled_non_wakeup_gpios |= gpio_bit; else
bank->enabled_non_wakeup_gpios &= ~gpio_bit;
}
}
/* * This only applies to chips that can't do both rising and falling edge * detection at once. For all other chips, this function is a noop.
*/ staticvoid omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
{ if (IS_ENABLED(CONFIG_ARCH_OMAP1) && bank->regs->irqctrl) { void __iomem *reg = bank->base + bank->regs->irqctrl;
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
irq_set_handler_locked(d, handle_level_irq); elseif (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) /* * Edge IRQs are already cleared/acked in irq_handler and * not need to be masked, as result handle_edge_irq() * logic is excessed here and may cause lose of interrupts. * So just use handle_simple_irq.
*/
irq_set_handler_locked(d, handle_simple_irq);
/* * Program GPIO wakeup along with IRQ enable to satisfy OMAP4430 TRM * note requiring correlation between the IRQ enable registers and * the wakeup registers. In any case, we want wakeup from idle * enabled for the GPIOs which support this feature.
*/ if (bank->regs->wkup_en &&
(bank->regs->edgectrl1 || !(bank->non_wakeup_gpios & gpio_mask))) {
bank->context.wake_en =
omap_gpio_rmw(bank->base + bank->regs->wkup_en,
gpio_mask, enable);
}
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ staticint omap_gpio_wake_enable(struct irq_data *d, unsignedint enable)
{ struct gpio_bank *bank = omap_irq_data_get_bank(d);
return irq_set_irq_wake(bank->irq, enable);
}
/* * We need to unmask the GPIO bank interrupt as soon as possible to * avoid missing GPIO interrupts for other lines in the bank. * Then we need to mask-read-clear-unmask the triggered GPIO lines * in the bank to avoid missing nested interrupts for a GPIO line. * If we wait to unmask individual GPIO lines in the bank after the * line's interrupt handler has been run, we may miss some nested * interrupts.
*/ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
{ void __iomem *isr_reg = NULL;
u32 enabled, isr, edge; unsignedint bit; struct gpio_bank *bank = gpiobank; unsignedlong wa_lock_flags; unsignedlong lock_flags;
isr_reg = bank->base + bank->regs->irqstatus; if (WARN_ON(!isr_reg)) gotoexit;
if (WARN_ONCE(!pm_runtime_active(bank->chip.parent), "gpio irq%i while runtime suspended?\n", irq)) return IRQ_NONE;
while (1) {
raw_spin_lock_irqsave(&bank->lock, lock_flags);
/* * Clear edge sensitive interrupts before calling handler(s) * so subsequent edge transitions are not missed while the * handlers are running.
*/
edge = isr & ~bank->level_mask; if (edge)
omap_clear_gpio_irqbank(bank, edge);
while (isr) {
bit = __ffs(isr);
isr &= ~(BIT(bit));
raw_spin_lock_irqsave(&bank->lock, lock_flags); /* * Some chips can't respond to both rising and falling * at the same time. If this irq was requested with * both flags, we need to flip the ICR data for the IRQ * to respond to the IRQ for the opposite direction. * This will be indicated in the bank toggle_mask.
*/ if (bank->toggle_mask & (BIT(bit)))
omap_toggle_gpio_edge_triggering(bank, bit);
/* * For level-triggered GPIOs, clearing must be done after the source * is cleared, thus after the handler has run. OMAP4 needs this done * after enabing the interrupt to clear the wakeup status.
*/ if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
omap_clear_gpio_irqstatus(bank, offset);
if (trigger)
omap_set_gpio_triggering(bank, offset, trigger);
raw_spin_lock_irqsave(&bank->lock, flags);
ret = omap2_set_gpio_debounce(bank, offset, debounce);
raw_spin_unlock_irqrestore(&bank->lock, flags);
if (ret)
dev_info(chip->parent, "Could not set line %u debounce to %u microseconds (%d)",
offset, debounce, ret);
return ret;
}
staticint omap_gpio_set_config(struct gpio_chip *chip, unsigned offset, unsignedlong config)
{
u32 debounce; int ret = -ENOTSUPP;
switch (pinconf_to_config_param(config)) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN:
ret = gpiochip_generic_config(chip, offset, config); break; case PIN_CONFIG_INPUT_DEBOUNCE:
debounce = pinconf_to_config_argument(config);
ret = omap_gpio_debounce(chip, offset, debounce); break; default: break;
}
if (bank->is_mpuio) {
writel_relaxed(l, bank->base + bank->regs->irqenable); return;
}
omap_gpio_rmw(base + bank->regs->irqenable, l,
bank->regs->irqenable_inv);
omap_gpio_rmw(base + bank->regs->irqstatus, l,
!bank->regs->irqenable_inv); if (bank->regs->debounce_en)
writel_relaxed(0, base + bank->regs->debounce_en);
/* Save OE default value (0xffffffff) in the context */
bank->context.oe = readl_relaxed(bank->base + bank->regs->direction); /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl)
writel_relaxed(0, base + bank->regs->ctrl);
}
writel_relaxed(bank->context.sysconfig, base + regs->sysconfig);
writel_relaxed(bank->context.wake_en, base + regs->wkup_en);
writel_relaxed(bank->context.ctrl, base + regs->ctrl);
writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0);
writel_relaxed(bank->context.leveldetect1, base + regs->leveldetect1);
writel_relaxed(bank->context.risingdetect, base + regs->risingdetect);
writel_relaxed(bank->context.fallingdetect, base + regs->fallingdetect);
writel_relaxed(bank->context.dataout, base + regs->dataout);
writel_relaxed(bank->context.oe, base + regs->direction);
if (bank->dbck_enable_mask) {
writel_relaxed(bank->context.debounce, base + regs->debounce);
writel_relaxed(bank->context.debounce_en,
base + regs->debounce_en);
}
writel_relaxed(bank->context.irqenable1, base + regs->irqenable);
writel_relaxed(bank->context.irqenable2, base + regs->irqenable2);
}
/* Save syconfig, it's runtime value can be different from init value */ if (bank->loses_context)
bank->context.sysconfig = readl_relaxed(base + bank->regs->sysconfig);
if (!bank->enabled_non_wakeup_gpios) goto update_gpio_context_count;
if (!may_lose_context) goto update_gpio_context_count;
/* * If going to OFF, remove triggering for all wkup domain * non-wakeup GPIOs. Otherwise spurious IRQs will be * generated. See OMAP2420 Errata item 1.101.
*/ if (!bank->loses_context && bank->enabled_non_wakeup_gpios) {
nowake = bank->enabled_non_wakeup_gpios;
omap_gpio_rmw(base + bank->regs->fallingdetect, nowake, ~nowake);
omap_gpio_rmw(base + bank->regs->risingdetect, nowake, ~nowake);
}
update_gpio_context_count: if (bank->get_context_loss_count)
bank->context_loss_count =
bank->get_context_loss_count(dev);
omap_gpio_dbck_disable(bank);
}
staticvoid omap_gpio_unidle(struct gpio_bank *bank)
{ struct device *dev = bank->chip.parent;
u32 l = 0, gen, gen0, gen1; int c;
/* * On the first resume during the probe, the context has not * been initialised and so initialise it now. Also initialise * the context loss count.
*/ if (bank->loses_context && !bank->context_valid) {
omap_gpio_init_context(bank);
if (bank->get_context_loss_count)
bank->context_loss_count =
bank->get_context_loss_count(dev);
}
omap_gpio_dbck_enable(bank);
if (bank->loses_context) { if (!bank->get_context_loss_count) {
omap_gpio_restore_context(bank);
} else {
c = bank->get_context_loss_count(dev); if (c != bank->context_loss_count) {
omap_gpio_restore_context(bank);
} else { return;
}
}
} else { /* Restore changes done for OMAP2420 errata 1.101 */
writel_relaxed(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
}
l = readl_relaxed(bank->base + bank->regs->datain);
/* * Check if any of the non-wakeup interrupt GPIOs have changed * state. If so, generate an IRQ by software. This is * horribly racy, but it's the best we can do to work around * this silicon bug.
*/
l ^= bank->saved_datain;
l &= bank->enabled_non_wakeup_gpios;
/* * No need to generate IRQs for the rising edge for gpio IRQs * configured with falling edge only; and vice versa.
*/
gen0 = l & bank->context.fallingdetect;
gen0 &= bank->saved_datain;
gen1 = l & bank->context.risingdetect;
gen1 &= ~(bank->saved_datain);
/* FIXME: Consider GPIO IRQs with level detections properly! */
gen = l & (~(bank->context.fallingdetect) &
~(bank->context.risingdetect)); /* Consider all GPIO IRQs needed to be updated */
gen |= gen0 | gen1;
/* Static mapping, never released */
bank->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(bank->base)) { return PTR_ERR(bank->base);
}
if (bank->dbck_flag) {
bank->dbck = devm_clk_get(dev, "dbclk"); if (IS_ERR(bank->dbck)) {
dev_err(dev, "Could not get gpio dbck. Disable debounce\n");
bank->dbck_flag = false;
} else {
clk_prepare(bank->dbck);
}
}
platform_set_drvdata(pdev, bank);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
if (bank->is_mpuio)
omap_mpuio_init(bank);
omap_gpio_mod_init(bank);
ret = omap_gpio_chip_init(bank, dev); if (ret) {
pm_runtime_put_sync(dev);
pm_runtime_disable(dev); if (bank->dbck_flag)
clk_unprepare(bank->dbck); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.