brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · c02c420 Raw
207 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// General Purpose SPI multiplexer4 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 description16 *17 * This driver supports a MUX on an SPI bus. This can be useful when you need18 * more chip selects than the hardware peripherals support, or than are19 * available in a particular board setup.20 *21 * The driver will create an additional SPI controller. Devices added under the22 * mux will be handled as 'chip selects' on this controller.23 */24 25/**26 * struct spi_mux_priv - the basic spi_mux structure27 * @spi:		pointer to the device struct attached to the parent28 *			spi controller29 * @current_cs:		The current chip select set in the mux30 * @child_msg_complete: The mux replaces the complete callback in the child's31 *			message to its own callback; this field is used by the32 *			driver to store the child's callback during a transfer33 * @child_msg_context:	Used to store the child's context to the callback34 * @child_msg_dev:	Used to store the spi_device pointer to the child35 * @mux:		mux_control structure used to provide chip selects for36 *			downstream spi devices37 */38struct 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 */49static int spi_mux_select(struct spi_device *spi)50{51	struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller);52	int ret;53 54	ret = mux_control_select(priv->mux, spi_get_chipselect(spi, 0));55	if (ret)56		return ret;57 58	if (priv->current_cs == spi_get_chipselect(spi, 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, 0);70 71	spi_setup(priv->spi);72 73	return 0;74}75 76static int spi_mux_setup(struct spi_device *spi)77{78	struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller);79 80	/*81	 * can be called multiple times, won't do a valid setup now but we will82	 * change the settings when we do a transfer (necessary because we83	 * can't predict from which device it will be anyway)84	 */85	return spi_setup(priv->spi);86}87 88static void spi_mux_complete_cb(void *context)89{90	struct spi_mux_priv *priv = (struct spi_mux_priv *)context;91	struct spi_controller *ctlr = spi_get_drvdata(priv->spi);92	struct spi_message *m = ctlr->cur_msg;93 94	m->complete = priv->child_msg_complete;95	m->context = priv->child_msg_context;96	m->spi = priv->child_msg_dev;97	spi_finalize_current_message(ctlr);98	mux_control_deselect(priv->mux);99}100 101static int spi_mux_transfer_one_message(struct spi_controller *ctlr,102						struct spi_message *m)103{104	struct spi_mux_priv *priv = spi_controller_get_devdata(ctlr);105	struct spi_device *spi = m->spi;106	int ret;107 108	ret = spi_mux_select(spi);109	if (ret)110		return ret;111 112	/*113	 * Replace the complete callback, context and spi_device with our own114	 * pointers. Save originals115	 */116	priv->child_msg_complete = m->complete;117	priv->child_msg_context = m->context;118	priv->child_msg_dev = m->spi;119 120	m->complete = spi_mux_complete_cb;121	m->context = priv;122	m->spi = priv->spi;123 124	/* do the transfer */125	return spi_async(priv->spi, m);126}127 128static int spi_mux_probe(struct spi_device *spi)129{130	struct spi_controller *ctlr;131	struct spi_mux_priv *priv;132	int ret;133 134	ctlr = spi_alloc_host(&spi->dev, sizeof(*priv));135	if (!ctlr)136		return -ENOMEM;137 138	spi_set_drvdata(spi, ctlr);139	priv = spi_controller_get_devdata(ctlr);140	priv->spi = spi;141 142	/*143	 * Increase lockdep class as these lock are taken while the parent bus144	 * already holds their instance's lock.145	 */146	lockdep_set_subclass(&ctlr->io_mutex, 1);147	lockdep_set_subclass(&ctlr->add_lock, 1);148 149	priv->mux = devm_mux_control_get(&spi->dev, NULL);150	if (IS_ERR(priv->mux)) {151		ret = dev_err_probe(&spi->dev, PTR_ERR(priv->mux),152				    "failed to get control-mux\n");153		goto err_put_ctlr;154	}155 156	priv->current_cs = SPI_MUX_NO_CS;157 158	/* supported modes are the same as our parent's */159	ctlr->mode_bits = spi->controller->mode_bits;160	ctlr->flags = spi->controller->flags;161	ctlr->bits_per_word_mask = spi->controller->bits_per_word_mask;162	ctlr->transfer_one_message = spi_mux_transfer_one_message;163	ctlr->setup = spi_mux_setup;164	ctlr->num_chipselect = mux_control_states(priv->mux);165	ctlr->bus_num = -1;166	ctlr->dev.of_node = spi->dev.of_node;167	ctlr->must_async = true;168	ctlr->defer_optimize_message = true;169 170	ret = devm_spi_register_controller(&spi->dev, ctlr);171	if (ret)172		goto err_put_ctlr;173 174	return 0;175 176err_put_ctlr:177	spi_controller_put(ctlr);178 179	return ret;180}181 182static const struct spi_device_id spi_mux_id[] = {183	{ "spi-mux" },184	{ }185};186MODULE_DEVICE_TABLE(spi, spi_mux_id);187 188static const struct of_device_id spi_mux_of_match[] = {189	{ .compatible = "spi-mux" },190	{ }191};192MODULE_DEVICE_TABLE(of, spi_mux_of_match);193 194static struct spi_driver spi_mux_driver = {195	.probe  = spi_mux_probe,196	.driver = {197		.name   = "spi-mux",198		.of_match_table = spi_mux_of_match,199	},200	.id_table = spi_mux_id,201};202 203module_spi_driver(spi_mux_driver);204 205MODULE_DESCRIPTION("SPI multiplexer");206MODULE_LICENSE("GPL");207