diff --git a/Documentation/devicetree/bindings/media/spi-ir.txt b/Documentation/devicetree/bindings/media/spi-ir.txt
new file mode 100644
index 0000000..2232d92
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/spi-ir.txt
@@ -0,0 +1,24 @@
+Device tree bindings for IR LED connected through SPI bus which is used as
+remote controller.
+
+The IR LED switch is connected to the MOSI line of the SPI device and the data
+are delivered thourgh that.
+
+Required properties:
+	- compatible: should be "ir-spi"
+
+Optional properties:
+	- irled,switch: specifies the gpio switch which enables the irled
+
+Example:
+
+        irled@0 {
+                compatible = "ir-spi";
+                reg = <0x0>;
+                spi-max-frequency = <5000000>;
+                irled,switch = <&gpr3 3 0>;
+
+                controller-data {
+                        samsung,spi-feedback-delay = <0>;
+                };
+        };
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index bd4d685..dacaa29 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -261,6 +261,15 @@ config IR_REDRAT3
 	   To compile this driver as a module, choose M here: the
 	   module will be called redrat3.
 
+config IR_SPI
+	tristate "SPI connected IR LED"
+	depends on SPI && LIRC
+	---help---
+	  Say Y if you want to use an IR LED connected through SPI bus.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ir-spi.
+
 config IR_STREAMZAP
 	tristate "Streamzap PC Remote IR Receiver"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 379a5c0..1417c8d 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
 obj-$(CONFIG_IR_ENE) += ene_ir.o
 obj-$(CONFIG_IR_REDRAT3) += redrat3.o
 obj-$(CONFIG_IR_RX51) += ir-rx51.o
+obj-$(CONFIG_IR_SPI) += ir-spi.o
 obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
 obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
 obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
