1/* 2 * GPIO char driver 3 * 4 * Copyright 2006, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: gpio.c,v 1.1.1.1 2008/10/15 03:26:06 james26_jang Exp $ 13 */ 14 15#include <linux/module.h> 16#include <linux/init.h> 17#include <linux/fs.h> 18#include <linux/miscdevice.h> 19#include <asm/uaccess.h> 20 21#include <typedefs.h> 22#include <bcmutils.h> 23#include <sbutils.h> 24#include <bcmdevs.h> 25 26static sb_t *gpio_sbh; 27static int gpio_major; 28static devfs_handle_t gpio_dir; 29static struct { 30 char *name; 31 devfs_handle_t handle; 32} gpio_file[] = { 33 { "in", NULL }, 34 { "out", NULL }, 35 { "outen", NULL }, 36 { "control", NULL } 37}; 38 39static int 40gpio_open(struct inode *inode, struct file * file) 41{ 42 if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file)) 43 return -ENODEV; 44 45 MOD_INC_USE_COUNT; 46 return 0; 47} 48 49static int 50gpio_release(struct inode *inode, struct file * file) 51{ 52 MOD_DEC_USE_COUNT; 53 return 0; 54} 55 56static ssize_t 57gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos) 58{ 59 u32 val; 60 61 switch (MINOR(file->f_dentry->d_inode->i_rdev)) { 62 case 0: 63 val = sb_gpioin(gpio_sbh); 64 break; 65 case 1: 66 val = sb_gpioout(gpio_sbh, 0, 0); 67 break; 68 case 2: 69 val = sb_gpioouten(gpio_sbh, 0, 0); 70 break; 71 case 3: 72 val = sb_gpiocontrol(gpio_sbh, 0, 0); 73 break; 74 default: 75 return -ENODEV; 76 } 77 78 if (put_user(val, (u32 *) buf)) 79 return -EFAULT; 80 81 return sizeof(val); 82} 83 84static ssize_t 85gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 86{ 87 u32 val; 88 89 if (get_user(val, (u32 *) buf)) 90 return -EFAULT; 91 92 switch (MINOR(file->f_dentry->d_inode->i_rdev)) { 93 case 0: 94 return -EACCES; 95 case 1: 96 sb_gpioout(gpio_sbh, ~0, val); 97 break; 98 case 2: 99 sb_gpioouten(gpio_sbh, ~0, val); 100 break; 101 case 3: 102 sb_gpiocontrol(gpio_sbh, ~0, val); 103 break; 104 default: 105 return -ENODEV; 106 } 107 108 return sizeof(val); 109} 110 111static struct file_operations gpio_fops = { 112 owner: THIS_MODULE, 113 open: gpio_open, 114 release: gpio_release, 115 read: gpio_read, 116 write: gpio_write, 117}; 118 119static int __init 120gpio_init(void) 121{ 122 int i; 123 124 if (!(gpio_sbh = sb_kattach(SB_OSH))) 125 return -ENODEV; 126 127 sb_gpiosetcore(gpio_sbh); 128 129 if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0) 130 return gpio_major; 131 132 gpio_dir = devfs_mk_dir(NULL, "gpio", NULL); 133 134 for (i = 0; i < ARRAYSIZE(gpio_file); i++) { 135 gpio_file[i].handle = devfs_register(gpio_dir, 136 gpio_file[i].name, 137 DEVFS_FL_DEFAULT, gpio_major, i, 138 S_IFCHR | S_IRUGO | S_IWUGO, 139 &gpio_fops, NULL); 140 } 141 142 return 0; 143} 144 145static void __exit 146gpio_exit(void) 147{ 148 int i; 149 150 for (i = 0; i < ARRAYSIZE(gpio_file); i++) 151 devfs_unregister(gpio_file[i].handle); 152 devfs_unregister(gpio_dir); 153 devfs_unregister_chrdev(gpio_major, "gpio"); 154 sb_detach(gpio_sbh); 155} 156 157module_init(gpio_init); 158module_exit(gpio_exit); 159