For a device driver, the hardware registers access usually involves following kernel API.
- request_mem_region: Tell kernel that the specific range of physical memory are to be used.
- ioremap: Maps the physical memory to kernel virtual memory that can be accessed by kernel.
- ioreadX, iowriteX: X could be 8, 16, 32, parameter is the kernel virtual memory.
- release_mem_region: tell kernel the range of physical memory is not to be used anymore
ioread & iowirte
There are some drivers for ARM device are using "writel" and "iowrite32" function to access IO mapped memory.
writeX read X are deprecated functions, should use ioreadX iowriteX functions.
There is some interesting story about memory barriers of io mapped memory access.
Seems in 2006, writel and iowrite32 is no-barrier. It is nowadays.
http://lwn.net/Articles/198988/
request_mem_region
About why some code, there is no calling of request_mem_region.
http://stackoverflow.com/questions/7682422/what-does-request-mem-region-actually-do-and-when-it-is-needed
Examples
Some source examples shows how to use io read/write related functions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//------------------------------------------------------------------------- | |
// mini s3c24xx I2S driver | |
/* IIS controller */ | |
#define S3C2410_PA_IIS (0x55000000) | |
s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); | |
reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK; | |
writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
#define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE) | |
__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) | |
{ | |
unsigned long last_addr; | |
unsigned long offset = phys_addr & ~PAGE_MASK; | |
unsigned long pfn = __phys_to_pfn(phys_addr); | |
/* | |
* Don't allow wraparound or zero size | |
*/ | |
last_addr = phys_addr + size - 1; | |
if (!size || last_addr < phys_addr) | |
return NULL; | |
return __arm_ioremap_pfn(pfn, offset, size, mtype); | |
} | |
//------------------------------------------------------------------------- | |
//mini s3c24xx framebuffer driver | |
info->mem = request_mem_region(res->start, size, pdev->name); | |
info->io = ioremap(res->start, size); | |
lcdcon1 = readl(info->io + S3C2410_LCDCON1); | |
writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); |
No comments:
Post a Comment