diff options
-rw-r--r-- | drivers/gpio/gpio-mockup.c | 117 |
1 files changed, 103 insertions, 14 deletions
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index c498b0fbbec8..154d959e8993 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c | |||
@@ -47,6 +47,7 @@ enum { | |||
47 | struct gpio_mockup_line_status { | 47 | struct gpio_mockup_line_status { |
48 | int dir; | 48 | int dir; |
49 | int value; | 49 | int value; |
50 | int pull; | ||
50 | }; | 51 | }; |
51 | 52 | ||
52 | struct gpio_mockup_chip { | 53 | struct gpio_mockup_chip { |
@@ -188,15 +189,56 @@ static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset) | |||
188 | return irq_sim_irqnum(&chip->irqsim, offset); | 189 | return irq_sim_irqnum(&chip->irqsim, offset); |
189 | } | 190 | } |
190 | 191 | ||
191 | static ssize_t gpio_mockup_event_write(struct file *file, | 192 | static void gpio_mockup_free(struct gpio_chip *gc, unsigned int offset) |
192 | const char __user *usr_buf, | 193 | { |
193 | size_t size, loff_t *ppos) | 194 | struct gpio_mockup_chip *chip = gpiochip_get_data(gc); |
195 | |||
196 | __gpio_mockup_set(chip, offset, chip->lines[offset].pull); | ||
197 | } | ||
198 | |||
199 | static ssize_t gpio_mockup_debugfs_read(struct file *file, | ||
200 | char __user *usr_buf, | ||
201 | size_t size, loff_t *ppos) | ||
194 | { | 202 | { |
195 | struct gpio_mockup_dbgfs_private *priv; | 203 | struct gpio_mockup_dbgfs_private *priv; |
196 | struct gpio_mockup_chip *chip; | 204 | struct gpio_mockup_chip *chip; |
197 | struct seq_file *sfile; | 205 | struct seq_file *sfile; |
206 | struct gpio_chip *gc; | ||
207 | char buf[3]; | ||
208 | int val, rv; | ||
209 | |||
210 | if (*ppos != 0) | ||
211 | return 0; | ||
212 | |||
213 | sfile = file->private_data; | ||
214 | priv = sfile->private; | ||
215 | chip = priv->chip; | ||
216 | gc = &chip->gc; | ||
217 | |||
218 | val = gpio_mockup_get(gc, priv->offset); | ||
219 | snprintf(buf, sizeof(buf), "%d\n", val); | ||
220 | |||
221 | rv = copy_to_user(usr_buf, buf, sizeof(buf)); | ||
222 | if (rv) | ||
223 | return rv; | ||
224 | |||
225 | return sizeof(buf) - 1; | ||
226 | } | ||
227 | |||
228 | static ssize_t gpio_mockup_debugfs_write(struct file *file, | ||
229 | const char __user *usr_buf, | ||
230 | size_t size, loff_t *ppos) | ||
231 | { | ||
232 | struct gpio_mockup_dbgfs_private *priv; | ||
233 | int rv, val, curr, irq, irq_type; | ||
234 | struct gpio_mockup_chip *chip; | ||
235 | struct seq_file *sfile; | ||
198 | struct gpio_desc *desc; | 236 | struct gpio_desc *desc; |
199 | int rv, val; | 237 | struct gpio_chip *gc; |
238 | struct irq_sim *sim; | ||
239 | |||
240 | if (*ppos != 0) | ||
241 | return -EINVAL; | ||
200 | 242 | ||
201 | rv = kstrtoint_from_user(usr_buf, size, 0, &val); | 243 | rv = kstrtoint_from_user(usr_buf, size, 0, &val); |
202 | if (rv) | 244 | if (rv) |
@@ -206,24 +248,70 @@ static ssize_t gpio_mockup_event_write(struct file *file, | |||
206 | 248 | ||
207 | sfile = file->private_data; | 249 | sfile = file->private_data; |
208 | priv = sfile->private; | 250 | priv = sfile->private; |
209 | desc = priv->desc; | ||
210 | chip = priv->chip; | 251 | chip = priv->chip; |
252 | gc = &chip->gc; | ||
253 | desc = &gc->gpiodev->descs[priv->offset]; | ||
254 | sim = &chip->irqsim; | ||
255 | |||
256 | mutex_lock(&chip->lock); | ||
257 | |||
258 | if (test_bit(FLAG_REQUESTED, &desc->flags) && | ||
259 | !test_bit(FLAG_IS_OUT, &desc->flags)) { | ||
260 | curr = __gpio_mockup_get(chip, priv->offset); | ||
261 | if (curr == val) | ||
262 | goto out; | ||
211 | 263 | ||
212 | gpiod_set_value_cansleep(desc, val); | 264 | irq = irq_sim_irqnum(sim, priv->offset); |
213 | irq_sim_fire(&chip->irqsim, priv->offset); | 265 | irq_type = irq_get_trigger_type(irq); |
266 | |||
267 | if ((val == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) || | ||
268 | (val == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING))) | ||
269 | irq_sim_fire(sim, priv->offset); | ||
270 | } | ||
271 | |||
272 | /* Change the value unless we're actively driving the line. */ | ||
273 | if (!test_bit(FLAG_REQUESTED, &desc->flags) || | ||
274 | !test_bit(FLAG_IS_OUT, &desc->flags)) | ||
275 | __gpio_mockup_set(chip, priv->offset, val); | ||
276 | |||
277 | out: | ||
278 | chip->lines[priv->offset].pull = val; | ||
279 | mutex_unlock(&chip->lock); | ||
214 | 280 | ||
215 | return size; | 281 | return size; |
216 | } | 282 | } |
217 | 283 | ||
218 | static int gpio_mockup_event_open(struct inode *inode, struct file *file) | 284 | static int gpio_mockup_debugfs_open(struct inode *inode, struct file *file) |
219 | { | 285 | { |
220 | return single_open(file, NULL, inode->i_private); | 286 | return single_open(file, NULL, inode->i_private); |
221 | } | 287 | } |
222 | 288 | ||
223 | static const struct file_operations gpio_mockup_event_ops = { | 289 | /* |
290 | * Each mockup chip is represented by a directory named after the chip's device | ||
291 | * name under /sys/kernel/debug/gpio-mockup/. Each line is represented by | ||
292 | * a file using the line's offset as the name under the chip's directory. | ||
293 | * | ||
294 | * Reading from the line's file yields the current *value*, writing to the | ||
295 | * line's file changes the current *pull*. Default pull for mockup lines is | ||
296 | * down. | ||
297 | * | ||
298 | * Examples: | ||
299 | * - when a line pulled down is requested in output mode and driven high, its | ||
300 | * value will return to 0 once it's released | ||
301 | * - when the line is requested in output mode and driven high, writing 0 to | ||
302 | * the corresponding debugfs file will change the pull to down but the | ||
303 | * reported value will still be 1 until the line is released | ||
304 | * - line requested in input mode always reports the same value as its pull | ||
305 | * configuration | ||
306 | * - when the line is requested in input mode and monitored for events, writing | ||
307 | * the same value to the debugfs file will be a noop, while writing the | ||
308 | * opposite value will generate a dummy interrupt with an appropriate edge | ||
309 | */ | ||
310 | static const struct file_operations gpio_mockup_debugfs_ops = { | ||
224 | .owner = THIS_MODULE, | 311 | .owner = THIS_MODULE, |
225 | .open = gpio_mockup_event_open, | 312 | .open = gpio_mockup_debugfs_open, |
226 | .write = gpio_mockup_event_write, | 313 | .read = gpio_mockup_debugfs_read, |
314 | .write = gpio_mockup_debugfs_write, | ||
227 | .llseek = no_llseek, | 315 | .llseek = no_llseek, |
228 | }; | 316 | }; |
229 | 317 | ||
@@ -258,7 +346,7 @@ static void gpio_mockup_debugfs_setup(struct device *dev, | |||
258 | priv->desc = &gc->gpiodev->descs[i]; | 346 | priv->desc = &gc->gpiodev->descs[i]; |
259 | 347 | ||
260 | evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv, | 348 | evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv, |
261 | &gpio_mockup_event_ops); | 349 | &gpio_mockup_debugfs_ops); |
262 | if (IS_ERR_OR_NULL(evfile)) | 350 | if (IS_ERR_OR_NULL(evfile)) |
263 | goto err; | 351 | goto err; |
264 | } | 352 | } |
@@ -266,7 +354,7 @@ static void gpio_mockup_debugfs_setup(struct device *dev, | |||
266 | return; | 354 | return; |
267 | 355 | ||
268 | err: | 356 | err: |
269 | dev_err(dev, "error creating debugfs event files\n"); | 357 | dev_err(dev, "error creating debugfs files\n"); |
270 | } | 358 | } |
271 | 359 | ||
272 | static int gpio_mockup_name_lines(struct device *dev, | 360 | static int gpio_mockup_name_lines(struct device *dev, |
@@ -342,6 +430,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) | |||
342 | gc->direction_input = gpio_mockup_dirin; | 430 | gc->direction_input = gpio_mockup_dirin; |
343 | gc->get_direction = gpio_mockup_get_direction; | 431 | gc->get_direction = gpio_mockup_get_direction; |
344 | gc->to_irq = gpio_mockup_to_irq; | 432 | gc->to_irq = gpio_mockup_to_irq; |
433 | gc->free = gpio_mockup_free; | ||
345 | 434 | ||
346 | chip->lines = devm_kcalloc(dev, gc->ngpio, | 435 | chip->lines = devm_kcalloc(dev, gc->ngpio, |
347 | sizeof(*chip->lines), GFP_KERNEL); | 436 | sizeof(*chip->lines), GFP_KERNEL); |
@@ -415,7 +504,7 @@ static int __init gpio_mockup_init(void) | |||
415 | return -EINVAL; | 504 | return -EINVAL; |
416 | } | 505 | } |
417 | 506 | ||
418 | gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL); | 507 | gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup", NULL); |
419 | if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir)) | 508 | if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir)) |
420 | gpio_mockup_err("error creating debugfs directory\n"); | 509 | gpio_mockup_err("error creating debugfs directory\n"); |
421 | 510 | ||