Logo Search packages:      
Sourcecode: linux version File versions  Download package

am300epd.c

/*
 * 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");

Generated by  Doxygen 1.6.0   Back to index