18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// General Purpose SPI multiplexer 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/err.h> 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/mux/consumer.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define SPI_MUX_NO_CS ((unsigned int)-1) 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/** 158c2ecf20Sopenharmony_ci * DOC: Driver description 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This driver supports a MUX on an SPI bus. This can be useful when you need 188c2ecf20Sopenharmony_ci * more chip selects than the hardware peripherals support, or than are 198c2ecf20Sopenharmony_ci * available in a particular board setup. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * The driver will create an additional SPI controller. Devices added under the 228c2ecf20Sopenharmony_ci * mux will be handled as 'chip selects' on this controller. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/** 268c2ecf20Sopenharmony_ci * struct spi_mux_priv - the basic spi_mux structure 278c2ecf20Sopenharmony_ci * @spi: pointer to the device struct attached to the parent 288c2ecf20Sopenharmony_ci * spi controller 298c2ecf20Sopenharmony_ci * @current_cs: The current chip select set in the mux 308c2ecf20Sopenharmony_ci * @child_msg_complete: The mux replaces the complete callback in the child's 318c2ecf20Sopenharmony_ci * message to its own callback; this field is used by the 328c2ecf20Sopenharmony_ci * driver to store the child's callback during a transfer 338c2ecf20Sopenharmony_ci * @child_msg_context: Used to store the child's context to the callback 348c2ecf20Sopenharmony_ci * @child_msg_dev: Used to store the spi_device pointer to the child 358c2ecf20Sopenharmony_ci * @mux: mux_control structure used to provide chip selects for 368c2ecf20Sopenharmony_ci * downstream spi devices 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistruct spi_mux_priv { 398c2ecf20Sopenharmony_ci struct spi_device *spi; 408c2ecf20Sopenharmony_ci unsigned int current_cs; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci void (*child_msg_complete)(void *context); 438c2ecf20Sopenharmony_ci void *child_msg_context; 448c2ecf20Sopenharmony_ci struct spi_device *child_msg_dev; 458c2ecf20Sopenharmony_ci struct mux_control *mux; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* should not get called when the parent controller is doing a transfer */ 498c2ecf20Sopenharmony_cistatic int spi_mux_select(struct spi_device *spi) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller); 528c2ecf20Sopenharmony_ci int ret; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ret = mux_control_select(priv->mux, spi->chip_select); 558c2ecf20Sopenharmony_ci if (ret) 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (priv->current_cs == spi->chip_select) 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci dev_dbg(&priv->spi->dev, "setting up the mux for cs %d\n", 628c2ecf20Sopenharmony_ci spi->chip_select); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* copy the child device's settings except for the cs */ 658c2ecf20Sopenharmony_ci priv->spi->max_speed_hz = spi->max_speed_hz; 668c2ecf20Sopenharmony_ci priv->spi->mode = spi->mode; 678c2ecf20Sopenharmony_ci priv->spi->bits_per_word = spi->bits_per_word; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci priv->current_cs = spi->chip_select; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int spi_mux_setup(struct spi_device *spi) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* 798c2ecf20Sopenharmony_ci * can be called multiple times, won't do a valid setup now but we will 808c2ecf20Sopenharmony_ci * change the settings when we do a transfer (necessary because we 818c2ecf20Sopenharmony_ci * can't predict from which device it will be anyway) 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci return spi_setup(priv->spi); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void spi_mux_complete_cb(void *context) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct spi_mux_priv *priv = (struct spi_mux_priv *)context; 898c2ecf20Sopenharmony_ci struct spi_controller *ctlr = spi_get_drvdata(priv->spi); 908c2ecf20Sopenharmony_ci struct spi_message *m = ctlr->cur_msg; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci m->complete = priv->child_msg_complete; 938c2ecf20Sopenharmony_ci m->context = priv->child_msg_context; 948c2ecf20Sopenharmony_ci m->spi = priv->child_msg_dev; 958c2ecf20Sopenharmony_ci spi_finalize_current_message(ctlr); 968c2ecf20Sopenharmony_ci mux_control_deselect(priv->mux); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int spi_mux_transfer_one_message(struct spi_controller *ctlr, 1008c2ecf20Sopenharmony_ci struct spi_message *m) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct spi_mux_priv *priv = spi_controller_get_devdata(ctlr); 1038c2ecf20Sopenharmony_ci struct spi_device *spi = m->spi; 1048c2ecf20Sopenharmony_ci int ret; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci ret = spi_mux_select(spi); 1078c2ecf20Sopenharmony_ci if (ret) 1088c2ecf20Sopenharmony_ci return ret; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* 1118c2ecf20Sopenharmony_ci * Replace the complete callback, context and spi_device with our own 1128c2ecf20Sopenharmony_ci * pointers. Save originals 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci priv->child_msg_complete = m->complete; 1158c2ecf20Sopenharmony_ci priv->child_msg_context = m->context; 1168c2ecf20Sopenharmony_ci priv->child_msg_dev = m->spi; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci m->complete = spi_mux_complete_cb; 1198c2ecf20Sopenharmony_ci m->context = priv; 1208c2ecf20Sopenharmony_ci m->spi = priv->spi; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* do the transfer */ 1238c2ecf20Sopenharmony_ci return spi_async(priv->spi, m); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int spi_mux_probe(struct spi_device *spi) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct spi_controller *ctlr; 1298c2ecf20Sopenharmony_ci struct spi_mux_priv *priv; 1308c2ecf20Sopenharmony_ci int ret; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci ctlr = spi_alloc_master(&spi->dev, sizeof(*priv)); 1338c2ecf20Sopenharmony_ci if (!ctlr) 1348c2ecf20Sopenharmony_ci return -ENOMEM; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci spi_set_drvdata(spi, ctlr); 1378c2ecf20Sopenharmony_ci priv = spi_controller_get_devdata(ctlr); 1388c2ecf20Sopenharmony_ci priv->spi = spi; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci priv->mux = devm_mux_control_get(&spi->dev, NULL); 1418c2ecf20Sopenharmony_ci if (IS_ERR(priv->mux)) { 1428c2ecf20Sopenharmony_ci ret = dev_err_probe(&spi->dev, PTR_ERR(priv->mux), 1438c2ecf20Sopenharmony_ci "failed to get control-mux\n"); 1448c2ecf20Sopenharmony_ci goto err_put_ctlr; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci priv->current_cs = SPI_MUX_NO_CS; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* supported modes are the same as our parent's */ 1508c2ecf20Sopenharmony_ci ctlr->mode_bits = spi->controller->mode_bits; 1518c2ecf20Sopenharmony_ci ctlr->flags = spi->controller->flags; 1528c2ecf20Sopenharmony_ci ctlr->transfer_one_message = spi_mux_transfer_one_message; 1538c2ecf20Sopenharmony_ci ctlr->setup = spi_mux_setup; 1548c2ecf20Sopenharmony_ci ctlr->num_chipselect = mux_control_states(priv->mux); 1558c2ecf20Sopenharmony_ci ctlr->bus_num = -1; 1568c2ecf20Sopenharmony_ci ctlr->dev.of_node = spi->dev.of_node; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci ret = devm_spi_register_controller(&spi->dev, ctlr); 1598c2ecf20Sopenharmony_ci if (ret) 1608c2ecf20Sopenharmony_ci goto err_put_ctlr; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cierr_put_ctlr: 1658c2ecf20Sopenharmony_ci spi_controller_put(ctlr); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return ret; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic const struct spi_device_id spi_mux_id[] = { 1718c2ecf20Sopenharmony_ci { "spi-mux" }, 1728c2ecf20Sopenharmony_ci { } 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, spi_mux_id); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic const struct of_device_id spi_mux_of_match[] = { 1778c2ecf20Sopenharmony_ci { .compatible = "spi-mux" }, 1788c2ecf20Sopenharmony_ci { } 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, spi_mux_of_match); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic struct spi_driver spi_mux_driver = { 1838c2ecf20Sopenharmony_ci .probe = spi_mux_probe, 1848c2ecf20Sopenharmony_ci .driver = { 1858c2ecf20Sopenharmony_ci .name = "spi-mux", 1868c2ecf20Sopenharmony_ci .of_match_table = spi_mux_of_match, 1878c2ecf20Sopenharmony_ci }, 1888c2ecf20Sopenharmony_ci .id_table = spi_mux_id, 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cimodule_spi_driver(spi_mux_driver); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SPI multiplexer"); 1948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 195