diff mbox

parport: Add character LCD driver for da850/omap-l138

Message ID 1251840159-22313-1-git-send-email-sudhakar.raj@ti.com (mailing list archive)
State Superseded
Headers show

Commit Message

Rajashekhara, Sudhakar Sept. 1, 2009, 9:22 p.m. UTC
On TI DA850/OMAP-L138 EVM, HD44780 (24x2) LCD panel is
being used, interfaced through the SoC specific LCD
interface[1].

Driver from drivers/staging/panel/panel.c works for this
LCD panel but that driver expects the LCD panel to be
interfaced through a parallel port.

This patch implements a dummy parallel port driver which
interfaces to the panel driver in staging area through the
LCD interface available on SoC.

Signed-off-by: Sudhakar Rajashekhara <sudhakar.raj@ti.com>
---
 drivers/parport/Kconfig               |    8 +
 drivers/parport/Makefile              |    3 +-
 drivers/parport/parport_da8xx.c       |  324 +++++++++++++++++++++++++++++++++
 include/linux/parport_da8xx.h         |   28 +++
 4 files changed, 362 insertions(+), 1 deletions(-)
 create mode 100644 drivers/parport/parport_da8xx.c
 create mode 100644 include/linux/parport_da8xx.h

Comments

Rajashekhara, Sudhakar Sept. 2, 2009, 1:53 p.m. UTC | #1
On Tue, Sep 01, 2009 at 18:53:30, Pavel Machek wrote:
> Hi!
> 
> > On TI DA850/OMAP-L138 EVM, HD44780 (24x2) LCD panel is
> > being used, interfaced through the SoC specific LCD
> > interface[1].
> > 
> > Driver from drivers/staging/panel/panel.c works for this
> > LCD panel but that driver expects the LCD panel to be
> > interfaced through a parallel port.
> > 
> > This patch implements a dummy parallel port driver which
> > interfaces to the panel driver in staging area through the
> > LCD interface available on SoC.
> 
> This is a nasty hack, right? Just fixup panel.c to work with your
> interface, too?
> 								Pavel
> 

Agree, that this is a hack. I have submitted a patch which modifies
panel.c to support this kind of interface.

Currently the problem with panel.c is that, it is tightly coupled
with parallel port interface. Panel driver needs to be completely
re-written to de-couple parallel port related stuff. If I have to
do this, then I need to start from ground zero as I do not have a
setup on which HD44780 panel has been interfaced using parallel
port. But I can certainly help here by testing such a modification
to the panel driver by testing on the hardware what I have.

In the meantime, can I re-submit this patch by moving the dummy
parallel port driver to reside in staging area? Later it can be
moved/deleted depending on the modifications to the panel driver.

