[RFC 6/7] staging: fbtft: extend core to use lcdctrl

Noralf Trønnes noralf at tronnes.org
Mon Mar 2 10:54:28 UTC 2015


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

Signed-off-by: Noralf Trønnes <noralf at 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



More information about the devel mailing list