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; 432cb8c474eSBartosz Golaszewski 433cb8c474eSBartosz Golaszewski ret = devm_gpiochip_add_data(dev, gc, chip); 434cb8c474eSBartosz Golaszewski if (ret) 435cb8c474eSBartosz Golaszewski return ret; 436cb8c474eSBartosz Golaszewski 437cb8c474eSBartosz Golaszewski /* Used by sysfs and configfs callbacks. */ 438cb8c474eSBartosz Golaszewski dev_set_drvdata(&gc->gpiodev->dev, chip); 439cb8c474eSBartosz Golaszewski 440cb8c474eSBartosz Golaszewski return gpio_sim_setup_sysfs(chip); 441cb8c474eSBartosz Golaszewski } 442cb8c474eSBartosz Golaszewski 443cb8c474eSBartosz Golaszewski static int gpio_sim_probe(struct platform_device *pdev) 444cb8c474eSBartosz Golaszewski { 445cb8c474eSBartosz Golaszewski struct device *dev = &pdev->dev; 446cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 447cb8c474eSBartosz Golaszewski int ret; 448cb8c474eSBartosz Golaszewski 449cb8c474eSBartosz Golaszewski device_for_each_child_node(dev, swnode) { 450cb8c474eSBartosz Golaszewski ret = gpio_sim_add_bank(swnode, dev); 451a2d05fb7SYang Yingliang if (ret) { 452a2d05fb7SYang Yingliang fwnode_handle_put(swnode); 453cb8c474eSBartosz Golaszewski return ret; 454cb8c474eSBartosz Golaszewski } 455a2d05fb7SYang Yingliang } 456cb8c474eSBartosz Golaszewski 457cb8c474eSBartosz Golaszewski return 0; 458cb8c474eSBartosz Golaszewski } 459cb8c474eSBartosz Golaszewski 460cb8c474eSBartosz Golaszewski static const struct of_device_id gpio_sim_of_match[] = { 461cb8c474eSBartosz Golaszewski { .compatible = "gpio-simulator" }, 462cb8c474eSBartosz Golaszewski { } 463cb8c474eSBartosz Golaszewski }; 464cb8c474eSBartosz Golaszewski MODULE_DEVICE_TABLE(of, gpio_sim_of_match); 465cb8c474eSBartosz Golaszewski 466cb8c474eSBartosz Golaszewski static struct platform_driver gpio_sim_driver = { 467cb8c474eSBartosz Golaszewski .driver = { 468cb8c474eSBartosz Golaszewski .name = "gpio-sim", 469cb8c474eSBartosz Golaszewski .of_match_table = gpio_sim_of_match, 470cb8c474eSBartosz Golaszewski }, 471cb8c474eSBartosz Golaszewski .probe = gpio_sim_probe, 472cb8c474eSBartosz Golaszewski }; 473cb8c474eSBartosz Golaszewski 474cb8c474eSBartosz Golaszewski struct gpio_sim_device { 475cb8c474eSBartosz Golaszewski struct config_group group; 476cb8c474eSBartosz Golaszewski 477cb8c474eSBartosz Golaszewski /* 478cb8c474eSBartosz Golaszewski * If pdev is NULL, the device is 'pending' (waiting for configuration). 479cb8c474eSBartosz Golaszewski * Once the pointer is assigned, the device has been created and the 480cb8c474eSBartosz Golaszewski * item is 'live'. 481cb8c474eSBartosz Golaszewski */ 482cb8c474eSBartosz Golaszewski struct platform_device *pdev; 483cb8c474eSBartosz Golaszewski int id; 484cb8c474eSBartosz Golaszewski 485cb8c474eSBartosz Golaszewski /* 486cb8c474eSBartosz Golaszewski * Each configfs filesystem operation is protected with the subsystem 487cb8c474eSBartosz Golaszewski * mutex. Each separate attribute is protected with the buffer mutex. 488cb8c474eSBartosz Golaszewski * This structure however can be modified by callbacks of different 489cb8c474eSBartosz Golaszewski * attributes so we need another lock. 490cb8c474eSBartosz Golaszewski * 491*43818a4bSBartosz Golaszewski * We use this lock for protecting all data structures owned by this 492cb8c474eSBartosz Golaszewski * object too. 493cb8c474eSBartosz Golaszewski */ 494cb8c474eSBartosz Golaszewski struct mutex lock; 495cb8c474eSBartosz Golaszewski 496cb8c474eSBartosz Golaszewski /* 497cb8c474eSBartosz Golaszewski * This is used to synchronously wait for the driver's probe to complete 498cb8c474eSBartosz Golaszewski * and notify the user-space about any errors. 499cb8c474eSBartosz Golaszewski */ 500cb8c474eSBartosz Golaszewski struct notifier_block bus_notifier; 501cb8c474eSBartosz Golaszewski struct completion probe_completion; 502cb8c474eSBartosz Golaszewski bool driver_bound; 503cb8c474eSBartosz Golaszewski 504cb8c474eSBartosz Golaszewski struct gpiod_hog *hogs; 505cb8c474eSBartosz Golaszewski 506cb8c474eSBartosz Golaszewski struct list_head bank_list; 507cb8c474eSBartosz Golaszewski }; 508cb8c474eSBartosz Golaszewski 509cb8c474eSBartosz Golaszewski /* This is called with dev->lock already taken. */ 510cb8c474eSBartosz Golaszewski static int gpio_sim_bus_notifier_call(struct notifier_block *nb, 511cb8c474eSBartosz Golaszewski unsigned long action, void *data) 512cb8c474eSBartosz Golaszewski { 513cb8c474eSBartosz Golaszewski struct gpio_sim_device *simdev = container_of(nb, 514cb8c474eSBartosz Golaszewski struct gpio_sim_device, 515cb8c474eSBartosz Golaszewski bus_notifier); 516cb8c474eSBartosz Golaszewski struct device *dev = data; 517cb8c474eSBartosz Golaszewski char devname[32]; 518cb8c474eSBartosz Golaszewski 519cb8c474eSBartosz Golaszewski snprintf(devname, sizeof(devname), "gpio-sim.%u", simdev->id); 520cb8c474eSBartosz Golaszewski 521cb8c474eSBartosz Golaszewski if (strcmp(dev_name(dev), devname) == 0) { 522cb8c474eSBartosz Golaszewski if (action == BUS_NOTIFY_BOUND_DRIVER) 523cb8c474eSBartosz Golaszewski simdev->driver_bound = true; 524cb8c474eSBartosz Golaszewski else if (action == BUS_NOTIFY_DRIVER_NOT_BOUND) 525cb8c474eSBartosz Golaszewski simdev->driver_bound = false; 526cb8c474eSBartosz Golaszewski else 527cb8c474eSBartosz Golaszewski return NOTIFY_DONE; 528cb8c474eSBartosz Golaszewski 529cb8c474eSBartosz Golaszewski complete(&simdev->probe_completion); 530cb8c474eSBartosz Golaszewski return NOTIFY_OK; 531cb8c474eSBartosz Golaszewski } 532cb8c474eSBartosz Golaszewski 533cb8c474eSBartosz Golaszewski return NOTIFY_DONE; 534cb8c474eSBartosz Golaszewski } 535cb8c474eSBartosz Golaszewski 536cb8c474eSBartosz Golaszewski static struct gpio_sim_device *to_gpio_sim_device(struct config_item *item) 537cb8c474eSBartosz Golaszewski { 538cb8c474eSBartosz Golaszewski struct config_group *group = to_config_group(item); 539cb8c474eSBartosz Golaszewski 540cb8c474eSBartosz Golaszewski return container_of(group, struct gpio_sim_device, group); 541cb8c474eSBartosz Golaszewski } 542cb8c474eSBartosz Golaszewski 543cb8c474eSBartosz Golaszewski struct gpio_sim_bank { 544cb8c474eSBartosz Golaszewski struct config_group group; 545cb8c474eSBartosz Golaszewski 546cb8c474eSBartosz Golaszewski /* 547cb8c474eSBartosz Golaszewski * We could have used the ci_parent field of the config_item but 548cb8c474eSBartosz Golaszewski * configfs is stupid and calls the item's release callback after 549cb8c474eSBartosz Golaszewski * already having cleared the parent pointer even though the parent 550cb8c474eSBartosz Golaszewski * is guaranteed to survive the child... 551cb8c474eSBartosz Golaszewski * 552cb8c474eSBartosz Golaszewski * So we need to store the pointer to the parent struct here. We can 553cb8c474eSBartosz Golaszewski * dereference it anywhere we need with no checks and no locking as 55455d01c98SBartosz Golaszewski * it's guaranteed to survive the children and protected by configfs 555cb8c474eSBartosz Golaszewski * locks. 556cb8c474eSBartosz Golaszewski * 557cb8c474eSBartosz Golaszewski * Same for other structures. 558cb8c474eSBartosz Golaszewski */ 559cb8c474eSBartosz Golaszewski struct gpio_sim_device *parent; 560cb8c474eSBartosz Golaszewski struct list_head siblings; 561cb8c474eSBartosz Golaszewski 562cb8c474eSBartosz Golaszewski char *label; 563cb8c474eSBartosz Golaszewski unsigned int num_lines; 564cb8c474eSBartosz Golaszewski 565cb8c474eSBartosz Golaszewski struct list_head line_list; 566cb8c474eSBartosz Golaszewski 567cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 568cb8c474eSBartosz Golaszewski }; 569cb8c474eSBartosz Golaszewski 570cb8c474eSBartosz Golaszewski static struct gpio_sim_bank *to_gpio_sim_bank(struct config_item *item) 571cb8c474eSBartosz Golaszewski { 572cb8c474eSBartosz Golaszewski struct config_group *group = to_config_group(item); 573cb8c474eSBartosz Golaszewski 574cb8c474eSBartosz Golaszewski return container_of(group, struct gpio_sim_bank, group); 575cb8c474eSBartosz Golaszewski } 576cb8c474eSBartosz Golaszewski 577c162ca0bSBartosz Golaszewski static bool gpio_sim_bank_has_label(struct gpio_sim_bank *bank) 578c162ca0bSBartosz Golaszewski { 579c162ca0bSBartosz Golaszewski return bank->label && *bank->label; 580c162ca0bSBartosz Golaszewski } 581c162ca0bSBartosz Golaszewski 582cb8c474eSBartosz Golaszewski static struct gpio_sim_device * 583cb8c474eSBartosz Golaszewski gpio_sim_bank_get_device(struct gpio_sim_bank *bank) 584cb8c474eSBartosz Golaszewski { 585cb8c474eSBartosz Golaszewski return bank->parent; 586cb8c474eSBartosz Golaszewski } 587cb8c474eSBartosz Golaszewski 588cb8c474eSBartosz Golaszewski struct gpio_sim_hog; 589cb8c474eSBartosz Golaszewski 590cb8c474eSBartosz Golaszewski struct gpio_sim_line { 591cb8c474eSBartosz Golaszewski struct config_group group; 592cb8c474eSBartosz Golaszewski 593cb8c474eSBartosz Golaszewski struct gpio_sim_bank *parent; 594cb8c474eSBartosz Golaszewski struct list_head siblings; 595cb8c474eSBartosz Golaszewski 596cb8c474eSBartosz Golaszewski unsigned int offset; 597cb8c474eSBartosz Golaszewski char *name; 598cb8c474eSBartosz Golaszewski 599cb8c474eSBartosz Golaszewski /* There can only be one hog per line. */ 600cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog; 601cb8c474eSBartosz Golaszewski }; 602cb8c474eSBartosz Golaszewski 603cb8c474eSBartosz Golaszewski static struct gpio_sim_line *to_gpio_sim_line(struct config_item *item) 604cb8c474eSBartosz Golaszewski { 605cb8c474eSBartosz Golaszewski struct config_group *group = to_config_group(item); 606cb8c474eSBartosz Golaszewski 607cb8c474eSBartosz Golaszewski return container_of(group, struct gpio_sim_line, group); 608cb8c474eSBartosz Golaszewski } 609cb8c474eSBartosz Golaszewski 610cb8c474eSBartosz Golaszewski static struct gpio_sim_device * 611cb8c474eSBartosz Golaszewski gpio_sim_line_get_device(struct gpio_sim_line *line) 612cb8c474eSBartosz Golaszewski { 613cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = line->parent; 614cb8c474eSBartosz Golaszewski 615cb8c474eSBartosz Golaszewski return gpio_sim_bank_get_device(bank); 616cb8c474eSBartosz Golaszewski } 617cb8c474eSBartosz Golaszewski 618cb8c474eSBartosz Golaszewski struct gpio_sim_hog { 619cb8c474eSBartosz Golaszewski struct config_item item; 620cb8c474eSBartosz Golaszewski struct gpio_sim_line *parent; 621cb8c474eSBartosz Golaszewski 622cb8c474eSBartosz Golaszewski char *name; 623cb8c474eSBartosz Golaszewski int dir; 624cb8c474eSBartosz Golaszewski }; 625cb8c474eSBartosz Golaszewski 626cb8c474eSBartosz Golaszewski static struct gpio_sim_hog *to_gpio_sim_hog(struct config_item *item) 627cb8c474eSBartosz Golaszewski { 628cb8c474eSBartosz Golaszewski return container_of(item, struct gpio_sim_hog, item); 629cb8c474eSBartosz Golaszewski } 630cb8c474eSBartosz Golaszewski 631cb8c474eSBartosz Golaszewski static struct gpio_sim_device *gpio_sim_hog_get_device(struct gpio_sim_hog *hog) 632cb8c474eSBartosz Golaszewski { 633cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = hog->parent; 634cb8c474eSBartosz Golaszewski 635cb8c474eSBartosz Golaszewski return gpio_sim_line_get_device(line); 636cb8c474eSBartosz Golaszewski } 637cb8c474eSBartosz Golaszewski 638cb8c474eSBartosz Golaszewski static bool gpio_sim_device_is_live_unlocked(struct gpio_sim_device *dev) 639cb8c474eSBartosz Golaszewski { 640cb8c474eSBartosz Golaszewski return !!dev->pdev; 641cb8c474eSBartosz Golaszewski } 642cb8c474eSBartosz Golaszewski 643cb8c474eSBartosz Golaszewski static char *gpio_sim_strdup_trimmed(const char *str, size_t count) 644cb8c474eSBartosz Golaszewski { 645cb8c474eSBartosz Golaszewski char *dup, *trimmed; 646cb8c474eSBartosz Golaszewski 647cb8c474eSBartosz Golaszewski dup = kstrndup(str, count, GFP_KERNEL); 648cb8c474eSBartosz Golaszewski if (!dup) 649cb8c474eSBartosz Golaszewski return NULL; 650cb8c474eSBartosz Golaszewski 651cb8c474eSBartosz Golaszewski trimmed = strstrip(dup); 652cb8c474eSBartosz Golaszewski memmove(dup, trimmed, strlen(trimmed) + 1); 653cb8c474eSBartosz Golaszewski 654cb8c474eSBartosz Golaszewski return dup; 655cb8c474eSBartosz Golaszewski } 656cb8c474eSBartosz Golaszewski 657cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item, 658cb8c474eSBartosz Golaszewski char *page) 659cb8c474eSBartosz Golaszewski { 660cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 661cb8c474eSBartosz Golaszewski struct platform_device *pdev; 662cb8c474eSBartosz Golaszewski int ret; 663cb8c474eSBartosz Golaszewski 664cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 665cb8c474eSBartosz Golaszewski pdev = dev->pdev; 666cb8c474eSBartosz Golaszewski if (pdev) 667cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", dev_name(&pdev->dev)); 668cb8c474eSBartosz Golaszewski else 669cb8c474eSBartosz Golaszewski ret = sprintf(page, "gpio-sim.%d\n", dev->id); 670cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 671cb8c474eSBartosz Golaszewski 672cb8c474eSBartosz Golaszewski return ret; 673cb8c474eSBartosz Golaszewski } 674cb8c474eSBartosz Golaszewski 675cb8c474eSBartosz Golaszewski CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name); 676cb8c474eSBartosz Golaszewski 677cb8c474eSBartosz Golaszewski static ssize_t 678cb8c474eSBartosz Golaszewski gpio_sim_device_config_live_show(struct config_item *item, char *page) 679cb8c474eSBartosz Golaszewski { 680cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 681cb8c474eSBartosz Golaszewski bool live; 682cb8c474eSBartosz Golaszewski 683cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 684cb8c474eSBartosz Golaszewski live = gpio_sim_device_is_live_unlocked(dev); 685cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 686cb8c474eSBartosz Golaszewski 687cb8c474eSBartosz Golaszewski return sprintf(page, "%c\n", live ? '1' : '0'); 688cb8c474eSBartosz Golaszewski } 689cb8c474eSBartosz Golaszewski 690cb8c474eSBartosz Golaszewski static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank, 691cb8c474eSBartosz Golaszewski unsigned int *line_names_size) 692cb8c474eSBartosz Golaszewski { 693cb8c474eSBartosz Golaszewski unsigned int max_offset = 0; 694cb8c474eSBartosz Golaszewski bool has_line_names = false; 695cb8c474eSBartosz Golaszewski struct gpio_sim_line *line; 696cb8c474eSBartosz Golaszewski char **line_names; 697cb8c474eSBartosz Golaszewski 698cb8c474eSBartosz Golaszewski list_for_each_entry(line, &bank->line_list, siblings) { 699d7459efcSKent Gibson if (line->offset >= bank->num_lines) 700d7459efcSKent Gibson continue; 701d7459efcSKent Gibson 702cb8c474eSBartosz Golaszewski if (line->name) { 703cb8c474eSBartosz Golaszewski if (line->offset > max_offset) 704cb8c474eSBartosz Golaszewski max_offset = line->offset; 705cb8c474eSBartosz Golaszewski 706cb8c474eSBartosz Golaszewski /* 707cb8c474eSBartosz Golaszewski * max_offset can stay at 0 so it's not an indicator 708cb8c474eSBartosz Golaszewski * of whether line names were configured at all. 709cb8c474eSBartosz Golaszewski */ 710cb8c474eSBartosz Golaszewski has_line_names = true; 711cb8c474eSBartosz Golaszewski } 712cb8c474eSBartosz Golaszewski } 713cb8c474eSBartosz Golaszewski 714cb8c474eSBartosz Golaszewski if (!has_line_names) 715cb8c474eSBartosz Golaszewski /* 716cb8c474eSBartosz Golaszewski * This is not an error - NULL means, there are no line 717cb8c474eSBartosz Golaszewski * names configured. 718cb8c474eSBartosz Golaszewski */ 719cb8c474eSBartosz Golaszewski return NULL; 720cb8c474eSBartosz Golaszewski 721cb8c474eSBartosz Golaszewski *line_names_size = max_offset + 1; 722cb8c474eSBartosz Golaszewski 723cb8c474eSBartosz Golaszewski line_names = kcalloc(*line_names_size, sizeof(*line_names), GFP_KERNEL); 724cb8c474eSBartosz Golaszewski if (!line_names) 725cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 726cb8c474eSBartosz Golaszewski 72795ae9979SKent Gibson list_for_each_entry(line, &bank->line_list, siblings) { 728d7459efcSKent Gibson if (line->offset >= bank->num_lines) 729d7459efcSKent Gibson continue; 730d7459efcSKent Gibson 73195ae9979SKent Gibson if (line->name && (line->offset <= max_offset)) 732cb8c474eSBartosz Golaszewski line_names[line->offset] = line->name; 73395ae9979SKent Gibson } 734cb8c474eSBartosz Golaszewski 735cb8c474eSBartosz Golaszewski return line_names; 736cb8c474eSBartosz Golaszewski } 737cb8c474eSBartosz Golaszewski 738cb8c474eSBartosz Golaszewski static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) 739cb8c474eSBartosz Golaszewski { 740cb8c474eSBartosz Golaszewski struct gpiod_hog *hog; 741cb8c474eSBartosz Golaszewski 742cb8c474eSBartosz Golaszewski if (!dev->hogs) 743cb8c474eSBartosz Golaszewski return; 744cb8c474eSBartosz Golaszewski 745cb8c474eSBartosz Golaszewski gpiod_remove_hogs(dev->hogs); 746cb8c474eSBartosz Golaszewski 74779eeab1dSBartosz Golaszewski for (hog = dev->hogs; hog->chip_label; hog++) { 748cb8c474eSBartosz Golaszewski kfree(hog->chip_label); 749cb8c474eSBartosz Golaszewski kfree(hog->line_name); 750cb8c474eSBartosz Golaszewski } 751cb8c474eSBartosz Golaszewski 752cb8c474eSBartosz Golaszewski kfree(dev->hogs); 753cb8c474eSBartosz Golaszewski dev->hogs = NULL; 754cb8c474eSBartosz Golaszewski } 755cb8c474eSBartosz Golaszewski 756cb8c474eSBartosz Golaszewski static int gpio_sim_add_hogs(struct gpio_sim_device *dev) 757cb8c474eSBartosz Golaszewski { 758cb8c474eSBartosz Golaszewski unsigned int num_hogs = 0, idx = 0; 759cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank; 760cb8c474eSBartosz Golaszewski struct gpio_sim_line *line; 761cb8c474eSBartosz Golaszewski struct gpiod_hog *hog; 762cb8c474eSBartosz Golaszewski 763cb8c474eSBartosz Golaszewski list_for_each_entry(bank, &dev->bank_list, siblings) { 764cb8c474eSBartosz Golaszewski list_for_each_entry(line, &bank->line_list, siblings) { 765d7459efcSKent Gibson if (line->offset >= bank->num_lines) 766d7459efcSKent Gibson continue; 767d7459efcSKent Gibson 768cb8c474eSBartosz Golaszewski if (line->hog) 769cb8c474eSBartosz Golaszewski num_hogs++; 770cb8c474eSBartosz Golaszewski } 771cb8c474eSBartosz Golaszewski } 772cb8c474eSBartosz Golaszewski 773cb8c474eSBartosz Golaszewski if (!num_hogs) 774cb8c474eSBartosz Golaszewski return 0; 775cb8c474eSBartosz Golaszewski 776cb8c474eSBartosz Golaszewski /* Allocate one more for the sentinel. */ 777cb8c474eSBartosz Golaszewski dev->hogs = kcalloc(num_hogs + 1, sizeof(*dev->hogs), GFP_KERNEL); 778cb8c474eSBartosz Golaszewski if (!dev->hogs) 779cb8c474eSBartosz Golaszewski return -ENOMEM; 780cb8c474eSBartosz Golaszewski 781cb8c474eSBartosz Golaszewski list_for_each_entry(bank, &dev->bank_list, siblings) { 782cb8c474eSBartosz Golaszewski list_for_each_entry(line, &bank->line_list, siblings) { 783d7459efcSKent Gibson if (line->offset >= bank->num_lines) 784d7459efcSKent Gibson continue; 785d7459efcSKent Gibson 786cb8c474eSBartosz Golaszewski if (!line->hog) 787cb8c474eSBartosz Golaszewski continue; 788cb8c474eSBartosz Golaszewski 789cb8c474eSBartosz Golaszewski hog = &dev->hogs[idx++]; 790cb8c474eSBartosz Golaszewski 791cb8c474eSBartosz Golaszewski /* 792cb8c474eSBartosz Golaszewski * We need to make this string manually because at this 793cb8c474eSBartosz Golaszewski * point the device doesn't exist yet and so dev_name() 794cb8c474eSBartosz Golaszewski * is not available. 795cb8c474eSBartosz Golaszewski */ 796c162ca0bSBartosz Golaszewski if (gpio_sim_bank_has_label(bank)) 797c162ca0bSBartosz Golaszewski hog->chip_label = kstrdup(bank->label, 798c162ca0bSBartosz Golaszewski GFP_KERNEL); 799c162ca0bSBartosz Golaszewski else 800cb8c474eSBartosz Golaszewski hog->chip_label = kasprintf(GFP_KERNEL, 8014827aae0SAndy Shevchenko "gpio-sim.%u-%pfwP", 802c162ca0bSBartosz Golaszewski dev->id, 8034827aae0SAndy Shevchenko bank->swnode); 804cb8c474eSBartosz Golaszewski if (!hog->chip_label) { 805cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 806cb8c474eSBartosz Golaszewski return -ENOMEM; 807cb8c474eSBartosz Golaszewski } 808cb8c474eSBartosz Golaszewski 809cb8c474eSBartosz Golaszewski /* 810cb8c474eSBartosz Golaszewski * We need to duplicate this because the hog config 811cb8c474eSBartosz Golaszewski * item can be removed at any time (and we can't block 812cb8c474eSBartosz Golaszewski * it) and gpiolib doesn't make a deep copy of the hog 813cb8c474eSBartosz Golaszewski * data. 814cb8c474eSBartosz Golaszewski */ 815cb8c474eSBartosz Golaszewski if (line->hog->name) { 816cb8c474eSBartosz Golaszewski hog->line_name = kstrdup(line->hog->name, 817cb8c474eSBartosz Golaszewski GFP_KERNEL); 818cb8c474eSBartosz Golaszewski if (!hog->line_name) { 819cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 820cb8c474eSBartosz Golaszewski return -ENOMEM; 821cb8c474eSBartosz Golaszewski } 822cb8c474eSBartosz Golaszewski } 823cb8c474eSBartosz Golaszewski 824cb8c474eSBartosz Golaszewski hog->chip_hwnum = line->offset; 825cb8c474eSBartosz Golaszewski hog->dflags = line->hog->dir; 826cb8c474eSBartosz Golaszewski } 827cb8c474eSBartosz Golaszewski } 828cb8c474eSBartosz Golaszewski 829cb8c474eSBartosz Golaszewski gpiod_add_hogs(dev->hogs); 830cb8c474eSBartosz Golaszewski 831cb8c474eSBartosz Golaszewski return 0; 832cb8c474eSBartosz Golaszewski } 833cb8c474eSBartosz Golaszewski 834cb8c474eSBartosz Golaszewski static struct fwnode_handle * 835cb8c474eSBartosz Golaszewski gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, 836cb8c474eSBartosz Golaszewski struct fwnode_handle *parent) 837cb8c474eSBartosz Golaszewski { 838cb8c474eSBartosz Golaszewski struct property_entry properties[GPIO_SIM_PROP_MAX]; 839cb8c474eSBartosz Golaszewski unsigned int prop_idx = 0, line_names_size = 0; 840cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 841cb8c474eSBartosz Golaszewski char **line_names; 842cb8c474eSBartosz Golaszewski 843cb8c474eSBartosz Golaszewski memset(properties, 0, sizeof(properties)); 844cb8c474eSBartosz Golaszewski 845cb8c474eSBartosz Golaszewski properties[prop_idx++] = PROPERTY_ENTRY_U32("ngpios", bank->num_lines); 846cb8c474eSBartosz Golaszewski 847c162ca0bSBartosz Golaszewski if (gpio_sim_bank_has_label(bank)) 848cb8c474eSBartosz Golaszewski properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label", 849cb8c474eSBartosz Golaszewski bank->label); 850cb8c474eSBartosz Golaszewski 851cb8c474eSBartosz Golaszewski line_names = gpio_sim_make_line_names(bank, &line_names_size); 852cb8c474eSBartosz Golaszewski if (IS_ERR(line_names)) 853cb8c474eSBartosz Golaszewski return ERR_CAST(line_names); 854cb8c474eSBartosz Golaszewski 855cb8c474eSBartosz Golaszewski if (line_names) 856cb8c474eSBartosz Golaszewski properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN( 857cb8c474eSBartosz Golaszewski "gpio-line-names", 858cb8c474eSBartosz Golaszewski line_names, line_names_size); 859cb8c474eSBartosz Golaszewski 860cb8c474eSBartosz Golaszewski swnode = fwnode_create_software_node(properties, parent); 861cb8c474eSBartosz Golaszewski kfree(line_names); 862cb8c474eSBartosz Golaszewski return swnode; 863cb8c474eSBartosz Golaszewski } 864cb8c474eSBartosz Golaszewski 865cb8c474eSBartosz Golaszewski static void gpio_sim_remove_swnode_recursive(struct fwnode_handle *swnode) 866cb8c474eSBartosz Golaszewski { 867cb8c474eSBartosz Golaszewski struct fwnode_handle *child; 868cb8c474eSBartosz Golaszewski 869cb8c474eSBartosz Golaszewski fwnode_for_each_child_node(swnode, child) 870cb8c474eSBartosz Golaszewski fwnode_remove_software_node(child); 871cb8c474eSBartosz Golaszewski 872cb8c474eSBartosz Golaszewski fwnode_remove_software_node(swnode); 873cb8c474eSBartosz Golaszewski } 874cb8c474eSBartosz Golaszewski 875cb8c474eSBartosz Golaszewski static bool gpio_sim_bank_labels_non_unique(struct gpio_sim_device *dev) 876cb8c474eSBartosz Golaszewski { 877cb8c474eSBartosz Golaszewski struct gpio_sim_bank *this, *pos; 878cb8c474eSBartosz Golaszewski 879cb8c474eSBartosz Golaszewski list_for_each_entry(this, &dev->bank_list, siblings) { 880cb8c474eSBartosz Golaszewski list_for_each_entry(pos, &dev->bank_list, siblings) { 881cb8c474eSBartosz Golaszewski if (this == pos || (!this->label || !pos->label)) 882cb8c474eSBartosz Golaszewski continue; 883cb8c474eSBartosz Golaszewski 884cb8c474eSBartosz Golaszewski if (strcmp(this->label, pos->label) == 0) 885cb8c474eSBartosz Golaszewski return true; 886cb8c474eSBartosz Golaszewski } 887cb8c474eSBartosz Golaszewski } 888cb8c474eSBartosz Golaszewski 889cb8c474eSBartosz Golaszewski return false; 890cb8c474eSBartosz Golaszewski } 891cb8c474eSBartosz Golaszewski 892cb8c474eSBartosz Golaszewski static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev) 893cb8c474eSBartosz Golaszewski { 894cb8c474eSBartosz Golaszewski struct platform_device_info pdevinfo; 895cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 896cb8c474eSBartosz Golaszewski struct platform_device *pdev; 897cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank; 898cb8c474eSBartosz Golaszewski int ret; 899cb8c474eSBartosz Golaszewski 900cb8c474eSBartosz Golaszewski if (list_empty(&dev->bank_list)) 901cb8c474eSBartosz Golaszewski return -ENODATA; 902cb8c474eSBartosz Golaszewski 903cb8c474eSBartosz Golaszewski /* 904cb8c474eSBartosz Golaszewski * Non-unique GPIO device labels are a corner-case we don't support 905cb8c474eSBartosz Golaszewski * as it would interfere with machine hogging mechanism and has little 906cb8c474eSBartosz Golaszewski * use in real life. 907cb8c474eSBartosz Golaszewski */ 908cb8c474eSBartosz Golaszewski if (gpio_sim_bank_labels_non_unique(dev)) 909cb8c474eSBartosz Golaszewski return -EINVAL; 910cb8c474eSBartosz Golaszewski 911cb8c474eSBartosz Golaszewski memset(&pdevinfo, 0, sizeof(pdevinfo)); 912cb8c474eSBartosz Golaszewski 913cb8c474eSBartosz Golaszewski swnode = fwnode_create_software_node(NULL, NULL); 914cb8c474eSBartosz Golaszewski if (IS_ERR(swnode)) 915cb8c474eSBartosz Golaszewski return PTR_ERR(swnode); 916cb8c474eSBartosz Golaszewski 917cb8c474eSBartosz Golaszewski list_for_each_entry(bank, &dev->bank_list, siblings) { 918cb8c474eSBartosz Golaszewski bank->swnode = gpio_sim_make_bank_swnode(bank, swnode); 919c08995bfSTom Rix if (IS_ERR(bank->swnode)) { 920c08995bfSTom Rix ret = PTR_ERR(bank->swnode); 921cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 922cb8c474eSBartosz Golaszewski return ret; 923cb8c474eSBartosz Golaszewski } 924cb8c474eSBartosz Golaszewski } 925cb8c474eSBartosz Golaszewski 926cb8c474eSBartosz Golaszewski ret = gpio_sim_add_hogs(dev); 927cb8c474eSBartosz Golaszewski if (ret) { 928cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 929cb8c474eSBartosz Golaszewski return ret; 930cb8c474eSBartosz Golaszewski } 931cb8c474eSBartosz Golaszewski 932cb8c474eSBartosz Golaszewski pdevinfo.name = "gpio-sim"; 933cb8c474eSBartosz Golaszewski pdevinfo.fwnode = swnode; 934cb8c474eSBartosz Golaszewski pdevinfo.id = dev->id; 935cb8c474eSBartosz Golaszewski 936cb8c474eSBartosz Golaszewski reinit_completion(&dev->probe_completion); 937cb8c474eSBartosz Golaszewski dev->driver_bound = false; 938cb8c474eSBartosz Golaszewski bus_register_notifier(&platform_bus_type, &dev->bus_notifier); 939cb8c474eSBartosz Golaszewski 940cb8c474eSBartosz Golaszewski pdev = platform_device_register_full(&pdevinfo); 941cb8c474eSBartosz Golaszewski if (IS_ERR(pdev)) { 942cb8c474eSBartosz Golaszewski bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); 943cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 944cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 945cb8c474eSBartosz Golaszewski return PTR_ERR(pdev); 946cb8c474eSBartosz Golaszewski } 947cb8c474eSBartosz Golaszewski 948cb8c474eSBartosz Golaszewski wait_for_completion(&dev->probe_completion); 949cb8c474eSBartosz Golaszewski bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); 950cb8c474eSBartosz Golaszewski 951cb8c474eSBartosz Golaszewski if (!dev->driver_bound) { 952cb8c474eSBartosz Golaszewski /* Probe failed, check kernel log. */ 953cb8c474eSBartosz Golaszewski platform_device_unregister(pdev); 954cb8c474eSBartosz Golaszewski gpio_sim_remove_hogs(dev); 955cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 956cb8c474eSBartosz Golaszewski return -ENXIO; 957cb8c474eSBartosz Golaszewski } 958cb8c474eSBartosz Golaszewski 959cb8c474eSBartosz Golaszewski dev->pdev = pdev; 960cb8c474eSBartosz Golaszewski 961cb8c474eSBartosz Golaszewski return 0; 962cb8c474eSBartosz Golaszewski } 963cb8c474eSBartosz Golaszewski 964cb8c474eSBartosz Golaszewski static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev) 965cb8c474eSBartosz Golaszewski { 966cb8c474eSBartosz Golaszewski struct fwnode_handle *swnode; 967cb8c474eSBartosz Golaszewski 968cb8c474eSBartosz Golaszewski swnode = dev_fwnode(&dev->pdev->dev); 969cb8c474eSBartosz Golaszewski platform_device_unregister(dev->pdev); 9700c14f3aaSAndy Shevchenko gpio_sim_remove_hogs(dev); 971cb8c474eSBartosz Golaszewski gpio_sim_remove_swnode_recursive(swnode); 972cb8c474eSBartosz Golaszewski dev->pdev = NULL; 973cb8c474eSBartosz Golaszewski } 974cb8c474eSBartosz Golaszewski 975cb8c474eSBartosz Golaszewski static ssize_t 976cb8c474eSBartosz Golaszewski gpio_sim_device_config_live_store(struct config_item *item, 977cb8c474eSBartosz Golaszewski const char *page, size_t count) 978cb8c474eSBartosz Golaszewski { 979cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 980cb8c474eSBartosz Golaszewski bool live; 981cb8c474eSBartosz Golaszewski int ret; 982cb8c474eSBartosz Golaszewski 983cb8c474eSBartosz Golaszewski ret = kstrtobool(page, &live); 984cb8c474eSBartosz Golaszewski if (ret) 985cb8c474eSBartosz Golaszewski return ret; 986cb8c474eSBartosz Golaszewski 987cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 988cb8c474eSBartosz Golaszewski 989cb8c474eSBartosz Golaszewski if ((!live && !gpio_sim_device_is_live_unlocked(dev)) || 990cb8c474eSBartosz Golaszewski (live && gpio_sim_device_is_live_unlocked(dev))) 991cb8c474eSBartosz Golaszewski ret = -EPERM; 992cb8c474eSBartosz Golaszewski else if (live) 993cb8c474eSBartosz Golaszewski ret = gpio_sim_device_activate_unlocked(dev); 994cb8c474eSBartosz Golaszewski else 995cb8c474eSBartosz Golaszewski gpio_sim_device_deactivate_unlocked(dev); 996cb8c474eSBartosz Golaszewski 997cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 998cb8c474eSBartosz Golaszewski 999cb8c474eSBartosz Golaszewski return ret ?: count; 1000cb8c474eSBartosz Golaszewski } 1001cb8c474eSBartosz Golaszewski 1002cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_device_config_, live); 1003cb8c474eSBartosz Golaszewski 1004cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_device_config_attrs[] = { 1005cb8c474eSBartosz Golaszewski &gpio_sim_device_config_attr_dev_name, 1006cb8c474eSBartosz Golaszewski &gpio_sim_device_config_attr_live, 1007cb8c474eSBartosz Golaszewski NULL 1008cb8c474eSBartosz Golaszewski }; 1009cb8c474eSBartosz Golaszewski 1010cb8c474eSBartosz Golaszewski struct gpio_sim_chip_name_ctx { 10117329b071SBartosz Golaszewski struct fwnode_handle *swnode; 1012cb8c474eSBartosz Golaszewski char *page; 1013cb8c474eSBartosz Golaszewski }; 1014cb8c474eSBartosz Golaszewski 1015cb8c474eSBartosz Golaszewski static int gpio_sim_emit_chip_name(struct device *dev, void *data) 1016cb8c474eSBartosz Golaszewski { 1017cb8c474eSBartosz Golaszewski struct gpio_sim_chip_name_ctx *ctx = data; 1018cb8c474eSBartosz Golaszewski 1019cb8c474eSBartosz Golaszewski /* This would be the sysfs device exported in /sys/class/gpio. */ 1020cb8c474eSBartosz Golaszewski if (dev->class) 1021cb8c474eSBartosz Golaszewski return 0; 1022cb8c474eSBartosz Golaszewski 10237329b071SBartosz Golaszewski if (device_match_fwnode(dev, ctx->swnode)) 1024cb8c474eSBartosz Golaszewski return sprintf(ctx->page, "%s\n", dev_name(dev)); 1025cb8c474eSBartosz Golaszewski 10267329b071SBartosz Golaszewski return 0; 1027cb8c474eSBartosz Golaszewski } 1028cb8c474eSBartosz Golaszewski 1029cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item, 1030cb8c474eSBartosz Golaszewski char *page) 1031cb8c474eSBartosz Golaszewski { 1032cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1033cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 10347329b071SBartosz Golaszewski struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page }; 1035cb8c474eSBartosz Golaszewski int ret; 1036cb8c474eSBartosz Golaszewski 1037cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1038cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) 1039cb8c474eSBartosz Golaszewski ret = device_for_each_child(&dev->pdev->dev, &ctx, 1040cb8c474eSBartosz Golaszewski gpio_sim_emit_chip_name); 1041cb8c474eSBartosz Golaszewski else 1042cb8c474eSBartosz Golaszewski ret = sprintf(page, "none\n"); 1043cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1044cb8c474eSBartosz Golaszewski 1045cb8c474eSBartosz Golaszewski return ret; 1046cb8c474eSBartosz Golaszewski } 1047cb8c474eSBartosz Golaszewski 1048cb8c474eSBartosz Golaszewski CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name); 1049cb8c474eSBartosz Golaszewski 1050cb8c474eSBartosz Golaszewski static ssize_t 1051cb8c474eSBartosz Golaszewski gpio_sim_bank_config_label_show(struct config_item *item, char *page) 1052cb8c474eSBartosz Golaszewski { 1053cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1054cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1055cb8c474eSBartosz Golaszewski int ret; 1056cb8c474eSBartosz Golaszewski 1057cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1058cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", bank->label ?: ""); 1059cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1060cb8c474eSBartosz Golaszewski 1061cb8c474eSBartosz Golaszewski return ret; 1062cb8c474eSBartosz Golaszewski } 1063cb8c474eSBartosz Golaszewski 1064cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_bank_config_label_store(struct config_item *item, 1065cb8c474eSBartosz Golaszewski const char *page, size_t count) 1066cb8c474eSBartosz Golaszewski { 1067cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1068cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1069cb8c474eSBartosz Golaszewski char *trimmed; 1070cb8c474eSBartosz Golaszewski 1071cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1072cb8c474eSBartosz Golaszewski 1073cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1074cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1075cb8c474eSBartosz Golaszewski return -EBUSY; 1076cb8c474eSBartosz Golaszewski } 1077cb8c474eSBartosz Golaszewski 1078cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1079cb8c474eSBartosz Golaszewski if (!trimmed) { 1080cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1081cb8c474eSBartosz Golaszewski return -ENOMEM; 1082cb8c474eSBartosz Golaszewski } 1083cb8c474eSBartosz Golaszewski 1084cb8c474eSBartosz Golaszewski kfree(bank->label); 1085cb8c474eSBartosz Golaszewski bank->label = trimmed; 1086cb8c474eSBartosz Golaszewski 1087cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1088cb8c474eSBartosz Golaszewski return count; 1089cb8c474eSBartosz Golaszewski } 1090cb8c474eSBartosz Golaszewski 1091cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_bank_config_, label); 1092cb8c474eSBartosz Golaszewski 1093cb8c474eSBartosz Golaszewski static ssize_t 1094cb8c474eSBartosz Golaszewski gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page) 1095cb8c474eSBartosz Golaszewski { 1096cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1097cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1098cb8c474eSBartosz Golaszewski int ret; 1099cb8c474eSBartosz Golaszewski 1100cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1101cb8c474eSBartosz Golaszewski ret = sprintf(page, "%u\n", bank->num_lines); 1102cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1103cb8c474eSBartosz Golaszewski 1104cb8c474eSBartosz Golaszewski return ret; 1105cb8c474eSBartosz Golaszewski } 1106cb8c474eSBartosz Golaszewski 1107cb8c474eSBartosz Golaszewski static ssize_t 1108cb8c474eSBartosz Golaszewski gpio_sim_bank_config_num_lines_store(struct config_item *item, 1109cb8c474eSBartosz Golaszewski const char *page, size_t count) 1110cb8c474eSBartosz Golaszewski { 1111cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1112cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1113cb8c474eSBartosz Golaszewski unsigned int num_lines; 1114cb8c474eSBartosz Golaszewski int ret; 1115cb8c474eSBartosz Golaszewski 1116cb8c474eSBartosz Golaszewski ret = kstrtouint(page, 0, &num_lines); 1117cb8c474eSBartosz Golaszewski if (ret) 1118cb8c474eSBartosz Golaszewski return ret; 1119cb8c474eSBartosz Golaszewski 1120cb8c474eSBartosz Golaszewski if (num_lines == 0) 1121cb8c474eSBartosz Golaszewski return -EINVAL; 1122cb8c474eSBartosz Golaszewski 1123cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1124cb8c474eSBartosz Golaszewski 1125cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1126cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1127cb8c474eSBartosz Golaszewski return -EBUSY; 1128cb8c474eSBartosz Golaszewski } 1129cb8c474eSBartosz Golaszewski 1130cb8c474eSBartosz Golaszewski bank->num_lines = num_lines; 1131cb8c474eSBartosz Golaszewski 1132cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1133cb8c474eSBartosz Golaszewski return count; 1134cb8c474eSBartosz Golaszewski } 1135cb8c474eSBartosz Golaszewski 1136cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_bank_config_, num_lines); 1137cb8c474eSBartosz Golaszewski 1138cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_bank_config_attrs[] = { 1139cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_attr_chip_name, 1140cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_attr_label, 1141cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_attr_num_lines, 1142cb8c474eSBartosz Golaszewski NULL 1143cb8c474eSBartosz Golaszewski }; 1144cb8c474eSBartosz Golaszewski 1145cb8c474eSBartosz Golaszewski static ssize_t 1146cb8c474eSBartosz Golaszewski gpio_sim_line_config_name_show(struct config_item *item, char *page) 1147cb8c474eSBartosz Golaszewski { 1148cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(item); 1149cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1150cb8c474eSBartosz Golaszewski int ret; 1151cb8c474eSBartosz Golaszewski 1152cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1153cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", line->name ?: ""); 1154cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1155cb8c474eSBartosz Golaszewski 1156cb8c474eSBartosz Golaszewski return ret; 1157cb8c474eSBartosz Golaszewski } 1158cb8c474eSBartosz Golaszewski 1159cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_line_config_name_store(struct config_item *item, 1160cb8c474eSBartosz Golaszewski const char *page, size_t count) 1161cb8c474eSBartosz Golaszewski { 1162cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(item); 1163cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1164cb8c474eSBartosz Golaszewski char *trimmed; 1165cb8c474eSBartosz Golaszewski 1166cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1167cb8c474eSBartosz Golaszewski 1168cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1169cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1170cb8c474eSBartosz Golaszewski return -EBUSY; 1171cb8c474eSBartosz Golaszewski } 1172cb8c474eSBartosz Golaszewski 1173cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1174cb8c474eSBartosz Golaszewski if (!trimmed) { 1175cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1176cb8c474eSBartosz Golaszewski return -ENOMEM; 1177cb8c474eSBartosz Golaszewski } 1178cb8c474eSBartosz Golaszewski 1179cb8c474eSBartosz Golaszewski kfree(line->name); 1180cb8c474eSBartosz Golaszewski line->name = trimmed; 1181cb8c474eSBartosz Golaszewski 1182cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1183cb8c474eSBartosz Golaszewski 1184cb8c474eSBartosz Golaszewski return count; 1185cb8c474eSBartosz Golaszewski } 1186cb8c474eSBartosz Golaszewski 1187cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_line_config_, name); 1188cb8c474eSBartosz Golaszewski 1189cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_line_config_attrs[] = { 1190cb8c474eSBartosz Golaszewski &gpio_sim_line_config_attr_name, 1191cb8c474eSBartosz Golaszewski NULL 1192cb8c474eSBartosz Golaszewski }; 1193cb8c474eSBartosz Golaszewski 1194cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_hog_config_name_show(struct config_item *item, 1195cb8c474eSBartosz Golaszewski char *page) 1196cb8c474eSBartosz Golaszewski { 1197cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1198cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1199cb8c474eSBartosz Golaszewski int ret; 1200cb8c474eSBartosz Golaszewski 1201cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1202cb8c474eSBartosz Golaszewski ret = sprintf(page, "%s\n", hog->name ?: ""); 1203cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1204cb8c474eSBartosz Golaszewski 1205cb8c474eSBartosz Golaszewski return ret; 1206cb8c474eSBartosz Golaszewski } 1207cb8c474eSBartosz Golaszewski 1208cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_hog_config_name_store(struct config_item *item, 1209cb8c474eSBartosz Golaszewski const char *page, size_t count) 1210cb8c474eSBartosz Golaszewski { 1211cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1212cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1213cb8c474eSBartosz Golaszewski char *trimmed; 1214cb8c474eSBartosz Golaszewski 1215cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1216cb8c474eSBartosz Golaszewski 1217cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1218cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1219cb8c474eSBartosz Golaszewski return -EBUSY; 1220cb8c474eSBartosz Golaszewski } 1221cb8c474eSBartosz Golaszewski 1222cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1223cb8c474eSBartosz Golaszewski if (!trimmed) { 1224cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1225cb8c474eSBartosz Golaszewski return -ENOMEM; 1226cb8c474eSBartosz Golaszewski } 1227cb8c474eSBartosz Golaszewski 1228cb8c474eSBartosz Golaszewski kfree(hog->name); 1229cb8c474eSBartosz Golaszewski hog->name = trimmed; 1230cb8c474eSBartosz Golaszewski 1231cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1232cb8c474eSBartosz Golaszewski 1233cb8c474eSBartosz Golaszewski return count; 1234cb8c474eSBartosz Golaszewski } 1235cb8c474eSBartosz Golaszewski 1236cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_hog_config_, name); 1237cb8c474eSBartosz Golaszewski 1238cb8c474eSBartosz Golaszewski static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item, 1239cb8c474eSBartosz Golaszewski char *page) 1240cb8c474eSBartosz Golaszewski { 1241cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1242cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1243cb8c474eSBartosz Golaszewski char *repr; 1244cb8c474eSBartosz Golaszewski int dir; 1245cb8c474eSBartosz Golaszewski 1246cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1247cb8c474eSBartosz Golaszewski dir = hog->dir; 1248cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1249cb8c474eSBartosz Golaszewski 1250cb8c474eSBartosz Golaszewski switch (dir) { 1251cb8c474eSBartosz Golaszewski case GPIOD_IN: 1252cb8c474eSBartosz Golaszewski repr = "input"; 1253cb8c474eSBartosz Golaszewski break; 1254cb8c474eSBartosz Golaszewski case GPIOD_OUT_HIGH: 1255cb8c474eSBartosz Golaszewski repr = "output-high"; 1256cb8c474eSBartosz Golaszewski break; 1257cb8c474eSBartosz Golaszewski case GPIOD_OUT_LOW: 1258cb8c474eSBartosz Golaszewski repr = "output-low"; 1259cb8c474eSBartosz Golaszewski break; 1260cb8c474eSBartosz Golaszewski default: 1261cb8c474eSBartosz Golaszewski /* This would be a programmer bug. */ 1262cb8c474eSBartosz Golaszewski WARN(1, "Unexpected hog direction value: %d", dir); 1263cb8c474eSBartosz Golaszewski return -EINVAL; 1264cb8c474eSBartosz Golaszewski } 1265cb8c474eSBartosz Golaszewski 1266cb8c474eSBartosz Golaszewski return sprintf(page, "%s\n", repr); 1267cb8c474eSBartosz Golaszewski } 1268cb8c474eSBartosz Golaszewski 1269cb8c474eSBartosz Golaszewski static ssize_t 1270cb8c474eSBartosz Golaszewski gpio_sim_hog_config_direction_store(struct config_item *item, 1271cb8c474eSBartosz Golaszewski const char *page, size_t count) 1272cb8c474eSBartosz Golaszewski { 1273cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1274cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1275cb8c474eSBartosz Golaszewski char *trimmed; 1276cb8c474eSBartosz Golaszewski int dir; 1277cb8c474eSBartosz Golaszewski 1278cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1279cb8c474eSBartosz Golaszewski 1280cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1281cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1282cb8c474eSBartosz Golaszewski return -EBUSY; 1283cb8c474eSBartosz Golaszewski } 1284cb8c474eSBartosz Golaszewski 1285cb8c474eSBartosz Golaszewski trimmed = gpio_sim_strdup_trimmed(page, count); 1286cb8c474eSBartosz Golaszewski if (!trimmed) { 1287cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1288cb8c474eSBartosz Golaszewski return -ENOMEM; 1289cb8c474eSBartosz Golaszewski } 1290cb8c474eSBartosz Golaszewski 1291cb8c474eSBartosz Golaszewski if (strcmp(trimmed, "input") == 0) 1292cb8c474eSBartosz Golaszewski dir = GPIOD_IN; 1293cb8c474eSBartosz Golaszewski else if (strcmp(trimmed, "output-high") == 0) 1294cb8c474eSBartosz Golaszewski dir = GPIOD_OUT_HIGH; 1295cb8c474eSBartosz Golaszewski else if (strcmp(trimmed, "output-low") == 0) 1296cb8c474eSBartosz Golaszewski dir = GPIOD_OUT_LOW; 1297cb8c474eSBartosz Golaszewski else 1298cb8c474eSBartosz Golaszewski dir = -EINVAL; 1299cb8c474eSBartosz Golaszewski 1300cb8c474eSBartosz Golaszewski kfree(trimmed); 1301cb8c474eSBartosz Golaszewski 1302cb8c474eSBartosz Golaszewski if (dir < 0) { 1303cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1304cb8c474eSBartosz Golaszewski return dir; 1305cb8c474eSBartosz Golaszewski } 1306cb8c474eSBartosz Golaszewski 1307cb8c474eSBartosz Golaszewski hog->dir = dir; 1308cb8c474eSBartosz Golaszewski 1309cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1310cb8c474eSBartosz Golaszewski 1311cb8c474eSBartosz Golaszewski return count; 1312cb8c474eSBartosz Golaszewski } 1313cb8c474eSBartosz Golaszewski 1314cb8c474eSBartosz Golaszewski CONFIGFS_ATTR(gpio_sim_hog_config_, direction); 1315cb8c474eSBartosz Golaszewski 1316cb8c474eSBartosz Golaszewski static struct configfs_attribute *gpio_sim_hog_config_attrs[] = { 1317cb8c474eSBartosz Golaszewski &gpio_sim_hog_config_attr_name, 1318cb8c474eSBartosz Golaszewski &gpio_sim_hog_config_attr_direction, 1319cb8c474eSBartosz Golaszewski NULL 1320cb8c474eSBartosz Golaszewski }; 1321cb8c474eSBartosz Golaszewski 1322cb8c474eSBartosz Golaszewski static void gpio_sim_hog_config_item_release(struct config_item *item) 1323cb8c474eSBartosz Golaszewski { 1324cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog = to_gpio_sim_hog(item); 1325cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = hog->parent; 1326cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); 1327cb8c474eSBartosz Golaszewski 1328cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1329cb8c474eSBartosz Golaszewski line->hog = NULL; 1330cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1331cb8c474eSBartosz Golaszewski 1332cb8c474eSBartosz Golaszewski kfree(hog->name); 1333cb8c474eSBartosz Golaszewski kfree(hog); 1334cb8c474eSBartosz Golaszewski } 1335cb8c474eSBartosz Golaszewski 1336a9a5b720SAndy Shevchenko static struct configfs_item_operations gpio_sim_hog_config_item_ops = { 1337cb8c474eSBartosz Golaszewski .release = gpio_sim_hog_config_item_release, 1338cb8c474eSBartosz Golaszewski }; 1339cb8c474eSBartosz Golaszewski 1340cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_hog_config_type = { 1341cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_hog_config_item_ops, 1342cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_hog_config_attrs, 1343cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1344cb8c474eSBartosz Golaszewski }; 1345cb8c474eSBartosz Golaszewski 1346cb8c474eSBartosz Golaszewski static struct config_item * 1347cb8c474eSBartosz Golaszewski gpio_sim_line_config_make_hog_item(struct config_group *group, const char *name) 1348cb8c474eSBartosz Golaszewski { 1349cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(&group->cg_item); 1350cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1351cb8c474eSBartosz Golaszewski struct gpio_sim_hog *hog; 1352cb8c474eSBartosz Golaszewski 1353cb8c474eSBartosz Golaszewski if (strcmp(name, "hog") != 0) 1354cb8c474eSBartosz Golaszewski return ERR_PTR(-EINVAL); 1355cb8c474eSBartosz Golaszewski 1356cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1357cb8c474eSBartosz Golaszewski 1358cb8c474eSBartosz Golaszewski hog = kzalloc(sizeof(*hog), GFP_KERNEL); 1359cb8c474eSBartosz Golaszewski if (!hog) { 1360cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1361cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1362cb8c474eSBartosz Golaszewski } 1363cb8c474eSBartosz Golaszewski 1364cb8c474eSBartosz Golaszewski config_item_init_type_name(&hog->item, name, 1365cb8c474eSBartosz Golaszewski &gpio_sim_hog_config_type); 1366cb8c474eSBartosz Golaszewski 1367cb8c474eSBartosz Golaszewski hog->dir = GPIOD_IN; 1368cb8c474eSBartosz Golaszewski hog->name = NULL; 1369cb8c474eSBartosz Golaszewski hog->parent = line; 1370cb8c474eSBartosz Golaszewski line->hog = hog; 1371cb8c474eSBartosz Golaszewski 1372cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1373cb8c474eSBartosz Golaszewski 1374cb8c474eSBartosz Golaszewski return &hog->item; 1375cb8c474eSBartosz Golaszewski } 1376cb8c474eSBartosz Golaszewski 1377cb8c474eSBartosz Golaszewski static void gpio_sim_line_config_group_release(struct config_item *item) 1378cb8c474eSBartosz Golaszewski { 1379cb8c474eSBartosz Golaszewski struct gpio_sim_line *line = to_gpio_sim_line(item); 1380cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1381cb8c474eSBartosz Golaszewski 1382cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1383cb8c474eSBartosz Golaszewski list_del(&line->siblings); 1384cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1385cb8c474eSBartosz Golaszewski 1386cb8c474eSBartosz Golaszewski kfree(line->name); 1387cb8c474eSBartosz Golaszewski kfree(line); 1388cb8c474eSBartosz Golaszewski } 1389cb8c474eSBartosz Golaszewski 1390cb8c474eSBartosz Golaszewski static struct configfs_item_operations gpio_sim_line_config_item_ops = { 1391cb8c474eSBartosz Golaszewski .release = gpio_sim_line_config_group_release, 1392cb8c474eSBartosz Golaszewski }; 1393cb8c474eSBartosz Golaszewski 1394cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_line_config_group_ops = { 1395cb8c474eSBartosz Golaszewski .make_item = gpio_sim_line_config_make_hog_item, 1396cb8c474eSBartosz Golaszewski }; 1397cb8c474eSBartosz Golaszewski 1398cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_line_config_type = { 1399cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_line_config_item_ops, 1400cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_line_config_group_ops, 1401cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_line_config_attrs, 1402cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1403cb8c474eSBartosz Golaszewski }; 1404cb8c474eSBartosz Golaszewski 1405cb8c474eSBartosz Golaszewski static struct config_group * 1406cb8c474eSBartosz Golaszewski gpio_sim_bank_config_make_line_group(struct config_group *group, 1407cb8c474eSBartosz Golaszewski const char *name) 1408cb8c474eSBartosz Golaszewski { 1409cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(&group->cg_item); 1410cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1411cb8c474eSBartosz Golaszewski struct gpio_sim_line *line; 1412cb8c474eSBartosz Golaszewski unsigned int offset; 1413cb8c474eSBartosz Golaszewski int ret, nchar; 1414cb8c474eSBartosz Golaszewski 1415cb8c474eSBartosz Golaszewski ret = sscanf(name, "line%u%n", &offset, &nchar); 1416cb8c474eSBartosz Golaszewski if (ret != 1 || nchar != strlen(name)) 1417cb8c474eSBartosz Golaszewski return ERR_PTR(-EINVAL); 1418cb8c474eSBartosz Golaszewski 1419cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1420cb8c474eSBartosz Golaszewski 1421cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1422cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1423cb8c474eSBartosz Golaszewski return ERR_PTR(-EBUSY); 1424cb8c474eSBartosz Golaszewski } 1425cb8c474eSBartosz Golaszewski 1426cb8c474eSBartosz Golaszewski line = kzalloc(sizeof(*line), GFP_KERNEL); 1427cb8c474eSBartosz Golaszewski if (!line) { 1428cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1429cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1430cb8c474eSBartosz Golaszewski } 1431cb8c474eSBartosz Golaszewski 1432cb8c474eSBartosz Golaszewski config_group_init_type_name(&line->group, name, 1433cb8c474eSBartosz Golaszewski &gpio_sim_line_config_type); 1434cb8c474eSBartosz Golaszewski 1435cb8c474eSBartosz Golaszewski line->parent = bank; 1436cb8c474eSBartosz Golaszewski line->offset = offset; 1437cb8c474eSBartosz Golaszewski list_add_tail(&line->siblings, &bank->line_list); 1438cb8c474eSBartosz Golaszewski 1439cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1440cb8c474eSBartosz Golaszewski 1441cb8c474eSBartosz Golaszewski return &line->group; 1442cb8c474eSBartosz Golaszewski } 1443cb8c474eSBartosz Golaszewski 1444cb8c474eSBartosz Golaszewski static void gpio_sim_bank_config_group_release(struct config_item *item) 1445cb8c474eSBartosz Golaszewski { 1446cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank = to_gpio_sim_bank(item); 1447cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); 1448cb8c474eSBartosz Golaszewski 1449cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1450cb8c474eSBartosz Golaszewski list_del(&bank->siblings); 1451cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1452cb8c474eSBartosz Golaszewski 1453cb8c474eSBartosz Golaszewski kfree(bank->label); 1454cb8c474eSBartosz Golaszewski kfree(bank); 1455cb8c474eSBartosz Golaszewski } 1456cb8c474eSBartosz Golaszewski 1457cb8c474eSBartosz Golaszewski static struct configfs_item_operations gpio_sim_bank_config_item_ops = { 1458cb8c474eSBartosz Golaszewski .release = gpio_sim_bank_config_group_release, 1459cb8c474eSBartosz Golaszewski }; 1460cb8c474eSBartosz Golaszewski 1461cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_bank_config_group_ops = { 1462cb8c474eSBartosz Golaszewski .make_group = gpio_sim_bank_config_make_line_group, 1463cb8c474eSBartosz Golaszewski }; 1464cb8c474eSBartosz Golaszewski 1465cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_bank_config_group_type = { 1466cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_bank_config_item_ops, 1467cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_bank_config_group_ops, 1468cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_bank_config_attrs, 1469cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1470cb8c474eSBartosz Golaszewski }; 1471cb8c474eSBartosz Golaszewski 1472cb8c474eSBartosz Golaszewski static struct config_group * 1473cb8c474eSBartosz Golaszewski gpio_sim_device_config_make_bank_group(struct config_group *group, 1474cb8c474eSBartosz Golaszewski const char *name) 1475cb8c474eSBartosz Golaszewski { 1476cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(&group->cg_item); 1477cb8c474eSBartosz Golaszewski struct gpio_sim_bank *bank; 1478cb8c474eSBartosz Golaszewski 1479cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1480cb8c474eSBartosz Golaszewski 1481cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) { 1482cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1483cb8c474eSBartosz Golaszewski return ERR_PTR(-EBUSY); 1484cb8c474eSBartosz Golaszewski } 1485cb8c474eSBartosz Golaszewski 1486cb8c474eSBartosz Golaszewski bank = kzalloc(sizeof(*bank), GFP_KERNEL); 1487cb8c474eSBartosz Golaszewski if (!bank) { 1488cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1489cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1490cb8c474eSBartosz Golaszewski } 1491cb8c474eSBartosz Golaszewski 1492cb8c474eSBartosz Golaszewski config_group_init_type_name(&bank->group, name, 1493cb8c474eSBartosz Golaszewski &gpio_sim_bank_config_group_type); 1494cb8c474eSBartosz Golaszewski bank->num_lines = 1; 1495cb8c474eSBartosz Golaszewski bank->parent = dev; 1496cb8c474eSBartosz Golaszewski INIT_LIST_HEAD(&bank->line_list); 1497cb8c474eSBartosz Golaszewski list_add_tail(&bank->siblings, &dev->bank_list); 1498cb8c474eSBartosz Golaszewski 1499cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1500cb8c474eSBartosz Golaszewski 1501cb8c474eSBartosz Golaszewski return &bank->group; 1502cb8c474eSBartosz Golaszewski } 1503cb8c474eSBartosz Golaszewski 1504cb8c474eSBartosz Golaszewski static void gpio_sim_device_config_group_release(struct config_item *item) 1505cb8c474eSBartosz Golaszewski { 1506cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev = to_gpio_sim_device(item); 1507cb8c474eSBartosz Golaszewski 1508cb8c474eSBartosz Golaszewski mutex_lock(&dev->lock); 1509cb8c474eSBartosz Golaszewski if (gpio_sim_device_is_live_unlocked(dev)) 1510cb8c474eSBartosz Golaszewski gpio_sim_device_deactivate_unlocked(dev); 1511cb8c474eSBartosz Golaszewski mutex_unlock(&dev->lock); 1512cb8c474eSBartosz Golaszewski 1513cb8c474eSBartosz Golaszewski mutex_destroy(&dev->lock); 1514cb8c474eSBartosz Golaszewski ida_free(&gpio_sim_ida, dev->id); 1515cb8c474eSBartosz Golaszewski kfree(dev); 1516cb8c474eSBartosz Golaszewski } 1517cb8c474eSBartosz Golaszewski 1518cb8c474eSBartosz Golaszewski static struct configfs_item_operations gpio_sim_device_config_item_ops = { 1519cb8c474eSBartosz Golaszewski .release = gpio_sim_device_config_group_release, 1520cb8c474eSBartosz Golaszewski }; 1521cb8c474eSBartosz Golaszewski 1522cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_device_config_group_ops = { 1523cb8c474eSBartosz Golaszewski .make_group = gpio_sim_device_config_make_bank_group, 1524cb8c474eSBartosz Golaszewski }; 1525cb8c474eSBartosz Golaszewski 1526cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_device_config_group_type = { 1527cb8c474eSBartosz Golaszewski .ct_item_ops = &gpio_sim_device_config_item_ops, 1528cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_device_config_group_ops, 1529cb8c474eSBartosz Golaszewski .ct_attrs = gpio_sim_device_config_attrs, 1530cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1531cb8c474eSBartosz Golaszewski }; 1532cb8c474eSBartosz Golaszewski 1533cb8c474eSBartosz Golaszewski static struct config_group * 1534cb8c474eSBartosz Golaszewski gpio_sim_config_make_device_group(struct config_group *group, const char *name) 1535cb8c474eSBartosz Golaszewski { 1536cb8c474eSBartosz Golaszewski struct gpio_sim_device *dev; 1537cb8c474eSBartosz Golaszewski int id; 1538cb8c474eSBartosz Golaszewski 1539cb8c474eSBartosz Golaszewski dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1540cb8c474eSBartosz Golaszewski if (!dev) 1541cb8c474eSBartosz Golaszewski return ERR_PTR(-ENOMEM); 1542cb8c474eSBartosz Golaszewski 1543cb8c474eSBartosz Golaszewski id = ida_alloc(&gpio_sim_ida, GFP_KERNEL); 1544cb8c474eSBartosz Golaszewski if (id < 0) { 1545cb8c474eSBartosz Golaszewski kfree(dev); 1546cb8c474eSBartosz Golaszewski return ERR_PTR(id); 1547cb8c474eSBartosz Golaszewski } 1548cb8c474eSBartosz Golaszewski 1549cb8c474eSBartosz Golaszewski config_group_init_type_name(&dev->group, name, 1550cb8c474eSBartosz Golaszewski &gpio_sim_device_config_group_type); 1551cb8c474eSBartosz Golaszewski dev->id = id; 1552cb8c474eSBartosz Golaszewski mutex_init(&dev->lock); 1553cb8c474eSBartosz Golaszewski INIT_LIST_HEAD(&dev->bank_list); 1554cb8c474eSBartosz Golaszewski 1555cb8c474eSBartosz Golaszewski dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call; 1556cb8c474eSBartosz Golaszewski init_completion(&dev->probe_completion); 1557cb8c474eSBartosz Golaszewski 1558cb8c474eSBartosz Golaszewski return &dev->group; 1559cb8c474eSBartosz Golaszewski } 1560cb8c474eSBartosz Golaszewski 1561cb8c474eSBartosz Golaszewski static struct configfs_group_operations gpio_sim_config_group_ops = { 1562cb8c474eSBartosz Golaszewski .make_group = gpio_sim_config_make_device_group, 1563cb8c474eSBartosz Golaszewski }; 1564cb8c474eSBartosz Golaszewski 1565cb8c474eSBartosz Golaszewski static const struct config_item_type gpio_sim_config_type = { 1566cb8c474eSBartosz Golaszewski .ct_group_ops = &gpio_sim_config_group_ops, 1567cb8c474eSBartosz Golaszewski .ct_owner = THIS_MODULE, 1568cb8c474eSBartosz Golaszewski }; 1569cb8c474eSBartosz Golaszewski 1570cb8c474eSBartosz Golaszewski static struct configfs_subsystem gpio_sim_config_subsys = { 1571cb8c474eSBartosz Golaszewski .su_group = { 1572cb8c474eSBartosz Golaszewski .cg_item = { 1573cb8c474eSBartosz Golaszewski .ci_namebuf = "gpio-sim", 1574cb8c474eSBartosz Golaszewski .ci_type = &gpio_sim_config_type, 1575cb8c474eSBartosz Golaszewski }, 1576cb8c474eSBartosz Golaszewski }, 1577cb8c474eSBartosz Golaszewski }; 1578cb8c474eSBartosz Golaszewski 1579cb8c474eSBartosz Golaszewski static int __init gpio_sim_init(void) 1580cb8c474eSBartosz Golaszewski { 1581cb8c474eSBartosz Golaszewski int ret; 1582cb8c474eSBartosz Golaszewski 1583cb8c474eSBartosz Golaszewski ret = platform_driver_register(&gpio_sim_driver); 1584cb8c474eSBartosz Golaszewski if (ret) { 1585cb8c474eSBartosz Golaszewski pr_err("Error %d while registering the platform driver\n", ret); 1586cb8c474eSBartosz Golaszewski return ret; 1587cb8c474eSBartosz Golaszewski } 1588cb8c474eSBartosz Golaszewski 1589cb8c474eSBartosz Golaszewski config_group_init(&gpio_sim_config_subsys.su_group); 1590cb8c474eSBartosz Golaszewski mutex_init(&gpio_sim_config_subsys.su_mutex); 1591cb8c474eSBartosz Golaszewski ret = configfs_register_subsystem(&gpio_sim_config_subsys); 1592cb8c474eSBartosz Golaszewski if (ret) { 1593cb8c474eSBartosz Golaszewski pr_err("Error %d while registering the configfs subsystem %s\n", 1594cb8c474eSBartosz Golaszewski ret, gpio_sim_config_subsys.su_group.cg_item.ci_namebuf); 1595cb8c474eSBartosz Golaszewski mutex_destroy(&gpio_sim_config_subsys.su_mutex); 1596cb8c474eSBartosz Golaszewski platform_driver_unregister(&gpio_sim_driver); 1597cb8c474eSBartosz Golaszewski return ret; 1598cb8c474eSBartosz Golaszewski } 1599cb8c474eSBartosz Golaszewski 1600cb8c474eSBartosz Golaszewski return 0; 1601cb8c474eSBartosz Golaszewski } 1602cb8c474eSBartosz Golaszewski module_init(gpio_sim_init); 1603cb8c474eSBartosz Golaszewski 1604cb8c474eSBartosz Golaszewski static void __exit gpio_sim_exit(void) 1605cb8c474eSBartosz Golaszewski { 1606cb8c474eSBartosz Golaszewski configfs_unregister_subsystem(&gpio_sim_config_subsys); 1607cb8c474eSBartosz Golaszewski mutex_destroy(&gpio_sim_config_subsys.su_mutex); 1608cb8c474eSBartosz Golaszewski platform_driver_unregister(&gpio_sim_driver); 1609cb8c474eSBartosz Golaszewski } 1610cb8c474eSBartosz Golaszewski module_exit(gpio_sim_exit); 1611cb8c474eSBartosz Golaszewski 1612cb8c474eSBartosz Golaszewski MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl"); 1613cb8c474eSBartosz Golaszewski MODULE_DESCRIPTION("GPIO Simulator Module"); 1614cb8c474eSBartosz Golaszewski MODULE_LICENSE("GPL"); 1615