Skip to content

Commit 0c36ec3

Browse files
Juergen Beiserttorvalds
authored andcommitted
gpio: gpio driver for max7301 SPI GPIO expander
Maxim's MAX7301 is an SPI GPIO expander with 28 GPIOs. Note: MAX7301's interrupt feature is not supported yet. [akpm@linux-foundation.org: coding-style fixes] [g.liakhovetski@pengutronix.de: Fix inaccuracies in comments, check spi_setup() return code, mask off high byte in max7301_read()] Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 6519108 commit 0c36ec3

File tree

4 files changed

+355
-0
lines changed

4 files changed

+355
-0
lines changed

drivers/gpio/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ config GPIO_PCF857X
6969

7070
comment "SPI GPIO expanders:"
7171

72+
config GPIO_MAX7301
73+
tristate "Maxim MAX7301 GPIO expander"
74+
depends on SPI_MASTER
75+
help
76+
gpio driver for Maxim MAX7301 SPI GPIO expander.
77+
7278
config GPIO_MCP23S08
7379
tristate "Microchip MCP23S08 I/O expander"
7480
depends on SPI_MASTER

drivers/gpio/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
44

55
obj-$(CONFIG_HAVE_GPIO_LIB) += gpiolib.o
66

7+
obj-$(CONFIG_GPIO_MAX7301) += max7301.o
78
obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
89
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
910
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o

