使用writel将4位写入ioremap-ed内存地址

时间:2017-04-02 05:36:36

标签: c linux-kernel kernel-module gpio ioremap

我是内核编程新手,现在尝试将一些值写入设备驱动程序中的32位GPIO寄存器。 I / O是ioremap() - 内存地址。问题是,我不知道writel() / writeb() / writew()如何将位写入地址。

供应商文件称寄存器位于0xE5200000。我必须写入的位是[0:3]位,并将剩余的28位([4:31]位)保留为零。

这是我到目前为止编写的设备驱动程序代码的一部分:

#define TCON_ADDR 0xE250000 // The address as provided by the vendor
static void *TIMER_CON_ADDR;
// I have to map and write to the address when the device is opened
static int on_dev_open(struct inode *inode, struct file *file) {
    unsigned int data;
    TIMER_CON_ADDR = ioremap(TCON_ADDR, 4); // Map the [0:4] bits to TIMER_CON_ADDR
    data = 4; // 0100 in binary
    writel(data, TIMER_CON_ADDR); // Write 0100 to TIMER_CON_ADDR
    return 0;
}

上述代码可能只是对你们所有人都是彻头彻尾的胡言乱语,但我对write(l|w|b)ioremap()并不熟悉。

所以我的问题是:

  1. 我是否正确地将[0:4]位映射到TIMER_CON_ADDR?
  2. 如果没有,我该如何正确映射它们?
  3. 在我正确映射了4位后,如何使用任何write(1|w|b)函数以正确的顺序将位(0100)写入TIMER_CON_ADDR?
  4. write(l|w|b)在编写位时做了什么?
  5. 我有错过/出错的信息吗?
  6. 提前感谢您的帮助。

1 个答案:

答案 0 :(得分:5)

  
      
  1. 我是否正确地将[0:4]位映射到TIMER_CON_ADDR?
  2.   

不,你写32位,writel写4个字节,4 * 8 = 32位

  
      
  1. 如果没有,我该如何正确映射它们?
  2.   

无法映射4位,最小8位= 1个字节,但如果使用32位 注册你需要地图32位= 4字节。另外别忘了检查和处理 错误。

  
      
  1. 在我正确映射了4位后,如何使用任何write(1|w|b)函数以正确的顺序将位(0100)写入TIMER_CON_ADDR?
  2.   

你需要使用readl,内核充满示例,只需在linux内核源代码树的grep子目录中运行drivers。 一般想法读/写:

u32 reg = readl(TIMER_CON_ADDR);
reg &= ~0xfu;
reg |= 4;
writel(reg, TIMER_CON_ADDR);
  
      
  1. write(l|w|b)在编写位时做了什么?
  2.   
看看源代码,它只是简单的C函数,如:

static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
    *(volatile u32 __force *)addr = value;
}

主要的想法是告诉编译器它不应该删除 你的记忆读/写

  
      
  1. 我有没有错过/出错的信息?
  2.   

读取类似驱动程序的源代码,它已经包含了差不多 这些简单驱动程序的所有解决方案。