#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GPIO_NUM_MAX 40 #define GPIO_FUNCTION_OUTPUT 0 #define GPIO_FUNCTION_INPUT 1 #define GPIO_FUNCTION_IRQ 2 #define GPIO_FUNCTION_FLASH 3 static int flash_flag = 0; struct rp_gpio { int gpio_num; //gpui num int gpio_irq; int action; //gpio flag int gpio_event; //input only int send_mode; //input only int gpio_function; //gpio function,i/o int gpio_ctrl; char *gpio_name; }; struct rp_gpio_data { struct rp_gpio rp_gpio_num[GPIO_NUM_MAX]; struct input_dev *input; struct timer_list mytimer; int gpio_dts_num; }; static struct rp_gpio_data *gpio_data = NULL; static int event_flag = 0; static int open_now = 0; static char* file_name = NULL; static int gpio_open(struct inode *inode, struct file *file) { struct dentry* dent = file->f_path.dentry; int i = 0; file_name = (char*)(dent->d_name.name); for (i = 0; i < gpio_data->gpio_dts_num; i++){ if(!strcmp(file_name,gpio_data->rp_gpio_num[i].gpio_name)){ open_now = i; } } return 0; } static ssize_t gpio_write(struct file *file, const char *buffer,size_t count, loff_t *data) { char buf[2]={0}; char s1[]="1"; if(copy_from_user(&buf[0],buffer,1)){ printk("failed to copy data to kernel space\n"); return -EFAULT; } if(!strcmp(buf,s1)){ // gpio_direction_output(gpio_data->rp_gpio_num[open_now].gpio_num,1); gpio_set_value_cansleep(gpio_data->rp_gpio_num[open_now].gpio_num,1); // printk("%s write 1 succeed\n",gpio_data->rp_gpio_num[open_now].gpio_name); }else{ // gpio_direction_output(gpio_data->rp_gpio_num[open_now].gpio_num,0); gpio_set_value_cansleep(gpio_data->rp_gpio_num[open_now].gpio_num,0); // printk("%s write 0 succeed\n",gpio_data->rp_gpio_num[open_now].gpio_name); } return count; } static ssize_t gpio_read(struct file *file, char __user * buffer, size_t count, loff_t *data) { int gpio_val = 0; int len = 0; char s[10] = {0}; if(*data) return 0; gpio_val = gpio_get_value_cansleep(gpio_data->rp_gpio_num[open_now].gpio_num); // printk("get %s value %d\n",gpio_data->rp_gpio_num[open_now].gpio_name,gpio_val); len = sprintf(s+len, "%d\n",gpio_val); return simple_read_from_buffer(buffer, count, data, s, 2); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) static const struct proc_ops gpio_ops = { .proc_open = gpio_open, .proc_write = gpio_write, .proc_read = gpio_read, }; #else static const struct file_operations gpio_ops = { .owner = THIS_MODULE, .open = gpio_open, .write = gpio_write, .read = gpio_read, }; #endif static struct workqueue_struct *my_workqueue; static struct work_struct my_work; static void send_event(struct work_struct *work) { int gpio_value = 0; int i = 0; for(i = 0; i <= gpio_data->gpio_dts_num; i++) { switch(gpio_data->rp_gpio_num[i].gpio_function) { case GPIO_FUNCTION_INPUT : gpio_value = gpio_get_value_cansleep(gpio_data->rp_gpio_num[i].gpio_num); if(gpio_value == 1){ input_report_key(gpio_data->input, gpio_data->rp_gpio_num[i].gpio_event, 1); input_sync(gpio_data->input); } if(gpio_value == 0){ input_report_key(gpio_data->input, gpio_data->rp_gpio_num[i].gpio_event, 0); input_sync(gpio_data->input); } //printk("\n%s gpio num %d %d\n",__func__,gpio_data->rp_gpio_num[i].gpio_num,gpio_value); //printk("\n%s send event %d\n",__func__,gpio_data->rp_gpio_num[i].gpio_event); break; case GPIO_FUNCTION_FLASH : // gpio_direction_output(gpio_data->rp_gpio_num[i].gpio_num,!flash_flag); if(gpio_is_valid(gpio_data->rp_gpio_num[i].gpio_num)){ gpio_set_value_cansleep(gpio_data->rp_gpio_num[i].gpio_num,!flash_flag); flash_flag = !flash_flag; } break; } } mod_timer(&(gpio_data->mytimer), jiffies + msecs_to_jiffies(1000)); } static void timer_callback(struct timer_list *t) { schedule_work(&my_work); } static int rp_gpio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *child_np; struct device *dev = &pdev->dev; static struct proc_dir_entry *root_entry_gpio; enum of_gpio_flags gpio_flags; int ret = 0; int gpio_cnt = 0; char gpio_name_num[GPIO_NUM_MAX]; int gpio_in_cnt = 0; int cnt =0; gpio_data = devm_kzalloc(&pdev->dev, sizeof(struct rp_gpio_data),GFP_KERNEL); if (!gpio_data) { dev_err(&pdev->dev, "failed to allocate memory\n"); return -ENOMEM; } gpio_data->gpio_dts_num = of_get_child_count(np); printk("rp_gpio prepare build %d gpio\n",gpio_data->gpio_dts_num); if (gpio_data->gpio_dts_num == 0){ dev_info(&pdev->dev, "no gpio defined\n"); } /* create node */ root_entry_gpio = proc_mkdir("rp_gpio", NULL); for_each_child_of_node(np, child_np) { /* parse dts */ gpio_data->rp_gpio_num[gpio_cnt].gpio_num = of_get_named_gpio_flags(child_np, "gpio_num", 0, &gpio_flags); if (!gpio_is_valid(gpio_data->rp_gpio_num[gpio_cnt].gpio_num)){ printk("gpio %d is invalid!!!!\n", gpio_data->rp_gpio_num[gpio_cnt].gpio_num); } gpio_data->rp_gpio_num[gpio_cnt].gpio_name = (char*)child_np -> name; gpio_data->rp_gpio_num[gpio_cnt].action = gpio_flags; gpio_data->rp_gpio_num[gpio_cnt].gpio_ctrl = gpio_cnt; of_property_read_u32(child_np, "gpio_function", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_function)); printk("rp_gpio request %s\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_name); switch(gpio_data->rp_gpio_num[gpio_cnt].gpio_function) { case GPIO_FUNCTION_INPUT : /* init input gpio */ ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num"); if (ret < 0) { printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); }else{ printk("success request gpio %d in\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); //gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action); ret = gpio_direction_input(gpio_data->rp_gpio_num[gpio_cnt].gpio_num); if(ret) printk("gpio%d direction input error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); event_flag = gpio_flags; of_property_read_u32(child_np, "send_mode", &(gpio_data->rp_gpio_num[gpio_cnt].send_mode)); of_property_read_u32(child_np, "gpio_event", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_event)); gpio_in_cnt++; } break; case GPIO_FUNCTION_OUTPUT : /* init output gpio */ ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num"); if (ret < 0){ printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); //return ret; }else{ gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action); printk("success request gpio%d out\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); } break; case GPIO_FUNCTION_FLASH : ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num"); if (ret < 0){ printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); //return ret; }else{ gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action); printk("success request gpio%d flash\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); gpio_in_cnt++; } break; } sprintf(gpio_name_num,gpio_data->rp_gpio_num[gpio_cnt].gpio_name,gpio_cnt); proc_create(gpio_name_num, 0666 , root_entry_gpio , &gpio_ops); gpio_cnt++; } if (gpio_in_cnt > 0) { // create workqueue my_workqueue = create_workqueue("my_workqueue"); // init workqueue INIT_WORK(&my_work, send_event); // init timer timer_setup(&gpio_data->mytimer, timer_callback, 0); // set timer mod_timer(&gpio_data->mytimer, jiffies + msecs_to_jiffies(10000)); /* init timer */ /* old linux version timer api init_timer(&(gpio_data->mytimer)); gpio_data->mytimer.expires = jiffies + msecs_to_jiffies(10000); gpio_data->mytimer.function = send_event; add_timer(&(gpio_data->mytimer));*/ /* timer_setup(&(gpio_data->mytimer), send_event, 0); gpio_data->mytimer.expires = jiffies + msecs_to_jiffies(10000); add_timer(&(gpio_data->mytimer)); */ /* init struct input_dev */ gpio_data->input = devm_input_allocate_device(dev); gpio_data->input->name = "gpio_event"; /* pdev->name; */ gpio_data->input->phys = "gpio_event/input1"; gpio_data->input->dev.parent = dev; gpio_data->input->id.bustype = BUS_HOST; gpio_data->input->id.vendor = 0x0001; gpio_data->input->id.product = 0x0001; gpio_data->input->id.version = 0x0100; for(cnt = 0; cnt < gpio_cnt; cnt++){ if (gpio_data->rp_gpio_num[cnt].gpio_function == 1){ input_set_capability(gpio_data->input, EV_KEY, gpio_data->rp_gpio_num[cnt].gpio_event); } } ret = input_register_device(gpio_data->input); } platform_set_drvdata(pdev, gpio_data); return 0; } static int rp_gpio_remove(struct platform_device *pdev) { return 0; } static const struct of_device_id rp_gpio_of_match[] = { { .compatible = "rp_gpio" }, { } }; static struct platform_driver rp_gpio_driver = { .probe = rp_gpio_probe, .remove = rp_gpio_remove, .driver = { .name = "rp_gpio", .of_match_table = of_match_ptr(rp_gpio_of_match), }, }; module_platform_driver(rp_gpio_driver); MODULE_LICENSE("GPL");