Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 765ea3ab authored by Loic Poulain's avatar Loic Poulain Committed by Marcel Holtmann
Browse files

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: default avatarLoic Poulain <loic.poulain@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 6f558b70
Loading
Loading
Loading
Loading
+61 −1
Original line number Original line Diff line number Diff line
@@ -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);