11ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie/* linux/drivers/char/nsc_gpio.c 21ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 31ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie National Semiconductor common GPIO device-file/VFS methods. 41ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie Allows a user space process to control the GPIO pins. 51ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 61ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> 71ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com> 81ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie*/ 91ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 101ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <linux/fs.h> 111ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <linux/module.h> 121ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <linux/errno.h> 131ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <linux/kernel.h> 141ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <linux/init.h> 151ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <linux/nsc_gpio.h> 16f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie#include <linux/platform_device.h> 171ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <asm/uaccess.h> 181ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#include <asm/io.h> 191ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 201ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie#define NAME "nsc_gpio" 211ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 22f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromievoid nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index) 230e41ef3c51ea7dbb764616f60a90700647fc8518Jim Cromie{ 24f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie /* retrieve current config w/o changing it */ 25f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie u32 config = amp->gpio_config(index, ~0, 0); 26f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie 27f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie /* user requested via 'v' command, so its INFO */ 2823916a8e3d8f41aa91474e834ac99808b197c39eJim Cromie dev_info(amp->dev, "io%02u: 0x%04x %s %s %s %s %s %s %s\tio:%d/%d\n", 29f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie index, config, 30f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie (config & 1) ? "OE" : "TS", /* output-enabled/tristate */ 31f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie (config & 2) ? "PP" : "OD", /* push pull / open drain */ 32f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie (config & 4) ? "PUE" : "PUD", /* pull up enabled/disabled */ 33f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie (config & 8) ? "LOCKED" : "", /* locked / unlocked */ 34f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie (config & 16) ? "LEVEL" : "EDGE",/* level/edge input */ 35f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie (config & 32) ? "HI" : "LO", /* trigger on rise/fall edge */ 3623916a8e3d8f41aa91474e834ac99808b197c39eJim Cromie (config & 64) ? "DEBOUNCE" : "", /* debounce */ 3723916a8e3d8f41aa91474e834ac99808b197c39eJim Cromie 3823916a8e3d8f41aa91474e834ac99808b197c39eJim Cromie amp->gpio_get(index), amp->gpio_current(index)); 390e41ef3c51ea7dbb764616f60a90700647fc8518Jim Cromie} 400e41ef3c51ea7dbb764616f60a90700647fc8518Jim Cromie 411a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromiessize_t nsc_gpio_write(struct file *file, const char __user *data, 421a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie size_t len, loff_t *ppos) 431a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie{ 44496ad9aa8ef448058e36ca7a787c61f2e63f0f54Al Viro unsigned m = iminor(file_inode(file)); 451a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie struct nsc_gpio_ops *amp = file->private_data; 46f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie struct device *dev = amp->dev; 471a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie size_t i; 481a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie int err = 0; 491a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie 501a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie for (i = 0; i < len; ++i) { 511a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie char c; 521a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie if (get_user(c, data + i)) 531a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie return -EFAULT; 541a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie switch (c) { 551a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case '0': 561a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_set(m, 0); 571a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 581a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case '1': 591a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_set(m, 1); 601a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 611a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case 'O': 62f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie dev_dbg(dev, "GPIO%d output enabled\n", m); 631a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_config(m, ~1, 1); 641a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 651a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case 'o': 66f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie dev_dbg(dev, "GPIO%d output disabled\n", m); 671a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_config(m, ~1, 0); 681a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 691a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case 'T': 70abecb6da704a71232a3103c8485c65ceb5fcd9dcJim Cromie dev_dbg(dev, "GPIO%d output is push pull\n", m); 711a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_config(m, ~2, 2); 721a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 731a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case 't': 74abecb6da704a71232a3103c8485c65ceb5fcd9dcJim Cromie dev_dbg(dev, "GPIO%d output is open drain\n", m); 751a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_config(m, ~2, 0); 761a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 771a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case 'P': 78f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie dev_dbg(dev, "GPIO%d pull up enabled\n", m); 791a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_config(m, ~4, 4); 801a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 811a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case 'p': 82f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie dev_dbg(dev, "GPIO%d pull up disabled\n", m); 831a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie amp->gpio_config(m, ~4, 0); 841a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 851a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case 'v': 861a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie /* View Current pin settings */ 87f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie amp->gpio_dump(amp, m); 881a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 891a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie case '\n': 901a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie /* end of settings string, do nothing */ 911a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie break; 921a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie default: 93f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie dev_err(dev, "io%2d bad setting: chr<0x%2x>\n", 94f31000e573da052b6b8bcc21faff520b4e2eda7aJim Cromie m, (int)c); 951a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie err++; 961a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie } 971a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie } 981a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie if (err) 991a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie return -EINVAL; /* full string handled, report error */ 1001a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie 1011a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie return len; 1021a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie} 1031a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie 1041a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromiessize_t nsc_gpio_read(struct file *file, char __user * buf, 1051a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie size_t len, loff_t * ppos) 1061a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie{ 107496ad9aa8ef448058e36ca7a787c61f2e63f0f54Al Viro unsigned m = iminor(file_inode(file)); 1081a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie int value; 1091a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie struct nsc_gpio_ops *amp = file->private_data; 1101a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie 1111a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie value = amp->gpio_get(m); 1121a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie if (put_user(value ? '1' : '0', buf)) 1131a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie return -EFAULT; 1141a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie 1151a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie return 1; 1161a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie} 1171a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie 1180e41ef3c51ea7dbb764616f60a90700647fc8518Jim Cromie/* common file-ops routines for both scx200_gpio and pc87360_gpio */ 1191a66fdf083bf2b60c4d12feb970bc7373b59e33aJim CromieEXPORT_SYMBOL(nsc_gpio_write); 1201a66fdf083bf2b60c4d12feb970bc7373b59e33aJim CromieEXPORT_SYMBOL(nsc_gpio_read); 1210e41ef3c51ea7dbb764616f60a90700647fc8518Jim CromieEXPORT_SYMBOL(nsc_gpio_dump); 1221ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 1231ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromiestatic int __init nsc_gpio_init(void) 1241ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie{ 1251ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie printk(KERN_DEBUG NAME " initializing\n"); 1261ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie return 0; 1271ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie} 1281ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 1291ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromiestatic void __exit nsc_gpio_cleanup(void) 1301ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie{ 1311ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie printk(KERN_DEBUG NAME " cleanup\n"); 1321ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie} 1331ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromie 1341ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromiemodule_init(nsc_gpio_init); 1351ca5df0a4cbd17a9536e63c5f69d4717c6538eb0Jim Cromiemodule_exit(nsc_gpio_cleanup); 1361a66fdf083bf2b60c4d12feb970bc7373b59e33aJim Cromie 1371a66fdf083bf2b60c4d12feb970bc7373b59e33aJim CromieMODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>"); 1381a66fdf083bf2b60c4d12feb970bc7373b59e33aJim CromieMODULE_DESCRIPTION("NatSemi GPIO Common Methods"); 1391a66fdf083bf2b60c4d12feb970bc7373b59e33aJim CromieMODULE_LICENSE("GPL"); 140