gpio-regmap.c (8864B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * regmap based generic GPIO driver 4 * 5 * Copyright 2020 Michael Walle <michael@walle.cc> 6 */ 7 8#include <linux/gpio/driver.h> 9#include <linux/gpio/regmap.h> 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/regmap.h> 13 14struct gpio_regmap { 15 struct device *parent; 16 struct regmap *regmap; 17 struct gpio_chip gpio_chip; 18 19 int reg_stride; 20 int ngpio_per_reg; 21 unsigned int reg_dat_base; 22 unsigned int reg_set_base; 23 unsigned int reg_clr_base; 24 unsigned int reg_dir_in_base; 25 unsigned int reg_dir_out_base; 26 27 int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base, 28 unsigned int offset, unsigned int *reg, 29 unsigned int *mask); 30 31 void *driver_data; 32}; 33 34static unsigned int gpio_regmap_addr(unsigned int addr) 35{ 36 if (addr == GPIO_REGMAP_ADDR_ZERO) 37 return 0; 38 39 return addr; 40} 41 42static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio, 43 unsigned int base, unsigned int offset, 44 unsigned int *reg, unsigned int *mask) 45{ 46 unsigned int line = offset % gpio->ngpio_per_reg; 47 unsigned int stride = offset / gpio->ngpio_per_reg; 48 49 *reg = base + stride * gpio->reg_stride; 50 *mask = BIT(line); 51 52 return 0; 53} 54 55static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset) 56{ 57 struct gpio_regmap *gpio = gpiochip_get_data(chip); 58 unsigned int base, val, reg, mask; 59 int ret; 60 61 /* we might not have an output register if we are input only */ 62 if (gpio->reg_dat_base) 63 base = gpio_regmap_addr(gpio->reg_dat_base); 64 else 65 base = gpio_regmap_addr(gpio->reg_set_base); 66 67 ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); 68 if (ret) 69 return ret; 70 71 ret = regmap_read(gpio->regmap, reg, &val); 72 if (ret) 73 return ret; 74 75 return !!(val & mask); 76} 77 78static void gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, 79 int val) 80{ 81 struct gpio_regmap *gpio = gpiochip_get_data(chip); 82 unsigned int base = gpio_regmap_addr(gpio->reg_set_base); 83 unsigned int reg, mask; 84 85 gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); 86 if (val) 87 regmap_update_bits(gpio->regmap, reg, mask, mask); 88 else 89 regmap_update_bits(gpio->regmap, reg, mask, 0); 90} 91 92static void gpio_regmap_set_with_clear(struct gpio_chip *chip, 93 unsigned int offset, int val) 94{ 95 struct gpio_regmap *gpio = gpiochip_get_data(chip); 96 unsigned int base, reg, mask; 97 98 if (val) 99 base = gpio_regmap_addr(gpio->reg_set_base); 100 else 101 base = gpio_regmap_addr(gpio->reg_clr_base); 102 103 gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); 104 regmap_write(gpio->regmap, reg, mask); 105} 106 107static int gpio_regmap_get_direction(struct gpio_chip *chip, 108 unsigned int offset) 109{ 110 struct gpio_regmap *gpio = gpiochip_get_data(chip); 111 unsigned int base, val, reg, mask; 112 int invert, ret; 113 114 if (gpio->reg_dir_out_base) { 115 base = gpio_regmap_addr(gpio->reg_dir_out_base); 116 invert = 0; 117 } else if (gpio->reg_dir_in_base) { 118 base = gpio_regmap_addr(gpio->reg_dir_in_base); 119 invert = 1; 120 } else { 121 return -EOPNOTSUPP; 122 } 123 124 ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); 125 if (ret) 126 return ret; 127 128 ret = regmap_read(gpio->regmap, reg, &val); 129 if (ret) 130 return ret; 131 132 if (!!(val & mask) ^ invert) 133 return GPIO_LINE_DIRECTION_OUT; 134 else 135 return GPIO_LINE_DIRECTION_IN; 136} 137 138static int gpio_regmap_set_direction(struct gpio_chip *chip, 139 unsigned int offset, bool output) 140{ 141 struct gpio_regmap *gpio = gpiochip_get_data(chip); 142 unsigned int base, val, reg, mask; 143 int invert, ret; 144 145 if (gpio->reg_dir_out_base) { 146 base = gpio_regmap_addr(gpio->reg_dir_out_base); 147 invert = 0; 148 } else if (gpio->reg_dir_in_base) { 149 base = gpio_regmap_addr(gpio->reg_dir_in_base); 150 invert = 1; 151 } else { 152 return -EOPNOTSUPP; 153 } 154 155 ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); 156 if (ret) 157 return ret; 158 159 if (invert) 160 val = output ? 0 : mask; 161 else 162 val = output ? mask : 0; 163 164 return regmap_update_bits(gpio->regmap, reg, mask, val); 165} 166 167static int gpio_regmap_direction_input(struct gpio_chip *chip, 168 unsigned int offset) 169{ 170 return gpio_regmap_set_direction(chip, offset, false); 171} 172 173static int gpio_regmap_direction_output(struct gpio_chip *chip, 174 unsigned int offset, int value) 175{ 176 gpio_regmap_set(chip, offset, value); 177 178 return gpio_regmap_set_direction(chip, offset, true); 179} 180 181void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio) 182{ 183 return gpio->driver_data; 184} 185EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata); 186 187/** 188 * gpio_regmap_register() - Register a generic regmap GPIO controller 189 * @config: configuration for gpio_regmap 190 * 191 * Return: A pointer to the registered gpio_regmap or ERR_PTR error value. 192 */ 193struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config) 194{ 195 struct gpio_regmap *gpio; 196 struct gpio_chip *chip; 197 int ret; 198 199 if (!config->parent) 200 return ERR_PTR(-EINVAL); 201 202 if (!config->ngpio) 203 return ERR_PTR(-EINVAL); 204 205 /* we need at least one */ 206 if (!config->reg_dat_base && !config->reg_set_base) 207 return ERR_PTR(-EINVAL); 208 209 /* if we have a direction register we need both input and output */ 210 if ((config->reg_dir_out_base || config->reg_dir_in_base) && 211 (!config->reg_dat_base || !config->reg_set_base)) 212 return ERR_PTR(-EINVAL); 213 214 /* we don't support having both registers simultaneously for now */ 215 if (config->reg_dir_out_base && config->reg_dir_in_base) 216 return ERR_PTR(-EINVAL); 217 218 gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); 219 if (!gpio) 220 return ERR_PTR(-ENOMEM); 221 222 gpio->parent = config->parent; 223 gpio->driver_data = config->drvdata; 224 gpio->regmap = config->regmap; 225 gpio->ngpio_per_reg = config->ngpio_per_reg; 226 gpio->reg_stride = config->reg_stride; 227 gpio->reg_mask_xlate = config->reg_mask_xlate; 228 gpio->reg_dat_base = config->reg_dat_base; 229 gpio->reg_set_base = config->reg_set_base; 230 gpio->reg_clr_base = config->reg_clr_base; 231 gpio->reg_dir_in_base = config->reg_dir_in_base; 232 gpio->reg_dir_out_base = config->reg_dir_out_base; 233 234 /* if not set, assume there is only one register */ 235 if (!gpio->ngpio_per_reg) 236 gpio->ngpio_per_reg = config->ngpio; 237 238 /* if not set, assume they are consecutive */ 239 if (!gpio->reg_stride) 240 gpio->reg_stride = 1; 241 242 if (!gpio->reg_mask_xlate) 243 gpio->reg_mask_xlate = gpio_regmap_simple_xlate; 244 245 chip = &gpio->gpio_chip; 246 chip->parent = config->parent; 247 chip->fwnode = config->fwnode; 248 chip->base = -1; 249 chip->ngpio = config->ngpio; 250 chip->names = config->names; 251 chip->label = config->label ?: dev_name(config->parent); 252 253 /* 254 * If our regmap is fast_io we should probably set can_sleep to false. 255 * Right now, the regmap doesn't save this property, nor is there any 256 * access function for it. 257 * The only regmap type which uses fast_io is regmap-mmio. For now, 258 * assume a safe default of true here. 259 */ 260 chip->can_sleep = true; 261 262 chip->get = gpio_regmap_get; 263 if (gpio->reg_set_base && gpio->reg_clr_base) 264 chip->set = gpio_regmap_set_with_clear; 265 else if (gpio->reg_set_base) 266 chip->set = gpio_regmap_set; 267 268 if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) { 269 chip->get_direction = gpio_regmap_get_direction; 270 chip->direction_input = gpio_regmap_direction_input; 271 chip->direction_output = gpio_regmap_direction_output; 272 } 273 274 ret = gpiochip_add_data(chip, gpio); 275 if (ret < 0) 276 goto err_free_gpio; 277 278 if (config->irq_domain) { 279 ret = gpiochip_irqchip_add_domain(chip, config->irq_domain); 280 if (ret) 281 goto err_remove_gpiochip; 282 } 283 284 return gpio; 285 286err_remove_gpiochip: 287 gpiochip_remove(chip); 288err_free_gpio: 289 kfree(gpio); 290 return ERR_PTR(ret); 291} 292EXPORT_SYMBOL_GPL(gpio_regmap_register); 293 294/** 295 * gpio_regmap_unregister() - Unregister a generic regmap GPIO controller 296 * @gpio: gpio_regmap device to unregister 297 */ 298void gpio_regmap_unregister(struct gpio_regmap *gpio) 299{ 300 gpiochip_remove(&gpio->gpio_chip); 301 kfree(gpio); 302} 303EXPORT_SYMBOL_GPL(gpio_regmap_unregister); 304 305static void devm_gpio_regmap_unregister(void *res) 306{ 307 gpio_regmap_unregister(res); 308} 309 310/** 311 * devm_gpio_regmap_register() - resource managed gpio_regmap_register() 312 * @dev: device that is registering this GPIO device 313 * @config: configuration for gpio_regmap 314 * 315 * Managed gpio_regmap_register(). For generic regmap GPIO device registered by 316 * this function, gpio_regmap_unregister() is automatically called on driver 317 * detach. See gpio_regmap_register() for more information. 318 * 319 * Return: A pointer to the registered gpio_regmap or ERR_PTR error value. 320 */ 321struct gpio_regmap *devm_gpio_regmap_register(struct device *dev, 322 const struct gpio_regmap_config *config) 323{ 324 struct gpio_regmap *gpio; 325 int ret; 326 327 gpio = gpio_regmap_register(config); 328 329 if (IS_ERR(gpio)) 330 return gpio; 331 332 ret = devm_add_action_or_reset(dev, devm_gpio_regmap_unregister, gpio); 333 if (ret) 334 return ERR_PTR(ret); 335 336 return gpio; 337} 338EXPORT_SYMBOL_GPL(devm_gpio_regmap_register); 339 340MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); 341MODULE_DESCRIPTION("GPIO generic regmap driver core"); 342MODULE_LICENSE("GPL");