#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "led_drv.h"
#include "led_imx6ull.h"
/*该数组中gpio_regs结构体的个数决定了LED灯的数量,一个gpio_regs结构体代表一个LED灯
*/
static const struct gpio_regs led_regs[] = {
{
{ 0x020C406C, 0x0C000000, 0x3 }, //GPIO时钟模块配置
{ 0x020E0068, 0x0000000F, 0x5 }, //GPIO引脚复用配置
{ 0x020E02F4, 0x0001FFFF, 0x10B0 }, //GPIO引脚电气属性配置
{ 0x0209C004, 0x00000008, 0x1 }, //GPIO引脚配置为输出
{ 0x0209C000, 0x00000008, 0x1 }, //GPIO默认输出高电平
},
//可在此添加gpio_regs结构体,增加LED灯
};
/*准备LED设备的驱动资源
*/
static void * prepare_drv_resource(int count)
{
int i;
struct led_resource *led_res;
//分配LED内存映射结构体
led_res = (struct led_resource *)kzalloc(sizeof(struct led_resource) * count, GFP_KERNEL);
//将LED用到的寄存器进行内存映射
for(i = 0; i < count; i++) {
led_res[i].ccm_map = ioremap(led_regs[i].ccm_reg[0], 4);
led_res[i].mux_map = ioremap(led_regs[i].mux_reg[0], 4);
led_res[i].pad_map = ioremap(led_regs[i].pad_reg[0], 4);
led_res[i].gdir_map = ioremap(led_regs[i].gdir_reg[0], 4);
led_res[i].dr_map = ioremap(led_regs[i].dr_reg[0], 4);
led_res[i].bitmask = led_regs[i].dr_reg[1];
}
return (void *)led_res;
}
static void release_drv_resource(void *res, int count)
{
int i;
struct led_resource *led_res = (struct led_resource *)res;
if(led_res) {
for(i = 0; i < count; i++) {
iounmap(led_res[i].ccm_map);
iounmap(led_res[i].mux_map);
iounmap(led_res[i].pad_map);
iounmap(led_res[i].gdir_map);
iounmap(led_res[i].dr_map);
}
kfree(led_res);
}
}
static int init_led_gpio(int which, void *res, void **ppriv)
{
unsigned int value, offset;
struct led_resource *led_res;
if(which < 0)
return -1;
if(!res || !ppriv)
return -1;
led_res = (struct led_resource *)res;
//开启GPIO模块时钟
GET_MASK_OFFSET(led_regs[which].ccm_reg[1], offset);
value = readl(led_res[which].ccm_map);
value &= (~led_regs[which].ccm_reg[1]);
value |= (led_regs[which].ccm_reg[2] << offset);
writel(value, led_res[which].ccm_map);
//复用引脚为GPIO
GET_MASK_OFFSET(led_regs[which].mux_reg[1], offset);
value = readl(led_res[which].mux_map);
value &= (~led_regs[which].mux_reg[1]);
value |= (led_regs[which].mux_reg[2] << offset);
writel(value, led_res[which].mux_map);
//设置引脚电气属性
GET_MASK_OFFSET(led_regs[which].pad_reg[1], offset);
value = readl(led_res[which].pad_map);
value &= (~led_regs[which].pad_reg[1]);
value |= (led_regs[which].pad_reg[2] << offset);
writel(value, led_res[which].pad_map);
//配置GPIO引脚为输出
GET_MASK_OFFSET(led_regs[which].gdir_reg[1], offset);
value = readl(led_res[which].gdir_map);
value &= (~led_regs[which].gdir_reg[1]);
value |= (led_regs[which].gdir_reg[2] << offset);
writel(value, led_res[which].gdir_map);
//默认输出高电平
GET_MASK_OFFSET(led_regs[which].dr_reg[1], offset);
value = readl(led_res[which].dr_map);
value &= (~led_regs[which].dr_reg[1]);
value |= (led_regs[which].dr_reg[2] << offset);
writel(value, led_res[which].dr_map);
//返回该LED设备的私有数据
*ppriv = (void*)&led_res[which];
return 0;
}
static int set_led_gpio(void *res, char val)
{
unsigned int value, offset;
struct led_resource *led_res;
//获取LED设备对应的资源结构体
led_res = (struct led_resource *)res;
if(!led_res)
return -1;
//设置GPIO引脚电平
GET_MASK_OFFSET(led_res->bitmask, offset);
value = readl(led_res->dr_map);
value &= (~led_res->bitmask);
if(val == LED_ON)
value &= (0x0 << offset);
else
value |= (0x1 << offset);
writel(value, led_res->dr_map);
return 0;
}
static int close_led_gpio(void *res)
{
unsigned int value, offset;
struct led_resource *led_res;
//获取LED设备对应的资源结构体
led_res = (struct led_resource *)res;
if(!led_res)
return -1;
//关闭LED
GET_MASK_OFFSET(led_res->bitmask, offset);
value = readl(led_res->dr_map);
value &= (~led_res->bitmask);
value |= (0x1 << offset);
writel(value, led_res->dr_map);
return 0;
}
static struct led_drv_func func_list;
static int __init imx6ull_led_init(void)
{
int ret;
func_list.func_prepare_drv_resource = prepare_drv_resource;
func_list.func_release_drv_resource = release_drv_resource;
func_list.func_init_led_gpio = init_led_gpio;
func_list.func_set_led_gpio = set_led_gpio;
func_list.func_close_led_gpio = close_led_gpio;
leddrv_register_func(&func_list);
ret = leddrv_register_leds(sizeof(led_regs) / sizeof(struct gpio_regs));
if(ret != 0)
return -1;
return 0;
}
static void __exit imx6ull_led_exit(void)
{
leddrv_unresister_func();
leddrv_unregister_leds();
}
module_init(imx6ull_led_init);
module_exit(imx6ull_led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David.Tang");