blob: 5da11d988e08718065f63237c485038294cec091 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Álvaro Fernández Rojase64bdb22017-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 Rojase64bdb22017-05-07 20:09:30 +02008 */
9
10#include <common.h>
Simon Glass9d922452017-05-17 17:18:03 -060011#include <dm.h>
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020012#include <errno.h>
13#include <asm/gpio.h>
14#include <asm/io.h>
Simon Glasscd93d622020-05-10 11:40:13 -060015#include <linux/bitops.h>
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020016
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020017struct bcm6345_gpio_priv {
18 void __iomem *reg_dirout;
19 void __iomem *reg_data;
20};
21
22static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset)
23{
24 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
25
Philippe Reynesea0d6aa2019-03-07 11:36:31 +010026 return !!(readl(priv->reg_data) & BIT(offset));
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020027}
28
29static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
30 int value)
31{
32 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
33
34 if (value)
Philippe Reynesea0d6aa2019-03-07 11:36:31 +010035 setbits_32(priv->reg_data, BIT(offset));
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020036 else
Philippe Reynesea0d6aa2019-03-07 11:36:31 +010037 clrbits_32(priv->reg_data, BIT(offset));
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020038
39 return 0;
40}
41
42static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset,
43 bool input)
44{
45 if (input)
Philippe Reynesea0d6aa2019-03-07 11:36:31 +010046 clrbits_32(dirout, BIT(offset));
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020047 else
Philippe Reynesea0d6aa2019-03-07 11:36:31 +010048 setbits_32(dirout, BIT(offset));
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020049
50 return 0;
51}
52
53static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset)
54{
55 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
56
57 return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1);
58}
59
60static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset,
61 int value)
62{
63 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
64
Axel Lind2d20d92017-06-08 17:20:12 +080065 bcm6345_gpio_set_value(dev, offset, value);
66
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020067 return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0);
68}
69
70static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset)
71{
72 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
73
Philippe Reynesea0d6aa2019-03-07 11:36:31 +010074 if (readl(priv->reg_dirout) & BIT(offset))
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020075 return GPIOF_OUTPUT;
76 else
77 return GPIOF_INPUT;
78}
79
80static const struct dm_gpio_ops bcm6345_gpio_ops = {
81 .direction_input = bcm6345_gpio_direction_input,
82 .direction_output = bcm6345_gpio_direction_output,
83 .get_value = bcm6345_gpio_get_value,
84 .set_value = bcm6345_gpio_set_value,
85 .get_function = bcm6345_gpio_get_function,
86};
87
88static int bcm6345_gpio_probe(struct udevice *dev)
89{
90 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
91 struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020092
Álvaro Fernández Rojase7e64fa2018-03-22 19:39:32 +010093 priv->reg_dirout = dev_remap_addr_index(dev, 0);
94 if (!priv->reg_dirout)
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020095 return -EINVAL;
96
Álvaro Fernández Rojase7e64fa2018-03-22 19:39:32 +010097 priv->reg_data = dev_remap_addr_index(dev, 1);
98 if (!priv->reg_data)
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +020099 return -EINVAL;
100
Álvaro Fernández Rojase7e64fa2018-03-22 19:39:32 +0100101 uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", 32);
Álvaro Fernández Rojase64bdb22017-05-07 20:09:30 +0200102 uc_priv->bank_name = dev->name;
103
104 return 0;
105}
106
107static const struct udevice_id bcm6345_gpio_ids[] = {
108 { .compatible = "brcm,bcm6345-gpio" },
109 { /* sentinel */ }
110};
111
112U_BOOT_DRIVER(bcm6345_gpio) = {
113 .name = "bcm6345-gpio",
114 .id = UCLASS_GPIO,
115 .of_match = bcm6345_gpio_ids,
116 .ops = &bcm6345_gpio_ops,
117 .priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv),
118 .probe = bcm6345_gpio_probe,
119};