1/* 2 * GPIO char driver 3 * 4 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: gpio.c,v 1.5 2008-04-03 03:49:45 $ 19 */ 20 21#include <linux/module.h> 22#include <linux/init.h> 23#include <linux/fs.h> 24#include <linux/miscdevice.h> 25#include <asm/uaccess.h> 26 27#include <typedefs.h> 28#include <bcmutils.h> 29#include <siutils.h> 30#include <bcmdevs.h> 31 32static si_t *gpio_sih; 33static int gpio_major; 34static devfs_handle_t gpio_dir; 35static struct { 36 char *name; 37 devfs_handle_t handle; 38} gpio_file[] = { 39 { "in", NULL }, 40 { "out", NULL }, 41 { "outen", NULL }, 42 { "control", NULL } 43}; 44 45static int 46gpio_open(struct inode *inode, struct file * file) 47{ 48 if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file)) 49 return -ENODEV; 50 51 MOD_INC_USE_COUNT; 52 return 0; 53} 54 55static int 56gpio_release(struct inode *inode, struct file * file) 57{ 58 MOD_DEC_USE_COUNT; 59 return 0; 60} 61 62static ssize_t 63gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos) 64{ 65 u32 val; 66 67 switch (MINOR(file->f_dentry->d_inode->i_rdev)) { 68 case 0: 69 val = si_gpioin(gpio_sih); 70 break; 71 case 1: 72 val = si_gpioout(gpio_sih, 0, 0); 73 break; 74 case 2: 75 val = si_gpioouten(gpio_sih, 0, 0); 76 break; 77 case 3: 78 val = si_gpiocontrol(gpio_sih, 0, 0); 79 break; 80 default: 81 return -ENODEV; 82 } 83 84 if (put_user(val, (u32 *) buf)) 85 return -EFAULT; 86 87 return sizeof(val); 88} 89 90static ssize_t 91gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 92{ 93 u32 val; 94 95 if (get_user(val, (u32 *) buf)) 96 return -EFAULT; 97 98 switch (MINOR(file->f_dentry->d_inode->i_rdev)) { 99 case 0: 100 return -EACCES; 101 case 1: 102 si_gpioout(gpio_sih, ~0, val); 103 break; 104 case 2: 105 si_gpioouten(gpio_sih, ~0, val); 106 break; 107 case 3: 108 si_gpiocontrol(gpio_sih, ~0, val); 109 break; 110 default: 111 return -ENODEV; 112 } 113 114 return sizeof(val); 115} 116 117static struct file_operations gpio_fops = { 118 owner: THIS_MODULE, 119 open: gpio_open, 120 release: gpio_release, 121 read: gpio_read, 122 write: gpio_write, 123}; 124 125static int __init 126gpio_init(void) 127{ 128 int i; 129 130 if (!(gpio_sih = si_kattach(SI_OSH))) 131 return -ENODEV; 132 133 si_gpiosetcore(gpio_sih); 134 135 if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0) 136 return gpio_major; 137 138 gpio_dir = devfs_mk_dir(NULL, "gpio", NULL); 139 140 for (i = 0; i < ARRAYSIZE(gpio_file); i++) { 141 gpio_file[i].handle = devfs_register(gpio_dir, 142 gpio_file[i].name, 143 DEVFS_FL_DEFAULT, gpio_major, i, 144 S_IFCHR | S_IRUGO | S_IWUGO, 145 &gpio_fops, NULL); 146 } 147 148 return 0; 149} 150 151static void __exit 152gpio_exit(void) 153{ 154 int i; 155 156 for (i = 0; i < ARRAYSIZE(gpio_file); i++) 157 devfs_unregister(gpio_file[i].handle); 158 devfs_unregister(gpio_dir); 159 devfs_unregister_chrdev(gpio_major, "gpio"); 160 si_detach(gpio_sih); 161} 162 163module_init(gpio_init); 164module_exit(gpio_exit); 165