xref: /openbmc/linux/arch/mips/bcm63xx/gpio.c (revision e7300d04)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7  * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
8  */
9 
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/spinlock.h>
13 #include <linux/platform_device.h>
14 #include <linux/gpio.h>
15 
16 #include <bcm63xx_cpu.h>
17 #include <bcm63xx_gpio.h>
18 #include <bcm63xx_io.h>
19 #include <bcm63xx_regs.h>
20 
21 static DEFINE_SPINLOCK(bcm63xx_gpio_lock);
22 static u32 gpio_out_low, gpio_out_high;
23 
24 static void bcm63xx_gpio_set(struct gpio_chip *chip,
25 			     unsigned gpio, int val)
26 {
27 	u32 reg;
28 	u32 mask;
29 	u32 *v;
30 	unsigned long flags;
31 
32 	if (gpio >= chip->ngpio)
33 		BUG();
34 
35 	if (gpio < 32) {
36 		reg = GPIO_DATA_LO_REG;
37 		mask = 1 << gpio;
38 		v = &gpio_out_low;
39 	} else {
40 		reg = GPIO_DATA_HI_REG;
41 		mask = 1 << (gpio - 32);
42 		v = &gpio_out_high;
43 	}
44 
45 	spin_lock_irqsave(&bcm63xx_gpio_lock, flags);
46 	if (val)
47 		*v |= mask;
48 	else
49 		*v &= ~mask;
50 	bcm_gpio_writel(*v, reg);
51 	spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags);
52 }
53 
54 static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio)
55 {
56 	u32 reg;
57 	u32 mask;
58 
59 	if (gpio >= chip->ngpio)
60 		BUG();
61 
62 	if (gpio < 32) {
63 		reg = GPIO_DATA_LO_REG;
64 		mask = 1 << gpio;
65 	} else {
66 		reg = GPIO_DATA_HI_REG;
67 		mask = 1 << (gpio - 32);
68 	}
69 
70 	return !!(bcm_gpio_readl(reg) & mask);
71 }
72 
73 static int bcm63xx_gpio_set_direction(struct gpio_chip *chip,
74 				      unsigned gpio, int dir)
75 {
76 	u32 reg;
77 	u32 mask;
78 	u32 tmp;
79 	unsigned long flags;
80 
81 	if (gpio >= chip->ngpio)
82 		BUG();
83 
84 	if (gpio < 32) {
85 		reg = GPIO_CTL_LO_REG;
86 		mask = 1 << gpio;
87 	} else {
88 		reg = GPIO_CTL_HI_REG;
89 		mask = 1 << (gpio - 32);
90 	}
91 
92 	spin_lock_irqsave(&bcm63xx_gpio_lock, flags);
93 	tmp = bcm_gpio_readl(reg);
94 	if (dir == GPIO_DIR_IN)
95 		tmp &= ~mask;
96 	else
97 		tmp |= mask;
98 	bcm_gpio_writel(tmp, reg);
99 	spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags);
100 
101 	return 0;
102 }
103 
104 static int bcm63xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
105 {
106 	return bcm63xx_gpio_set_direction(chip, gpio, GPIO_DIR_IN);
107 }
108 
109 static int bcm63xx_gpio_direction_output(struct gpio_chip *chip,
110 					 unsigned gpio, int value)
111 {
112 	bcm63xx_gpio_set(chip, gpio, value);
113 	return bcm63xx_gpio_set_direction(chip, gpio, GPIO_DIR_OUT);
114 }
115 
116 
117 static struct gpio_chip bcm63xx_gpio_chip = {
118 	.label			= "bcm63xx-gpio",
119 	.direction_input	= bcm63xx_gpio_direction_input,
120 	.direction_output	= bcm63xx_gpio_direction_output,
121 	.get			= bcm63xx_gpio_get,
122 	.set			= bcm63xx_gpio_set,
123 	.base			= 0,
124 };
125 
126 int __init bcm63xx_gpio_init(void)
127 {
128 	bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count();
129 	pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio);
130 
131 	return gpiochip_add(&bcm63xx_gpio_chip);
132 }
133 
134 arch_initcall(bcm63xx_gpio_init);
135