]> git.sur5r.net Git - u-boot/blob - drivers/gpio/pic32_gpio.c
Merge branch 'master' of git://git.denx.de/u-boot-sh
[u-boot] / drivers / gpio / pic32_gpio.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Microchip Technology Inc
4  * Purna Chandra Mandal <purna.mandal@microchip.com>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <malloc.h>
11 #include <asm/io.h>
12 #include <asm/gpio.h>
13 #include <linux/compat.h>
14 #include <mach/pic32.h>
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 /* Peripheral Pin Control */
19 struct pic32_reg_port {
20         struct pic32_reg_atomic ansel;
21         struct pic32_reg_atomic tris;
22         struct pic32_reg_atomic port;
23         struct pic32_reg_atomic lat;
24         struct pic32_reg_atomic open_drain;
25         struct pic32_reg_atomic cnpu;
26         struct pic32_reg_atomic cnpd;
27         struct pic32_reg_atomic cncon;
28 };
29
30 enum {
31         MICROCHIP_GPIO_DIR_OUT,
32         MICROCHIP_GPIO_DIR_IN,
33         MICROCHIP_GPIOS_PER_BANK = 16,
34 };
35
36 struct pic32_gpio_priv {
37         struct pic32_reg_port *regs;
38         char name[2];
39 };
40
41 static int pic32_gpio_get_value(struct udevice *dev, unsigned offset)
42 {
43         struct pic32_gpio_priv *priv = dev_get_priv(dev);
44
45         return !!(readl(&priv->regs->port.raw) & BIT(offset));
46 }
47
48 static int pic32_gpio_set_value(struct udevice *dev, unsigned offset,
49                                 int value)
50 {
51         struct pic32_gpio_priv *priv = dev_get_priv(dev);
52         int mask = BIT(offset);
53
54         if (value)
55                 writel(mask, &priv->regs->port.set);
56         else
57                 writel(mask, &priv->regs->port.clr);
58
59         return 0;
60 }
61
62 static int pic32_gpio_direction(struct udevice *dev, unsigned offset)
63 {
64         struct pic32_gpio_priv *priv = dev_get_priv(dev);
65
66         /* pin in analog mode ? */
67         if (readl(&priv->regs->ansel.raw) & BIT(offset))
68                 return -EPERM;
69
70         if (readl(&priv->regs->tris.raw) & BIT(offset))
71                 return MICROCHIP_GPIO_DIR_IN;
72         else
73                 return MICROCHIP_GPIO_DIR_OUT;
74 }
75
76 static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset)
77 {
78         struct pic32_gpio_priv *priv = dev_get_priv(dev);
79         int mask = BIT(offset);
80
81         writel(mask, &priv->regs->ansel.clr);
82         writel(mask, &priv->regs->tris.set);
83
84         return 0;
85 }
86
87 static int pic32_gpio_direction_output(struct udevice *dev,
88                                        unsigned offset, int value)
89 {
90         struct pic32_gpio_priv *priv = dev_get_priv(dev);
91         int mask = BIT(offset);
92
93         writel(mask, &priv->regs->ansel.clr);
94         writel(mask, &priv->regs->tris.clr);
95
96         pic32_gpio_set_value(dev, offset, value);
97         return 0;
98 }
99
100 static int pic32_gpio_get_function(struct udevice *dev, unsigned offset)
101 {
102         int ret = GPIOF_UNUSED;
103
104         switch (pic32_gpio_direction(dev, offset)) {
105         case MICROCHIP_GPIO_DIR_OUT:
106                 ret = GPIOF_OUTPUT;
107                 break;
108         case MICROCHIP_GPIO_DIR_IN:
109                 ret = GPIOF_INPUT;
110                 break;
111         default:
112                 ret = GPIOF_UNUSED;
113                 break;
114         }
115         return ret;
116 }
117
118 static const struct dm_gpio_ops gpio_pic32_ops = {
119         .direction_input        = pic32_gpio_direction_input,
120         .direction_output       = pic32_gpio_direction_output,
121         .get_value              = pic32_gpio_get_value,
122         .set_value              = pic32_gpio_set_value,
123         .get_function           = pic32_gpio_get_function,
124 };
125
126 static int pic32_gpio_probe(struct udevice *dev)
127 {
128         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
129         struct pic32_gpio_priv *priv = dev_get_priv(dev);
130         fdt_addr_t addr;
131         fdt_size_t size;
132         char *end;
133         int bank;
134
135         addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
136                                     &size);
137         if (addr == FDT_ADDR_T_NONE)
138                 return -EINVAL;
139
140         priv->regs = ioremap(addr, size);
141
142         uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK;
143         /* extract bank name */
144         end = strrchr(dev->name, '@');
145         bank = trailing_strtoln(dev->name, end);
146         priv->name[0] = 'A' + bank;
147         uc_priv->bank_name = priv->name;
148
149         return 0;
150 }
151
152 static const struct udevice_id pic32_gpio_ids[] = {
153         { .compatible = "microchip,pic32mzda-gpio" },
154         { }
155 };
156
157 U_BOOT_DRIVER(gpio_pic32) = {
158         .name           = "gpio_pic32",
159         .id             = UCLASS_GPIO,
160         .of_match       = pic32_gpio_ids,
161         .ops            = &gpio_pic32_ops,
162         .probe          = pic32_gpio_probe,
163         .priv_auto_alloc_size   = sizeof(struct pic32_gpio_priv),
164 };