1 /* 2 * Copyright (c) 2011 The Chromium OS Authors. 3 * SPDX-License-Identifier: GPL-2.0+ 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <fdtdec.h> 9 #include <malloc.h> 10 #include <asm/gpio.h> 11 12 DECLARE_GLOBAL_DATA_PTR; 13 14 /* Flags for each GPIO */ 15 #define GPIOF_OUTPUT (1 << 0) /* Currently set as an output */ 16 #define GPIOF_HIGH (1 << 1) /* Currently set high */ 17 #define GPIOF_RESERVED (1 << 2) /* Is in use / requested */ 18 19 struct gpio_state { 20 const char *label; /* label given by requester */ 21 u8 flags; /* flags (GPIOF_...) */ 22 }; 23 24 /* Access routines for GPIO state */ 25 static u8 *get_gpio_flags(struct device *dev, unsigned offset) 26 { 27 struct gpio_dev_priv *uc_priv = dev->uclass_priv; 28 struct gpio_state *state = dev_get_priv(dev); 29 30 if (offset >= uc_priv->gpio_count) { 31 static u8 invalid_flags; 32 printf("sandbox_gpio: error: invalid gpio %u\n", offset); 33 return &invalid_flags; 34 } 35 36 return &state[offset].flags; 37 } 38 39 static int get_gpio_flag(struct device *dev, unsigned offset, int flag) 40 { 41 return (*get_gpio_flags(dev, offset) & flag) != 0; 42 } 43 44 static int set_gpio_flag(struct device *dev, unsigned offset, int flag, 45 int value) 46 { 47 u8 *gpio = get_gpio_flags(dev, offset); 48 49 if (value) 50 *gpio |= flag; 51 else 52 *gpio &= ~flag; 53 54 return 0; 55 } 56 57 static int check_reserved(struct device *dev, unsigned offset, 58 const char *func) 59 { 60 if (!get_gpio_flag(dev, offset, GPIOF_RESERVED)) { 61 printf("sandbox_gpio: %s: error: offset %u not reserved\n", 62 func, offset); 63 return -1; 64 } 65 66 return 0; 67 } 68 69 /* 70 * Back-channel sandbox-internal-only access to GPIO state 71 */ 72 73 int sandbox_gpio_get_value(struct device *dev, unsigned offset) 74 { 75 if (get_gpio_flag(dev, offset, GPIOF_OUTPUT)) 76 debug("sandbox_gpio: get_value on output gpio %u\n", offset); 77 return get_gpio_flag(dev, offset, GPIOF_HIGH); 78 } 79 80 int sandbox_gpio_set_value(struct device *dev, unsigned offset, int value) 81 { 82 return set_gpio_flag(dev, offset, GPIOF_HIGH, value); 83 } 84 85 int sandbox_gpio_get_direction(struct device *dev, unsigned offset) 86 { 87 return get_gpio_flag(dev, offset, GPIOF_OUTPUT); 88 } 89 90 int sandbox_gpio_set_direction(struct device *dev, unsigned offset, int output) 91 { 92 return set_gpio_flag(dev, offset, GPIOF_OUTPUT, output); 93 } 94 95 /* 96 * These functions implement the public interface within U-Boot 97 */ 98 99 /* set GPIO port 'offset' as an input */ 100 static int sb_gpio_direction_input(struct device *dev, unsigned offset) 101 { 102 debug("%s: offset:%u\n", __func__, offset); 103 104 if (check_reserved(dev, offset, __func__)) 105 return -1; 106 107 return sandbox_gpio_set_direction(dev, offset, 0); 108 } 109 110 /* set GPIO port 'offset' as an output, with polarity 'value' */ 111 static int sb_gpio_direction_output(struct device *dev, unsigned offset, 112 int value) 113 { 114 debug("%s: offset:%u, value = %d\n", __func__, offset, value); 115 116 if (check_reserved(dev, offset, __func__)) 117 return -1; 118 119 return sandbox_gpio_set_direction(dev, offset, 1) | 120 sandbox_gpio_set_value(dev, offset, value); 121 } 122 123 /* read GPIO IN value of port 'offset' */ 124 static int sb_gpio_get_value(struct device *dev, unsigned offset) 125 { 126 debug("%s: offset:%u\n", __func__, offset); 127 128 if (check_reserved(dev, offset, __func__)) 129 return -1; 130 131 return sandbox_gpio_get_value(dev, offset); 132 } 133 134 /* write GPIO OUT value to port 'offset' */ 135 static int sb_gpio_set_value(struct device *dev, unsigned offset, int value) 136 { 137 debug("%s: offset:%u, value = %d\n", __func__, offset, value); 138 139 if (check_reserved(dev, offset, __func__)) 140 return -1; 141 142 if (!sandbox_gpio_get_direction(dev, offset)) { 143 printf("sandbox_gpio: error: set_value on input gpio %u\n", 144 offset); 145 return -1; 146 } 147 148 return sandbox_gpio_set_value(dev, offset, value); 149 } 150 151 static int sb_gpio_request(struct device *dev, unsigned offset, 152 const char *label) 153 { 154 struct gpio_dev_priv *uc_priv = dev->uclass_priv; 155 struct gpio_state *state = dev_get_priv(dev); 156 157 debug("%s: offset:%u, label:%s\n", __func__, offset, label); 158 159 if (offset >= uc_priv->gpio_count) { 160 printf("sandbox_gpio: error: invalid gpio %u\n", offset); 161 return -1; 162 } 163 164 if (get_gpio_flag(dev, offset, GPIOF_RESERVED)) { 165 printf("sandbox_gpio: error: gpio %u already reserved\n", 166 offset); 167 return -1; 168 } 169 170 state[offset].label = label; 171 return set_gpio_flag(dev, offset, GPIOF_RESERVED, 1); 172 } 173 174 static int sb_gpio_free(struct device *dev, unsigned offset) 175 { 176 struct gpio_state *state = dev_get_priv(dev); 177 178 debug("%s: offset:%u\n", __func__, offset); 179 180 if (check_reserved(dev, offset, __func__)) 181 return -1; 182 183 state[offset].label = NULL; 184 return set_gpio_flag(dev, offset, GPIOF_RESERVED, 0); 185 } 186 187 static int sb_gpio_get_state(struct device *dev, unsigned int offset, 188 char *buf, int bufsize) 189 { 190 struct gpio_dev_priv *uc_priv = dev->uclass_priv; 191 struct gpio_state *state = dev_get_priv(dev); 192 const char *label; 193 194 label = state[offset].label; 195 snprintf(buf, bufsize, "%s%d: %s: %d [%c]%s%s", 196 uc_priv->bank_name ? uc_priv->bank_name : "", offset, 197 sandbox_gpio_get_direction(dev, offset) ? "out" : " in", 198 sandbox_gpio_get_value(dev, offset), 199 get_gpio_flag(dev, offset, GPIOF_RESERVED) ? 'x' : ' ', 200 label ? " " : "", 201 label ? label : ""); 202 203 return 0; 204 } 205 206 static const struct dm_gpio_ops gpio_sandbox_ops = { 207 .request = sb_gpio_request, 208 .free = sb_gpio_free, 209 .direction_input = sb_gpio_direction_input, 210 .direction_output = sb_gpio_direction_output, 211 .get_value = sb_gpio_get_value, 212 .set_value = sb_gpio_set_value, 213 .get_state = sb_gpio_get_state, 214 }; 215 216 static int sandbox_gpio_ofdata_to_platdata(struct device *dev) 217 { 218 struct gpio_dev_priv *uc_priv = dev->uclass_priv; 219 220 uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 221 "num-gpios", 0); 222 uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, 223 "gpio-bank-name", NULL); 224 225 return 0; 226 } 227 228 static int gpio_sandbox_probe(struct device *dev) 229 { 230 struct gpio_dev_priv *uc_priv = dev->uclass_priv; 231 232 if (dev->of_offset == -1) { 233 /* Tell the uclass how many GPIOs we have */ 234 uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT; 235 } 236 237 dev->priv = calloc(sizeof(struct gpio_state), uc_priv->gpio_count); 238 239 return 0; 240 } 241 242 static const struct device_id sandbox_gpio_ids[] = { 243 { .compatible = "sandbox,gpio" }, 244 { } 245 }; 246 247 U_BOOT_DRIVER(gpio_sandbox) = { 248 .name = "gpio_sandbox", 249 .id = UCLASS_GPIO, 250 .of_match = sandbox_gpio_ids, 251 .ofdata_to_platdata = sandbox_gpio_ofdata_to_platdata, 252 .probe = gpio_sandbox_probe, 253 .ops = &gpio_sandbox_ops, 254 }; 255