Regards, Sudhakar
Rajashekhara, Sudhakar Sept. 7, 2009, 1:55 p.m. UTC | #2
On Fri, Sep 04, 2009 at 03:50:42, Andrew Morton wrote:
> On Wed, 2 Sep 2009 19:23:27 +0530
> "Sudhakar Rajashekhara" <sudhakar.raj@ti.com> wrote:
> 
> > On Tue, Sep 01, 2009 at 18:53:30, Pavel Machek wrote:
> > > Hi!
> > > 
> > > > On TI DA850/OMAP-L138 EVM, HD44780 (24x2) LCD panel is
> > > > being used, interfaced through the SoC specific LCD
> > > > interface[1].
> > > > 
> > > > Driver from drivers/staging/panel/panel.c works for this
> > > > LCD panel but that driver expects the LCD panel to be
> > > > interfaced through a parallel port.
> > > > 
> > > > This patch implements a dummy parallel port driver which
> > > > interfaces to the panel driver in staging area through the
> > > > LCD interface available on SoC.
> > > 
> > > This is a nasty hack, right? Just fixup panel.c to work with your
> > > interface, too?
> > > 								Pavel
> > > 
> > 
> > Agree, that this is a hack. I have submitted a patch which modifies
> > panel.c to support this kind of interface.
> > 
> > Currently the problem with panel.c is that, it is tightly coupled
> > with parallel port interface. Panel driver needs to be completely
> > re-written to de-couple parallel port related stuff. If I have to
> > do this, then I need to start from ground zero as I do not have a
> > setup on which HD44780 panel has been interfaced using parallel
> > port. But I can certainly help here by testing such a modification
> > to the panel driver by testing on the hardware what I have.
> > 
> > In the meantime, can I re-submit this patch by moving the dummy
> > parallel port driver to reside in staging area? Later it can be
> > moved/deleted depending on the modifications to the panel driver.
> > 
> 
> If we're going to pull tricks like that then panel.c will never get
> itself moved from outside staging/ :(
> 
> Really, I don't think we should be hacking things into drivers/parport/
> code to accommodate design shortcomings in a staging/ driver.  Once done,
> these things have a tendency to never be undone.
> 

Is anyone working on cleaning up the panel driver under staging to
remove dependency on parallel port? If yes, please reply to this
mail, so that we can coordinate.

Regards, Sudhakar
diff mbox

Patch

diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 855f389..5709b88 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -154,6 +154,14 @@  config PARPORT_1284
 	  transfer modes. Also say Y if you want device ID information to
 	  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
 
+config PARPORT_DA8XX
+	tristate "DA8XX Dummy Parallel Port"
+	depends on ARCH_DAVINCI_DA8XX && !(FB_DA8XX = y) && !(FB_DA8XX = m)
+	select PARPORT_NOT_PC
+	help
+	  Say Y here if you need support for the DA8XX/OMAP-L1XX character
+	  LCD which is using the staging panel driver.
+
 config PARPORT_NOT_PC
 	bool
 
diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile
index 696b8d4..ad7dfd0 100644
--- a/drivers/parport/Makefile
+++ b/drivers/parport/Makefile
@@ -18,4 +18,5 @@  obj-$(CONFIG_PARPORT_ATARI)	+= parport_atari.o
 obj-$(CONFIG_PARPORT_SUNBPP)	+= parport_sunbpp.o
 obj-$(CONFIG_PARPORT_GSC)	+= parport_gsc.o
 obj-$(CONFIG_PARPORT_AX88796)	+= parport_ax88796.o
-obj-$(CONFIG_PARPORT_IP32)	+= parport_ip32.o
\ No newline at end of file
+obj-$(CONFIG_PARPORT_IP32)	+= parport_ip32.o
+obj-$(CONFIG_PARPORT_DA8XX)	+= parport_da8xx.o
diff --git a/drivers/parport/parport_da8xx.c b/drivers/parport/parport_da8xx.c
new file mode 100644
index 0000000..117123f
--- /dev/null
+++ b/drivers/parport/parport_da8xx.c
@@ -0,0 +1,324 @@ 
+/* linux/drivers/parport/parport_da8xx.c
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/parport_da8xx.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+/* LCDC register offsets */
+#define LCDC_LCD_CTRL			0x04
+#define LCDC_LIDD_CTRL			0x0c
+#define LCDC_LIDD_CS0_CONF		0x10
+#define LCDC_LIDD_CS0_ADDR		0x14
+#define LCDC_LIDD_CS0_DATA		0x18
+#define LCDC_LIDD_CS1_CONF		0x1c
+#define LCDC_LIDD_CS1_ADDR		0x20
+#define LCDC_LIDD_CS1_DATA		0x24
+
+#define LCD_CTRL_RASTER_MODE		BIT(0)
+#define LIDD_CONF_W_SU			BIT(27)
+#define LIDD_CONF_W_STROBE		(4 << 21)
+#define LIDD_CONF_W_HOLD		BIT(17)
+#define LIDD_CONF_R_SU			BIT(12)
+#define LIDD_CONF_R_STROBE		(4 << 6)
+#define LIDD_CONF_R_HOLD		BIT(2)
+#define LIDD_CTRL_MODE_SEL_MASK		0x7
+#define LIDD_CTRL_MODE_HITACHI		0x4
+
+struct da8xx_drvdata {
+	struct parport		*parport;
+
+	struct device		*dev;
+	struct resource		*io;
+	struct clk		*clk;
+
+	unsigned char		irq_enabled;
+	unsigned char		version;
+
+	void __iomem		*base;
+	void __iomem            *spp_data;
+	void __iomem            *spp_cpr;
+};
+
+static inline struct da8xx_drvdata *pp_to_drv(struct parport *p)
+{
+	return p->private_data;
+}
+
+static void
+parport_da8xx_init_state(struct pardevice *d, struct parport_state *s)
+{
+	struct da8xx_drvdata *dd = pp_to_drv(d->port);
+
+	memset(s, 0, sizeof(struct parport_state));
+
+	dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s);
+}
+
+static void
+parport_da8xx_save_state(struct parport *p, struct parport_state *s)
+{
+	/* do nothing */
+}
+
+static void
+parport_da8xx_restore_state(struct parport *p, struct parport_state *s)
+{
+	/* do nothing */
+}
+
+static unsigned char
+parport_da8xx_read_data(struct parport *p)
+{
+	struct da8xx_drvdata *dd = pp_to_drv(p);
+
+	return readl(dd->spp_data);
+}
+
+static void
+parport_da8xx_write_data(struct parport *p, unsigned char data)
+{
+	struct da8xx_drvdata *dd = pp_to_drv(p);
+
+	writel(data, dd->spp_data);
+}
+
+static unsigned char
+parport_da8xx_read_control(struct parport *p)
+{
+	struct da8xx_drvdata *dd = pp_to_drv(p);
+
+	return readl(dd->spp_cpr);
+}
+
+static void
+parport_da8xx_write_control(struct parport *p, unsigned char control)
+{
+	struct da8xx_drvdata *dd = pp_to_drv(p);
+
+	writel(control, dd->spp_cpr);
+}
+
+static void da8xx_init_clcd(struct parport *p)
+{
+	struct da8xx_drvdata *dd = pp_to_drv(p);
+	unsigned int regval;
+
+	regval = readl(dd->base + LCDC_LCD_CTRL);
+	regval &= ~LCD_CTRL_RASTER_MODE;
+	writel(regval, dd->base + LCDC_LCD_CTRL);
+
+	regval = readl(dd->base + LCDC_LCD_CTRL);
+	regval &= ~0xFF00;
+	writel(regval, dd->base + LCDC_LCD_CTRL);
+
+	regval = readl(dd->base + LCDC_LCD_CTRL);
+	regval |= 0x7F00;
+	writel(regval, dd->base + LCDC_LCD_CTRL);
+
+	regval = readl(dd->base + LCDC_LIDD_CTRL);
+	regval &= ~LIDD_CTRL_MODE_SEL_MASK;
+	writel(regval, dd->base + LCDC_LIDD_CTRL);
+
+	regval = readl(dd->base + LCDC_LIDD_CTRL);
+	regval |= LIDD_CTRL_MODE_HITACHI;
+	writel(regval, dd->base + LCDC_LIDD_CTRL);
+
+	regval = LIDD_CONF_W_SU | LIDD_CONF_W_STROBE | LIDD_CONF_W_HOLD |
+		LIDD_CONF_R_SU | LIDD_CONF_R_STROBE | LIDD_CONF_R_HOLD;
+
+	if (dd->version == CONFIG_SPACE_0)
+		writel(regval, dd->base + LCDC_LIDD_CS0_CONF);
+	else
+		writel(regval, dd->base + LCDC_LIDD_CS1_CONF);
+}
+
+static struct parport_operations parport_da8xx_ops = {
+	.init_state	= parport_da8xx_init_state,
+	.save_state	= parport_da8xx_save_state,
+	.restore_state	= parport_da8xx_restore_state,
+
+	.write_data	= parport_da8xx_write_data,
+	.read_data	= parport_da8xx_read_data,
+
+	.write_control	= parport_da8xx_write_control,
+	.read_control	= parport_da8xx_read_control,
+
+	.owner		= THIS_MODULE,
+};
+
+static int parport_da8xx_probe(struct platform_device *pdev)
+{
+	struct da8xx_clcd_platform_data *pdata = pdev->dev.platform_data;
+	struct device *_dev = &pdev->dev;
+	struct da8xx_drvdata *dd;
+	struct parport *pp = NULL;
+	struct resource *res;
+	unsigned long size;
+	int irq;
+	int ret;
+
+	dd = kzalloc(sizeof(struct da8xx_drvdata), GFP_KERNEL);
+	if (dd == NULL) {
+		dev_err(_dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(_dev, "no MEM specified\n");
+		ret = -ENXIO;
+		goto exit_mem;
+	}
+
+	size = resource_size(res);
+
+	dd->io = request_mem_region(res->start, size, pdev->name);
+	if (dd->io == NULL) {
+		dev_err(_dev, "cannot reserve memory\n");
+		ret = -ENXIO;
+		goto exit_mem;
+	}
+
+	dd->base = ioremap(res->start, size);
+	if (dd->base == NULL) {
+		dev_err(_dev, "cannot ioremap region\n");
+		ret = -ENXIO;
+		goto exit_res;
+	}
+
+	dd->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dd->clk)) {
+		dev_err(_dev, "Can not get device clock\n");
+		ret = -ENODEV;
+		goto exit_unmap;
+	}
+	clk_enable(dd->clk);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		irq = PARPORT_IRQ_NONE;
+
+	pp = parport_register_port((unsigned long)dd->base, irq,
+				   PARPORT_DMA_NONE,
+				   &parport_da8xx_ops);
+
+	if (pp == NULL) {
+		dev_err(_dev, "failed to register parallel port\n");
+		ret = -ENOMEM;
+		goto exit_clk_put;
+	}
+
+	pp->private_data = dd;
+	dd->parport = pp;
+	dd->dev = pp->dev = _dev;
+	dd->version = pdata->version;
+
+	if (dd->version == CONFIG_SPACE_0) {
+		dd->spp_data = dd->base + LCDC_LIDD_CS0_DATA;
+		dd->spp_cpr  = dd->base + LCDC_LIDD_CS0_ADDR;
+	} else {
+		dd->spp_data = dd->base + LCDC_LIDD_CS1_DATA;
+		dd->spp_cpr  = dd->base + LCDC_LIDD_CS1_ADDR;
+	}
+
+	/* initialize LCDC */
+	da8xx_init_clcd(pp);
+
+	if (irq >= 0) {
+		/* request irq */
+		ret = request_irq(irq, parport_irq_handler,
+				  IRQF_TRIGGER_FALLING, pdev->name, pp);
+
+		if (ret < 0)
+			goto exit_port;
+
+		dd->irq_enabled = 1;
+	}
+
+	platform_set_drvdata(pdev, pp);
+
+	dev_info(_dev, "attached parallel port driver\n");
+	parport_announce_port(pp);
+
+	return 0;
+
+ exit_port:
+	parport_remove_port(pp);
+ exit_clk_put:
+	clk_disable(dd->clk);
+	clk_put(dd->clk);
+ exit_unmap:
+	iounmap(dd->base);
+ exit_res:
+	release_resource(dd->io);
+	kfree(dd->io);
+ exit_mem:
+	kfree(dd);
+	return ret;
+}
+
+static int parport_da8xx_remove(struct platform_device *pdev)
+{
+	struct parport *p = platform_get_drvdata(pdev);
+	struct da8xx_drvdata *dd = pp_to_drv(p);
+
+	free_irq(p->irq, p);
+	parport_remove_port(p);
+	clk_disable(dd->clk);
+	clk_put(dd->clk);
+	iounmap(dd->base);
+	release_resource(dd->io);
+	kfree(dd->io);
+	kfree(dd);
+
+	return 0;
+}
+
+MODULE_ALIAS("platform:da8xx_lcdc");
+
+static struct platform_driver da8xx_drv = {
+	.driver		= {
+		.name	= "da8xx_lcdc",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= parport_da8xx_probe,
+	.remove		= parport_da8xx_remove,
+};
+
+static int __init parport_da8xx_init(void)
+{
+	return platform_driver_register(&da8xx_drv);
+}
+
+static void __exit parport_da8xx_exit(void)
+{
+	platform_driver_unregister(&da8xx_drv);
+}
+
+module_init(parport_da8xx_init)
+module_exit(parport_da8xx_exit)
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("DA8xx/OMAP-L1xx Parport parallel port driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/parport_da8xx.h b/include/linux/parport_da8xx.h
new file mode 100644
index 0000000..53a01a3
--- /dev/null
+++ b/include/linux/parport_da8xx.h
@@ -0,0 +1,28 @@ 
+/*
+ * Header file for TI DA8XX/OMAP-L1XX LCD controller platform data.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PARPORT_DA8XX_H
+#define PARPORT_DA8XX_H
+
+struct da8xx_clcd_platform_data {
+	u8 version;
+};
+
+enum {
+	CONFIG_SPACE_0 = 0,	/* DA830 */
+	CONFIG_SPACE_1,		/* DA850 */
+};
+
+#endif  /* ifndef PARPORT_DA8XX_H */