Bluetooth: hci_intel: Retrieve host-wake IRQ
An IRQ can be retrieved from the pdev resources. This irq will be used in case of LPM suspend mode to wake-up the host and resume the link. This resource can be declared as a GPIO-Interrupt which requires to be converted into IRQ. Signed-off-by: Loic Poulain <loic.poulain@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
6f558b70fb
commit
765ea3abd1
@ -31,6 +31,7 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
#include <net/bluetooth/hci_core.h>
|
#include <net/bluetooth/hci_core.h>
|
||||||
@ -48,6 +49,7 @@ struct intel_device {
|
|||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct gpio_desc *reset;
|
struct gpio_desc *reset;
|
||||||
|
int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
static LIST_HEAD(intel_device_list);
|
static LIST_HEAD(intel_device_list);
|
||||||
@ -113,6 +115,15 @@ static int intel_wait_booting(struct hci_uart *hu)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static irqreturn_t intel_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct intel_device *idev = dev_id;
|
||||||
|
|
||||||
|
dev_info(&idev->pdev->dev, "hci_intel irq\n");
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
static int intel_set_power(struct hci_uart *hu, bool powered)
|
static int intel_set_power(struct hci_uart *hu, bool powered)
|
||||||
{
|
{
|
||||||
struct list_head *p;
|
struct list_head *p;
|
||||||
@ -139,6 +150,27 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
|
|||||||
hu, dev_name(&idev->pdev->dev), powered);
|
hu, dev_name(&idev->pdev->dev), powered);
|
||||||
|
|
||||||
gpiod_set_value(idev->reset, powered);
|
gpiod_set_value(idev->reset, powered);
|
||||||
|
|
||||||
|
if (idev->irq < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (powered && device_can_wakeup(&idev->pdev->dev)) {
|
||||||
|
err = devm_request_threaded_irq(&idev->pdev->dev,
|
||||||
|
idev->irq, NULL,
|
||||||
|
intel_irq,
|
||||||
|
IRQF_ONESHOT,
|
||||||
|
"bt-host-wake", idev);
|
||||||
|
if (err) {
|
||||||
|
BT_ERR("hu %p, unable to allocate irq-%d",
|
||||||
|
hu, idev->irq);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_wakeup_enable(&idev->pdev->dev);
|
||||||
|
} else if (!powered && device_may_wakeup(&idev->pdev->dev)) {
|
||||||
|
devm_free_irq(&idev->pdev->dev, idev->irq, idev);
|
||||||
|
device_wakeup_disable(&idev->pdev->dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&intel_device_list_lock);
|
spin_unlock(&intel_device_list_lock);
|
||||||
@ -838,6 +870,31 @@ static int intel_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR(idev->reset);
|
return PTR_ERR(idev->reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idev->irq = platform_get_irq(pdev, 0);
|
||||||
|
if (idev->irq < 0) {
|
||||||
|
struct gpio_desc *host_wake;
|
||||||
|
|
||||||
|
dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
|
||||||
|
|
||||||
|
host_wake = devm_gpiod_get_optional(&pdev->dev, "host-wake",
|
||||||
|
GPIOD_IN);
|
||||||
|
if (IS_ERR(host_wake)) {
|
||||||
|
dev_err(&pdev->dev, "Unable to retrieve IRQ\n");
|
||||||
|
goto no_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
idev->irq = gpiod_to_irq(host_wake);
|
||||||
|
if (idev->irq < 0) {
|
||||||
|
dev_err(&pdev->dev, "No corresponding irq for gpio\n");
|
||||||
|
goto no_irq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only enable wake-up/irq when controller is powered */
|
||||||
|
device_set_wakeup_capable(&pdev->dev, true);
|
||||||
|
device_wakeup_disable(&pdev->dev);
|
||||||
|
|
||||||
|
no_irq:
|
||||||
platform_set_drvdata(pdev, idev);
|
platform_set_drvdata(pdev, idev);
|
||||||
|
|
||||||
/* Place this instance on the device list */
|
/* Place this instance on the device list */
|
||||||
@ -845,7 +902,8 @@ static int intel_probe(struct platform_device *pdev)
|
|||||||
list_add_tail(&idev->list, &intel_device_list);
|
list_add_tail(&idev->list, &intel_device_list);
|
||||||
spin_unlock(&intel_device_list_lock);
|
spin_unlock(&intel_device_list_lock);
|
||||||
|
|
||||||
dev_info(&pdev->dev, "registered.\n");
|
dev_info(&pdev->dev, "registered, gpio(%d)/irq(%d).\n",
|
||||||
|
desc_to_gpio(idev->reset), idev->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -854,6 +912,8 @@ static int intel_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct intel_device *idev = platform_get_drvdata(pdev);
|
struct intel_device *idev = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
device_wakeup_disable(&pdev->dev);
|
||||||
|
|
||||||
spin_lock(&intel_device_list_lock);
|
spin_lock(&intel_device_list_lock);
|
||||||
list_del(&idev->list);
|
list_del(&idev->list);
|
||||||
spin_unlock(&intel_device_list_lock);
|
spin_unlock(&intel_device_list_lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user