Hi I have problem that using hrtimer only getting 21Hz of interrupts. Did I configure it wrongly?
I am looking something that goes for MHz range(says 10-20MHz), anyway for me to that?
I am using omap powered "devkit8000".
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <plat/mux.h>
#include <linux/string.h>
#include <linux/spi/spi.h>
#include <linux/version.h>
#include <linux/vmalloc.h> // for vmalloc
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/cdev.h> // for char device
#include <linux/slab.h>
#include <linux/fs.h> // for file operation
#include <linux/mm.h>
#include<linux/fcntl.h>
#include <asm/uaccess.h> // for copy_from and copy_to user
#include <asm/io.h>
#include <linux/ioctl.h>
#include <linux/timer.h>
#define DEBUG_KERNEL 1
#define SPI_BUFF_SIZE 16
#define USER_BUFF_SIZE 128
#define SUCCESS 0
#define ERROR -1
#define SPI_BUS 1
#define SPI_BUS_CS1 1
#define SPI_BUS_SPEED 1000000
#define PRODUCT_ID_ADDR 0x00
#define PRODUCT_ID 0x33
#define MS_TO_NS(x) (x * 1E6L)
#define GPIO_130 130
#define HIGH 1
#define LOW 0
#define USER_TIMER 10
const char this_driver_name[] = "testgpio";
struct testgpio_dev {
struct semaphore spi_sem;
struct semaphore fop_sem;
struct mutex mutex;
dev_t devt;
struct cdev cdev;
struct class *class;
char *user_buff;
u8 test_data;
struct mutex lock;
char loopcounter;
};
static struct testgpio_dev testgpio_dev;
static unsigned long delay_in_ms;
static struct hrtimer hr_timer;
static int my_tasklet_data;
void inittimer(unsigned long data );
void setting_timer(unsigned long data, ktime_t *t);
DECLARE_TASKLET( tasklet_inittimer, inittimer, (unsigned long) &my_tasklet_data );
enum hrtimer_restart my_hrtimer_callback( struct hrtimer *timer )
{
// ktime : interval
// currtime : current time
ktime_t currtime, ktime;
unsigned long missed;
currtime = ktime_get();
setting_timer(delay_in_ms, &ktime);
//hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );
missed = hrtimer_forward(&hr_timer, currtime, ktime);
if (missed > 1)
printk("Missed ticks %ld\n", missed - 1);
gpio_set_value( GPIO_130, (!gpio_get_value(GPIO_130)) );// tonggle IO
printk( "my_hrtimer_callback CurrTime: %llu ns\n", (unsigned long long)(ktime_to_ns(currtime)>>10) );
return HRTIMER_RESTART;
}
void setting_timer(unsigned long data, ktime_t *t)
{
switch(data)
{
case 1:
*t = ktime_set( 0, 1 );
break;
case 10:
*t = ktime_set( 0, 10L );
break;
case 100:
*t = ktime_set( 0, 100L );
break;
case 1000:
*t = ktime_set( 0, 1000L );
break;
case 10000:
*t = ktime_set( 0, 10000L);
break;
default:
break;
}
}
void inittimer( unsigned long data )
{
ktime_t ktime,currtime;
printk("HR Timer module installing\n");
setting_timer(delay_in_ms, &ktime);
hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
hr_timer.function = &my_hrtimer_callback;
currtime = ktime_get();
printk( "Starting timer to fire in %ldms (%ld)\n", delay_in_ms, jiffies );
printk( "inittimer CurrTime: (%llu)ns.\n", (unsigned long long)(ktime_to_ns(currtime)>>10) );
hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );
}
static ssize_t testgpio_read(struct file *filp, char __user *buff, size_t count,
loff_t *offp)
{
size_t len;
ssize_t status = 0;
printk(KERN_ALERT "@testgpio_read\n");
return status;
}
static ssize_t testgpio_write(struct file *file, const char __user * buffer, size_t length, loff_t * offset)
{
int status = 0;
char cmdtype[10];
char wrmode[10];
u8 addval = 0;
u8 dataval = 0;
unsigned int timerval = 0;
mutex_lock(&testgpio_dev.mutex);
if (!buffer)
return -EFAULT;
if (*offset > 0)
return 0;
printk(KERN_ALERT "@testgpio_write\n");
printk(KERN_ALERT "@testgpio_write length: %d",length);
sscanf(buffer,"%s %s %hhx %hhx %d"
,cmdtype, wrmode, &addval, &dataval, &timerval);
printk(KERN_ALERT "@testgpio_write buffer content: %s %s 0x%x 0x%x %d"
,cmdtype, wrmode, addval, dataval, timerval);
if(strcmp(cmdtype,"timer") == 0)
{
if(strcmp(wrmode,"w") == 0)
{
//delay_in_ms = (unsigned long)timerval;
//printk(KERN_ALERT"@testgpio_write user_timer: %lu'\n",user_timer);
}
else if(strcmp(wrmode,"i") == 0)
{
//delay_in_ms = (signed int)timerval;
tasklet_schedule( &tasklet_inittimer );
}
else if(strcmp(wrmode,"k") == 0)
{
hrtimer_try_to_cancel(&hr_timer); // cancel the timer without waiting
tasklet_kill(&tasklet_inittimer);
gpio_set_value(GPIO_130, LOW); //
}
else if(strcmp(wrmode,"k") == 0)
{
hrtimer_try_to_cancel(&hr_timer); // cancel the timer without waiting
}
delay_in_ms = timerval;
}
printk(KERN_ALERT "@testgpio_write counter %d\n",testgpio_dev.loopcounter++);
status = length; // notes: somehow this need to be length else there will be looping
mutex_unlock(&testgpio_dev.mutex);
return status;
}
static int testgpio_open(struct inode *inode, struct file *filp)
{
int status = 0;
testgpio_dev.loopcounter =0;
printk(KERN_ALERT "@testgpio_open\n");
if (down_interruptible(&testgpio_dev.fop_sem))
return -ERESTARTSYS;
if (!testgpio_dev.user_buff) {
testgpio_dev.user_buff = kmalloc(USER_BUFF_SIZE, GFP_KERNEL);
if (!testgpio_dev.user_buff)
status = -ENOMEM;
}
up(&testgpio_dev.fop_sem);
return status;
}
static const struct file_operations testgpio_fops = {
.owner = THIS_MODULE,
.read = testgpio_read,
.open = testgpio_open,
.write = testgpio_write,
};
static int __init testgpio_init_GPIO(void)
{
int status;
printk(KERN_INFO "@testgpio_init_GPIO\n");
status = omap_cfg_reg(AE2_34XX_GPIO130_OUT);
printk(KERN_INFO "@testgpio_init_GPIO omap_cfg_reg's status %d, %d\n",
status,AE2_34XX_GPIO130_OUT );
if((gpio_request(GPIO_130, "AE2_34XX_GPIO130_OUT") == 0) &&
(gpio_direction_output(GPIO_130, HIGH)==0) )
{
gpio_set_value(GPIO_130, LOW); // Preset to LOW
printk(KERN_INFO "@testgpio_init_GPIO AE2_34XX_GPIO130_OUT is good!\n");
return SUCCESS;
}
else
return ERROR;
return status;
}
static int __init testgpio_init_cdev(void)
{
int error;
printk(KERN_ALERT "@testgpio_init_cdev\n");
testgpio_dev.devt = MKDEV(0, 0);
error = alloc_chrdev_region(&testgpio_dev.devt, 0, 1, this_driver_name);
if (error < 0) {
printk(KERN_ALERT "alloc_chrdev_region() failed: %d \n",
error);
return -1;
}
cdev_init(&testgpio_dev.cdev, &testgpio_fops);
testgpio_dev.cdev.owner = THIS_MODULE;
error = cdev_add(&testgpio_dev.cdev, testgpio_dev.devt, 1);
if (error) {
printk(KERN_ALERT "cdev_add() failed: %d\n", error);
unregister_chrdev_region(testgpio_dev.devt, 1);
return -1;
}
return 0;
}
static int __init testgpio_init_class(void)
{
printk(KERN_ALERT "@testgpio_init_class\n");
testgpio_dev.class = class_create(THIS_MODULE, this_driver_name);
if (!testgpio_dev.class) {
printk(KERN_ALERT "class_create() failed\n");
return -1;
}
if (!device_create(testgpio_dev.class, NULL, testgpio_dev.devt, NULL,
this_driver_name)) {
printk(KERN_ALERT "device_create(..., %s) failed\n",
this_driver_name);
class_destroy(testgpio_dev.class);
return -1;
}
return 0;
}
static int __init testgpio_init(void)
{
memset(&testgpio_dev, 0, sizeof(testgpio_dev));
memset(&testgpio_ctl, 0, sizeof(testgpio_ctl));
sema_init(&testgpio_dev.spi_sem, 1);
sema_init(&testgpio_dev.fop_sem, 1);
if (testgpio_init_cdev() < 0)
goto fail_1;
if (testgpio_init_class() < 0)
goto fail_2;
if(testgpio_init_GPIO() < 0)
goto fail_4;
return SUCCESS;
fail_3:
device_destroy(testgpio_dev.class, testgpio_dev.devt);
class_destroy(testgpio_dev.class);
fail_2:
cdev_del(&testgpio_dev.cdev);
unregister_chrdev_region(testgpio_dev.devt, 1);
fail_1:
return ERROR;
}
module_init(testgpio_init);
static void __exit testgpio_exit(void)
{
device_destroy(testgpio_dev.class, testgpio_dev.devt);
class_destroy(testgpio_dev.class);
cdev_del(&testgpio_dev.cdev);
unregister_chrdev_region(testgpio_dev.devt, 1);
gpio_free(GPIO_130);
if (testgpio_dev.user_buff)
kfree(testgpio_dev.user_buff);
}
module_exit(testgpio_exit);
MODULE_AUTHOR("Den");
MODULE_DESCRIPTION("testgpio module - an video SPI driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");