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