cyb4_linux/drivers/input/misc/orizon_tilt.c
2021-11-21 00:20:20 +00:00

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