402 lines
10 KiB
C
402 lines
10 KiB
C
/* ===========================================================================
|
|
* orizon_tilt.c
|
|
* Copyright (C) 2009-2010 Bookeen - All rights reserved
|
|
* ===========================================================================
|
|
*/
|
|
|
|
/* TODO: Verify if all this includes are necessary */
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <asm/atomic.h>
|
|
#include <asm/io.h>
|
|
#include <asm/arch/irqs.h>
|
|
#include <asm/arch/gpio.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <cybook.h>
|
|
|
|
#include <linux/cyevent.h>
|
|
|
|
//#define DEBUG_MESSAGES
|
|
//#define DEBUG_TRACEFUNC
|
|
//#define DBG_IRQ
|
|
|
|
#define MODULE_NAME "CYB_TILT"
|
|
|
|
#undef MSG
|
|
#undef DBG
|
|
#ifdef DEBUG_MESSAGES
|
|
|
|
#ifdef DEBUG_TRACEFUNC
|
|
static int _dbg_FunctionLevel = 0;
|
|
|
|
#define MSG(str) {\
|
|
int i;\
|
|
printk(KERN_ALERT "+");\
|
|
for (i = 0; i < _dbg_FunctionLevel; i++)\
|
|
printk("-");\
|
|
printk("||" str "\n");\
|
|
}
|
|
|
|
#define DBG(str, ...) {\
|
|
int i;\
|
|
printk(KERN_ALERT "+");\
|
|
for (i = 0; i < _dbg_FunctionLevel; i++)\
|
|
printk("-");\
|
|
printk("||" str "\n", __VA_ARGS__);\
|
|
}
|
|
|
|
#define FUNC_IN() {\
|
|
int i;\
|
|
_dbg_FunctionLevel++;\
|
|
printk(KERN_ALERT "+");\
|
|
for (i = 0; i < _dbg_FunctionLevel; i++)\
|
|
printk("-");\
|
|
printk(">> %s() >>\n", __func__);\
|
|
}
|
|
|
|
#define FUNC_OUT() {\
|
|
int i;\
|
|
printk(KERN_ALERT "+");\
|
|
for (i = 0; i < _dbg_FunctionLevel; i++)\
|
|
printk("-");\
|
|
printk("<< %s() <<\n", __func__);\
|
|
_dbg_FunctionLevel--;\
|
|
}
|
|
|
|
#define FUNC_OUTR(val) {\
|
|
int i;\
|
|
printk(KERN_ALERT "+");\
|
|
for (i = 0; i < _dbg_FunctionLevel; i++)\
|
|
printk("-");\
|
|
printk("<< %s() = %d <<\n", __func__, val);\
|
|
_dbg_FunctionLevel--;\
|
|
}
|
|
#else /* DEBUG_TRACEFUNC */
|
|
|
|
#define MSG(str) do {\
|
|
printk(KERN_ALERT MODULE_NAME ": " str "\n");\
|
|
} while(0)
|
|
|
|
#define DBG(str, ...) do {\
|
|
printk(KERN_ALERT MODULE_NAME ": " str "\n", __VA_ARGS__);\
|
|
} while(0)
|
|
#define FUNC_IN() do {\
|
|
} while(0)
|
|
|
|
#define FUNC_OUT() do {\
|
|
} while(0)
|
|
|
|
#define FUNC_OUTR(val) do {\
|
|
printk(KERN_ALERT MODULE_NAME ": %s() return %d\n", __func__, val);\
|
|
} while(0)
|
|
|
|
#endif /* DEBUG_TRACEFUNC */
|
|
|
|
#else /* DEBUG_MESSAGES */
|
|
#define MSG(str)
|
|
#define DBG(str, ...)
|
|
#define FUNC_IN()
|
|
#define FUNC_OUT()
|
|
#define FUNC_OUTR(val)
|
|
#endif /* DEBUG_MESSAGES */
|
|
|
|
#define GPROCFS_ROOTFOLDER "cybook"
|
|
#define GPROCFS_MODULEFOLDER "gsensor"
|
|
#define GPROCFS_IOFILE "io"
|
|
|
|
#define TRUE (1==1)
|
|
#define FALSE (1==0)
|
|
|
|
static struct proc_dir_entry *rootDir,
|
|
*ioProcEntry;
|
|
|
|
atomic_t OrizonTilt_Status;
|
|
atomic_t OrizonTilt_IrqSet;
|
|
|
|
static volatile short OrizonTilt_CurrentDirection = 270;
|
|
static int SensorsInt[2];
|
|
static DEFINE_SPINLOCK(suspendLock);
|
|
|
|
static unsigned char OrizonTilt_finishedWork = 0;
|
|
|
|
/*============================================================================*/
|
|
/*============================= Prototypes ===================================*/
|
|
/*============================================================================*/
|
|
|
|
/********************************* PM *****************************************/
|
|
static int orizontilt_suspend(struct device *dev, pm_message_t state);
|
|
static int orizontilt_resume (struct device *dev);
|
|
/************************* Data collection Functions **************************/
|
|
|
|
/********************** Interrupt Related functions ***************************/
|
|
static void orizontilt_setMode(int mode);
|
|
static int orizontilt_initIrq(void);
|
|
static void orizontilt_deinitIrq(void);
|
|
static irqreturn_t orizontilt_interrupt(int irq, void *dev_id);
|
|
|
|
/****************************** ProcFs functions ******************************/
|
|
static int orizontilt_procReadIo (char *page, char **start, off_t off, int count,
|
|
int *eof, void *data);
|
|
static int orizontilt_procWriteIo (struct file *file, const char *buffer,
|
|
unsigned long count, void *data);
|
|
/****************************** Module functions ******************************/
|
|
static int __init orizontilt_init(void);
|
|
static void __exit orizontilt_exit(void);
|
|
/*============================= End of prototypes ============================*/
|
|
|
|
/******************************************************************************/
|
|
/********************** Interrupt Related functions ***************************/
|
|
/******************************************************************************/
|
|
static int orizontilt_initIrq(void)
|
|
{
|
|
int ret = 0;
|
|
FUNC_IN();
|
|
|
|
if ( atomic_read(&OrizonTilt_IrqSet) != TRUE )
|
|
{
|
|
MSG("I will enable IRQ\n");
|
|
|
|
set_irq_type(IRQ_EINT11, IRQT_BOTHEDGE);
|
|
set_irq_type(IRQ_EINT12, IRQT_BOTHEDGE);
|
|
s3c2410_gpio_pullup(S3C2410_GPG3, 0);
|
|
s3c2410_gpio_pullup(S3C2410_GPG4, 0);
|
|
if(request_irq(IRQ_EINT11, orizontilt_interrupt, SA_INTERRUPT, "TILT-SENSOR[1]", &SensorsInt[0]))
|
|
{
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
if(request_irq(IRQ_EINT12, orizontilt_interrupt, SA_INTERRUPT, "TILT-SENSOR[2]", &SensorsInt[1]))
|
|
{
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
atomic_set(&OrizonTilt_IrqSet, TRUE);
|
|
}
|
|
|
|
exit:
|
|
FUNC_OUTR(ret);
|
|
return ret;
|
|
}
|
|
|
|
static void orizontilt_deinitIrq(void)
|
|
{
|
|
FUNC_IN();
|
|
|
|
/* Set the orizontilt to standby mode */
|
|
if ( atomic_read(&OrizonTilt_IrqSet) == TRUE )
|
|
{
|
|
disable_irq_wake(IRQ_EINT11);
|
|
disable_irq_wake(IRQ_EINT12);
|
|
free_irq(IRQ_EINT11, NULL);
|
|
free_irq(IRQ_EINT12, NULL);
|
|
atomic_set(&OrizonTilt_IrqSet, FALSE);
|
|
}
|
|
|
|
FUNC_OUT();
|
|
}
|
|
|
|
static irqreturn_t orizontilt_interrupt(int irq, void *dev_id)
|
|
{
|
|
irqreturn_t ret = IRQ_HANDLED;
|
|
unsigned long tmpReg;
|
|
unsigned long calcTilt;
|
|
CyEvent_t event = NEW_CYEVENT(CYEVENT_TYPE_ORIENTATION);
|
|
FUNC_IN();
|
|
|
|
spin_lock(&suspendLock);
|
|
OrizonTilt_finishedWork = 1;
|
|
spin_unlock(&suspendLock);
|
|
|
|
|
|
/* Do it here */
|
|
MSG("Will read gpios...");
|
|
tmpReg = (__raw_readl(S3C2410_GPGDAT) >> 3) & 0x3;
|
|
DBG("Got reg: %lu", tmpReg);
|
|
calcTilt = 0;
|
|
switch(tmpReg)
|
|
{
|
|
case 0x00: /* 90 */
|
|
calcTilt = 90;
|
|
break;
|
|
|
|
case 0x02: /* 0 */
|
|
calcTilt = 0;
|
|
break;
|
|
|
|
case 0x01: /* 180 */
|
|
calcTilt = 180;
|
|
break;
|
|
|
|
case 0x03: /* 270 */
|
|
calcTilt = 270;
|
|
break;
|
|
}
|
|
DBG("New Orientation is: %lu", calcTilt);
|
|
if (calcTilt != OrizonTilt_CurrentDirection)
|
|
{
|
|
MSG("Different from old one, push new event!");
|
|
OrizonTilt_CurrentDirection = calcTilt;
|
|
event.data.orientation = calcTilt / 90;
|
|
CyEvent_PushOrUpdateUniqueEvent(&event, false);
|
|
}
|
|
|
|
spin_lock(&suspendLock);
|
|
OrizonTilt_finishedWork = 0;
|
|
spin_unlock(&suspendLock);
|
|
|
|
FUNC_OUT();
|
|
|
|
exit:
|
|
FUNC_OUTR((int)ret);
|
|
return ret;
|
|
}
|
|
|
|
static void orizontilt_setMode(int mode)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case G_SENSOR_ON:
|
|
orizontilt_initIrq();
|
|
enable_irq_wake(IRQ_EINT11);
|
|
enable_irq_wake(IRQ_EINT12);
|
|
/* Switch TILT on */
|
|
gpio_direction_output(S3C2410_GPC3, 1);
|
|
atomic_set(&OrizonTilt_Status, CYGSENSOR_STATUS_ENABLED);
|
|
break;
|
|
case G_SENSOR_OFF:
|
|
atomic_set(&OrizonTilt_Status, CYGSENSOR_STATUS_DISABLED);
|
|
/* Switch TILT off */
|
|
gpio_direction_output(S3C2410_GPC3, 0);
|
|
orizontilt_deinitIrq();
|
|
disable_irq_wake(IRQ_EINT11);
|
|
disable_irq_wake(IRQ_EINT12);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/****************************** ProcFs functions ******************************/
|
|
/******************************************************************************/
|
|
static int orizontilt_procReadIo (char *page, char **start, off_t off, int count,
|
|
int *eof, void *data)
|
|
{
|
|
int len;
|
|
char tmp = 0;
|
|
|
|
|
|
/* We are a tilt and need no calibration */
|
|
tmp |= (1 << 6);
|
|
|
|
if ( atomic_read(&OrizonTilt_Status) != CYGSENSOR_STATUS_ENABLED )
|
|
tmp |= (1 << 4);
|
|
|
|
switch (OrizonTilt_CurrentDirection)
|
|
{
|
|
case 270:
|
|
tmp++;
|
|
case 180:
|
|
tmp++;
|
|
case 90:
|
|
tmp++;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
len = sprintf (page, "%02X", tmp);
|
|
DBG("io readed value: %02X", tmp);
|
|
|
|
FUNC_OUTR(len);
|
|
return len;
|
|
}
|
|
|
|
static int orizontilt_procWriteIo (struct file *file, const char *buffer,
|
|
unsigned long count, void *data)
|
|
{
|
|
char cmd;
|
|
FUNC_IN();
|
|
|
|
/* in case of... */
|
|
if ( count < 1 )
|
|
return 0;
|
|
|
|
cmd = buffer[0];
|
|
switch(cmd)
|
|
{
|
|
case G_SENSOR_ON:
|
|
case G_SENSOR_OFF:
|
|
orizontilt_setMode(cmd);
|
|
break;
|
|
|
|
default:
|
|
printk(KERN_ERR "ProcIO: Unknown command '%c'\n",cmd);
|
|
break;
|
|
}
|
|
|
|
FUNC_OUTR((int)count);
|
|
return count;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/****************************** Module functions ******************************/
|
|
/******************************************************************************/
|
|
static int __init orizontilt_init(void)
|
|
{
|
|
|
|
FUNC_IN();
|
|
//printk(KERN_ERR "Platform is Cybook %d\n", platform_type);
|
|
|
|
SensorsInt[0] = 1;
|
|
SensorsInt[1] = 2;
|
|
|
|
if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GTILT)
|
|
{
|
|
atomic_set(&OrizonTilt_Status, CYGSENSOR_STATUS_UNKNOWN);
|
|
atomic_set(&OrizonTilt_IrqSet, FALSE);
|
|
|
|
rootDir = proc_mkdir(GPROCFS_ROOTFOLDER, NULL);
|
|
|
|
rootDir = proc_mkdir(GPROCFS_MODULEFOLDER, proc_root_driver);
|
|
ioProcEntry = create_proc_entry(GPROCFS_IOFILE, 0644, rootDir);
|
|
|
|
ioProcEntry->read_proc = orizontilt_procReadIo;
|
|
ioProcEntry->write_proc = orizontilt_procWriteIo;
|
|
ioProcEntry->owner = THIS_MODULE;
|
|
}
|
|
|
|
FUNC_OUT();
|
|
return 0;
|
|
}
|
|
// ---------------------------------------------------------------------------
|
|
static void __exit orizontilt_exit(void)
|
|
{
|
|
FUNC_IN();
|
|
|
|
if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GTILT)
|
|
{
|
|
orizontilt_setMode(G_SENSOR_OFF);
|
|
|
|
remove_proc_entry(GPROCFS_IOFILE, rootDir);
|
|
remove_proc_entry(GPROCFS_MODULEFOLDER, proc_root_driver);
|
|
}
|
|
|
|
FUNC_OUT();
|
|
}
|
|
// ---------------------------------------------------------------------------
|
|
module_init(orizontilt_init);
|
|
module_exit(orizontilt_exit);
|
|
// ---------------------------------------------------------------------------
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Bookeen <developers@bookeen.com>");
|
|
MODULE_VERSION("1.1");
|
|
MODULE_DESCRIPTION("Orizon Tilt Sensor driver");
|
|
// ===========================================================================
|