xref: /rk3399_rockchip-uboot/drivers/gpio/pic32_gpio.c (revision 21342d4aed6c77a4aa7a5b2579b3c23e21aea31a)
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