Firefly开源社区

[Linux] RK3288 通过控制寄存器实现LED灯控制

97

积分

0

威望

0

贡献

技术小白

积分
97
发表于 2019-11-18 17:41:00     
麻烦帮我看一下,通过设置power led的寄存器来控制其亮灭,编译安装后,发现无效,麻烦大神指点。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/rockchip/iomap.h>

#define DEVICE_NUM 1
#define DEVICE_NAME "rockled"
#define LEDOFF 0
#define LEDON 1

#define RK_SW_GPIO8_DR_BASE (0xFF7F0000)
#define RK_SW_GPIO8_GRF_BASE (0xFF770080)
#define RK_SW_GPIO8_GDIR_BASE (0xFF7F0004)

static void __iomem *SW_GPIO8_2_DR;
static void __iomem *SW_GPIO8_2_GDIR;
static void __iomem *SW_GPIO8_MUX;

struct rockled_dev {
    dev_t devid;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    int major;
    int minor;
};

struct rockled_dev rockled;

static int rockled_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &rockled;
    printk("rockled open\r\n");
    return 0;
}

static int rockled_release(struct inode *inode, struct file *filp)
{
    printk("rockled release\r\n");
    return 0;
}

static ssize_t rockled_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
    printk("rockled read\r\n");
    return 0;
}

static void led_switch(unsigned char state)
{
    u32 val;
    if(state == LEDON) {
        val = readl(SW_GPIO8_2_DR);
        val &= ~(1<<2);
        writel(val,SW_GPIO8_2_DR);
    } else if( state == LEDOFF ) {
        val = readl(SW_GPIO8_2_DR);
        val |= (1<<2);
        writel(val,SW_GPIO8_2_DR);
    }
}
static ssize_t rockled_write(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
    int retvalue;
    unsigned char databuf[10];
    unsigned char ledstat;

    retvalue = copy_from_user(databuf, buf, size);
    if(retvalue < 0) {
        printk("rockled write failed\r\n");
        return -EFAULT;
    }

    ledstat = databuf[0];
    if(ledstat == LEDON) {
        led_switch(LEDON);
    } else if (ledstat = LEDOFF) {
        led_switch(LEDOFF);
    }
    printk("rockled write success\r\n");
    return 0;
}

static const struct file_operations rockled_fops = {
    .owner = THIS_MODULE,
    .read = rockled_read,
    .write = rockled_write,
    .open = rockled_open,
    .release = rockled_release,
};

static int __init rockled_init(void)
{
    unsigned long val;
    SW_GPIO8_2_DR = ioremap(RK_SW_GPIO8_DR_BASE,4);
    SW_GPIO8_2_GDIR = ioremap(RK_SW_GPIO8_GDIR_BASE,4);
    SW_GPIO8_MUX = ioremap(RK_SW_GPIO8_GRF_BASE,4);

    val = readl(SW_GPIO8_MUX);
    val &= ~(1<<4);
    writel(val,SW_GPIO8_MUX);

    val = readl(SW_GPIO8_2_GDIR);
    val |= (1<<2);
    writel(val,SW_GPIO8_2_GDIR);

    val = readl(SW_GPIO8_2_DR);
    val |= (1<<2);
    writel(val,SW_GPIO8_2_DR);

    if(rockled.major) {
        rockled.devid = MKDEV(rockled.major,0);   
        register_chrdev_region(rockled.devid,DEVICE_NUM,DEVICE_NAME);
    } else {
        alloc_chrdev_region(&rockled.devid,0,DEVICE_NUM,DEVICE_NAME);
        rockled.major = MAJOR(rockled.devid);
        rockled.minor = MINOR(rockled.devid);
    }

    printk("rockled init, major=%d,minor=%d\r\n", rockled.major, rockled.minor);

    rockled.cdev.owner = THIS_MODULE;
    cdev_init(&rockled.cdev, &rockled_fops);

    cdev_add(&rockled.cdev,rockled.devid,DEVICE_NUM);

    rockled.class = class_create(THIS_MODULE, DEVICE_NAME);
    if(IS_ERR(rockled.class)) {
        return PTR_ERR(rockled.class);
    }

    rockled.device = device_create(rockled.class,NULL,rockled.devid,NULL,DEVICE_NAME);
    if(IS_ERR(rockled.device)) {
        return PTR_ERR(rockled.device);
    }
    return 0;
}

module_init(rockled_init);

static void __exit rockled_exit(void)
{
    iounmap(SW_GPIO8_2_GDIR);
    iounmap(SW_GPIO8_2_DR);
    iounmap(SW_GPIO8_MUX);
    device_destroy(rockled.class,rockled.devid);
    class_destroy(rockled.class);
    cdev_del(&rockled.cdev);
    unregister_chrdev_region(rockled.devid,DEVICE_NUM);
}

module_exit(rockled_exit);

MODULE_AUTHOR("rockled");
MODULE_LICENSE("GPL");
回复

使用道具 举报

24

积分

0

威望

0

贡献

技术小白

积分
24
发表于 2019-12-10 11:41:52     
我也在研究这个,说下我的理解:
SW_GPIO8_MUX寄存器控制io复用功能,根据文档描述,如果要修改低16位,就需要在高十六位相对位置置1
举个例子:我要设置gpio8a6复用为gpio功能,就要将[13:12]两个置0,同时将[13+16:12+16]也就是[29:28]两位置1

但是后面设置输入输出方向死活也设不了,读出来是0xa,然后写进去0x4a,再读出来依旧是0xa,不知道哪里出了问题。

请问楼主解决了吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

友情链接 : 爱板网 电子发烧友论坛 云汉电子社区 粤ICP备14022046号-2
快速回复 返回顶部 返回列表