Atmel website | ARM Community | AVR freaks | Technical Support
Banner
 FAQ •  Search •  Register •  Login 

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Framebuffer Driver Nokia 6610 LCD with epson controller
PostPosted: Mon Jul 13, 2009 4:12 pm 
Offline

Joined: Mon Jul 13, 2009 2:06 pm
Posts: 3
Framebuffer Driver for the epson S1D15G00 controller based 12 bit color LCD with mmap support.

Code :

/*
*File epson12bpp.c
*
*Driver for the epson S1D15G00 controller based 12-bit color LCD
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* For all queries about this code, please contact the current author,
* PrasadTVR <vishnu.tvrprasad@gmail.com> .
*
*
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include <asm/arch/cpu.h>
#include "lcd.h"
#include <linux/vmalloc.h>




#define DEBUG 1
#define X_RES 132
#define Y_RES 132
#define B_PP 12
#define MEM_LEN X_RES*Y_RES*B_PP/8
#define EPSON_REFRESH_JIFFIES (HZ)/5
#define EPSON_NAME "EPSONREFD"
#define BLACK 0x000


static void *videomemory;
static u_long videomemorysize = MEM_LEN;
module_param(videomemorysize, ulong, 0);

static int __devinit mylcd_probe(struct spi_device *spi);
static int __devexit mylcd_remove(struct spi_device *spi);
static void *rvmalloc(unsigned long size);
static void rvfree(void *mem, unsigned long size);
void LCDClearScreen(struct spi_device *spi) ;
static void WriteSpiCommand(struct spi_device *spi, unsigned int c);
static void WriteSpiData(struct spi_device *spi, unsigned int d);


/******************************************************************************************/
struct EpsonLCD
{
struct fb_info *info;
struct spi_device *spi;
u16 *scr;
u8 *shadow;
u8 quitting;
int RefThrPid;
struct semaphore thread_sem;
};

static struct fb_fix_screeninfo Epson_fix __devinitdata = {
.id = "EpsonLCD",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_DIRECTCOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.line_length = X_RES*B_PP/8,
.smem_len = MEM_LEN,
.accel = FB_ACCEL_NONE,
};

static struct fb_var_screeninfo Epson_var __devinitdata = {
.xres = X_RES,
.yres = Y_RES,
.xres_virtual = X_RES,
.yres_virtual = Y_RES,
.bits_per_pixel = B_PP,
.red = {8, 4, 0},
.green = {4, 4, 0},
.blue = {0, 4, 0},
.transp = {0, 0, 0},
.nonstd = 0,
};
static struct spi_driver mylcd_driver = {
.driver = {
.name = "mylcd",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},

.probe = mylcd_probe,
.remove = __devexit_p(mylcd_remove),

/* FIXME: investigate suspend and resume... */
};
/***********************************************************************************************/
static void *rvmalloc(unsigned long size)
{
void *mem;
unsigned long adr;

size = PAGE_ALIGN(size);
mem = vmalloc_32(size);
if (!mem)
return NULL;

memset(mem, 0, size); /* Clear the ram out, no junk to the user */
adr = (unsigned long) mem;
while (size > 0) {
SetPageReserved(vmalloc_to_page((void *)adr));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}

return mem;
}
/***********************************************************************************************/
static void rvfree(void *mem, unsigned long size)
{
unsigned long adr;

if (!mem)
return;

adr = (unsigned long) mem;
while ((long) size > 0) {
ClearPageReserved(vmalloc_to_page((void *)adr));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
vfree(mem);
}
/*********************************************************************************************/
static void WriteSpiCommand(struct spi_device *spi, unsigned int c)
{
unsigned int w = c & ~0x0100;

spi_write(spi, (u8 *)&w, 2);
}
/*-------------------------------------------------------------------------------------------*/
static void WriteSpiData(struct spi_device *spi, unsigned int d)
{
unsigned int w = d | 0x0100;

spi_write(spi, (u8 *)&w, 2);
}
/*------------------------------------------------------------------------------------------*/
void Backlight(unsigned char state) {

if(state == BKLGHT_LCD_ON)
at91_set_gpio_value(AT91_PIN_PB9,1);
else
at91_set_gpio_value(AT91_PIN_PB9,0);

}
/*------------------------------------------------------------------------------------------*/
static void epson_gram_update(struct EpsonLCD *par)
{
struct spi_device *spi = par->spi;
unsigned int x=0, y=0, i=0;
u16 *scr = par->scr;
u8 *videomemory = par->info->screen_base;
for(x = 0; x <MEM_LEN; x++) {
scr[i] = videomemory[x] | 0x100;
i++;
}

WriteSpiCommand(spi, CASET); // column start/end ram (x)
WriteSpiData(spi, 0);
WriteSpiData(spi, 131);
WriteSpiCommand(spi, PASET); // page start/end ram (y)
WriteSpiData(spi, 0);
WriteSpiData(spi, 131);

WriteSpiCommand(spi, RAMWR); // write some stuff
spi_write(spi, (u8 *)scr, i*2);

}
/*------------------------------------------------------------------------------------------*/
static void epson_fillrect(struct fb_info *info,
const struct fb_fillrect *rect)
{
struct EpsonLCD *par = info->par;

cfb_fillrect(info, rect);

/* update the physical lcd */
epson_gram_update(par);
}
/*------------------------------------------------------------------------------------------*/
static void epson_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
struct EpsonLCD *par = info->par;

cfb_copyarea(info, area);

/* update the physical lcd */
epson_gram_update(par);
}
/*------------------------------------------------------------------------------------------*/
static void epson_imageblit(struct fb_info *info,
const struct fb_image *image)
{
struct EpsonLCD *par = info->par;

cfb_imageblit(info, image);

/* update the physical lcd */
epson_gram_update(par);
}
/*------------------------------------------------------------------------------------------*/
static int epson_mmap(struct fb_info *info,struct vm_area_struct *vma)
{
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
if (offset + size > info->fix.smem_len) {
return -EINVAL;
}

pos = (unsigned long)info->fix.smem_start + offset;

while (size > 0) {
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
return -EAGAIN;
}
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
size -= PAGE_SIZE;
else
size = 0;
}

