1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Qualcomm GPIO driver
4 *
5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
6 */
7
8#include <common.h>
9#include <dm.h>
10#include <errno.h>
11#include <asm/global_data.h>
12#include <asm/gpio.h>
13#include <asm/io.h>
14#include <mach/gpio.h>
15
16DECLARE_GLOBAL_DATA_PTR;
17
18/* OE */
19#define GPIO_OE_DISABLE  (0x0 << 9)
20#define GPIO_OE_ENABLE   (0x1 << 9)
21#define GPIO_OE_MASK     (0x1 << 9)
22
23/* GPIO_IN_OUT register shifts. */
24#define GPIO_IN          0
25#define GPIO_OUT         1
26
27struct msm_gpio_bank {
28	phys_addr_t base;
29	const struct msm_pin_data *pin_data;
30};
31
32#define GPIO_CONFIG_REG(dev, x) \
33	(qcom_pin_offset(((struct msm_gpio_bank *)dev_get_priv(dev))->pin_data->pin_offsets, x))
34
35#define GPIO_IN_OUT_REG(dev, x) \
36	(GPIO_CONFIG_REG(dev, x) + 0x4)
37
38static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
39{
40	struct msm_gpio_bank *priv = dev_get_priv(dev);
41
42	/* Always NOP for special pins, assume they're in the correct state */
43	if (qcom_is_special_pin(priv->pin_data, gpio))
44		return;
45
46	/* Disable OE bit */
47	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
48			GPIO_OE_MASK, GPIO_OE_DISABLE);
49
50	return;
51}
52
53static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
54{
55	struct msm_gpio_bank *priv = dev_get_priv(dev);
56
57	/* Always NOP for special pins, assume they're in the correct state */
58	if (qcom_is_special_pin(priv->pin_data, gpio))
59		return 0;
60
61	value = !!value;
62	/* set value */
63	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
64
65	return 0;
66}
67
68static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
69				     int value)
70{
71	struct msm_gpio_bank *priv = dev_get_priv(dev);
72
73	/* Always NOP for special pins, assume they're in the correct state */
74	if (qcom_is_special_pin(priv->pin_data, gpio))
75		return 0;
76
77	value = !!value;
78	/* set value */
79	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
80	/* switch direction */
81	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
82			GPIO_OE_MASK, GPIO_OE_ENABLE);
83
84	return 0;
85}
86
87static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
88{
89	if (flags & GPIOD_IS_OUT_ACTIVE) {
90		return msm_gpio_direction_output(dev, gpio, 1);
91	} else if (flags & GPIOD_IS_OUT) {
92		return msm_gpio_direction_output(dev, gpio, 0);
93	} else if (flags & GPIOD_IS_IN) {
94		msm_gpio_direction_input(dev, gpio);
95		if (flags & GPIOD_PULL_UP)
96			return msm_gpio_set_value(dev, gpio, 1);
97		else if (flags & GPIOD_PULL_DOWN)
98			return msm_gpio_set_value(dev, gpio, 0);
99	}
100
101	return 0;
102}
103
104static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
105{
106	struct msm_gpio_bank *priv = dev_get_priv(dev);
107
108	/* Always NOP for special pins, assume they're in the correct state */
109	if (qcom_is_special_pin(priv->pin_data, gpio))
110		return 0;
111
112	return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
113}
114
115static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
116{
117	struct msm_gpio_bank *priv = dev_get_priv(dev);
118
119	/* Always NOP for special pins, assume they're in the correct state */
120	if (qcom_is_special_pin(priv->pin_data, gpio))
121		return 0;
122
123	if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
124		return GPIOF_OUTPUT;
125
126	return GPIOF_INPUT;
127}
128
129static const struct dm_gpio_ops gpio_msm_ops = {
130	.set_flags		= msm_gpio_set_flags,
131	.get_value		= msm_gpio_get_value,
132	.get_function		= msm_gpio_get_function,
133};
134
135static int msm_gpio_probe(struct udevice *dev)
136{
137	struct msm_gpio_bank *priv = dev_get_priv(dev);
138
139	priv->base = dev_read_addr(dev);
140	priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
141
142	return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
143}
144
145static int msm_gpio_of_to_plat(struct udevice *dev)
146{
147	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
148	const struct msm_pin_data *pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
149
150	/* Get the pin count from the pinctrl driver */
151	uc_priv->gpio_count = pin_data->pin_count;
152	uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
153					 "gpio-bank-name", NULL);
154	if (uc_priv->bank_name == NULL)
155		uc_priv->bank_name = "soc";
156
157	return 0;
158}
159
160U_BOOT_DRIVER(gpio_msm) = {
161	.name	= "gpio_msm",
162	.id	= UCLASS_GPIO,
163	.of_to_plat = msm_gpio_of_to_plat,
164	.probe	= msm_gpio_probe,
165	.ops	= &gpio_msm_ops,
166	.flags	= DM_UC_FLAG_SEQ_ALIAS,
167	.priv_auto	= sizeof(struct msm_gpio_bank),
168};
169