[U-Boot] [PATCH v2 11/22] GPIO: STM32: make DTS-aware
Benjamin Tietz
uboot at dresden.micronet24.de
Mon Jun 20 20:26:56 CEST 2016
From: Benjamin Tietz <benjamin at micronet24.de>
If CONFIG_DM_GPIO is enabled, the STM32 SOC GPIO driver will switch it's behaviour
from implementing the gpio_*() interface directly to provide a gpio-device.
---
drivers/gpio/stm32_gpio.c | 133 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c
index be662c3..844b3e1 100644
--- a/drivers/gpio/stm32_gpio.c
+++ b/drivers/gpio/stm32_gpio.c
@@ -220,6 +220,138 @@ out:
return rv;
}
+#ifdef CONFIG_DM_GPIO
+#include <asm-generic/gpio.h>
+#include <dm/device.h>
+#include <clk.h>
+#include <dt-bindings/gpio/gpio.h>
+
+struct stm32_gpio_priv {
+ int portnum;
+ u32 requested;
+};
+
+static int stm32_gpio_request(struct udevice *dev, unsigned offset, const char *label)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ if(priv->requested & (1<<offset))
+ return -EBUSY;
+ if(!priv->requested) {
+ struct udevice *clk = NULL;
+ int clk_id;
+ if((clk_id = clk_get_by_index(dev, 0, &clk)) >= 0)
+ clk_enable(clk, clk_id);
+ }
+ priv->requested |= 1<<offset;
+ return 0;
+}
+
+static int stm32_gpio_free(struct udevice *dev, unsigned offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ priv->requested &= ~(1<<offset);
+ if(!priv->requested) {
+ struct udevice *clk = NULL;
+ int clk_id;
+ if((clk_id = clk_get_by_index(dev, 0, &clk)) >= 0)
+ clk_disable(clk, clk_id);
+ }
+ return 0;
+}
+
+static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_dsc dsc = {
+ .port = priv->portnum,
+ .pin = offset,
+ };
+ return stm32_gpio_config(&dsc, &ctl_in);
+}
+
+static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, int value)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_dsc dsc = {
+ .port = priv->portnum,
+ .pin = offset,
+ };
+ int ret = stm32_gpio_config(&dsc, &ctl_out);
+ if(ret >= 0)
+ ret = stm32_gpout_set(&dsc, value);
+ return ret;
+}
+
+static int stm32_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_dsc dsc = {
+ .port = priv->portnum,
+ .pin = offset,
+ };
+ return !!stm32_gpin_get(&dsc);
+}
+
+static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_dsc dsc = {
+ .port = priv->portnum,
+ .pin = offset,
+ };
+ return stm32_gpout_set(&dsc, value);
+}
+
+static struct dm_gpio_ops stm32_gpio_ops = {
+ .request = stm32_gpio_request,
+ .free = stm32_gpio_free,
+ .direction_input = stm32_gpio_direction_input,
+ .direction_output = stm32_gpio_direction_output,
+ .get_value = stm32_gpio_get_value,
+ .set_value = stm32_gpio_set_value,
+};
+
+static int stm32_gpio_probe(struct udevice *dev)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int i;
+ priv->requested = 0;
+
+ addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ if(size < sizeof(struct stm32_gpio_ctl))
+ return -EINVAL;
+
+ for(i=0; i < sizeof(io_base)/sizeof(io_base[0]); i++) {
+ if(io_base[i] != addr)
+ continue;
+ priv->portnum = i;
+ uc_priv->bank_name = dev->name;
+ uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "gpio-count", 16);
+ return 0;
+ }
+ return -ENXIO;
+}
+
+static const struct udevice_id stm32_gpio_ids[] = {
+ { .compatible = "st,stm32-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(stm32_gpio) = {
+ .name = "stm32_gpio",
+ .id = UCLASS_GPIO,
+ .ops = &stm32_gpio_ops,
+ .probe = stm32_gpio_probe,
+ .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv),
+ .of_match = stm32_gpio_ids,
+};
+#else
/* Common GPIO API */
int gpio_request(unsigned gpio, const char *label)
@@ -277,3 +409,4 @@ int gpio_set_value(unsigned gpio, int value)
return stm32_gpout_set(&dsc, value);
}
+#endif
More information about the U-Boot
mailing list