[PATCH linux v2 1/2] misc/bt-host: Add facility for interrupt-driven BT messages
OpenBMC Patches
openbmc-patches at stwcx.xyz
Wed Nov 18 15:10:18 AEDT 2015
From: Jeremy Kerr <jk at ozlabs.org>
This change adds a facility for the bt-host driver to use interrupts
rather than polling via a timer.
If we find an interrupts property in the device tree, we'll enable
interrupts on the bt device.
Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
---
arch/arm/boot/dts/ast2400.dtsi | 1 +
drivers/misc/bt-host.c | 74 ++++++++++++++++++++++++++++++++++++++----
2 files changed, 69 insertions(+), 6 deletions(-)
diff --git a/arch/arm/boot/dts/ast2400.dtsi b/arch/arm/boot/dts/ast2400.dtsi
index d924ac1..6a09125 100644
--- a/arch/arm/boot/dts/ast2400.dtsi
+++ b/arch/arm/boot/dts/ast2400.dtsi
@@ -87,6 +87,7 @@
ibt at 1e789140 {
compatible = "aspeed,bt-host";
reg = <0x1e789140 0x18>;
+ interrupts = <8>;
};
i2c: i2c at 1e78a040 {
diff --git a/drivers/misc/bt-host.c b/drivers/misc/bt-host.c
index bf1e4ac..7b5206e 100644
--- a/drivers/misc/bt-host.c
+++ b/drivers/misc/bt-host.c
@@ -8,8 +8,10 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/timer.h>
@@ -28,7 +30,11 @@
#define BT_CR0_EN_CLR_SLV_WRP 0x4
#define BT_CR0_ENABLE_IBT 0x1
#define BT_CR1 0x4
+#define BT_CR1_IRQ_H2B 0x01
+#define BT_CR1_IRQ_HBUSY 0x40
#define BT_CR2 0x8
+#define BT_CR2_IRQ_H2B 0x01
+#define BT_CR2_IRQ_HBUSY 0x40
#define BT_CR3 0xc
#define BT_CTRL 0x10
#define BT_CTRL_B_BUSY 0x80
@@ -50,6 +56,7 @@ struct bt_host {
struct miscdevice miscdev;
void *base;
int open_count;
+ int irq;
wait_queue_head_t queue;
struct timer_list poll_timer;
};
@@ -253,6 +260,53 @@ static void poll_timer(unsigned long data)
add_timer(&bt_host->poll_timer);
}
+irqreturn_t bt_host_irq(int irq, void *arg)
+{
+ struct bt_host *bt_host = arg;
+ uint32_t reg;
+
+ reg = ioread32(bt_host->base + BT_CR2);
+ reg &= BT_CR2_IRQ_H2B | BT_CR2_IRQ_HBUSY;
+ if (!reg)
+ return IRQ_NONE;
+
+ /* ack pending IRQs */
+ iowrite32(reg, bt_host->base + BT_CR2);
+
+ wake_up(&bt_host->queue);
+ return IRQ_HANDLED;
+}
+
+static int bt_host_config_irq(struct bt_host *bt_host,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ uint32_t reg;
+ int rc;
+
+ bt_host->irq = irq_of_parse_and_map(dev->of_node, 0);
+ if (!bt_host->irq)
+ return -ENODEV;
+
+ rc = devm_request_irq(dev, bt_host->irq, bt_host_irq, IRQF_SHARED,
+ DEVICE_NAME, bt_host);
+ if (rc < 0) {
+ dev_warn(dev, "Unable to request IRQ %d\n", bt_host->irq);
+ bt_host->irq = 0;
+ return rc;
+ }
+
+ /* Configure IRQs on the host clearing the H2B and HBUSY bits;
+ * H2B will be asserted when the host has data for us; HBUSY
+ * will be cleared (along with B2H) when we can write the next
+ * message to the BT buffer */
+ reg = ioread32(bt_host->base + BT_CR1);
+ reg |= BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY;
+ iowrite32(reg, bt_host->base + BT_CR1);
+
+ return 0;
+}
+
static int bt_host_probe(struct platform_device *pdev)
{
struct bt_host *bt_host;
@@ -298,11 +352,18 @@ static int bt_host_probe(struct platform_device *pdev)
goto out_unmap;
}
- init_timer(&bt_host->poll_timer);
- bt_host->poll_timer.function = poll_timer;
- bt_host->poll_timer.data = (unsigned long)bt_host;
- bt_host->poll_timer.expires = jiffies + msecs_to_jiffies(10);
- add_timer(&bt_host->poll_timer);
+ bt_host_config_irq(bt_host, pdev);
+
+ if (bt_host->irq) {
+ dev_info(dev, "Using IRQ %d\n", bt_host->irq);
+ } else {
+ dev_info(dev, "No IRQ; using timer\n");
+ init_timer(&bt_host->poll_timer);
+ bt_host->poll_timer.function = poll_timer;
+ bt_host->poll_timer.data = (unsigned long)bt_host;
+ bt_host->poll_timer.expires = jiffies + msecs_to_jiffies(10);
+ add_timer(&bt_host->poll_timer);
+ }
iowrite32((BT_IO_BASE << BT_CR0_IO_BASE) |
(BT_IRQ << BT_CR0_IRQ) |
@@ -327,8 +388,9 @@ out_free:
static int bt_host_remove(struct platform_device *pdev)
{
struct bt_host *bt_host = dev_get_drvdata(&pdev->dev);
- del_timer_sync(&bt_host->poll_timer);
misc_deregister(&bt_host->miscdev);
+ if (!bt_host->irq)
+ del_timer_sync(&bt_host->poll_timer);
devm_iounmap(&pdev->dev, bt_host->base);
devm_kfree(&pdev->dev, bt_host);
bt_host = NULL;
--
2.6.3
More information about the openbmc
mailing list