xref: /openbmc/u-boot/drivers/gpio/bcm2835_gpio.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
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