1cb8c474eSBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0-or-later 2cb8c474eSBartosz Golaszewski /* 3cb8c474eSBartosz Golaszewski * GPIO testing driver based on configfs. 4cb8c474eSBartosz Golaszewski * 5cb8c474eSBartosz Golaszewski * Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl> 6cb8c474eSBartosz Golaszewski */ 7cb8c474eSBartosz Golaszewski 8cb8c474eSBartosz Golaszewski #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9cb8c474eSBartosz Golaszewski 10cb8c474eSBartosz Golaszewski #include <linux/bitmap.h> 11cb8c474eSBartosz Golaszewski #include <linux/completion.h> 12cb8c474eSBartosz Golaszewski #include <linux/configfs.h> 13cb8c474eSBartosz Golaszewski #include <linux/device.h> 14cb8c474eSBartosz Golaszewski #include <linux/gpio/driver.h> 15cb8c474eSBartosz Golaszewski #include <linux/gpio/machine.h> 16cb8c474eSBartosz Golaszewski #include <linux/idr.h> 17cb8c474eSBartosz Golaszewski #include <linux/interrupt.h> 18cb8c474eSBartosz Golaszewski #include <linux/irq.h> 19cb8c474eSBartosz Golaszewski #include <linux/irq_sim.h> 20cb8c474eSBartosz Golaszewski #include <linux/list.h> 21cb8c474eSBartosz Golaszewski #include <linux/mod_devicetable.h> 22cb8c474eSBartosz Golaszewski #include <linux/module.h> 23cb8c474eSBartosz Golaszewski #include <linux/mutex.h> 24cb8c474eSBartosz Golaszewski #include <linux/notifier.h> 25cb8c474eSBartosz Golaszewski #include <linux/platform_device.h> 26cb8c474eSBartosz Golaszewski #include <linux/property.h> 27cb8c474eSBartosz Golaszewski #include <linux/slab.h> 28cb8c474eSBartosz Golaszewski #include <linux/string.h> 29cb8c474eSBartosz Golaszewski #include <linux/string_helpers.h> 30cb8c474eSBartosz Golaszewski #include <linux/sysfs.h> 31cb8c474eSBartosz Golaszewski 32cb8c474eSBartosz Golaszewski #include "gpiolib.h" 33cb8c474eSBartosz Golaszewski 3411e47bbdSBartosz Golaszewski #define GPIO_SIM_NGPIO_MAX 1024 35cb8c474eSBartosz Golaszewski #define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ 36cb8c474eSBartosz Golaszewski #define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */ 37cb8c474eSBartosz Golaszewski 38cb8c474eSBartosz Golaszewski static DEFINE_IDA(gpio_sim_ida); 39cb8c474eSBartosz Golaszewski 40cb8c474eSBartosz Golaszewski struct gpio_sim_chip { 41cb8c474eSBartosz Golaszewski struct gpio_chip gc; 42cb8c474eSBartosz Golaszewski unsigned long *direction_map; 43cb8c474eSBartosz Golaszewski unsigned long *value_map; 44cb8c474eSBartosz Golaszewski unsigned long *pull_map; 45cb8c474eSBartosz Golaszewski struct irq_domain *irq_sim; 46cb8c474eSBartosz Golaszewski struct mutex lock; 47cb8c474eSBartosz Golaszewski const struct attribute_group **attr_groups; 48cb8c474eSBartosz Golaszewski }; 49cb8c474eSBartosz Golaszewski 50cb8c474eSBartosz Golaszewski struct gpio_sim_attribute { 51cb8c474eSBartosz Golaszewski struct device_attribute dev_attr; 52cb8c474eSBartosz Golaszewski unsigned int offset; 53cb8c474eSBartosz Golaszewski }; 54cb8c474eSBartosz Golaszewski 55cb8c474eSBartosz Golaszewski static struct gpio_sim_attribute * 56cb8c474eSBartosz Golaszewski to_gpio_sim_attr(struct device_attribute *dev_attr) 57cb8c474eSBartosz Golaszewski { 58cb8c474eSBartosz Golaszewski return container_of(dev_attr, struct gpio_sim_attribute, dev_attr); 59cb8c474eSBartosz Golaszewski } 60cb8c474eSBartosz Golaszewski 61cb8c474eSBartosz Golaszewski static int gpio_sim_apply_pull(struct gpio_sim_chip *chip, 62cb8c474eSBartosz Golaszewski unsigned int offset, int value) 63cb8c474eSBartosz Golaszewski { 64cb8c474eSBartosz Golaszewski int irq, irq_type, ret; 65cb8c474eSBartosz Golaszewski struct gpio_desc *desc; 66cb8c474eSBartosz Golaszewski struct gpio_chip *gc; 67cb8c474eSBartosz Golaszewski 68cb8c474eSBartosz Golaszewski gc = &chip->gc; 69cb8c474eSBartosz Golaszewski desc = &gc->gpiodev->descs[offset]; 70cb8c474eSBartosz Golaszewski 71cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 72cb8c474eSBartosz Golaszewski 73cb8c474eSBartosz Golaszewski if (test_bit(FLAG_REQUESTED, &desc->flags) && 74cb8c474eSBartosz Golaszewski !test_bit(FLAG_IS_OUT, &desc->flags)) { 75cb8c474eSBartosz Golaszewski if (value == !!test_bit(offset, chip->value_map)) 76cb8c474eSBartosz Golaszewski goto set_pull; 77cb8c474eSBartosz Golaszewski 78cb8c474eSBartosz Golaszewski /* 79cb8c474eSBartosz Golaszewski * This is fine - it just means, nobody is listening 80cb8c474eSBartosz Golaszewski * for interrupts on this line, otherwise 81cb8c474eSBartosz Golaszewski * irq_create_mapping() would have been called from 82cb8c474eSBartosz Golaszewski * the to_irq() callback. 83cb8c474eSBartosz Golaszewski */ 84cb8c474eSBartosz Golaszewski irq = irq_find_mapping(chip->irq_sim, offset); 85cb8c474eSBartosz Golaszewski if (!irq) 86cb8c474eSBartosz Golaszewski goto set_value; 87cb8c474eSBartosz Golaszewski 88cb8c474eSBartosz Golaszewski irq_type = irq_get_trigger_type(irq); 89cb8c474eSBartosz Golaszewski 90cb8c474eSBartosz Golaszewski if ((value && (irq_type & IRQ_TYPE_EDGE_RISING)) || 91cb8c474eSBartosz Golaszewski (!value && (irq_type & IRQ_TYPE_EDGE_FALLING))) { 92cb8c474eSBartosz Golaszewski ret = irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, 93cb8c474eSBartosz Golaszewski true); 94cb8c474eSBartosz Golaszewski if (ret) 95cb8c474eSBartosz Golaszewski goto set_pull; 96cb8c474eSBartosz Golaszewski } 97cb8c474eSBartosz Golaszewski } 98cb8c474eSBartosz Golaszewski 99cb8c474eSBartosz Golaszewski set_value: 100cb8c474eSBartosz Golaszewski /* Change the value unless we're actively driving the line. */ 101cb8c474eSBartosz Golaszewski if (!test_bit(FLAG_REQUESTED, &desc->flags) || 102cb8c474eSBartosz Golaszewski !test_bit(FLAG_IS_OUT, &desc->flags)) 103cb8c474eSBartosz Golaszewski __assign_bit(offset, chip->value_map, value); 104cb8c474eSBartosz Golaszewski 105cb8c474eSBartosz Golaszewski set_pull: 106cb8c474eSBartosz Golaszewski __assign_bit(offset, chip->pull_map, value); 107cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 108cb8c474eSBartosz Golaszewski return 0; 109cb8c474eSBartosz Golaszewski } 110cb8c474eSBartosz Golaszewski 111cb8c474eSBartosz Golaszewski static int gpio_sim_get(struct gpio_chip *gc, unsigned int offset) 112cb8c474eSBartosz Golaszewski { 113cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 114cb8c474eSBartosz Golaszewski int ret; 115cb8c474eSBartosz Golaszewski 116cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 117cb8c474eSBartosz Golaszewski ret = !!test_bit(offset, chip->value_map); 118cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 119cb8c474eSBartosz Golaszewski 120cb8c474eSBartosz Golaszewski return ret; 121cb8c474eSBartosz Golaszewski } 122cb8c474eSBartosz Golaszewski 123cb8c474eSBartosz Golaszewski static void gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value) 124cb8c474eSBartosz Golaszewski { 125cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 126cb8c474eSBartosz Golaszewski 127cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 128cb8c474eSBartosz Golaszewski __assign_bit(offset, chip->value_map, value); 129cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 130cb8c474eSBartosz Golaszewski } 131cb8c474eSBartosz Golaszewski 132cb8c474eSBartosz Golaszewski static int gpio_sim_get_multiple(struct gpio_chip *gc, 133cb8c474eSBartosz Golaszewski unsigned long *mask, unsigned long *bits) 134cb8c474eSBartosz Golaszewski { 135cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 136cb8c474eSBartosz Golaszewski 137cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 1383836c73eSBartosz Golaszewski bitmap_replace(bits, bits, chip->value_map, mask, gc->ngpio); 139cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 140cb8c474eSBartosz Golaszewski 141cb8c474eSBartosz Golaszewski return 0; 142cb8c474eSBartosz Golaszewski } 143cb8c474eSBartosz Golaszewski 144cb8c474eSBartosz Golaszewski static void gpio_sim_set_multiple(struct gpio_chip *gc, 145cb8c474eSBartosz Golaszewski unsigned long *mask, unsigned long *bits) 146cb8c474eSBartosz Golaszewski { 147cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 148cb8c474eSBartosz Golaszewski 149cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 1503836c73eSBartosz Golaszewski bitmap_replace(chip->value_map, chip->value_map, bits, mask, gc->ngpio); 151cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 152cb8c474eSBartosz Golaszewski } 153cb8c474eSBartosz Golaszewski 154cb8c474eSBartosz Golaszewski static int gpio_sim_direction_output(struct gpio_chip *gc, 155cb8c474eSBartosz Golaszewski unsigned int offset, int value) 156cb8c474eSBartosz Golaszewski { 157cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 158cb8c474eSBartosz Golaszewski 159cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 160cb8c474eSBartosz Golaszewski __clear_bit(offset, chip->direction_map); 161cb8c474eSBartosz Golaszewski __assign_bit(offset, chip->value_map, value); 162cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 163cb8c474eSBartosz Golaszewski 164cb8c474eSBartosz Golaszewski return 0; 165cb8c474eSBartosz Golaszewski } 166cb8c474eSBartosz Golaszewski 167cb8c474eSBartosz Golaszewski static int gpio_sim_direction_input(struct gpio_chip *gc, unsigned int offset) 168cb8c474eSBartosz Golaszewski { 169cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 170cb8c474eSBartosz Golaszewski 171cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 172cb8c474eSBartosz Golaszewski __set_bit(offset, chip->direction_map); 173cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 174cb8c474eSBartosz Golaszewski 175cb8c474eSBartosz Golaszewski return 0; 176cb8c474eSBartosz Golaszewski } 177cb8c474eSBartosz Golaszewski 178cb8c474eSBartosz Golaszewski static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset) 179cb8c474eSBartosz Golaszewski { 180cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 181cb8c474eSBartosz Golaszewski int direction; 182cb8c474eSBartosz Golaszewski 183cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 184cb8c474eSBartosz Golaszewski direction = !!test_bit(offset, chip->direction_map); 185cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 186cb8c474eSBartosz Golaszewski 187cb8c474eSBartosz Golaszewski return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; 188cb8c474eSBartosz Golaszewski } 189cb8c474eSBartosz Golaszewski 190cb8c474eSBartosz Golaszewski static int gpio_sim_set_config(struct gpio_chip *gc, 191cb8c474eSBartosz Golaszewski unsigned int offset, unsigned long config) 192cb8c474eSBartosz Golaszewski { 193cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 194cb8c474eSBartosz Golaszewski 195cb8c474eSBartosz Golaszewski switch (pinconf_to_config_param(config)) { 196cb8c474eSBartosz Golaszewski case PIN_CONFIG_BIAS_PULL_UP: 197cb8c474eSBartosz Golaszewski return gpio_sim_apply_pull(chip, offset, 1); 198cb8c474eSBartosz Golaszewski case PIN_CONFIG_BIAS_PULL_DOWN: 199cb8c474eSBartosz Golaszewski return gpio_sim_apply_pull(chip, offset, 0); 200cb8c474eSBartosz Golaszewski default: 201cb8c474eSBartosz Golaszewski break; 202cb8c474eSBartosz Golaszewski } 203cb8c474eSBartosz Golaszewski 204cb8c474eSBartosz Golaszewski return -ENOTSUPP; 205cb8c474eSBartosz Golaszewski } 206cb8c474eSBartosz Golaszewski 207cb8c474eSBartosz Golaszewski static int gpio_sim_to_irq(struct gpio_chip *gc, unsigned int offset) 208cb8c474eSBartosz Golaszewski { 209cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 210cb8c474eSBartosz Golaszewski 211cb8c474eSBartosz Golaszewski return irq_create_mapping(chip->irq_sim, offset); 212cb8c474eSBartosz Golaszewski } 213cb8c474eSBartosz Golaszewski 214cb8c474eSBartosz Golaszewski static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) 215cb8c474eSBartosz Golaszewski { 216cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = gpiochip_get_data(gc); 217cb8c474eSBartosz Golaszewski 218cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 219cb8c474eSBartosz Golaszewski __assign_bit(offset, chip->value_map, !!test_bit(offset, chip->pull_map)); 220cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 221cb8c474eSBartosz Golaszewski } 222cb8c474eSBartosz Golaszewski 223cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_sysfs_val_show(struct device *dev, 224cb8c474eSBartosz Golaszewski struct device_attribute *attr, char *buf) 225cb8c474eSBartosz Golaszewski { 226cb8c474eSBartosz Golaszewski struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(attr); 227cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = dev_get_drvdata(dev); 228cb8c474eSBartosz Golaszewski int val; 229cb8c474eSBartosz Golaszewski 230cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 231cb8c474eSBartosz Golaszewski val = !!test_bit(line_attr->offset, chip->value_map); 232cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 233cb8c474eSBartosz Golaszewski 234cb8c474eSBartosz Golaszewski return sysfs_emit(buf, "%d\n", val); 235cb8c474eSBartosz Golaszewski } 236cb8c474eSBartosz Golaszewski 237cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_sysfs_val_store(struct device *dev, 238cb8c474eSBartosz Golaszewski struct device_attribute *attr, 239cb8c474eSBartosz Golaszewski const char *buf, size_t count) 240cb8c474eSBartosz Golaszewski { 241cb8c474eSBartosz Golaszewski /* 242cb8c474eSBartosz Golaszewski * Not assigning this function will result in write() returning -EIO 243cb8c474eSBartosz Golaszewski * which is confusing. Return -EPERM explicitly. 244cb8c474eSBartosz Golaszewski */ 245cb8c474eSBartosz Golaszewski return -EPERM; 246cb8c474eSBartosz Golaszewski } 247cb8c474eSBartosz Golaszewski 248cb8c474eSBartosz Golaszewski static const char *const gpio_sim_sysfs_pull_strings[] = { 249cb8c474eSBartosz Golaszewski [0] = "pull-down", 250cb8c474eSBartosz Golaszewski [1] = "pull-up", 251cb8c474eSBartosz Golaszewski }; 252cb8c474eSBartosz Golaszewski 253cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_sysfs_pull_show(struct device *dev, 254cb8c474eSBartosz Golaszewski struct device_attribute *attr, 255cb8c474eSBartosz Golaszewski char *buf) 256cb8c474eSBartosz Golaszewski { 257cb8c474eSBartosz Golaszewski struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(attr); 258cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = dev_get_drvdata(dev); 259cb8c474eSBartosz Golaszewski int pull; 260cb8c474eSBartosz Golaszewski 261cb8c474eSBartosz Golaszewski mutex_lock(&chip->lock); 262cb8c474eSBartosz Golaszewski pull = !!test_bit(line_attr->offset, chip->pull_map); 263cb8c474eSBartosz Golaszewski mutex_unlock(&chip->lock); 264cb8c474eSBartosz Golaszewski 265cb8c474eSBartosz Golaszewski return sysfs_emit(buf, "%s\n", gpio_sim_sysfs_pull_strings[pull]); 266cb8c474eSBartosz Golaszewski } 267cb8c474eSBartosz Golaszewski 268cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_sysfs_pull_store(struct device *dev, 269cb8c474eSBartosz Golaszewski struct device_attribute *attr, 270cb8c474eSBartosz Golaszewski const char *buf, size_t len) 271cb8c474eSBartosz Golaszewski { 272cb8c474eSBartosz Golaszewski struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(attr); 273cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = dev_get_drvdata(dev); 274cb8c474eSBartosz Golaszewski int ret, pull; 275cb8c474eSBartosz Golaszewski 276cb8c474eSBartosz Golaszewski pull = sysfs_match_string(gpio_sim_sysfs_pull_strings, buf); 277cb8c474eSBartosz Golaszewski if (pull < 0) 278cb8c474eSBartosz Golaszewski return pull; 279cb8c474eSBartosz Golaszewski 280cb8c474eSBartosz Golaszewski ret = gpio_sim_apply_pull(chip, line_attr->offset, pull); 281cb8c474eSBartosz Golaszewski if (ret) 282cb8c474eSBartosz Golaszewski return ret; 283cb8c474eSBartosz Golaszewski 284cb8c474eSBartosz Golaszewski return len; 285cb8c474eSBartosz Golaszewski } 286cb8c474eSBartosz Golaszewski 287cb8c474eSBartosz Golaszewski static void gpio_sim_mutex_destroy(void *data) 288cb8c474eSBartosz Golaszewski { 289cb8c474eSBartosz Golaszewski struct mutex *lock = data; 290cb8c474eSBartosz Golaszewski 291cb8c474eSBartosz Golaszewski mutex_destroy(lock); 292cb8c474eSBartosz Golaszewski } 293cb8c474eSBartosz Golaszewski 294cb8c474eSBartosz Golaszewski static void gpio_sim_sysfs_remove(void *data) 295cb8c474eSBartosz Golaszewski { 296cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip = data; 297cb8c474eSBartosz Golaszewski 298cb8c474eSBartosz Golaszewski sysfs_remove_groups(&chip->gc.gpiodev->dev.kobj, chip->attr_groups); 299cb8c474eSBartosz Golaszewski } 300cb8c474eSBartosz Golaszewski 301cb8c474eSBartosz Golaszewski static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip) 302cb8c474eSBartosz Golaszewski { 303cb8c474eSBartosz Golaszewski struct device_attribute *val_dev_attr, *pull_dev_attr; 304cb8c474eSBartosz Golaszewski struct gpio_sim_attribute *val_attr, *pull_attr; 305cb8c474eSBartosz Golaszewski unsigned int num_lines = chip->gc.ngpio; 306cb8c474eSBartosz Golaszewski struct device *dev = chip->gc.parent; 307cb8c474eSBartosz Golaszewski struct attribute_group *attr_group; 308cb8c474eSBartosz Golaszewski struct attribute **attrs; 309cb8c474eSBartosz Golaszewski int i, ret; 310cb8c474eSBartosz Golaszewski 311cb8c474eSBartosz Golaszewski chip->attr_groups = devm_kcalloc(dev, sizeof(*chip->attr_groups), 312cb8c474eSBartosz Golaszewski num_lines + 1, GFP_KERNEL); 313cb8c474eSBartosz Golaszewski if (!chip->attr_groups) 314cb8c474eSBartosz Golaszewski return -ENOMEM; 315cb8c474eSBartosz Golaszewski 316cb8c474eSBartosz Golaszewski for (i = 0; i < num_lines; i++) { 317cb8c474eSBartosz Golaszewski attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL); 318c680c6a8SChristophe JAILLET attrs = devm_kcalloc(dev, GPIO_SIM_NUM_ATTRS, sizeof(*attrs), 319c680c6a8SChristophe JAILLET GFP_KERNEL); 320cb8c474eSBartosz Golaszewski val_attr = devm_kzalloc(dev, sizeof(*val_attr), GFP_KERNEL); 321cb8c474eSBartosz Golaszewski pull_attr = devm_kzalloc(dev, sizeof(*pull_attr), GFP_KERNEL); 322cb8c474eSBartosz Golaszewski if (!attr_group || !attrs || !val_attr || !pull_attr) 323cb8c474eSBartosz Golaszewski return -ENOMEM; 324cb8c474eSBartosz Golaszewski 325cb8c474eSBartosz Golaszewski attr_group->name = devm_kasprintf(dev, GFP_KERNEL, 326cb8c474eSBartosz Golaszewski "sim_gpio%u", i); 327cb8c474eSBartosz Golaszewski if (!attr_group->name) 328cb8c474eSBartosz Golaszewski return -ENOMEM; 329cb8c474eSBartosz Golaszewski 330cb8c474eSBartosz Golaszewski val_attr->offset = pull_attr->offset = i; 331cb8c474eSBartosz Golaszewski 332cb8c474eSBartosz Golaszewski val_dev_attr = &val_attr->dev_attr; 333cb8c474eSBartosz Golaszewski pull_dev_attr = &pull_attr->dev_attr; 334cb8c474eSBartosz Golaszewski 335cb8c474eSBartosz Golaszewski sysfs_attr_init(&val_dev_attr->attr); 336cb8c474eSBartosz Golaszewski sysfs_attr_init(&pull_dev_attr->attr); 337cb8c474eSBartosz Golaszewski 338cb8c474eSBartosz Golaszewski val_dev_attr->attr.name = "value"; 339cb8c474eSBartosz Golaszewski pull_dev_attr->attr.name = "pull"; 340cb8c474eSBartosz Golaszewski 341cb8c474eSBartosz Golaszewski val_dev_attr->attr.mode = pull_dev_attr->attr.mode = 0644; 342cb8c474eSBartosz Golaszewski 343cb8c474eSBartosz Golaszewski val_dev_attr->show = gpio_sim_sysfs_val_show; 344cb8c474eSBartosz Golaszewski val_dev_attr->store = gpio_sim_sysfs_val_store; 345cb8c474eSBartosz Golaszewski pull_dev_attr->show = gpio_sim_sysfs_pull_show; 346cb8c474eSBartosz Golaszewski pull_dev_attr->store = gpio_sim_sysfs_pull_store; 347cb8c474eSBartosz Golaszewski 348cb8c474eSBartosz Golaszewski attrs[0] = &val_dev_attr->attr; 349cb8c474eSBartosz Golaszewski attrs[1] = &pull_dev_attr->attr; 350cb8c474eSBartosz Golaszewski 351cb8c474eSBartosz Golaszewski attr_group->attrs = attrs; 352cb8c474eSBartosz Golaszewski chip->attr_groups[i] = attr_group; 353cb8c474eSBartosz Golaszewski } 354cb8c474eSBartosz Golaszewski 355cb8c474eSBartosz Golaszewski ret = sysfs_create_groups(&chip->gc.gpiodev->dev.kobj, 356cb8c474eSBartosz Golaszewski chip->attr_groups); 357cb8c474eSBartosz Golaszewski if (ret) 358cb8c474eSBartosz Golaszewski return ret; 359cb8c474eSBartosz Golaszewski 360cb8c474eSBartosz Golaszewski return devm_add_action_or_reset(dev, gpio_sim_sysfs_remove, chip); 361cb8c474eSBartosz Golaszewski } 362cb8c474eSBartosz Golaszewski 363cb8c474eSBartosz Golaszewski static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) 364cb8c474eSBartosz Golaszewski { 365cb8c474eSBartosz Golaszewski struct gpio_sim_chip *chip; 366cb8c474eSBartosz Golaszewski struct gpio_chip *gc; 367cb8c474eSBartosz Golaszewski const char *label; 368cb8c474eSBartosz Golaszewski u32 num_lines; 369cb8c474eSBartosz Golaszewski int ret; 370cb8c474eSBartosz Golaszewski 371cb8c474eSBartosz Golaszewski ret = fwnode_property_read_u32(swnode, "ngpios", &num_lines); 372cb8c474eSBartosz Golaszewski if (ret) 373cb8c474eSBartosz Golaszewski return ret; 374cb8c474eSBartosz Golaszewski 37511e47bbdSBartosz Golaszewski if (num_lines > GPIO_SIM_NGPIO_MAX) 37611e47bbdSBartosz Golaszewski return -ERANGE; 37711e47bbdSBartosz Golaszewski 378cb8c474eSBartosz Golaszewski ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label); 379cb8c474eSBartosz Golaszewski if (ret) { 3804827aae0SAndy Shevchenko label = devm_kasprintf(dev, GFP_KERNEL, "%s-%pfwP", 3814827aae0SAndy Shevchenko dev_name(dev), swnode); 382cb8c474eSBartosz Golaszewski if (!label) 383cb8c474eSBartosz Golaszewski return -ENOMEM; 384cb8c474eSBartosz Golaszewski } 385cb8c474eSBartosz Golaszewski 386cb8c474eSBartosz Golaszewski chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 387cb8c474eSBartosz Golaszewski if (!chip) 388cb8c474eSBartosz Golaszewski return -ENOMEM; 389cb8c474eSBartosz Golaszewski 390cb8c474eSBartosz Golaszewski chip->direction_map = devm_bitmap_alloc(dev, num_lines, GFP_KERNEL); 391cb8c474eSBartosz Golaszewski if (!chip->direction_map) 392cb8c474eSBartosz Golaszewski return -ENOMEM; 393cb8c474eSBartosz Golaszewski 394cb8c474eSBartosz Golaszewski /* Default to input mode. */ 395cb8c474eSBartosz Golaszewski bitmap_fill(chip->direction_map, num_lines); 396cb8c474eSBartosz Golaszewski 397cb8c474eSBartosz Golaszewski chip->value_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL); 398cb8c474eSBartosz Golaszewski if (!chip->value_map) 399cb8c474eSBartosz Golaszewski return -ENOMEM; 400cb8c474eSBartosz Golaszewski 401cb8c474eSBartosz Golaszewski chip->pull_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL); 402cb8c474eSBartosz Golaszewski if (!chip->pull_map) 403cb8c474eSBartosz Golaszewski return -ENOMEM; 404cb8c474eSBartosz Golaszewski 405cb8c474eSBartosz Golaszewski chip->irq_sim = devm_irq_domain_create_sim(dev, NULL, num_lines); 406cb8c474eSBartosz Golaszewski if (IS_ERR(chip->irq_sim)) 407cb8c474eSBartosz Golaszewski return PTR_ERR(chip->irq_sim); 408cb8c474eSBartosz Golaszewski 409cb8c474eSBartosz Golaszewski mutex_init(&chip->lock); 410cb8c474eSBartosz Golaszewski ret = devm_add_action_or_reset(dev, gpio_sim_mutex_destroy, 411cb8c474eSBartosz Golaszewski &chip->lock); 412cb8c474eSBartosz Golaszewski if (ret) 413cb8c474eSBartosz Golaszewski return ret; 414cb8c474eSBartosz Golaszewski 415cb8c474eSBartosz Golaszewski gc = &chip->gc; 416cb8c474eSBartosz Golaszewski gc->base = -1; 417cb8c474eSBartosz Golaszewski gc->ngpio = num_lines; 418cb8c474eSBartosz Golaszewski gc->label = label; 419cb8c474eSBartosz Golaszewski gc->owner = THIS_MODULE; 420cb8c474eSBartosz Golaszewski gc->parent = dev; 421cb8c474eSBartosz Golaszewski gc->fwnode = swnode; 422cb8c474eSBartosz Golaszewski gc->get = gpio_sim_get; 423cb8c474eSBartosz Golaszewski gc->set = gpio_sim_set; 424cb8c474eSBartosz Golaszewski gc->get_multiple = gpio_sim_get_multiple; 425cb8c474eSBartosz Golaszewski gc->set_multiple = gpio_sim_set_multiple; 426cb8c474eSBartosz Golaszewski gc->direction_output = gpio_sim_direction_output; 427cb8c474eSBartosz Golaszewski gc->direction_input = gpio_sim_direction_input; 428cb8c474eSBartosz Golaszewski gc->get_direction = gpio_sim_get_direction; 429cb8c474eSBartosz Golaszewski gc->set_config = gpio_sim_set_config; 430cb8c474eSBartosz Golaszewski gc->to_irq = gpio_sim_to_irq; 431cb8c474eSBartosz Golaszewski gc->free = gpio_sim_free; 432*5a78d5dbSBartosz Golaszewski gc->can_sleep = true; 433cb8c474eSBartosz Golaszewski 434cb8c474eSBartosz Golaszewski ret = devm_gpiochip_add_data(dev, gc, chip); 435cb8c474eSBartosz Golaszewski if (ret) 436cb8c474eSBartosz Golaszewski return ret; 437cb8c474eSBartosz Golaszewski 438cb8c474eSBartosz Golaszewski /* Used by sysfs and configfs callbacks. */ 439cb8c474eSBartosz Golaszewski dev_set_drvdata(&gc->gpiodev->dev, chip); 440cb8c474eSBartosz Golaszewski 441cb8c474eSBartosz Golaszewski return gpio_sim_setup_sysfs(chip); 442cb8c474eSBartosz Golaszewski } 443cb8c474eSBartosz Golaszewski 444cb8c474eSBartosz Golaszewski static int gpio_sim_probe(struct platform_device *pdev) 445cb8c474eSBartosz Golaszewski { 446cb8c474eSBartosz Golaszewski struct device *dev = &pdev->dev; 447cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 448cb8c474eSBartosz Golaszewski int ret; 449cb8c474eSBartosz Golaszewski 450cb8c474eSBartosz Golaszewski device_for_each_child_node(dev, swnode) { 451cb8c474eSBartosz Golaszewski ret = gpio_sim_add_bank(swnode, dev); 452a2d05fb7SYang Yingliang if (ret) { 453a2d05fb7SYang Yingliang fwnode_handle_put(swnode); 454cb8c474eSBartosz Golaszewski return ret; 455cb8c474eSBartosz Golaszewski } 456a2d05fb7SYang Yingliang } 457cb8c474eSBartosz Golaszewski 458cb8c474eSBartosz Golaszewski return 0; 459cb8c474eSBartosz Golaszewski } 460cb8c474eSBartosz Golaszewski 461cb8c474eSBartosz Golaszewski static const struct of_device_id gpio_sim_of_match[] = { 462cb8c474eSBartosz Golaszewski { .compatible = "gpio-simulator" }, 463cb8c474eSBartosz Golaszewski { } 464cb8c474eSBartosz Golaszewski }; 465cb8c474eSBartosz Golaszewski MODULE_DEVICE_TABLE(of, gpio_sim_of_match); 466cb8c474eSBartosz Golaszewski 467cb8c474eSBartosz Golaszewski static struct platform_driver gpio_sim_driver = { 468cb8c474eSBartosz Golaszewski .driver = { 469cb8c474eSBartosz Golaszewski .name = "gpio-sim", 470cb8c474eSBartosz Golaszewski .of_match_table = gpio_sim_of_match, 471cb8c474eSBartosz Golaszewski }, 472cb8c474eSBartosz Golaszewski .probe = gpio_sim_probe, 473cb8c474eSBartosz Golaszewski }; 474cb8c474eSBartosz Golaszewski 475cb8c474eSBartosz Golaszewski struct gpio_sim_device { 476cb8c474eSBartosz Golaszewski struct config_group group; 477cb8c474eSBartosz Golaszewski 478cb8c474eSBartosz Golaszewski /* 479cb8c474eSBartosz Golaszewski * If pdev is NULL, the device is 'pending' (waiting for configuration). 480cb8c474eSBartosz Golaszewski * Once the pointer is assigned, the device has been created and the 481cb8c474eSBartosz Golaszewski * item is 'live'. 482cb8c474eSBartosz Golaszewski */ 483cb8c474eSBartosz Golaszewski struct platform_device *pdev; 484cb8c474eSBartosz Golaszewski int id; 485cb8c474eSBartosz Golaszewski 486cb8c474eSBartosz Golaszewski /* 487cb8c474eSBartosz Golaszewski * Each configfs filesystem operation is protected with the subsystem 488cb8c474eSBartosz Golaszewski * mutex. Each separate attribute is protected with the buffer mutex. 489cb8c474eSBartosz Golaszewski * This structure however can be modified by callbacks of different 490cb8c474eSBartosz Golaszewski * attributes so we need another lock. 491cb8c474eSBartosz Golaszewski * 492cb8c474eSBartosz Golaszewski * We use this lock fo protecting all data structures owned by this 493cb8c474eSBartosz Golaszewski * object too. 494cb8c474eSBartosz Golaszewski */ 495cb8c474eSBartosz Golaszewski struct mutex lock; 496cb8c474eSBartosz Golaszewski 497cb8c474eSBartosz Golaszewski /* 498cb8c474eSBartosz Golaszewski * This is used to synchronously wait for the driver's probe to complete 499cb8c474eSBartosz Golaszewski * and notify the user-space about any errors. 500cb8c474eSBartosz Golaszewski */ 501cb8c474eSBartosz Golaszewski struct notifier_block bus_notifier; 502cb8c474eSBartosz Golaszewski struct completion probe_completion; 503cb8c474eSBartosz Golaszewski bool driver_bound; 504cb8c474eSBartosz Golaszewski 505cb8c474eSBartosz Golaszewski struct gpiod_hog *hogs; 506cb8c474eSBartosz Golaszewski 507cb8c474eSBartosz Golaszewski struct list_head bank_list; 508cb8c474eSBartosz Golaszewski }; 509cb8c474eSBartosz Golaszewski 510cb8c474eSBartosz Golaszewski /* This is called with dev->lock already taken. */ 511cb8c474eSBartosz Golaszewski static int gpio_sim_bus_notifier_call(struct notifier_block *nb, 512cb8c474eSBartosz Golaszewski unsigned long action, void *data) 513cb8c474eSBartosz Golaszewski { 514cb8c474eSBartosz Golaszewski struct gpio_sim_device *simdev = container_of(nb, 515cb8c474eSBartosz Golaszewski struct gpio_sim_device, 516cb8c474eSBartosz Golaszewski bus_notifier); 517cb8c474eSBartosz Golaszewski struct device *dev = data; 518cb8c474eSBartosz Golaszewski char devname[32]; 519cb8c474eSBartosz Golaszewski 520cb8c474eSBartosz Golaszewski snprintf(devname, sizeof(devname), "gpio-sim.%u", simdev->id); 521cb8c474eSBartosz Golaszewski 522cb8c474eSBartosz Golaszewski if (strcmp(dev_name(dev), devname) == 0) { 523cb8c474eSBartosz Golaszewski if (action == BUS_NOTIFY_BOUND_DRIVER) 524cb8c474eSBartosz Golaszewski simdev->driver_bound = true; 525cb8c474eSBartosz Golaszewski else if (action == BUS_NOTIFY_DRIVER_NOT_BOUND) 526cb8c474eSBartosz Golaszewski simdev->driver_bound = false; 527cb8c474eSBartosz Golaszewski else 528cb8c474eSBartosz Golaszewski return NOTIFY_DONE; 529cb8c474eSBartosz Golaszewski 530cb8c474eSBartosz Golaszewski complete(&simdev->probe_completion); 531cb8c474eSBartosz Golaszewski return NOTIFY_OK; 532cb8c474eSBartosz Golaszewski } 533cb8c474eSBartosz Golaszewski 534cb8c474eSBartosz Golaszewski return NOTIFY_DONE; 535cb8c474eSBartosz Golaszewski } 536cb8c474eSBartosz Golaszewski 537cb8c474eSBartosz Golaszewski static struct gpio_sim_device *to_gpio_sim_device(struct config_item *item) 538cb8c474eSBartosz Golaszewski { 539cb8c474eSBartosz Golaszewski struct config_group *group = to_config_group(item); 540cb8c474eSBartosz Golaszewski 541cb8c474eSBartosz Golaszewski return container_of(group, struct gpio_sim_device, group); 542cb8c474eSBartosz Golaszewski } 543cb8c474eSBartosz Golaszewski 544cb8c474eSBartosz Golaszewski struct gpio_sim_bank { 545cb8c474eSBartosz Golaszewski struct config_group group; 546cb8c474eSBartosz Golaszewski 547cb8c474eSBartosz Golaszewski /* 548cb8c474eSBartosz Golaszewski * We could have used the ci_parent field of the config_item but 549cb8c474eSBartosz Golaszewski * configfs is stupid and calls the item's release callback after 550cb8c474eSBartosz Golaszewski * already having cleared the parent pointer even though the parent 551cb8c474eSBartosz Golaszewski * is guaranteed to survive the child... 552cb8c474eSBartosz Golaszewski * 553cb8c474eSBartosz Golaszewski * So we need to store the pointer to the parent struct here. We can 554cb8c474eSBartosz Golaszewski * dereference it anywhere we need with no checks and no locking as 55555d01c98SBartosz Golaszewski * it's guaranteed to survive the children and protected by configfs 556cb8c474eSBartosz Golaszewski * locks. 557cb8c474eSBartosz Golaszewski * 558cb8c474eSBartosz Golaszewski * Same for other structures. 559cb8c474eSBartosz Golaszewski */ 560cb8c474eSBartosz Golaszewski struct gpio_sim_device *parent; 561cb8c474eSBartosz Golaszewski struct list_head siblings; 562cb8c474eSBartosz Golaszewski 563cb8c474eSBartosz Golaszewski char *label; 564cb8c474eSBartosz Golaszewski unsigned int num_lines; 565cb8c474eSBartosz Golaszewski 566cb8c474eSBartosz Golaszewski struct list_head line_list; 567cb8c474eSBartosz Golaszewski 568cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 569cb8c474eSBartosz Golaszewski }; 570cb8c474eSBartosz Golaszewski 571cb8c474eSBartosz Golaszewski static struct gpio_sim_bank *to_gpio_sim_bank(struct config_item *item) 572cb8c474eSBartosz Golaszewski { 573cb8c474eSBartosz Golaszewski struct config_group *group = to_config_group(item); 574cb8c474eSBartosz Golaszewski 575cb8c474eSBartosz Golaszewski return container_of(group, struct gpio_sim_bank, group); 576cb8c474eSBartosz Golaszewski } 577cb8c474eSBartosz Golaszewski 578c162ca0bSBartosz Golaszewski static bool gpio_sim_bank_has_label(struct gpio_sim_bank *bank) 579c162ca0bSBartosz Golaszewski { 580c162ca0bSBartosz Golaszewski return bank->label && *bank->label; 581c162ca0bSBartosz Golaszewski } 582c162ca0bSBartosz Golaszewski 583cb8c474eSBartosz Golaszewski static struct gpio_sim_device * 584cb8c474eSBartosz Golaszewski gpio_sim_bank_get_device(struct gpio_sim_bank *bank) 585cb8c474eSBartosz Golaszewski { 586cb8c474eSBartosz Golaszewski return bank->parent; 587cb8c474eSBartosz Golaszewski } 588cb8c474eSBartosz Golaszewski 589cb8c474eSBartosz Golaszewski struct gpio_sim_hog; 590cb8c474eSBartosz Golaszewski 591cb8c474eSBartosz Golaszewski struct gpio_sim_line { 592cb8c474eSBartosz Golaszewski struct config_group group; 593cb8c474eSBartosz Golaszewski 594cb8c474eSBartosz Golaszewski struct gpio_sim_bank *parent; 595cb8c474eSBartosz Golaszewski struct list_head siblings; 596cb8c474eSBartosz Golaszewski 597cb8c474eSBartosz Golaszewski unsigned int offset; 598cb8c474eSBartosz Golaszewski char *name; 599cb8c474eSBartosz Golaszewski 600cb8c474eSBartosz Golaszewski /* There can only be one hog per line. */ 601cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog; 602cb8c474eSBartosz Golaszewski }; 603cb8c474eSBartosz Golaszewski 604cb8c474eSBartosz Golaszewski static struct gpio_sim_line *to_gpio_sim_line(struct config_item *item) 605cb8c474eSBartosz Golaszewski { 606cb8c474eSBartosz Golaszewski struct config_group *group = to_config_group(item); 607cb8c474eSBartosz Golaszewski 608cb8c474eSBartosz Golaszewski return container_of(group, struct gpio_sim_line, group); 609cb8c474eSBartosz Golaszewski } 610cb8c474eSBartosz Golaszewski 611cb8c474eSBartosz Golaszewski static struct gpio_sim_device * 612cb8c474eSBartosz Golaszewski gpio_sim_line_get_device(struct gpio_sim_line *line) 613cb8c474eSBartosz Golaszewski { 614cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = line->parent; 615cb8c474eSBartosz Golaszewski 616cb8c474eSBartosz Golaszewski return gpio_sim_bank_get_device(bank); 617cb8c474eSBartosz Golaszewski } 618cb8c474eSBartosz Golaszewski 619cb8c474eSBartosz Golaszewski struct gpio_sim_hog { 620cb8c474eSBartosz Golaszewski struct config_item item; 621cb8c474eSBartosz Golaszewski struct gpio_sim_line *parent; 622cb8c474eSBartosz Golaszewski 623cb8c474eSBartosz Golaszewski char *name; 624cb8c474eSBartosz Golaszewski int dir; 625cb8c474eSBartosz Golaszewski }; 626cb8c474eSBartosz Golaszewski 627cb8c474eSBartosz Golaszewski static struct gpio_sim_hog *to_gpio_sim_hog(struct config_item *item) 628cb8c474eSBartosz Golaszewski { 629cb8c474eSBartosz Golaszewski return container_of(item, struct gpio_sim_hog, item); 630cb8c474eSBartosz Golaszewski } 631cb8c474eSBartosz Golaszewski 632cb8c474eSBartosz Golaszewski static struct gpio_sim_device *gpio_sim_hog_get_device(struct gpio_sim_hog *hog) 633cb8c474eSBartosz Golaszewski { 634cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = hog->parent; 635cb8c474eSBartosz Golaszewski 636cb8c474eSBartosz Golaszewski return gpio_sim_line_get_device(line); 637cb8c474eSBartosz Golaszewski } 638cb8c474eSBartosz Golaszewski 639cb8c474eSBartosz Golaszewski static bool gpio_sim_device_is_live_unlocked(struct gpio_sim_device *dev) 640cb8c474eSBartosz Golaszewski { 641cb8c474eSBartosz Golaszewski return !!dev->pdev; 642cb8c474eSBartosz Golaszewski } 643cb8c474eSBartosz Golaszewski 644cb8c474eSBartosz Golaszewski static char *gpio_sim_strdup_trimmed(const char *str, size_t count) 645cb8c474eSBartosz Golaszewski { 646cb8c474eSBartosz Golaszewski char *dup, *trimmed; 647cb8c474eSBartosz Golaszewski 648cb8c474eSBartosz Golaszewski dup = kstrndup(str, count, GFP_KERNEL); 649cb8c474eSBartosz Golaszewski if (!dup) 650cb8c474eSBartosz Golaszewski return NULL; 651cb8c474eSBartosz Golaszewski 652cb8c474eSBartosz Golaszewski trimmed = strstrip(dup); 653cb8c474eSBartosz Golaszewski memmove(dup, trimmed, strlen(trimmed) + 1); 654cb8c474eSBartosz Golaszewski 655cb8c474eSBartosz Golaszewski return dup; 656cb8c474eSBartosz Golaszewski } 657cb8c474eSBartosz Golaszewski 658cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item, 659cb8c474eSBartosz Golaszewski char *page) 660cb8c474eSBartosz Golaszewski { 661cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 662cb8c474eSBartosz Golaszewski struct platform_device *pdev; 663cb8c474eSBartosz Golaszewski int ret; 664cb8c474eSBartosz Golaszewski 665cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 666cb8c474eSBartosz Golaszewski pdev = dev->pdev; 667cb8c474eSBartosz Golaszewski if (pdev) 668cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", dev_name(&pdev->dev)); 669cb8c474eSBartosz Golaszewski else 670cb8c474eSBartosz Golaszewski ret = sprintf(page, "gpio-sim.%d\n", dev->id); 671cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 672cb8c474eSBartosz Golaszewski 673cb8c474eSBartosz Golaszewski return ret; 674cb8c474eSBartosz Golaszewski } 675cb8c474eSBartosz Golaszewski 676cb8c474eSBartosz Golaszewski CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name); 677cb8c474eSBartosz Golaszewski 678cb8c474eSBartosz Golaszewski static ssize_t 679cb8c474eSBartosz Golaszewski gpio_sim_device_config_live_show(struct config_item *item, char *page) 680cb8c474eSBartosz Golaszewski { 681cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 682cb8c474eSBartosz Golaszewski bool live; 683cb8c474eSBartosz Golaszewski 684cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 685cb8c474eSBartosz Golaszewski live = gpio_sim_device_is_live_unlocked(dev); 686cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 687cb8c474eSBartosz Golaszewski 688cb8c474eSBartosz Golaszewski return sprintf(page, "%c\n", live ? '1' : '0'); 689cb8c474eSBartosz Golaszewski } 690cb8c474eSBartosz Golaszewski 691cb8c474eSBartosz Golaszewski static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank, 692cb8c474eSBartosz Golaszewski unsigned int *line_names_size) 693cb8c474eSBartosz Golaszewski { 694cb8c474eSBartosz Golaszewski unsigned int max_offset = 0; 695cb8c474eSBartosz Golaszewski bool has_line_names = false; 696cb8c474eSBartosz Golaszewski struct gpio_sim_line *line; 697cb8c474eSBartosz Golaszewski char **line_names; 698cb8c474eSBartosz Golaszewski 699cb8c474eSBartosz Golaszewski list_for_each_entry(line, &bank->line_list, siblings) { 700d7459efcSKent Gibson if (line->offset >= bank->num_lines) 701d7459efcSKent Gibson continue; 702d7459efcSKent Gibson 703cb8c474eSBartosz Golaszewski if (line->name) { 704cb8c474eSBartosz Golaszewski if (line->offset > max_offset) 705cb8c474eSBartosz Golaszewski max_offset = line->offset; 706cb8c474eSBartosz Golaszewski 707cb8c474eSBartosz Golaszewski /* 708cb8c474eSBartosz Golaszewski * max_offset can stay at 0 so it's not an indicator 709cb8c474eSBartosz Golaszewski * of whether line names were configured at all. 710cb8c474eSBartosz Golaszewski */ 711cb8c474eSBartosz Golaszewski has_line_names = true; 712cb8c474eSBartosz Golaszewski } 713cb8c474eSBartosz Golaszewski } 714cb8c474eSBartosz Golaszewski 715cb8c474eSBartosz Golaszewski if (!has_line_names) 716cb8c474eSBartosz Golaszewski /* 717cb8c474eSBartosz Golaszewski * This is not an error - NULL means, there are no line 718cb8c474eSBartosz Golaszewski * names configured. 719cb8c474eSBartosz Golaszewski */ 720cb8c474eSBartosz Golaszewski return NULL; 721cb8c474eSBartosz Golaszewski 722cb8c474eSBartosz Golaszewski *line_names_size = max_offset + 1; 723cb8c474eSBartosz Golaszewski 724cb8c474eSBartosz Golaszewski line_names = kcalloc(*line_names_size, sizeof(*line_names), GFP_KERNEL); 725cb8c474eSBartosz Golaszewski if (!line_names) 726cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 727cb8c474eSBartosz Golaszewski 72895ae9979SKent Gibson list_for_each_entry(line, &bank->line_list, siblings) { 729d7459efcSKent Gibson if (line->offset >= bank->num_lines) 730d7459efcSKent Gibson continue; 731d7459efcSKent Gibson 73295ae9979SKent Gibson if (line->name && (line->offset <= max_offset)) 733cb8c474eSBartosz Golaszewski line_names[line->offset] = line->name; 73495ae9979SKent Gibson } 735cb8c474eSBartosz Golaszewski 736cb8c474eSBartosz Golaszewski return line_names; 737cb8c474eSBartosz Golaszewski } 738cb8c474eSBartosz Golaszewski 739cb8c474eSBartosz Golaszewski static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) 740cb8c474eSBartosz Golaszewski { 741cb8c474eSBartosz Golaszewski struct gpiod_hog *hog; 742cb8c474eSBartosz Golaszewski 743cb8c474eSBartosz Golaszewski if (!dev->hogs) 744cb8c474eSBartosz Golaszewski return; 745cb8c474eSBartosz Golaszewski 746cb8c474eSBartosz Golaszewski gpiod_remove_hogs(dev->hogs); 747cb8c474eSBartosz Golaszewski 74879eeab1dSBartosz Golaszewski for (hog = dev->hogs; hog->chip_label; hog++) { 749cb8c474eSBartosz Golaszewski kfree(hog->chip_label); 750cb8c474eSBartosz Golaszewski kfree(hog->line_name); 751cb8c474eSBartosz Golaszewski } 752cb8c474eSBartosz Golaszewski 753cb8c474eSBartosz Golaszewski kfree(dev->hogs); 754cb8c474eSBartosz Golaszewski dev->hogs = NULL; 755cb8c474eSBartosz Golaszewski } 756cb8c474eSBartosz Golaszewski 757cb8c474eSBartosz Golaszewski static int gpio_sim_add_hogs(struct gpio_sim_device *dev) 758cb8c474eSBartosz Golaszewski { 759cb8c474eSBartosz Golaszewski unsigned int num_hogs = 0, idx = 0; 760cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank; 761cb8c474eSBartosz Golaszewski struct gpio_sim_line *line; 762cb8c474eSBartosz Golaszewski struct gpiod_hog *hog; 763cb8c474eSBartosz Golaszewski 764cb8c474eSBartosz Golaszewski list_for_each_entry(bank, &dev->bank_list, siblings) { 765cb8c474eSBartosz Golaszewski list_for_each_entry(line, &bank->line_list, siblings) { 766d7459efcSKent Gibson if (line->offset >= bank->num_lines) 767d7459efcSKent Gibson continue; 768d7459efcSKent Gibson 769cb8c474eSBartosz Golaszewski if (line->hog) 770cb8c474eSBartosz Golaszewski num_hogs++; 771cb8c474eSBartosz Golaszewski } 772cb8c474eSBartosz Golaszewski } 773cb8c474eSBartosz Golaszewski 774cb8c474eSBartosz Golaszewski if (!num_hogs) 775cb8c474eSBartosz Golaszewski return 0; 776cb8c474eSBartosz Golaszewski 777cb8c474eSBartosz Golaszewski /* Allocate one more for the sentinel. */ 778cb8c474eSBartosz Golaszewski dev->hogs = kcalloc(num_hogs + 1, sizeof(*dev->hogs), GFP_KERNEL); 779cb8c474eSBartosz Golaszewski if (!dev->hogs) 780cb8c474eSBartosz Golaszewski return -ENOMEM; 781cb8c474eSBartosz Golaszewski 782cb8c474eSBartosz Golaszewski list_for_each_entry(bank, &dev->bank_list, siblings) { 783cb8c474eSBartosz Golaszewski list_for_each_entry(line, &bank->line_list, siblings) { 784d7459efcSKent Gibson if (line->offset >= bank->num_lines) 785d7459efcSKent Gibson continue; 786d7459efcSKent Gibson 787cb8c474eSBartosz Golaszewski if (!line->hog) 788cb8c474eSBartosz Golaszewski continue; 789cb8c474eSBartosz Golaszewski 790cb8c474eSBartosz Golaszewski hog = &dev->hogs[idx++]; 791cb8c474eSBartosz Golaszewski 792cb8c474eSBartosz Golaszewski /* 793cb8c474eSBartosz Golaszewski * We need to make this string manually because at this 794cb8c474eSBartosz Golaszewski * point the device doesn't exist yet and so dev_name() 795cb8c474eSBartosz Golaszewski * is not available. 796cb8c474eSBartosz Golaszewski */ 797c162ca0bSBartosz Golaszewski if (gpio_sim_bank_has_label(bank)) 798c162ca0bSBartosz Golaszewski hog->chip_label = kstrdup(bank->label, 799c162ca0bSBartosz Golaszewski GFP_KERNEL); 800c162ca0bSBartosz Golaszewski else 801cb8c474eSBartosz Golaszewski hog->chip_label = kasprintf(GFP_KERNEL, 8024827aae0SAndy Shevchenko "gpio-sim.%u-%pfwP", 803c162ca0bSBartosz Golaszewski dev->id, 8044827aae0SAndy Shevchenko bank->swnode); 805cb8c474eSBartosz Golaszewski if (!hog->chip_label) { 806cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 807cb8c474eSBartosz Golaszewski return -ENOMEM; 808cb8c474eSBartosz Golaszewski } 809cb8c474eSBartosz Golaszewski 810cb8c474eSBartosz Golaszewski /* 811cb8c474eSBartosz Golaszewski * We need to duplicate this because the hog config 812cb8c474eSBartosz Golaszewski * item can be removed at any time (and we can't block 813cb8c474eSBartosz Golaszewski * it) and gpiolib doesn't make a deep copy of the hog 814cb8c474eSBartosz Golaszewski * data. 815cb8c474eSBartosz Golaszewski */ 816cb8c474eSBartosz Golaszewski if (line->hog->name) { 817cb8c474eSBartosz Golaszewski hog->line_name = kstrdup(line->hog->name, 818cb8c474eSBartosz Golaszewski GFP_KERNEL); 819cb8c474eSBartosz Golaszewski if (!hog->line_name) { 820cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 821cb8c474eSBartosz Golaszewski return -ENOMEM; 822cb8c474eSBartosz Golaszewski } 823cb8c474eSBartosz Golaszewski } 824cb8c474eSBartosz Golaszewski 825cb8c474eSBartosz Golaszewski hog->chip_hwnum = line->offset; 826cb8c474eSBartosz Golaszewski hog->dflags = line->hog->dir; 827cb8c474eSBartosz Golaszewski } 828cb8c474eSBartosz Golaszewski } 829cb8c474eSBartosz Golaszewski 830cb8c474eSBartosz Golaszewski gpiod_add_hogs(dev->hogs); 831cb8c474eSBartosz Golaszewski 832cb8c474eSBartosz Golaszewski return 0; 833cb8c474eSBartosz Golaszewski } 834cb8c474eSBartosz Golaszewski 835cb8c474eSBartosz Golaszewski static struct fwnode_handle * 836cb8c474eSBartosz Golaszewski gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, 837cb8c474eSBartosz Golaszewski struct fwnode_handle *parent) 838cb8c474eSBartosz Golaszewski { 839cb8c474eSBartosz Golaszewski struct property_entry properties[GPIO_SIM_PROP_MAX]; 840cb8c474eSBartosz Golaszewski unsigned int prop_idx = 0, line_names_size = 0; 841cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 842cb8c474eSBartosz Golaszewski char **line_names; 843cb8c474eSBartosz Golaszewski 844cb8c474eSBartosz Golaszewski memset(properties, 0, sizeof(properties)); 845cb8c474eSBartosz Golaszewski 846cb8c474eSBartosz Golaszewski properties[prop_idx++] = PROPERTY_ENTRY_U32("ngpios", bank->num_lines); 847cb8c474eSBartosz Golaszewski 848c162ca0bSBartosz Golaszewski if (gpio_sim_bank_has_label(bank)) 849cb8c474eSBartosz Golaszewski properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label", 850cb8c474eSBartosz Golaszewski bank->label); 851cb8c474eSBartosz Golaszewski 852cb8c474eSBartosz Golaszewski line_names = gpio_sim_make_line_names(bank, &line_names_size); 853cb8c474eSBartosz Golaszewski if (IS_ERR(line_names)) 854cb8c474eSBartosz Golaszewski return ERR_CAST(line_names); 855cb8c474eSBartosz Golaszewski 856cb8c474eSBartosz Golaszewski if (line_names) 857cb8c474eSBartosz Golaszewski properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN( 858cb8c474eSBartosz Golaszewski "gpio-line-names", 859cb8c474eSBartosz Golaszewski line_names, line_names_size); 860cb8c474eSBartosz Golaszewski 861cb8c474eSBartosz Golaszewski swnode = fwnode_create_software_node(properties, parent); 862cb8c474eSBartosz Golaszewski kfree(line_names); 863cb8c474eSBartosz Golaszewski return swnode; 864cb8c474eSBartosz Golaszewski } 865cb8c474eSBartosz Golaszewski 866cb8c474eSBartosz Golaszewski static void gpio_sim_remove_swnode_recursive(struct fwnode_handle *swnode) 867cb8c474eSBartosz Golaszewski { 868cb8c474eSBartosz Golaszewski struct fwnode_handle *child; 869cb8c474eSBartosz Golaszewski 870cb8c474eSBartosz Golaszewski fwnode_for_each_child_node(swnode, child) 871cb8c474eSBartosz Golaszewski fwnode_remove_software_node(child); 872cb8c474eSBartosz Golaszewski 873cb8c474eSBartosz Golaszewski fwnode_remove_software_node(swnode); 874cb8c474eSBartosz Golaszewski } 875cb8c474eSBartosz Golaszewski 876cb8c474eSBartosz Golaszewski static bool gpio_sim_bank_labels_non_unique(struct gpio_sim_device *dev) 877cb8c474eSBartosz Golaszewski { 878cb8c474eSBartosz Golaszewski struct gpio_sim_bank *this, *pos; 879cb8c474eSBartosz Golaszewski 880cb8c474eSBartosz Golaszewski list_for_each_entry(this, &dev->bank_list, siblings) { 881cb8c474eSBartosz Golaszewski list_for_each_entry(pos, &dev->bank_list, siblings) { 882cb8c474eSBartosz Golaszewski if (this == pos || (!this->label || !pos->label)) 883cb8c474eSBartosz Golaszewski continue; 884cb8c474eSBartosz Golaszewski 885cb8c474eSBartosz Golaszewski if (strcmp(this->label, pos->label) == 0) 886cb8c474eSBartosz Golaszewski return true; 887cb8c474eSBartosz Golaszewski } 888cb8c474eSBartosz Golaszewski } 889cb8c474eSBartosz Golaszewski 890cb8c474eSBartosz Golaszewski return false; 891cb8c474eSBartosz Golaszewski } 892cb8c474eSBartosz Golaszewski 893cb8c474eSBartosz Golaszewski static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev) 894cb8c474eSBartosz Golaszewski { 895cb8c474eSBartosz Golaszewski struct platform_device_info pdevinfo; 896cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 897cb8c474eSBartosz Golaszewski struct platform_device *pdev; 898cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank; 899cb8c474eSBartosz Golaszewski int ret; 900cb8c474eSBartosz Golaszewski 901cb8c474eSBartosz Golaszewski if (list_empty(&dev->bank_list)) 902cb8c474eSBartosz Golaszewski return -ENODATA; 903cb8c474eSBartosz Golaszewski 904cb8c474eSBartosz Golaszewski /* 905cb8c474eSBartosz Golaszewski * Non-unique GPIO device labels are a corner-case we don't support 906cb8c474eSBartosz Golaszewski * as it would interfere with machine hogging mechanism and has little 907cb8c474eSBartosz Golaszewski * use in real life. 908cb8c474eSBartosz Golaszewski */ 909cb8c474eSBartosz Golaszewski if (gpio_sim_bank_labels_non_unique(dev)) 910cb8c474eSBartosz Golaszewski return -EINVAL; 911cb8c474eSBartosz Golaszewski 912cb8c474eSBartosz Golaszewski memset(&pdevinfo, 0, sizeof(pdevinfo)); 913cb8c474eSBartosz Golaszewski 914cb8c474eSBartosz Golaszewski swnode = fwnode_create_software_node(NULL, NULL); 915cb8c474eSBartosz Golaszewski if (IS_ERR(swnode)) 916cb8c474eSBartosz Golaszewski return PTR_ERR(swnode); 917cb8c474eSBartosz Golaszewski 918cb8c474eSBartosz Golaszewski list_for_each_entry(bank, &dev->bank_list, siblings) { 919cb8c474eSBartosz Golaszewski bank->swnode = gpio_sim_make_bank_swnode(bank, swnode); 920c08995bfSTom Rix if (IS_ERR(bank->swnode)) { 921c08995bfSTom Rix ret = PTR_ERR(bank->swnode); 922cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 923cb8c474eSBartosz Golaszewski return ret; 924cb8c474eSBartosz Golaszewski } 925cb8c474eSBartosz Golaszewski } 926cb8c474eSBartosz Golaszewski 927cb8c474eSBartosz Golaszewski ret = gpio_sim_add_hogs(dev); 928cb8c474eSBartosz Golaszewski if (ret) { 929cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 930cb8c474eSBartosz Golaszewski return ret; 931cb8c474eSBartosz Golaszewski } 932cb8c474eSBartosz Golaszewski 933cb8c474eSBartosz Golaszewski pdevinfo.name = "gpio-sim"; 934cb8c474eSBartosz Golaszewski pdevinfo.fwnode = swnode; 935cb8c474eSBartosz Golaszewski pdevinfo.id = dev->id; 936cb8c474eSBartosz Golaszewski 937cb8c474eSBartosz Golaszewski reinit_completion(&dev->probe_completion); 938cb8c474eSBartosz Golaszewski dev->driver_bound = false; 939cb8c474eSBartosz Golaszewski bus_register_notifier(&platform_bus_type, &dev->bus_notifier); 940cb8c474eSBartosz Golaszewski 941cb8c474eSBartosz Golaszewski pdev = platform_device_register_full(&pdevinfo); 942cb8c474eSBartosz Golaszewski if (IS_ERR(pdev)) { 943cb8c474eSBartosz Golaszewski bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); 944cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 945cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 946cb8c474eSBartosz Golaszewski return PTR_ERR(pdev); 947cb8c474eSBartosz Golaszewski } 948cb8c474eSBartosz Golaszewski 949cb8c474eSBartosz Golaszewski wait_for_completion(&dev->probe_completion); 950cb8c474eSBartosz Golaszewski bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); 951cb8c474eSBartosz Golaszewski 952cb8c474eSBartosz Golaszewski if (!dev->driver_bound) { 953cb8c474eSBartosz Golaszewski /* Probe failed, check kernel log. */ 954cb8c474eSBartosz Golaszewski platform_device_unregister(pdev); 955cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 956cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 957cb8c474eSBartosz Golaszewski return -ENXIO; 958cb8c474eSBartosz Golaszewski } 959cb8c474eSBartosz Golaszewski 960cb8c474eSBartosz Golaszewski dev->pdev = pdev; 961cb8c474eSBartosz Golaszewski 962cb8c474eSBartosz Golaszewski return 0; 963cb8c474eSBartosz Golaszewski } 964cb8c474eSBartosz Golaszewski 965cb8c474eSBartosz Golaszewski static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev) 966cb8c474eSBartosz Golaszewski { 967cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 968cb8c474eSBartosz Golaszewski 969cb8c474eSBartosz Golaszewski swnode = dev_fwnode(&dev->pdev->dev); 970cb8c474eSBartosz Golaszewski platform_device_unregister(dev->pdev); 9710c14f3aaSAndy Shevchenko gpio_sim_remove_hogs(dev); 972cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 973cb8c474eSBartosz Golaszewski dev->pdev = NULL; 974cb8c474eSBartosz Golaszewski } 975cb8c474eSBartosz Golaszewski 976cb8c474eSBartosz Golaszewski static ssize_t 977cb8c474eSBartosz Golaszewski gpio_sim_device_config_live_store(struct config_item *item, 978cb8c474eSBartosz Golaszewski const char *page, size_t count) 979cb8c474eSBartosz Golaszewski { 980cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 981cb8c474eSBartosz Golaszewski bool live; 982cb8c474eSBartosz Golaszewski int ret; 983cb8c474eSBartosz Golaszewski 984cb8c474eSBartosz Golaszewski ret = kstrtobool(page, &live); 985cb8c474eSBartosz Golaszewski if (ret) 986cb8c474eSBartosz Golaszewski return ret; 987cb8c474eSBartosz Golaszewski 988cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 989cb8c474eSBartosz Golaszewski 990cb8c474eSBartosz Golaszewski if ((!live && !gpio_sim_device_is_live_unlocked(dev)) || 991cb8c474eSBartosz Golaszewski (live && gpio_sim_device_is_live_unlocked(dev))) 992cb8c474eSBartosz Golaszewski ret = -EPERM; 993cb8c474eSBartosz Golaszewski else if (live) 994cb8c474eSBartosz Golaszewski ret = gpio_sim_device_activate_unlocked(dev); 995cb8c474eSBartosz Golaszewski else 996cb8c474eSBartosz Golaszewski gpio_sim_device_deactivate_unlocked(dev); 997cb8c474eSBartosz Golaszewski 998cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 999cb8c474eSBartosz Golaszewski 1000cb8c474eSBartosz Golaszewski return ret ?: count; 1001cb8c474eSBartosz Golaszewski } 1002cb8c474eSBartosz Golaszewski 1003cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_device_config_, live); 1004cb8c474eSBartosz Golaszewski 1005cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_device_config_attrs[] = { 1006cb8c474eSBartosz Golaszewski &gpio_sim_device_config_attr_dev_name, 1007cb8c474eSBartosz Golaszewski &gpio_sim_device_config_attr_live, 1008cb8c474eSBartosz Golaszewski NULL 1009cb8c474eSBartosz Golaszewski }; 1010cb8c474eSBartosz Golaszewski 1011cb8c474eSBartosz Golaszewski struct gpio_sim_chip_name_ctx { 10127329b071SBartosz Golaszewski struct fwnode_handle *swnode; 1013cb8c474eSBartosz Golaszewski char *page; 1014cb8c474eSBartosz Golaszewski }; 1015cb8c474eSBartosz Golaszewski 1016cb8c474eSBartosz Golaszewski static int gpio_sim_emit_chip_name(struct device *dev, void *data) 1017cb8c474eSBartosz Golaszewski { 1018cb8c474eSBartosz Golaszewski struct gpio_sim_chip_name_ctx *ctx = data; 1019cb8c474eSBartosz Golaszewski 1020cb8c474eSBartosz Golaszewski /* This would be the sysfs device exported in /sys/class/gpio. */ 1021cb8c474eSBartosz Golaszewski if (dev->class) 1022cb8c474eSBartosz Golaszewski return 0; 1023cb8c474eSBartosz Golaszewski 10247329b071SBartosz Golaszewski if (device_match_fwnode(dev, ctx->swnode)) 1025cb8c474eSBartosz Golaszewski return sprintf(ctx->page, "%s\n", dev_name(dev)); 1026cb8c474eSBartosz Golaszewski 10277329b071SBartosz Golaszewski return 0; 1028cb8c474eSBartosz Golaszewski } 1029cb8c474eSBartosz Golaszewski 1030cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item, 1031cb8c474eSBartosz Golaszewski char *page) 1032cb8c474eSBartosz Golaszewski { 1033cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1034cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 10357329b071SBartosz Golaszewski struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page }; 1036cb8c474eSBartosz Golaszewski int ret; 1037cb8c474eSBartosz Golaszewski 1038cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1039cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) 1040cb8c474eSBartosz Golaszewski ret = device_for_each_child(&dev->pdev->dev, &ctx, 1041cb8c474eSBartosz Golaszewski gpio_sim_emit_chip_name); 1042cb8c474eSBartosz Golaszewski else 1043cb8c474eSBartosz Golaszewski ret = sprintf(page, "none\n"); 1044cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1045cb8c474eSBartosz Golaszewski 1046cb8c474eSBartosz Golaszewski return ret; 1047cb8c474eSBartosz Golaszewski } 1048cb8c474eSBartosz Golaszewski 1049cb8c474eSBartosz Golaszewski CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name); 1050cb8c474eSBartosz Golaszewski 1051cb8c474eSBartosz Golaszewski static ssize_t 1052cb8c474eSBartosz Golaszewski gpio_sim_bank_config_label_show(struct config_item *item, char *page) 1053cb8c474eSBartosz Golaszewski { 1054cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1055cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1056cb8c474eSBartosz Golaszewski int ret; 1057cb8c474eSBartosz Golaszewski 1058cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1059cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", bank->label ?: ""); 1060cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1061cb8c474eSBartosz Golaszewski 1062cb8c474eSBartosz Golaszewski return ret; 1063cb8c474eSBartosz Golaszewski } 1064cb8c474eSBartosz Golaszewski 1065cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_bank_config_label_store(struct config_item *item, 1066cb8c474eSBartosz Golaszewski const char *page, size_t count) 1067cb8c474eSBartosz Golaszewski { 1068cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1069cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1070cb8c474eSBartosz Golaszewski char *trimmed; 1071cb8c474eSBartosz Golaszewski 1072cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1073cb8c474eSBartosz Golaszewski 1074cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1075cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1076cb8c474eSBartosz Golaszewski return -EBUSY; 1077cb8c474eSBartosz Golaszewski } 1078cb8c474eSBartosz Golaszewski 1079cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1080cb8c474eSBartosz Golaszewski if (!trimmed) { 1081cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1082cb8c474eSBartosz Golaszewski return -ENOMEM; 1083cb8c474eSBartosz Golaszewski } 1084cb8c474eSBartosz Golaszewski 1085cb8c474eSBartosz Golaszewski kfree(bank->label); 1086cb8c474eSBartosz Golaszewski bank->label = trimmed; 1087cb8c474eSBartosz Golaszewski 1088cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1089cb8c474eSBartosz Golaszewski return count; 1090cb8c474eSBartosz Golaszewski } 1091cb8c474eSBartosz Golaszewski 1092cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_bank_config_, label); 1093cb8c474eSBartosz Golaszewski 1094cb8c474eSBartosz Golaszewski static ssize_t 1095cb8c474eSBartosz Golaszewski gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page) 1096cb8c474eSBartosz Golaszewski { 1097cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1098cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1099cb8c474eSBartosz Golaszewski int ret; 1100cb8c474eSBartosz Golaszewski 1101cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1102cb8c474eSBartosz Golaszewski ret = sprintf(page, "%u\n", bank->num_lines); 1103cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1104cb8c474eSBartosz Golaszewski 1105cb8c474eSBartosz Golaszewski return ret; 1106cb8c474eSBartosz Golaszewski } 1107cb8c474eSBartosz Golaszewski 1108cb8c474eSBartosz Golaszewski static ssize_t 1109cb8c474eSBartosz Golaszewski gpio_sim_bank_config_num_lines_store(struct config_item *item, 1110cb8c474eSBartosz Golaszewski const char *page, size_t count) 1111cb8c474eSBartosz Golaszewski { 1112cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1113cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1114cb8c474eSBartosz Golaszewski unsigned int num_lines; 1115cb8c474eSBartosz Golaszewski int ret; 1116cb8c474eSBartosz Golaszewski 1117cb8c474eSBartosz Golaszewski ret = kstrtouint(page, 0, &num_lines); 1118cb8c474eSBartosz Golaszewski if (ret) 1119cb8c474eSBartosz Golaszewski return ret; 1120cb8c474eSBartosz Golaszewski 1121cb8c474eSBartosz Golaszewski if (num_lines == 0) 1122cb8c474eSBartosz Golaszewski return -EINVAL; 1123cb8c474eSBartosz Golaszewski 1124cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1125cb8c474eSBartosz Golaszewski 1126cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1127cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1128cb8c474eSBartosz Golaszewski return -EBUSY; 1129cb8c474eSBartosz Golaszewski } 1130cb8c474eSBartosz Golaszewski 1131cb8c474eSBartosz Golaszewski bank->num_lines = num_lines; 1132cb8c474eSBartosz Golaszewski 1133cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1134cb8c474eSBartosz Golaszewski return count; 1135cb8c474eSBartosz Golaszewski } 1136cb8c474eSBartosz Golaszewski 1137cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_bank_config_, num_lines); 1138cb8c474eSBartosz Golaszewski 1139cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_bank_config_attrs[] = { 1140cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_attr_chip_name, 1141cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_attr_label, 1142cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_attr_num_lines, 1143cb8c474eSBartosz Golaszewski NULL 1144cb8c474eSBartosz Golaszewski }; 1145cb8c474eSBartosz Golaszewski 1146cb8c474eSBartosz Golaszewski static ssize_t 1147cb8c474eSBartosz Golaszewski gpio_sim_line_config_name_show(struct config_item *item, char *page) 1148cb8c474eSBartosz Golaszewski { 1149cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(item); 1150cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1151cb8c474eSBartosz Golaszewski int ret; 1152cb8c474eSBartosz Golaszewski 1153cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1154cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", line->name ?: ""); 1155cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1156cb8c474eSBartosz Golaszewski 1157cb8c474eSBartosz Golaszewski return ret; 1158cb8c474eSBartosz Golaszewski } 1159cb8c474eSBartosz Golaszewski 1160cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_line_config_name_store(struct config_item *item, 1161cb8c474eSBartosz Golaszewski const char *page, size_t count) 1162cb8c474eSBartosz Golaszewski { 1163cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(item); 1164cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1165cb8c474eSBartosz Golaszewski char *trimmed; 1166cb8c474eSBartosz Golaszewski 1167cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1168cb8c474eSBartosz Golaszewski 1169cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1170cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1171cb8c474eSBartosz Golaszewski return -EBUSY; 1172cb8c474eSBartosz Golaszewski } 1173cb8c474eSBartosz Golaszewski 1174cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1175cb8c474eSBartosz Golaszewski if (!trimmed) { 1176cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1177cb8c474eSBartosz Golaszewski return -ENOMEM; 1178cb8c474eSBartosz Golaszewski } 1179cb8c474eSBartosz Golaszewski 1180cb8c474eSBartosz Golaszewski kfree(line->name); 1181cb8c474eSBartosz Golaszewski line->name = trimmed; 1182cb8c474eSBartosz Golaszewski 1183cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1184cb8c474eSBartosz Golaszewski 1185cb8c474eSBartosz Golaszewski return count; 1186cb8c474eSBartosz Golaszewski } 1187cb8c474eSBartosz Golaszewski 1188cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_line_config_, name); 1189cb8c474eSBartosz Golaszewski 1190cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_line_config_attrs[] = { 1191cb8c474eSBartosz Golaszewski &gpio_sim_line_config_attr_name, 1192cb8c474eSBartosz Golaszewski NULL 1193cb8c474eSBartosz Golaszewski }; 1194cb8c474eSBartosz Golaszewski 1195cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_hog_config_name_show(struct config_item *item, 1196cb8c474eSBartosz Golaszewski char *page) 1197cb8c474eSBartosz Golaszewski { 1198cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1199cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1200cb8c474eSBartosz Golaszewski int ret; 1201cb8c474eSBartosz Golaszewski 1202cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1203cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", hog->name ?: ""); 1204cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1205cb8c474eSBartosz Golaszewski 1206cb8c474eSBartosz Golaszewski return ret; 1207cb8c474eSBartosz Golaszewski } 1208cb8c474eSBartosz Golaszewski 1209cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_hog_config_name_store(struct config_item *item, 1210cb8c474eSBartosz Golaszewski const char *page, size_t count) 1211cb8c474eSBartosz Golaszewski { 1212cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1213cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1214cb8c474eSBartosz Golaszewski char *trimmed; 1215cb8c474eSBartosz Golaszewski 1216cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1217cb8c474eSBartosz Golaszewski 1218cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1219cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1220cb8c474eSBartosz Golaszewski return -EBUSY; 1221cb8c474eSBartosz Golaszewski } 1222cb8c474eSBartosz Golaszewski 1223cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1224cb8c474eSBartosz Golaszewski if (!trimmed) { 1225cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1226cb8c474eSBartosz Golaszewski return -ENOMEM; 1227cb8c474eSBartosz Golaszewski } 1228cb8c474eSBartosz Golaszewski 1229cb8c474eSBartosz Golaszewski kfree(hog->name); 1230cb8c474eSBartosz Golaszewski hog->name = trimmed; 1231cb8c474eSBartosz Golaszewski 1232cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1233cb8c474eSBartosz Golaszewski 1234cb8c474eSBartosz Golaszewski return count; 1235cb8c474eSBartosz Golaszewski } 1236cb8c474eSBartosz Golaszewski 1237cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_hog_config_, name); 1238cb8c474eSBartosz Golaszewski 1239cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item, 1240cb8c474eSBartosz Golaszewski char *page) 1241cb8c474eSBartosz Golaszewski { 1242cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1243cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1244cb8c474eSBartosz Golaszewski char *repr; 1245cb8c474eSBartosz Golaszewski int dir; 1246cb8c474eSBartosz Golaszewski 1247cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1248cb8c474eSBartosz Golaszewski dir = hog->dir; 1249cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1250cb8c474eSBartosz Golaszewski 1251cb8c474eSBartosz Golaszewski switch (dir) { 1252cb8c474eSBartosz Golaszewski case GPIOD_IN: 1253cb8c474eSBartosz Golaszewski repr = "input"; 1254cb8c474eSBartosz Golaszewski break; 1255cb8c474eSBartosz Golaszewski case GPIOD_OUT_HIGH: 1256cb8c474eSBartosz Golaszewski repr = "output-high"; 1257cb8c474eSBartosz Golaszewski break; 1258cb8c474eSBartosz Golaszewski case GPIOD_OUT_LOW: 1259cb8c474eSBartosz Golaszewski repr = "output-low"; 1260cb8c474eSBartosz Golaszewski break; 1261cb8c474eSBartosz Golaszewski default: 1262cb8c474eSBartosz Golaszewski /* This would be a programmer bug. */ 1263cb8c474eSBartosz Golaszewski WARN(1, "Unexpected hog direction value: %d", dir); 1264cb8c474eSBartosz Golaszewski return -EINVAL; 1265cb8c474eSBartosz Golaszewski } 1266cb8c474eSBartosz Golaszewski 1267cb8c474eSBartosz Golaszewski return sprintf(page, "%s\n", repr); 1268cb8c474eSBartosz Golaszewski } 1269cb8c474eSBartosz Golaszewski 1270cb8c474eSBartosz Golaszewski static ssize_t 1271cb8c474eSBartosz Golaszewski gpio_sim_hog_config_direction_store(struct config_item *item, 1272cb8c474eSBartosz Golaszewski const char *page, size_t count) 1273cb8c474eSBartosz Golaszewski { 1274cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1275cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1276cb8c474eSBartosz Golaszewski char *trimmed; 1277cb8c474eSBartosz Golaszewski int dir; 1278cb8c474eSBartosz Golaszewski 1279cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1280cb8c474eSBartosz Golaszewski 1281cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1282cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1283cb8c474eSBartosz Golaszewski return -EBUSY; 1284cb8c474eSBartosz Golaszewski } 1285cb8c474eSBartosz Golaszewski 1286cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1287cb8c474eSBartosz Golaszewski if (!trimmed) { 1288cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1289cb8c474eSBartosz Golaszewski return -ENOMEM; 1290cb8c474eSBartosz Golaszewski } 1291cb8c474eSBartosz Golaszewski 1292cb8c474eSBartosz Golaszewski if (strcmp(trimmed, "input") == 0) 1293cb8c474eSBartosz Golaszewski dir = GPIOD_IN; 1294cb8c474eSBartosz Golaszewski else if (strcmp(trimmed, "output-high") == 0) 1295cb8c474eSBartosz Golaszewski dir = GPIOD_OUT_HIGH; 1296cb8c474eSBartosz Golaszewski else if (strcmp(trimmed, "output-low") == 0) 1297cb8c474eSBartosz Golaszewski dir = GPIOD_OUT_LOW; 1298cb8c474eSBartosz Golaszewski else 1299cb8c474eSBartosz Golaszewski dir = -EINVAL; 1300cb8c474eSBartosz Golaszewski 1301cb8c474eSBartosz Golaszewski kfree(trimmed); 1302cb8c474eSBartosz Golaszewski 1303cb8c474eSBartosz Golaszewski if (dir < 0) { 1304cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1305cb8c474eSBartosz Golaszewski return dir; 1306cb8c474eSBartosz Golaszewski } 1307cb8c474eSBartosz Golaszewski 1308cb8c474eSBartosz Golaszewski hog->dir = dir; 1309cb8c474eSBartosz Golaszewski 1310cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1311cb8c474eSBartosz Golaszewski 1312cb8c474eSBartosz Golaszewski return count; 1313cb8c474eSBartosz Golaszewski } 1314cb8c474eSBartosz Golaszewski 1315cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_hog_config_, direction); 1316cb8c474eSBartosz Golaszewski 1317cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_hog_config_attrs[] = { 1318cb8c474eSBartosz Golaszewski &gpio_sim_hog_config_attr_name, 1319cb8c474eSBartosz Golaszewski &gpio_sim_hog_config_attr_direction, 1320cb8c474eSBartosz Golaszewski NULL 1321cb8c474eSBartosz Golaszewski }; 1322cb8c474eSBartosz Golaszewski 1323cb8c474eSBartosz Golaszewski static void gpio_sim_hog_config_item_release(struct config_item *item) 1324cb8c474eSBartosz Golaszewski { 1325cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1326cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = hog->parent; 1327cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1328cb8c474eSBartosz Golaszewski 1329cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1330cb8c474eSBartosz Golaszewski line->hog = NULL; 1331cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1332cb8c474eSBartosz Golaszewski 1333cb8c474eSBartosz Golaszewski kfree(hog->name); 1334cb8c474eSBartosz Golaszewski kfree(hog); 1335cb8c474eSBartosz Golaszewski } 1336cb8c474eSBartosz Golaszewski 1337a9a5b720SAndy Shevchenko static struct configfs_item_operations gpio_sim_hog_config_item_ops = { 1338cb8c474eSBartosz Golaszewski .release = gpio_sim_hog_config_item_release, 1339cb8c474eSBartosz Golaszewski }; 1340cb8c474eSBartosz Golaszewski 1341cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_hog_config_type = { 1342cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_hog_config_item_ops, 1343cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_hog_config_attrs, 1344cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1345cb8c474eSBartosz Golaszewski }; 1346cb8c474eSBartosz Golaszewski 1347cb8c474eSBartosz Golaszewski static struct config_item * 1348cb8c474eSBartosz Golaszewski gpio_sim_line_config_make_hog_item(struct config_group *group, const char *name) 1349cb8c474eSBartosz Golaszewski { 1350cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(&group->cg_item); 1351cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1352cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog; 1353cb8c474eSBartosz Golaszewski 1354cb8c474eSBartosz Golaszewski if (strcmp(name, "hog") != 0) 1355cb8c474eSBartosz Golaszewski return ERR_PTR(-EINVAL); 1356cb8c474eSBartosz Golaszewski 1357cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1358cb8c474eSBartosz Golaszewski 1359cb8c474eSBartosz Golaszewski hog = kzalloc(sizeof(*hog), GFP_KERNEL); 1360cb8c474eSBartosz Golaszewski if (!hog) { 1361cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1362cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1363cb8c474eSBartosz Golaszewski } 1364cb8c474eSBartosz Golaszewski 1365cb8c474eSBartosz Golaszewski config_item_init_type_name(&hog->item, name, 1366cb8c474eSBartosz Golaszewski &gpio_sim_hog_config_type); 1367cb8c474eSBartosz Golaszewski 1368cb8c474eSBartosz Golaszewski hog->dir = GPIOD_IN; 1369cb8c474eSBartosz Golaszewski hog->name = NULL; 1370cb8c474eSBartosz Golaszewski hog->parent = line; 1371cb8c474eSBartosz Golaszewski line->hog = hog; 1372cb8c474eSBartosz Golaszewski 1373cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1374cb8c474eSBartosz Golaszewski 1375cb8c474eSBartosz Golaszewski return &hog->item; 1376cb8c474eSBartosz Golaszewski } 1377cb8c474eSBartosz Golaszewski 1378cb8c474eSBartosz Golaszewski static void gpio_sim_line_config_group_release(struct config_item *item) 1379cb8c474eSBartosz Golaszewski { 1380cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(item); 1381cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1382cb8c474eSBartosz Golaszewski 1383cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1384cb8c474eSBartosz Golaszewski list_del(&line->siblings); 1385cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1386cb8c474eSBartosz Golaszewski 1387cb8c474eSBartosz Golaszewski kfree(line->name); 1388cb8c474eSBartosz Golaszewski kfree(line); 1389cb8c474eSBartosz Golaszewski } 1390cb8c474eSBartosz Golaszewski 1391cb8c474eSBartosz Golaszewski static struct configfs_item_operations gpio_sim_line_config_item_ops = { 1392cb8c474eSBartosz Golaszewski .release = gpio_sim_line_config_group_release, 1393cb8c474eSBartosz Golaszewski }; 1394cb8c474eSBartosz Golaszewski 1395cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_line_config_group_ops = { 1396cb8c474eSBartosz Golaszewski .make_item = gpio_sim_line_config_make_hog_item, 1397cb8c474eSBartosz Golaszewski }; 1398cb8c474eSBartosz Golaszewski 1399cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_line_config_type = { 1400cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_line_config_item_ops, 1401cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_line_config_group_ops, 1402cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_line_config_attrs, 1403cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1404cb8c474eSBartosz Golaszewski }; 1405cb8c474eSBartosz Golaszewski 1406cb8c474eSBartosz Golaszewski static struct config_group * 1407cb8c474eSBartosz Golaszewski gpio_sim_bank_config_make_line_group(struct config_group *group, 1408cb8c474eSBartosz Golaszewski const char *name) 1409cb8c474eSBartosz Golaszewski { 1410cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(&group->cg_item); 1411cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1412cb8c474eSBartosz Golaszewski struct gpio_sim_line *line; 1413cb8c474eSBartosz Golaszewski unsigned int offset; 1414cb8c474eSBartosz Golaszewski int ret, nchar; 1415cb8c474eSBartosz Golaszewski 1416cb8c474eSBartosz Golaszewski ret = sscanf(name, "line%u%n", &offset, &nchar); 1417cb8c474eSBartosz Golaszewski if (ret != 1 || nchar != strlen(name)) 1418cb8c474eSBartosz Golaszewski return ERR_PTR(-EINVAL); 1419cb8c474eSBartosz Golaszewski 1420cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1421cb8c474eSBartosz Golaszewski 1422cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1423cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1424cb8c474eSBartosz Golaszewski return ERR_PTR(-EBUSY); 1425cb8c474eSBartosz Golaszewski } 1426cb8c474eSBartosz Golaszewski 1427cb8c474eSBartosz Golaszewski line = kzalloc(sizeof(*line), GFP_KERNEL); 1428cb8c474eSBartosz Golaszewski if (!line) { 1429cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1430cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1431cb8c474eSBartosz Golaszewski } 1432cb8c474eSBartosz Golaszewski 1433cb8c474eSBartosz Golaszewski config_group_init_type_name(&line->group, name, 1434cb8c474eSBartosz Golaszewski &gpio_sim_line_config_type); 1435cb8c474eSBartosz Golaszewski 1436cb8c474eSBartosz Golaszewski line->parent = bank; 1437cb8c474eSBartosz Golaszewski line->offset = offset; 1438cb8c474eSBartosz Golaszewski list_add_tail(&line->siblings, &bank->line_list); 1439cb8c474eSBartosz Golaszewski 1440cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1441cb8c474eSBartosz Golaszewski 1442cb8c474eSBartosz Golaszewski return &line->group; 1443cb8c474eSBartosz Golaszewski } 1444cb8c474eSBartosz Golaszewski 1445cb8c474eSBartosz Golaszewski static void gpio_sim_bank_config_group_release(struct config_item *item) 1446cb8c474eSBartosz Golaszewski { 1447cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1448cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1449cb8c474eSBartosz Golaszewski 1450cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1451cb8c474eSBartosz Golaszewski list_del(&bank->siblings); 1452cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1453cb8c474eSBartosz Golaszewski 1454cb8c474eSBartosz Golaszewski kfree(bank->label); 1455cb8c474eSBartosz Golaszewski kfree(bank); 1456cb8c474eSBartosz Golaszewski } 1457cb8c474eSBartosz Golaszewski 1458cb8c474eSBartosz Golaszewski static struct configfs_item_operations gpio_sim_bank_config_item_ops = { 1459cb8c474eSBartosz Golaszewski .release = gpio_sim_bank_config_group_release, 1460cb8c474eSBartosz Golaszewski }; 1461cb8c474eSBartosz Golaszewski 1462cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_bank_config_group_ops = { 1463cb8c474eSBartosz Golaszewski .make_group = gpio_sim_bank_config_make_line_group, 1464cb8c474eSBartosz Golaszewski }; 1465cb8c474eSBartosz Golaszewski 1466cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_bank_config_group_type = { 1467cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_bank_config_item_ops, 1468cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_bank_config_group_ops, 1469cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_bank_config_attrs, 1470cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1471cb8c474eSBartosz Golaszewski }; 1472cb8c474eSBartosz Golaszewski 1473cb8c474eSBartosz Golaszewski static struct config_group * 1474cb8c474eSBartosz Golaszewski gpio_sim_device_config_make_bank_group(struct config_group *group, 1475cb8c474eSBartosz Golaszewski const char *name) 1476cb8c474eSBartosz Golaszewski { 1477cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(&group->cg_item); 1478cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank; 1479cb8c474eSBartosz Golaszewski 1480cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1481cb8c474eSBartosz Golaszewski 1482cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1483cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1484cb8c474eSBartosz Golaszewski return ERR_PTR(-EBUSY); 1485cb8c474eSBartosz Golaszewski } 1486cb8c474eSBartosz Golaszewski 1487cb8c474eSBartosz Golaszewski bank = kzalloc(sizeof(*bank), GFP_KERNEL); 1488cb8c474eSBartosz Golaszewski if (!bank) { 1489cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1490cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1491cb8c474eSBartosz Golaszewski } 1492cb8c474eSBartosz Golaszewski 1493cb8c474eSBartosz Golaszewski config_group_init_type_name(&bank->group, name, 1494cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_group_type); 1495cb8c474eSBartosz Golaszewski bank->num_lines = 1; 1496cb8c474eSBartosz Golaszewski bank->parent = dev; 1497cb8c474eSBartosz Golaszewski INIT_LIST_HEAD(&bank->line_list); 1498cb8c474eSBartosz Golaszewski list_add_tail(&bank->siblings, &dev->bank_list); 1499cb8c474eSBartosz Golaszewski 1500cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1501cb8c474eSBartosz Golaszewski 1502cb8c474eSBartosz Golaszewski return &bank->group; 1503cb8c474eSBartosz Golaszewski } 1504cb8c474eSBartosz Golaszewski 1505cb8c474eSBartosz Golaszewski static void gpio_sim_device_config_group_release(struct config_item *item) 1506cb8c474eSBartosz Golaszewski { 1507cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 1508cb8c474eSBartosz Golaszewski 1509cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1510cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) 1511cb8c474eSBartosz Golaszewski gpio_sim_device_deactivate_unlocked(dev); 1512cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1513cb8c474eSBartosz Golaszewski 1514cb8c474eSBartosz Golaszewski mutex_destroy(&dev->lock); 1515cb8c474eSBartosz Golaszewski ida_free(&gpio_sim_ida, dev->id); 1516cb8c474eSBartosz Golaszewski kfree(dev); 1517cb8c474eSBartosz Golaszewski } 1518cb8c474eSBartosz Golaszewski 1519cb8c474eSBartosz Golaszewski static struct configfs_item_operations gpio_sim_device_config_item_ops = { 1520cb8c474eSBartosz Golaszewski .release = gpio_sim_device_config_group_release, 1521cb8c474eSBartosz Golaszewski }; 1522cb8c474eSBartosz Golaszewski 1523cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_device_config_group_ops = { 1524cb8c474eSBartosz Golaszewski .make_group = gpio_sim_device_config_make_bank_group, 1525cb8c474eSBartosz Golaszewski }; 1526cb8c474eSBartosz Golaszewski 1527cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_device_config_group_type = { 1528cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_device_config_item_ops, 1529cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_device_config_group_ops, 1530cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_device_config_attrs, 1531cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1532cb8c474eSBartosz Golaszewski }; 1533cb8c474eSBartosz Golaszewski 1534cb8c474eSBartosz Golaszewski static struct config_group * 1535cb8c474eSBartosz Golaszewski gpio_sim_config_make_device_group(struct config_group *group, const char *name) 1536cb8c474eSBartosz Golaszewski { 1537cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev; 1538cb8c474eSBartosz Golaszewski int id; 1539cb8c474eSBartosz Golaszewski 1540cb8c474eSBartosz Golaszewski dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1541cb8c474eSBartosz Golaszewski if (!dev) 1542cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1543cb8c474eSBartosz Golaszewski 1544cb8c474eSBartosz Golaszewski id = ida_alloc(&gpio_sim_ida, GFP_KERNEL); 1545cb8c474eSBartosz Golaszewski if (id < 0) { 1546cb8c474eSBartosz Golaszewski kfree(dev); 1547cb8c474eSBartosz Golaszewski return ERR_PTR(id); 1548cb8c474eSBartosz Golaszewski } 1549cb8c474eSBartosz Golaszewski 1550cb8c474eSBartosz Golaszewski config_group_init_type_name(&dev->group, name, 1551cb8c474eSBartosz Golaszewski &gpio_sim_device_config_group_type); 1552cb8c474eSBartosz Golaszewski dev->id = id; 1553cb8c474eSBartosz Golaszewski mutex_init(&dev->lock); 1554cb8c474eSBartosz Golaszewski INIT_LIST_HEAD(&dev->bank_list); 1555cb8c474eSBartosz Golaszewski 1556cb8c474eSBartosz Golaszewski dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call; 1557cb8c474eSBartosz Golaszewski init_completion(&dev->probe_completion); 1558cb8c474eSBartosz Golaszewski 1559cb8c474eSBartosz Golaszewski return &dev->group; 1560cb8c474eSBartosz Golaszewski } 1561cb8c474eSBartosz Golaszewski 1562cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_config_group_ops = { 1563cb8c474eSBartosz Golaszewski .make_group = gpio_sim_config_make_device_group, 1564cb8c474eSBartosz Golaszewski }; 1565cb8c474eSBartosz Golaszewski 1566cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_config_type = { 1567cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_config_group_ops, 1568cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1569cb8c474eSBartosz Golaszewski }; 1570cb8c474eSBartosz Golaszewski 1571cb8c474eSBartosz Golaszewski static struct configfs_subsystem gpio_sim_config_subsys = { 1572cb8c474eSBartosz Golaszewski .su_group = { 1573cb8c474eSBartosz Golaszewski .cg_item = { 1574cb8c474eSBartosz Golaszewski .ci_namebuf = "gpio-sim", 1575cb8c474eSBartosz Golaszewski .ci_type = &gpio_sim_config_type, 1576cb8c474eSBartosz Golaszewski }, 1577cb8c474eSBartosz Golaszewski }, 1578cb8c474eSBartosz Golaszewski }; 1579cb8c474eSBartosz Golaszewski 1580cb8c474eSBartosz Golaszewski static int __init gpio_sim_init(void) 1581cb8c474eSBartosz Golaszewski { 1582cb8c474eSBartosz Golaszewski int ret; 1583cb8c474eSBartosz Golaszewski 1584cb8c474eSBartosz Golaszewski ret = platform_driver_register(&gpio_sim_driver); 1585cb8c474eSBartosz Golaszewski if (ret) { 1586cb8c474eSBartosz Golaszewski pr_err("Error %d while registering the platform driver\n", ret); 1587cb8c474eSBartosz Golaszewski return ret; 1588cb8c474eSBartosz Golaszewski } 1589cb8c474eSBartosz Golaszewski 1590cb8c474eSBartosz Golaszewski config_group_init(&gpio_sim_config_subsys.su_group); 1591cb8c474eSBartosz Golaszewski mutex_init(&gpio_sim_config_subsys.su_mutex); 1592cb8c474eSBartosz Golaszewski ret = configfs_register_subsystem(&gpio_sim_config_subsys); 1593cb8c474eSBartosz Golaszewski if (ret) { 1594cb8c474eSBartosz Golaszewski pr_err("Error %d while registering the configfs subsystem %s\n", 1595cb8c474eSBartosz Golaszewski ret, gpio_sim_config_subsys.su_group.cg_item.ci_namebuf); 1596cb8c474eSBartosz Golaszewski mutex_destroy(&gpio_sim_config_subsys.su_mutex); 1597cb8c474eSBartosz Golaszewski platform_driver_unregister(&gpio_sim_driver); 1598cb8c474eSBartosz Golaszewski return ret; 1599cb8c474eSBartosz Golaszewski } 1600cb8c474eSBartosz Golaszewski 1601cb8c474eSBartosz Golaszewski return 0; 1602cb8c474eSBartosz Golaszewski } 1603cb8c474eSBartosz Golaszewski module_init(gpio_sim_init); 1604cb8c474eSBartosz Golaszewski 1605cb8c474eSBartosz Golaszewski static void __exit gpio_sim_exit(void) 1606cb8c474eSBartosz Golaszewski { 1607cb8c474eSBartosz Golaszewski configfs_unregister_subsystem(&gpio_sim_config_subsys); 1608cb8c474eSBartosz Golaszewski mutex_destroy(&gpio_sim_config_subsys.su_mutex); 1609cb8c474eSBartosz Golaszewski platform_driver_unregister(&gpio_sim_driver); 1610cb8c474eSBartosz Golaszewski } 1611cb8c474eSBartosz Golaszewski module_exit(gpio_sim_exit); 1612cb8c474eSBartosz Golaszewski 1613cb8c474eSBartosz Golaszewski MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl"); 1614cb8c474eSBartosz Golaszewski MODULE_DESCRIPTION("GPIO Simulator Module"); 1615cb8c474eSBartosz Golaszewski MODULE_LICENSE("GPL"); 1616