Add lcdctrl support in core fbtft module.
Provide new API for drivers to use.

Signed-off-by: Noralf Trønnes <nor...@tronnes.org>
---
 drivers/staging/fbtft/Makefile        |   1 +
 drivers/staging/fbtft/fbtft-lcdctrl.c | 311 ++++++++++++++++++++++++++++++++++
 drivers/staging/fbtft/fbtft.h         |  13 ++
 3 files changed, 325 insertions(+)
 create mode 100644 drivers/staging/fbtft/fbtft-lcdctrl.c

diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile
index 69f7c2c..6f002a6 100644
--- a/drivers/staging/fbtft/Makefile
+++ b/drivers/staging/fbtft/Makefile
@@ -1,6 +1,7 @@
 # Core modules
 obj-$(CONFIG_FB_TFT)             += fbtft.o
 fbtft-y                          += fbtft-core.o fbtft-sysfs.o fbtft-bus.o 
fbtft-io.o
+fbtft-$(if $(CONFIG_LCDCTRL),y,) += fbtft-lcdctrl.o
 
 obj-$(CONFIG_LCDREG)             += lcdreg/
 obj-$(CONFIG_LCDCTRL)            += lcdctrl/
diff --git a/drivers/staging/fbtft/fbtft-lcdctrl.c 
b/drivers/staging/fbtft/fbtft-lcdctrl.c
new file mode 100644
index 0000000..b4e6011
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-lcdctrl.c
@@ -0,0 +1,311 @@
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+
+#include "fbtft.h"
+
+extern void fbtft_sysfs_init(struct fbtft_par *par);
+
+static int fbtft_lcdctrl_blank(struct fbtft_par *par, bool on)
+{
+       struct lcdctrl *ctrl = par->lcdctrl;
+
+       if (ctrl->blank)
+               return lcdctrl_blank(ctrl, on);
+       else if (par->info->bl_dev)
+               return 0; /* backlight subsystem handles blanking */
+       else
+               return -EINVAL; /* no blanking support */
+}
+
+static void fbtft_lcdctrl_update_display(struct fbtft_par *par,
+                                       unsigned start_line, unsigned end_line)
+{
+       struct lcdctrl *ctrl = par->lcdctrl;
+       struct lcdctrl_update update = {
+               .base = (void __force *)par->info->screen_base,
+               .ys = start_line,
+               .ye = end_line,
+       };
+       int ret;
+
+       ret = lcdctrl_update(ctrl, &update);
+       if (ret)
+               pr_err_once("%s %s: lcdctrl_update failed: %i\n",
+                           dev_driver_string(ctrl->lcdreg->dev),
+                           dev_name(ctrl->lcdreg->dev), ret);
+}
+
+static int fbtft_fb_check_var(struct fb_var_screeninfo *var, struct fb_info 
*info)
+{
+       u32 rotate = var->rotate;
+
+       *var = info->var;
+       var->rotate = rotate;
+
+       switch (var->rotate) {
+       case 0:
+       case 90:
+       case 180:
+       case 270:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int fbtft_fb_set_par(struct fb_info *info)
+{
+       struct fbtft_par *par = info->par;
+       struct lcdctrl *ctrl = par->lcdctrl;
+       int ret;
+
+       lcdreg_lock(ctrl->lcdreg);
+
+       ret = _lcdctrl_rotate(ctrl, info->var.rotate);
+       if (ret) {
+               info->var.rotate = ctrl->rotation;
+               goto rotate_failed;
+       }
+
+       info->var.xres = lcdctrl_xres(ctrl);
+       info->var.yres = lcdctrl_yres(ctrl);
+       info->var.xres_virtual = info->var.xres;
+       info->var.yres_virtual = info->var.yres;
+
+       switch (info->var.bits_per_pixel) {
+       case 1:
+               info->fix.line_length = info->var.xres / 8;
+               break;
+       case 8:
+               info->fix.line_length = info->var.xres;
+               break;
+       case 16:
+               info->fix.line_length = info->var.xres * 2;
+               break;
+       case 24:
+               info->fix.line_length = info->var.xres * 3;
+               break;
+       case 32:
+               info->fix.line_length = info->var.xres * 4;
+               break;
+       }
+
+rotate_failed:
+       lcdreg_unlock(ctrl->lcdreg);
+
+       return ret;
+}
+
+static struct fb_info *fbtft_lcdctrl_register(struct lcdctrl *ctrl)
+{
+       struct device *dev = ctrl->lcdreg->dev;
+       struct fb_info *info;
+       struct fbtft_par *par;
+       int ret;
+       struct fbtft_display display = {
+               .width = lcdctrl_xres(ctrl),
+               .height = lcdctrl_yres(ctrl),
+               .fps = 20,
+               .txbuflen = -2, /* don't allocate txbuf */
+       };
+
+       switch (ctrl->format) {
+       case LCDCTRL_FORMAT_MONO10:
+               display.bpp = 1;
+               break;
+       case LCDCTRL_FORMAT_RGB565:
+               display.bpp = 16;
+               break;
+       case LCDCTRL_FORMAT_RGB888:
+               display.bpp = 24;
+               break;
+       case LCDCTRL_FORMAT_XRGB8888:
+               display.bpp = 32;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+
+       info = fbtft_framebuffer_alloc(&display, dev);
+       if (!info)
+               return ERR_PTR(-ENOMEM);
+
+       switch (ctrl->format) {
+       case LCDCTRL_FORMAT_MONO10:
+               info->fix.visual = FB_VISUAL_MONO10;
+               info->var.red.length = 1;
+               info->var.red.offset = 0;
+               info->var.green.length = 1;
+               info->var.green.offset = 0;
+               info->var.blue.length = 1;
+               info->var.blue.offset = 0;
+               break;
+       case LCDCTRL_FORMAT_RGB565:
+               /* set by fbtft_framebuffer_alloc() */
+               break;
+       case LCDCTRL_FORMAT_RGB888:
+               info->var.red.offset = 16;
+               info->var.red.length = 8;
+               info->var.green.offset = 8;
+               info->var.green.length = 8;
+               info->var.blue.offset = 0;
+               info->var.blue.length = 8;
+               break;
+       case LCDCTRL_FORMAT_XRGB8888:
+               info->var.red.offset = 16;
+               info->var.red.length = 8;
+               info->var.green.offset = 8;
+               info->var.green.length = 8;
+               info->var.blue.offset = 0;
+               info->var.blue.length = 8;
+               break;
+       default:
+               ret = -EINVAL;
+               goto err_release;
+       }
+
+       par = info->par;
+       par->lcdctrl = ctrl;
+       par->fbtftops.blank = fbtft_lcdctrl_blank;
+       par->fbtftops.update_display = fbtft_lcdctrl_update_display;
+       if (ctrl->rotate) {
+               info->var.rotate = ctrl->rotation;
+               info->fbops->fb_check_var = fbtft_fb_check_var;
+               info->fbops->fb_set_par = fbtft_fb_set_par;
+       }
+
+       ret = lcdctrl_enable(ctrl, info->screen_base);
+       if (ret)
+               goto err_release;
+
+       ret = register_framebuffer(info);
+       if (ret)
+               goto err_release;
+
+       fbtft_sysfs_init(par);
+       dev_set_drvdata(dev, info);
+
+       dev_info(info->dev, "%s frame buffer, %ux%u, %u KiB video memory\n",
+                info->fix.id, info->var.xres, info->var.yres,
+                info->fix.smem_len >> 10);
+
+       return info;
+
+err_release:
+       fbtft_framebuffer_release(info);
+
+       return ERR_PTR(ret);
+}
+
+static void fbtft_lcdctrl_release(struct fb_info *info)
+{
+       struct fbtft_par *par = info->par;
+       struct lcdctrl *ctrl = par->lcdctrl;
+
+       fb_blank(info, FB_BLANK_POWERDOWN);
+       if (info->bl_dev) {
+               put_device(&info->bl_dev->dev);
+               info->bl_dev = NULL;
+       }
+       lcdctrl_disable(ctrl);
+       fbtft_unregister_framebuffer(info);
+       fbtft_framebuffer_release(info);
+}
+
+static void devm_lcdctrl_release(struct device *dev, void *res)
+{
+       fbtft_lcdctrl_release(*(struct fb_info **)res);
+}
+
+int devm_fbtft_lcdctrl_register(struct lcdctrl *ctrl)
+{
+       struct fb_info **ptr;
+
+       if (WARN_ON(!ctrl || !ctrl->lcdreg || !ctrl->lcdreg->dev))
+               return -EINVAL;
+
+       ptr = devres_alloc(devm_lcdctrl_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       *ptr = fbtft_lcdctrl_register(ctrl);
+       if (IS_ERR(*ptr)) {
+               int ret = PTR_ERR(*ptr);
+
+               devres_free(ptr);
+               return ret;
+       }
+
+       devres_add(ctrl->lcdreg->dev, ptr);
+
+       return 0;
+}
+EXPORT_SYMBOL(devm_fbtft_lcdctrl_register);
+
+int devm_fbtft_lcdctrl_of_register(struct lcdctrl *ctrl)
+{
+       struct device *dev;
+       struct device_node *backlight_node;
+       struct backlight_device *backlight = NULL;
+       int ret;
+
+       if (WARN_ON(!ctrl || !ctrl->lcdreg || !ctrl->lcdreg->dev))
+               return -EINVAL;
+
+       dev = ctrl->lcdreg->dev;
+       ctrl->initialized = of_property_read_bool(dev->of_node, "initialized");
+       ctrl->power_supply = devm_regulator_get(dev, "power");
+       if (IS_ERR(ctrl->power_supply))
+               return PTR_ERR(ctrl->power_supply);
+
+       backlight_node = of_parse_phandle(dev->of_node, "backlight", 0);
+       if (backlight_node) {
+               backlight = of_find_backlight_by_node(backlight_node);
+               of_node_put(backlight_node);
+               if (!backlight)
+                       return -EPROBE_DEFER;
+       }
+
+       lcdctrl_of_get_format(ctrl);
+       lcdctrl_of_get_rotation(ctrl);
+
+       ret = devm_fbtft_lcdctrl_register(ctrl);
+       if (ret)
+               return ret;
+
+       if (backlight) {
+               struct fb_info *info = dev_get_drvdata(dev);
+
+               info->bl_dev = backlight;
+               get_device(&info->bl_dev->dev);
+               if (backlight->props.brightness == 0)
+                       backlight->props.brightness = 
backlight->props.max_brightness;
+               fb_blank(info, FB_BLANK_UNBLANK);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(devm_fbtft_lcdctrl_of_register);
+
+#ifdef CONFIG_PM_SLEEP
+static int fbtft_pm_suspend(struct device *dev)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct fbtft_par *par = info->par;
+
+       lcdctrl_disable(par->lcdctrl);
+
+       return 0;
+}
+
+static int fbtft_pm_resume(struct device *dev)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct fbtft_par *par = info->par;
+
+       return lcdctrl_enable(par->lcdctrl, info->screen_base);
+}
+
+SIMPLE_DEV_PM_OPS(fbtft_pm_ops, fbtft_pm_suspend, fbtft_pm_resume);
+EXPORT_SYMBOL(fbtft_pm_ops);
+#endif
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index 0dbf3f9..d64aded 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -24,6 +24,8 @@
 #include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 
+#include "lcdctrl/lcdctrl.h"
+
 
 #define FBTFT_NOP              0x00
 #define FBTFT_SWRESET  0x01
@@ -214,6 +216,7 @@ struct fbtft_platform_data {
  * @extra: Extra info needed by driver
  */
 struct fbtft_par {
+       struct lcdctrl *lcdctrl;
        struct spi_device *spi;
        struct platform_device *pdev;
        struct fb_info *info;
@@ -298,6 +301,16 @@ extern void fbtft_write_reg8_bus9(struct fbtft_par *par, 
int len, ...);
 extern void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...);
 extern void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...);
 
+/* fbtft-lcdctrl.c */
+extern int devm_fbtft_lcdctrl_register(struct lcdctrl *ctrl);
+extern int devm_fbtft_lcdctrl_of_register(struct lcdctrl *ctrl);
+
+#ifdef CONFIG_PM_SLEEP
+extern const struct dev_pm_ops fbtft_pm_ops;
+#define FBTFT_PM_OPS (&fbtft_pm_ops)
+#else
+#define FBTFT_PM_OPS NULL
+#endif
 
 #define FBTFT_REGISTER_DRIVER(_name, _compatible, _display)                \
                                                                           \
-- 
2.2.2

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

Reply via email to