xref: /linux/drivers/spi/spi-cs42l43.c (revision 249ebf3f65f8530beb2cbfb91bff1d83ba88d23c)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // CS42L43 SPI Controller Driver
4 //
5 // Copyright (C) 2022-2023 Cirrus Logic, Inc. and
6 //                         Cirrus Logic International Semiconductor Ltd.
7 
8 #include <linux/acpi.h>
9 #include <linux/array_size.h>
10 #include <linux/bits.h>
11 #include <linux/bitfield.h>
12 #include <linux/device.h>
13 #include <linux/errno.h>
14 #include <linux/gpio/machine.h>
15 #include <linux/gpio/property.h>
16 #include <linux/mfd/cs42l43.h>
17 #include <linux/mfd/cs42l43-regs.h>
18 #include <linux/mod_devicetable.h>
19 #include <linux/module.h>
20 #include <linux/of.h>
21 #include <linux/platform_device.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/property.h>
24 #include <linux/regmap.h>
25 #include <linux/spi/spi.h>
26 #include <linux/units.h>
27 
28 #define CS42L43_FIFO_SIZE		16
29 #define CS42L43_SPI_ROOT_HZ		(40 * HZ_PER_MHZ)
30 #define CS42L43_SPI_MAX_LENGTH		65532
31 
32 enum cs42l43_spi_cmd {
33 	CS42L43_WRITE,
34 	CS42L43_READ
35 };
36 
37 struct cs42l43_spi {
38 	struct device *dev;
39 	struct regmap *regmap;
40 	struct spi_controller *ctlr;
41 };
42 
43 static const unsigned int cs42l43_clock_divs[] = {
44 	2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
45 };
46 
47 static const struct software_node ampl = {
48 	.name			= "cs35l56-left",
49 };
50 
51 static const struct software_node ampr = {
52 	.name			= "cs35l56-right",
53 };
54 
55 static struct spi_board_info ampl_info = {
56 	.modalias		= "cs35l56",
57 	.max_speed_hz		= 20 * HZ_PER_MHZ,
58 	.chip_select		= 0,
59 	.mode			= SPI_MODE_0,
60 	.swnode			= &ampl,
61 };
62 
63 static struct spi_board_info ampr_info = {
64 	.modalias		= "cs35l56",
65 	.max_speed_hz		= 20 * HZ_PER_MHZ,
66 	.chip_select		= 1,
67 	.mode			= SPI_MODE_0,
68 	.swnode			= &ampr,
69 };
70 
71 static const struct software_node cs42l43_gpiochip_swnode = {
72 	.name			= "cs42l43-pinctrl",
73 };
74 
75 static const struct software_node_ref_args cs42l43_cs_refs[] = {
76 	SOFTWARE_NODE_REFERENCE(&cs42l43_gpiochip_swnode, 0, GPIO_ACTIVE_LOW),
77 	SOFTWARE_NODE_REFERENCE(&swnode_gpio_undefined),
78 };
79 
80 static const struct property_entry cs42l43_cs_props[] = {
81 	PROPERTY_ENTRY_REF_ARRAY("cs-gpios", cs42l43_cs_refs),
82 	{}
83 };
84 
85 static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len)
86 {
87 	const u8 *end = buf + len;
88 	u32 val = 0;
89 	int ret;
90 
91 	while (buf < end) {
92 		const u8 *block = min(buf + CS42L43_FIFO_SIZE, end);
93 
94 		while (buf < block) {
95 			const u8 *word = min(buf + sizeof(u32), block);
96 			int pad = (buf + sizeof(u32)) - word;
97 
98 			while (buf < word) {
99 				val >>= BITS_PER_BYTE;
100 				val |= FIELD_PREP(GENMASK(31, 24), *buf);
101 
102 				buf++;
103 			}
104 
105 			val >>= pad * BITS_PER_BYTE;
106 
107 			regmap_write(regmap, CS42L43_TX_DATA, val);
108 		}
109 
110 		regmap_write(regmap, CS42L43_TRAN_CONFIG8, CS42L43_SPI_TX_DONE_MASK);
111 
112 		ret = regmap_read_poll_timeout(regmap, CS42L43_TRAN_STATUS1,
113 					       val, (val & CS42L43_SPI_TX_REQUEST_MASK),
114 					       1000, 5000);
115 		if (ret)
116 			return ret;
117 	}
118 
119 	return 0;
120 }
121 
122 static int cs42l43_spi_rx(struct regmap *regmap, u8 *buf, unsigned int len)
123 {
124 	u8 *end = buf + len;
125 	u32 val;
126 	int ret;
127 
128 	while (buf < end) {
129 		u8 *block = min(buf + CS42L43_FIFO_SIZE, end);
130 
131 		ret = regmap_read_poll_timeout(regmap, CS42L43_TRAN_STATUS1,
132 					       val, (val & CS42L43_SPI_RX_REQUEST_MASK),
133 					       1000, 5000);
134 		if (ret)
135 			return ret;
136 
137 		while (buf < block) {
138 			u8 *word = min(buf + sizeof(u32), block);
139 
140 			ret = regmap_read(regmap, CS42L43_RX_DATA, &val);
141 			if (ret)
142 				return ret;
143 
144 			while (buf < word) {
145 				*buf = FIELD_GET(GENMASK(7, 0), val);
146 
147 				val >>= BITS_PER_BYTE;
148 				buf++;
149 			}
150 		}
151 
152 		regmap_write(regmap, CS42L43_TRAN_CONFIG8, CS42L43_SPI_RX_DONE_MASK);
153 	}
154 
155 	return 0;
156 }
157 
158 static int cs42l43_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
159 				struct spi_transfer *tfr)
160 {
161 	struct cs42l43_spi *priv = spi_controller_get_devdata(spi->controller);
162 	int i, ret = -EINVAL;
163 
164 	for (i = 0; i < ARRAY_SIZE(cs42l43_clock_divs); i++) {
165 		if (CS42L43_SPI_ROOT_HZ / cs42l43_clock_divs[i] <= tfr->speed_hz)
166 			break;
167 	}
168 
169 	if (i == ARRAY_SIZE(cs42l43_clock_divs))
170 		return -EINVAL;
171 
172 	regmap_write(priv->regmap, CS42L43_SPI_CLK_CONFIG1, i);
173 
174 	if (tfr->tx_buf) {
175 		regmap_write(priv->regmap, CS42L43_TRAN_CONFIG3, CS42L43_WRITE);
176 		regmap_write(priv->regmap, CS42L43_TRAN_CONFIG4, tfr->len - 1);
177 	} else if (tfr->rx_buf) {
178 		regmap_write(priv->regmap, CS42L43_TRAN_CONFIG3, CS42L43_READ);
179 		regmap_write(priv->regmap, CS42L43_TRAN_CONFIG5, tfr->len - 1);
180 	}
181 
182 	regmap_write(priv->regmap, CS42L43_TRAN_CONFIG1, CS42L43_SPI_START_MASK);
183 
184 	if (tfr->tx_buf)
185 		ret = cs42l43_spi_tx(priv->regmap, (const u8 *)tfr->tx_buf, tfr->len);
186 	else if (tfr->rx_buf)
187 		ret = cs42l43_spi_rx(priv->regmap, (u8 *)tfr->rx_buf, tfr->len);
188 
189 	return ret;
190 }
191 
192 static void cs42l43_set_cs(struct spi_device *spi, bool is_high)
193 {
194 	struct cs42l43_spi *priv = spi_controller_get_devdata(spi->controller);
195 
196 	regmap_write(priv->regmap, CS42L43_SPI_CONFIG2, !is_high);
197 }
198 
199 static int cs42l43_prepare_message(struct spi_controller *ctlr, struct spi_message *msg)
200 {
201 	struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
202 	struct spi_device *spi = msg->spi;
203 	unsigned int spi_config1 = 0;
204 
205 	/* select another internal CS, which doesn't exist, so CS 0 is not used */
206 	if (spi_get_csgpiod(spi, 0))
207 		spi_config1 |= 1 << CS42L43_SPI_SS_SEL_SHIFT;
208 	if (spi->mode & SPI_CPOL)
209 		spi_config1 |= CS42L43_SPI_CPOL_MASK;
210 	if (spi->mode & SPI_CPHA)
211 		spi_config1 |= CS42L43_SPI_CPHA_MASK;
212 	if (spi->mode & SPI_3WIRE)
213 		spi_config1 |= CS42L43_SPI_THREE_WIRE_MASK;
214 
215 	regmap_write(priv->regmap, CS42L43_SPI_CONFIG1, spi_config1);
216 
217 	return 0;
218 }
219 
220 static int cs42l43_prepare_transfer_hardware(struct spi_controller *ctlr)
221 {
222 	struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
223 	int ret;
224 
225 	ret = regmap_write(priv->regmap, CS42L43_BLOCK_EN2, CS42L43_SPI_MSTR_EN_MASK);
226 	if (ret)
227 		dev_err(priv->dev, "Failed to enable SPI controller: %d\n", ret);
228 
229 	return ret;
230 }
231 
232 static int cs42l43_unprepare_transfer_hardware(struct spi_controller *ctlr)
233 {
234 	struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
235 	int ret;
236 
237 	ret = regmap_write(priv->regmap, CS42L43_BLOCK_EN2, 0);
238 	if (ret)
239 		dev_err(priv->dev, "Failed to disable SPI controller: %d\n", ret);
240 
241 	return ret;
242 }
243 
244 static size_t cs42l43_spi_max_length(struct spi_device *spi)
245 {
246 	return CS42L43_SPI_MAX_LENGTH;
247 }
248 
249 static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode)
250 {
251 	static const u32 func_smart_amp = 0x1;
252 	struct fwnode_handle *child_fwnode, *ext_fwnode;
253 	unsigned int val;
254 	u32 function;
255 	int ret;
256 
257 	fwnode_for_each_child_node(fwnode, child_fwnode) {
258 		acpi_handle handle = ACPI_HANDLE_FWNODE(child_fwnode);
259 
260 		ret = acpi_get_local_address(handle, &function);
261 		if (ret || function != func_smart_amp)
262 			continue;
263 
264 		ext_fwnode = fwnode_get_named_child_node(child_fwnode,
265 				"mipi-sdca-function-expansion-subproperties");
266 		if (!ext_fwnode)
267 			continue;
268 
269 		ret = fwnode_property_read_u32(ext_fwnode,
270 					       "01fa-sidecar-instances",
271 					       &val);
272 
273 		fwnode_handle_put(ext_fwnode);
274 
275 		if (ret)
276 			continue;
277 
278 		fwnode_handle_put(child_fwnode);
279 
280 		return !!val;
281 	}
282 
283 	return false;
284 }
285 
286 static void cs42l43_release_of_node(void *data)
287 {
288 	fwnode_handle_put(data);
289 }
290 
291 static void cs42l43_release_sw_node(void *data)
292 {
293 	software_node_unregister(&cs42l43_gpiochip_swnode);
294 }
295 
296 static int cs42l43_spi_probe(struct platform_device *pdev)
297 {
298 	struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
299 	struct cs42l43_spi *priv;
300 	struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
301 	bool has_sidecar = cs42l43_has_sidecar(fwnode);
302 	int ret;
303 
304 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
305 	if (!priv)
306 		return -ENOMEM;
307 
308 	priv->ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*priv->ctlr));
309 	if (!priv->ctlr)
310 		return -ENOMEM;
311 
312 	spi_controller_set_devdata(priv->ctlr, priv);
313 
314 	priv->dev = &pdev->dev;
315 	priv->regmap = cs42l43->regmap;
316 
317 	priv->ctlr->prepare_message = cs42l43_prepare_message;
318 	priv->ctlr->prepare_transfer_hardware = cs42l43_prepare_transfer_hardware;
319 	priv->ctlr->unprepare_transfer_hardware = cs42l43_unprepare_transfer_hardware;
320 	priv->ctlr->transfer_one = cs42l43_transfer_one;
321 	priv->ctlr->set_cs = cs42l43_set_cs;
322 	priv->ctlr->max_transfer_size = cs42l43_spi_max_length;
323 	priv->ctlr->mode_bits = SPI_3WIRE | SPI_MODE_X_MASK;
324 	priv->ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
325 	priv->ctlr->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
326 					 SPI_BPW_MASK(32);
327 	priv->ctlr->min_speed_hz = CS42L43_SPI_ROOT_HZ /
328 				   cs42l43_clock_divs[ARRAY_SIZE(cs42l43_clock_divs) - 1];
329 	priv->ctlr->max_speed_hz = CS42L43_SPI_ROOT_HZ / cs42l43_clock_divs[0];
330 	priv->ctlr->use_gpio_descriptors = true;
331 	priv->ctlr->auto_runtime_pm = true;
332 
333 	ret = devm_pm_runtime_enable(priv->dev);
334 	if (ret)
335 		return ret;
336 
337 	pm_runtime_idle(priv->dev);
338 
339 	regmap_write(priv->regmap, CS42L43_TRAN_CONFIG6, CS42L43_FIFO_SIZE - 1);
340 	regmap_write(priv->regmap, CS42L43_TRAN_CONFIG7, CS42L43_FIFO_SIZE - 1);
341 
342 	// Disable Watchdog timer and enable stall
343 	regmap_write(priv->regmap, CS42L43_SPI_CONFIG3, 0);
344 	regmap_write(priv->regmap, CS42L43_SPI_CONFIG4, CS42L43_SPI_STALL_ENA_MASK);
345 
346 	if (is_of_node(fwnode)) {
347 		fwnode = fwnode_get_named_child_node(fwnode, "spi");
348 		ret = devm_add_action_or_reset(priv->dev, cs42l43_release_of_node, fwnode);
349 		if (ret)
350 			return ret;
351 	}
352 
353 	if (has_sidecar) {
354 		ret = software_node_register(&cs42l43_gpiochip_swnode);
355 		if (ret)
356 			return dev_err_probe(priv->dev, ret,
357 					     "Failed to register gpio swnode\n");
358 
359 		ret = devm_add_action_or_reset(priv->dev, cs42l43_release_sw_node, NULL);
360 		if (ret)
361 			return ret;
362 
363 		ret = device_create_managed_software_node(&priv->ctlr->dev,
364 							  cs42l43_cs_props, NULL);
365 		if (ret)
366 			return dev_err_probe(priv->dev, ret, "Failed to add swnode\n");
367 	} else {
368 		device_set_node(&priv->ctlr->dev, fwnode);
369 	}
370 
371 	ret = devm_spi_register_controller(priv->dev, priv->ctlr);
372 	if (ret)
373 		return dev_err_probe(priv->dev, ret,
374 				     "Failed to register SPI controller\n");
375 
376 	if (has_sidecar) {
377 		if (!spi_new_device(priv->ctlr, &ampl_info))
378 			return dev_err_probe(priv->dev, -ENODEV,
379 					     "Failed to create left amp slave\n");
380 
381 		if (!spi_new_device(priv->ctlr, &ampr_info))
382 			return dev_err_probe(priv->dev, -ENODEV,
383 					     "Failed to create right amp slave\n");
384 	}
385 
386 	return 0;
387 }
388 
389 static const struct platform_device_id cs42l43_spi_id_table[] = {
390 	{ "cs42l43-spi", },
391 	{}
392 };
393 MODULE_DEVICE_TABLE(platform, cs42l43_spi_id_table);
394 
395 static struct platform_driver cs42l43_spi_driver = {
396 	.driver = {
397 		.name	= "cs42l43-spi",
398 	},
399 	.probe		= cs42l43_spi_probe,
400 	.id_table	= cs42l43_spi_id_table,
401 };
402 module_platform_driver(cs42l43_spi_driver);
403 
404 MODULE_IMPORT_NS(GPIO_SWNODE);
405 MODULE_DESCRIPTION("CS42L43 SPI Driver");
406 MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
407 MODULE_AUTHOR("Maciej Strozek <mstrozek@opensource.cirrus.com>");
408 MODULE_LICENSE("GPL");
409