2 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
3 * Andrew F. Davis <afd@ti.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
10 * kind, whether expressed or implied; without even the implied warranty
11 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License version 2 for more details.
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/gpio/driver.h>
18 #include <linux/module.h>
19 #include <linux/mutex.h>
20 #include <linux/spi/spi.h>
22 #define DEFAULT_NGPIO 8
25 * struct pisosr_gpio - GPIO driver data
26 * @chip: GPIO controller chip
27 * @spi: SPI device pointer
28 * @buffer: Buffer for device reads
29 * @buffer_size: Size of buffer
30 * @load_gpio: GPIO pin used to load input into device
31 * @lock: Protects read sequences
34 struct gpio_chip chip
;
35 struct spi_device
*spi
;
38 struct gpio_desc
*load_gpio
;
42 static int pisosr_gpio_refresh(struct pisosr_gpio
*gpio
)
46 mutex_lock(&gpio
->lock
);
48 if (gpio
->load_gpio
) {
49 gpiod_set_value_cansleep(gpio
->load_gpio
, 1);
50 udelay(1); /* registers load time (~10ns) */
51 gpiod_set_value_cansleep(gpio
->load_gpio
, 0);
52 udelay(1); /* registers recovery time (~5ns) */
55 ret
= spi_read(gpio
->spi
, gpio
->buffer
, gpio
->buffer_size
);
57 mutex_unlock(&gpio
->lock
);
62 static int pisosr_gpio_get_direction(struct gpio_chip
*chip
,
65 /* This device always input */
69 static int pisosr_gpio_direction_input(struct gpio_chip
*chip
,
72 /* This device always input */
76 static int pisosr_gpio_direction_output(struct gpio_chip
*chip
,
77 unsigned offset
, int value
)
79 /* This device is input only */
83 static int pisosr_gpio_get(struct gpio_chip
*chip
, unsigned offset
)
85 struct pisosr_gpio
*gpio
= gpiochip_get_data(chip
);
87 /* Refresh may not always be needed */
88 pisosr_gpio_refresh(gpio
);
90 return (gpio
->buffer
[offset
/ 8] >> (offset
% 8)) & 0x1;
93 static const struct gpio_chip template_chip
= {
94 .label
= "pisosr-gpio",
96 .get_direction
= pisosr_gpio_get_direction
,
97 .direction_input
= pisosr_gpio_direction_input
,
98 .direction_output
= pisosr_gpio_direction_output
,
99 .get
= pisosr_gpio_get
,
101 .ngpio
= DEFAULT_NGPIO
,
105 static int pisosr_gpio_probe(struct spi_device
*spi
)
107 struct device
*dev
= &spi
->dev
;
108 struct pisosr_gpio
*gpio
;
111 gpio
= devm_kzalloc(dev
, sizeof(*gpio
), GFP_KERNEL
);
115 spi_set_drvdata(spi
, gpio
);
117 gpio
->chip
= template_chip
;
118 gpio
->chip
.parent
= dev
;
119 of_property_read_u16(dev
->of_node
, "ngpios", &gpio
->chip
.ngpio
);
123 gpio
->buffer_size
= DIV_ROUND_UP(gpio
->chip
.ngpio
, 8);
124 gpio
->buffer
= devm_kzalloc(dev
, gpio
->buffer_size
, GFP_KERNEL
);
128 gpio
->load_gpio
= devm_gpiod_get_optional(dev
, "load", GPIOD_OUT_LOW
);
129 if (IS_ERR(gpio
->load_gpio
)) {
130 ret
= PTR_ERR(gpio
->load_gpio
);
131 if (ret
!= -EPROBE_DEFER
)
132 dev_err(dev
, "Unable to allocate load GPIO\n");
136 mutex_init(&gpio
->lock
);
138 ret
= gpiochip_add_data(&gpio
->chip
, gpio
);
140 dev_err(dev
, "Unable to register gpiochip\n");
147 static int pisosr_gpio_remove(struct spi_device
*spi
)
149 struct pisosr_gpio
*gpio
= spi_get_drvdata(spi
);
151 gpiochip_remove(&gpio
->chip
);
153 mutex_destroy(&gpio
->lock
);
158 static const struct spi_device_id pisosr_gpio_id_table
[] = {
162 MODULE_DEVICE_TABLE(spi
, pisosr_gpio_id_table
);
164 static const struct of_device_id pisosr_gpio_of_match_table
[] = {
165 { .compatible
= "pisosr-gpio", },
168 MODULE_DEVICE_TABLE(of
, pisosr_gpio_of_match_table
);
170 static struct spi_driver pisosr_gpio_driver
= {
172 .name
= "pisosr-gpio",
173 .of_match_table
= pisosr_gpio_of_match_table
,
175 .probe
= pisosr_gpio_probe
,
176 .remove
= pisosr_gpio_remove
,
177 .id_table
= pisosr_gpio_id_table
,
179 module_spi_driver(pisosr_gpio_driver
);
181 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
182 MODULE_DESCRIPTION("SPI Compatible PISO Shift Register GPIO Driver");
183 MODULE_LICENSE("GPL v2");