1/*
2 * Linux Broadcom BCM47xx GPIO char driver
3 *
4 * Copyright 2007, 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 * $Id: linux_gpio.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $
12 *
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
26#include <linux_gpio.h>
27
28/* handle to the sb */
29static sb_t *gpio_sbh;
30
31/* major number assigned to the device and device handles */
32static int gpio_major;
33devfs_handle_t gpiodev_handle;
34
35static int
36gpio_open(struct inode *inode, struct file * file)
37{
38	MOD_INC_USE_COUNT;
39	return 0;
40}
41
42static int
43gpio_release(struct inode *inode, struct file * file)
44{
45	MOD_DEC_USE_COUNT;
46	return 0;
47}
48
49static int
50gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
51{
52	struct gpio_ioctl gpioioc;
53
54	if (copy_from_user(&gpioioc, (struct gpio_ioctl *)arg, sizeof(struct gpio_ioctl)))
55		return -EFAULT;
56
57	switch (cmd) {
58		case GPIO_IOC_RESERVE:
59			gpioioc.val = sb_gpioreserve(gpio_sbh, gpioioc.mask, GPIO_APP_PRIORITY);
60			break;
61		case GPIO_IOC_RELEASE:
62			/*
63			 * releasing the gpio doesn't change the current
64			 * value on the GPIO last write value
65			 * persists till some one overwrites it
66			 */
67			gpioioc.val = sb_gpiorelease(gpio_sbh, gpioioc.mask, GPIO_APP_PRIORITY);
68			break;
69		case GPIO_IOC_OUT:
70			gpioioc.val = sb_gpioout(gpio_sbh, gpioioc.mask, gpioioc.val,
71			                         GPIO_APP_PRIORITY);
72			break;
73		case GPIO_IOC_OUTEN:
74			gpioioc.val = sb_gpioouten(gpio_sbh, gpioioc.mask, gpioioc.val,
75			                           GPIO_APP_PRIORITY);
76			break;
77		case GPIO_IOC_IN:
78			gpioioc.val = sb_gpioin(gpio_sbh);
79			break;
80		default:
81			break;
82	}
83	if (copy_to_user((struct gpio_ioctl *)arg, &gpioioc, sizeof(struct gpio_ioctl)))
84		return -EFAULT;
85
86	return 0;
87
88}
89static struct file_operations gpio_fops = {
90	owner:		THIS_MODULE,
91	open:		gpio_open,
92	release:	gpio_release,
93	ioctl:		gpio_ioctl,
94	};
95
96static int __init
97gpio_init(void)
98{
99	if (!(gpio_sbh = sb_kattach(SB_OSH)))
100		return -ENODEV;
101
102	if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0)
103		return gpio_major;
104
105	gpiodev_handle = devfs_register(NULL, "gpio", DEVFS_FL_DEFAULT,
106	                                gpio_major, 0, S_IFCHR | S_IRUGO | S_IWUGO,
107	                                &gpio_fops, NULL);
108
109	return 0;
110}
111
112static void __exit
113gpio_exit(void)
114{
115	if (gpiodev_handle != NULL)
116		devfs_unregister(gpiodev_handle);
117	gpiodev_handle = NULL;
118	devfs_unregister_chrdev(gpio_major, "gpio");
119	sb_detach(gpio_sbh);
120}
121
122module_init(gpio_init);
123module_exit(gpio_exit);
124