www.pudn.com > ucosii_core.rar > ak4182.c, change:2007-06-28,size:10114b
/*
* ak4182.c using national microwire protocol
*
* Touch screen driver interface to the AK4182A .
*
* 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.
*/
#include <sysdefs.h>
#include <regs.h>
#include <ops.h>
#include "jztouch.h"
#include <ucos_ii.h>
#define TS_PIN (98)
#define TS_SAMPLE_TIME (20)
#define X_CH 5
#define Y_CH 1
#define BAT_CH 2
#define TOUCH_TASK_PRIO 3
#define JZ_EXTAL (12*1000*1000)
#define TS_IRQ (IRQ_GPIO_0 + TS_PIN)
#define TS_SAMPLE_TICK (TS_SAMPLE_TIME / (1000 / OS_TICKS_PER_SEC))
#define ts_gpio_mask_irq(n) (REG_GPIO_GPIMR(n / 32) |= (1 << (n % 32)))
#define ts_gpio_unmask_irq(n) (REG_GPIO_GPIMR((n / 32)) &= ~(1 << (n % 32)))
#define ts_gpio_ack_irq(n) (REG_GPIO_GPFR((n / 32)) |= (1 << (n % 32)))
#define TS_enable_irq() \
do{ \
__gpio_unmask_irq(TS_PIN); \
__intc_unmask_irq(IRQ_SSI); \
}while(0)
#define TS_disable_irq() \
do{ \
__gpio_mask_irq(TS_PIN); \
__intc_mask_irq(IRQ_SSI); \
}while(0)
#define TASK_STK_SIZE 1024
static OS_EVENT *touchEvent;
static void jz47ssi_handler(unsigned int arg)
{
__intc_mask_irq(IRQ_SSI);
//OSSemPost((OS_EVENT *)arg);
OSSemPost(touchEvent);
}
static void touchpen_handler(unsigned int arg)
{
__gpio_mask_irq(TS_PIN);
// OSSemPost((OS_EVENT *)arg);
OSSemPost(touchEvent);
}
#define ak4182_ssi_reset() \
do{ \
REG_SSI_CR0 = 0x0000; \
REG_SSI_CR1 = 0x00007960; \
REG_SSI_SR = 0x00000098; \
REG_SSI_ITR = 0x0000; \
REG_SSI_ICR = 0x00; \
REG_SSI_GR = 0x0000; \
__ssi_disable(); \
__ssi_flush_fifo(); \
__ssi_clear_errors(); \
__ssi_select_ce(); \
}while(0)
#define ak4182_ssi_enable() __ssi_enable()
#define ak4182_ssi_disable() __ssi_disable()
#define ak4182_ssi_set_trans_mode_format() \
do{ \
__ssi_microwire_format(); \
__ssi_set_msb(); \
__ssi_set_microwire_command_length(8); \
__ssi_set_frame_length(12); \
}while(0)
#define ak4182_ssi_set_clk_div_ratio(dev_clk,ssi_clk) __ssi_set_clk(dev_clk, ssi_clk)
//#define ak4182_ssi_set_normal_mode() __ssi_normal_mode()
/*------------------ AK4182 routines ------------------*/
#define ak4182_reg_write(val) __ssi_transmit_data(val)
#define ak4148_ssi_irq_set() \
do{ \
__ssi_set_rx_trigger(1); \
__ssi_enable_rx_intr(); \
__ssi_disable_tx_intr(); \
}while(0);
#define ak4182_reg_read() __ssi_receive_data()
static U8 adStatus = 0;
static U16 ts_TimeOut = 0;
static U16 AdFlag = 0;
#define RETRY_COUNT 3
#define ADC_STARTBITNUM (1 << 7)
#define ADC_CHANNEL(x) (x << 4)
#define ADC_MODE(x) (x << 3)
#define ADC_SER(x) (x << 2)
#define ADC_PD(y) (y)
#define ADC_COMMAND(x,y,m) (ADC_STARTBITNUM | \
ADC_CHANNEL(x) | \
ADC_MODE(0) | \
ADC_SER(m) | \
ADC_PD(y))
#define TOUCH_PD_MODE 2
#define ADC_PD_MODE 3
static PFN_CALIBRATE xCalibrate = 0;
static PFN_CALIBRATE yCalibrate = 0;
static PFN_CALIBRATE AdCalibrate = 0;
#define SETFLAG(x,val) \
do{ \
x &= 0xf0; \
x |= val; \
}while(0)
static void touchTaskEntry(void *arg)
{
U8 err;
U32 val;
U8 count;
U8 retrycount;
U8 touch_pen = 0;
while(1)
{
OSSemPend(touchEvent,ts_TimeOut,&err);
switch(adStatus)
{
case 0:
if(__gpio_get_pin(TS_PIN) == 0)
{
ts_gpio_ack_irq(TS_PIN);
ts_gpio_mask_irq(TS_PIN);
__gpio_mask_irq(TS_PIN);
touch_pen = 1;
ts_TimeOut = 2;
adStatus = 1;
count = 0;
ak4182_reg_write((U32)ADC_COMMAND(X_CH,TOUCH_PD_MODE,0));
retrycount = 0;
//printf("pen down\r\n");
}else
{
if(err == OS_NO_ERR)
{
if(__ssi_get_rxfifo_count())
val = ak4182_reg_read();
ts_TimeOut = 0;
count = 0;
retrycount = 0;
ts_gpio_ack_irq(TS_PIN);
ts_gpio_unmask_irq(TS_PIN);
__gpio_unmask_irq(TS_PIN);
//printf("unuse data \r\n");
}
if((touch_pen == 1)&&(__gpio_get_pin(TS_PIN) != 0))
{
touch_pen = 0;
if(xCalibrate) xCalibrate(-1);
if(yCalibrate) yCalibrate(-1);
}
}
break;
case 1: //x_ch preCalibrate
if(err == OS_NO_ERR)
{
val = ak4182_reg_read();
count++;
retrycount = 0;
if(count > 2)
{
adStatus = 2;
count = 0;
}
}else if(__gpio_get_pin(TS_PIN) != 0)
{
ts_TimeOut = 0;
adStatus = 0;
retrycount = 0;
touch_pen = 0;
if(xCalibrate) xCalibrate(-1);
if(yCalibrate) yCalibrate(-1);
//printf("pen up\r\n");
ts_gpio_ack_irq(TS_PIN);
ts_gpio_unmask_irq(TS_PIN);
__gpio_unmask_irq(TS_PIN);
if(__ssi_get_rxfifo_count())
val = ak4182_reg_read();
} else
retrycount++;
if(adStatus != 0)
{
if(retrycount < RETRY_COUNT)
ak4182_reg_write(ADC_COMMAND(X_CH,TOUCH_PD_MODE,0));
else
{
retrycount = 0;
ts_TimeOut = 0;
adStatus = 0;
ak4182_reg_write(ADC_COMMAND(0,0,1));
}
}
break;
case 2: //x_ch Calibrate
if(err == OS_NO_ERR)
{
val = (val + ak4182_reg_read()) / 2;
count++;
retrycount = 0;
if(count > 2)
{
ak4182_reg_write(ADC_COMMAND(Y_CH,TOUCH_PD_MODE,0));
if(xCalibrate) xCalibrate((U16)val);
adStatus = 3;
count = 0;
}else
ak4182_reg_write(ADC_COMMAND(X_CH,TOUCH_PD_MODE,0));
}else
{
retrycount++;
if(retrycount < RETRY_COUNT)
ak4182_reg_write(ADC_COMMAND(X_CH,TOUCH_PD_MODE,0));
else
{
retrycount = 0;
ts_TimeOut = 0;
adStatus = 0;
ak4182_reg_write(ADC_COMMAND(0,0,1));
}
}
break;
case 3: // Y_CH preCalibrate
if(err == OS_NO_ERR)
{
val = ak4182_reg_read();
count++;
retrycount = 0;
if(count > 2)
{
adStatus = 4;
count = 0;
}
}else
retrycount++;
if(retrycount < RETRY_COUNT)
ak4182_reg_write(ADC_COMMAND(Y_CH,TOUCH_PD_MODE,0));
else
{
retrycount = 0;
ts_TimeOut = 0;
adStatus = 0;
ak4182_reg_write(ADC_COMMAND(0,0,1));
}
break;
case 4: //Y_CH Calibrate
if(err == OS_NO_ERR)
{
val = (val + ak4182_reg_read()) / 2;
count++;
if(count > 2)
{
//Calibrate PD Down
ak4182_reg_write(ADC_COMMAND(0,0,1));
if(yCalibrate) yCalibrate((U16)val);
adStatus = 5;
count = 0;
}else
ak4182_reg_write(ADC_COMMAND(Y_CH,TOUCH_PD_MODE,0));
}else
{
retrycount++;
if(retrycount < RETRY_COUNT)
ak4182_reg_write(ADC_COMMAND(Y_CH,TOUCH_PD_MODE,0));
else
{
retrycount = 0;
adStatus = 0;
ts_TimeOut = 0;
ak4182_reg_write(ADC_COMMAND(0,0,1));
}
}
break;
case 5: //wait sample period
if(err == OS_NO_ERR)
val = ak4182_reg_read();
__ssi_flush_fifo();
ts_TimeOut = TS_SAMPLE_TICK;
adStatus = 1;
count = 0;
break;
}
if((AdFlag & 0x80) && ((adStatus == 0)||(adStatus == 6)))
{
ts_gpio_mask_irq(TS_PIN);
printf("No Touch Calibrate\r\n");
switch(AdFlag & 0x70)
{
case 0x10:
ak4182_reg_write(ADC_COMMAND(AdFlag & 0x0f,ADC_PD_MODE,1));
adStatus = 6;
count = 0;
ts_TimeOut = 1;
AdFlag &= 0x8f;
AdFlag |= 0x20;
retrycount = 0;
break;
case 0x20: //preCalibrate
if(err == OS_NO_ERR)
{
val = ak4182_reg_read();
count++;
if(count > 2)
{
AdFlag &= 0x8f;
AdFlag |= 0x30;
count = 0;
}
}else
retrycount++;
if(retrycount < RETRY_COUNT)
ak4182_reg_write(ADC_COMMAND(AdFlag & 0x0f,ADC_PD_MODE,1));
else
{
retrycount = 0;
AdFlag = 0;
ts_TimeOut = 0;
ak4182_reg_write(ADC_COMMAND(0,0,1));
}
break;
case 0x30:
if(err == OS_NO_ERR)
{
val = (val + ak4182_reg_read()) / 2;
count++;
if(count > 3)
{
AdFlag &= 0x8f;
AdFlag |= 0x40;
count = 0;
if(AdCalibrate) AdCalibrate((U16)val);
__gpio_unmask_irq(TS_PIN);
}
ak4182_reg_write(ADC_COMMAND(AdFlag & 0x0f,ADC_PD_MODE,1));
}else
{
retrycount++;
if(retrycount < RETRY_COUNT)
ak4182_reg_write(ADC_COMMAND(AdFlag & 0x0f,ADC_PD_MODE,1));
else
{
count = 0;
AdFlag = 0;
ts_TimeOut = 0;
ak4182_reg_write(ADC_COMMAND(0,0,0));
}
}
break;
case 0x40:
if(err == OS_NO_ERR)
val = ak4182_reg_read();
AdFlag = 0;
adStatus = 0;
ts_TimeOut = 0;
ts_gpio_unmask_irq(TS_PIN);
break;
}
}
__intc_unmask_irq(IRQ_SSI);;
}
}
#define TASK_STK_SIZE 1024
static OS_STK touchTaskStack[TASK_STK_SIZE];
int TS_init(void)
{
touchEvent = OSSemCreate(1);
__gpio_as_ssi();
ak4182_ssi_reset();
ak4182_ssi_set_trans_mode_format();
REG_SSI_ITR = 1;
ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 125*1000);//DCLK is 125K Hz max
ak4148_ssi_irq_set();
request_irq(IRQ_SSI, jz47ssi_handler, (unsigned int)touchEvent);
//touch_pen_init
__gpio_as_irq_fall_edge(TS_PIN);
/* register irq handler */
request_irq(TS_IRQ, touchpen_handler,(unsigned int)touchEvent);
OSTaskCreate(touchTaskEntry, (void *)0,
(void *)&touchTaskStack[TASK_STK_SIZE - 1],
TOUCH_TASK_PRIO);
ts_gpio_ack_irq(TS_PIN);
TS_enable_irq();
ak4182_ssi_enable();
ak4182_reg_write(ADC_COMMAND(0,0,1));
printf("AK4182 touch screen driver initialized\n");
return 0;
}
void TS_SetxCalibration(PFN_CALIBRATE xCal,PFN_CALIBRATE yCal)
{
xCalibrate = xCal;
yCalibrate = yCal;
}