xref: /rk3399_rockchip-uboot/drivers/gpio/bcm2835_gpio.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
1efad6cf8SStephen Warren /*
2efad6cf8SStephen Warren  * Copyright (C) 2012 Vikram Narayananan
3efad6cf8SStephen Warren  * <vikram186@gmail.com>
4efad6cf8SStephen Warren  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6efad6cf8SStephen Warren  */
7efad6cf8SStephen Warren 
8efad6cf8SStephen Warren #include <common.h>
941e98e01SSimon Glass #include <dm.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;
1741e98e01SSimon Glass };
1841e98e01SSimon Glass 
bcm2835_gpio_direction_input(struct udevice * dev,unsigned gpio)1941e98e01SSimon Glass static int bcm2835_gpio_direction_input(struct udevice *dev, unsigned gpio)
2041e98e01SSimon Glass {
2141e98e01SSimon Glass 	struct bcm2835_gpios *gpios = dev_get_priv(dev);
22efad6cf8SStephen Warren 	unsigned val;
23efad6cf8SStephen Warren 
2441e98e01SSimon Glass 	val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
25efad6cf8SStephen Warren 	val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
26efad6cf8SStephen Warren 	val |= (BCM2835_GPIO_INPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
2741e98e01SSimon Glass 	writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
28efad6cf8SStephen Warren 
29efad6cf8SStephen Warren 	return 0;
30efad6cf8SStephen Warren }
31efad6cf8SStephen Warren 
bcm2835_gpio_direction_output(struct udevice * dev,unsigned gpio,int value)3241e98e01SSimon Glass static int bcm2835_gpio_direction_output(struct udevice *dev, unsigned gpio,
3341e98e01SSimon Glass 					 int value)
34efad6cf8SStephen Warren {
3541e98e01SSimon Glass 	struct bcm2835_gpios *gpios = dev_get_priv(dev);
36efad6cf8SStephen Warren 	unsigned val;
37efad6cf8SStephen Warren 
38efad6cf8SStephen Warren 	gpio_set_value(gpio, value);
39efad6cf8SStephen Warren 
4041e98e01SSimon Glass 	val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
41efad6cf8SStephen Warren 	val &= ~(BCM2835_GPIO_FSEL_MASK << BCM2835_GPIO_FSEL_SHIFT(gpio));
42efad6cf8SStephen Warren 	val |= (BCM2835_GPIO_OUTPUT << BCM2835_GPIO_FSEL_SHIFT(gpio));
4341e98e01SSimon Glass 	writel(val, &gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
44efad6cf8SStephen Warren 
45efad6cf8SStephen Warren 	return 0;
46efad6cf8SStephen Warren }
47efad6cf8SStephen Warren 
bcm2835_get_value(const struct bcm2835_gpios * gpios,unsigned gpio)4841e98e01SSimon Glass static int bcm2835_get_value(const struct bcm2835_gpios *gpios, unsigned gpio)
4941e98e01SSimon Glass {
50efad6cf8SStephen Warren 	unsigned val;
51efad6cf8SStephen Warren 
5241e98e01SSimon Glass 	val = readl(&gpios->reg->gplev[BCM2835_GPIO_COMMON_BANK(gpio)]);
53efad6cf8SStephen Warren 
54efad6cf8SStephen Warren 	return (val >> BCM2835_GPIO_COMMON_SHIFT(gpio)) & 0x1;
55efad6cf8SStephen Warren }
56efad6cf8SStephen Warren 
bcm2835_gpio_get_value(struct udevice * dev,unsigned gpio)5741e98e01SSimon Glass static int bcm2835_gpio_get_value(struct udevice *dev, unsigned gpio)
58efad6cf8SStephen Warren {
5941e98e01SSimon Glass 	const struct bcm2835_gpios *gpios = dev_get_priv(dev);
6041e98e01SSimon Glass 
6141e98e01SSimon Glass 	return bcm2835_get_value(gpios, gpio);
6241e98e01SSimon Glass }
6341e98e01SSimon Glass 
bcm2835_gpio_set_value(struct udevice * dev,unsigned gpio,int value)6441e98e01SSimon Glass static int bcm2835_gpio_set_value(struct udevice *dev, unsigned gpio,
6541e98e01SSimon Glass 				  int value)
6641e98e01SSimon Glass {
6741e98e01SSimon Glass 	struct bcm2835_gpios *gpios = dev_get_priv(dev);
6841e98e01SSimon Glass 	u32 *output_reg = value ? gpios->reg->gpset : gpios->reg->gpclr;
69efad6cf8SStephen Warren 
70efad6cf8SStephen Warren 	writel(1 << BCM2835_GPIO_COMMON_SHIFT(gpio),
71efad6cf8SStephen Warren 				&output_reg[BCM2835_GPIO_COMMON_BANK(gpio)]);
72efad6cf8SStephen Warren 
73efad6cf8SStephen Warren 	return 0;
74efad6cf8SStephen Warren }
7541e98e01SSimon Glass 
bcm2835_gpio_get_func_id(struct udevice * dev,unsigned gpio)7604a993feSAlexander Graf int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned gpio)
7741e98e01SSimon Glass {
7841e98e01SSimon Glass 	struct bcm2835_gpios *gpios = dev_get_priv(dev);
7904a993feSAlexander Graf 	u32 val;
8041e98e01SSimon Glass 
8104a993feSAlexander Graf 	val = readl(&gpios->reg->gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
8204a993feSAlexander Graf 
8304a993feSAlexander Graf 	return (val >> BCM2835_GPIO_FSEL_SHIFT(gpio) & BCM2835_GPIO_FSEL_MASK);
8404a993feSAlexander Graf }
8504a993feSAlexander Graf 
bcm2835_gpio_get_function(struct udevice * dev,unsigned offset)8604a993feSAlexander Graf static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset)
8704a993feSAlexander Graf {
8804a993feSAlexander Graf 	int funcid = bcm2835_gpio_get_func_id(dev, offset);
8904a993feSAlexander Graf 
9004a993feSAlexander Graf 	switch (funcid) {
9104a993feSAlexander Graf 	case BCM2835_GPIO_OUTPUT:
9241e98e01SSimon Glass 		return GPIOF_OUTPUT;
9304a993feSAlexander Graf 	case BCM2835_GPIO_INPUT:
9441e98e01SSimon Glass 		return GPIOF_INPUT;
9504a993feSAlexander Graf 	default:
9604a993feSAlexander Graf 		return GPIOF_FUNC;
9704a993feSAlexander Graf 	}
9841e98e01SSimon Glass }
9941e98e01SSimon Glass 
10041e98e01SSimon Glass 
10141e98e01SSimon Glass static const struct dm_gpio_ops gpio_bcm2835_ops = {
10241e98e01SSimon Glass 	.direction_input	= bcm2835_gpio_direction_input,
10341e98e01SSimon Glass 	.direction_output	= bcm2835_gpio_direction_output,
10441e98e01SSimon Glass 	.get_value		= bcm2835_gpio_get_value,
10541e98e01SSimon Glass 	.set_value		= bcm2835_gpio_set_value,
10641e98e01SSimon Glass 	.get_function		= bcm2835_gpio_get_function,
10741e98e01SSimon Glass };
10841e98e01SSimon Glass 
bcm2835_gpio_probe(struct udevice * dev)10941e98e01SSimon Glass static int bcm2835_gpio_probe(struct udevice *dev)
11041e98e01SSimon Glass {
11141e98e01SSimon Glass 	struct bcm2835_gpios *gpios = dev_get_priv(dev);
11241e98e01SSimon Glass 	struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev);
113e564f054SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
11441e98e01SSimon Glass 
11541e98e01SSimon Glass 	uc_priv->bank_name = "GPIO";
11641e98e01SSimon Glass 	uc_priv->gpio_count = BCM2835_GPIO_COUNT;
11741e98e01SSimon Glass 	gpios->reg = (struct bcm2835_gpio_regs *)plat->base;
11841e98e01SSimon Glass 
11941e98e01SSimon Glass 	return 0;
12041e98e01SSimon Glass }
12141e98e01SSimon Glass 
1224faf5f93SFabian Vogt #if CONFIG_IS_ENABLED(OF_CONTROL)
1234faf5f93SFabian Vogt static const struct udevice_id bcm2835_gpio_id[] = {
1244faf5f93SFabian Vogt 	{.compatible = "brcm,bcm2835-gpio"},
1254faf5f93SFabian Vogt 	{}
1264faf5f93SFabian Vogt };
1274faf5f93SFabian Vogt 
bcm2835_gpio_ofdata_to_platdata(struct udevice * dev)1284faf5f93SFabian Vogt static int bcm2835_gpio_ofdata_to_platdata(struct udevice *dev)
1294faf5f93SFabian Vogt {
1304faf5f93SFabian Vogt 	struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev);
1314faf5f93SFabian Vogt 	fdt_addr_t addr;
1324faf5f93SFabian Vogt 
133*a821c4afSSimon Glass 	addr = devfdt_get_addr(dev);
1344faf5f93SFabian Vogt 	if (addr == FDT_ADDR_T_NONE)
1354faf5f93SFabian Vogt 		return -EINVAL;
1364faf5f93SFabian Vogt 
1374faf5f93SFabian Vogt 	plat->base = addr;
1384faf5f93SFabian Vogt 	return 0;
1394faf5f93SFabian Vogt }
1404faf5f93SFabian Vogt #endif
1414faf5f93SFabian Vogt 
14241e98e01SSimon Glass U_BOOT_DRIVER(gpio_bcm2835) = {
14341e98e01SSimon Glass 	.name	= "gpio_bcm2835",
14441e98e01SSimon Glass 	.id	= UCLASS_GPIO,
1454faf5f93SFabian Vogt 	.of_match = of_match_ptr(bcm2835_gpio_id),
1464faf5f93SFabian Vogt 	.ofdata_to_platdata = of_match_ptr(bcm2835_gpio_ofdata_to_platdata),
1474faf5f93SFabian Vogt 	.platdata_auto_alloc_size = sizeof(struct bcm2835_gpio_platdata),
14841e98e01SSimon Glass 	.ops	= &gpio_bcm2835_ops,
14941e98e01SSimon Glass 	.probe	= bcm2835_gpio_probe,
150601147b0SAlexander Graf 	.flags	= DM_FLAG_PRE_RELOC,
15141e98e01SSimon Glass 	.priv_auto_alloc_size = sizeof(struct bcm2835_gpios),
15241e98e01SSimon Glass };
153