硬件定时器的使用方法

SSC3xx系列芯片有三个硬件定时器timer0 timer1 timer2,

硬件定时器有两种模式: Repeat mode 和 One time mode 。

以下以One time mode为例的例程:

/mdrv_timer.h/

#ifndef __MDRV_TIMER_H
#define __MDRV_TIMER_H

#include "../include/ms_types.h"
#include "../include/ms_platform.h"
#include "../include/infinity6/irqs.h"
#define INT_FIQ_TIMER_0_MAP (INT_FIQ_TIMER_0+32)
#define INT_FIQ_TIMER_1_MAP (INT_FIQ_TIMER_1+32)
#define INT_FIQ_TIMER_2_MAP (INT_FIQ_TIMER_2+32)
#define BIT_0 0x1
#define BIT_1 0x2
#define BIT_2 0x4
#define BIT_3 0x8
#define BIT_4 0x10
#define BIT_5 0x20
#define BIT_6 0x40
#define BIT_7 0x80
#define BIT_8 0x100
#define BIT_9 0x200
#define BIT_10 0x400
#define BIT_11 0x800
#define BIT_12 0x1000 #define BIT_13 0x2000
#define BIT_14 0x4000
#define BIT_15 0x8000

#define INFINITY_BASE_REG_RIU_PA (0x1F000000)
#define BASE_REG_TIMER_PA GET_REG_ADDR(INFINITY_BASE_REG_RIU_PA, 0x001800)
#define BK_REG(reg) ((reg) << 2)

#define TIMER0_EN_REG BK_REG(0x10)
#define TIMER0_HIT_REG BK_REG(0x11)
#define TIMER0_MAX_L_REG BK_REG(0x12)
#define TIMER0_MAX_H_REG BK_REG(0x13)
#define TIMER0_CAP_L_REG BK_REG(0x14)
#define TIMER0_CAP_H_REG BK_REG(0x15)

#define TIMER1_EN_REG BK_REG(0x20)
#define TIMER1_HIT_REG BK_REG(0x21)
#define TIMER1_MAX_L_REG BK_REG(0x22)
#define TIMER1_MAX_H_REG BK_REG(0x23)
#define TIMER1_CAP_L_REG BK_REG(0x24)
#define TIMER1_CAP_H_REG BK_REG(0x25)

#define TIMER2_EN_REG BK_REG(0x30)
#define TIMER2_HIT_REG BK_REG(0x31)
#define TIMER2_MAX_L_REG BK_REG(0x32)
#define TIMER2_MAX_H_REG BK_REG(0x33)
#define TIMER2_CAP_L_REG BK_REG(0x34)
#define TIMER2_CAP_H_REG BK_REG(0x35)

#define TIMER_TRIG_BIT BIT_1
#define TIMER_EN_BIT BIT_0
#define TIMER_INT_EN_BIT BIT_8
#define TIMER_HIT_BIT BIT_0

#endif

/mdrv_timer.c/
/******************************************************************/
//dts file: /*
timer_test {
compatible = "sstar,infinity-timer";
};
*/
/******************************************************************/
#include < linux/module.h >
#include < linux/moduleparam.h >
#include < linux/types.h >
#include < linux/timer.h >
#include < linux/watchdog.h >
#include < linux/init.h >
#include < linux/platform_device.h >
#include < linux/interrupt.h >
#include < linux/clk.h >
#include < linux/uaccess.h >
#include < linux/io.h >
#include < linux/cpufreq.h >
#include < linux/slab.h >
#include < linux/err.h >
#include "../include/ms_types.h"
#include "../include/ms_platform.h"
#include "mdrv_timer.h"
#include < linux/of.h >
#include < linux/of_irq.h >
#include < linux/irqdomain.h >
#include < linux/irq.h >
#include < dt-bindings/interrupt-controller/arm-gic.h >

#define TimerDbg printk

