blob: f5d9ab54e8170704f867cf3e6ae26a0c8bee2838 [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
8#include <common.h>
9#include <dm.h>
10#include <errno.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060011#include <asm/global_data.h>
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020012#include <asm/gpio.h>
13#include <asm/io.h>
Caleb Connollyfabb8972023-11-14 12:55:42 +000014#include <mach/gpio.h>
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020015
16DECLARE_GLOBAL_DATA_PTR;
17
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020018/* 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;
Caleb Connollyfabb8972023-11-14 12:55:42 +000029 const struct msm_pin_data *pin_data;
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020030};
31
Caleb Connollyfabb8972023-11-14 12:55:42 +000032#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
Caleb Connolly241dfda2024-04-03 14:07:43 +020038static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020039{
40 struct msm_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020041
Caleb Connolly190005c2024-02-26 17:26:17 +000042 /* Always NOP for special pins, assume they're in the correct state */
43 if (qcom_is_special_pin(priv->pin_data, gpio))
Caleb Connolly241dfda2024-04-03 14:07:43 +020044 return;
Caleb Connolly190005c2024-02-26 17:26:17 +000045
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020046 /* Disable OE bit */
Caleb Connollyfabb8972023-11-14 12:55:42 +000047 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
48 GPIO_OE_MASK, GPIO_OE_DISABLE);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020049
Caleb Connolly241dfda2024-04-03 14:07:43 +020050 return;
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020051}
52
Caleb Connolly8fff7eb2023-11-14 12:55:43 +000053static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020054{
55 struct msm_gpio_bank *priv = dev_get_priv(dev);
56
Caleb Connolly190005c2024-02-26 17:26:17 +000057 /* 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
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020061 value = !!value;
62 /* set value */
Caleb Connollyfabb8972023-11-14 12:55:42 +000063 writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020064
65 return 0;
66}
67
Caleb Connolly8fff7eb2023-11-14 12:55:43 +000068static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020069 int value)
70{
71 struct msm_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020072
Caleb Connolly190005c2024-02-26 17:26:17 +000073 /* 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
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020077 value = !!value;
78 /* set value */
Caleb Connollyfabb8972023-11-14 12:55:42 +000079 writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020080 /* switch direction */
Caleb Connollyfabb8972023-11-14 12:55:42 +000081 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
82 GPIO_OE_MASK, GPIO_OE_ENABLE);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +020083
84 return 0;
85}
86
Caleb Connolly241dfda2024-04-03 14:07:43 +020087static 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
Caleb Connolly8fff7eb2023-11-14 12:55:43 +0000104static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200105{
106 struct msm_gpio_bank *priv = dev_get_priv(dev);
107
Caleb Connolly190005c2024-02-26 17:26:17 +0000108 /* 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
Caleb Connollyfabb8972023-11-14 12:55:42 +0000112 return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200113}
114
Caleb Connolly8fff7eb2023-11-14 12:55:43 +0000115static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200116{
117 struct msm_gpio_bank *priv = dev_get_priv(dev);
118
Caleb Connolly190005c2024-02-26 17:26:17 +0000119 /* 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
Caleb Connollyfabb8972023-11-14 12:55:42 +0000123 if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200124 return GPIOF_OUTPUT;
125
126 return GPIOF_INPUT;
127}
128
129static const struct dm_gpio_ops gpio_msm_ops = {
Caleb Connolly241dfda2024-04-03 14:07:43 +0200130 .set_flags = msm_gpio_set_flags,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200131 .get_value = msm_gpio_get_value,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200132 .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
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900139 priv->base = dev_read_addr(dev);
Caleb Connollyfabb8972023-11-14 12:55:42 +0000140 priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200141
142 return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
143}
144
Simon Glassaad29ae2020-12-03 16:55:21 -0700145static int msm_gpio_of_to_plat(struct udevice *dev)
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200146{
147 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Caleb Connollyfabb8972023-11-14 12:55:42 +0000148 const struct msm_pin_data *pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200149
Caleb Connollyfabb8972023-11-14 12:55:42 +0000150 /* Get the pin count from the pinctrl driver */
151 uc_priv->gpio_count = pin_data->pin_count;
Simon Glassdd79d6e2017-01-17 16:52:55 -0700152 uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200153 "gpio-bank-name", NULL);
154 if (uc_priv->bank_name == NULL)
155 uc_priv->bank_name = "soc";
156
157 return 0;
158}
159
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200160U_BOOT_DRIVER(gpio_msm) = {
161 .name = "gpio_msm",
162 .id = UCLASS_GPIO,
Simon Glassaad29ae2020-12-03 16:55:21 -0700163 .of_to_plat = msm_gpio_of_to_plat,
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200164 .probe = msm_gpio_probe,
165 .ops = &gpio_msm_ops,
Sumit Gargb7572e52022-07-27 13:52:04 +0530166 .flags = DM_UC_FLAG_SEQ_ALIAS,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700167 .priv_auto = sizeof(struct msm_gpio_bank),
Mateusz Kulikowskia1b3ae92016-03-31 23:12:15 +0200168};