diff options
Diffstat (limited to 'drivers/staging/iio/trigger')
-rw-r--r-- | drivers/staging/iio/trigger/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/iio/trigger/iio-trig-bfin-timer.c | 109 | ||||
-rw-r--r-- | drivers/staging/iio/trigger/iio-trig-bfin-timer.h | 24 | ||||
-rw-r--r-- | drivers/staging/iio/trigger/iio-trig-gpio.c | 8 | ||||
-rw-r--r-- | drivers/staging/iio/trigger/iio-trig-periodic-rtc.c | 8 | ||||
-rw-r--r-- | drivers/staging/iio/trigger/iio-trig-sysfs.c | 17 |
6 files changed, 138 insertions, 30 deletions
diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig index b8abf5473ddc..7d3207559265 100644 --- a/drivers/staging/iio/trigger/Kconfig +++ b/drivers/staging/iio/trigger/Kconfig @@ -21,6 +21,8 @@ config IIO_GPIO_TRIGGER config IIO_SYSFS_TRIGGER tristate "SYSFS trigger" depends on SYSFS + depends on HAVE_IRQ_WORK + select IRQ_WORK help Provides support for using SYSFS entry as IIO triggers. If unsure, say N (but it's safe to say "Y"). diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c index ce6a7b1b8860..52062d786f84 100644 --- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c @@ -14,14 +14,18 @@ #include <linux/delay.h> #include <asm/gptimers.h> +#include <asm/portmux.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> +#include "iio-trig-bfin-timer.h" + struct bfin_timer { unsigned short id, bit; unsigned long irqbit; int irq; + int pin; }; /* @@ -30,22 +34,22 @@ struct bfin_timer { */ static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = { - {TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0}, - {TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1}, - {TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2}, + {TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0, P_TMR0}, + {TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1, P_TMR1}, + {TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2, P_TMR2}, #if (MAX_BLACKFIN_GPTIMERS > 3) - {TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3}, - {TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4}, - {TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5}, - {TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6}, - {TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7}, + {TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3, P_TMR3}, + {TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4, P_TMR4}, + {TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5, P_TMR5}, + {TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6, P_TMR6}, + {TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7, P_TMR7}, #endif #if (MAX_BLACKFIN_GPTIMERS > 8) - {TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8}, - {TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9}, - {TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10}, + {TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8, P_TMR8}, + {TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9, P_TMR9}, + {TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10, P_TMR10}, #if (MAX_BLACKFIN_GPTIMERS > 11) - {TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11}, + {TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11, P_TMR11}, #endif #endif }; @@ -54,15 +58,33 @@ struct bfin_tmr_state { struct iio_trigger *trig; struct bfin_timer *t; unsigned timer_num; + bool output_enable; + unsigned int duty; int irq; }; +static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state) +{ + struct bfin_tmr_state *st = trig->private_data; + + if (get_gptimer_period(st->t->id) == 0) + return -EINVAL; + + if (state) + enable_gptimers(st->t->bit); + else + disable_gptimers(st->t->bit); + + return 0; +} + static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct iio_trigger *trig = to_iio_trigger(dev); struct bfin_tmr_state *st = trig->private_data; - long val; + unsigned long val; + bool enabled; int ret; ret = strict_strtoul(buf, 10, &val); @@ -74,20 +96,25 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, goto error_ret; } - disable_gptimers(st->t->bit); + enabled = get_enabled_gptimers() & st->t->bit; + + if (enabled) + disable_gptimers(st->t->bit); if (!val) goto error_ret; val = get_sclk() / val; - if (val <= 4) { + if (val <= 4 || val <= st->duty) { ret = -EINVAL; goto error_ret; } set_gptimer_period(st->t->id, val); - set_gptimer_pwidth(st->t->id, 1); - enable_gptimers(st->t->bit); + set_gptimer_pwidth(st->t->id, val - st->duty); + + if (enabled) + enable_gptimers(st->t->bit); error_ret: return ret ? ret : count; @@ -99,9 +126,15 @@ static ssize_t iio_bfin_tmr_frequency_show(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct bfin_tmr_state *st = trig->private_data; + unsigned int period = get_gptimer_period(st->t->id); + unsigned long val; + + if (period == 0) + val = 0; + else + val = get_sclk() / get_gptimer_period(st->t->id); - return sprintf(buf, "%lu\n", - get_sclk() / get_gptimer_period(st->t->id)); + return sprintf(buf, "%lu\n", val); } static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show, @@ -121,7 +154,6 @@ static const struct attribute_group *iio_bfin_tmr_trigger_attr_groups[] = { NULL }; - static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid) { struct bfin_tmr_state *st = devid; @@ -145,11 +177,14 @@ static int iio_bfin_tmr_get_number(int irq) static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = { .owner = THIS_MODULE, + .set_trigger_state = iio_bfin_tmr_set_state, }; static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) { + struct iio_bfin_timer_trigger_pdata *pdata = pdev->dev.platform_data; struct bfin_tmr_state *st; + unsigned int config; int ret; st = kzalloc(sizeof(*st), GFP_KERNEL); @@ -193,13 +228,43 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) goto out4; } - set_gptimer_config(st->t->id, OUT_DIS | PWM_OUT | PERIOD_CNT | IRQ_ENA); + config = PWM_OUT | PERIOD_CNT | IRQ_ENA; + + if (pdata && pdata->output_enable) { + unsigned long long val; + + st->output_enable = true; + + ret = peripheral_request(st->t->pin, st->trig->name); + if (ret) + goto out_free_irq; + + val = (unsigned long long)get_sclk() * pdata->duty_ns; + do_div(val, NSEC_PER_SEC); + st->duty = val; + + /** + * The interrupt will be generated at the end of the period, + * since we want the interrupt to be generated at end of the + * pulse we invert both polarity and duty cycle, so that the + * pulse will be generated directly before the interrupt. + */ + if (pdata->active_low) + config |= PULSE_HI; + } else { + st->duty = 1; + config |= OUT_DIS; + } + + set_gptimer_config(st->t->id, config); dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d", st->timer_num, st->irq); platform_set_drvdata(pdev, st); return 0; +out_free_irq: + free_irq(st->irq, st); out4: iio_trigger_unregister(st->trig); out2: @@ -215,6 +280,8 @@ static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev) struct bfin_tmr_state *st = platform_get_drvdata(pdev); disable_gptimers(st->t->bit); + if (st->output_enable) + peripheral_free(st->t->pin); free_irq(st->irq, st); iio_trigger_unregister(st->trig); iio_trigger_put(st->trig); diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.h b/drivers/staging/iio/trigger/iio-trig-bfin-timer.h new file mode 100644 index 000000000000..c07321f8d94c --- /dev/null +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.h @@ -0,0 +1,24 @@ +#ifndef __IIO_BFIN_TIMER_TRIGGER_H__ +#define __IIO_BFIN_TIMER_TRIGGER_H__ + +/** + * struct iio_bfin_timer_trigger_pdata - timer trigger platform data + * @output_enable: Enable external trigger pulse generation. + * @active_low: Whether the trigger pulse is active low. + * @duty_ns: Length of the trigger pulse in nanoseconds. + * + * This struct is used to configure the output pulse generation of the blackfin + * timer trigger. If output_enable is set to true an external trigger signal + * will generated on the pin corresponding to the timer. This is useful for + * converters which needs an external signal to start conversion. active_low and + * duty_ns are used to configure the type of the trigger pulse. If output_enable + * is set to false no external trigger pulse will be generated and active_low + * and duty_ns are ignored. + **/ +struct iio_bfin_timer_trigger_pdata { + bool output_enable; + bool active_low; + unsigned int duty_ns; +}; + +#endif diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c index 90b26846fc6b..5ff4d7fa20fa 100644 --- a/drivers/staging/iio/trigger/iio-trig-gpio.c +++ b/drivers/staging/iio/trigger/iio-trig-gpio.c @@ -51,7 +51,7 @@ static const struct iio_trigger_ops iio_gpio_trigger_ops = { .owner = THIS_MODULE, }; -static int iio_gpio_trigger_probe(struct platform_device *pdev) +static int __devinit iio_gpio_trigger_probe(struct platform_device *pdev) { struct iio_gpio_trigger_info *trig_info; struct iio_trigger *trig, *trig2; @@ -130,7 +130,7 @@ error_free_completed_registrations: return ret; } -static int iio_gpio_trigger_remove(struct platform_device *pdev) +static int __devexit iio_gpio_trigger_remove(struct platform_device *pdev) { struct iio_trigger *trig, *trig2; struct iio_gpio_trigger_info *trig_info; @@ -153,7 +153,7 @@ static int iio_gpio_trigger_remove(struct platform_device *pdev) static struct platform_driver iio_gpio_trigger_driver = { .probe = iio_gpio_trigger_probe, - .remove = iio_gpio_trigger_remove, + .remove = __devexit_p(iio_gpio_trigger_remove), .driver = { .name = "iio_gpio_trigger", .owner = THIS_MODULE, @@ -162,6 +162,6 @@ static struct platform_driver iio_gpio_trigger_driver = { module_platform_driver(iio_gpio_trigger_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 4ceaa18ef9f4..a3de76d70cdc 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -101,7 +101,7 @@ static const struct iio_trigger_ops iio_prtc_trigger_ops = { .set_trigger_state = &iio_trig_periodic_rtc_set_state, }; -static int iio_trig_periodic_rtc_probe(struct platform_device *dev) +static int __devinit iio_trig_periodic_rtc_probe(struct platform_device *dev) { char **pdata = dev->dev.platform_data; struct iio_prtc_trigger_info *trig_info; @@ -167,7 +167,7 @@ error_free_completed_registrations: return ret; } -static int iio_trig_periodic_rtc_remove(struct platform_device *dev) +static int __devexit iio_trig_periodic_rtc_remove(struct platform_device *dev) { struct iio_trigger *trig, *trig2; struct iio_prtc_trigger_info *trig_info; @@ -188,7 +188,7 @@ static int iio_trig_periodic_rtc_remove(struct platform_device *dev) static struct platform_driver iio_trig_periodic_rtc_driver = { .probe = iio_trig_periodic_rtc_probe, - .remove = iio_trig_periodic_rtc_remove, + .remove = __devexit_p(iio_trig_periodic_rtc_remove), .driver = { .name = "iio_prtc_trigger", .owner = THIS_MODULE, @@ -197,6 +197,6 @@ static struct platform_driver iio_trig_periodic_rtc_driver = { module_platform_driver(iio_trig_periodic_rtc_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Periodic realtime clock trigger for the iio subsystem"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c index fee474648108..3bac97224bf4 100644 --- a/drivers/staging/iio/trigger/iio-trig-sysfs.c +++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c @@ -10,12 +10,14 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/list.h> +#include <linux/irq_work.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> struct iio_sysfs_trig { struct iio_trigger *trig; + struct irq_work work; int id; struct list_head l; }; @@ -89,11 +91,21 @@ static struct device iio_sysfs_trig_dev = { .release = &iio_trigger_sysfs_release, }; +static void iio_sysfs_trigger_work(struct irq_work *work) +{ + struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig, + work); + + iio_trigger_poll(trig->trig, 0); +} + static ssize_t iio_sysfs_trigger_poll(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct iio_trigger *trig = to_iio_trigger(dev); - iio_trigger_poll_chained(trig, 0); + struct iio_sysfs_trig *sysfs_trig = trig->private_data; + + irq_work_queue(&sysfs_trig->work); return count; } @@ -148,6 +160,9 @@ static int iio_sysfs_trigger_probe(int id) t->trig->dev.groups = iio_sysfs_trigger_attr_groups; t->trig->ops = &iio_sysfs_trigger_ops; t->trig->dev.parent = &iio_sysfs_trig_dev; + t->trig->private_data = t; + + init_irq_work(&t->work, iio_sysfs_trigger_work); ret = iio_trigger_register(t->trig); if (ret) |