vma->vm_flags |=VM_IO | VM_RESERVED;
return 0;
}
/*-------------------------------------------------------------------------------------------*/
static int
epson_thread(void *arg)
{
struct EpsonLCD *info = (struct EpsonLCD*)arg;
/* Do some setup to look like a real daemon */
daemonize(EPSON_NAME);
//set_user_nice(current, -5);
while (!info->quitting) {
struct spi_device *spi = info->spi;
if (memcmp(info->shadow, info->info->screen_base,MEM_LEN)) {
memcpy(info->shadow, info->info->screen_base,MEM_LEN);
epson_gram_update(info);
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(EPSON_REFRESH_JIFFIES);
}
/* Tell module we're done */
up(&info->thread_sem);
return 0;
}
/*------------------------------------------------------------------------------------------*/
void resetLCD (void)
{
gpio_direction_output(AT91_PIN_PB8,0);
mdelay(100);
gpio_direction_output(AT91_PIN_PB8,1);
mdelay(100);
}
/*------------------------------------------------------------------------------------------*/
void LCDInit(struct spi_device *spi)
{

resetLCD();

WriteSpiCommand(spi,DISCTL);

WriteSpiData(spi,0x0c); // default
WriteSpiData(spi,0x20); // (32 + 1) * 4 = 132 lines (of which 130 are visible)
WriteSpiData(spi,0x00); // default
WriteSpiData(spi,0x01); // default



WriteSpiCommand(spi,COMSCN);
WriteSpiData(spi,0x01); // Scan 1-80
WriteSpiCommand(spi,OSCON);

WriteSpiCommand(spi,SLPOUT);
WriteSpiCommand(spi,PWRCTR);
WriteSpiData(spi,0x0f); // referance voltage regulator on, circuit voltage follower on, BOOST ON

WriteSpiCommand(spi,DISINV);
WriteSpiCommand(spi,DATCTL);
WriteSpiData(spi,0x01); // all inversions off, column direction
WriteSpiData(spi,0x00); // RGB sequence
WriteSpiData(spi,0x02); // Grayscale -> 16
WriteSpiCommand(spi,VOLCTR); // electronic volume, this is the contrast/brightness(EPSON)
WriteSpiData(spi,0x24); // volume (contrast) setting - fine tuning, original
WriteSpiData(spi,0x03); // internal resistor ratio - coarse adjustmen

WriteSpiCommand(spi,NOP);

WriteSpiCommand(spi,DISON);

}
/*----------------------------------------------------------------------------------------------------------*/
static struct fb_ops epson_ops = {
.owner = THIS_MODULE,
.fb_read = epson_read,
.fb_mmap = epson_mmap,
.fb_fillrect = epson_fillrect,
.fb_copyarea = epson_copyarea,
.fb_imageblit = epson_imageblit,
};
/*------------------------------------------------------------------------------------------------------------*/
void LCDClearScreen(struct spi_device *spi)
{
long i; // loop counter
// Row address set (command 0x2B)
WriteSpiCommand(spi,PASET);
WriteSpiData(spi,0);
WriteSpiData(spi,131);
// Column address set (command 0x2A)
WriteSpiCommand(spi,CASET);
WriteSpiData(spi,0);
WriteSpiData(spi,131);
// set the display memory to BLACK
WriteSpiCommand(spi,RAMWR);
for(i = 0; i < ((131 * 131) / 2); i++)
{
WriteSpiData(spi,(BLACK >> 4) & 0xFF);
WriteSpiData(spi,((BLACK & 0xF) << 4) | ((BLACK >> & 0xF));
WriteSpiData(spi,BLACK & 0xFF);
}
}
/*------------------------------------------------------------------------------------------------------------*/
static int __devinit mylcd_probe(struct spi_device *spi)
{
int retval;
struct fb_info *info;
struct EpsonLCD *priv;
spi->master->bus_num = 1;
spi->chip_select = 0;
spi->max_speed_hz = 6 * 1000 * 1000; // ??
spi->mode = SPI_MODE_0;
spi->bits_per_word = 9;
retval = spi_setup(spi);
#ifdef DEBUG
printk("SPI setup for LCD successful \n");
#endif
if (retval < 0)
return retval;
LCDInit(spi);
#ifdef DEBUG
printk("LCD Initialisation successful \n");
#endif
LCDClearScreen(spi);
retval = -ENOMEM;
videomemorysize = MEM_LEN;
if (!(videomemory = rvmalloc(videomemorysize)))
return retval;
memset(videomemory, 0, videomemorysize);
#ifdef DEBUG
printk("videomemory Allocation successful \n");
#endif

info = framebuffer_alloc(sizeof(struct EpsonLCD), &spi->dev);
if (!info)
goto err;
#ifdef DEBUG
printk("Framebuffer alloc successful \n");
#endif

info->screen_base = (char __iomem *)videomemory;
info->fbops = &epson_ops;
info->var = Epson_var;
Epson_fix.smem_start=(unsigned long) videomemory;
Epson_fix.smem_len = PAGE_ALIGN(videomemorysize);
info->fix = Epson_fix;
info->flags = FBINFO_FLAG_DEFAULT;

priv = info->par;
priv->info = info;
priv->spi = spi;
if(!(priv->scr = kzalloc(MEM_LEN*2, GFP_KERNEL)))
goto err;

if(!(priv->shadow = kzalloc(MEM_LEN, GFP_KERNEL)))
goto err1;
priv->quitting=0;
retval = register_framebuffer(info);
if (retval < 0)
goto err2;
#ifdef DEBUG
printk("Register framebuffer successful \n");
#endif

dev_set_drvdata(&spi->dev, info);
init_MUTEX_LOCKED(&priv->thread_sem);
if ((priv->RefThrPid = kernel_thread(epson_thread,priv, CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) < 0) {
printk("can't create refresh thread\n");
goto err3;
}

printk(KERN_INFO "fb%d: %s frame buffer device, %dK of video memory\n",
info->node, info->fix.id, videomemorysize >> 10);

return 0;

err3:

unregister_framebuffer(info);
framebuffer_release(info);
err2:
kfree(priv->shadow);
err1:
kfree(priv->scr);
err:
rvfree(videomemory,videomemorysize);
return retval;

return 0;
}
/*-----------------------------------------------------------------------------------------------------------------*/
static int __devexit mylcd_remove(struct spi_device *spi)
{
struct fb_info *info = dev_get_drvdata(&spi->dev);

if (info) {
struct EpsonLCD *priv = info->par;
priv->quitting=1;
down(&priv->thread_sem);
unregister_framebuffer(info);
rvfree((void __force *)info->screen_base,MEM_LEN);
kfree((void __force *)priv->scr);
kfree((void __force *)priv->shadow);
framebuffer_release(info);
}
return 0;
}
/*------------------------------------------------------------------------------------------------------------------*/
static int __init mylcd_spi_init(void)
{
int ret=0;

at91_set_gpio_output(AT91_PIN_PB8,1);
at91_set_gpio_output(AT91_PIN_PB9,1);
spi_register_driver(&mylcd_driver);
return ret;
}

module_init(mylcd_spi_init);
/*----------------------------------------------------------------------------------------------------------------*/
static void __exit mylcd_spi_exit(void)
{
spi_unregister_driver(&mylcd_driver);
}
module_exit(mylcd_spi_exit);
/*---------------------------------------------------------------------------------------------------------------*/
MODULE_DESCRIPTION("Nokia 6610 LCD driver");
MODULE_AUTHOR("vishnu.tvrprasad@gmail.com");
MODULE_LICENSE("GPL");


Top
 Profile  
 
 Post subject: Re: Framebuffer Driver Nokia 6610 LCD with epson controller
PostPosted: Wed Aug 26, 2009 2:32 am 
Offline

Joined: Sat Jun 13, 2009 5:50 pm
Posts: 44
Thanks


Top
 Profile  
 
 Post subject: Re: Framebuffer Driver Nokia 6610 LCD with epson controller
PostPosted: Thu May 10, 2012 1:48 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Thank you for this LCD driver.
I am a beginner in the area. How to load this driver into my Linux SAM9 board?
Regards,
Arnaud


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: