一个通过MIO50引脚点亮LED的驱动。
1、GPIO 基地址:0xE000 A000
2、数据寄存器偏移:0x0000 000C(MASK_DATA_1_MSW)
3、方向寄存器偏移:0x0000 0244 (DIRM_1)
4、使能寄存器偏移:0x0000 0244 (OEN_1)
5、slcr:0xF800 0000
6、时钟:0x0000 012C(APER_CLK_CTRL)
这个寄存器的bit[22]为GPIO_CPU_1XCLKACT需要enable。
7、引脚:0x0000 07C8(MIO_PIN_50)
这个寄存器bit[0]为TRI_ENABLE,需要设置为0(disable)。
gpio_led.c,适配linux4.14。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "first_gpio"
//MIO 50
#define MY_GPIO_BASE_ADDR 0xE000A000
#define XGPIOPS_DIRM_OFFSET 0x00000244U
#define XGPIOPS_OEN_OFFSET 0x00000248U
#define XGPIOPS_DATA_MSW_OFFSET 0x0000000CU
#define SLCR_BASE_ADDR 0xF8000000
#define APER_CLK_OFFSET 0x0000012C
#define MIO_PIN_OFFSET 0x000007C8
MODULE_AUTHOR("Xilinx XUP");
MODULE_DESCRIPTION("LED moudle dirver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");
static int gpio_driver_major;
static struct class* gpio_driver_class = NULL;
static struct device* gpio_driver_device = NULL;
volatile unsigned long *Gpio_DIR = NULL;
volatile unsigned long *Gpio_EN = NULL;
volatile unsigned long *Gpio_DATA = NULL;
volatile unsigned long *DATA = NULL;
volatile unsigned long *CLK = NULL;
volatile unsigned long *MIN_PIN_7 = NULL;
static int gpio_open(struct inode * inode, struct file * filp)
{
printk("first_drv_open\n");
iowrite32(ioread32(Gpio_DIR) | 0x40000, Gpio_DIR);
iowrite32(ioread32(Gpio_EN) | 0x40000, Gpio_EN);
printk("GPIO_DIR_ADDR %x DATA %x \n", Gpio_DIR, ioread32(Gpio_DIR));
printk("GPIO_EN_ADDR %x DATA %x \n", Gpio_EN, ioread32(Gpio_EN));
printk("CLK_ADDR %x DATA %x \n", CLK, ioread32(CLK));
return 0;
}
static ssize_t gpio_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val;
int state ;
printk("first_drv_write\n");
state = copy_from_user(&val, buf, count); // copy_to_user();
if(state)
{
}
if (val == 1)
{
// 点灯
iowrite32(0xfffb0004, Gpio_DATA);
printk("GPIO_DATA_ADDR %x DATA %x \n", Gpio_DATA, ioread32(Gpio_DATA));
}
else
{
// 灭灯
*Gpio_DATA = 0xfffb0000;
printk("GPIO_DATA_ADDR %x DATA %x \n", Gpio_DATA, ioread32(Gpio_DATA));
}
return 0;
}
static struct file_operations gpio_drv_fops = {
.owner = THIS_MODULE,
.open = gpio_open,
.write = gpio_write,
};
int major;
static int __init gpio_drv_init(void)
{
printk("first_drv_init\n");
major = register_chrdev(0, "first_gpio", &gpio_drv_fops);
if (major < 0) {
printk("failed to register device.\n");
return -1;
}
gpio_driver_class = class_create(THIS_MODULE, "firstgpio");
if (IS_ERR(gpio_driver_class)) {
printk("failed to create pwm moudle class.\n");
unregister_chrdev(major, "first_gpio");
return -1;
}
gpio_driver_device = device_create(gpio_driver_class, NULL, MKDEV(major, 0), NULL, "first_gpio"); /* /dev/first_gpio */;
if (IS_ERR(gpio_driver_device)) {
printk("failed to create device .\n");
unregister_chrdev(major, "first_gpio");
return -1;
}
Gpio_DIR = (volatile unsigned long *)ioremap(MY_GPIO_BASE_ADDR + XGPIOPS_DIRM_OFFSET, 4);
Gpio_EN = (volatile unsigned long *)ioremap(MY_GPIO_BASE_ADDR + XGPIOPS_OEN_OFFSET, 4);
Gpio_DATA = (volatile unsigned long *)ioremap(MY_GPIO_BASE_ADDR + XGPIOPS_DATA_MSW_OFFSET, 4);
CLK = (volatile unsigned long *)ioremap(SLCR_BASE_ADDR + APER_CLK_OFFSET, 4);
MIN_PIN_7 = (volatile unsigned long *)ioremap(SLCR_BASE_ADDR + MIO_PIN_OFFSET, 4);
iowrite32(0x3200, MIN_PIN_7);
iowrite32(ioread32(CLK) | 0x400000, CLK);//时钟使能 bit[22] GPIO CLK enable
return 0;
}
static void __exit gpio_drv_exit(void)
{
printk("Exit gpio module.\n");
device_destroy(gpio_driver_class, MKDEV(major, 0));
class_unregister(gpio_driver_class);
class_destroy(gpio_driver_class);
unregister_chrdev(major, "first_gpio");
printk("gpio module exit.\n");
iounmap(Gpio_DIR);
iounmap(Gpio_EN);
iounmap(Gpio_DATA);
iounmap(CLK);
iounmap(MIN_PIN_7);
}
module_init(gpio_drv_init);
module_exit(gpio_drv_exit);
程序参考1。
测试程序gpio_text.c。
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/first_gpio", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
if (argc != 2)
{
printf("Usage :\n");
printf("%s \n" , argv[0]);
return 0;
}
if (strcmp(argv[1], "on") == 0)
{
val = 1;
}
else
{
val = 0;
}
write(fd, &val, 4);
return 0;
}
程序还是有out of tree moudle taints kernel的问题。
https://blog.csdn.net/qq_34322603/article/details/77886912 ↩︎