drivers: Add a new framework for multiplexer devices
Add a new subsystem that handles multiplexer controllers. The API is the
same as in Linux.
Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
[trini: Update some error calls to use different functions or pass
correct arguments]
Signed-off-by: Tom Rini <trini@konsulko.com>
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 88f10c4..17542de 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -71,6 +71,7 @@
UCLASS_MMC, /* SD / MMC card or chip */
UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_MTD, /* Memory Technology Device (MTD) device */
+ UCLASS_MUX, /* Multiplexer device */
UCLASS_NOP, /* No-op devices */
UCLASS_NORTHBRIDGE, /* Intel Northbridge / SDRAM controller */
UCLASS_NVME, /* NVM Express device */
diff --git a/include/dt-bindings/mux/mux.h b/include/dt-bindings/mux/mux.h
new file mode 100644
index 0000000..0427192
--- /dev/null
+++ b/include/dt-bindings/mux/mux.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides constants for most Multiplexer bindings.
+ *
+ * Most Multiplexer bindings specify an idle state. In most cases, the
+ * the multiplexer can be left as is when idle, and in some cases it can
+ * disconnect the input/output and leave the multiplexer in a high
+ * impedance state.
+ */
+
+#ifndef _DT_BINDINGS_MUX_MUX_H
+#define _DT_BINDINGS_MUX_MUX_H
+
+#define MUX_IDLE_AS_IS (-1)
+#define MUX_IDLE_DISCONNECT (-2)
+
+#endif
diff --git a/include/mux-internal.h b/include/mux-internal.h
new file mode 100644
index 0000000..93e3a5c
--- /dev/null
+++ b/include/mux-internal.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Based on the linux multiplexer framework
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#ifndef _MUX_INTERNAL_H
+#define _MUX_INTERNAL_H
+
+/* See mux.h for background documentation. */
+
+struct ofnode_phandle_args;
+
+/**
+ * struct mux_chip - Represents a chip holding mux controllers.
+ * @controllers: Number of mux controllers handled by the chip.
+ * @mux: Array of mux controllers that are handled.
+ *
+ * This a per-device uclass-private data.
+ */
+struct mux_chip {
+ unsigned int controllers;
+ struct mux_control *mux;
+};
+
+/**
+ * struct mux_control_ops - Mux controller operations for a mux chip.
+ * @set: Set the state of the given mux controller.
+ */
+struct mux_control_ops {
+ /**
+ * set - Apply a state to a multiplexer control
+ *
+ * @mux: A multiplexer control
+ * @return 0 if OK, or a negative error code.
+ */
+ int (*set)(struct mux_control *mux, int state);
+
+ /**
+ * of_xlate - Translate a client's device-tree (OF) multiplexer
+ * specifier.
+ *
+ * If this function pointer is set to NULL, the multiplexer core will
+ * use a default implementation, which assumes #mux-control-cells = <1>
+ * and that the DT cell contains a simple integer channel ID.
+ *
+ * @dev_mux: The multiplexer device. A single device may handle
+ * several multiplexer controls.
+ * @args: The multiplexer specifier values from device tree.
+ * @muxp: (out) A multiplexer control
+ * @return 0 if OK, or a negative error code.
+ */
+ int (*of_xlate)(struct mux_chip *dev_mux,
+ struct ofnode_phandle_args *args,
+ struct mux_control **muxp);
+};
+
+/**
+ * struct mux_control - Represents a mux controller.
+ * @in_use: Whether the mux controller is in use or not.
+ * @dev: The client device.
+ * @cached_state: The current mux controller state, or -1 if none.
+ * @states: The number of mux controller states.
+ * @idle_state: The mux controller state to use when inactive, or one
+ * of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
+ * @id: The index of the mux controller within the mux chip
+ * it is a part of.
+ *
+ * Mux drivers may only change @states and @idle_state, and may only do so
+ * between allocation and registration of the mux controller. Specifically,
+ * @cached_state is internal to the mux core and should never be written by
+ * mux drivers.
+ */
+struct mux_control {
+ bool in_use;
+ struct udevice *dev;
+ int cached_state;
+ unsigned int states;
+ int idle_state;
+ int id;
+};
+
+/**
+ * mux_control_get_index() - Get the index of the given mux controller
+ * @mux: The mux-control to get the index for.
+ *
+ * Return: The index of the mux controller within the mux chip the mux
+ * controller is a part of.
+ */
+static inline unsigned int mux_control_get_index(struct mux_control *mux)
+{
+ return mux->id;
+}
+
+/**
+ * mux_alloc_controllers() - Allocate the given number of mux controllers.
+ * @dev: The client device.
+ * controllers: Number of controllers to allocate.
+ *
+ * Return: 0 of OK, -errno otherwise.
+ */
+int mux_alloc_controllers(struct udevice *dev, unsigned int controllers);
+
+#endif
diff --git a/include/mux.h b/include/mux.h
new file mode 100644
index 0000000..85eb7d4
--- /dev/null
+++ b/include/mux.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Based on the linux multiplexer framework
+ *
+ * At its core, a multiplexer (or mux), also known as a data selector, is a
+ * device that selects between several analog or digital input signals and
+ * forwards it to a single output line. This notion can be extended to work
+ * with buses, like a I2C bus multiplexer for example.
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#ifndef _MUX_H_
+#define _MUX_H_
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+struct udevice;
+struct mux_control;
+
+#if CONFIG_IS_ENABLED(MULTIPLEXER)
+/**
+ * mux_control_states() - Query the number of multiplexer states.
+ * @mux: The mux-control to query.
+ *
+ * Return: The number of multiplexer states.
+ */
+unsigned int mux_control_states(struct mux_control *mux);
+
+/**
+ * mux_control_select() - Select the given multiplexer state.
+ * @mux: The mux-control to request a change of state from.
+ * @state: The new requested state.
+ *
+ * On successfully selecting the mux-control state, it will be locked until
+ * there is a call to mux_control_deselect(). If the mux-control is already
+ * selected when mux_control_select() is called, the function will indicate
+ * -EBUSY
+ *
+ * Therefore, make sure to call mux_control_deselect() when the operation is
+ * complete and the mux-control is free for others to use, but do not call
+ * mux_control_deselect() if mux_control_select() fails.
+ *
+ * Return: 0 when the mux-control state has the requested state or a negative
+ * errno on error.
+ */
+int __must_check mux_control_select(struct mux_control *mux,
+ unsigned int state);
+#define mux_control_try_select(mux) mux_control_select(mux)
+
+/**
+ * mux_control_deselect() - Deselect the previously selected multiplexer state.
+ * @mux: The mux-control to deselect.
+ *
+ * It is required that a single call is made to mux_control_deselect() for
+ * each and every successful call made to either of mux_control_select() or
+ * mux_control_try_select().
+ *
+ * Return: 0 on success and a negative errno on error. An error can only
+ * occur if the mux has an idle state. Note that even if an error occurs, the
+ * mux-control is unlocked and is thus free for the next access.
+ */
+int mux_control_deselect(struct mux_control *mux);
+
+/**
+ * mux_get_by_index() = Get a mux by integer index.
+ * @dev: The client device.
+ * @index: The index of the mux to get.
+ * @mux: A pointer to the 'mux_control' struct to initialize.
+ *
+ * This looks up and initializes a mux. The index is relative to the client
+ * device.
+ *
+ * Return: 0 if OK, or a negative error code.
+ */
+int mux_get_by_index(struct udevice *dev, int index, struct mux_control **mux);
+
+/**
+ * mux_control_get() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ * @mux: A pointer to the mux-control pointer.
+ *
+ * Return: 0 of OK, or a negative error code.
+ */
+int mux_control_get(struct udevice *dev, const char *name,
+ struct mux_control **mux);
+
+/**
+ * mux_control_put() - Put away the mux-control for good.
+ * @mux: The mux-control to put away.
+ *
+ * mux_control_put() reverses the effects of mux_control_get().
+ */
+void mux_control_put(struct mux_control *mux);
+
+/**
+ * devm_mux_control_get() - Get the mux-control for a device, with resource
+ * management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get(struct udevice *dev,
+ const char *mux_name);
+#else
+unsigned int mux_control_states(struct mux_control *mux)
+{
+ return -ENOSYS;
+}
+
+int __must_check mux_control_select(struct mux_control *mux,
+ unsigned int state)
+{
+ return -ENOSYS;
+}
+
+#define mux_control_try_select(mux) mux_control_select(mux)
+
+int mux_control_deselect(struct mux_control *mux)
+{
+ return -ENOSYS;
+}
+
+struct mux_control *mux_control_get(struct udevice *dev, const char *mux_name)
+{
+ return NULL;
+}
+
+void mux_control_put(struct mux_control *mux)
+{
+}
+
+struct mux_control *devm_mux_control_get(struct udevice *dev,
+ const char *mux_name)
+{
+ return NULL;
+}
+#endif
+
+#endif