Add abstraction for MIPI DCS/DBI like LCD controllers.

Signed-off-by: Noralf Trønnes <nor...@tronnes.org>
---
 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
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to