1704d9a64SStefan Roese /*
2704d9a64SStefan Roese * Copyright (C) 2016 Stefan Roese <sr@denx.de>
3704d9a64SStefan Roese *
4704d9a64SStefan Roese * SPDX-License-Identifier: GPL-2.0+
5704d9a64SStefan Roese */
6704d9a64SStefan Roese
7704d9a64SStefan Roese #include <common.h>
8704d9a64SStefan Roese #include <dm.h>
9704d9a64SStefan Roese #include <asm/gpio.h>
10704d9a64SStefan Roese #include <asm/io.h>
11704d9a64SStefan Roese #include <errno.h>
12704d9a64SStefan Roese
13704d9a64SStefan Roese DECLARE_GLOBAL_DATA_PTR;
14704d9a64SStefan Roese
15704d9a64SStefan Roese #define MVEBU_GPIOS_PER_BANK 32
16704d9a64SStefan Roese
17704d9a64SStefan Roese struct mvebu_gpio_regs {
18704d9a64SStefan Roese u32 data_out;
19704d9a64SStefan Roese u32 io_conf;
20704d9a64SStefan Roese u32 blink_en;
21704d9a64SStefan Roese u32 in_pol;
22704d9a64SStefan Roese u32 data_in;
23704d9a64SStefan Roese };
24704d9a64SStefan Roese
25704d9a64SStefan Roese struct mvebu_gpio_priv {
26704d9a64SStefan Roese struct mvebu_gpio_regs *regs;
27704d9a64SStefan Roese char name[2];
28704d9a64SStefan Roese };
29704d9a64SStefan Roese
mvebu_gpio_direction_input(struct udevice * dev,unsigned int gpio)30704d9a64SStefan Roese static int mvebu_gpio_direction_input(struct udevice *dev, unsigned int gpio)
31704d9a64SStefan Roese {
32704d9a64SStefan Roese struct mvebu_gpio_priv *priv = dev_get_priv(dev);
33704d9a64SStefan Roese struct mvebu_gpio_regs *regs = priv->regs;
34704d9a64SStefan Roese
35704d9a64SStefan Roese setbits_le32(®s->io_conf, BIT(gpio));
36704d9a64SStefan Roese
37704d9a64SStefan Roese return 0;
38704d9a64SStefan Roese }
39704d9a64SStefan Roese
mvebu_gpio_direction_output(struct udevice * dev,unsigned gpio,int value)40704d9a64SStefan Roese static int mvebu_gpio_direction_output(struct udevice *dev, unsigned gpio,
41704d9a64SStefan Roese int value)
42704d9a64SStefan Roese {
43704d9a64SStefan Roese struct mvebu_gpio_priv *priv = dev_get_priv(dev);
44704d9a64SStefan Roese struct mvebu_gpio_regs *regs = priv->regs;
45704d9a64SStefan Roese
46b23005ceSStefan Roese if (value)
47b23005ceSStefan Roese setbits_le32(®s->data_out, BIT(gpio));
48b23005ceSStefan Roese else
49b23005ceSStefan Roese clrbits_le32(®s->data_out, BIT(gpio));
50704d9a64SStefan Roese clrbits_le32(®s->io_conf, BIT(gpio));
51704d9a64SStefan Roese
52704d9a64SStefan Roese return 0;
53704d9a64SStefan Roese }
54704d9a64SStefan Roese
mvebu_gpio_get_function(struct udevice * dev,unsigned gpio)55704d9a64SStefan Roese static int mvebu_gpio_get_function(struct udevice *dev, unsigned gpio)
56704d9a64SStefan Roese {
57704d9a64SStefan Roese struct mvebu_gpio_priv *priv = dev_get_priv(dev);
58704d9a64SStefan Roese struct mvebu_gpio_regs *regs = priv->regs;
59704d9a64SStefan Roese u32 val;
60704d9a64SStefan Roese
61704d9a64SStefan Roese val = readl(®s->io_conf) & BIT(gpio);
62704d9a64SStefan Roese if (val)
63704d9a64SStefan Roese return GPIOF_INPUT;
64704d9a64SStefan Roese else
65704d9a64SStefan Roese return GPIOF_OUTPUT;
66704d9a64SStefan Roese }
67704d9a64SStefan Roese
mvebu_gpio_set_value(struct udevice * dev,unsigned gpio,int value)68704d9a64SStefan Roese static int mvebu_gpio_set_value(struct udevice *dev, unsigned gpio,
69704d9a64SStefan Roese int value)
70704d9a64SStefan Roese {
71704d9a64SStefan Roese struct mvebu_gpio_priv *priv = dev_get_priv(dev);
72704d9a64SStefan Roese struct mvebu_gpio_regs *regs = priv->regs;
73704d9a64SStefan Roese
74704d9a64SStefan Roese if (value)
75704d9a64SStefan Roese setbits_le32(®s->data_out, BIT(gpio));
76704d9a64SStefan Roese else
77704d9a64SStefan Roese clrbits_le32(®s->data_out, BIT(gpio));
78704d9a64SStefan Roese
79704d9a64SStefan Roese return 0;
80704d9a64SStefan Roese }
81704d9a64SStefan Roese
mvebu_gpio_get_value(struct udevice * dev,unsigned gpio)82704d9a64SStefan Roese static int mvebu_gpio_get_value(struct udevice *dev, unsigned gpio)
83704d9a64SStefan Roese {
84704d9a64SStefan Roese struct mvebu_gpio_priv *priv = dev_get_priv(dev);
85704d9a64SStefan Roese struct mvebu_gpio_regs *regs = priv->regs;
86704d9a64SStefan Roese
87704d9a64SStefan Roese return !!(readl(®s->data_in) & BIT(gpio));
88704d9a64SStefan Roese }
89704d9a64SStefan Roese
mvebu_gpio_probe(struct udevice * dev)90704d9a64SStefan Roese static int mvebu_gpio_probe(struct udevice *dev)
91704d9a64SStefan Roese {
92704d9a64SStefan Roese struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
93704d9a64SStefan Roese struct mvebu_gpio_priv *priv = dev_get_priv(dev);
94704d9a64SStefan Roese
95*a821c4afSSimon Glass priv->regs = (struct mvebu_gpio_regs *)devfdt_get_addr(dev);
96704d9a64SStefan Roese uc_priv->gpio_count = MVEBU_GPIOS_PER_BANK;
97704d9a64SStefan Roese priv->name[0] = 'A' + dev->req_seq;
98704d9a64SStefan Roese uc_priv->bank_name = priv->name;
99704d9a64SStefan Roese
100704d9a64SStefan Roese return 0;
101704d9a64SStefan Roese }
102704d9a64SStefan Roese
103704d9a64SStefan Roese static const struct dm_gpio_ops mvebu_gpio_ops = {
104704d9a64SStefan Roese .direction_input = mvebu_gpio_direction_input,
105704d9a64SStefan Roese .direction_output = mvebu_gpio_direction_output,
106704d9a64SStefan Roese .get_function = mvebu_gpio_get_function,
107704d9a64SStefan Roese .get_value = mvebu_gpio_get_value,
108704d9a64SStefan Roese .set_value = mvebu_gpio_set_value,
109704d9a64SStefan Roese };
110704d9a64SStefan Roese
111704d9a64SStefan Roese static const struct udevice_id mvebu_gpio_ids[] = {
112704d9a64SStefan Roese { .compatible = "marvell,orion-gpio" },
113704d9a64SStefan Roese { }
114704d9a64SStefan Roese };
115704d9a64SStefan Roese
116704d9a64SStefan Roese U_BOOT_DRIVER(gpio_mvebu) = {
117704d9a64SStefan Roese .name = "gpio_mvebu",
118704d9a64SStefan Roese .id = UCLASS_GPIO,
119704d9a64SStefan Roese .of_match = mvebu_gpio_ids,
120704d9a64SStefan Roese .ops = &mvebu_gpio_ops,
121704d9a64SStefan Roese .probe = mvebu_gpio_probe,
122704d9a64SStefan Roese .priv_auto_alloc_size = sizeof(struct mvebu_gpio_priv),
123704d9a64SStefan Roese };
124