1/* 2 * Copyright (C) 2007 Nicolas Thill <nico@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include <linux/device.h> 20#include <linux/fs.h> 21#include <linux/module.h> 22#include <linux/errno.h> 23#include <linux/kernel.h> 24#include <linux/init.h> 25#include <linux/platform_device.h> 26#include <linux/uaccess.h> 27#include <linux/io.h> 28#include <linux/types.h> 29#include <linux/cdev.h> 30#include <gpio.h> 31 32#define DRVNAME "ar7_gpio" 33#define LONGNAME "TI AR7 GPIOs Driver" 34 35MODULE_AUTHOR("Nicolas Thill <nico@openwrt.org>"); 36MODULE_DESCRIPTION(LONGNAME); 37MODULE_LICENSE("GPL"); 38 39static int ar7_gpio_major; 40 41static ssize_t ar7_gpio_write(struct file *file, const char __user *buf, 42 size_t len, loff_t *ppos) 43{ 44 int pin = iminor(file->f_dentry->d_inode); 45 size_t i; 46 47 for (i = 0; i < len; ++i) { 48 char c; 49 if (get_user(c, buf + i)) 50 return -EFAULT; 51 switch (c) { 52 case '0': 53 gpio_set_value(pin, 0); 54 break; 55 case '1': 56 gpio_set_value(pin, 1); 57 break; 58 case 'd': 59 case 'D': 60 ar7_gpio_disable(pin); 61 break; 62 case 'e': 63 case 'E': 64 ar7_gpio_enable(pin); 65 break; 66 case 'i': 67 case 'I': 68 case '<': 69 gpio_direction_input(pin); 70 break; 71 case 'o': 72 case 'O': 73 case '>': 74 gpio_direction_output(pin, 0); 75 break; 76 default: 77 return -EINVAL; 78 } 79 } 80 81 return len; 82} 83 84static ssize_t ar7_gpio_read(struct file *file, char __user *buf, 85 size_t len, loff_t *ppos) 86{ 87 int pin = iminor(file->f_dentry->d_inode); 88 int value; 89 90 value = gpio_get_value(pin); 91 if (put_user(value ? '1' : '0', buf)) 92 return -EFAULT; 93 94 return 1; 95} 96 97static int ar7_gpio_open(struct inode *inode, struct file *file) 98{ 99 int m = iminor(inode); 100 101 if (m >= (ar7_is_titan() ? TITAN_GPIO_MAX : AR7_GPIO_MAX)) 102 return -EINVAL; 103 104 return nonseekable_open(inode, file); 105} 106 107static int ar7_gpio_release(struct inode *inode, struct file *file) 108{ 109 return 0; 110} 111 112static const struct file_operations ar7_gpio_fops = { 113 .owner = THIS_MODULE, 114 .write = ar7_gpio_write, 115 .read = ar7_gpio_read, 116 .open = ar7_gpio_open, 117 .release = ar7_gpio_release, 118 .llseek = no_llseek, 119}; 120 121static struct platform_device *ar7_gpio_device; 122 123static int __init ar7_gpio_char_init(void) 124{ 125 int rc; 126 127 ar7_gpio_device = platform_device_alloc(DRVNAME, -1); 128 if (!ar7_gpio_device) 129 return -ENOMEM; 130 131 rc = platform_device_add(ar7_gpio_device); 132 if (rc < 0) 133 goto out_put; 134 135 rc = register_chrdev(ar7_gpio_major, DRVNAME, &ar7_gpio_fops); 136 if (rc < 0) 137 goto out_put; 138 139 ar7_gpio_major = rc; 140 141 rc = 0; 142 143 goto out; 144 145out_put: 146 platform_device_put(ar7_gpio_device); 147out: 148 return rc; 149} 150 151static void __exit ar7_gpio_char_exit(void) 152{ 153 unregister_chrdev(ar7_gpio_major, DRVNAME); 154 platform_device_unregister(ar7_gpio_device); 155} 156 157module_init(ar7_gpio_char_init); 158module_exit(ar7_gpio_char_exit); 159