blob: 1a507fce8e7c6dcbc4641a3bf0f48d6742afd9f3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Álvaro Fernández Rojase9301112017-05-07 20:09:30 +02002/*
3 * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
4 *
5 * Derived from linux/arch/mips/bcm63xx/gpio.c:
6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7 * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
Álvaro Fernández Rojase9301112017-05-07 20:09:30 +02008 */
9
10#include <common.h>
Simon Glass11c89f32017-05-17 17:18:03 -060011#include <dm.h>
Álvaro Fernández Rojase9301112017-05-07 20:09:30 +020012#include <errno.h>
13#include <asm/gpio.h>
14#include <asm/io.h>
Álvaro Fernández Rojase9301112017-05-07 20:09:30 +020015
16DECLARE_GLOBAL_DATA_PTR;
17
18struct bcm6345_gpio_priv {
19 void __iomem *reg_dirout;
20 void __iomem *reg_data;
21};
22
23static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset)
24{
25 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
26
27 return !!(readl_be(priv->reg_data) & BIT(offset));
28}
29
30static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
31 int value)
32{
33 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
34
35 if (value)
36 setbits_be32(priv->reg_data, BIT(offset));
37 else
38 clrbits_be32(priv->reg_data, BIT(offset));
39
40 return 0;
41}
42
43static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset,
44 bool input)
45{
46 if (input)
47 clrbits_be32(dirout, BIT(offset));
48 else
49 setbits_be32(dirout, BIT(offset));
50
51 return 0;
52}
53
54static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset)
55{
56 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
57
58 return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1);
59}
60
61static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset,
62 int value)
63{
64 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
65
Axel Lin90a59f22017-06-08 17:20:12 +080066 bcm6345_gpio_set_value(dev, offset, value);
67
Álvaro Fernández Rojase9301112017-05-07 20:09:30 +020068 return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0);
69}
70
71static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset)
72{
73 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
74
75 if (readl_be(priv->reg_dirout) & BIT(offset))
76 return GPIOF_OUTPUT;
77 else
78 return GPIOF_INPUT;
79}
80
81static const struct dm_gpio_ops bcm6345_gpio_ops = {
82 .direction_input = bcm6345_gpio_direction_input,
83 .direction_output = bcm6345_gpio_direction_output,
84 .get_value = bcm6345_gpio_get_value,
85 .set_value = bcm6345_gpio_set_value,
86 .get_function = bcm6345_gpio_get_function,
87};
88
89static int bcm6345_gpio_probe(struct udevice *dev)
90{
91 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
92 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
93 fdt_addr_t data_addr, dirout_addr;
94 fdt_size_t data_size, dirout_size;
95
Simon Glassba1dea42017-05-17 17:18:05 -060096 dirout_addr = devfdt_get_addr_size_index(dev, 0, &dirout_size);
Álvaro Fernández Rojase9301112017-05-07 20:09:30 +020097 if (dirout_addr == FDT_ADDR_T_NONE)
98 return -EINVAL;
99
Simon Glassba1dea42017-05-17 17:18:05 -0600100 data_addr = devfdt_get_addr_size_index(dev, 1, &data_size);
Álvaro Fernández Rojase9301112017-05-07 20:09:30 +0200101 if (data_addr == FDT_ADDR_T_NONE)
102 return -EINVAL;
103
104 priv->reg_data = ioremap(data_addr, data_size);
105 priv->reg_dirout = ioremap(dirout_addr, dirout_size);
106
107 uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
108 "ngpios", 32);
109 uc_priv->bank_name = dev->name;
110
111 return 0;
112}
113
114static const struct udevice_id bcm6345_gpio_ids[] = {
115 { .compatible = "brcm,bcm6345-gpio" },
116 { /* sentinel */ }
117};
118
119U_BOOT_DRIVER(bcm6345_gpio) = {
120 .name = "bcm6345-gpio",
121 .id = UCLASS_GPIO,
122 .of_match = bcm6345_gpio_ids,
123 .ops = &bcm6345_gpio_ops,
124 .priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv),
125 .probe = bcm6345_gpio_probe,
126};