1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2efad6cf8SStephen Warren /*
3efad6cf8SStephen Warren * Copyright (C) 2012 Vikram Narayananan
4efad6cf8SStephen Warren * <vikram186@gmail.com>
5efad6cf8SStephen Warren */
6efad6cf8SStephen Warren
7efad6cf8SStephen Warren #include <common.h>
841e98e01SSimon Glass #include <dm.h>
9caf2233bSAlexander Graf #include <dm/pinctrl.h>
1041e98e01SSimon Glass #include <errno.h>
11efad6cf8SStephen Warren #include <asm/gpio.h>
12efad6cf8SStephen Warren #include <asm/io.h>
134faf5f93SFabian Vogt #include <fdtdec.h>
14efad6cf8SStephen Warren
1541e98e01SSimon Glass struct bcm2835_gpios {
1641e98e01SSimon Glass struct bcm2835_gpio_regs *reg;
17caf2233bSAlexander Graf struct udevice *pinctrl;
1841e98e01SSimon Glass };
1941e98e01SSimon Glass
bcm2835_gpio_direction_input(struct udevice * dev,unsigned gpio)2041e98e01SSimon Glass static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio)
2141e98e01SSimon Glass {
2241e98e01SSimon Glass struct bcm2835_gpios *gpios = dev_get_priv(dev);
23efad6cf8SStephen Warren unsigned val;
24efad6cf8SStephen Warren
2541e98e01SSimon Glass val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
26efad6cf8SStephen Warren val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
27efad6cf8SStephen Warren val |= (BCM2835_GPIO_INPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
2841e98e01SSimon Glass writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
29efad6cf8SStephen Warren
30efad6cf8SStephen Warren return 0;
31efad6cf8SStephen Warren }
32efad6cf8SStephen Warren
bcm2835_gpio_direction_output(struct udevice * dev,unsigned int gpio,int value)33caf2233bSAlexander Graf static int bcm2835_gpio_direction_output(struct udevice *dev, unsigned int gpio,
3441e98e01SSimon Glass int value)
35efad6cf8SStephen Warren {
3641e98e01SSimon Glass struct bcm2835_gpios *gpios = dev_get_priv(dev);
37efad6cf8SStephen Warren unsigned val;
38efad6cf8SStephen Warren
39efad6cf8SStephen Warren gpio_set_value(gpio, value);
40efad6cf8SStephen Warren
4141e98e01SSimon Glass val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
42efad6cf8SStephen Warren val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
43efad6cf8SStephen Warren val |= (BCM2835_GPIO_OUTPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
4441e98e01SSimon Glass writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
45efad6cf8SStephen Warren
46efad6cf8SStephen Warren return 0;
47efad6cf8SStephen Warren }
48efad6cf8SStephen Warren
bcm2835_get_value(const struct bcm2835_gpios * gpios,unsigned gpio)4941e98e01SSimon Glass static int bcm2835_get_value(const struct bcm2835_gpios *gpios, unsigned gpio)
5041e98e01SSimon Glass {
51efad6cf8SStephen Warren unsigned val;
52efad6cf8SStephen Warren
5341e98e01SSimon Glass val = readl(&gpios->reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]);
54efad6cf8SStephen Warren
55efad6cf8SStephen Warren return (val >> BCM2835_GPIO_COMMON_SHIFT(gpio)) & 0x1;
56efad6cf8SStephen Warren }
57efad6cf8SStephen Warren
bcm2835_gpio_get_value(struct udevice * dev,unsigned gpio)5841e98e01SSimon Glass static int bcm2835_gpio_get_value(struct udevice *dev, unsigned gpio)
59efad6cf8SStephen Warren {
6041e98e01SSimon Glass const struct bcm2835_gpios *gpios = dev_get_priv(dev);
6141e98e01SSimon Glass
6241e98e01SSimon Glass return bcm2835_get_value(gpios, gpio);
6341e98e01SSimon Glass }
6441e98e01SSimon Glass
bcm2835_gpio_set_value(struct udevice * dev,unsigned gpio,int value)6541e98e01SSimon Glass static int bcm2835_gpio_set_value(struct udevice *dev, unsigned gpio,
6641e98e01SSimon Glass int value)
6741e98e01SSimon Glass {
6841e98e01SSimon Glass struct bcm2835_gpios *gpios = dev_get_priv(dev);
6941e98e01SSimon Glass u32 *output_reg = value ? gpios->reg->gpset : gpios->reg->gpclr;
70efad6cf8SStephen Warren
71efad6cf8SStephen Warren writel(1 << BCM2835_GPIO_COMMON_SHIFT(gpio),
72efad6cf8SStephen Warren &output_reg[BCM2835_GPIO_COMMON_BANK(gpio)]);
73efad6cf8SStephen Warren
74efad6cf8SStephen Warren return 0;
75efad6cf8SStephen Warren }
7641e98e01SSimon Glass
bcm2835_gpio_get_function(struct udevice * dev,unsigned offset)7704a993feSAlexander Graf static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset)
7804a993feSAlexander Graf {
79caf2233bSAlexander Graf struct bcm2835_gpios *priv = dev_get_priv(dev);
80caf2233bSAlexander Graf int funcid;
81caf2233bSAlexander Graf
82caf2233bSAlexander Graf funcid = pinctrl_get_gpio_mux(priv->pinctrl, 0, offset);
8304a993feSAlexander Graf
8404a993feSAlexander Graf switch (funcid) {
8504a993feSAlexander Graf case BCM2835_GPIO_OUTPUT:
8641e98e01SSimon Glass return GPIOF_OUTPUT;
8704a993feSAlexander Graf case BCM2835_GPIO_INPUT:
8841e98e01SSimon Glass return GPIOF_INPUT;
8904a993feSAlexander Graf default:
9004a993feSAlexander Graf return GPIOF_FUNC;
9104a993feSAlexander Graf }
9241e98e01SSimon Glass }
9341e98e01SSimon Glass
9441e98e01SSimon Glass static const struct dm_gpio_ops gpio_bcm2835_ops = {
9541e98e01SSimon Glass .direction_input = bcm2835_gpio_direction_input,
9641e98e01SSimon Glass .direction_output = bcm2835_gpio_direction_output,
9741e98e01SSimon Glass .get_value = bcm2835_gpio_get_value,
9841e98e01SSimon Glass .set_value = bcm2835_gpio_set_value,
9941e98e01SSimon Glass .get_function = bcm2835_gpio_get_function,
10041e98e01SSimon Glass };
10141e98e01SSimon Glass
bcm2835_gpio_probe(struct udevice * dev)10241e98e01SSimon Glass static int bcm2835_gpio_probe(struct udevice *dev)
10341e98e01SSimon Glass {
10441e98e01SSimon Glass struct bcm2835_gpios *gpios = dev_get_priv(dev);
10541e98e01SSimon Glass struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev);
106e564f054SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
10741e98e01SSimon Glass
10841e98e01SSimon Glass uc_priv->bank_name = "GPIO";
10941e98e01SSimon Glass uc_priv->gpio_count = BCM2835_GPIO_COUNT;
11041e98e01SSimon Glass gpios->reg = (struct bcm2835_gpio_regs *)plat->base;
11141e98e01SSimon Glass
112caf2233bSAlexander Graf /* We know we're spawned by the pinctrl driver */
113caf2233bSAlexander Graf gpios->pinctrl = dev->parent;
114caf2233bSAlexander Graf
11541e98e01SSimon Glass return 0;
11641e98e01SSimon Glass }
11741e98e01SSimon Glass
1184faf5f93SFabian Vogt #if CONFIG_IS_ENABLED(OF_CONTROL)
bcm2835_gpio_ofdata_to_platdata(struct udevice * dev)1194faf5f93SFabian Vogt static int bcm2835_gpio_ofdata_to_platdata(struct udevice *dev)
1204faf5f93SFabian Vogt {
1214faf5f93SFabian Vogt struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev);
1224faf5f93SFabian Vogt fdt_addr_t addr;
1234faf5f93SFabian Vogt
124a821c4afSSimon Glass addr = devfdt_get_addr(dev);
1254faf5f93SFabian Vogt if (addr == FDT_ADDR_T_NONE)
1264faf5f93SFabian Vogt return -EINVAL;
1274faf5f93SFabian Vogt
1284faf5f93SFabian Vogt plat->base = addr;
1294faf5f93SFabian Vogt return 0;
1304faf5f93SFabian Vogt }
1314faf5f93SFabian Vogt #endif
1324faf5f93SFabian Vogt
13341e98e01SSimon Glass U_BOOT_DRIVER(gpio_bcm2835) = {
13441e98e01SSimon Glass .name = "gpio_bcm2835",
13541e98e01SSimon Glass .id = UCLASS_GPIO,
1364faf5f93SFabian Vogt .ofdata_to_platdata = of_match_ptr(bcm2835_gpio_ofdata_to_platdata),
1374faf5f93SFabian Vogt .platdata_auto_alloc_size = sizeof(struct bcm2835_gpio_platdata),
13841e98e01SSimon Glass .ops = &gpio_bcm2835_ops,
13941e98e01SSimon Glass .probe = bcm2835_gpio_probe,
140601147b0SAlexander Graf .flags = DM_FLAG_PRE_RELOC,
14141e98e01SSimon Glass .priv_auto_alloc_size = sizeof(struct bcm2835_gpios),
14241e98e01SSimon Glass };
143