/* =========================================================================== * orizon_tilt.c * Copyright (C) 2009-2010 Bookeen - All rights reserved * =========================================================================== */ /* TODO: Verify if all this includes are necessary */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; 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; Cyio_PushEvent(CYEVENT_ORIENTATIONCHANGED, true); } 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 "); MODULE_VERSION("1.1"); MODULE_DESCRIPTION("Orizon Tilt Sensor driver"); // ===========================================================================