imx6q 定时器设置

2021年9月7日 5点热度 0条评论 来源: wince_lover

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处理流程是一样的。

    原文作者:wince_lover
    原文地址: https://blog.csdn.net/wince_lover/article/details/54577898
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。