Add abstraction for MIPI DCS/DBI like LCD controllers.
Signed-off-by: Noralf Trønnes <[email protected]>
---
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
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel