1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2386d934eSPurna Chandra Mandal /*
3386d934eSPurna Chandra Mandal * Copyright (c) 2015 Microchip Technology Inc
4386d934eSPurna Chandra Mandal * Purna Chandra Mandal <purna.mandal@microchip.com>
5386d934eSPurna Chandra Mandal */
6386d934eSPurna Chandra Mandal
7386d934eSPurna Chandra Mandal #include <common.h>
8386d934eSPurna Chandra Mandal #include <dm.h>
9386d934eSPurna Chandra Mandal #include <errno.h>
10386d934eSPurna Chandra Mandal #include <malloc.h>
11386d934eSPurna Chandra Mandal #include <asm/io.h>
12386d934eSPurna Chandra Mandal #include <asm/gpio.h>
13386d934eSPurna Chandra Mandal #include <linux/compat.h>
14386d934eSPurna Chandra Mandal #include <mach/pic32.h>
15386d934eSPurna Chandra Mandal
16386d934eSPurna Chandra Mandal DECLARE_GLOBAL_DATA_PTR;
17386d934eSPurna Chandra Mandal
18386d934eSPurna Chandra Mandal /* Peripheral Pin Control */
19386d934eSPurna Chandra Mandal struct pic32_reg_port {
20386d934eSPurna Chandra Mandal struct pic32_reg_atomic ansel;
21386d934eSPurna Chandra Mandal struct pic32_reg_atomic tris;
22386d934eSPurna Chandra Mandal struct pic32_reg_atomic port;
23386d934eSPurna Chandra Mandal struct pic32_reg_atomic lat;
24386d934eSPurna Chandra Mandal struct pic32_reg_atomic open_drain;
25386d934eSPurna Chandra Mandal struct pic32_reg_atomic cnpu;
26386d934eSPurna Chandra Mandal struct pic32_reg_atomic cnpd;
27386d934eSPurna Chandra Mandal struct pic32_reg_atomic cncon;
28386d934eSPurna Chandra Mandal };
29386d934eSPurna Chandra Mandal
30386d934eSPurna Chandra Mandal enum {
31386d934eSPurna Chandra Mandal MICROCHIP_GPIO_DIR_OUT,
32386d934eSPurna Chandra Mandal MICROCHIP_GPIO_DIR_IN,
33386d934eSPurna Chandra Mandal MICROCHIP_GPIOS_PER_BANK = 16,
34386d934eSPurna Chandra Mandal };
35386d934eSPurna Chandra Mandal
36386d934eSPurna Chandra Mandal struct pic32_gpio_priv {
37386d934eSPurna Chandra Mandal struct pic32_reg_port *regs;
38386d934eSPurna Chandra Mandal char name[2];
39386d934eSPurna Chandra Mandal };
40386d934eSPurna Chandra Mandal
pic32_gpio_get_value(struct udevice * dev,unsigned offset)41386d934eSPurna Chandra Mandal static int pic32_gpio_get_value(struct udevice *dev, unsigned offset)
42386d934eSPurna Chandra Mandal {
43386d934eSPurna Chandra Mandal struct pic32_gpio_priv *priv = dev_get_priv(dev);
44386d934eSPurna Chandra Mandal
45386d934eSPurna Chandra Mandal return !!(readl(&priv->regs->port.raw) & BIT(offset));
46386d934eSPurna Chandra Mandal }
47386d934eSPurna Chandra Mandal
pic32_gpio_set_value(struct udevice * dev,unsigned offset,int value)48386d934eSPurna Chandra Mandal static int pic32_gpio_set_value(struct udevice *dev, unsigned offset,
49386d934eSPurna Chandra Mandal int value)
50386d934eSPurna Chandra Mandal {
51386d934eSPurna Chandra Mandal struct pic32_gpio_priv *priv = dev_get_priv(dev);
52386d934eSPurna Chandra Mandal int mask = BIT(offset);
53386d934eSPurna Chandra Mandal
54386d934eSPurna Chandra Mandal if (value)
55386d934eSPurna Chandra Mandal writel(mask, &priv->regs->port.set);
56386d934eSPurna Chandra Mandal else
57386d934eSPurna Chandra Mandal writel(mask, &priv->regs->port.clr);
58386d934eSPurna Chandra Mandal
59386d934eSPurna Chandra Mandal return 0;
60386d934eSPurna Chandra Mandal }
61386d934eSPurna Chandra Mandal
pic32_gpio_direction(struct udevice * dev,unsigned offset)62386d934eSPurna Chandra Mandal static int pic32_gpio_direction(struct udevice *dev, unsigned offset)
63386d934eSPurna Chandra Mandal {
64386d934eSPurna Chandra Mandal struct pic32_gpio_priv *priv = dev_get_priv(dev);
65386d934eSPurna Chandra Mandal
66386d934eSPurna Chandra Mandal /* pin in analog mode ? */
67386d934eSPurna Chandra Mandal if (readl(&priv->regs->ansel.raw) & BIT(offset))
68386d934eSPurna Chandra Mandal return -EPERM;
69386d934eSPurna Chandra Mandal
70386d934eSPurna Chandra Mandal if (readl(&priv->regs->tris.raw) & BIT(offset))
71386d934eSPurna Chandra Mandal return MICROCHIP_GPIO_DIR_IN;
72386d934eSPurna Chandra Mandal else
73386d934eSPurna Chandra Mandal return MICROCHIP_GPIO_DIR_OUT;
74386d934eSPurna Chandra Mandal }
75386d934eSPurna Chandra Mandal
pic32_gpio_direction_input(struct udevice * dev,unsigned offset)76386d934eSPurna Chandra Mandal static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset)
77386d934eSPurna Chandra Mandal {
78386d934eSPurna Chandra Mandal struct pic32_gpio_priv *priv = dev_get_priv(dev);
79386d934eSPurna Chandra Mandal int mask = BIT(offset);
80386d934eSPurna Chandra Mandal
81386d934eSPurna Chandra Mandal writel(mask, &priv->regs->ansel.clr);
82386d934eSPurna Chandra Mandal writel(mask, &priv->regs->tris.set);
83386d934eSPurna Chandra Mandal
84386d934eSPurna Chandra Mandal return 0;
85386d934eSPurna Chandra Mandal }
86386d934eSPurna Chandra Mandal
pic32_gpio_direction_output(struct udevice * dev,unsigned offset,int value)87386d934eSPurna Chandra Mandal static int pic32_gpio_direction_output(struct udevice *dev,
88386d934eSPurna Chandra Mandal unsigned offset, int value)
89386d934eSPurna Chandra Mandal {
90386d934eSPurna Chandra Mandal struct pic32_gpio_priv *priv = dev_get_priv(dev);
91386d934eSPurna Chandra Mandal int mask = BIT(offset);
92386d934eSPurna Chandra Mandal
93386d934eSPurna Chandra Mandal writel(mask, &priv->regs->ansel.clr);
94386d934eSPurna Chandra Mandal writel(mask, &priv->regs->tris.clr);
95386d934eSPurna Chandra Mandal
96386d934eSPurna Chandra Mandal pic32_gpio_set_value(dev, offset, value);
97386d934eSPurna Chandra Mandal return 0;
98386d934eSPurna Chandra Mandal }
99386d934eSPurna Chandra Mandal
pic32_gpio_get_function(struct udevice * dev,unsigned offset)100386d934eSPurna Chandra Mandal static int pic32_gpio_get_function(struct udevice *dev, unsigned offset)
101386d934eSPurna Chandra Mandal {
102386d934eSPurna Chandra Mandal int ret = GPIOF_UNUSED;
103386d934eSPurna Chandra Mandal
104386d934eSPurna Chandra Mandal switch (pic32_gpio_direction(dev, offset)) {
105386d934eSPurna Chandra Mandal case MICROCHIP_GPIO_DIR_OUT:
106386d934eSPurna Chandra Mandal ret = GPIOF_OUTPUT;
107386d934eSPurna Chandra Mandal break;
108386d934eSPurna Chandra Mandal case MICROCHIP_GPIO_DIR_IN:
109386d934eSPurna Chandra Mandal ret = GPIOF_INPUT;
110386d934eSPurna Chandra Mandal break;
111386d934eSPurna Chandra Mandal default:
112386d934eSPurna Chandra Mandal ret = GPIOF_UNUSED;
113386d934eSPurna Chandra Mandal break;
114386d934eSPurna Chandra Mandal }
115386d934eSPurna Chandra Mandal return ret;
116386d934eSPurna Chandra Mandal }
117386d934eSPurna Chandra Mandal
118386d934eSPurna Chandra Mandal static const struct dm_gpio_ops gpio_pic32_ops = {
119386d934eSPurna Chandra Mandal .direction_input = pic32_gpio_direction_input,
120386d934eSPurna Chandra Mandal .direction_output = pic32_gpio_direction_output,
121386d934eSPurna Chandra Mandal .get_value = pic32_gpio_get_value,
122386d934eSPurna Chandra Mandal .set_value = pic32_gpio_set_value,
123386d934eSPurna Chandra Mandal .get_function = pic32_gpio_get_function,
124386d934eSPurna Chandra Mandal };
125386d934eSPurna Chandra Mandal
pic32_gpio_probe(struct udevice * dev)126386d934eSPurna Chandra Mandal static int pic32_gpio_probe(struct udevice *dev)
127386d934eSPurna Chandra Mandal {
128386d934eSPurna Chandra Mandal struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
129386d934eSPurna Chandra Mandal struct pic32_gpio_priv *priv = dev_get_priv(dev);
130386d934eSPurna Chandra Mandal fdt_addr_t addr;
131386d934eSPurna Chandra Mandal fdt_size_t size;
132386d934eSPurna Chandra Mandal char *end;
133386d934eSPurna Chandra Mandal int bank;
134386d934eSPurna Chandra Mandal
135e160f7d4SSimon Glass addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
136e160f7d4SSimon Glass &size);
137386d934eSPurna Chandra Mandal if (addr == FDT_ADDR_T_NONE)
138386d934eSPurna Chandra Mandal return -EINVAL;
139386d934eSPurna Chandra Mandal
140386d934eSPurna Chandra Mandal priv->regs = ioremap(addr, size);
141386d934eSPurna Chandra Mandal
142386d934eSPurna Chandra Mandal uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK;
143386d934eSPurna Chandra Mandal /* extract bank name */
144386d934eSPurna Chandra Mandal end = strrchr(dev->name, '@');
145386d934eSPurna Chandra Mandal bank = trailing_strtoln(dev->name, end);
146386d934eSPurna Chandra Mandal priv->name[0] = 'A' + bank;
147386d934eSPurna Chandra Mandal uc_priv->bank_name = priv->name;
148386d934eSPurna Chandra Mandal
149386d934eSPurna Chandra Mandal return 0;
150386d934eSPurna Chandra Mandal }
151386d934eSPurna Chandra Mandal
152386d934eSPurna Chandra Mandal static const struct udevice_id pic32_gpio_ids[] = {
153386d934eSPurna Chandra Mandal { .compatible = "microchip,pic32mzda-gpio" },
154386d934eSPurna Chandra Mandal { }
155386d934eSPurna Chandra Mandal };
156386d934eSPurna Chandra Mandal
157386d934eSPurna Chandra Mandal U_BOOT_DRIVER(gpio_pic32) = {
158386d934eSPurna Chandra Mandal .name = "gpio_pic32",
159386d934eSPurna Chandra Mandal .id = UCLASS_GPIO,
160386d934eSPurna Chandra Mandal .of_match = pic32_gpio_ids,
161386d934eSPurna Chandra Mandal .ops = &gpio_pic32_ops,
162386d934eSPurna Chandra Mandal .probe = pic32_gpio_probe,
163386d934eSPurna Chandra Mandal .priv_auto_alloc_size = sizeof(struct pic32_gpio_priv),
164386d934eSPurna Chandra Mandal };
165