new file mode 100644
index 0000000..6eb14e9
--- /dev/null
+++ b/drivers/media/rc/ir-spi.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Author: Andi Shyti <andi.shyti@samsung.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * SPI driven IR LED device driver
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <media/lirc_dev.h>
+
+#define IR_SPI_DRIVER_NAME		"ir-spi"
+
+#define IR_SPI_DEFAULT_FREQUENCY	38000
+#define IR_SPI_BIT_PER_WORD		    8
+
+struct ir_spi_data {
+	u16 nusers;
+	int power_gpio;
+
+	u8 *buffer;
+
+	struct lirc_driver lirc_driver;
+	struct spi_device *spi;
+	struct spi_transfer xfer;
+	struct mutex mutex;
+	struct regulator *regulator;
+};
+
+static ssize_t ir_spi_chardev_write(struct file *file,
+					const char __user *buffer,
+					size_t length, loff_t *offset)
+{
+	struct ir_spi_data *idata = file->private_data;
+	bool please_free = false;
+	int ret = 0;
+
+	if (idata->xfer.len && (idata->xfer.len != length))
+		return -EINVAL;
+
+	mutex_lock(&idata->mutex);
+
+	if (!idata->xfer.len) {
+		idata->buffer = kmalloc(length, GFP_KERNEL);
+
+		if (!idata->buffer) {
+			ret = -ENOMEM;
+			goto out_unlock;
+		}
+
+		idata->xfer.len = length;
+		please_free = true;
+	}
+
+	if (copy_from_user(idata->buffer, buffer, length)) {
+		ret = -EFAULT;
+		goto out_free;
+	}
+
+	ret = regulator_enable(idata->regulator);
+	if (ret) {
+		dev_err(&idata->spi->dev, "failed to power on the LED\n");
+		goto out_free;
+	}
+
+	idata->xfer.tx_buf = idata->buffer;
+
+	ret = spi_sync_transfer(idata->spi, &idata->xfer, 1);
+	if (ret)
+		dev_err(&idata->spi->dev, "unable to deliver the signal\n");
+
+	regulator_disable(idata->regulator);
+
+out_free:
+	if (please_free) {
+		kfree(idata->buffer);
+		idata->xfer.len = 0;
+		idata->buffer = NULL;
+	}
+
+out_unlock:
+	mutex_unlock(&idata->mutex);
+
+	return ret ? ret : length;
+}
+
+static int ir_spi_chardev_open(struct inode *inode, struct file *file)
+{
+	struct ir_spi_data *idata = lirc_get_pdata(file);
+
+	if (unlikely(idata->nusers >= SHRT_MAX)) {
+		dev_err(&idata->spi->dev, "device busy\n");
+		return -EBUSY;
+	}
+
+	file->private_data = idata;
+
+	mutex_lock(&idata->mutex);
+	idata->nusers++;
+	mutex_unlock(&idata->mutex);
+
+	return 0;
+}
+
+static int ir_spi_chardev_close(struct inode *inode, struct file *file)
+{
+	struct ir_spi_data *idata = lirc_get_pdata(file);
+
+	mutex_lock(&idata->mutex);
+	idata->nusers--;
+
+	/*
+	 * check if someone else is using the driver,
+	 * if not, then:
+	 *
+	 *  - reset length and frequency values to default
+	 *  - shut down the LED
+	 *  - free the buffer (NULL or ZERO_SIZE_PTR are noop)
+	 */
+	if (!idata->nusers) {
+		idata->xfer.len = 0;
+		idata->xfer.speed_hz = IR_SPI_DEFAULT_FREQUENCY;
+
+		kfree(idata->buffer);
+		idata->buffer = NULL;
+	}
+
+	mutex_unlock(&idata->mutex);
+
+	return 0;
+}
+
+static long ir_spi_chardev_ioctl(struct file *file, unsigned int cmd,
+						unsigned long arg)
+{
+	__u32 p;
+	s32 ret;
+	struct ir_spi_data *idata = file->private_data;
+
+	switch (cmd) {
+	case LIRC_GET_FEATURES:
+		return put_user(idata->lirc_driver.features,
+					(__u32 __user *) arg);
+
+	case LIRC_GET_LENGTH:
+		return put_user(idata->xfer.len, (__u32 __user *) arg);
+
+	case LIRC_SET_LENGTH: {
+		void *new;
+
+		ret = get_user(p, (__u32 __user *) arg);
+		if (ret)
+			return ret;
+
+		/*
+		 * the user is trying to set the same
+		 * length of the current value
+		 */
+		if (idata->xfer.len == p)
+			return 0;
+
+		/*
+		 * multiple users should use the driver with the
+		 * length, otherwise return EPERM same data
+		 */
+		if (idata->nusers > 1)
+			return -EPERM;
+
+		/*
+		 * if the buffer is already allocated, reallocate it with the
+		 * desired value. If the desired value is 0, then the buffer is
+		 * freed from krealloc()
+		 */
+		if (idata->xfer.len)
+			new = krealloc(idata->buffer, p, GFP_KERNEL);
+		else
+			new = kmalloc(p, GFP_KERNEL);
+
+		if (!new)
+			return -ENOMEM;
+
+		mutex_lock(&idata->mutex);
+		idata->buffer = new;
+		idata->xfer.len = p;
+		mutex_unlock(&idata->mutex);
+
+		return 0;
+	}
+
+	case LIRC_GET_SEND_CARRIER:
+		return put_user(idata->xfer.speed_hz, (__u32 __user *) arg);
+
+	case LIRC_SET_SEND_CARRIER:
+		ret = get_user(p, (__u32 __user *) arg);
+		if (ret)
+			return ret;
+
+		/*
+		 * The frequency cannot be obviously set to '0',
+		 * while, as in the case of the data length,
+		 * multiple users should use the driver with the same
+		 * frequency value, otherwise return EPERM
+		 */
+		if (!p || ((idata->nusers > 1) && p != idata->xfer.speed_hz))
+			return -EPERM;
+
+		mutex_lock(&idata->mutex);
+		idata->xfer.speed_hz = p;
+		mutex_unlock(&idata->mutex);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static const struct file_operations ir_spi_fops = {
+	.owner   = THIS_MODULE,
+	.read    = lirc_dev_fop_read,
+	.write   = ir_spi_chardev_write,
+	.poll    = lirc_dev_fop_poll,
+	.open    = ir_spi_chardev_open,
+	.release = ir_spi_chardev_close,
+	.llseek  = noop_llseek,
+	.unlocked_ioctl = ir_spi_chardev_ioctl,
+	.compat_ioctl   = ir_spi_chardev_ioctl,
+};
+
+static int ir_spi_probe(struct spi_device *spi)
+{
+	struct ir_spi_data *idata;
+
+	idata = devm_kzalloc(&spi->dev, sizeof(*idata), GFP_KERNEL);
+	if (!idata)
+		return -ENOMEM;
+
+	idata->regulator = devm_regulator_get(&spi->dev, "irda_regulator");
+	if (IS_ERR(idata->regulator))
+		return PTR_ERR(idata->regulator);
+
+	snprintf(idata->lirc_driver.name, sizeof(idata->lirc_driver.name),
+							IR_SPI_DRIVER_NAME);
+	idata->lirc_driver.features    = LIRC_CAN_SEND_RAW;
+	idata->lirc_driver.code_length = 1;
+	idata->lirc_driver.fops        = &ir_spi_fops;
+	idata->lirc_driver.dev         = &spi->dev;
+	idata->lirc_driver.data        = idata;
+	idata->lirc_driver.owner       = THIS_MODULE;
+	idata->lirc_driver.minor       = -1;
+
+	idata->lirc_driver.minor = lirc_register_driver(&idata->lirc_driver);
+	if (idata->lirc_driver.minor < 0) {
+		dev_err(&spi->dev, "unable to generate character device\n");
+		return idata->lirc_driver.minor;
+	}
+
+	mutex_init(&idata->mutex);
+
+	idata->spi = spi;
+
+	idata->xfer.bits_per_word = IR_SPI_BIT_PER_WORD;
+	idata->xfer.speed_hz = IR_SPI_DEFAULT_FREQUENCY;
+
+	return 0;
+}
+
+static int ir_spi_remove(struct spi_device *spi)
+{
+	struct ir_spi_data *idata = spi_get_drvdata(spi);
+
+	lirc_unregister_driver(idata->lirc_driver.minor);
+
+	return 0;
+}
+
+static const struct of_device_id ir_spi_of_match[] = {
+	{ .compatible = "ir-spi" },
+	{},
+};
+
+static struct spi_driver ir_spi_driver = {
+	.probe = ir_spi_probe,
+	.remove = ir_spi_remove,
+	.driver = {
+		.name = IR_SPI_DRIVER_NAME,
+		.of_match_table = ir_spi_of_match,
+	},
+};
+
+module_spi_driver(ir_spi_driver);
+
+MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
+MODULE_DESCRIPTION("SPI IR LED");
+MODULE_LICENSE("GPL v2");
