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