Add support for the pull up/down state set via gpiolib line requests to be reflected in the state of the mockup. Use case is for testing of the GPIO uAPI, specifically the pull up/down flags.
Unified · Split
| @@ -141,6 +141,61 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc, · 140 unmodified lines | |||
| 141 | mutex_unlock(&chip->lock); | 141 | mutex_unlock(&chip->lock); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, | ||
| 145 | unsigned int offset, int value) | ||
| 146 | { | ||
| 147 | struct gpio_desc *desc; | ||
| 148 | struct gpio_chip *gc; | ||
| 149 | struct irq_sim *sim; | ||
| 150 | int curr, irq, irq_type; | ||
| 151 | |||
| 152 | gc = &chip->gc; | ||
| 153 | desc = &gc->gpiodev->descs[offset]; | ||
| 154 | sim = &chip->irqsim; | ||
| 155 | |||
| 156 | mutex_lock(&chip->lock); | ||
| 157 | |||
| 158 | if (test_bit(FLAG_REQUESTED, &desc->flags) && | ||
| 159 | !test_bit(FLAG_IS_OUT, &desc->flags)) { | ||
| 160 | curr = __gpio_mockup_get(chip, offset); | ||
| 161 | if (curr == value) | ||
| 162 | goto out; | ||
| 163 | |||
| 164 | irq = irq_sim_irqnum(sim, offset); | ||
| 165 | irq_type = irq_get_trigger_type(irq); | ||
| 166 | |||
| 167 | if ((value == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) || | ||
| 168 | (value == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING))) | ||
| 169 | irq_sim_fire(sim, offset); | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Change the value unless we're actively driving the line. */ | ||
| 173 | if (!test_bit(FLAG_REQUESTED, &desc->flags) || | ||
| 174 | !test_bit(FLAG_IS_OUT, &desc->flags)) | ||
| 175 | __gpio_mockup_set(chip, offset, value); | ||
| 176 | |||
| 177 | out: | ||
| 178 | chip->lines[offset].pull = value; | ||
| 179 | mutex_unlock(&chip->lock); | ||
| 180 | return 0; | ||
| 181 | } | ||
| 182 | |||
| 183 | static int gpio_mockup_set_config(struct gpio_chip *gc, | ||
| 184 | unsigned int offset, unsigned long config) | ||
| 185 | { | ||
| 186 | struct gpio_mockup_chip *chip = gpiochip_get_data(gc); | ||
| 187 | |||
| 188 | switch (pinconf_to_config_param(config)) { | ||
| 189 | case PIN_CONFIG_BIAS_PULL_UP: | ||
| 190 | return gpio_mockup_apply_pull(chip, offset, 1); | ||
| 191 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
| 192 | return gpio_mockup_apply_pull(chip, offset, 0); | ||
| 193 | default: | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | return -ENOTSUPP; | ||
| 197 | } | ||
| 198 | |||
| 144 | static int gpio_mockup_dirout(struct gpio_chip *gc, | 199 | static int gpio_mockup_dirout(struct gpio_chip *gc, |
| 145 | unsigned int offset, int value) | 200 | unsigned int offset, int value) |
| 146 | { | 201 | { |
| @@ -221,12 +276,8 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file, · 74 unmodified lines | |||
| 221 | size_t size, loff_t *ppos) | 276 | size_t size, loff_t *ppos) |
| 222 | { | 277 | { |
| 223 | struct gpio_mockup_dbgfs_private *priv; | 278 | struct gpio_mockup_dbgfs_private *priv; |
| 224 | int rv, val, curr, irq, irq_type; | 279 | int rv, val; |
| 225 | struct gpio_mockup_chip *chip; | ||
| 226 | struct seq_file *sfile; | 280 | struct seq_file *sfile; |
| 227 | struct gpio_desc *desc; | ||
| 228 | struct gpio_chip *gc; | ||
| 229 | struct irq_sim *sim; | ||
| 230 | 281 | ||
| 231 | if (*ppos != 0) | 282 | if (*ppos != 0) |
| 232 | return -EINVAL; | 283 | return -EINVAL; |
| @@ -239,35 +290,9 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file, · 6 unmodified lines | |||
| 239 | 290 | ||
| 240 | sfile = file->private_data; | 291 | sfile = file->private_data; |
| 241 | priv = sfile->private; | 292 | priv = sfile->private; |
| 242 | chip = priv->chip; | 293 | rv = gpio_mockup_apply_pull(priv->chip, priv->offset, val); |
| 243 | gc = &chip->gc; | 294 | if (rv) |
| 244 | desc = &gc->gpiodev->descs[priv->offset]; | 295 | return rv; |
| 245 | sim = &chip->irqsim; | ||
| 246 | |||
| 247 | mutex_lock(&chip->lock); | ||
| 248 | |||
| 249 | if (test_bit(FLAG_REQUESTED, &desc->flags) && | ||
| 250 | !test_bit(FLAG_IS_OUT, &desc->flags)) { | ||
| 251 | curr = __gpio_mockup_get(chip, priv->offset); | ||
| 252 | if (curr == val) | ||
| 253 | goto out; | ||
| 254 | |||
| 255 | irq = irq_sim_irqnum(sim, priv->offset); | ||
| 256 | irq_type = irq_get_trigger_type(irq); | ||
| 257 | |||
| 258 | if ((val == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) || | ||
| 259 | (val == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING))) | ||
| 260 | irq_sim_fire(sim, priv->offset); | ||
| 261 | } | ||
| 262 | |||
| 263 | /* Change the value unless we're actively driving the line. */ | ||
| 264 | if (!test_bit(FLAG_REQUESTED, &desc->flags) || | ||
| 265 | !test_bit(FLAG_IS_OUT, &desc->flags)) | ||
| 266 | __gpio_mockup_set(chip, priv->offset, val); | ||
| 267 | |||
| 268 | out: | ||
| 269 | chip->lines[priv->offset].pull = val; | ||
| 270 | mutex_unlock(&chip->lock); | ||
| 271 | 296 | ||
| 272 | return size; | 297 | return size; |
| 273 | } | 298 | } |
| @@ -413,6 +438,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) · 139 unmodified lines | |||
| 413 | gc->direction_output = gpio_mockup_dirout; | 438 | gc->direction_output = gpio_mockup_dirout; |
| 414 | gc->direction_input = gpio_mockup_dirin; | 439 | gc->direction_input = gpio_mockup_dirin; |
| 415 | gc->get_direction = gpio_mockup_get_direction; | 440 | gc->get_direction = gpio_mockup_get_direction; |
| 441 | gc->set_config = gpio_mockup_set_config; | ||
| 416 | gc->to_irq = gpio_mockup_to_irq; | 442 | gc->to_irq = gpio_mockup_to_irq; |
| 417 | gc->free = gpio_mockup_free; | 443 | gc->free = gpio_mockup_free; |
| 418 | 444 | ||