[RFC 3/7] staging: fbtft: add lcd controller abstraction

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

 



Add abstraction for MIPI DCS/DBI like LCD controllers.

Signed-off-by: Noralf Trønnes <noralf@xxxxxxxxxxx>
---
 drivers/staging/fbtft/Kconfig           |   1 +
 drivers/staging/fbtft/Makefile          |   1 +
 drivers/staging/fbtft/lcdctrl/Kconfig   |   3 +
 drivers/staging/fbtft/lcdctrl/Makefile  |   1 +
 drivers/staging/fbtft/lcdctrl/lcdctrl.c | 207 ++++++++++++++++++++++++++++++++
 drivers/staging/fbtft/lcdctrl/lcdctrl.h | 104 ++++++++++++++++
 6 files changed, 317 insertions(+)
 create mode 100644 drivers/staging/fbtft/lcdctrl/Kconfig
 create mode 100644 drivers/staging/fbtft/lcdctrl/Makefile
 create mode 100644 drivers/staging/fbtft/lcdctrl/lcdctrl.c
 create mode 100644 drivers/staging/fbtft/lcdctrl/lcdctrl.h

diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig
index 2d1490f..0ac1b41 100644
--- a/drivers/staging/fbtft/Kconfig
+++ b/drivers/staging/fbtft/Kconfig
@@ -168,4 +168,5 @@ config FB_TFT_FBTFT_DEVICE
 	tristate "Module to for adding FBTFT devices"
 	depends on FB_TFT
 
+source "drivers/staging/fbtft/lcdctrl/Kconfig"
 source "drivers/staging/fbtft/lcdreg/Kconfig"
diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile
index 2769421..69f7c2c 100644
--- a/drivers/staging/fbtft/Makefile
+++ b/drivers/staging/fbtft/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_FB_TFT)             += fbtft.o
 fbtft-y                          += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o
 
 obj-$(CONFIG_LCDREG)             += lcdreg/
+obj-$(CONFIG_LCDCTRL)            += lcdctrl/
 
 # Controller drivers
 obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o
