2 * FILE NAME ibm_ocp_gpio.c
4 * BRIEF MODULE DESCRIPTION
5 * API for IBM PowerPC 4xx GPIO device.
6 * Driver for IBM PowerPC 4xx GPIO device.
8 * Armin Kuster akuster@pacbell.net
12 * Author: MontaVista Software, Inc. <source@mvista.com>
13 * Frank Rowand <frank_rowand@mvista.com>
14 * Debbie Chu <debbie_chu@mvista.com>
16 * Copyright 2000,2001,2002 MontaVista Software Inc.
18 * This program is free software; you can redistribute it and/or modify it
19 * under the terms of the GNU General Public License as published by the
20 * Free Software Foundation; either version 2 of the License, or (at your
21 * option) any later version.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
26 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * You should have received a copy of the GNU General Public License along
35 * with this program; if not, write to the Free Software Foundation, Inc.,
36 * 675 Mass Ave, Cambridge, MA 02139, USA.
40 * Version: 02/01/12 - Armin
41 * converted to ocp and using ioremap
43 * 1.2 02/21/01 - Armin
44 * minor compiler warning fixes
46 * 1.3 02/22/01 - Armin
49 * 1.4 05/07/02 - Armin/David Mueller
50 * coverted to core_ocp[];
52 * 1.5 05/25/02 - Armin
53 * name change from *_driver to *_dev
55 * 1.6 06/04/02 - Matt Porter
56 * ioremap paddr. Comment as 4xx generic driver.
57 * Fix header to be userland safe and locate in
58 * an accessible area. Add ioctl to configure
59 * multiplexed GPIO pins.
61 * 1.7 07/25/02 - Armin
62 * added CPM to enable/disable in init/exit
66 #define VUFX "07.25.02"
68 #include <linux/module.h>
69 #include <linux/config.h>
70 #include <linux/types.h>
71 #include <linux/kernel.h>
72 #include <linux/miscdevice.h>
73 #include <linux/init.h>
74 #include <linux/ioctl.h>
76 #include <linux/ibm_ocp_gpio.h>
77 #include <asm/uaccess.h>
79 #include <asm/machdep.h>
82 struct miscdevice ibm_gpio_miscdev;
83 static struct gpio_regs *gpiop;
86 static struct pm_dev *pm_gpio;
89 gpio_save_state(u32 state)
95 gpio_suspend(u32 state)
97 mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | state);
102 gpio_resume(u32 state)
104 mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~state);
110 ibm_gpio_config(__u32 device, __u32 mask, __u32 data)
122 * PPC405 uses CPC0_CR0 to select multiplexed GPIO pins.
124 cfg_reg = mfdcr(DCRN_CHCR0);
125 cfg_reg = (cfg_reg & ~mask) | (data & mask);
126 mtdcr(DCRN_CHCR0, cfg_reg);
129 * PPC440 uses CPC0_GPIO to select multiplexed GPIO pins.
131 cfg_reg = mfdcr(DCRN_CPC0_GPIO);
132 cfg_reg = (cfg_reg & ~mask) | (data & mask);
133 mtdcr(DCRN_CPC0_GPIO, cfg_reg);
135 #error This driver is only supported on PPC40x and PPC440 CPUs
142 ibm_gpio_tristate(__u32 device, __u32 mask, __u32 data)
149 gpiop->tcr = (gpiop->tcr & ~mask) | (data & mask);
154 ibm_gpio_open_drain(__u32 device, __u32 mask, __u32 data)
161 gpiop->odr = (gpiop->odr & ~mask) | (data & mask);
167 ibm_gpio_in(__u32 device, __u32 mask, volatile __u32 * data)
174 gpiop->tcr = gpiop->tcr & ~mask;
178 ** If the previous state was OUT, and gpiop->ir is read once, then the
179 ** data that was being OUTput will be read. One way to get the right
180 ** data is to read gpiop->ir twice.
184 *data = gpiop->ir & mask;
190 ibm_gpio_out(__u32 device, __u32 mask, __u32 data)
197 gpiop->or = (gpiop->or & ~mask) | (data & mask);
199 gpiop->tcr = gpiop->tcr | mask;
205 ibm_gpio_open(struct inode *inode, struct file *file)
213 ibm_gpio_release(struct inode *inode, struct file *file)
221 ibm_gpio_ioctl(struct inode *inode, struct file *file,
222 unsigned int cmd, unsigned long arg)
224 static struct ibm_gpio_ioctl_data ioctl_data;
229 if (copy_from_user(&ioctl_data,
230 (struct ibm_gpio_ioctl_data *) arg,
231 sizeof (ioctl_data))) {
235 status = ibm_gpio_in(ioctl_data.device,
236 ioctl_data.mask, &ioctl_data.data);
240 if (copy_to_user((struct ibm_gpio_ioctl_data *) arg,
241 &ioctl_data, sizeof (ioctl_data))) {
248 if (copy_from_user(&ioctl_data,
249 (struct ibm_gpio_ioctl_data *) arg,
250 sizeof (ioctl_data))) {
254 return ibm_gpio_out(ioctl_data.device,
255 ioctl_data.mask, ioctl_data.data);
259 case IBMGPIO_OPEN_DRAIN:
260 if (copy_from_user(&ioctl_data,
261 (struct ibm_gpio_ioctl_data *) arg,
262 sizeof (ioctl_data))) {
266 return ibm_gpio_open_drain(ioctl_data.device,
267 ioctl_data.mask, ioctl_data.data);
271 case IBMGPIO_TRISTATE:
272 if (copy_from_user(&ioctl_data,
273 (struct ibm_gpio_ioctl_data *) arg,
274 sizeof (ioctl_data)))
277 return ibm_gpio_tristate(ioctl_data.device,
278 ioctl_data.mask, ioctl_data.data);
283 if (copy_from_user(&ioctl_data,
284 (struct ibm_gpio_ioctl_data *) arg,
285 sizeof (ioctl_data)))
288 return ibm_gpio_config(ioctl_data.device,
289 ioctl_data.mask, ioctl_data.data);
300 static struct file_operations ibm_gpio_fops = {
302 ioctl:ibm_gpio_ioctl,
304 release:ibm_gpio_release,
311 struct ocp_dev *gpio_dev;
313 printk("IBM gpio driver version %s\n", VUFX);
314 while (curr_gpio != -ENXIO) {
315 if (!(gpio_dev = ocp_alloc_dev(0)))
318 gpio_dev->type = GPIO;
319 if ((curr_gpio = ocp_register(gpio_dev)) == -ENXIO) {
320 ocp_free_dev(gpio_dev);
323 ibm_gpio_miscdev.minor = 185; /*GPIO_MINOR; */
324 ibm_gpio_miscdev.name = gpio_dev->name;
325 ibm_gpio_miscdev.fops = &ibm_gpio_fops;
326 misc_register(&ibm_gpio_miscdev); /*ibm_gpio_miscdev); */
328 gpiop = (struct gpio_regs *) ioremap(gpio_dev->paddr,
329 sizeof (struct gpio_regs));
330 mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR)
331 & ~ocp_get_pm(GPIO, curr_gpio));
332 printk("GPIO #%d at 0x%lx\n", curr_gpio,
333 (unsigned long) gpiop);
338 return (curr_gpio == -ENXIO) ? 0 : curr_gpio;
345 struct ocp_dev *gpio_dev;
347 for (i = 0; i < ocp_get_max(GPIO); i++) {
348 gpio_dev = ocp_get_dev(GPIO, i);
349 misc_deregister(&ibm_gpio_miscdev);
350 mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | ocp_get_pm(GPIO, i));
351 ocp_unregister(gpio_dev);
355 module_init(ibm_gpio_init);
356 module_exit(ibm_gpio_exit);
358 EXPORT_SYMBOL(ibm_gpio_tristate);
359 EXPORT_SYMBOL(ibm_gpio_open_drain);
360 EXPORT_SYMBOL(ibm_gpio_in);
361 EXPORT_SYMBOL(ibm_gpio_out);
363 MODULE_LICENSE("GPL");