imx6q 定時器設定
阿新 • • 發佈:2019-01-05
IMX6Q提供了一個General Purpose Timer (GPT)和兩個Enhanced Periodic Interrupt Timer (EPIT),共三個定時器中斷,但是GPT已經用作系統的時鐘中斷了。
如果我們要用到其他的時鐘中斷,就只能用兩個EPIT。
可是,在IMX6Q的BSP裡面沒有提供EPIT的中斷,下面就介紹下如何實現EPIT中斷。
1 在dts檔案裡面新增對EPIT的支援.
在imx6q.dtsi中新增下面的程式碼
epit1: [email protected] { /* EPIT1 */
compatible = "fsl,imx6q-epit1";
reg = <0x020d0000 0x4000>;
interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
};
epit2: [email protected] { /* 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處理流程是一樣的。
如果我們要用到其他的時鐘中斷,就只能用兩個EPIT。
可是,在IMX6Q的BSP裡面沒有提供EPIT的中斷,下面就介紹下如何實現EPIT中斷。
1 在dts檔案裡面新增對EPIT的支援.
在imx6q.dtsi中新增下面的程式碼
epit1: [email protected] { /* EPIT1 */
compatible = "fsl,imx6q-epit1";
reg = <0x020d0000 0x4000>;
interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
};
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處理流程是一樣的。