// SPDX-License-Identifier: GPL-2.0-only /* * GPIO driver for the IP block found in the Nomadik SoC; it is an AMBA device, * managing 32 pins with alternate functions. It can also handle the STA2X11 * block from ST. * * The GPIO chips are shared with pinctrl-nomadik if used; it needs access for * pinmuxing functionality and others. * * This driver also handles the mobileye,eyeq5-gpio compatible. It is an STA2X11 * but with only data, direction and interrupts register active. We want to * avoid touching SLPM, RWIMSC, FWIMSC, AFSLA and AFSLB registers; that is, * wake and alternate function registers. It is NOT compatible with * pinctrl-nomadik. * * Copyright (C) 2008,2009 STMicroelectronics * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org>
*/ #include <linux/cleanup.h> #include <linux/clk.h> #include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mod_devicetable.h> #include <linux/pinctrl/pinctrl.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/reset.h> #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/string_choices.h> #include <linux/types.h>
if (which == NORMAL) {
rimscreg = NMK_GPIO_RIMSC;
fimscreg = NMK_GPIO_FIMSC;
rimscval = &nmk_chip->rimsc;
fimscval = &nmk_chip->fimsc;
} else { /* We should NOT have been called. */ if (WARN_ON(nmk_chip->is_mobileye_soc)) return;
rimscreg = NMK_GPIO_RWIMSC;
fimscreg = NMK_GPIO_FWIMSC;
rimscval = &nmk_chip->rwimsc;
fimscval = &nmk_chip->fwimsc;
}
/* we must individually set/clear the two edges */ if (nmk_chip->edge_rising & BIT(offset)) { if (enable)
*rimscval |= BIT(offset); else
*rimscval &= ~BIT(offset);
writel(*rimscval, nmk_chip->addr + rimscreg);
} if (nmk_chip->edge_falling & BIT(offset)) { if (enable)
*fimscval |= BIT(offset); else
*fimscval &= ~BIT(offset);
writel(*fimscval, nmk_chip->addr + fimscreg);
}
}
staticvoid __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, int offset, bool on)
{ /* We should NOT have been called. */ if (WARN_ON(nmk_chip->is_mobileye_soc)) return;
/* * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is * disabled, since setting SLPM to 1 increases power consumption, and * wakeup is anyhow controlled by the RIMSC and FIMSC registers.
*/ if (nmk_chip->sleepmode && on) {
__nmk_gpio_set_slpm(nmk_chip, offset,
NMK_GPIO_SLPM_WAKEUP_ENABLE);
}
/* Ensure we cannot leave pending bits; this should never occur. */ if (unlikely(status & ~mask))
writel(status & ~mask, nmk_chip->addr + NMK_GPIO_IC);
val = nmk_gpio_get_input(chip, offset);
seq_printf(s, " VAL %d", val);
/* * This races with request_irq(), set_irq_type(), * and set_irq_wake() ... but those are "rare".
*/ if (irq > 0 && irq_has_action(irq)) { char *trigger; bool wake;
for (i = 0; i < chip->ngpio; i++, gpio++) {
nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio);
seq_puts(s, "\n");
}
}
#else
#define nmk_gpio_dbg_show NULL
#endif
/* * We will allocate memory for the state container using devm* allocators * binding to the first device reaching this point, it doesn't matter if * it is the pin controller or GPIO driver. However we need to use the right * platform device when looking up resources so pay attention to pdev.
*/ struct nmk_gpio_chip *nmk_gpio_populate_chip(struct fwnode_handle *fwnode, struct platform_device *pdev)
{ struct nmk_gpio_chip *nmk_chip; struct platform_device *gpio_pdev; struct device *dev = &pdev->dev; struct reset_control *reset; struct device *gpio_dev; struct gpio_chip *chip; struct resource *res; struct clk *clk; void __iomem *base;
u32 id, ngpio; int ret;
gpio_dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode); if (!gpio_dev) {
dev_err(dev, "populate \"%pfwP\": device not found\n", fwnode); return ERR_PTR(-ENODEV);
}
gpio_pdev = to_platform_device(gpio_dev);
if (device_property_read_u32(gpio_dev, "gpio-bank", &id)) {
dev_err(dev, "populate: gpio-bank property not found\n");
platform_device_put(gpio_pdev); return ERR_PTR(-EINVAL);
}
/* NOTE: different devices! No devm_platform_ioremap_resource() here! */
res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) {
platform_device_put(gpio_pdev); return ERR_CAST(base);
}
nmk_chip->addr = base;
/* NOTE: do not use devm_ here! */
clk = clk_get_optional(gpio_dev, NULL); if (IS_ERR(clk)) {
platform_device_put(gpio_pdev); return ERR_CAST(clk);
}
clk_prepare(clk);
nmk_chip->clk = clk;
/* NOTE: do not use devm_ here! */
reset = reset_control_get_optional_shared(gpio_dev, NULL); if (IS_ERR(reset)) {
clk_unprepare(clk);
clk_put(clk);
platform_device_put(gpio_pdev);
dev_err(dev, "failed getting reset control: %pe\n",
reset); return ERR_CAST(reset);
}
/* * Reset might be shared and asserts/deasserts calls are unbalanced. We * only support sharing this reset with other gpio-nomadik devices that * use this reset to ensure deassertion at probe.
*/
ret = reset_control_deassert(reset); if (ret) {
reset_control_put(reset);
clk_unprepare(clk);
clk_put(clk);
platform_device_put(gpio_pdev);
dev_err(dev, "failed reset deassert: %d\n", ret); return ERR_PTR(ret);
}
/* Correct platform device ID */
pdev->id = nmk_chip->bank;
irq = platform_get_irq(pdev, 0); if (irq < 0) return irq;
/* * The virt address in nmk_chip->addr is in the nomadik register space, * so we can simply convert the resource address, without remapping
*/
nmk_chip->sleepmode = supports_sleepmode;
spin_lock_init(&nmk_chip->lock);
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.