epit driver

https://blog.csdn.net/wince_lover/article/details/54577898#comments


IMX6Q提供了一個General Purpose Timer (GPT)和兩個Enhanced Periodic Interrupt Timer (EPIT),共三個定時器中斷,但是GPT已經用作系統的時鐘中斷了。
如果我們要用到其他的時鐘中斷,就只能用兩個EPIT。
可是,在IMX6Q的BSP裏面沒有提供EPIT的中斷,下面就介紹下如何實現EPIT中斷。
1 在dts文件裏面添加對EPIT的支持.
  在imx6q.dtsi中添加下面的代碼
  epit1: epit@020d0000 { /* EPIT1 */
                  compatible = "fsl,imx6q-epit1";
                reg = <0x020d0000 0x4000>;
                interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
  };


  epit2: epit@020d4000 { /* EPIT2 */
                compatible = "fsl,imx6q-epit2";
                reg = <0x020d4000 0x4000>;
                interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>;
  };
2 在 include/dt-bindings/clock/imx6qdl-clock.h
  增加
  #define IMX6QDL_CLK_EPIT1                        264
  #define IMX6QDL_CLK_EPIT2                        265
  這兩個宏的數值根據實際情況定義了,也許不是這兩個數字,反正跟在原來定義的宏後面添加就好了。
  修改arch/arm/mach-imx/clk-imx6q.c
  在imx6q_clocks_init函數中添加
  clk[IMX6QDL_CLK_EPIT1]        = imx_clk_gate2("epit1",        "perclk",            base + 0x6c, 12);
  clk[IMX6QDL_CLK_EPIT2]        = imx_clk_gate2("epit2",        "perclk",            base + 0x6c, 14);
  和
  clk_register_clkdev(clk[IMX6QDL_CLK_EPIT1], "per", "imx-epit.1");
  clk_register_clkdev(clk[IMX6QDL_CLK_EPIT2], "per", "imx-epit.2");
  這裏一定不能漏了,否則在驅動中clk_get_sys會失敗的。
 
3 在驅動中初始化定時器中斷
  #define COUNT_TO_NS                15
  epit_reg *reg;
  int init_epit( )
  {
                struct device_node *node;
                u32 val;
                struct clk *timer_clk;
                node = of_find_compatible_node(NULL, NULL,"fsl,imx6q-epit2");
                if(node)
                {
                        reg = of_iomap(node, 0);
                        irq = irq_of_parse_and_map(node, 0);
                }
                else
                {
                        return -1;
                }
                writel(0,&(reg->EPITCR) );
                timer_clk = clk_get_sys("imx-epit.2", "per");
                if (IS_ERR(timer_clk)) {
                        return -1;
                }
                clk_prepare_enable(timer_clk);
                writel(0x0, &(reg->EPITCMPR));
        
                val = EPITCR_CLKSRC_REF_HIGH|EPITCR_IOVW|EPITCR_ENMOD|EPITCR_WAITEN|EPITCR_STOPEN;
         
                val |= EPITCR_RLD;
         
        
                writel(val ,&(reg->EPITCR));
                writel(0, &(reg->EPITLR));
                request_irq(irq, epit2_irq, 0, DEV_NAME, reg);
                return 0;
  }
  這裏需要注意的是如果希望在6Q進入wait或者stop狀態的時候定時器也能工作,一定要或上EPITCR_WAITEN和EPITCR_STOPEN。
  否則在wait或者stop狀態時,定時器就停止計數了。
 
 
  設置定時器的超時時間
  void epit_set_count(epit_reg *reg,int delayus)
  {
                u32 val;
         
                val = delayus*1000/COUNT_TO_NS;
                writel(val, &(reg->EPITLR));
  }
 
 
  使能中斷,在init_epit是沒有打開中斷的
  void epit_enable(epit_reg *reg,int isOn)
  {
                u32 val;
                val = readl(&(reg->EPITCR));
                if(isOn)
                {
                        val |= EPITCR_EN|EPITCR_OCIEN;
                }
                else
                {
                        val &= ~(EPITCR_EN|EPITCR_OCIEN);
                }
                writel(val, &(reg->EPITCR));
  }
 
  清中斷標誌位,這裏如果產生中斷後,一定要清中斷標誌,否則會不斷產生中斷。
  void clearint(epit_reg *reg)
  {
                writel(0x1, &(reg->EPITSR));
  }
 
  定義中斷處理函數
  static irqreturn_t epit2_irq(int irq, void *dev_id)
  {
                clearint((epit_reg *)dev_id);
                epit_enable((epit_reg *)dev_id,0);
         
         
                。。。。處理中斷。。。
                return IRQ_HANDLED;
  }
  OK!大功告成!
  上面的代碼設置了epit2,如果是epit1處理流程是一樣的。

finish code:

#include <linux/module.h> //所有模塊都需要的頭文件
#include <linux/init.h>   // init&exit相關宏
#include <linux/kernel.h>

#include<linux/miscdevice.h>
#include<linux/gpio.h>
#include <linux/gpio.h>
#include<linux/fs.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/pwm.h>
#include <linux/err.h>

#include <linux/mutex.h>
#include <linux/kfifo.h>
#include <linux/completion.h>

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of_irq.h>

