staticint brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv, unsignedint enable)
{ int ret = 0;
if (enable)
ret = enable_irq_wake(priv->parent_wake_irq); else
ret = disable_irq_wake(priv->parent_wake_irq); if (ret)
dev_err(&priv->pdev->dev, "failed to %s wake-up interrupt\n",
str_enable_disable(enable)); return ret;
}
/* * Do not do anything specific for now, suspend/resume callbacks will * configure the interrupt mask appropriately
*/ if (enable)
bank->wake_active |= mask; else
bank->wake_active &= ~mask;
staticstruct brcmstb_gpio_bank *brcmstb_gpio_hwirq_to_bank( struct brcmstb_gpio_priv *priv, irq_hw_number_t hwirq)
{ struct brcmstb_gpio_bank *bank; int i = 0;
/* banks are in descending order */
list_for_each_entry_reverse(bank, &priv->bank_list, node) {
i += bank->gc.ngpio; if (hwirq < i) return bank;
} return NULL;
}
/* * This lock class tells lockdep that GPIO irqs are in a different * category than their parents, so it won't report false recursion.
*/ staticstruct lock_class_key brcmstb_gpio_irq_lock_class; staticstruct lock_class_key brcmstb_gpio_irq_request_class;
/* Make sure that the number of banks matches up between properties */ staticint brcmstb_gpio_sanity_check_banks(struct device *dev, struct device_node *np, struct resource *res)
{ int res_num_banks = resource_size(res) / GIO_BANK_SIZE; int num_banks =
of_property_count_u32_elems(np, "brcm,gpio-bank-widths");
if (res_num_banks != num_banks) {
dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n",
res_num_banks, num_banks); return -EINVAL;
} else { return 0;
}
}
if (priv->parent_irq > 0)
irq_set_chained_handler_and_data(priv->parent_irq, NULL, NULL);
/* Remove all IRQ mappings and delete the domain */ if (priv->irq_domain) { for (offset = 0; offset < priv->num_gpios; offset++) {
virq = irq_find_mapping(priv->irq_domain, offset);
irq_dispose_mapping(virq);
}
irq_domain_remove(priv->irq_domain);
}
/* * You can lose return values below, but we report all errors, and it's * more important to actually perform all of the steps.
*/
list_for_each_entry(bank, &priv->bank_list, node)
gpiochip_remove(&bank->gc);
}
if (unlikely(offset >= bank->width)) {
dev_warn_ratelimited(&priv->pdev->dev, "Received request for invalid GPIO offset %d\n",
gpiospec->args[0]);
}
if (flags)
*flags = gpiospec->args[1];
return offset;
}
/* priv->parent_irq and priv->num_gpios must be set before calling */ staticint brcmstb_gpio_irq_setup(struct platform_device *pdev, struct brcmstb_gpio_priv *priv)
{ struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; int err;
if (of_property_read_bool(np, "wakeup-source")) {
priv->parent_wake_irq = platform_get_irq(pdev, 1); if (priv->parent_wake_irq < 0) {
priv->parent_wake_irq = 0;
dev_warn(dev, "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep");
} else { /* * Set wakeup capability so we can process boot-time * "wakeups" (e.g., from S5 cold boot)
*/
device_set_wakeup_capable(dev, true);
device_wakeup_enable(dev);
err = devm_request_irq(dev, priv->parent_wake_irq,
brcmstb_gpio_wake_irq_handler,
IRQF_SHARED, "brcmstb-gpio-wake", priv);
if (err < 0) {
dev_err(dev, "Couldn't request wake IRQ"); goto out_free_domain;
}
}
}
if (brcmstb_gpio_sanity_check_banks(dev, np, res)) return -EINVAL;
/* * MIPS endianness is configured by boot strap, which also reverses all * bus endianness (i.e., big-endian CPU + big endian bus ==> native * endian I/O). * * Other architectures (e.g., ARM) either do not support big endian, or * else leave I/O in little endian mode.
*/ #ifdefined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER; #endif
/* * If bank_width is 0, then there is an empty bank in the * register block. Special handling for this case.
*/ if (bank_width == 0) {
dev_dbg(dev, "Width 0 found: Empty bank @ %d\n",
num_banks);
num_banks++;
num_gpios += MAX_GPIO_PER_BANK; continue;
}
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); if (!bank) {
err = -ENOMEM; goto fail;
}
/* * Regs are 4 bytes wide, have data reg, no set/clear regs, * and direction bits have 0 = output and 1 = input
*/
gc = &bank->gc;
err = bgpio_init(gc, dev, 4,
reg_base + GIO_DATA(bank->id),
NULL, NULL, NULL,
reg_base + GIO_IODIR(bank->id), flags); if (err) {
dev_err(dev, "bgpio_init() failed\n"); goto fail;
}
gc->owner = THIS_MODULE;
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); if (!gc->label) {
err = -ENOMEM; goto fail;
}
gc->of_gpio_n_cells = 2;
gc->of_xlate = brcmstb_gpio_of_xlate; /* not all ngpio lines are valid, will use bank width later */
gc->ngpio = MAX_GPIO_PER_BANK;
gc->offset = bank->id * MAX_GPIO_PER_BANK;
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free; if (priv->parent_irq > 0)
gc->to_irq = brcmstb_gpio_to_irq;
/* * Mask all interrupts by default, since wakeup interrupts may * be retained from S5 cold boot
*/
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
err = gpiochip_add_data(gc, bank); if (err) {
dev_err(dev, "Could not add gpiochip for bank %d\n",
bank->id); goto fail;
}
num_gpios += gc->ngpio;
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.