Merge tag 'reset-for-v5.3' of git://git.pengutronix.de/git/pza/linux into arm/drivers
[sfrench/cifs-2.6.git] / arch / powerpc / sysdev / simple_gpio.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Simple Memory-Mapped GPIOs
4  *
5  * Copyright (c) MontaVista Software, Inc. 2008.
6  *
7  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
8  */
9
10 #include <linux/init.h>
11 #include <linux/kernel.h>
12 #include <linux/spinlock.h>
13 #include <linux/types.h>
14 #include <linux/ioport.h>
15 #include <linux/io.h>
16 #include <linux/of.h>
17 #include <linux/of_gpio.h>
18 #include <linux/gpio/driver.h>
19 #include <linux/slab.h>
20 #include <asm/prom.h>
21 #include "simple_gpio.h"
22
23 struct u8_gpio_chip {
24         struct of_mm_gpio_chip mm_gc;
25         spinlock_t lock;
26
27         /* shadowed data register to clear/set bits safely */
28         u8 data;
29 };
30
31 static u8 u8_pin2mask(unsigned int pin)
32 {
33         return 1 << (8 - 1 - pin);
34 }
35
36 static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio)
37 {
38         struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
39
40         return !!(in_8(mm_gc->regs) & u8_pin2mask(gpio));
41 }
42
43 static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
44 {
45         struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
46         struct u8_gpio_chip *u8_gc = gpiochip_get_data(gc);
47         unsigned long flags;
48
49         spin_lock_irqsave(&u8_gc->lock, flags);
50
51         if (val)
52                 u8_gc->data |= u8_pin2mask(gpio);
53         else
54                 u8_gc->data &= ~u8_pin2mask(gpio);
55
56         out_8(mm_gc->regs, u8_gc->data);
57
58         spin_unlock_irqrestore(&u8_gc->lock, flags);
59 }
60
61 static int u8_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
62 {
63         return 0;
64 }
65
66 static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
67 {
68         u8_gpio_set(gc, gpio, val);
69         return 0;
70 }
71
72 static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
73 {
74         struct u8_gpio_chip *u8_gc =
75                 container_of(mm_gc, struct u8_gpio_chip, mm_gc);
76
77         u8_gc->data = in_8(mm_gc->regs);
78 }
79
80 static int __init u8_simple_gpiochip_add(struct device_node *np)
81 {
82         int ret;
83         struct u8_gpio_chip *u8_gc;
84         struct of_mm_gpio_chip *mm_gc;
85         struct gpio_chip *gc;
86
87         u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL);
88         if (!u8_gc)
89                 return -ENOMEM;
90
91         spin_lock_init(&u8_gc->lock);
92
93         mm_gc = &u8_gc->mm_gc;
94         gc = &mm_gc->gc;
95
96         mm_gc->save_regs = u8_gpio_save_regs;
97         gc->ngpio = 8;
98         gc->direction_input = u8_gpio_dir_in;
99         gc->direction_output = u8_gpio_dir_out;
100         gc->get = u8_gpio_get;
101         gc->set = u8_gpio_set;
102
103         ret = of_mm_gpiochip_add_data(np, mm_gc, u8_gc);
104         if (ret)
105                 goto err;
106         return 0;
107 err:
108         kfree(u8_gc);
109         return ret;
110 }
111
112 void __init simple_gpiochip_init(const char *compatible)
113 {
114         struct device_node *np;
115
116         for_each_compatible_node(np, NULL, compatible) {
117                 int ret;
118                 struct resource r;
119
120                 ret = of_address_to_resource(np, 0, &r);
121                 if (ret)
122                         goto err;
123
124                 switch (resource_size(&r)) {
125                 case 1:
126                         ret = u8_simple_gpiochip_add(np);
127                         if (ret)
128                                 goto err;
129                         break;
130                 default:
131                         /*
132                          * Whenever you need support for GPIO bank width > 1,
133                          * please just turn u8_ code into huge macros, and
134                          * construct needed uX_ code with it.
135                          */
136                         ret = -ENOSYS;
137                         goto err;
138                 }
139                 continue;
140 err:
141                 pr_err("%pOF: registration failed, status %d\n", np, ret);
142         }
143 }