Merge tag 'for-5.15/parisc' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[linux-2.6-microblaze.git] / arch / mips / bcm63xx / gpio.c
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-2011 Florian Fainelli <florian@openwrt.org>
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/spinlock.h>
13 #include <linux/platform_device.h>
14 #include <linux/gpio/driver.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 u32 gpio_out_low_reg;
22
23 static void bcm63xx_gpio_out_low_reg_init(void)
24 {
25         switch (bcm63xx_get_cpu_id()) {
26         case BCM6345_CPU_ID:
27                 gpio_out_low_reg = GPIO_DATA_LO_REG_6345;
28                 break;
29         default:
30                 gpio_out_low_reg = GPIO_DATA_LO_REG;
31                 break;
32         }
33 }
34
35 static DEFINE_SPINLOCK(bcm63xx_gpio_lock);
36 static u32 gpio_out_low, gpio_out_high;
37
38 static void bcm63xx_gpio_set(struct gpio_chip *chip,
39                              unsigned gpio, int val)
40 {
41         u32 reg;
42         u32 mask;
43         u32 *v;
44         unsigned long flags;
45
46         BUG_ON(gpio >= chip->ngpio);
47
48         if (gpio < 32) {
49                 reg = gpio_out_low_reg;
50                 mask = 1 << gpio;
51                 v = &gpio_out_low;
52         } else {
53                 reg = GPIO_DATA_HI_REG;
54                 mask = 1 << (gpio - 32);
55                 v = &gpio_out_high;
56         }
57
58         spin_lock_irqsave(&bcm63xx_gpio_lock, flags);
59         if (val)
60                 *v |= mask;
61         else
62                 *v &= ~mask;
63         bcm_gpio_writel(*v, reg);
64         spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags);
65 }
66
67 static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio)
68 {
69         u32 reg;
70         u32 mask;
71
72         BUG_ON(gpio >= chip->ngpio);
73
74         if (gpio < 32) {
75                 reg = gpio_out_low_reg;
76                 mask = 1 << gpio;
77         } else {
78                 reg = GPIO_DATA_HI_REG;
79                 mask = 1 << (gpio - 32);
80         }
81
82         return !!(bcm_gpio_readl(reg) & mask);
83 }
84
85 static int bcm63xx_gpio_set_direction(struct gpio_chip *chip,
86                                       unsigned gpio, int dir)
87 {
88         u32 reg;
89         u32 mask;
90         u32 tmp;
91         unsigned long flags;
92
93         BUG_ON(gpio >= chip->ngpio);
94
95         if (gpio < 32) {
96                 reg = GPIO_CTL_LO_REG;
97                 mask = 1 << gpio;
98         } else {
99                 reg = GPIO_CTL_HI_REG;
100                 mask = 1 << (gpio - 32);
101         }
102
103         spin_lock_irqsave(&bcm63xx_gpio_lock, flags);
104         tmp = bcm_gpio_readl(reg);
105         if (dir == BCM63XX_GPIO_DIR_IN)
106                 tmp &= ~mask;
107         else
108                 tmp |= mask;
109         bcm_gpio_writel(tmp, reg);
110         spin_unlock_irqrestore(&bcm63xx_gpio_lock, flags);
111
112         return 0;
113 }
114
115 static int bcm63xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
116 {
117         return bcm63xx_gpio_set_direction(chip, gpio, BCM63XX_GPIO_DIR_IN);
118 }
119
120 static int bcm63xx_gpio_direction_output(struct gpio_chip *chip,
121                                          unsigned gpio, int value)
122 {
123         bcm63xx_gpio_set(chip, gpio, value);
124         return bcm63xx_gpio_set_direction(chip, gpio, BCM63XX_GPIO_DIR_OUT);
125 }
126
127
128 static struct gpio_chip bcm63xx_gpio_chip = {
129         .label                  = "bcm63xx-gpio",
130         .direction_input        = bcm63xx_gpio_direction_input,
131         .direction_output       = bcm63xx_gpio_direction_output,
132         .get                    = bcm63xx_gpio_get,
133         .set                    = bcm63xx_gpio_set,
134         .base                   = 0,
135 };
136
137 int __init bcm63xx_gpio_init(void)
138 {
139         bcm63xx_gpio_out_low_reg_init();
140
141         gpio_out_low = bcm_gpio_readl(gpio_out_low_reg);
142         if (!BCMCPU_IS_6345())
143                 gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG);
144         bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count();
145         pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio);
146
147         return gpiochip_add_data(&bcm63xx_gpio_chip, NULL);
148 }