#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GPIO_NUM_MAX 4 struct gpio_info{ char name[64]; int pin; int direction; int out_def; }; static struct gpio_info all_gpio_pin[GPIO_NUM_MAX]={ { .name = "mcu_boot", .pin = MCU_BOOT, .direction = GPIO_DIR_OUT, .out_def = GPIO_OUT_LOW, }, { .name = "mcu_reset", .pin = MCU_RESET, .direction = GPIO_DIR_OUT, .out_def = GPIO_OUT_LOW, }, { .name = "mcu_pwr", .pin = MCU_PWR, .direction = GPIO_DIR_OUT, .out_def = GPIO_OUT_LOW, }, { .name = "mcu_uart_pwr", .pin = MCU_UART_PWR, .direction = GPIO_DIR_OUT, .out_def = GPIO_OUT_LOW, }, }; static void rs_gpio_request(void) { int ret; int index; for(index=0; index= GPIO_NUM_MAX){ KERNEL_INFO("ERROR gpio=%d when reading!!\n", gpio_index); return -EFAULT; } sprintf(send_msg, "%u\n", gpio_get_value(all_gpio_pin[gpio_index].pin));; cnt = copy_to_user(buf, send_msg, sizeof(send_msg));// 将内核空间的数据copy到用户空间 if(cnt){ KERNEL_INFO("ERROR occur when reading!!\n"); return -EFAULT; } KERNEL_INFO("name:%s %d", all_gpio_pin[gpio_index].name, gpio_get_value(all_gpio_pin[gpio_index].pin)); return cnt; } // 当用户往设备文件写数据时,调用这个函数 // counter 10 intervalgpio 30 intervaladc 30 bufsize 2048 gpiopin 总个数 0 122 124 threshold ssize_t rs_gpio_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { int gpio = 0; KERNEL_INFO("%s\n", ubuf); if(!strncmp(ubuf, "SETGPIO ", 8) && count > 8){ // SETGPIO 1 1 gpio = ubuf[8]; if(gpio < GPIO_NUM_MAX){ if (gpio_is_valid(all_gpio_pin[gpio].pin)) { if(count > 10){ gpio_set_value(all_gpio_pin[gpio].pin, ubuf[10]); } else { KERNEL_INFO("error pin=%d", all_gpio_pin[gpio].pin); } } } else { KERNEL_INFO("error gpio=%d", gpio); } }else if(!strncmp(ubuf, "GETGPIO ", 8) && count > 8){ // GETGPIO 1 gpio = ubuf[8]; if(gpio < GPIO_NUM_MAX){ gpio_index = gpio; } } return count; } // File opertion 结构体,我们通过这个结构体建立应用程序到内核之间操作的映射 static struct file_operations file_oprts = { .owner = THIS_MODULE, .read = rs_gpio_read, .write = rs_gpio_write, }; #define DEVICE_NAME "rsgpio" // Device 名称,对应/dev下的目录名称 static struct miscdevice rs_gpio_misc_device = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &file_oprts }; /* static int rs_gpio_suspend(void) { bright = 0; printk("bright %d gpio_get_value(88) = %d \n",bright,gpio_get_value(88)); return 0; } static int rs_gpio_resume(void) { bright = 1; printk("bright %d gpio_get_value(88) = %d \n",bright,gpio_get_value(88)); return 0; } static struct dev_pm_ops rs_gpio_pm_ops = { .suspend = rs_gpio_suspend, .resume = rs_gpio_resume, }; */ static void mcu_power_on(void) { // Init MCU_Boot = 0 && MCU_Reset = 1'b0 if (gpio_is_valid(MCU_BOOT)) { gpio_direction_output(MCU_BOOT, GPIO_OUT_LOW); } if (gpio_is_valid(MCU_RESET)) { gpio_direction_output(MCU_RESET, GPIO_OUT_LOW); } // Enable MCU 3.3 if (gpio_is_valid(MCU_PWR)) { gpio_direction_output(MCU_PWR, GPIO_OUT_HIGH); msleep(20); } // Enable OE of AW3911 - Level shifter if (gpio_is_valid(MCU_UART_PWR)) { gpio_direction_output(MCU_UART_PWR, GPIO_OUT_HIGH); msleep(20); } if (gpio_is_valid(MCU_RESET)) { gpio_direction_output(MCU_RESET, GPIO_OUT_HIGH); } } static void mcu_power_off(void) { //rs_gpio_set(MCU_PWR, GPIO_OUT_LOW); if (gpio_is_valid(MCU_PWR)) { gpio_direction_output(MCU_PWR, GPIO_OUT_LOW); } //rs_gpio_set(MCU_UART_PWR, GPIO_OUT_LOW); if (gpio_is_valid(MCU_UART_PWR)) { gpio_direction_output(MCU_UART_PWR, GPIO_OUT_LOW); } if (gpio_is_valid(MCU_BOOT)) { gpio_direction_output(MCU_BOOT, GPIO_OUT_LOW); } if (gpio_is_valid(MCU_RESET)) { gpio_direction_output(MCU_RESET, GPIO_OUT_LOW); } } /* // android_print 表示Android层LOG打印开关 #ifdef CONFIG_ANDROID_LOG_CLOSED static char android_print = 0; // 0表示不打印(user版本的默认不打印) #else static char android_print = 1; // 1表示打印 #endif #define LOG_SEEK_OFFSET 8*1024*1024 #define LOG_PATH "/dev/block/sde65" static int rwdev(char* buf, int len, int flag) { struct file *log_filp; mm_segment_t old_fs; int length=0; log_filp=filp_open(LOG_PATH,O_RDWR,0); if(IS_ERR(log_filp)){ KERNEL_ERROR("open %s err:%d !\n",LOG_PATH,PTR_ERR(log_filp)); return -1; } old_fs = get_fs(); set_fs(KERNEL_DS); log_filp->f_op->llseek(log_filp, LOG_SEEK_OFFSET, SEEK_SET); if(flag==0) length=vfs_read(log_filp, buf, len, &log_filp->f_pos); else length=vfs_write(log_filp, buf, len, &log_filp->f_pos); set_fs(old_fs); return length; } static int get_log_enable(void) { char buf[2]; int length = rwdev(buf, 2, 0); if(length < 2) { KERNEL_ERROR("get_log_enable %s err!\n",LOG_PATH); return -1; } if(buf[0] == '1') { if(buf[1] == '1') { return 1; } else { return 0; } } else { return android_print; } } static int write_log_enable(char is_enable) { char buf[2] = {'1',is_enable}; int length = rwdev(buf, 2, 1); if(length < 2) { KERNEL_ERROR("write_log_enable %s err!\n",LOG_PATH); return -1; } return 0; } */ // 添加节点控制 static ssize_t sysfs_set_driver_ctl(struct device *dev, struct device_attribute *attr, const char *ubuf, size_t size) { KERNEL_ERROR("cmd_write:%s", ubuf); if(!strncmp(ubuf, "mcupower ", 9) && size > 9){ if(ubuf[9] == '1'){ // 打开MCU的电 mcu_power_on(); } else { // 关掉MCU的电 mcu_power_off(); } } else if(!strncmp(ubuf, "logenable ", 10) && size > 10){ if(ubuf[10] == '1'){ //write_log_enable('1'); } else { //write_log_enable('0'); } } else { KERNEL_ERROR(KERN_ERR "muxcmd error for cmd %s", ubuf); } return size; } static ssize_t sysfs_get_driver_ctl(struct device *dev, struct device_attribute *attr, char *ubuf) { ssize_t size = 0;//sprintf(ubuf, "%d", get_log_enable()); KERNEL_ERROR("cmd_read: size=%d, ubuf=%s", size, ubuf); return size; } static DEVICE_ATTR(driver_ctl, 0644, sysfs_get_driver_ctl, sysfs_set_driver_ctl); static void rs_gpio_shutdown(struct platform_device *device) { KERNEL_INFO("done!"); } static int rs_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int ret = misc_register(&rs_gpio_misc_device); if (ret) { KERNEL_INFO("rs_gpio: Unable to register misc device ret=%d\n", ret); } rs_gpio_request(); device_create_file(dev, &dev_attr_driver_ctl); //mcu_power_on(); KERNEL_INFO("\n"); return ret; } static int __exit rs_gpio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; KERNEL_INFO("\n"); rs_gpio_free(); misc_deregister(&rs_gpio_misc_device); device_remove_file(dev, &dev_attr_driver_ctl); return 0; } static struct platform_driver rs_gpio_driver = { .driver = { .owner = THIS_MODULE, .name = DEVICE_NAME, //.pm = &rs_gpio_pm_ops, }, .shutdown = rs_gpio_shutdown, .probe = rs_gpio_probe, .remove = rs_gpio_remove, }; static struct platform_device rs_gpio_dev = { .name = DEVICE_NAME, .id = -1, }; int __init rs_gpio_init(void) { platform_device_register(&rs_gpio_dev); platform_driver_register(&rs_gpio_driver); KERNEL_INFO("driver init success!!\n"); return 0; } void __exit rs_gpio_exit(void) { platform_device_unregister(&rs_gpio_dev); platform_driver_unregister(&rs_gpio_driver); KERNEL_INFO("driver %s removed\n", DEVICE_NAME); } module_init(rs_gpio_init); module_exit(rs_gpio_exit); MODULE_AUTHOR("kevin"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIO driver");