Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpio/gpio-74x164.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
4
*
5
* Copyright (C) 2010 Gabor Juhos <[email protected]>
6
* Copyright (C) 2010 Miguel Gaio <[email protected]>
7
*/
8
9
#include <linux/bitops.h>
10
#include <linux/cleanup.h>
11
#include <linux/gpio/consumer.h>
12
#include <linux/gpio/driver.h>
13
#include <linux/module.h>
14
#include <linux/mutex.h>
15
#include <linux/property.h>
16
#include <linux/slab.h>
17
#include <linux/spi/spi.h>
18
19
#define GEN_74X164_NUMBER_GPIOS 8
20
21
struct gen_74x164_chip {
22
struct gpio_chip gpio_chip;
23
struct mutex lock;
24
struct gpio_desc *gpiod_oe;
25
u32 registers;
26
/*
27
* Since the registers are chained, every byte sent will make
28
* the previous byte shift to the next register in the
29
* chain. Thus, the first byte sent will end up in the last
30
* register at the end of the transfer. So, to have a logical
31
* numbering, store the bytes in reverse order.
32
*/
33
u8 buffer[] __counted_by(registers);
34
};
35
36
static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
37
{
38
return spi_write(to_spi_device(chip->gpio_chip.parent), chip->buffer,
39
chip->registers);
40
}
41
42
static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
43
{
44
struct gen_74x164_chip *chip = gpiochip_get_data(gc);
45
u8 bank = chip->registers - 1 - offset / 8;
46
u8 pin = offset % 8;
47
48
guard(mutex)(&chip->lock);
49
50
return !!(chip->buffer[bank] & BIT(pin));
51
}
52
53
static int gen_74x164_set_value(struct gpio_chip *gc,
54
unsigned int offset, int val)
55
{
56
struct gen_74x164_chip *chip = gpiochip_get_data(gc);
57
u8 bank = chip->registers - 1 - offset / 8;
58
u8 pin = offset % 8;
59
60
guard(mutex)(&chip->lock);
61
62
if (val)
63
chip->buffer[bank] |= BIT(pin);
64
else
65
chip->buffer[bank] &= ~BIT(pin);
66
67
return __gen_74x164_write_config(chip);
68
}
69
70
static int gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask,
71
unsigned long *bits)
72
{
73
struct gen_74x164_chip *chip = gpiochip_get_data(gc);
74
unsigned long offset;
75
unsigned long bankmask;
76
size_t bank;
77
unsigned long bitmask;
78
79
guard(mutex)(&chip->lock);
80
81
for_each_set_clump8(offset, bankmask, mask, chip->registers * 8) {
82
bank = chip->registers - 1 - offset / 8;
83
bitmask = bitmap_get_value8(bits, offset) & bankmask;
84
85
chip->buffer[bank] &= ~bankmask;
86
chip->buffer[bank] |= bitmask;
87
}
88
return __gen_74x164_write_config(chip);
89
}
90
91
static int gen_74x164_direction_output(struct gpio_chip *gc,
92
unsigned offset, int val)
93
{
94
gen_74x164_set_value(gc, offset, val);
95
return 0;
96
}
97
98
static void gen_74x164_deactivate(void *data)
99
{
100
struct gen_74x164_chip *chip = data;
101
102
gpiod_set_value_cansleep(chip->gpiod_oe, 0);
103
}
104
105
static int gen_74x164_activate(struct device *dev, struct gen_74x164_chip *chip)
106
{
107
gpiod_set_value_cansleep(chip->gpiod_oe, 1);
108
return devm_add_action_or_reset(dev, gen_74x164_deactivate, chip);
109
}
110
111
static int gen_74x164_probe(struct spi_device *spi)
112
{
113
struct device *dev = &spi->dev;
114
struct gen_74x164_chip *chip;
115
u32 nregs;
116
int ret;
117
118
/*
119
* bits_per_word cannot be configured in platform data
120
*/
121
spi->bits_per_word = 8;
122
123
ret = spi_setup(spi);
124
if (ret < 0)
125
return ret;
126
127
ret = device_property_read_u32(dev, "registers-number", &nregs);
128
if (ret)
129
return dev_err_probe(dev, ret, "Missing 'registers-number' property.\n");
130
131
chip = devm_kzalloc(dev, struct_size(chip, buffer, nregs), GFP_KERNEL);
132
if (!chip)
133
return -ENOMEM;
134
135
chip->registers = nregs;
136
137
chip->gpiod_oe = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
138
if (IS_ERR(chip->gpiod_oe))
139
return PTR_ERR(chip->gpiod_oe);
140
141
chip->gpio_chip.label = spi->modalias;
142
chip->gpio_chip.direction_output = gen_74x164_direction_output;
143
chip->gpio_chip.get = gen_74x164_get_value;
144
chip->gpio_chip.set = gen_74x164_set_value;
145
chip->gpio_chip.set_multiple = gen_74x164_set_multiple;
146
chip->gpio_chip.base = -1;
147
chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
148
chip->gpio_chip.can_sleep = true;
149
chip->gpio_chip.parent = dev;
150
chip->gpio_chip.owner = THIS_MODULE;
151
152
ret = devm_mutex_init(dev, &chip->lock);
153
if (ret)
154
return ret;
155
156
ret = __gen_74x164_write_config(chip);
157
if (ret)
158
return dev_err_probe(dev, ret, "Config write failed\n");
159
160
ret = gen_74x164_activate(dev, chip);
161
if (ret)
162
return ret;
163
164
return devm_gpiochip_add_data(dev, &chip->gpio_chip, chip);
165
}
166
167
static const struct spi_device_id gen_74x164_spi_ids[] = {
168
{ .name = "74hc595" },
169
{ .name = "74lvc594" },
170
{},
171
};
172
MODULE_DEVICE_TABLE(spi, gen_74x164_spi_ids);
173
174
static const struct of_device_id gen_74x164_dt_ids[] = {
175
{ .compatible = "fairchild,74hc595" },
176
{ .compatible = "nxp,74lvc594" },
177
{},
178
};
179
MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids);
180
181
static struct spi_driver gen_74x164_driver = {
182
.driver = {
183
.name = "74x164",
184
.of_match_table = gen_74x164_dt_ids,
185
},
186
.probe = gen_74x164_probe,
187
.id_table = gen_74x164_spi_ids,
188
};
189
module_spi_driver(gen_74x164_driver);
190
191
MODULE_AUTHOR("Gabor Juhos <[email protected]>");
192
MODULE_AUTHOR("Miguel Gaio <[email protected]>");
193
MODULE_DESCRIPTION("GPIO expander driver for 74X164 8-bits shift register");
194
MODULE_LICENSE("GPL v2");
195
196