diff options
Diffstat (limited to 'drivers/misc/mei/vsc-tp.c')
-rw-r--r-- | drivers/misc/mei/vsc-tp.c | 80 |
1 files changed, 24 insertions, 56 deletions
diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index 267d0de5fade..5ecf99883996 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -18,6 +18,7 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/types.h> +#include <linux/workqueue.h> #include "vsc-tp.h" @@ -76,12 +77,12 @@ struct vsc_tp { atomic_t assert_cnt; wait_queue_head_t xfer_wait; + struct work_struct event_work; vsc_tp_event_cb_t event_notify; void *event_notify_context; - - /* used to protect command download */ - struct mutex mutex; + struct mutex event_notify_mutex; /* protects event_notify + context */ + struct mutex mutex; /* protects command download */ }; /* GPIO resources */ @@ -106,17 +107,19 @@ static irqreturn_t vsc_tp_isr(int irq, void *data) wake_up(&tp->xfer_wait); - return IRQ_WAKE_THREAD; + schedule_work(&tp->event_work); + + return IRQ_HANDLED; } -static irqreturn_t vsc_tp_thread_isr(int irq, void *data) +static void vsc_tp_event_work(struct work_struct *work) { - struct vsc_tp *tp = data; + struct vsc_tp *tp = container_of(work, struct vsc_tp, event_work); + + guard(mutex)(&tp->event_notify_mutex); if (tp->event_notify) tp->event_notify(tp->event_notify_context); - - return IRQ_HANDLED; } /* wakeup firmware and wait for response */ @@ -399,6 +402,8 @@ EXPORT_SYMBOL_NS_GPL(vsc_tp_need_read, "VSC_TP"); int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb, void *context) { + guard(mutex)(&tp->event_notify_mutex); + tp->event_notify = event_cb; tp->event_notify_context = context; @@ -407,37 +412,6 @@ int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb, EXPORT_SYMBOL_NS_GPL(vsc_tp_register_event_cb, "VSC_TP"); /** - * vsc_tp_request_irq - request irq for vsc_tp device - * @tp: vsc_tp device handle - */ -int vsc_tp_request_irq(struct vsc_tp *tp) -{ - struct spi_device *spi = tp->spi; - struct device *dev = &spi->dev; - int ret; - - irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY); - ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(dev), tp); - if (ret) - return ret; - - return 0; -} -EXPORT_SYMBOL_NS_GPL(vsc_tp_request_irq, "VSC_TP"); - -/** - * vsc_tp_free_irq - free irq for vsc_tp device - * @tp: vsc_tp device handle - */ -void vsc_tp_free_irq(struct vsc_tp *tp) -{ - free_irq(tp->spi->irq, tp); -} -EXPORT_SYMBOL_NS_GPL(vsc_tp_free_irq, "VSC_TP"); - -/** * vsc_tp_intr_synchronize - synchronize vsc_tp interrupt * @tp: vsc_tp device handle */ @@ -523,13 +497,15 @@ static int vsc_tp_probe(struct spi_device *spi) tp->spi = spi; irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY); - ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr, + ret = request_threaded_irq(spi->irq, NULL, vsc_tp_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), tp); if (ret) return ret; mutex_init(&tp->mutex); + mutex_init(&tp->event_notify_mutex); + INIT_WORK(&tp->event_work, vsc_tp_event_work); /* only one child acpi device */ ret = acpi_dev_for_each_child(ACPI_COMPANION(dev), @@ -552,35 +528,27 @@ static int vsc_tp_probe(struct spi_device *spi) return 0; err_destroy_lock: - mutex_destroy(&tp->mutex); - free_irq(spi->irq, tp); + cancel_work_sync(&tp->event_work); + mutex_destroy(&tp->event_notify_mutex); + mutex_destroy(&tp->mutex); + return ret; } +/* Note this is also used for shutdown */ static void vsc_tp_remove(struct spi_device *spi) { struct vsc_tp *tp = spi_get_drvdata(spi); platform_device_unregister(tp->pdev); - mutex_destroy(&tp->mutex); - free_irq(spi->irq, tp); -} - -static void vsc_tp_shutdown(struct spi_device *spi) -{ - struct vsc_tp *tp = spi_get_drvdata(spi); - - platform_device_unregister(tp->pdev); + cancel_work_sync(&tp->event_work); + mutex_destroy(&tp->event_notify_mutex); mutex_destroy(&tp->mutex); - - vsc_tp_reset(tp); - - free_irq(spi->irq, tp); } static const struct acpi_device_id vsc_tp_acpi_ids[] = { @@ -595,7 +563,7 @@ MODULE_DEVICE_TABLE(acpi, vsc_tp_acpi_ids); static struct spi_driver vsc_tp_driver = { .probe = vsc_tp_probe, .remove = vsc_tp_remove, - .shutdown = vsc_tp_shutdown, + .shutdown = vsc_tp_remove, .driver = { .name = "vsc-tp", .acpi_match_table = vsc_tp_acpi_ids, |