diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig
index 526ec0f..f57464a 100644
--- a/drivers/staging/media/lirc/Kconfig
+++ b/drivers/staging/media/lirc/Kconfig
@@ -75,4 +75,13 @@ config LIRC_ZILOG
 	help
 	  Driver for the Zilog/Hauppauge IR Transmitter, found on
 	  PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards
+
+config LIRC_GPIO
+	tristate "LIRC GPIO receiver/transmitter"
+	depends on LIRC && GPIOLIB
+	help
+	  Driver for GPIOLIB enabled gpio chip. Module setup for and tested
+	  on Allwinner A10 Gpio SOC.
+	  change/redefine LIRC_GPIO_ID_STRING to the correct gpiochip label
+
 endif
diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile
index d76b0fa..e729ad0 100644
--- a/drivers/staging/media/lirc/Makefile
+++ b/drivers/staging/media/lirc/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_LIRC_SERIAL)	+= lirc_serial.o
 obj-$(CONFIG_LIRC_SIR)		+= lirc_sir.o
 obj-$(CONFIG_LIRC_TTUSBIR)	+= lirc_ttusbir.o
 obj-$(CONFIG_LIRC_ZILOG)	+= lirc_zilog.o
+obj-$(CONFIG_LIRC_GPIO)		+= lirc_gpio.o
diff --git a/drivers/staging/media/lirc/lirc_gpio.c b/drivers/staging/media/lirc/lirc_gpio.c
new file mode 100644
index 0000000..2e7fbbe
--- /dev/null
+++ b/drivers/staging/media/lirc/lirc_gpio.c
@@ -0,0 +1,953 @@
+/*
+ * lirc_gpio.c
+ *
+ * lirc_gpio - Device driver that records pulse- and pause-lengths
+ *              (space-lengths) (just like the lirc_serial driver does)
+ *              between GPIO interrupt events.  Tested on a Cubieboard with Allwinner A10
+ *        However, everything relies on the gpiolib.c module, so there is a good
+ *        chance it will also run on other platforms.
+ *              Lots of code has been taken from the lirc_rpi module, who in turn took a
+ *        lot of code from the lirc_serial module,
+ *              so I would like say thanks to the authors.
+ *
+ * Copyright (C) 2013 Matthias Hölling <mhoel....@gmail.nospam.com>,
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <linux/gpio.h>
+
+#define LIRC_DRIVER_NAME "lirc_gpio"
+/* this may have to be adapted for different platforms */
+#define LIRC_GPIO_ID_STRING "A1X_GPIO"
+#define RBUF_LEN 256
+#define LIRC_TRANSMITTER_LATENCY 256
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+#define RX_OFFSET_GPIOCHIP gpio_in_pin - gpiochip->base
+#define TX_OFFSET_GPIOCHIP gpio_out_pin - gpiochip->base
+
+#define dprintk(fmt, args...)                                        \
+do {                                                        \
+if (debug)                                        \
+printk(KERN_DEBUG LIRC_DRIVER_NAME ": "        \
+fmt, ## args);                        \
+} while (0)
+
+/* module parameters */
+
+/* set the default GPIO input pins, 3 channels */
+static int gpio_in_pin = 0;
+/* -1 = auto, 0 = active high, 1 = active low */
+static int sense = -1;
+static struct timeval lasttv = { 0, 0 };
+static spinlock_t lock;
+
+/* set the default GPIO output pin, 4 channels */
+static int gpio_out_pin = 0;
+/* enable debugging messages */
+static int debug;
+/* use softcarrier by default */
+static int softcarrier = 1;
+/* 0 = do not invert output, 1 = invert output */
+static int invert = 0;
+
+/* is the device open, so interrupt must be changed if pins are changed */
+static int device_open = 0;
+
+struct gpio_chip *gpiochip=NULL;
+struct irq_chip *irqchip=NULL;
+struct irq_data *irqdata=NULL;
+
+/* forward declarations */
+static long send_pulse(unsigned long length);
+static void send_space(long length);
+static void lirc_gpio_exit(void);
+
+static struct platform_device *lirc_gpio_dev;
+static struct lirc_buffer rbuf;
+
+/* initialized/set in init_timing_params() */
+static unsigned int freq = 38000;
+static unsigned int duty_cycle = 50;
+static unsigned long period;
+static unsigned long pulse_width;
+static unsigned long space_width;
+
+
+/* stuff for TX pin */
+
+static void safe_udelay(unsigned long usecs)
+{
+        while (usecs > MAX_UDELAY_US) {
+                udelay(MAX_UDELAY_US);
+                usecs -= MAX_UDELAY_US;
+        }
+        udelay(usecs);
+}
+
+static int init_timing_params(unsigned int new_duty_cycle,
+                              unsigned int new_freq)
+{
+        /*
+         * period, pulse/space width are kept with 8 binary places -
+         * IE multiplied by 256.
+         */
+        if (256 * 1000000L / new_freq * new_duty_cycle / 100 <=
+            LIRC_TRANSMITTER_LATENCY)
+                return -EINVAL;
+        if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
+            LIRC_TRANSMITTER_LATENCY)
+                return -EINVAL;
+        duty_cycle = new_duty_cycle;
+        freq = new_freq;
+        period = 256 * 1000000L / freq;
+        pulse_width = period * duty_cycle / 100;
+        space_width = period - pulse_width;
+        /*printk(KERN_INFO "in init_timing_params, freq=%d pulse=%ld, "
+           "space=%ld\n", freq, pulse_width, space_width); */
+        return 0;
+}
+
+static long send_pulse_softcarrier(unsigned long length)
+{
+        int flag;
+        unsigned long actual, target, d;
+
+        length <<= 8;
+
+        actual = 0; target = 0; flag = 0;
+        while (actual < length) {
+                if (flag) {
+                        gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, invert);
+                        target += space_width;
+                } else {
+                        gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, !invert);
+                        target += pulse_width;
+                }
+                d = (target - actual -
+                     LIRC_TRANSMITTER_LATENCY + 128) >> 8;
+                /*
+                 * Note - we've checked in ioctl that the pulse/space
+                 * widths are big enough so that d is > 0
+                 */
+                udelay(d);
+                actual += (d << 8) + LIRC_TRANSMITTER_LATENCY;
+                flag = !flag;
+        }
+        return (actual-length) >> 8;
+}
+
+static long send_pulse(unsigned long length)
+{
+        if (length <= 0)
+                return 0;
+
+        if (softcarrier) {
+                return send_pulse_softcarrier(length);
+        } else {
+                gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, !invert);
+                safe_udelay(length);
+                return 0;
+        }
+}
+
+
+static void send_space(long length)
+{
+        gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, invert);
+        if (length <= 0)
+                return;
+        safe_udelay(length);
+}
+
+/* end of TX stuff */
+
+
+
+/* RX stuff: Handle interrupt and write vals to lirc buffer */
+
+static void rbwrite(int l)
+{
+        if (lirc_buffer_full(&rbuf)) {
+                /* no new signals will be accepted */
+                dprintk("Buffer overrun\n");
+                return;
+        }
+        lirc_buffer_write(&rbuf, (void *)&l);
+}
+
+static void frbwrite(int l)
+{
+        /* simple noise filter */
+        static int pulse, space;
+        static unsigned int ptr;
+
+        if (ptr > 0 && (l & PULSE_BIT)) {
+                pulse += l & PULSE_MASK;
+                if (pulse > 250) {
+                        rbwrite(space);
+                        rbwrite(pulse | PULSE_BIT);
+                        ptr = 0;
+                        pulse = 0;
+                }
+                return;
+        }
+        if (!(l & PULSE_BIT)) {
+                if (ptr == 0) {
+                        if (l > 20000) {
+                                space = l;
+                                ptr++;
+                                return;
+                        }
+                } else {
+                        if (l > 20000) {
+                                space += pulse;
+                                if (space > PULSE_MASK)
+                                        space = PULSE_MASK;
+                                space += l;
+                                if (space > PULSE_MASK)
+                                        space = PULSE_MASK;
+                                pulse = 0;
+                                return;
+                        }
+                        rbwrite(space);
+                        rbwrite(pulse | PULSE_BIT);
+                        ptr = 0;
+                        pulse = 0;
+                }
+        }
+        rbwrite(l);
+}
+
+static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs)
+{
+        struct timeval tv;
+        long deltv;
+        int data;
+        int signal;
+
+        /* use the GPIO signal level */
+        signal = gpiochip->get(gpiochip, RX_OFFSET_GPIOCHIP);
+
+        /* unmask the irq */
+        irqchip->irq_unmask(irqdata);
+
+        if (sense != -1) {
+                /* get current time */
+                do_gettimeofday(&tv);
+
+                /* calc time since last interrupt in microseconds */
+                deltv = tv.tv_sec-lasttv.tv_sec;
+                if (tv.tv_sec < lasttv.tv_sec ||
+                    (tv.tv_sec == lasttv.tv_sec &&
+                     tv.tv_usec < lasttv.tv_usec)) {
+                printk(KERN_WARNING LIRC_DRIVER_NAME
+                       ": AIEEEE: your clock just jumped backwards\n");
+                printk(KERN_WARNING LIRC_DRIVER_NAME
+                       ": %d %d %lx %lx %lx %lx\n", signal, sense,
+                       tv.tv_sec, lasttv.tv_sec,
+                       tv.tv_usec, lasttv.tv_usec);
+                data = PULSE_MASK;
+            } else if (deltv > 15) {
+                data = PULSE_MASK; /* really long time */
+                if (!(signal^sense)) {
+                    /* sanity check */
+                    printk(KERN_WARNING LIRC_DRIVER_NAME
+                           ": AIEEEE: %d %d %lx %lx %lx %lx\n",
+                           signal, sense, tv.tv_sec, lasttv.tv_sec,
+                           tv.tv_usec, lasttv.tv_usec);
+                    /*
+                     * detecting pulse while this
+                     * MUST be a space!
+                     */
+                    sense = sense ? 0 : 1;
+                }
+            } else {
+                data = (int) (deltv*1000000 +
+                              (tv.tv_usec - lasttv.tv_usec));
+            }
+                frbwrite(signal^sense ? data : (data|PULSE_BIT));
+                lasttv = tv;
+                wake_up_interruptible(&rbuf.wait_poll);
+        }
+
+        return IRQ_HANDLED;
+}
+
+/*  end of rx stuff */
+
+
+/* setup pins, rx, tx, interrupts, active low/high.... */
+
+static void set_sense(void)
+{
+    int i,nlow, nhigh;
+    if (gpio_in_pin==0) {
+        return;  // no rx
+    }
+    if (sense == -1) {
+        /* wait 1/10 sec for the power supply */
+        msleep(100);
+
+        /*
+         * probe 9 times every 0.04s, collect "votes" for
+         * active high/low
+         */
+        nlow = 0;
+        nhigh = 0;
+        for (i = 0; i < 9; i++) {
+            if (gpiochip->get(gpiochip, RX_OFFSET_GPIOCHIP))
+                nlow++;
+            else
+                nhigh++;
+            msleep(40);
+        }
+        sense = (nlow >= nhigh ? 1 : 0);
+        printk(KERN_INFO LIRC_DRIVER_NAME
+               ": auto-detected active %s receiver on GPIO pin %d\n",
+               sense ? "low" : "high", gpio_in_pin);
+    } else {
+        printk(KERN_INFO LIRC_DRIVER_NAME
+               ": manually/previously detected using active %s receiver on GPIO pin %d\n",
+               sense ? "low" : "high", gpio_in_pin);
+    }
+
+}
+
+
+
+static int setup_tx(int new_out_pin)
+{
+    int ret;
+    if (gpio_out_pin==new_out_pin)
+        return 0; //do not set up, pin not changed
+
+    if (gpio_out_pin!=0) {   //we had tx pin setup.  Free it so others can use it!
+        dprintk(": trying to free old out pin index %d: %s\n",gpio_out_pin,gpiochip->names[TX_OFFSET_GPIOCHIP]);
+        gpio_free(gpio_out_pin);
+    }
+    gpio_out_pin=new_out_pin;
+    if (gpio_out_pin==0) {
+        return 0; // do not set up, TX disabled
+    }
+    dprintk(": trying to claim new out pin index %d: %s\n",gpio_out_pin,gpiochip->names[TX_OFFSET_GPIOCHIP]);
+    ret = gpio_request(gpio_out_pin,LIRC_DRIVER_NAME "ir/out");
+    if (ret){
+        printk(KERN_ALERT LIRC_DRIVER_NAME
+               ": cant claim gpio pin %d with code %d\n", gpio_out_pin,ret);
+        ret = -ENODEV;
+        goto exit_disable_tx;
+    }
+        gpiochip->direction_output(gpiochip, TX_OFFSET_GPIOCHIP, 1);
+        gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, invert);
+
+    return 0;  // successfully set up
+
+exit_disable_tx:
+    // cannot claim new pin
+    gpio_out_pin = 0; // disable tx
+    return ret;
+}
+
+static int setup_rx(int new_in_pin)
+{
+    int ret,irq;
+    if (gpio_in_pin==new_in_pin)
+        return 0; //do not set up, pin not changed
+
+    if (gpio_in_pin!=0) {   //we had rx pin setup.  Free it so others can use it!
+        dprintk(": trying to free old in pin index %d: %s\n",gpio_in_pin,gpiochip->names[RX_OFFSET_GPIOCHIP]);
+        gpio_free(gpio_in_pin);
+        irqchip=NULL;
+        irqdata=NULL;
+    }
+    gpio_in_pin=new_in_pin;
+    if (gpio_in_pin==0) {
+        return 0; // do not set up, RX disabled
+    }
+    dprintk(": trying to claim new in pin index %d: %s\n",gpio_in_pin,gpiochip->names[RX_OFFSET_GPIOCHIP]);
+    ret = gpio_request(gpio_in_pin, LIRC_DRIVER_NAME " ir/in");
+    if (ret) {
+        printk(KERN_ALERT LIRC_DRIVER_NAME
+               ": cant claim gpio pin %d with code %d\n", gpio_in_pin,ret);
+        ret = -ENODEV;
+        goto exit_disable_rx;
+    }
+
+    gpiochip->direction_input(gpiochip, RX_OFFSET_GPIOCHIP);
+    /* try to setup interrupt data */
+    irq = gpiochip->to_irq(gpiochip, RX_OFFSET_GPIOCHIP);
+    dprintk("to_irq %d for pin %d\n", irq, gpio_in_pin);
+    irqdata = irq_get_irq_data(irq);
+
+    if (irqdata && irqdata->chip) {
+        irqchip = irqdata->chip;
+    } else {
+        ret = -ENODEV;
+        goto exit_gpio_free_in_pin;
+    }
+
+    set_sense();
+
+    return 0; //successfully set up
+
+exit_gpio_free_in_pin:
+    // interrupt set up failed, so free pin
+    gpio_free(gpio_in_pin);
+exit_disable_rx:
+    // could not claim new pin
+    gpio_in_pin=0; // disable rx
+    return ret;
+
+}
+
+/* end of pin setup */
+
+/* get right gpio chip */
+
+static int is_right_chip(struct gpio_chip *chip, const void *data)
+{
+        if (strcmp(data, chip->label) == 0)
+                return 1;
+        return 0;
+}
+
+
+static int set_gpiochip(void)
+{
+        gpiochip = gpiochip_find(LIRC_GPIO_ID_STRING, is_right_chip);
+
+        if (!gpiochip)
+                return -ENODEV;
+
+        return 0;
+
+}
+
+/* end of find gpio chip */
+
+
+
+/* lirc device stuff */
+
+/* called when the character device is opened
+   timing params initialized and interrupts activated */
+static int set_use_inc(void *data)
+{
+        int result;
+        unsigned long flags;
+
+        init_timing_params(duty_cycle, freq);
+        /* initialize pulse/space widths */
+
+    //initialize timestamp, would not be needed if no RX
+    do_gettimeofday(&lasttv);
+    device_open++;
+
+    if (gpio_in_pin!=0) { // entered if RX used
+        /* try to set all interrupts to same handler, should work */
+        result = request_irq(gpiochip->to_irq(gpiochip, RX_OFFSET_GPIOCHIP),
+                             (irq_handler_t) irq_handler, 0,
+                             LIRC_DRIVER_NAME, (void*) 0);
+
+        switch (result) {
+            case -EBUSY:
+                printk(KERN_ERR LIRC_DRIVER_NAME
+                       ": IRQ %d is busy\n",
+                       gpiochip->to_irq(gpiochip, RX_OFFSET_GPIOCHIP));
+                return -EBUSY;
+            case -EINVAL:
+                printk(KERN_ERR LIRC_DRIVER_NAME
+                       ": Bad irq number or handler\n");
+                return -EINVAL;
+            default:
+                dprintk("Interrupt %d obtained\n",
+                        gpiochip->to_irq(gpiochip, RX_OFFSET_GPIOCHIP));
+                break;
+        };
+        spin_lock_irqsave(&lock, flags);
+
+        /* GPIO Pin Falling/Rising Edge Detect Enable */
+        irqchip->irq_set_type(irqdata,
+                              IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING);
+
+        /* unmask the irq for active channel, only */
+        irqchip->irq_unmask(irqdata);
+        spin_unlock_irqrestore(&lock, flags);
+
+    }
+
+        return 0;
+}
+
+/* called when character device is closed */
+static void set_use_dec(void *data)
+{
+        unsigned long flags;
+    device_open--;
+
+    if(!irqchip)
+        return;
+
+        /* GPIO Pin Falling/Rising Edge Detect Disable */
+    spin_lock_irqsave(&lock, flags);
+    irqchip->irq_set_type(irqdata, 0);
+    irqchip->irq_mask(irqdata);
+    spin_unlock_irqrestore(&lock, flags);
+
+    free_irq(gpiochip->to_irq(gpiochip, RX_OFFSET_GPIOCHIP), (void *) 0);
+    device_open--;
+    dprintk("freed IRQ %d\n", gpiochip->to_irq(gpiochip, RX_OFFSET_GPIOCHIP));
+
+}
+
+/* lirc to tx */
+static ssize_t lirc_write(struct file *file, const char *buf,
+                          size_t n, loff_t *ppos)
+{
+        int i, count;
+        unsigned long flags;
+
+        long delta = 0;
+        int *wbuf;
+    if (!gpio_out_pin) {
+        return -ENODEV;
+    }
+        count = n / sizeof(int);
+        if (n % sizeof(int) || count % 2 == 0)
+                return -EINVAL;
+        wbuf = memdup_user(buf, n);
+        if (IS_ERR(wbuf))
+                return PTR_ERR(wbuf);
+        spin_lock_irqsave(&lock, flags);
+    dprintk("lirc_write called, offset %d",TX_OFFSET_GPIOCHIP);
+        for (i = 0; i < count; i++) {
+                if (i%2)
+                        send_space(wbuf[i] - delta);
+                else
+                        delta = send_pulse(wbuf[i]);
+        }
+        gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, invert);
+        spin_unlock_irqrestore(&lock, flags);
+    if (count>11) {
+        dprintk("lirc_write sent %d pulses: no10: %d, no11: %d\n",count,wbuf[10],wbuf[11]);
+    }
+        kfree(wbuf);
+        return n;
+}
+
+/* interpret lirc commands */
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+        int result;
+        __u32 value;
+
+        switch (cmd) {
+        case LIRC_GET_SEND_MODE:
+            return -ENOIOCTLCMD;
+            break;
+
+        case LIRC_SET_SEND_MODE:
+            result = get_user(value, (__u32 *) arg);
+            if (result)
+                return result;
+            /* only LIRC_MODE_PULSE supported */
+            if (value != LIRC_MODE_PULSE)
+                return -ENOSYS;
+            dprintk("Sending stuff on lirc");
+            break;
+
+        case LIRC_GET_LENGTH:
+            return -ENOSYS;
+            break;
+
+        case LIRC_SET_SEND_DUTY_CYCLE:
+            result = get_user(value, (__u32 *) arg);
+            if (result)
+                return result;
+            if (value <= 0 || value > 100)
+                return -EINVAL;
+            dprintk("SET_SEND_DUTY_CYCLE to %d \n", value);
+            return init_timing_params(value, freq);
+            break;
+
+        case LIRC_SET_SEND_CARRIER:
+            result = get_user(value, (__u32 *) arg);
+            if (result)
+                return result;
+            if (value > 500000 || value < 20000)
+                return -EINVAL;
+            dprintk("SET_SEND_CARRIER to %d \n",value);
+            return init_timing_params(duty_cycle, value);
+            break;
+
+        default:
+            return lirc_dev_fop_ioctl(filep, cmd, arg);
+        }
+        return 0;
+}
+
+static const struct file_operations lirc_fops = {
+        .owner                = THIS_MODULE,
+        .write                = lirc_write,
+        .unlocked_ioctl        = lirc_ioctl,
+        .read                = lirc_dev_fop_read, // this and the rest is default
+        .poll                = lirc_dev_fop_poll,
+        .open                = lirc_dev_fop_open,
+        .release        = lirc_dev_fop_close,
+        .llseek                = no_llseek,
+};
+
+static struct lirc_driver driver = {
+        .name                = LIRC_DRIVER_NAME,
+        .minor                = -1,           // assing automatically
+        .code_length        = 1,
+        .sample_rate        = 0,
+        .data                = NULL,
+        .add_to_buf        = NULL,
+        .rbuf                = &rbuf,
+        .set_use_inc        = set_use_inc,
+        .set_use_dec        = set_use_dec,
+        .fops                = &lirc_fops,
+        .dev                = NULL,
+        .owner                = THIS_MODULE,
+};
+
+/* end of lirc device/driver stuff */
+
+/* now comes THIS driver, above is lirc */
+static struct platform_driver lirc_gpio_driver = {
+        .driver = {
+                .name   = LIRC_DRIVER_NAME,
+                .owner  = THIS_MODULE,
+        },
+};
+
+
+
+/* stuff for sysfs*/
+
+static DEFINE_MUTEX(sysfs_lock);
+
+
+
+static ssize_t lirc_txpin_show(struct class *class, struct class_attribute *attr, char *buf)
+{
+    ssize_t status;
+    mutex_lock(&sysfs_lock);
+    status = sprintf(buf,"%d\n",gpio_out_pin);
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_txpin_store(struct class *class, struct class_attribute *attr, const char* buf, size_t size)
+{
+    int new_pin;
+    ssize_t status;
+    mutex_lock(&sysfs_lock);
+    sscanf(buf,"%d",&new_pin);
+    status = setup_tx(new_pin) ? : size;
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_rxpin_show(struct class *class, struct class_attribute *attr, char *buf)
+{
+    ssize_t status;
+    mutex_lock(&sysfs_lock);
+    status = sprintf(buf,"%d\n",gpio_in_pin);
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_rxpin_store(struct class *class, struct class_attribute *attr, const char* buf, size_t size)
+{
+    int new_pin;
+    ssize_t status;
+    mutex_lock(&sysfs_lock);
+    sscanf(buf,"%d",&new_pin);
+    status = setup_rx(new_pin) ? : size;
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_softcarrier_show(struct class *class, struct class_attribute *attr, char *buf)
+{
+    ssize_t status;
+    mutex_lock(&sysfs_lock);
+    status = sprintf(buf,"%d\n",softcarrier);
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_softcarrier_store(struct class *class, struct class_attribute *attr, const char* buf, size_t size)
+{
+    int try_value;
+    ssize_t status=size;
+    mutex_lock(&sysfs_lock);
+    sscanf(buf,"%d",&try_value);
+    if ((try_value==0) || (try_value==1)) {
+        softcarrier=try_value;
+    }
+    else
+        status = -EINVAL;
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+static ssize_t lirc_invert_show(struct class *class, struct class_attribute *attr, char *buf)
+{
+    ssize_t status;
+    mutex_lock(&sysfs_lock);
+    status = sprintf(buf,"%d\n",invert);
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_invert_store(struct class *class, struct class_attribute *attr, const char* buf, size_t size)
+{
+    int try_value;
+    ssize_t status=size;
+    mutex_lock(&sysfs_lock);
+    sscanf(buf,"%d",&try_value);
+    if ((try_value==0) || (try_value==1)) {
+        invert=try_value;
+    }
+    else
+        status = -EINVAL;
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_sense_show(struct class *class, struct class_attribute *attr, char *buf)
+{
+    ssize_t status;
+    mutex_lock(&sysfs_lock);
+    status = sprintf(buf,"%d\n",sense);
+    mutex_unlock(&sysfs_lock);
+    return status;
+}
+
+static ssize_t lirc_sense_store(struct class *class, struct class_attribute *attr, const char* buf, size_t size)
+{
+    int try_value;
+    ssize_t status=size;
+    mutex_lock(&sysfs_lock);
+    sscanf(buf,"%d",&try_value);
+    mutex_unlock(&sysfs_lock);
+    if ((try_value<2) && (try_value>-2)) {
+        sense=try_value;
+    }
+    else
+        return -EINVAL;
+
+    if (gpio_in_pin>0) {
+        set_sense();
+    }
+    return status;
+}
+
+/* I don't think we need another device, so just put it in the class directory
+ * All we need is a way to access some global parameters of this module */
+
+static struct class_attribute lirc_gpio_attrs[] = {
+    __ATTR(tx_gpio_pin, 0644, lirc_txpin_show, lirc_txpin_store),
+    __ATTR(rx_gpio_pin, 0644, lirc_rxpin_show, lirc_rxpin_store),
+    __ATTR(lirc_softcarrier, 0644, lirc_softcarrier_show, lirc_softcarrier_store),
+    __ATTR(lirc_invert, 0644, lirc_invert_show, lirc_invert_store),
+    __ATTR(lirc_sense, 0644, lirc_sense_show, lirc_sense_store),
+    __ATTR_NULL,
+};
+static struct class lirc_gpio_class = {
+    .name = "lirc_gpio",
+    .owner = THIS_MODULE,
+    .class_attrs = lirc_gpio_attrs,
+};
+
+/* end of sysfs stuff */
+
+/* initialize / free THIS driver and device and a lirc buffer*/
+
+static int __init lirc_gpio_init(void)
+{
+        int result;
+
+        /* Init read buffer. */
+        result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
+        if (result < 0)
+                return -ENOMEM;
+
+        result = platform_driver_register(&lirc_gpio_driver);
+        if (result) {
+                printk(KERN_ERR LIRC_DRIVER_NAME
+                       ": lirc register returned %d\n", result);
+                goto exit_buffer_free;
+        }
+
+        lirc_gpio_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
+        if (!lirc_gpio_dev) {
+                result = -ENOMEM;
+                goto exit_driver_unregister;
+        }
+
+        result = platform_device_add(lirc_gpio_dev);
+        if (result)
+                goto exit_device_put;
+
+        return 0;
+
+exit_device_put:
+        platform_device_put(lirc_gpio_dev);
+
+exit_driver_unregister:
+        platform_driver_unregister(&lirc_gpio_driver);
+
+exit_buffer_free:
+        lirc_buffer_free(&rbuf);
+
+        return result;
+}
+
+static void lirc_gpio_exit(void)
+{
+    setup_tx(0); // frees gpio_out_pin if set
+    setup_rx(0); //  dito
+        platform_device_unregister(lirc_gpio_dev);
+        platform_driver_unregister(&lirc_gpio_driver);
+        lirc_buffer_free(&rbuf);
+}
+
+/* end of stuff for THIS driver/device registration */
+/* ignorance of unset pins in setup routines tolerate call if nothing is set up */
+
+/* master init */
+
+static int __init lirc_gpio_init_module(void)
+{
+    int result,temp_in_pin,temp_out_pin;
+
+        result = lirc_gpio_init();
+        if (result)
+                return result;
+    // 'driver' is the lirc driver
+        driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE |
+    LIRC_CAN_SET_SEND_CARRIER |
+    LIRC_CAN_SEND_PULSE |
+    LIRC_CAN_REC_MODE2;
+
+        driver.dev = &lirc_gpio_dev->dev;  // link THIS platform device to lirc driver
+        driver.minor = lirc_register_driver(&driver);
+
+        if (driver.minor < 0) {
+                printk(KERN_ERR LIRC_DRIVER_NAME
+                       ": device registration failed with %d\n", result);
+                result = -EIO;
+                goto exit_lirc;
+        }
+
+        printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");
+
+        result = set_gpiochip();
+        if (result < 0)
+                goto exit_lirc;
+    /* some hacking to get pins initialized on first used */
+    /* setup_tx/rx will not do anything if pins would not change */
+    temp_out_pin = gpio_out_pin; gpio_out_pin = 0;
+    result = setup_tx(temp_out_pin);
+    if (result < 0)
+        goto exit_lirc;
+    /* dito for rx */
+    temp_in_pin = gpio_in_pin; gpio_in_pin = 0;
+    result = setup_rx(temp_in_pin);
+    if (result < 0)
+        goto exit_lirc;
+    if (device_open) {  // this is unlikely, but well...
+        result = set_use_inc((void*) 0);
+        if (result<0) {
+            goto exit_lirc;
+        }
+    }
+
+    result=class_register(&lirc_gpio_class);
+    if (result) {
+        goto exit_lirc;
+    }
+
+
+        return 0;
+
+exit_lirc:
+    /* failed attempt to setup_tx/rx sets pin to 0. */
+    /* next call with arg 0 will then not do anything -> only one exit routine */
+        lirc_gpio_exit();
+
+        return result;
+}
+
+static void __exit lirc_gpio_exit_module(void)
+{
+
+        lirc_gpio_exit();
+    class_unregister(&lirc_gpio_class);
+
+        lirc_unregister_driver(driver.minor);
+        printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
+}
+
+module_init(lirc_gpio_init_module);
+module_exit(lirc_gpio_exit_module);
+
+MODULE_DESCRIPTION("Infra-red receiver and blaster driver for GPIO-Lib.");
+MODULE_DESCRIPTION("Parameters can be set/changed in /sys/class/lirc_gpio");
+MODULE_DESCRIPTION("If RX Pin is changed, previous value of sense is taken");
+MODULE_DESCRIPTION("You may want to write -1 to lirc_sense to force new auto-detection");
+MODULE_AUTHOR("Matthias Hoelling <mhoel....@gmail.nospam.com");
+MODULE_LICENSE("GPL");
+
+module_param(gpio_out_pin, int, S_IRUGO);
+MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin array");
+
+module_param(gpio_in_pin, int, S_IRUGO);
+MODULE_PARM_DESC(gpio_in_pin, "GPIO input/receiver pin array");
+
+module_param(sense, int, S_IRUGO);
+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit");
+
+module_param(softcarrier, int, S_IRUGO);
+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
+
+module_param(invert, int, S_IRUGO);
+MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off");
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");

diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig
index f57464a..a2d4cf0 100644
--- a/drivers/staging/media/lirc/Kconfig
+++ b/drivers/staging/media/lirc/Kconfig
@@ -83,5 +83,13 @@ config LIRC_GPIO
 	  Driver for GPIOLIB enabled gpio chip. Module setup for and tested
 	  on Allwinner A10 Gpio SOC.
 	  change/redefine LIRC_GPIO_ID_STRING to the correct gpiochip label
+	  
+config LIRC_SUNXI_RAW
+	tristate "LIRC for sunxi CIR interface"
+	depends on LIRC
+	help
+	  Driver for Allwinner's native CIR interface, passing
+	  data (almost) unfiltered to LIRC device
+	
 
 endif
diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile
index e729ad0..e59bcfc 100644
--- a/drivers/staging/media/lirc/Makefile
+++ b/drivers/staging/media/lirc/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_LIRC_SIR)		+= lirc_sir.o
 obj-$(CONFIG_LIRC_TTUSBIR)	+= lirc_ttusbir.o
 obj-$(CONFIG_LIRC_ZILOG)	+= lirc_zilog.o
 obj-$(CONFIG_LIRC_GPIO)		+= lirc_gpio.o
+obj-$(CONFIG_LIRC_SUNXI_RAW)	+= sunxi-lirc.o
diff --git a/drivers/staging/media/lirc/lirc_gpio.c b/drivers/staging/media/lirc/lirc_gpio.c
index 2e7fbbe..10f5129 100644
--- a/drivers/staging/media/lirc/lirc_gpio.c
+++ b/drivers/staging/media/lirc/lirc_gpio.c
@@ -10,7 +10,7 @@
  *        lot of code from the lirc_serial module,
  *              so I would like say thanks to the authors.
  *
- * Copyright (C) 2013 Matthias Hölling <mhoel....@gmail.nospam.com>,
+ * Copyright (C) 2013 Matthias H��lling <mhoel....@gmail.nospam.com>,
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -41,6 +41,8 @@
 #include <media/lirc.h>
 #include <media/lirc_dev.h>
 #include <linux/gpio.h>
+#include <plat/sys_config.h>
+#include <../drivers/gpio/gpio-sunxi.h>
 
 #define LIRC_DRIVER_NAME "lirc_gpio"
 /* this may have to be adapted for different platforms */
@@ -349,7 +351,10 @@ static void set_sense(void)
 
 static int setup_tx(int new_out_pin)
 {
-    int ret;
+	int ret;
+    user_gpio_set_t* pinstate;
+    struct sunxi_gpio_chip* sgpio = container_of(gpiochip,struct sunxi_gpio_chip,chip);
+    dprintk("addresses: gpiochip: %lx, sgpio: %lx",(unsigned long int) gpiochip,(unsigned long int) sgpio);
     if (gpio_out_pin==new_out_pin)
         return 0; //do not set up, pin not changed
 
@@ -369,9 +374,19 @@ static int setup_tx(int new_out_pin)
         ret = -ENODEV;
         goto exit_disable_tx;
     }
-        gpiochip->direction_output(gpiochip, TX_OFFSET_GPIOCHIP, 1);
-        gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, invert);
-
+    gpiochip->direction_output(gpiochip, TX_OFFSET_GPIOCHIP, 1);
+    gpiochip->set(gpiochip, TX_OFFSET_GPIOCHIP, invert);
+    pinstate=kzalloc(sizeof(user_gpio_set_t),GFP_KERNEL);
+
+    //dprintk("pin:address %lx, pin_name: %s, pin handler: %d",(unsigned long int) &(sgpio->data[TX_OFFSET_GPIOCHIP]),
+    // 		sgpio->data[TX_OFFSET_GPIOCHIP].pin_name,sgpio->data[TX_OFFSET_GPIOCHIP].gpio_handler);
+    ret=gpio_get_one_pin_status(sgpio->data[TX_OFFSET_GPIOCHIP].gpio_handler, pinstate, sgpio->data[TX_OFFSET_GPIOCHIP].pin_name, true);
+    if(pinstate && !ret) {
+    	pr_info("Maximum load on '%s' is %d mA\n", gpiochip->names[TX_OFFSET_GPIOCHIP], 10+10*pinstate->drv_level);
+    	kfree(pinstate);
+    }
+    else
+    	printk(KERN_ALERT LIRC_DRIVER_NAME ": something might have gone wrong, return from pin status query: %d",ret);
     return 0;  // successfully set up
 
 exit_disable_tx:
diff --git a/drivers/staging/media/lirc/sunxi-lirc.c b/drivers/staging/media/lirc/sunxi-lirc.c
new file mode 100644
index 0000000..b571b7b
--- /dev/null
+++ b/drivers/staging/media/lirc/sunxi-lirc.c
@@ -0,0 +1,590 @@
+/*
+ *
+ * sunxi_lirc.c
+ *
+ * sunxi_lirc - Device driver that uses Allwinner A1X or A20 IR module in CIR mode
+ *              for LIRC. Tested on a Cubietruck with Allwinner A20
+ *              a lot of code from the sunxi-ir module,
+ *              so I would like say thanks to the authors.
+ *        		Difference to sunxi-ir is that no verification of IR code
+ *        		against NEC protocol is made, whatsoever
+ *        		but just passed on to lirc buffer to let lirc do any decoding
+ *
+ * Copyright (C) 2014 Matthias Hoelling <mhoel....@gmail.nospam.com>,
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <mach/clock.h>
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#include <mach/irqs.h>
+#include <mach/system.h>
+#include <mach/hardware.h>
+#include <plat/sys_config.h>
+
+#include <linux/clk.h>
+
+#define LIRC_DRIVER_NAME "sunxi_lirc"
+#define RBUF_LEN 256
+
+static struct platform_device *lirc_sunxi_dev;
+
+static struct clk *apb_ir_clk;
+static struct clk *ir_clk;
+static u32 ir_gpio_hdle;
+
+#define SYS_CLK_CFG_EN
+
+#define SYS_GPIO_CFG_EN
+/* #define DEBUG_IR */
+#define PRINT_SUSPEND_INFO
+
+#define dprintk(fmt, args...)                                        \
+do {                                                        \
+if (debug)                                        \
+printk(KERN_DEBUG LIRC_DRIVER_NAME ": "        \
+fmt, ## args);                        \
+} while (0)
+
+/* Registers */
+#define IR_REG(x)	(x)
+#define IR0_BASE	(0xf1c21800)
+#define IR1_BASE	(0xf1c21c00)
+#define IR_BASE		IR0_BASE
+#define IR_IRQNO	(SW_INT_IRQNO_IR0)
+
+/* CCM register */
+#define CCM_BASE	0xf1c20000
+/* PIO register */
+#define PI_BASE		0xf1c20800
+
+#define IR_CTRL_REG	IR_REG(0x00) /* IR Control */
+#define IR_RXCFG_REG	IR_REG(0x10) /* Rx Config */
+#define IR_RXDAT_REG	IR_REG(0x20) /* Rx Data */
+#define IR_RXINTE_REG	IR_REG(0x2c) /* Rx Interrupt Enable */
+#define IR_RXINTS_REG	IR_REG(0x30) /* Rx Interrupt Status */
+#define IR_SPLCFG_REG	IR_REG(0x34) /* IR Sample Config */
+
+
+/* Bit Definition of IR_RXINTS_REG Register */
+#define IR_RXINTS_RXOF	(0x1 << 0)	/* Rx FIFO Overflow */
+#define IR_RXINTS_RXPE	(0x1 << 1)	/* Rx Packet End */
+#define IR_RXINTS_RXDA	(0x1 << 4)	/* Rx FIFO Data Available */
+
+/* Helper */
+#define PULSE_BIT_SHIFTER	(17)  /* from 0x80 to PULSE_BIT */
+#define SAMPLES_TO_US(us)	(( ((unsigned long) us) * 1000000UL)/46875UL)
+
+#ifdef CONFIG_ARCH_SUN5I
+#define IR_FIFO_SIZE	(64)	/* 64Bytes */
+#else
+#define IR_FIFO_SIZE	(16)	/* 16Bytes */
+#endif
+/* Frequency of Sample Clock = 46875.Hz, Cycle is 21.3us */
+
+#define IR_RXFILT_VAL	(8)	/* Filter Threshold = 8*21.3 = ~128us	< 200us */
+#define IR_RXIDLE_VAL	(5)	/* Idle Threshold = (5+1)*128*21.3 = ~16.4ms > 9ms */
+
+
+#define	IR_RAW_BUF_SIZE	128
+#define DRV_VERSION	"1.00"
+
+
+
+struct ir_raw_buffer {
+	unsigned int dcnt;	/*Packet Count*/
+	unsigned char buf[IR_RAW_BUF_SIZE];
+};
+
+static struct lirc_buffer rbuf;
+
+DEFINE_SPINLOCK(sunxi_lirc_spinlock);
+
+
+
+static struct ir_raw_buffer ir_rawbuf;
+
+static int debug=0;
+
+
+
+static inline void ir_reset_rawbuffer(void)
+{
+	ir_rawbuf.dcnt = 0;
+}
+
+static inline void ir_write_rawbuffer(unsigned char data)
+{
+	if (ir_rawbuf.dcnt < IR_RAW_BUF_SIZE)
+		ir_rawbuf.buf[ir_rawbuf.dcnt++] = data;
+	else
+		printk("ir_write_rawbuffer: IR Rx buffer full\n");
+}
+
+static inline unsigned char ir_read_rawbuffer(void)
+{
+	unsigned char data = 0x00;
+
+	if (ir_rawbuf.dcnt > 0)
+		data = ir_rawbuf.buf[--ir_rawbuf.dcnt];
+
+	return data;
+}
+
+static inline int ir_rawbuffer_empty(void)
+{
+	return (ir_rawbuf.dcnt == 0);
+}
+
+static inline int ir_rawbuffer_full(void)
+{
+	return (ir_rawbuf.dcnt >= IR_RAW_BUF_SIZE);
+}
+
+static void ir_clk_cfg(void)
+{
+#ifdef SYS_CLK_CFG_EN
+	unsigned long rate = 3000000; /* 6 MHz */
+#else
+	unsigned long tmp = 0;
+#endif
+
+#ifdef SYS_CLK_CFG_EN
+	apb_ir_clk = clk_get(NULL, "apb_ir0");
+	if (!apb_ir_clk) {
+		printk("try to get apb_ir0 clock failed\n");
+		return;
+	}
+
+	ir_clk = clk_get(NULL, "ir0");
+	if (!ir_clk) {
+		printk("try to get ir0 clock failed\n");
+		return;
+	}
+	dprintk("trying to set clock via SYS_CLK_CFG_EN, when no error follows -> succeeded\n");
+	if (clk_set_rate(ir_clk, rate))
+		printk("set ir0 clock freq to 6M failed\n");
+
+	if (clk_enable(apb_ir_clk))
+		printk("try to enable apb_ir_clk failed\n");
+
+	if (clk_enable(ir_clk))
+		printk("try to enable apb_ir_clk failed\n");
+
+#else
+	dprintk("setting clock via register manipulation\n");
+	/* Enable APB Clock for IR */
+	/* copied from sunxi-ir.c, but not sure if this will work, registers do not seem conform with data sheet */
+	tmp = readl(CCM_BASE + 0x10);
+	tmp |= 0x1 << 10;  /* IR */
+	writel(tmp, CCM_BASE + 0x10);
+
+	/* config Special Clock for IR (24/8=6MHz) */
+	tmp = readl(CCM_BASE + 0x34);
+	tmp &= ~(0x3 << 8);
+	tmp |= (0x1 << 8);	/* Select 24MHz */
+	tmp |= (0x1 << 7);	/* Open Clock */
+	tmp &= ~(0x3f << 0);
+	tmp |= (7 << 0);	/* Divisor = 8 */
+	writel(tmp, CCM_BASE + 0x34);
+#endif
+
+	return;
+}
+
+static void ir_clk_uncfg(void)
+{
+#ifdef SYS_CLK_CFG_EN
+	clk_put(apb_ir_clk);
+	clk_put(ir_clk);
+#endif
+
+	return;
+}
+static void ir_sys_cfg(void)
+{
+#ifdef SYS_GPIO_CFG_EN
+	ir_gpio_hdle = gpio_request_ex("ir_para", "ir0_rx");
+	if (0 == ir_gpio_hdle)
+		printk("try to request ir_para gpio failed\n");
+#else
+	/* config IO: PIOB4 to IR_Rx */
+	tmp = readl(PI_BASE + 0x24); /* PIOB_CFG0_REG */
+	tmp &= ~(0xf << 16);
+	tmp |= (0x2 << 16);
+	writel(tmp, PI_BASE + 0x24);
+#endif
+
+	ir_clk_cfg();
+
+	return;
+}
+
+static void ir_sys_uncfg(void)
+{
+#ifdef SYS_GPIO_CFG_EN
+	gpio_release(ir_gpio_hdle, 2);
+#endif
+	ir_clk_uncfg();
+
+	return;
+}
+
+static void ir_reg_cfg(void)
+{
+	unsigned long tmp = 0;
+	/* Enable CIR Mode */
+	tmp = 0x3 << 4;
+	writel(tmp, IR_BASE + IR_CTRL_REG);
+
+	/* Config IR Sample Register */
+	tmp = 0x0 << 0; /* Fsample = 3MHz/64 =46875Hz (21.3us) */
+
+
+	tmp |= (IR_RXFILT_VAL & 0x3f) << 2; /* Set Filter Threshold */
+	tmp |= (IR_RXIDLE_VAL & 0xff) << 8; /* Set Idle Threshold */
+	writel(tmp, IR_BASE + IR_SPLCFG_REG);
+
+	/* Invert Input Signal */
+	writel(0x1 << 2, IR_BASE + IR_RXCFG_REG);
+
+
+	/* Clear All Rx Interrupt Status */
+	writel(0xff, IR_BASE + IR_RXINTS_REG);
+
+	/* Set Rx Interrupt Enable */
+	tmp = (0x1 << 4) | 0x3;
+#ifdef CONFIG_ARCH_SUN5I
+	tmp |= ((IR_FIFO_SIZE >> 2) - 1) << 8; /* Rx FIFO Threshold = FIFOsz/4 */
+#else
+	tmp |= ((IR_FIFO_SIZE >> 1) - 1) << 8; /* Rx FIFO Threshold = FIFOsz/2 */
+#endif
+	writel(tmp, IR_BASE + IR_RXINTE_REG);
+
+	/* Enable IR Module */
+	tmp = readl(IR_BASE + IR_CTRL_REG);
+	tmp |= 0x3;
+	writel(tmp, IR_BASE + IR_CTRL_REG);
+
+	return;
+}
+
+
+
+static void ir_setup(void)
+{
+	dprintk("ir_setup: ir setup start!!\n");
+
+	ir_reset_rawbuffer();
+	ir_sys_cfg();
+	ir_reg_cfg();
+
+	dprintk("ir_setup: ir setup end!!\n");
+
+	return;
+}
+
+static inline unsigned char ir_get_data(void)
+{
+	return (unsigned char)(readl(IR_BASE + IR_RXDAT_REG));
+}
+
+static inline unsigned long ir_get_intsta(void)
+{
+	return readl(IR_BASE + IR_RXINTS_REG);
+}
+
+static inline void ir_clr_intsta(unsigned long bitmap)
+{
+	unsigned long tmp = readl(IR_BASE + IR_RXINTS_REG);
+
+	tmp &= ~0xff;
+	tmp |= bitmap&0xff;
+	writel(tmp, IR_BASE + IR_RXINTS_REG);
+}
+
+
+
+void ir_packet_handler(unsigned char *buf, unsigned int dcnt)
+{
+	unsigned int i;
+	unsigned  int lirc_val;
+	dprintk("Buffer length: %d",dcnt);
+	for(i=0;i<dcnt;i++) {
+		lirc_val= ((unsigned int) (buf[i] & 0x80) << PULSE_BIT_SHIFTER) | (SAMPLES_TO_US(buf[i] &0x7f));
+		while((buf[i] & 0x80) == (buf[i+1] & 0x80)) {
+			lirc_val += SAMPLES_TO_US(buf[++i]&0x7f);
+		}
+		/* statistically pulses are one sample period (?) too long, spaces too short */
+		/* would make sense because of bandpass latency, but not sure... */
+		lirc_val += (buf[i] & 0x80) ? (-SAMPLES_TO_US(1)) : SAMPLES_TO_US(1);
+		dprintk("rawbuf: %x, value: %x, level:%d for %d us\n",buf[i],lirc_val,(buf[i]&0x80) ? 1 : 0,lirc_val & PULSE_MASK) ;
+		/* to do, write to lirc buffer */
+	    if (lirc_buffer_full(&rbuf)) {
+	            /* no new signals will be accepted */
+	            dprintk("Buffer overrun\n");
+	            return;
+	    }
+	    lirc_buffer_write(&rbuf,(unsigned char*)&lirc_val);
+	}
+
+
+	return;
+}
+
+
+
+static irqreturn_t ir_irq_service(int irqno, void *dev_id)
+{
+	unsigned int dcnt;
+	unsigned int i = 0;
+	unsigned long intsta;
+
+	intsta = ir_get_intsta();
+
+	ir_clr_intsta(intsta);
+
+	/* Read Data Every Time Enter this Routine*/
+#ifdef CONFIG_ARCH_SUN5I
+	dcnt = (unsigned int) (ir_get_intsta() >> 8) & 0x3f;
+#else
+	dcnt = (unsigned int) (ir_get_intsta() >> 8) & 0x1f;
+#endif
+
+	/* Read FIFO */
+	for (i = 0; i < dcnt; i++) {
+		if (ir_rawbuffer_full()) {
+			dprintk("ir_irq_service: raw buffer full\n");
+			break;
+		} else {
+			ir_write_rawbuffer(ir_get_data());
+		}
+	}
+
+	if (intsta & IR_RXINTS_RXPE) { /* Packet End */
+
+		ir_packet_handler(ir_rawbuf.buf, ir_rawbuf.dcnt);
+		dprintk("Buffer written\n");
+		ir_rawbuf.dcnt = 0;
+
+        wake_up_interruptible(&rbuf.wait_poll);
+
+
+	}
+
+	if (intsta & IR_RXINTS_RXOF) {/* FIFO Overflow */
+		/* flush raw buffer */
+		ir_reset_rawbuffer();
+		dprintk("ir_irq_service: Rx FIFO Overflow!!\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+
+/* interpret lirc commands */
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+
+        switch (cmd) {
+        case LIRC_GET_SEND_MODE:
+            return -ENOIOCTLCMD;
+            break;
+
+            /* driver cannot send */
+        case LIRC_SET_SEND_MODE:
+            return -ENOSYS;
+            break;
+
+        case LIRC_GET_LENGTH:
+            return -ENOSYS;
+            break;
+
+        case LIRC_SET_SEND_DUTY_CYCLE:
+            return -ENOSYS;
+             break;
+
+        case LIRC_SET_SEND_CARRIER:
+            return -ENOSYS;
+            break;
+
+        default:
+            return lirc_dev_fop_ioctl(filep, cmd, arg);
+        }
+        return 0;
+}
+
+
+static int set_use_inc(void* data) {
+	return 0;
+}
+
+static void set_use_dec(void* data) {
+
+}
+
+static const struct file_operations lirc_fops = {
+        .owner                = THIS_MODULE,
+        .unlocked_ioctl        = lirc_ioctl,
+        .read                = lirc_dev_fop_read, // this and the rest is default
+        .write                = lirc_dev_fop_write,
+        .poll                = lirc_dev_fop_poll,
+        .open                = lirc_dev_fop_open,
+        .release        = lirc_dev_fop_close,
+        .llseek                = no_llseek,
+};
+
+static struct lirc_driver driver = {
+        .name                = LIRC_DRIVER_NAME,
+        .minor                = -1,           // assing automatically
+        .code_length        = 1,
+        .sample_rate        = 0,
+        .data                = NULL,
+        .add_to_buf        = NULL,
+        .rbuf                = &rbuf,
+        .set_use_inc        = set_use_inc,
+        .set_use_dec        = set_use_dec,
+        .fops                = &lirc_fops,
+        .dev                = NULL,
+        .owner                = THIS_MODULE,
+};
+
+/* end of lirc device/driver stuff */
+
+/* now comes THIS driver, above is lirc */
+static struct platform_driver lirc_sunxi_driver = {
+        .driver = {
+                .name   = LIRC_DRIVER_NAME,
+                .owner  = THIS_MODULE,
+        },
+};
+
+
+
+
+
+static int __init ir_init(void)
+{
+	int result;
+    /* Init read buffer. */
+    result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
+    if (result < 0)
+            return -ENOMEM;
+
+    result = platform_driver_register(&lirc_sunxi_driver);
+    if (result) {
+            printk(KERN_ERR LIRC_DRIVER_NAME
+                   ": lirc register returned %d\n", result);
+            goto exit_buffer_free;
+    }
+
+    lirc_sunxi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
+    if (!lirc_sunxi_dev) {
+            result = -ENOMEM;
+            goto exit_driver_unregister;
+    }
+
+    result = platform_device_add(lirc_sunxi_dev);
+    if (result) {
+    	platform_device_put(lirc_sunxi_dev);
+    	goto exit_driver_unregister;
+    }
+
+	if (request_irq(IR_IRQNO, ir_irq_service, 0, "RemoteIR",
+			(void*) 0)) {
+		result = -EBUSY;
+		goto exit_device_unregister;
+	}
+
+	ir_setup();
+
+	printk("IR Initial OK\n");
+
+
+
+    // 'driver' is the lirc driver
+        driver.features = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+
+        driver.dev = &lirc_sunxi_dev->dev;  // link THIS platform device to lirc driver
+        driver.minor = lirc_register_driver(&driver);
+
+        if (driver.minor < 0) {
+                printk(KERN_ERR LIRC_DRIVER_NAME
+                       ": device registration failed with %d\n", result);
+
+                result = -EIO;
+                goto exit_free_irq;
+        }
+
+        printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");
+
+    return 0;
+
+
+exit_free_irq:
+	free_irq(IR_IRQNO, (void*) 0);
+
+exit_device_unregister:
+    platform_device_unregister(lirc_sunxi_dev);
+
+exit_driver_unregister:
+    platform_driver_unregister(&lirc_sunxi_driver);
+
+exit_buffer_free:
+    lirc_buffer_free(&rbuf);
+
+	return result;
+}
+
+static void __exit ir_exit(void)
+{
+
+	free_irq(IR_IRQNO, (void*) 0);
+	ir_sys_uncfg();
+    platform_device_unregister(lirc_sunxi_dev);
+
+    platform_driver_unregister(&lirc_sunxi_driver);
+
+    lirc_buffer_free(&rbuf);
+    lirc_unregister_driver(driver.minor);
+    printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
+
+}
+
+module_init(ir_init);
+module_exit(ir_exit);
+
+MODULE_DESCRIPTION("Remote IR driver");
+MODULE_AUTHOR("Matthias Hoelling");
+MODULE_LICENSE("GPL");
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