#include <linux/clk-provider.h>
#include <linux/clk/ti.h>

#include <linux/of.h>
#include <linux/io.h>
#include <linux/of_address.h>

#include "epit_lqd.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("_lqd");
MODULE_DESCRIPTION("GPIO_LED _lqd");


#define EPITCR      0x00
#define EPITSR      0x04
#define EPITLR      0x08
#define EPITCMPR    0x0c
#define EPITCNR     0x10

#define EPITCR_EN           (1 << 0)
#define EPITCR_ENMOD            (1 << 1)
#define EPITCR_OCIEN            (1 << 2)
#define EPITCR_RLD          (1 << 3)
#define EPITCR_PRESC(x)         (((x) & 0xfff) << 4)
#define EPITCR_SWR          (1 << 16)
#define EPITCR_IOVW         (1 << 17)
#define EPITCR_DBGEN            (1 << 18)
#define EPITCR_WAITEN           (1 << 19)
#define EPITCR_RES          (1 << 20)
#define EPITCR_STOPEN           (1 << 21)
#define EPITCR_OM_DISCON        (0 << 22)
#define EPITCR_OM_TOGGLE        (1 << 22)
#define EPITCR_OM_CLEAR         (2 << 22)
#define EPITCR_OM_SET           (3 << 22)
#define EPITCR_CLKSRC_OFF       (0 << 24)
#define EPITCR_CLKSRC_PERIPHERAL    (1 << 24)
#define EPITCR_CLKSRC_REF_HIGH      (1 << 24)
#define EPITCR_CLKSRC_REF_LOW       (3 << 24)

#define EPITSR_OCIF         (1 << 0)

//static struct class *epit_class;
//struct device   *epit_dev = NULL;

static int epit_irq = 0;
#define DEV_NAME "epit_lqd"
#define COUNT_TO_NS                15

static void __iomem *timer_base = NULL;


//���ó�ʱʱ��
void epit_set_count(void __iomem *reg, int delayus)
{
    u32 val;
    val = delayus * 1000 / COUNT_TO_NS;
    writel(val, (timer_base + EPITLR));
}

void clearint(void __iomem *reg)
{
    if(NULL != timer_base)
    {
        writel(0x1, (timer_base + EPITSR));
    }

}

//ʱ�Ӷ�ʱ���ж�
void epit_enable(void __iomem *reg, int isOn)
{
    u32 val;
    val = readl((timer_base + EPITCR));
    if(isOn)
    {
        val |= EPITCR_EN | EPITCR_OCIEN;
    }
    else
    {
        val &= ~(EPITCR_EN | EPITCR_OCIEN);
    }
    writel(val, (timer_base + EPITCR));
}

//��ʱ���жϴ�������
static irqreturn_t epit2_irq(int irq, void *dev_id)
{
    clearint((void __iomem *)dev_id);
    epit_enable((void __iomem *)dev_id, 1);
    printk("this is epit2_irq kernel _lqd\n");
    return IRQ_HANDLED;
}

static int __init epit_init(void)
{
    struct device_node *node = NULL;
    u32 val;
    int ret = 0;
    struct clk *timer_clk = NULL;
    printk("epit_init kernel _lqd !\n");
    node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-epit1");
    if(NULL == node)
    {
        printk("of_find_compatible_node fail kernel _lqd !\n");
    }
    else
    {
        printk("of_find_compatible_node success kernel _lqd !\n");
    }
    timer_base = of_iomap(node, 0);
    if(NULL == timer_base)
    {
        printk("epit map fail ! kernel _lqd \n");
    }
    else
    {
        printk("epit map success ! kernel _lqd \n");
    }

    epit_irq = irq_of_parse_and_map(node, 0);
    if(0 == epit_irq)
    {
        printk("irq fail ! kernel _lqd \n");
    }
    else
    {
        printk("irq success ! kernel _lqd \n");
    }
    writel(0, (timer_base + EPITCR) );
    timer_clk = clk_get_sys("imx-epit.1", "per");
    if (IS_ERR(timer_clk))
    {
        printk("timer_clk fail kernel _lqd !\n");
        return -1;
    }
    else
    {
        printk("clk_get_sys success kernel _lqd !\n");
    }
    clk_prepare_enable(timer_clk);
    writel(0x0, (timer_base + EPITCMPR));
    val = EPITCR_CLKSRC_REF_HIGH | EPITCR_IOVW | EPITCR_ENMOD | EPITCR_WAITEN | EPITCR_STOPEN;
    val |= EPITCR_RLD;
    writel(val, (timer_base + EPITCR));
    writel(0, (timer_base + EPITLR));
    ret = request_irq(epit_irq, epit2_irq, 0, DEV_NAME, timer_base);
    if(ret < 0)
    {
        printk("epit request_irq fail kernel _lqd !\n");
    }
    else
    {
        printk("epit request_irq success kernel _lqd !\n");
    }
    epit_set_count(timer_base, 1000000);
    epit_enable(timer_base, 1);
    return 0;
}

static void __init epit_exit(void)
{
    printk("epit_init kernel _lqd !\n");
}


module_init(epit_init);
module_exit(epit_exit);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章