diff --git a/drivers/staging/fbtft/lcdctrl/Kconfig b/drivers/staging/fbtft/lcdctrl/Kconfig
new file mode 100644
index 0000000..5272847
--- /dev/null
+++ b/drivers/staging/fbtft/lcdctrl/Kconfig
@@ -0,0 +1,3 @@
+config LCDCTRL
+	tristate
+	default n
diff --git a/drivers/staging/fbtft/lcdctrl/Makefile b/drivers/staging/fbtft/lcdctrl/Makefile
new file mode 100644
index 0000000..e6e4e8c
--- /dev/null
+++ b/drivers/staging/fbtft/lcdctrl/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_LCDCTRL)                  += lcdctrl.o
diff --git a/drivers/staging/fbtft/lcdctrl/lcdctrl.c b/drivers/staging/fbtft/lcdctrl/lcdctrl.c
new file mode 100644
index 0000000..028fc6b
--- /dev/null
+++ b/drivers/staging/fbtft/lcdctrl/lcdctrl.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 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/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include "lcdctrl.h"
+
+void lcdctrl_of_get_format(struct lcdctrl *ctrl)
+{
+	struct device *dev = ctrl->lcdreg->dev;
+	const char *fmt_str;
+	int ret;
+
+	if (!ctrl->set_format)
+		return;
+
+	ret = of_property_read_string(dev->of_node, "format", &fmt_str);
+	if (ret)
+		return;
+
+	if (!strcmp(fmt_str, "monochrome"))
+		ctrl->format = LCDCTRL_FORMAT_MONO10;
+	else if (!strcmp(fmt_str, "rgb565"))
+		ctrl->format = LCDCTRL_FORMAT_RGB565;
+	else if (!strcmp(fmt_str, "rgb888"))
+		ctrl->format = LCDCTRL_FORMAT_RGB888;
+	else if (!strcmp(fmt_str, "xrgb8888"))
+		ctrl->format = LCDCTRL_FORMAT_XRGB8888;
+	else
+		dev_err(dev, "Invalid format: %s. Using default.\n", fmt_str);
+}
+EXPORT_SYMBOL(lcdctrl_of_get_format);
+
+void lcdctrl_of_get_rotation(struct lcdctrl *ctrl)
+{
+	struct device *dev = ctrl->lcdreg->dev;
+	u32 val;
+	int ret;
+
+	if (!ctrl->rotate)
+		return;
+
+	ret = of_property_read_u32(dev->of_node, "rotation", &val);
+	if (ret) {
+		if (ret != -EINVAL)
+			dev_err(dev, "error reading property 'rotation': %i\n",
+				ret);
+		return;
+	}
+
+	switch (val) {
+	case 0:
+	case 90:
+	case 180:
+	case 270:
+		ctrl->rotation = val;
+		break;
+	default:
+		dev_err(dev, "illegal rotation value: %u\n", val);
+		break;
+	}
+}
+EXPORT_SYMBOL(lcdctrl_of_get_rotation);
+
+int lcdctrl_enable(struct lcdctrl *ctrl, void *videomem)
+{
+	struct lcdctrl_update update = {
+		.base = videomem,
+		.ys = 0,
+		.ye = lcdctrl_yres(ctrl) - 1,
+	};
+	int ret;
+
+	if (WARN_ON_ONCE(!ctrl->update))
+		return -EINVAL;
+
+	if (ctrl->initialized)
+		return 0;
+
+	lcdreg_lock(ctrl->lcdreg);
+
+	if (ctrl->power_supply) {
+		ret = regulator_enable(ctrl->power_supply);
+		if (ret) {
+			dev_err(ctrl->lcdreg->dev,
+				"failed to enable power supply: %d\n", ret);
+			goto enable_failed;
+		}
+	}
+	if (ctrl->poweron) {
+		ret = ctrl->poweron(ctrl);
+		if (ret)
+			goto enable_failed;
+	}
+
+	if (ctrl->set_format) {
+		ret = ctrl->set_format(ctrl);
+		if (ret) {
+			dev_err(ctrl->lcdreg->dev,
+				"failed to set format '%d'\n", ctrl->format);
+			goto enable_failed;
+		}
+	}
+
+	if (ctrl->rotate) {
+		ret = _lcdctrl_rotate(ctrl, ctrl->rotation);
+		if (ret)
+			goto enable_failed;
+	}
+
+	ret = ctrl->update(ctrl, &update);
+	if (ret)
+		goto enable_failed;
+
+	if (ctrl->blank) {
+		ret = ctrl->blank(ctrl, false);
+		if (ret)
+			goto enable_failed;
+	}
+
+	ctrl->initialized = true;
+
+enable_failed:
+	lcdreg_unlock(ctrl->lcdreg);
+
+	return ret;
+}
+EXPORT_SYMBOL(lcdctrl_enable);
+
+void lcdctrl_disable(struct lcdctrl *ctrl)
+{
+	lcdreg_lock(ctrl->lcdreg);
+
+	if (ctrl->blank)
+		ctrl->blank(ctrl, true);
+	if (ctrl->poweroff)
+		ctrl->poweroff(ctrl);
+	if (ctrl->power_supply)
+		regulator_disable(ctrl->power_supply);
+	ctrl->initialized = false;
+
+	lcdreg_unlock(ctrl->lcdreg);
+}
+EXPORT_SYMBOL(lcdctrl_disable);
+
+int lcdctrl_update(struct lcdctrl *ctrl, struct lcdctrl_update *update)
+{
+	u32 yres = lcdctrl_yres(ctrl);
+	int ret;
+
+	if (!ctrl->initialized)
+		return -EINVAL;
+
+	lcdreg_lock(ctrl->lcdreg);
+
+	if (update->ys > update->ye) {
+		update->ys = 0;
+		update->ye = yres - 1;
+	}
+	if (update->ye >= yres)
+		update->ye = yres - 1;
+
+	ret = ctrl->update(ctrl, update);
+
+	lcdreg_unlock(ctrl->lcdreg);
+
+	return ret;
+}
+EXPORT_SYMBOL(lcdctrl_update);
+
+/**
+ * Caller is responsible for locking.
+ */
+int _lcdctrl_rotate(struct lcdctrl *ctrl, u32 rotation)
+{
+	int ret;
+
+	if (!ctrl->rotate)
+		return -ENOSYS;
+
+	switch (rotation) {
+	case 0:
+	case 90:
+	case 180:
+	case 270:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = ctrl->rotate(ctrl, rotation);
+	if (!ret)
+		ctrl->rotation = rotation;
+
+	return ret;
+}
+EXPORT_SYMBOL(_lcdctrl_rotate);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/lcdctrl/lcdctrl.h b/drivers/staging/fbtft/lcdctrl/lcdctrl.h
new file mode 100644
index 0000000..e74a66d
--- /dev/null
+++ b/drivers/staging/fbtft/lcdctrl/lcdctrl.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef __LINUX_LCDCTRL_H
+#define __LINUX_LCDCTRL_H
+
+#include "../lcdreg/lcdreg.h"
+
+enum lcdctrl_format {
+	LCDCTRL_FORMAT_NONE = 0,
+	LCDCTRL_FORMAT_MONO10,
+	LCDCTRL_FORMAT_RGB565,
+	LCDCTRL_FORMAT_RGB888,
+	LCDCTRL_FORMAT_XRGB8888,
+};
+
+/**
+ * Description of a display update
+ *
+ * @base: Base address of video memory
+ * @ys: Horizontal line to start the transfer from (zero based)
+ * @ye: Last line to transfer (inclusive)
+ */
+struct lcdctrl_update {
+	void *base;
+	u32 ys;
+	u32 ye;
+};
+
+/**
+ * Description of LCD controller
+ *
+ * @width: Width of display in pixels
+ * @height: Height of display in pixels
+ * @rotation: Display rotation Counter Clockwise (0,90,180,270)
+ * @format: Videomemory format
+ * @initialized: Controller is initialized
+ * @poweron: Power on operation (optional)
+ * @poweroff: Power off operation (optional)
+ * @update: Updates the controllers video memory
+ * @rotate: Rotates the display (optional)
+ * @set_format: Sets format according to @format (optional)
+ * @blank: Blanks display (optional)
+ * @lcdreg: LCD register operated upon
+ * @driver_private: Driver data (not touched by core)
+ * @power_supply: Regulator for power supply
+ */
+struct lcdctrl {
+	u32 width;
+	u32 height;
+	u32 rotation;
+	enum lcdctrl_format format;
+	bool initialized;
+
+	int (*poweron)(struct lcdctrl *ctrl);
+	void (*poweroff)(struct lcdctrl *ctrl);
+	int (*update)(struct lcdctrl *ctrl, struct lcdctrl_update *update);
+	int (*rotate)(struct lcdctrl *ctrl, u32 rotation);
+	int (*set_format)(struct lcdctrl *ctrl);
+	int (*blank)(struct lcdctrl *ctrl, bool blank);
+
+	struct lcdreg *lcdreg;
+	struct regulator *power_supply;
+	void *driver_private;
+};
+
+static inline u32 lcdctrl_xres(struct lcdctrl *ctrl)
+{
+	return (ctrl->rotation % 180) ? ctrl->height : ctrl->width;
+}
+
+static inline u32 lcdctrl_yres(struct lcdctrl *ctrl)
+{
+	return (ctrl->rotation % 180) ? ctrl->width : ctrl->height;
+}
+
+static inline int lcdctrl_blank(struct lcdctrl *ctrl, bool blank)
+{
+	int ret;
+
+	if (!ctrl->blank)
+		return -ENOSYS;
+
+	lcdreg_lock(ctrl->lcdreg);
+	ret = ctrl->blank(ctrl, blank);
+	lcdreg_unlock(ctrl->lcdreg);
+
+	return ret;
+}
+
+extern void lcdctrl_of_get_format(struct lcdctrl *ctrl);
+extern void lcdctrl_of_get_rotation(struct lcdctrl *ctrl);
+extern int lcdctrl_enable(struct lcdctrl *ctrl, void *videomem);
+extern void lcdctrl_disable(struct lcdctrl *ctrl);
+extern int lcdctrl_update(struct lcdctrl *ctrl, struct lcdctrl_update *update);
+extern int _lcdctrl_rotate(struct lcdctrl *ctrl, u32 rotate);
+
+#endif /* __LINUX_LCDCTRL_H */
-- 
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