From: Jon Smirl <jonsmirl@gmail.com>
To: linux-kernel@vger.kernel.org, lirc-list@lists.sourceforge.net
Subject: [RFC PATCH 2/4] GPT driver for in-kernel IR support.
Date: Mon, 06 Oct 2008 15:43:10 -0400 [thread overview]
Message-ID: <20081006194310.15992.71553.stgit@terra> (raw)
In-Reply-To: <20081006194032.15992.8393.stgit@terra>
GPT is a GPIO pin that is cable able of measuring the lenght of pulses.
GPTs are common on embedded systems
---
drivers/input/ir/Kconfig | 6 +
drivers/input/ir/Makefile | 1
drivers/input/ir/ir-gpt.c | 221 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 228 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/ir/ir-gpt.c
diff --git a/drivers/input/ir/Kconfig b/drivers/input/ir/Kconfig
index 8afd2d6..b80ab31 100644
--- a/drivers/input/ir/Kconfig
+++ b/drivers/input/ir/Kconfig
@@ -11,4 +11,10 @@ menuconfig INPUT_IR
if INPUT_IR
+config IR_GPT
+ tristate "GPT Based IR Receiver"
+ default m
+ help
+ Driver for GPT-based IR receiver found on Digispeaker
+
endif
diff --git a/drivers/input/ir/Makefile b/drivers/input/ir/Makefile
index 08e6954..7082f1d 100644
--- a/drivers/input/ir/Makefile
+++ b/drivers/input/ir/Makefile
@@ -3,3 +3,4 @@
# Each configuration option enables a list of files.
+obj-$(CONFIG_IR_GPT) += ir-gpt.o
diff --git a/drivers/input/ir/ir-gpt.c b/drivers/input/ir/ir-gpt.c
new file mode 100644
index 0000000..a26abe9
--- /dev/null
+++ b/drivers/input/ir/ir-gpt.c
@@ -0,0 +1,221 @@
+/*
+ * GPT timer based IR device
+ *
+ * Copyright (C) 2008 Jon Smirl <jonsmirl@gmail.com>
+ */
+
+#define DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/input.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+
+#define MAX_SAMPLES 200
+
+struct ir_gpt {
+ int irq;
+ struct mpc52xx_gpt __iomem *regs;
+ spinlock_t lock;
+ struct work_struct queue;
+ int head, tail, previous;
+ unsigned int samples[MAX_SAMPLES];
+ struct input_dev *input;
+};
+
+static void ir_event(struct work_struct *work)
+{
+ unsigned long flags;
+ int delta, count;
+ unsigned int sample, wrap, bit;
+ struct ir_gpt *ir_gpt = container_of(work, struct ir_gpt, queue);
+
+ while (1) {
+ spin_lock_irqsave(ir_gpt->lock, flags);
+ if (ir_gpt->tail == ir_gpt->head) {
+ spin_unlock_irqrestore(ir_gpt->lock, flags);
+ break;
+ }
+ sample = ir_gpt->samples[ir_gpt->tail];
+
+ ir_gpt->tail++;
+ if (ir_gpt->tail >= MAX_SAMPLES)
+ ir_gpt->tail = 0;
+
+ spin_unlock_irqrestore(ir_gpt->lock, flags);
+
+ count = sample >> 16;
+ wrap = (sample >> 12) & 7;
+ bit = (sample >> 8) & 1;
+
+ delta = count - ir_gpt->previous;
+ delta += wrap * 0x10000;
+
+ ir_gpt->previous = count;
+
+ input_ir_decode(ir_gpt->input, delta, bit);
+ }
+}
+
+/*
+ * Interrupt handlers
+ */
+static irqreturn_t dpeak_ir_irq(int irq, void *_ir)
+{
+ unsigned long flags;
+ unsigned int sample, next;
+ struct ir_gpt *ir_gpt = _ir;
+
+ sample = in_be32(&ir_gpt->regs->status);
+ out_be32(&ir_gpt->regs->status, 0xF);
+
+ spin_lock_irqsave(ir_gpt->lock, flags);
+ ir_gpt->samples[ir_gpt->head] = sample;
+ next = ir_gpt->head + 1;
+ ir_gpt->head = (next >= MAX_SAMPLES ? 0 : next);
+ spin_unlock_irqrestore(ir_gpt->lock, flags);
+
+ schedule_work(&ir_gpt->queue);
+
+ return IRQ_HANDLED;
+}
+
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit ir_gpt_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct ir_gpt *ir_gpt;
+ struct resource res;
+ int ret, rc;
+
+ dev_dbg(&op->dev, "ir_gpt_of_probe\n");
+
+ /* Allocate and initialize the driver private data */
+ ir_gpt = kzalloc(sizeof *ir_gpt, GFP_KERNEL);
+ if (!ir_gpt)
+ return -ENOMEM;
+
+ ir_gpt->input = input_allocate_device();
+ if (!ir_gpt->input) {
+ ret = -ENOMEM;
+ goto free_mem;
+ }
+ ret = input_ir_create(ir_gpt->input, ir_gpt, NULL);
+ if (ret)
+ goto free_input;
+
+ ir_gpt->input->id.bustype = BUS_HOST;
+ ir_gpt->input->name = "GPT IR Receiver";
+
+ ir_gpt->input->irbit[0] |= BIT_MASK(IR_CAP_RECEIVE_36K);
+ ir_gpt->input->irbit[0] |= BIT_MASK(IR_CAP_RECEIVE_38K);
+ ir_gpt->input->irbit[0] |= BIT_MASK(IR_CAP_RECEIVE_40K);
+ ir_gpt->input->irbit[0] |= BIT_MASK(IR_CAP_RECEIVE_RAW);
+
+ ret = input_register_device(ir_gpt->input);
+ if (ret)
+ goto free_input;
+
+ spin_lock_init(&ir_gpt->lock);
+ INIT_WORK (&ir_gpt->queue, ir_event);
+
+ /* Fetch the registers and IRQ of the GPT */
+ if (of_address_to_resource(op->node, 0, &res)) {
+ dev_err(&op->dev, "Missing reg property\n");
+ ret = -ENODEV;
+ goto free_input;
+ }
+ ir_gpt->regs = ioremap(res.start, 1 + res.end - res.start);
+ if (!ir_gpt->regs) {
+ dev_err(&op->dev, "Could not map registers\n");
+ ret = -ENODEV;
+ goto free_input;
+ }
+ ir_gpt->irq = irq_of_parse_and_map(op->node, 0);
+ if (ir_gpt->irq == NO_IRQ) {
+ ret = -ENODEV;
+ goto free_input;
+ }
+ dev_dbg(&op->dev, "ir_gpt_of_probe irq=%d\n", ir_gpt->irq);
+
+ rc = request_irq(ir_gpt->irq, &dpeak_ir_irq, IRQF_SHARED,
+ "gpt-ir", ir_gpt);
+ dev_dbg(&op->dev, "ir_gpt_of_probe request irq rc=%d\n", rc);
+
+ /* set prescale to ? */
+ out_be32(&ir_gpt->regs->count, 0x00870000);
+
+ /* Select input capture, enable the counter, and interrupt */
+ out_be32(&ir_gpt->regs->mode, 0x0);
+ out_be32(&ir_gpt->regs->mode, 0x00000501);
+
+ /* Save what we've done so it can be found again later */
+ dev_set_drvdata(&op->dev, ir_gpt);
+
+ printk("GPT IR Receiver driver\n");
+
+ return 0;
+
+free_input:
+ input_ir_destroy(ir_gpt->input);
+ input_free_device(ir_gpt->input);
+free_mem:
+ kfree(ir_gpt);
+ return ret;
+}
+
+static int __devexit ir_gpt_of_remove(struct of_device *op)
+{
+ struct ir_gpt *ir_gpt = dev_get_drvdata(&op->dev);
+
+ dev_dbg(&op->dev, "ir_gpt_remove()\n");
+
+ input_ir_destroy(ir_gpt->input);
+ input_free_device(ir_gpt->input);
+ kfree(ir_gpt);
+ dev_set_drvdata(&op->dev, NULL);
+
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id ir_gpt_match[] __devinitdata = {
+ { .compatible = "gpt-ir", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ir_gpt_match);
+
+static struct of_platform_driver ir_gpt_driver = {
+ .match_table = ir_gpt_match,
+ .probe = ir_gpt_of_probe,
+ .remove = __devexit_p(ir_gpt_of_remove),
+ .driver = {
+ .name = "ir-gpt",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ */
+static int __init ir_gpt_init(void)
+{
+ return of_register_platform_driver(&ir_gpt_driver);
+}
+module_init(ir_gpt_init);
+
+static void __exit ir_gpt_exit(void)
+{
+ of_unregister_platform_driver(&ir_gpt_driver);
+}
+module_exit(ir_gpt_exit);
next prev parent reply other threads:[~2008-10-06 19:43 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-10-06 19:43 [RFC PATCH 0/4] V3 - Implementation of IR support using the input subsystem Jon Smirl
2008-10-06 19:43 ` [RFC PATCH 1/4] Changes to core input subsystem to allow send and receive of IR messages. Encode and decode state machines are provided for common IR porotocols such as Sony, JVC, NEC, Philips, etc Jon Smirl
2009-05-28 23:23 ` Maxim Levitsky
2009-05-29 1:15 ` Jon Smirl
2008-10-06 19:43 ` Jon Smirl [this message]
2008-10-06 19:43 ` [RFC PATCH 3/4] Example of PowerPC device tree support for GPT based IR Jon Smirl
2008-10-06 19:43 ` [RFC PATCH 4/4] Microsoft mceusb2 driver for in-kernel IR subsystem Jon Smirl
2008-10-06 19:46 ` [RFC PATCH 0/4] V3 - Implementation of IR support using the input subsystem Jon Smirl
2008-10-09 12:03 ` Pavel Machek
2008-10-10 4:11 ` Jarod Wilson
2008-10-10 5:04 ` Jon Smirl
2008-10-10 13:42 ` Jarod Wilson
2008-10-10 14:08 ` Jon Smirl
2008-10-10 21:10 ` Jarod Wilson
2009-05-28 15:06 ` Maxim Levitsky
2009-05-28 15:58 ` Maxim Levitsky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20081006194310.15992.71553.stgit@terra \
--to=jonsmirl@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lirc-list@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox