xref: /openbmc/u-boot/drivers/gpio/pic32_gpio.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
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