[ARM] 5354/1: mach-pxa: add AM300 platform driver v3
authorJaya Kumar <jayakumar.lkml@gmail.com>
Thu, 1 Jan 2009 16:51:01 +0000 (17:51 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 10 Feb 2009 11:28:00 +0000 (11:28 +0000)
This patch adds support for the AM300 platform driver which uses the
E-Ink broadsheetfb display driver.

Cc: Eric Miao <eric.miao@marvell.com>
Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/am300epd.c [new file with mode: 0644]
arch/arm/mach-pxa/gumstix.c
arch/arm/mach-pxa/include/mach/gumstix.h

index ffd28e48d75f5ffbb5136730816493964974d87e..9c2221c236635f9a20eaff64a98ba9c4ce8b2a06 100644 (file)
@@ -40,6 +40,9 @@ choice
 config GUMSTIX_AM200EPD
        bool "Enable AM200EPD board support"
 
+config GUMSTIX_AM300EPD
+       bool "Enable AM300EPD board support"
+
 endchoice
 
 config MACH_INTELMOTE2
index 146aba72fa229bbcd3f6f422d51e827e226b561f..6bfbddc5769d5916b2d1c25332b86093e8df0961 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_CPU_PXA930)      += pxa930.o
 # Specific board support
 obj-$(CONFIG_ARCH_GUMSTIX)     += gumstix.o
 obj-$(CONFIG_GUMSTIX_AM200EPD) += am200epd.o
+obj-$(CONFIG_GUMSTIX_AM300EPD) += am300epd.o
 obj-$(CONFIG_ARCH_LUBBOCK)     += lubbock.o
 obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
 obj-$(CONFIG_MACH_MAINSTONE)   += mainstone.o
diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c
new file mode 100644 (file)
index 0000000..4bd10a1
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * am300epd.c -- Platform device for AM300 EPD kit
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * This work was made possible by help and equipment support from E-Ink
+ * Corporation. http://support.eink.com/community
+ *
+ * This driver is written to be used with the Broadsheet display controller.
+ * on the AM300 EPD prototype kit/development kit with an E-Ink 800x600
+ * Vizplex EPD on a Gumstix board using the Broadsheet interface board.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include <mach/gumstix.h>
+#include <mach/mfp-pxa25x.h>
+#include <mach/pxafb.h>
+
+#include "generic.h"
+
+#include <video/broadsheetfb.h>
+
+static unsigned int panel_type = 6;
+static struct platform_device *am300_device;
+static struct broadsheet_board am300_board;
+
+static unsigned long am300_pin_config[] __initdata = {
+       GPIO16_GPIO,
+       GPIO17_GPIO,
+       GPIO32_GPIO,
+       GPIO48_GPIO,
+       GPIO49_GPIO,
+       GPIO51_GPIO,
+       GPIO74_GPIO,
+       GPIO75_GPIO,
+       GPIO76_GPIO,
+       GPIO77_GPIO,
+
+       /* this is the 16-bit hdb bus 58-73 */
+       GPIO58_GPIO,
+       GPIO59_GPIO,
+       GPIO60_GPIO,
+       GPIO61_GPIO,
+
+       GPIO62_GPIO,
+       GPIO63_GPIO,
+       GPIO64_GPIO,
+       GPIO65_GPIO,
+
+       GPIO66_GPIO,
+       GPIO67_GPIO,
+       GPIO68_GPIO,
+       GPIO69_GPIO,
+
+       GPIO70_GPIO,
+       GPIO71_GPIO,
+       GPIO72_GPIO,
+       GPIO73_GPIO,
+};
+
+/* register offsets for gpio control */
+#define PWR_GPIO_PIN   16
+#define CFG_GPIO_PIN   17
+#define RDY_GPIO_PIN   32
+#define DC_GPIO_PIN    48
+#define RST_GPIO_PIN   49
+#define LED_GPIO_PIN   51
+#define RD_GPIO_PIN    74
+#define WR_GPIO_PIN    75
+#define CS_GPIO_PIN    76
+#define IRQ_GPIO_PIN   77
+
+/* hdb bus */
+#define DB0_GPIO_PIN   58
+#define DB15_GPIO_PIN  73
+
+static int gpios[] = { PWR_GPIO_PIN, CFG_GPIO_PIN, RDY_GPIO_PIN, DC_GPIO_PIN,
+                       RST_GPIO_PIN, RD_GPIO_PIN, WR_GPIO_PIN, CS_GPIO_PIN,
+                       IRQ_GPIO_PIN, LED_GPIO_PIN };
+static char *gpio_names[] = { "PWR", "CFG", "RDY", "DC", "RST", "RD", "WR",
+                               "CS", "IRQ", "LED" };
+
+static int am300_wait_event(struct broadsheetfb_par *par)
+{
+       /* todo: improve err recovery */
+       wait_event(par->waitq, gpio_get_value(RDY_GPIO_PIN));
+       return 0;
+}
+
+static int am300_init_gpio_regs(struct broadsheetfb_par *par)
+{
+       int i;
+       int err;
+       char dbname[8];
+
+       for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+               err = gpio_request(gpios[i], gpio_names[i]);
+               if (err) {
+                       dev_err(&am300_device->dev, "failed requesting "
+                               "gpio %s, err=%d\n", gpio_names[i], err);
+                       goto err_req_gpio;
+               }
+       }
+
+       /* we also need to take care of the hdb bus */
+       for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) {
+               sprintf(dbname, "DB%d", i);
+               err = gpio_request(i, dbname);
+               if (err) {
+                       dev_err(&am300_device->dev, "failed requesting "
+                               "gpio %d, err=%d\n", i, err);
+                       while (i >= DB0_GPIO_PIN)
+                               gpio_free(i--);
+                       i = ARRAY_SIZE(gpios) - 1;
+                       goto err_req_gpio;
+               }
+       }
+
+       /* setup the outputs and init values */
+       gpio_direction_output(PWR_GPIO_PIN, 0);
+       gpio_direction_output(CFG_GPIO_PIN, 1);
+       gpio_direction_output(DC_GPIO_PIN, 0);
+       gpio_direction_output(RD_GPIO_PIN, 1);
+       gpio_direction_output(WR_GPIO_PIN, 1);
+       gpio_direction_output(CS_GPIO_PIN, 1);
+       gpio_direction_output(RST_GPIO_PIN, 0);
+
+       /* setup the inputs */
+       gpio_direction_input(RDY_GPIO_PIN);
+       gpio_direction_input(IRQ_GPIO_PIN);
+
+       /* start the hdb bus as an input */
+       for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++)
+               gpio_direction_output(i, 0);
+
+       /* go into command mode */
+       gpio_set_value(CFG_GPIO_PIN, 1);
+       gpio_set_value(RST_GPIO_PIN, 0);
+       msleep(10);
+       gpio_set_value(RST_GPIO_PIN, 1);
+       msleep(10);
+       am300_wait_event(par);
+
+       return 0;
+
+err_req_gpio:
+       while (i > 0)
+               gpio_free(gpios[i--]);
+
+       return err;
+}
+
+static int am300_init_board(struct broadsheetfb_par *par)
+{
+       return am300_init_gpio_regs(par);
+}
+
+static void am300_cleanup(struct broadsheetfb_par *par)
+{
+       int i;
+
+       free_irq(IRQ_GPIO(RDY_GPIO_PIN), par);
+
+       for (i = 0; i < ARRAY_SIZE(gpios); i++)
+               gpio_free(gpios[i]);
+
+       for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++)
+               gpio_free(i);
+
+}
+
+static u16 am300_get_hdb(struct broadsheetfb_par *par)
+{
+       u16 res = 0;
+       int i;
+
+       for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++)
+               res |= (gpio_get_value(DB0_GPIO_PIN + i)) ? (1 << i) : 0;
+
+       return res;
+}
+
+static void am300_set_hdb(struct broadsheetfb_par *par, u16 data)
+{
+       int i;
+
+       for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++)
+               gpio_set_value(DB0_GPIO_PIN + i, (data >> i) & 0x01);
+}
+
+
+static void am300_set_ctl(struct broadsheetfb_par *par, unsigned char bit,
+                               u8 state)
+{
+       switch (bit) {
+       case BS_CS:
+               gpio_set_value(CS_GPIO_PIN, state);
+               break;
+       case BS_DC:
+               gpio_set_value(DC_GPIO_PIN, state);
+               break;
+       case BS_WR:
+               gpio_set_value(WR_GPIO_PIN, state);
+               break;
+       }
+}
+
+static int am300_get_panel_type(void)
+{
+       return panel_type;
+}
+
+static irqreturn_t am300_handle_irq(int irq, void *dev_id)
+{
+       struct broadsheetfb_par *par = dev_id;
+
+       wake_up(&par->waitq);
+       return IRQ_HANDLED;
+}
+
+static int am300_setup_irq(struct fb_info *info)
+{
+       int ret;
+       struct broadsheetfb_par *par = info->par;
+
+       ret = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am300_handle_irq,
+                               IRQF_DISABLED|IRQF_TRIGGER_RISING,
+                               "AM300", par);
+       if (ret)
+               dev_err(&am300_device->dev, "request_irq failed: %d\n", ret);
+
+       return ret;
+}
+
+static struct broadsheet_board am300_board = {
+       .owner                  = THIS_MODULE,
+       .init                   = am300_init_board,
+       .cleanup                = am300_cleanup,
+       .set_hdb                = am300_set_hdb,
+       .get_hdb                = am300_get_hdb,
+       .set_ctl                = am300_set_ctl,
+       .wait_for_rdy           = am300_wait_event,
+       .get_panel_type         = am300_get_panel_type,
+       .setup_irq              = am300_setup_irq,
+};
+
+int __init am300_init(void)
+{
+       int ret;
+
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(am300_pin_config));
+
+       /* request our platform independent driver */
+       request_module("broadsheetfb");
+
+       am300_device = platform_device_alloc("broadsheetfb", -1);
+       if (!am300_device)
+               return -ENOMEM;
+
+       /* the am300_board that will be seen by broadsheetfb is a copy */
+       platform_device_add_data(am300_device, &am300_board,
+                                       sizeof(am300_board));
+
+       ret = platform_device_add(am300_device);
+
+       if (ret) {
+               platform_device_put(am300_device);
+               return ret;
+       }
+
+       return 0;
+}
+
+module_param(panel_type, uint, 0);
+MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97");
+
+MODULE_DESCRIPTION("board driver for am300 epd kit");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
index e296ce11658c48633aae5c696fbcaab1355e9ec2..9cb4a074d9f076792df452857ae64ea7c243f0fd 100644 (file)
@@ -191,6 +191,11 @@ int __attribute__((weak)) am200_init(void)
        return 0;
 }
 
+int __attribute__((weak)) am300_init(void)
+{
+       return 0;
+}
+
 static void __init carrier_board_init(void)
 {
        /*
@@ -198,6 +203,7 @@ static void __init carrier_board_init(void)
         * they cannot be detected programatically
         */
        am200_init();
+       am300_init();
 }
 
 static void __init gumstix_init(void)
index 099f54a41de4cf1f45cb8905241d1503660899fb..06abd416060765497cf9ee047bc9f2293a88de53 100644 (file)
@@ -97,4 +97,5 @@ has detected a cable insertion; driven low otherwise. */
 
 /* for expansion boards that can't be programatically detected */
 extern int am200_init(void);
+extern int am300_init(void);