diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-29 00:03:14 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-29 00:03:14 +0300 |
commit | 0fe41b8982001cd14ee2c77cd776735a5024e98b (patch) | |
tree | 83e65d595c413d55259ea14fb97748ce5efe5707 /arch/arm/mach-pxa/am300epd.c | |
parent | eedf2c5296a8dfaaf9aec1a938c1d3bd73159a30 (diff) | |
parent | 9759d22c8348343b0da4e25d6150c41712686c14 (diff) | |
download | linux-0fe41b8982001cd14ee2c77cd776735a5024e98b.tar.xz |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (422 commits)
[ARM] 5435/1: fix compile warning in sanity_check_meminfo()
[ARM] 5434/1: ARM: OMAP: Fix mailbox compile for 24xx
[ARM] pxa: fix the bad assumption that PCMCIA sockets always start with 0
[ARM] pxa: fix Colibri PXA300 and PXA320 LCD backlight pins
imxfb: Fix TFT mode
i.MX21/27: remove ifdef CONFIG_FB_IMX
imxfb: add clock support
mxc: add arch_reset() function
clkdev: add possibility to get a clock based on the device name
i.MX1: remove fb support from mach-imx
[ARM] pxa: build arch/arm/plat-pxa/mfp.c only when PXA3xx or ARCH_MMP defined
Gemini: Add support for Teltonika RUT100
Gemini: gpiolib based GPIO support v2
MAINTAINERS: add myself as Gemini architecture maintainer
ARM: Add Gemini architecture v3
[ARM] OMAP: Fix compile for omap2_init_common_hw()
MAINTAINERS: Add myself as Faraday ARM core variant maintainer
ARM: Add support for FA526 v2
[ARM] acorn,ebsa110,footbridge,integrator,sa1100: Convert asm/io.h to linux/io.h
[ARM] collie: fix two minor formatting nits
...
Diffstat (limited to 'arch/arm/mach-pxa/am300epd.c')
-rw-r--r-- | arch/arm/mach-pxa/am300epd.c | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c new file mode 100644 index 000000000000..4bd10a17332e --- /dev/null +++ b/arch/arm/mach-pxa/am300epd.c @@ -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"); |