1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // General Purpose SPI multiplexer |
4 | |
5 | #include <linux/err.h> |
6 | #include <linux/kernel.h> |
7 | #include <linux/module.h> |
8 | #include <linux/mux/consumer.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/spi/spi.h> |
11 | |
12 | #define SPI_MUX_NO_CS ((unsigned int)-1) |
13 | |
14 | /** |
15 | * DOC: Driver description |
16 | * |
17 | * This driver supports a MUX on an SPI bus. This can be useful when you need |
18 | * more chip selects than the hardware peripherals support, or than are |
19 | * available in a particular board setup. |
20 | * |
21 | * The driver will create an additional SPI controller. Devices added under the |
22 | * mux will be handled as 'chip selects' on this controller. |
23 | */ |
24 | |
25 | /** |
26 | * struct spi_mux_priv - the basic spi_mux structure |
27 | * @spi: pointer to the device struct attached to the parent |
28 | * spi controller |
29 | * @current_cs: The current chip select set in the mux |
30 | * @child_msg_complete: The mux replaces the complete callback in the child's |
31 | * message to its own callback; this field is used by the |
32 | * driver to store the child's callback during a transfer |
33 | * @child_msg_context: Used to store the child's context to the callback |
34 | * @child_msg_dev: Used to store the spi_device pointer to the child |
35 | * @mux: mux_control structure used to provide chip selects for |
36 | * downstream spi devices |
37 | */ |
38 | struct spi_mux_priv { |
39 | struct spi_device *spi; |
40 | unsigned int current_cs; |
41 | |
42 | void (*child_msg_complete)(void *context); |
43 | void *child_msg_context; |
44 | struct spi_device *child_msg_dev; |
45 | struct mux_control *mux; |
46 | }; |
47 | |
48 | /* should not get called when the parent controller is doing a transfer */ |
49 | static int spi_mux_select(struct spi_device *spi) |
50 | { |
51 | struct spi_mux_priv *priv = spi_controller_get_devdata(ctlr: spi->controller); |
52 | int ret; |
53 | |
54 | ret = mux_control_select(mux: priv->mux, state: spi_get_chipselect(spi, idx: 0)); |
55 | if (ret) |
56 | return ret; |
57 | |
58 | if (priv->current_cs == spi_get_chipselect(spi, idx: 0)) |
59 | return 0; |
60 | |
61 | dev_dbg(&priv->spi->dev, "setting up the mux for cs %d\n" , |
62 | spi_get_chipselect(spi, 0)); |
63 | |
64 | /* copy the child device's settings except for the cs */ |
65 | priv->spi->max_speed_hz = spi->max_speed_hz; |
66 | priv->spi->mode = spi->mode; |
67 | priv->spi->bits_per_word = spi->bits_per_word; |
68 | |
69 | priv->current_cs = spi_get_chipselect(spi, idx: 0); |
70 | |
71 | return 0; |
72 | } |
73 | |
74 | static int spi_mux_setup(struct spi_device *spi) |
75 | { |
76 | struct spi_mux_priv *priv = spi_controller_get_devdata(ctlr: spi->controller); |
77 | |
78 | /* |
79 | * can be called multiple times, won't do a valid setup now but we will |
80 | * change the settings when we do a transfer (necessary because we |
81 | * can't predict from which device it will be anyway) |
82 | */ |
83 | return spi_setup(spi: priv->spi); |
84 | } |
85 | |
86 | static void spi_mux_complete_cb(void *context) |
87 | { |
88 | struct spi_mux_priv *priv = (struct spi_mux_priv *)context; |
89 | struct spi_controller *ctlr = spi_get_drvdata(spi: priv->spi); |
90 | struct spi_message *m = ctlr->cur_msg; |
91 | |
92 | m->complete = priv->child_msg_complete; |
93 | m->context = priv->child_msg_context; |
94 | m->spi = priv->child_msg_dev; |
95 | spi_finalize_current_message(ctlr); |
96 | mux_control_deselect(mux: priv->mux); |
97 | } |
98 | |
99 | static int spi_mux_transfer_one_message(struct spi_controller *ctlr, |
100 | struct spi_message *m) |
101 | { |
102 | struct spi_mux_priv *priv = spi_controller_get_devdata(ctlr); |
103 | struct spi_device *spi = m->spi; |
104 | int ret; |
105 | |
106 | ret = spi_mux_select(spi); |
107 | if (ret) |
108 | return ret; |
109 | |
110 | /* |
111 | * Replace the complete callback, context and spi_device with our own |
112 | * pointers. Save originals |
113 | */ |
114 | priv->child_msg_complete = m->complete; |
115 | priv->child_msg_context = m->context; |
116 | priv->child_msg_dev = m->spi; |
117 | |
118 | m->complete = spi_mux_complete_cb; |
119 | m->context = priv; |
120 | m->spi = priv->spi; |
121 | |
122 | /* do the transfer */ |
123 | return spi_async(spi: priv->spi, message: m); |
124 | } |
125 | |
126 | static int spi_mux_probe(struct spi_device *spi) |
127 | { |
128 | struct spi_controller *ctlr; |
129 | struct spi_mux_priv *priv; |
130 | int ret; |
131 | |
132 | ctlr = spi_alloc_host(dev: &spi->dev, size: sizeof(*priv)); |
133 | if (!ctlr) |
134 | return -ENOMEM; |
135 | |
136 | spi_set_drvdata(spi, data: ctlr); |
137 | priv = spi_controller_get_devdata(ctlr); |
138 | priv->spi = spi; |
139 | |
140 | /* |
141 | * Increase lockdep class as these lock are taken while the parent bus |
142 | * already holds their instance's lock. |
143 | */ |
144 | lockdep_set_subclass(&ctlr->io_mutex, 1); |
145 | lockdep_set_subclass(&ctlr->add_lock, 1); |
146 | |
147 | priv->mux = devm_mux_control_get(dev: &spi->dev, NULL); |
148 | if (IS_ERR(ptr: priv->mux)) { |
149 | ret = dev_err_probe(dev: &spi->dev, err: PTR_ERR(ptr: priv->mux), |
150 | fmt: "failed to get control-mux\n" ); |
151 | goto err_put_ctlr; |
152 | } |
153 | |
154 | priv->current_cs = SPI_MUX_NO_CS; |
155 | |
156 | /* supported modes are the same as our parent's */ |
157 | ctlr->mode_bits = spi->controller->mode_bits; |
158 | ctlr->flags = spi->controller->flags; |
159 | ctlr->transfer_one_message = spi_mux_transfer_one_message; |
160 | ctlr->setup = spi_mux_setup; |
161 | ctlr->num_chipselect = mux_control_states(mux: priv->mux); |
162 | ctlr->bus_num = -1; |
163 | ctlr->dev.of_node = spi->dev.of_node; |
164 | ctlr->must_async = true; |
165 | |
166 | ret = devm_spi_register_controller(dev: &spi->dev, ctlr); |
167 | if (ret) |
168 | goto err_put_ctlr; |
169 | |
170 | return 0; |
171 | |
172 | err_put_ctlr: |
173 | spi_controller_put(ctlr); |
174 | |
175 | return ret; |
176 | } |
177 | |
178 | static const struct spi_device_id spi_mux_id[] = { |
179 | { "spi-mux" }, |
180 | { } |
181 | }; |
182 | MODULE_DEVICE_TABLE(spi, spi_mux_id); |
183 | |
184 | static const struct of_device_id spi_mux_of_match[] = { |
185 | { .compatible = "spi-mux" }, |
186 | { } |
187 | }; |
188 | MODULE_DEVICE_TABLE(of, spi_mux_of_match); |
189 | |
190 | static struct spi_driver spi_mux_driver = { |
191 | .probe = spi_mux_probe, |
192 | .driver = { |
193 | .name = "spi-mux" , |
194 | .of_match_table = spi_mux_of_match, |
195 | }, |
196 | .id_table = spi_mux_id, |
197 | }; |
198 | |
199 | module_spi_driver(spi_mux_driver); |
200 | |
201 | MODULE_DESCRIPTION("SPI multiplexer" ); |
202 | MODULE_LICENSE("GPL" ); |
203 | |