blob: 2fb266f12854d17ae570da1f048e8ae8d2e57fc7 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +02002/*
3 * Qualcomm GPIO driver
4 *
5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +02006 */
7
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +02008#include <dm.h>
9#include <errno.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060010#include <asm/global_data.h>
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020011#include <asm/gpio.h>
12#include <asm/io.h>
Caleb Connollyfabb8972023-11-14 12:55:42 +000013#include <mach/gpio.h>
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020014
15DECLARE_GLOBAL_DATA_PTR;
16
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020017/* OE */
18#define GPIO_OE_DISABLE (0x0 << 9)
19#define GPIO_OE_ENABLE (0x1 << 9)
20#define GPIO_OE_MASK (0x1 << 9)
21
22/* GPIO_IN_OUT register shifts. */
23#define GPIO_IN 0
24#define GPIO_OUT 1
25
26struct msm_gpio_bank {
27 phys_addr_t base;
Caleb Connollyfabb8972023-11-14 12:55:42 +000028 const struct msm_pin_data *pin_data;
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020029};
30
Caleb Connollyfabb8972023-11-14 12:55:42 +000031#define GPIO_CONFIG_REG(dev, x) \
32 (qcom_pin_offset(((struct msm_gpio_bank *)dev_get_priv(dev))->pin_data->pin_offsets, x))
33
34#define GPIO_IN_OUT_REG(dev, x) \
35 (GPIO_CONFIG_REG(dev, x) + 0x4)
36
Caleb Connolly241dfda2024-04-03 14:07:43 +020037static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020038{
39 struct msm_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020040
Caleb Connolly190005c2024-02-26 17:26:17 +000041 /* Always NOP for special pins, assume they're in the correct state */
42 if (qcom_is_special_pin(priv->pin_data, gpio))
Caleb Connolly241dfda2024-04-03 14:07:43 +020043 return;
Caleb Connolly190005c2024-02-26 17:26:17 +000044
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020045 /* Disable OE bit */
Caleb Connollyfabb8972023-11-14 12:55:42 +000046 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
47 GPIO_OE_MASK, GPIO_OE_DISABLE);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020048
Caleb Connolly241dfda2024-04-03 14:07:43 +020049 return;
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020050}
51
Caleb Connolly8fff7eb2023-11-14 12:55:43 +000052static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020053{
54 struct msm_gpio_bank *priv = dev_get_priv(dev);
55
Caleb Connolly190005c2024-02-26 17:26:17 +000056 /* Always NOP for special pins, assume they're in the correct state */
57 if (qcom_is_special_pin(priv->pin_data, gpio))
58 return 0;
59
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020060 value = !!value;
61 /* set value */
Caleb Connollyfabb8972023-11-14 12:55:42 +000062 writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020063
64 return 0;
65}
66
Caleb Connolly8fff7eb2023-11-14 12:55:43 +000067static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020068 int value)
69{
70 struct msm_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020071
Caleb Connolly190005c2024-02-26 17:26:17 +000072 /* Always NOP for special pins, assume they're in the correct state */
73 if (qcom_is_special_pin(priv->pin_data, gpio))
74 return 0;
75
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020076 value = !!value;
77 /* set value */
Caleb Connollyfabb8972023-11-14 12:55:42 +000078 writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020079 /* switch direction */
Caleb Connollyfabb8972023-11-14 12:55:42 +000080 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
81 GPIO_OE_MASK, GPIO_OE_ENABLE);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020082
83 return 0;
84}
85
Caleb Connolly241dfda2024-04-03 14:07:43 +020086static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
87{
88 if (flags & GPIOD_IS_OUT_ACTIVE) {
89 return msm_gpio_direction_output(dev, gpio, 1);
90 } else if (flags & GPIOD_IS_OUT) {
91 return msm_gpio_direction_output(dev, gpio, 0);
92 } else if (flags & GPIOD_IS_IN) {
93 msm_gpio_direction_input(dev, gpio);
94 if (flags & GPIOD_PULL_UP)
95 return msm_gpio_set_value(dev, gpio, 1);
96 else if (flags & GPIOD_PULL_DOWN)
97 return msm_gpio_set_value(dev, gpio, 0);
98 }
99
100 return 0;
101}
102
Caleb Connolly8fff7eb2023-11-14 12:55:43 +0000103static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200104{
105 struct msm_gpio_bank *priv = dev_get_priv(dev);
106
Caleb Connolly190005c2024-02-26 17:26:17 +0000107 /* Always NOP for special pins, assume they're in the correct state */
108 if (qcom_is_special_pin(priv->pin_data, gpio))
109 return 0;
110
Caleb Connollyfabb8972023-11-14 12:55:42 +0000111 return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200112}
113
Caleb Connolly8fff7eb2023-11-14 12:55:43 +0000114static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200115{
116 struct msm_gpio_bank *priv = dev_get_priv(dev);
117
Caleb Connolly190005c2024-02-26 17:26:17 +0000118 /* Always NOP for special pins, assume they're in the correct state */
119 if (qcom_is_special_pin(priv->pin_data, gpio))
120 return 0;
121
Caleb Connollyfabb8972023-11-14 12:55:42 +0000122 if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200123 return GPIOF_OUTPUT;
124
125 return GPIOF_INPUT;
126}
127
128static const struct dm_gpio_ops gpio_msm_ops = {
Caleb Connolly241dfda2024-04-03 14:07:43 +0200129 .set_flags = msm_gpio_set_flags,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200130 .get_value = msm_gpio_get_value,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200131 .get_function = msm_gpio_get_function,
132};
133
134static int msm_gpio_probe(struct udevice *dev)
135{
136 struct msm_gpio_bank *priv = dev_get_priv(dev);
137
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900138 priv->base = dev_read_addr(dev);
Caleb Connollyfabb8972023-11-14 12:55:42 +0000139 priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200140
141 return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
142}
143
Simon Glassaad29ae2020-12-03 16:55:21 -0700144static int msm_gpio_of_to_plat(struct udevice *dev)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200145{
146 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Caleb Connollyfabb8972023-11-14 12:55:42 +0000147 const struct msm_pin_data *pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200148
Caleb Connollyfabb8972023-11-14 12:55:42 +0000149 /* Get the pin count from the pinctrl driver */
150 uc_priv->gpio_count = pin_data->pin_count;
Simon Glassdd79d6e2017-01-17 16:52:55 -0700151 uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200152 "gpio-bank-name", NULL);
153 if (uc_priv->bank_name == NULL)
154 uc_priv->bank_name = "soc";
155
156 return 0;
157}
158
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200159U_BOOT_DRIVER(gpio_msm) = {
160 .name = "gpio_msm",
161 .id = UCLASS_GPIO,
Simon Glassaad29ae2020-12-03 16:55:21 -0700162 .of_to_plat = msm_gpio_of_to_plat,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200163 .probe = msm_gpio_probe,
164 .ops = &gpio_msm_ops,
Sumit Gargb7572e52022-07-27 13:52:04 +0530165 .flags = DM_UC_FLAG_SEQ_ALIAS,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700166 .priv_auto = sizeof(struct msm_gpio_bank),
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200167};