Merge tag 'arm-soc-fixes-5.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[platform/kernel/linux-starfive.git] / drivers / gpio / gpio-max730x.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /**
3  * Copyright (C) 2006 Juergen Beisert, Pengutronix
4  * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix
5  * Copyright (C) 2009 Wolfram Sang, Pengutronix
6  *
7  * The Maxim MAX7300/1 device is an I2C/SPI driven GPIO expander. There are
8  * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more
9  * details
10  * Note:
11  * - DIN must be stable at the rising edge of clock.
12  * - when writing:
13  *   - always clock in 16 clocks at once
14  *   - at DIN: D15 first, D0 last
15  *   - D0..D7 = databyte, D8..D14 = commandbyte
16  *   - D15 = low -> write command
17  * - when reading
18  *   - always clock in 16 clocks at once
19  *   - at DIN: D15 first, D0 last
20  *   - D0..D7 = dummy, D8..D14 = register address
21  *   - D15 = high -> read command
22  *   - raise CS and assert it again
23  *   - always clock in 16 clocks at once
24  *   - at DOUT: D15 first, D0 last
25  *   - D0..D7 contains the data from the first cycle
26  *
27  * The driver exports a standard gpiochip interface
28  */
29
30 #include <linux/module.h>
31 #include <linux/init.h>
32 #include <linux/platform_device.h>
33 #include <linux/mutex.h>
34 #include <linux/spi/max7301.h>
35 #include <linux/gpio/driver.h>
36 #include <linux/slab.h>
37
38 /*
39  * Pin configurations, see MAX7301 datasheet page 6
40  */
41 #define PIN_CONFIG_MASK 0x03
42 #define PIN_CONFIG_IN_PULLUP 0x03
43 #define PIN_CONFIG_IN_WO_PULLUP 0x02
44 #define PIN_CONFIG_OUT 0x01
45
46 #define PIN_NUMBER 28
47
48 static int max7301_direction_input(struct gpio_chip *chip, unsigned offset)
49 {
50         struct max7301 *ts = container_of(chip, struct max7301, chip);
51         u8 *config;
52         u8 offset_bits, pin_config;
53         int ret;
54
55         /* First 4 pins are unused in the controller */
56         offset += 4;
57         offset_bits = (offset & 3) << 1;
58
59         config = &ts->port_config[offset >> 2];
60
61         if (ts->input_pullup_active & BIT(offset))
62                 pin_config = PIN_CONFIG_IN_PULLUP;
63         else
64                 pin_config = PIN_CONFIG_IN_WO_PULLUP;
65
66         mutex_lock(&ts->lock);
67
68         *config = (*config & ~(PIN_CONFIG_MASK << offset_bits))
69                            | (pin_config << offset_bits);
70
71         ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config);
72
73         mutex_unlock(&ts->lock);
74
75         return ret;
76 }
77
78 static int __max7301_set(struct max7301 *ts, unsigned offset, int value)
79 {
80         if (value) {
81                 ts->out_level |= 1 << offset;
82                 return ts->write(ts->dev, 0x20 + offset, 0x01);
83         } else {
84                 ts->out_level &= ~(1 << offset);
85                 return ts->write(ts->dev, 0x20 + offset, 0x00);
86         }
87 }
88
89 static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,
90                                     int value)
91 {
92         struct max7301 *ts = container_of(chip, struct max7301, chip);
93         u8 *config;
94         u8 offset_bits;
95         int ret;
96
97         /* First 4 pins are unused in the controller */
98         offset += 4;
99         offset_bits = (offset & 3) << 1;
100
101         config = &ts->port_config[offset >> 2];
102
103         mutex_lock(&ts->lock);
104
105         *config = (*config & ~(PIN_CONFIG_MASK << offset_bits))
106                            | (PIN_CONFIG_OUT << offset_bits);
107
108         ret = __max7301_set(ts, offset, value);
109
110         if (!ret)
111                 ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config);
112
113         mutex_unlock(&ts->lock);
114
115         return ret;
116 }
117
118 static int max7301_get(struct gpio_chip *chip, unsigned offset)
119 {
120         struct max7301 *ts = gpiochip_get_data(chip);
121         int config, level = -EINVAL;
122
123         /* First 4 pins are unused in the controller */
124         offset += 4;
125
126         mutex_lock(&ts->lock);
127
128         config = (ts->port_config[offset >> 2] >> ((offset & 3) << 1))
129                         & PIN_CONFIG_MASK;
130
131         switch (config) {
132         case PIN_CONFIG_OUT:
133                 /* Output: return cached level */
134                 level =  !!(ts->out_level & (1 << offset));
135                 break;
136         case PIN_CONFIG_IN_WO_PULLUP:
137         case PIN_CONFIG_IN_PULLUP:
138                 /* Input: read out */
139                 level = ts->read(ts->dev, 0x20 + offset) & 0x01;
140         }
141         mutex_unlock(&ts->lock);
142
143         return level;
144 }
145
146 static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
147 {
148         struct max7301 *ts = gpiochip_get_data(chip);
149
150         /* First 4 pins are unused in the controller */
151         offset += 4;
152
153         mutex_lock(&ts->lock);
154
155         __max7301_set(ts, offset, value);
156
157         mutex_unlock(&ts->lock);
158 }
159
160 int __max730x_probe(struct max7301 *ts)
161 {
162         struct device *dev = ts->dev;
163         struct max7301_platform_data *pdata;
164         int i, ret;
165
166         pdata = dev_get_platdata(dev);
167
168         mutex_init(&ts->lock);
169         dev_set_drvdata(dev, ts);
170
171         /* Power up the chip and disable IRQ output */
172         ts->write(dev, 0x04, 0x01);
173
174         if (pdata) {
175                 ts->input_pullup_active = pdata->input_pullup_active;
176                 ts->chip.base = pdata->base;
177         } else {
178                 ts->chip.base = -1;
179         }
180         ts->chip.label = dev->driver->name;
181
182         ts->chip.direction_input = max7301_direction_input;
183         ts->chip.get = max7301_get;
184         ts->chip.direction_output = max7301_direction_output;
185         ts->chip.set = max7301_set;
186
187         ts->chip.ngpio = PIN_NUMBER;
188         ts->chip.can_sleep = true;
189         ts->chip.parent = dev;
190         ts->chip.owner = THIS_MODULE;
191
192         /*
193          * initialize pullups according to platform data and cache the
194          * register values for later use.
195          */
196         for (i = 1; i < 8; i++) {
197                 int j;
198                 /*
199                  * initialize port_config with "0xAA", which means
200                  * input with internal pullup disabled. This is needed
201                  * to avoid writing zeros (in the inner for loop),
202                  * which is not allowed according to the datasheet.
203                  */
204                 ts->port_config[i] = 0xAA;
205                 for (j = 0; j < 4; j++) {
206                         int offset = (i - 1) * 4 + j;
207                         ret = max7301_direction_input(&ts->chip, offset);
208                         if (ret)
209                                 goto exit_destroy;
210                 }
211         }
212
213         ret = gpiochip_add_data(&ts->chip, ts);
214         if (!ret)
215                 return ret;
216
217 exit_destroy:
218         mutex_destroy(&ts->lock);
219         return ret;
220 }
221 EXPORT_SYMBOL_GPL(__max730x_probe);
222
223 int __max730x_remove(struct device *dev)
224 {
225         struct max7301 *ts = dev_get_drvdata(dev);
226
227         if (ts == NULL)
228                 return -ENODEV;
229
230         /* Power down the chip and disable IRQ output */
231         ts->write(dev, 0x04, 0x00);
232         gpiochip_remove(&ts->chip);
233         mutex_destroy(&ts->lock);
234         return 0;
235 }
236 EXPORT_SYMBOL_GPL(__max730x_remove);
237
238 MODULE_AUTHOR("Juergen Beisert, Wolfram Sang");
239 MODULE_LICENSE("GPL v2");
240 MODULE_DESCRIPTION("MAX730x GPIO-Expanders, generic parts");