static unsigned int time_count = 0;
static int virq = -1;
irqreturn_t timer_int_service(int irq, void *dummy)
{
time_count ++;
if(time_count%2)
{
OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_L_REG, 0x8D80);
OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_H_REG, 0x005B); //0.5 secord
}
else {
OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_L_REG, 0x1B00);
OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_H_REG, 0x00B7); //1 secord
}
SETREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG ,TIMER_INT_EN_BIT | TIMER_TRIG_BIT); //Enable interrupt,and set mode:ont shot
TimerDbg(KERN_ERR "[%d]timer_int_service doing\n\n",irq);
return IRQ_HANDLED;
}

static int infinity_timer_probe(struct platform_device *pdev)
{
S32 s32_ret=-1;
struct device_node *intr_node;
struct irq_domain *intr_domain;
struct irq_fwspec fwspec;

intr_node = of_find_compatible_node(NULL, NULL, "sstar,main-intc");  
intr_domain = irq_find_host(intr_node);  
if(!intr_domain){  
    TimerDbg(KERN_ERR "timer_mod : irq_find_host fail \n");  
    return -ENXIO;  
}  
fwspec.param_count = 3;  
fwspec.param[0] = GIC_SPI;  
fwspec.param[1] = INT_FIQ_TIMER_0;  
fwspec.param[2] = IRQ_TYPE_NONE;  
fwspec.fwnode = of_node_to_fwnode(intr_node);  
virq = irq_create_fwspec_mapping(&fwspec);  
s32_ret = request_irq(virq, timer_int_service, IRQF_SHARED, "timer_int_service", (void *)timer_int_service);  
if (s32_ret)  
{  
    TimerDbg(KERN_ERR"timer_modules Err: request_irq fail %d \n",s32_ret);  
}  
else{  
    TimerDbg(KERN_ERR"timer_modules: request_irq successful \n");  
}

OUTREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG,0); //disable timer  
OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_L_REG, 0x1B00);   
OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_H_REG, 0x00B7); //set 32bits counter :1 secord  
SETREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG ,TIMER_INT_EN_BIT | TIMER_TRIG_BIT);    //Enable interrupt,and set mode:ont shot  
TimerDbg("Timer_open:successful!\n");  
return 0;

}
static int infinity_timer_remove(struct platform_device *dev)
{
free_irq(virq,timer_int_service);
TimerDbg("[Timer]infinity_timer_remove \n");
return 0;
}

static void infinity_timer_shutdown(struct platform_device *dev)
{
TimerDbg("[Timer]infinity_timer_shutdown \n");
}

static const struct of_device_id ms_timer_of_match_table[] = {
{ .compatible = "sstar,infinity-timer" },
{}
};
MODULE_DEVICE_TABLE(of, ms_timer_of_match_table);

static struct platform_driver infinity_timer_driver = {
.probe = infinity_timer_probe,
.remove = infinity_timer_remove,
.shutdown = infinity_timer_shutdown,

.driver        = {  
    .owner    = THIS_MODULE,  
    .name    = "infinity-timer",  
    .of_match_table = ms_timer_of_match_table,  
},

};

module_platform_driver(infinity_timer_driver);

MODULE_AUTHOR("MStar Semiconductor, Inc.");
MODULE_DESCRIPTION("infinity timer Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:infinity-timer");

两种mode的操作区别:

one shot:

初始化: OUTREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG, 0x0); //清除

OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_L_REG, 0x1B00); //set 32bits counter OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_H_REG, 0x00B7); SETREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG ,TIMER_INT_EN_BIT|TIMER_TRIG_BIT); //Enable interrupt & triger oneshot

在中断服务里,设计下一个中断:

OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_L_REG, 0x1B00); //set new 32bits counter OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_H_REG, 0x00B7); SETREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG,TIMER_INT_EN_BIT|TIMER_TRIG_BIT); //Enable interrupt & triger oneshot

report mode

初始化:

OUTREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG, 0x0); //清除

OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_L_REG, 0x1B00); //set 32bits counter OUTREG16(BASE_REG_TIMER_PA + TIMER0_MAX_H_REG, 0x00B7);

SETREG16(BASE_REG_TIMER_PA + TIMER0_EN_REG,TIMER_INT_EN_BIT|TIMER_EN_BIT); //Enable interrupt & triger oneshot

在中断服务里,再不用设置寄存器。