1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * GPIO latch driver |
4 | * |
5 | * Copyright (C) 2022 Sascha Hauer <s.hauer@pengutronix.de> |
6 | * |
7 | * This driver implements a GPIO (or better GPO as there is no input) |
8 | * multiplexer based on latches like this: |
9 | * |
10 | * CLK0 ----------------------. ,--------. |
11 | * CLK1 -------------------. `--------|> #0 | |
12 | * | | | |
13 | * OUT0 ----------------+--|-----------|D0 Q0|-----|< |
14 | * OUT1 --------------+-|--|-----------|D1 Q1|-----|< |
15 | * OUT2 ------------+-|-|--|-----------|D2 Q2|-----|< |
16 | * OUT3 ----------+-|-|-|--|-----------|D3 Q3|-----|< |
17 | * OUT4 --------+-|-|-|-|--|-----------|D4 Q4|-----|< |
18 | * OUT5 ------+-|-|-|-|-|--|-----------|D5 Q5|-----|< |
19 | * OUT6 ----+-|-|-|-|-|-|--|-----------|D6 Q6|-----|< |
20 | * OUT7 --+-|-|-|-|-|-|-|--|-----------|D7 Q7|-----|< |
21 | * | | | | | | | | | `--------' |
22 | * | | | | | | | | | |
23 | * | | | | | | | | | ,--------. |
24 | * | | | | | | | | `-----------|> #1 | |
25 | * | | | | | | | | | | |
26 | * | | | | | | | `--------------|D0 Q0|-----|< |
27 | * | | | | | | `----------------|D1 Q1|-----|< |
28 | * | | | | | `------------------|D2 Q2|-----|< |
29 | * | | | | `--------------------|D3 Q3|-----|< |
30 | * | | | `----------------------|D4 Q4|-----|< |
31 | * | | `------------------------|D5 Q5|-----|< |
32 | * | `--------------------------|D6 Q6|-----|< |
33 | * `----------------------------|D7 Q7|-----|< |
34 | * `--------' |
35 | * |
36 | * The above is just an example. The actual number of number of latches and |
37 | * the number of inputs per latch is derived from the number of GPIOs given |
38 | * in the corresponding device tree properties. |
39 | */ |
40 | |
41 | #include <linux/err.h> |
42 | #include <linux/gpio/consumer.h> |
43 | #include <linux/gpio/driver.h> |
44 | #include <linux/module.h> |
45 | #include <linux/mod_devicetable.h> |
46 | #include <linux/platform_device.h> |
47 | #include <linux/delay.h> |
48 | |
49 | #include "gpiolib.h" |
50 | |
51 | struct gpio_latch_priv { |
52 | struct gpio_chip gc; |
53 | struct gpio_descs *clk_gpios; |
54 | struct gpio_descs *latched_gpios; |
55 | int n_latched_gpios; |
56 | unsigned int setup_duration_ns; |
57 | unsigned int clock_duration_ns; |
58 | unsigned long *shadow; |
59 | /* |
60 | * Depending on whether any of the underlying GPIOs may sleep we either |
61 | * use a mutex or a spinlock to protect our shadow map. |
62 | */ |
63 | union { |
64 | struct mutex mutex; /* protects @shadow */ |
65 | spinlock_t spinlock; /* protects @shadow */ |
66 | }; |
67 | }; |
68 | |
69 | static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset) |
70 | { |
71 | return GPIO_LINE_DIRECTION_OUT; |
72 | } |
73 | |
74 | static void gpio_latch_set_unlocked(struct gpio_latch_priv *priv, |
75 | void (*set)(struct gpio_desc *desc, int value), |
76 | unsigned int offset, bool val) |
77 | { |
78 | int latch = offset / priv->n_latched_gpios; |
79 | int i; |
80 | |
81 | assign_bit(nr: offset, addr: priv->shadow, value: val); |
82 | |
83 | for (i = 0; i < priv->n_latched_gpios; i++) |
84 | set(priv->latched_gpios->desc[i], |
85 | test_bit(latch * priv->n_latched_gpios + i, priv->shadow)); |
86 | |
87 | ndelay(priv->setup_duration_ns); |
88 | set(priv->clk_gpios->desc[latch], 1); |
89 | ndelay(priv->clock_duration_ns); |
90 | set(priv->clk_gpios->desc[latch], 0); |
91 | } |
92 | |
93 | static void gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val) |
94 | { |
95 | struct gpio_latch_priv *priv = gpiochip_get_data(gc); |
96 | unsigned long flags; |
97 | |
98 | spin_lock_irqsave(&priv->spinlock, flags); |
99 | |
100 | gpio_latch_set_unlocked(priv, set: gpiod_set_value, offset, val); |
101 | |
102 | spin_unlock_irqrestore(lock: &priv->spinlock, flags); |
103 | } |
104 | |
105 | static void gpio_latch_set_can_sleep(struct gpio_chip *gc, unsigned int offset, int val) |
106 | { |
107 | struct gpio_latch_priv *priv = gpiochip_get_data(gc); |
108 | |
109 | mutex_lock(&priv->mutex); |
110 | |
111 | gpio_latch_set_unlocked(priv, set: gpiod_set_value_cansleep, offset, val); |
112 | |
113 | mutex_unlock(lock: &priv->mutex); |
114 | } |
115 | |
116 | static bool gpio_latch_can_sleep(struct gpio_latch_priv *priv, unsigned int n_latches) |
117 | { |
118 | int i; |
119 | |
120 | for (i = 0; i < n_latches; i++) |
121 | if (gpiod_cansleep(desc: priv->clk_gpios->desc[i])) |
122 | return true; |
123 | |
124 | for (i = 0; i < priv->n_latched_gpios; i++) |
125 | if (gpiod_cansleep(desc: priv->latched_gpios->desc[i])) |
126 | return true; |
127 | |
128 | return false; |
129 | } |
130 | |
131 | /* |
132 | * Some value which is still acceptable to delay in atomic context. |
133 | * If we need to go higher we might have to switch to usleep_range(), |
134 | * but that cannot ne used in atomic context and the driver would have |
135 | * to be adjusted to support that. |
136 | */ |
137 | #define DURATION_NS_MAX 5000 |
138 | |
139 | static int gpio_latch_probe(struct platform_device *pdev) |
140 | { |
141 | struct gpio_latch_priv *priv; |
142 | unsigned int n_latches; |
143 | struct device_node *np = pdev->dev.of_node; |
144 | |
145 | priv = devm_kzalloc(dev: &pdev->dev, size: sizeof(*priv), GFP_KERNEL); |
146 | if (!priv) |
147 | return -ENOMEM; |
148 | |
149 | priv->clk_gpios = devm_gpiod_get_array(dev: &pdev->dev, con_id: "clk" , flags: GPIOD_OUT_LOW); |
150 | if (IS_ERR(ptr: priv->clk_gpios)) |
151 | return PTR_ERR(ptr: priv->clk_gpios); |
152 | |
153 | priv->latched_gpios = devm_gpiod_get_array(dev: &pdev->dev, con_id: "latched" , flags: GPIOD_OUT_LOW); |
154 | if (IS_ERR(ptr: priv->latched_gpios)) |
155 | return PTR_ERR(ptr: priv->latched_gpios); |
156 | |
157 | n_latches = priv->clk_gpios->ndescs; |
158 | priv->n_latched_gpios = priv->latched_gpios->ndescs; |
159 | |
160 | priv->shadow = devm_bitmap_zalloc(dev: &pdev->dev, nbits: n_latches * priv->n_latched_gpios, |
161 | GFP_KERNEL); |
162 | if (!priv->shadow) |
163 | return -ENOMEM; |
164 | |
165 | if (gpio_latch_can_sleep(priv, n_latches)) { |
166 | priv->gc.can_sleep = true; |
167 | priv->gc.set = gpio_latch_set_can_sleep; |
168 | mutex_init(&priv->mutex); |
169 | } else { |
170 | priv->gc.can_sleep = false; |
171 | priv->gc.set = gpio_latch_set; |
172 | spin_lock_init(&priv->spinlock); |
173 | } |
174 | |
175 | of_property_read_u32(np, propname: "setup-duration-ns" , out_value: &priv->setup_duration_ns); |
176 | if (priv->setup_duration_ns > DURATION_NS_MAX) { |
177 | dev_warn(&pdev->dev, "setup-duration-ns too high, limit to %d\n" , |
178 | DURATION_NS_MAX); |
179 | priv->setup_duration_ns = DURATION_NS_MAX; |
180 | } |
181 | |
182 | of_property_read_u32(np, propname: "clock-duration-ns" , out_value: &priv->clock_duration_ns); |
183 | if (priv->clock_duration_ns > DURATION_NS_MAX) { |
184 | dev_warn(&pdev->dev, "clock-duration-ns too high, limit to %d\n" , |
185 | DURATION_NS_MAX); |
186 | priv->clock_duration_ns = DURATION_NS_MAX; |
187 | } |
188 | |
189 | priv->gc.get_direction = gpio_latch_get_direction; |
190 | priv->gc.ngpio = n_latches * priv->n_latched_gpios; |
191 | priv->gc.owner = THIS_MODULE; |
192 | priv->gc.base = -1; |
193 | priv->gc.parent = &pdev->dev; |
194 | |
195 | platform_set_drvdata(pdev, data: priv); |
196 | |
197 | return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv); |
198 | } |
199 | |
200 | static const struct of_device_id gpio_latch_ids[] = { |
201 | { |
202 | .compatible = "gpio-latch" , |
203 | }, |
204 | { /* sentinel */ } |
205 | }; |
206 | MODULE_DEVICE_TABLE(of, gpio_latch_ids); |
207 | |
208 | static struct platform_driver gpio_latch_driver = { |
209 | .driver = { |
210 | .name = "gpio-latch" , |
211 | .of_match_table = gpio_latch_ids, |
212 | }, |
213 | .probe = gpio_latch_probe, |
214 | }; |
215 | module_platform_driver(gpio_latch_driver); |
216 | |
217 | MODULE_LICENSE("GPL v2" ); |
218 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>" ); |
219 | MODULE_DESCRIPTION("GPIO latch driver" ); |
220 | |