drivers/gpio/max7301.c

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
/**
2+
* drivers/gpio/max7301.c
3+
*
4+
* Copyright (C) 2006 Juergen Beisert, Pengutronix
5+
* Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License version 2 as
9+
* published by the Free Software Foundation.
10+
*
11+
* The Maxim's MAX7301 device is an SPI driven GPIO expander. There are
12+
* 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more
13+
* details
14+
* Note:
15+
* - DIN must be stable at the rising edge of clock.
16+
* - when writing:
17+
* - always clock in 16 clocks at once
18+
* - at DIN: D15 first, D0 last
19+
* - D0..D7 = databyte, D8..D14 = commandbyte
20+
* - D15 = low -> write command
21+
* - when reading
22+
* - always clock in 16 clocks at once
23+
* - at DIN: D15 first, D0 last
24+
* - D0..D7 = dummy, D8..D14 = register address
25+
* - D15 = high -> read command
26+
* - raise CS and assert it again
27+
* - always clock in 16 clocks at once
28+
* - at DOUT: D15 first, D0 last
29+
* - D0..D7 contains the data from the first cycle
30+
*
31+
* The driver exports a standard gpiochip interface
32+
*/
33+
34+
#include <linux/init.h>
35+
#include <linux/platform_device.h>
36+
#include <linux/mutex.h>
37+
#include <linux/spi/spi.h>
38+
#include <linux/spi/max7301.h>
39+
#include <linux/gpio.h>
40+
41+
#define DRIVER_NAME "max7301"
42+
43+
/*
44+
* Pin configurations, see MAX7301 datasheet page 6
45+
*/
46+
#define PIN_CONFIG_MASK 0x03
47+
#define PIN_CONFIG_IN_PULLUP 0x03
48+
#define PIN_CONFIG_IN_WO_PULLUP 0x02
49+
#define PIN_CONFIG_OUT 0x01
50+
51+
#define PIN_NUMBER 28
52+
53+
54+
/*
55+
* Some registers must be read back to modify.
56+
* To save time we cache them here in memory
57+
*/
58+
struct max7301 {
59+
struct mutex lock;
60+
u8 port_config[8]; /* field 0 is unused */
61+
u32 out_level; /* cached output levels */
62+
struct gpio_chip chip;
63+
struct spi_device *spi;
64+
};
65+
66+
/**
67+
* max7301_write - Write a new register content
68+
* @spi: The SPI device
69+
* @reg: Register offset
70+
* @val: Value to write
71+
*
72+
* A write to the MAX7301 means one message with one transfer
73+
*
74+
* Returns 0 if successful or a negative value on error
75+
*/
76+
static int max7301_write(struct spi_device *spi, unsigned int reg, unsigned int val)
77+
{
78+
u16 word = ((reg & 0x7F) << 8) | (val & 0xFF);
79+
return spi_write(spi, (const u8 *)&word, sizeof(word));
80+
}
81+
82+
/**
83+
* max7301_read - Read back register content
84+
* @spi: The SPI device
85+
* @reg: Register offset
86+
*
87+
* A read from the MAX7301 means two transfers; here, one message each
88+
*
89+
* Returns positive 8 bit value from device if successful or a
90+
* negative value on error
91+
*/
92+
static int max7301_read(struct spi_device *spi, unsigned int reg)
93+
{
94+
int ret;
95+
u16 word;
96+
97+
word = 0x8000 | (reg << 8);
98+
ret = spi_write(spi, (const u8 *)&word, sizeof(word));
99+
if (ret)
100+
return ret;
101+
/*
102+
* This relies on the fact, that a transfer with NULL tx_buf shifts out
103+
* zero bytes (=NOOP for MAX7301)
104+
*/
105+
ret = spi_read(spi, (u8 *)&word, sizeof(word));
106+
if (ret)
107+
return ret;
108+
return word & 0xff;
109+
}
110+
111+
static int max7301_direction_input(struct gpio_chip *chip, unsigned offset)
112+
{
113+
struct max7301 *ts = container_of(chip, struct max7301, chip);
114+
u8 *config;
115+
int ret;
116+
117+
/* First 4 pins are unused in the controller */
118+
offset += 4;
119+
120+
config = &ts->port_config[offset >> 2];
121+
122+
mutex_lock(&ts->lock);
123+
124+
/* Standard GPIO API doesn't support pull-ups, has to be extended.
125+
* Hard-coding no pollup for now. */
126+
*config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3));
127+
128+
ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config);
129+
130+
mutex_unlock(&ts->lock);
131+
132+
return ret;
133+
}
134+
135+
static int __max7301_set(struct max7301 *ts, unsigned offset, int value)
136+
{
137+
if (value) {
138+
ts->out_level |= 1 << offset;
139+
return max7301_write(ts->spi, 0x20 + offset, 0x01);
140+
} else {
141+
ts->out_level &= ~(1 << offset);
142+
return max7301_write(ts->spi, 0x20 + offset, 0x00);
143+
}
144+
}
145+
146+
static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,
147+
int value)
148+
{
149+
struct max7301 *ts = container_of(chip, struct max7301, chip);
150+
u8 *config;
151+
int ret;
152+
153+
/* First 4 pins are unused in the controller */
154+
offset += 4;
155+
156+
config = &ts->port_config[offset >> 2];
157+
158+
mutex_lock(&ts->lock);
159+
160+
*config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3));
161+
162+
ret = __max7301_set(ts, offset, value);
163+
164+
if (!ret)
165+
ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config);
166+
167+
mutex_unlock(&ts->lock);
168+
169+
return ret;
170+
}
171+
172+
static int max7301_get(struct gpio_chip *chip, unsigned offset)
173+
{
174+
struct max7301 *ts = container_of(chip, struct max7301, chip);
175+
int config, level = -EINVAL;
176+
177+
/* First 4 pins are unused in the controller */
178+
offset += 4;
179+
180+
mutex_lock(&ts->lock);
181+
182+
config = (ts->port_config[offset >> 2] >> ((offset & 3) * 2)) & 3;
183+
184+
switch (config) {
185+
case 1:
186+
/* Output: return cached level */
187+
level = !!(ts->out_level & (1 << offset));
188+
break;
189+
case 2:
190+
case 3:
191+
/* Input: read out */
192+
level = max7301_read(ts->spi, 0x20 + offset) & 0x01;
193+
}
194+
mutex_unlock(&ts->lock);
195+
196+
return level;
197+
}
198+
199+
static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
200+
{
201+
struct max7301 *ts = container_of(chip, struct max7301, chip);
202+
203+
/* First 4 pins are unused in the controller */
204+
offset += 4;
205+
206+
mutex_lock(&ts->lock);
207+
208+
__max7301_set(ts, offset, value);
209+
210+
mutex_unlock(&ts->lock);
211+
}
212+
213+
static int __devinit max7301_probe(struct spi_device *spi)
214+
{
215+
struct max7301 *ts;
216+
struct max7301_platform_data *pdata;
217+
int i, ret;
218+
219+
pdata = spi->dev.platform_data;
220+
if (!pdata || !pdata->base)
221+
return -ENODEV;
222+
223+
/*
224+
* bits_per_word cannot be configured in platform data
225+
*/
226+
spi->bits_per_word = 16;
227+
228+
ret = spi_setup(spi);
229+
if (ret < 0)
230+
return ret;
231+
232+
ts = kzalloc(sizeof(struct max7301), GFP_KERNEL);
233+
if (!ts)
234+
return -ENOMEM;
235+
236+
mutex_init(&ts->lock);
237+
238+
dev_set_drvdata(&spi->dev, ts);
239+
240+
/* Power up the chip and disable IRQ output */
241+
max7301_write(spi, 0x04, 0x01);
242+
243+
ts->spi = spi;
244+
245+
ts->chip.label = DRIVER_NAME,
246+
247+
ts->chip.direction_input = max7301_direction_input;
248+
ts->chip.get = max7301_get;
249+
ts->chip.direction_output = max7301_direction_output;
250+
ts->chip.set = max7301_set;
251+
252+
ts->chip.base = pdata->base;
253+
ts->chip.ngpio = PIN_NUMBER;
254+
ts->chip.can_sleep = 1;
255+
ts->chip.dev = &spi->dev;
256+
ts->chip.owner = THIS_MODULE;
257+
258+
ret = gpiochip_add(&ts->chip);
259+
if (ret)
260+
goto exit_destroy;
261+
262+
/*
263+
* tristate all pins in hardware and cache the
264+
* register values for later use.
265+
*/
266+
for (i = 1; i < 8; i++) {
267+
int j;
268+
/* 0xAA means input with internal pullup disabled */
269+
max7301_write(spi, 0x08 + i, 0xAA);
270+
ts->port_config[i] = 0xAA;
271+
for (j = 0; j < 4; j++) {
272+
int idx = ts->chip.base + (i - 1) * 4 + j;
273+
ret = gpio_direction_input(idx);
274+
if (ret)
275+
goto exit_remove;
276+
gpio_free(idx);
277+
}
278+
}
279+
return ret;
280+
281+
exit_remove:
282+
gpiochip_remove(&ts->chip);
283+
exit_destroy:
284+
dev_set_drvdata(&spi->dev, NULL);
285+
mutex_destroy(&ts->lock);
286+
kfree(ts);
287+
return ret;
288+
}
289+
290+
static int max7301_remove(struct spi_device *spi)
291+
{
292+
struct max7301 *ts;
293+
int ret;
294+
295+
ts = dev_get_drvdata(&spi->dev);
296+
if (ts == NULL)
297+
return -ENODEV;
298+
299+
dev_set_drvdata(&spi->dev, NULL);
300+
301+
/* Power down the chip and disable IRQ output */
302+
max7301_write(spi, 0x04, 0x00);
303+
304+
ret = gpiochip_remove(&ts->chip);
305+
if (!ret) {
306+
mutex_destroy(&ts->lock);
307+
kfree(ts);
308+
} else
309+
dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
310+
ret);
311+
312+
return ret;
313+
}
314+
315+
static struct spi_driver max7301_driver = {
316+
.driver = {
317+
.name = DRIVER_NAME,
318+
.owner = THIS_MODULE,
319+
},
320+
.probe = max7301_probe,
321+
.remove = __devexit_p(max7301_remove),
322+
};
323+
324+
static int __init max7301_init(void)
325+
{
326+
return spi_register_driver(&max7301_driver);
327+
}
328+
329+
static void __exit max7301_exit(void)
330+
{
331+
spi_unregister_driver(&max7301_driver);
332+
}
333+
334+
module_init(max7301_init);
335+
module_exit(max7301_exit);
336+
337+
MODULE_AUTHOR("Juergen Beisert");
338+
MODULE_LICENSE("GPL v2");
339+
MODULE_DESCRIPTION("MAX7301 SPI based GPIO-Expander");

include/linux/spi/max7301.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef LINUX_SPI_MAX7301_H
2+
#define LINUX_SPI_MAX7301_H
3+
4+
struct max7301_platform_data {
5+
/* number assigned to the first GPIO */
6+
unsigned base;
7+
};
8+
9+
#endif

0 commit comments

Comments
 (0)