1/* 2 * Linux Broadcom BCM47xx GPIO char driver 3 * 4 * Copyright (C) 2010, 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 * $Id: linux_gpio.c,v 1.10 2008/03/28 19:25:35 Exp $ 18 * 19 */ 20#include <linux/module.h> 21#include <linux/init.h> 22#include <linux/fs.h> 23#include <linux/miscdevice.h> 24#include <asm/uaccess.h> 25 26#include <typedefs.h> 27#include <bcmutils.h> 28#include <siutils.h> 29#include <bcmdevs.h> 30 31#include <linux_gpio.h> 32 33/* handle to the sb */ 34static si_t *gpio_sih; 35 36/* major number assigned to the device and device handles */ 37static int gpio_major; 38#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) 39static struct class *gpiodev_class = NULL; 40#else 41devfs_handle_t gpiodev_handle; 42#endif 43 44static int 45gpio_open(struct inode *inode, struct file * file) 46{ 47 MOD_INC_USE_COUNT; 48 return 0; 49} 50 51static int 52gpio_release(struct inode *inode, struct file * file) 53{ 54 MOD_DEC_USE_COUNT; 55 return 0; 56} 57 58static int 59gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 60{ 61 struct gpio_ioctl gpioioc; 62 63 if (copy_from_user(&gpioioc, (struct gpio_ioctl *)arg, sizeof(struct gpio_ioctl))) 64 return -EFAULT; 65 66 switch (cmd) { 67 case GPIO_IOC_RESERVE: 68 gpioioc.val = si_gpioreserve(gpio_sih, gpioioc.mask, GPIO_APP_PRIORITY); 69 break; 70 case GPIO_IOC_RELEASE: 71 /* 72 * releasing the gpio doesn't change the current 73 * value on the GPIO last write value 74 * persists till some one overwrites it 75 */ 76 gpioioc.val = si_gpiorelease(gpio_sih, gpioioc.mask, GPIO_APP_PRIORITY); 77 break; 78 case GPIO_IOC_OUT: 79 gpioioc.val = si_gpioout(gpio_sih, gpioioc.mask, gpioioc.val, 80 GPIO_APP_PRIORITY); 81 break; 82 case GPIO_IOC_OUTEN: 83 gpioioc.val = si_gpioouten(gpio_sih, gpioioc.mask, gpioioc.val, 84 GPIO_APP_PRIORITY); 85 break; 86 case GPIO_IOC_IN: 87 gpioioc.val = si_gpioin(gpio_sih); 88 break; 89 default: 90 break; 91 } 92 if (copy_to_user((struct gpio_ioctl *)arg, &gpioioc, sizeof(struct gpio_ioctl))) 93 return -EFAULT; 94 95 return 0; 96 97} 98static struct file_operations gpio_fops = { 99 owner: THIS_MODULE, 100 open: gpio_open, 101 release: gpio_release, 102 ioctl: gpio_ioctl 103}; 104 105static int __init 106gpio_init(void) 107{ 108 if (!(gpio_sih = si_kattach(SI_OSH))) 109 return -ENODEV; 110 111#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) 112 if ((gpio_major = register_chrdev(0, "gpio", &gpio_fops)) < 0) 113#else 114 if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0) 115#endif 116 return gpio_major; 117#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) 118 gpiodev_class = class_create(THIS_MODULE, "gpio"); 119 if (IS_ERR(gpiodev_class)) { 120 printk("Error creating gpio class\n"); 121 return -1; 122 } 123 124 /* Add the device gpio0 */ 125 class_device_create(gpiodev_class, NULL, MKDEV(gpio_major, 0), NULL, "gpio"); 126#else 127 gpiodev_handle = devfs_register(NULL, "gpio", DEVFS_FL_DEFAULT, 128 gpio_major, 0, S_IFCHR | S_IRUGO | S_IWUGO, 129 &gpio_fops, NULL); 130#endif 131 132 return 0; 133} 134 135static void __exit 136gpio_exit(void) 137{ 138#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) 139 if (gpiodev_class != NULL) { 140 class_device_destroy(gpiodev_class, MKDEV(gpio_major, 0)); 141 class_destroy(gpiodev_class); 142 } 143 144 gpiodev_class = NULL; 145 if (gpio_major >= 0) 146 unregister_chrdev(gpio_major, "gpio"); 147#else 148 if (gpiodev_handle != NULL) 149 devfs_unregister(gpiodev_handle); 150 gpiodev_handle = NULL; 151 devfs_unregister_chrdev(gpio_major, "gpio"); 152#endif 153 si_detach(gpio_sih); 154} 155 156module_init(gpio_init); 157module_exit(gpio_exit); 158