[RFC 2/7] staging: fbtft: lcdreg: add i2c support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add I2C bus support to lcdreg.

Signed-off-by: Noralf Trønnes <noralf@xxxxxxxxxxx>
---
 drivers/staging/fbtft/lcdreg/Kconfig      |   6 ++
 drivers/staging/fbtft/lcdreg/Makefile     |   2 +
 drivers/staging/fbtft/lcdreg/lcdreg-i2c.c | 129 ++++++++++++++++++++++++++++++
 drivers/staging/fbtft/lcdreg/lcdreg.h     |   3 +
 4 files changed, 140 insertions(+)
 create mode 100644 drivers/staging/fbtft/lcdreg/lcdreg-i2c.c

diff --git a/drivers/staging/fbtft/lcdreg/Kconfig b/drivers/staging/fbtft/lcdreg/Kconfig
index ec0c097..8f000b5 100644
--- a/drivers/staging/fbtft/lcdreg/Kconfig
+++ b/drivers/staging/fbtft/lcdreg/Kconfig
@@ -2,3 +2,9 @@ config LCDREG
 	tristate
 	depends on GPIOLIB
 	default n
+
+config LCDREG_I2C
+	tristate
+	depends on I2C
+	select LCDREG
+	default n
diff --git a/drivers/staging/fbtft/lcdreg/Makefile b/drivers/staging/fbtft/lcdreg/Makefile
index c9ea774..1ec65af 100644
--- a/drivers/staging/fbtft/lcdreg/Makefile
+++ b/drivers/staging/fbtft/lcdreg/Makefile
@@ -1,3 +1,5 @@
 obj-$(CONFIG_LCDREG)                   += lcdreg.o
 lcdreg-y                               += lcdreg-core.o
 lcdreg-$(CONFIG_DEBUG_FS)              += lcdreg-debugfs.o
+
+obj-$(CONFIG_LCDREG_I2C)               += lcdreg-i2c.o
diff --git a/drivers/staging/fbtft/lcdreg/lcdreg-i2c.c b/drivers/staging/fbtft/lcdreg/lcdreg-i2c.c
new file mode 100644
index 0000000..297926f
--- /dev/null
+++ b/drivers/staging/fbtft/lcdreg/lcdreg-i2c.c
@@ -0,0 +1,129 @@
+/*
+ * lcdreg I2C support
+ *
+ * Copyright 2015 Noralf Trønnes
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "lcdreg.h"
+
+struct lcdreg_i2c {
+	struct lcdreg reg;
+	struct i2c_client *client;
+	struct gpio_desc *reset;
+};
+
+static inline struct lcdreg_i2c *to_lcdreg_i2c(struct lcdreg *reg)
+{
+	return reg ? container_of(reg, struct lcdreg_i2c, reg) : NULL;
+}
+
+static int lcdreg_i2c_send(struct i2c_client *client, unsigned index,
+			   void *buf, size_t len)
+{
+	u8 *txbuf;
+	int ret;
+
+	txbuf = kmalloc(1 + len, GFP_KERNEL);
+	if (!txbuf)
+		return -ENOMEM;
+
+	txbuf[0] = index ? 0x40 : 0x80;
+	memcpy(&txbuf[1], buf, len);
+
+	ret = i2c_master_send(client, txbuf, 1 + len);
+	kfree(txbuf);
+
+	return ret < 0 ? ret : 0;
+}
+
+static int lcdreg_i2c_write(struct lcdreg *reg, unsigned regnr,
+			    struct lcdreg_transfer *transfer)
+{
+	struct lcdreg_i2c *i2c = to_lcdreg_i2c(reg);
+	u8 regnr_buf[1] = { regnr };
+	int ret;
+
+	ret = lcdreg_i2c_send(i2c->client, 0, regnr_buf, 1);
+	if (ret)
+		return ret;
+
+	if (!transfer || !transfer->count)
+		return 0;
+
+	if (WARN_ON(transfer->width != 8))
+		return -EINVAL;
+
+	if (!transfer->count)
+		return 0;
+
+	return lcdreg_i2c_send(i2c->client, transfer->index, transfer->buf,
+			       transfer->count);
+}
+
+static int lcdreg_i2c_read(struct lcdreg *reg, unsigned regnr,
+			   struct lcdreg_transfer *transfer)
+{
+	struct lcdreg_i2c *i2c = to_lcdreg_i2c(reg);
+	int ret;
+
+	if (WARN_ON(regnr != 0 || !transfer || transfer->width != 8))
+		return -EINVAL;
+
+	if (!reg->readable)
+		return -EACCES;
+
+	ret = i2c_master_recv(i2c->client, transfer->buf, transfer->count);
+
+	return ret < 0 ? ret : 0;
+}
+
+static void lcdreg_i2c_reset(struct lcdreg *reg)
+{
+	struct lcdreg_i2c *i2c = to_lcdreg_i2c(reg);
+
+	if (!i2c->reset)
+		return;
+
+	gpiod_set_value_cansleep(i2c->reset, 0);
+	msleep(20);
+	gpiod_set_value_cansleep(i2c->reset, 1);
+	msleep(120);
+}
+
+struct lcdreg *devm_lcdreg_i2c_init(struct i2c_client *client)
+{
+	struct lcdreg_i2c *i2c;
+
+	i2c = devm_kzalloc(&client->dev, sizeof(*i2c), GFP_KERNEL);
+	if (i2c == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	i2c->reg.readable = true;
+	i2c->client = client;
+	i2c->reset = devm_gpiod_get_optional(&client->dev, "reset",
+					     GPIOD_OUT_HIGH);
+	if (IS_ERR(i2c->reset))
+		return ERR_PTR(PTR_ERR(i2c->reset));
+
+	i2c->reg.write = lcdreg_i2c_write;
+	i2c->reg.read = lcdreg_i2c_read;
+	i2c->reg.reset = lcdreg_i2c_reset;
+
+	return devm_lcdreg_init(&client->dev, &i2c->reg);
+}
+EXPORT_SYMBOL(devm_lcdreg_i2c_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/lcdreg/lcdreg.h b/drivers/staging/fbtft/lcdreg/lcdreg.h
index 0ddf40e..4fa5aea 100644
--- a/drivers/staging/fbtft/lcdreg/lcdreg.h
+++ b/drivers/staging/fbtft/lcdreg/lcdreg.h
@@ -11,6 +11,7 @@
 #define __LINUX_LCDREG_H
 
 #include <linux/device.h>
+#include <linux/i2c.h>
 #include <linux/mutex.h>
 
 /**
@@ -121,6 +122,8 @@ static inline unsigned lcdreg_bytes_per_word(unsigned bits_per_word)
 		return 4;
 }
 
+struct lcdreg *devm_lcdreg_i2c_init(struct i2c_client *client);
+
 #if defined(CONFIG_DYNAMIC_DEBUG)
 
 #define lcdreg_dbg_transfer_buf(transfer)                            \
-- 
2.2.2

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux