2009-01-01 19:51:01 +03:00
/*
* 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 800 x600
* 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>
2012-08-24 17:16:48 +04:00
# include <linux/platform_data/video-pxafb.h>
2009-01-01 19:51:01 +03:00
# 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 ) ;
2011-03-07 08:56:11 +03:00
goto err_req_gpio2 ;
2009-01-01 19:51:01 +03:00
}
}
/* 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 ;
2011-03-07 08:56:11 +03:00
err_req_gpio2 :
while ( - - i > = DB0_GPIO_PIN )
gpio_free ( i ) ;
i = ARRAY_SIZE ( gpios ) ;
2009-01-01 19:51:01 +03:00
err_req_gpio :
2011-03-07 08:56:11 +03:00
while ( - - i > = 0 )
gpio_free ( gpios [ i ] ) ;
2009-01-01 19:51:01 +03:00
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 ;
2011-10-10 10:21:08 +04:00
free_irq ( PXA_GPIO_TO_IRQ ( RDY_GPIO_PIN ) , par ) ;
2009-01-01 19:51:01 +03:00
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 ;
2011-10-10 10:21:08 +04:00
ret = request_irq ( PXA_GPIO_TO_IRQ ( RDY_GPIO_PIN ) , am300_handle_irq ,
2009-01-01 19:51:01 +03:00
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 ) ;
2010-03-11 02:21:24 +03:00
MODULE_PARM_DESC ( panel_type , " Select the panel type: 37, 6, 97 " ) ;
2009-01-01 19:51:01 +03:00
MODULE_DESCRIPTION ( " board driver for am300 epd kit " ) ;
MODULE_AUTHOR ( " Jaya Kumar " ) ;
MODULE_LICENSE ( " GPL " ) ;