diff options
Diffstat (limited to 'drivers/misc/mei/vsc-tp.c')
-rw-r--r-- | drivers/misc/mei/vsc-tp.c | 113 |
1 files changed, 75 insertions, 38 deletions
diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index 55f7db490d3b..e6a98dba8a73 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -25,7 +25,8 @@ #define VSC_TP_ROM_BOOTUP_DELAY_MS 10 #define VSC_TP_ROM_XFER_POLL_TIMEOUT_US (500 * USEC_PER_MSEC) #define VSC_TP_ROM_XFER_POLL_DELAY_US (20 * USEC_PER_MSEC) -#define VSC_TP_WAIT_FW_ASSERTED_TIMEOUT (2 * HZ) +#define VSC_TP_WAIT_FW_POLL_TIMEOUT (2 * HZ) +#define VSC_TP_WAIT_FW_POLL_DELAY_US (20 * USEC_PER_MSEC) #define VSC_TP_MAX_XFER_COUNT 5 #define VSC_TP_PACKET_SYNC 0x31 @@ -93,6 +94,27 @@ static const struct acpi_gpio_mapping vsc_tp_acpi_gpios[] = { {} }; +static irqreturn_t vsc_tp_isr(int irq, void *data) +{ + struct vsc_tp *tp = data; + + atomic_inc(&tp->assert_cnt); + + wake_up(&tp->xfer_wait); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t vsc_tp_thread_isr(int irq, void *data) +{ + struct vsc_tp *tp = data; + + if (tp->event_notify) + tp->event_notify(tp->event_notify_context); + + return IRQ_HANDLED; +} + /* wakeup firmware and wait for response */ static int vsc_tp_wakeup_request(struct vsc_tp *tp) { @@ -101,13 +123,15 @@ static int vsc_tp_wakeup_request(struct vsc_tp *tp) gpiod_set_value_cansleep(tp->wakeupfw, 0); ret = wait_event_timeout(tp->xfer_wait, - atomic_read(&tp->assert_cnt) && - gpiod_get_value_cansleep(tp->wakeuphost), - VSC_TP_WAIT_FW_ASSERTED_TIMEOUT); + atomic_read(&tp->assert_cnt), + VSC_TP_WAIT_FW_POLL_TIMEOUT); if (!ret) return -ETIMEDOUT; - return 0; + return read_poll_timeout(gpiod_get_value_cansleep, ret, ret, + VSC_TP_WAIT_FW_POLL_DELAY_US, + VSC_TP_WAIT_FW_POLL_TIMEOUT, false, + tp->wakeuphost); } static void vsc_tp_wakeup_release(struct vsc_tp *tp) @@ -381,6 +405,37 @@ 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 */ @@ -410,27 +465,6 @@ void vsc_tp_intr_disable(struct vsc_tp *tp) } EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_disable, VSC_TP); -static irqreturn_t vsc_tp_isr(int irq, void *data) -{ - struct vsc_tp *tp = data; - - atomic_inc(&tp->assert_cnt); - - wake_up(&tp->xfer_wait); - - return IRQ_WAKE_THREAD; -} - -static irqreturn_t vsc_tp_thread_isr(int irq, void *data) -{ - struct vsc_tp *tp = data; - - if (tp->event_notify) - tp->event_notify(tp->event_notify_context); - - return IRQ_HANDLED; -} - static int vsc_tp_match_any(struct acpi_device *adev, void *data) { struct acpi_device **__adev = data; @@ -442,11 +476,16 @@ static int vsc_tp_match_any(struct acpi_device *adev, void *data) static int vsc_tp_probe(struct spi_device *spi) { - struct platform_device_info pinfo = { 0 }; + struct vsc_tp *tp; + struct platform_device_info pinfo = { + .name = "intel_vsc", + .data = &tp, + .size_data = sizeof(tp), + .id = PLATFORM_DEVID_NONE, + }; struct device *dev = &spi->dev; struct platform_device *pdev; struct acpi_device *adev; - struct vsc_tp *tp; int ret; tp = devm_kzalloc(dev, sizeof(*tp), GFP_KERNEL); @@ -482,10 +521,9 @@ static int vsc_tp_probe(struct spi_device *spi) tp->spi = spi; irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY); - ret = devm_request_threaded_irq(dev, spi->irq, vsc_tp_isr, - vsc_tp_thread_isr, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(dev), tp); + 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; @@ -498,13 +536,8 @@ static int vsc_tp_probe(struct spi_device *spi) ret = -ENODEV; goto err_destroy_lock; } - pinfo.fwnode = acpi_fwnode_handle(adev); - - pinfo.name = "intel_vsc"; - pinfo.data = &tp; - pinfo.size_data = sizeof(tp); - pinfo.id = PLATFORM_DEVID_NONE; + pinfo.fwnode = acpi_fwnode_handle(adev); pdev = platform_device_register_full(&pinfo); if (IS_ERR(pdev)) { ret = PTR_ERR(pdev); @@ -519,6 +552,8 @@ static int vsc_tp_probe(struct spi_device *spi) err_destroy_lock: mutex_destroy(&tp->mutex); + free_irq(spi->irq, tp); + return ret; } @@ -529,6 +564,8 @@ static void vsc_tp_remove(struct spi_device *spi) platform_device_unregister(tp->pdev); mutex_destroy(&tp->mutex); + + free_irq(spi->irq, tp); } static const struct acpi_device_id vsc_tp_acpi_ids[] = { |