cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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, &reg, &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, &reg, &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, &reg, &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, &reg, &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, &reg, &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");