summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/gpio-mockup.c117
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 {
47struct gpio_mockup_line_status { 47struct gpio_mockup_line_status {
48 int dir; 48 int dir;
49 int value; 49 int value;
50 int pull;
50}; 51};
51 52
52struct gpio_mockup_chip { 53struct 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
191static ssize_t gpio_mockup_event_write(struct file *file, 192static 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
199static 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
228static 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
277out:
278 chip->lines[priv->offset].pull = val;
279 mutex_unlock(&chip->lock);
214 280
215 return size; 281 return size;
216} 282}
217 283
218static int gpio_mockup_event_open(struct inode *inode, struct file *file) 284static 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
223static 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 */
310static 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
268err: 356err:
269 dev_err(dev, "error creating debugfs event files\n"); 357 dev_err(dev, "error creating debugfs files\n");
270} 358}
271 359
272static int gpio_mockup_name_lines(struct device *dev, 360static 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