From 8f3addf1b451784104ba3593d80702b4815d5a94 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 22 Aug 2017 08:27:08 +0200 Subject: mux: zap mux- prefix from the source files Preserve the module names with Makefile additions. Signed-off-by: Peter Rosin Signed-off-by: Greg Kroah-Hartman --- drivers/mux/Makefile | 5 + drivers/mux/adg792a.c | 157 +++++++++++++ drivers/mux/core.c | 547 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/mux/gpio.c | 114 ++++++++++ drivers/mux/mmio.c | 141 ++++++++++++ drivers/mux/mux-adg792a.c | 157 ------------- drivers/mux/mux-core.c | 547 ---------------------------------------------- drivers/mux/mux-gpio.c | 114 ---------- drivers/mux/mux-mmio.c | 141 ------------ 9 files changed, 964 insertions(+), 959 deletions(-) create mode 100644 drivers/mux/adg792a.c create mode 100644 drivers/mux/core.c create mode 100644 drivers/mux/gpio.c create mode 100644 drivers/mux/mmio.c delete mode 100644 drivers/mux/mux-adg792a.c delete mode 100644 drivers/mux/mux-core.c delete mode 100644 drivers/mux/mux-gpio.c delete mode 100644 drivers/mux/mux-mmio.c (limited to 'drivers/mux') diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile index 6bac5b0fea13..0e1e59760e3f 100644 --- a/drivers/mux/Makefile +++ b/drivers/mux/Makefile @@ -2,6 +2,11 @@ # Makefile for multiplexer devices. # +mux-core-objs := core.o +mux-adg792a-objs := adg792a.o +mux-gpio-objs := gpio.o +mux-mmio-objs := mmio.o + obj-$(CONFIG_MULTIPLEXER) += mux-core.o obj-$(CONFIG_MUX_ADG792A) += mux-adg792a.o obj-$(CONFIG_MUX_GPIO) += mux-gpio.o diff --git a/drivers/mux/adg792a.c b/drivers/mux/adg792a.c new file mode 100644 index 000000000000..12aa221ab90d --- /dev/null +++ b/drivers/mux/adg792a.c @@ -0,0 +1,157 @@ +/* + * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux + * + * Copyright (C) 2017 Axentia Technologies AB + * + * Author: Peter Rosin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define ADG792A_LDSW BIT(0) +#define ADG792A_RESETB BIT(1) +#define ADG792A_DISABLE(mux) (0x50 | (mux)) +#define ADG792A_DISABLE_ALL (0x5f) +#define ADG792A_MUX(mux, state) (0xc0 | (((mux) + 1) << 2) | (state)) +#define ADG792A_MUX_ALL(state) (0xc0 | (state)) + +static int adg792a_write_cmd(struct i2c_client *i2c, u8 cmd, int reset) +{ + u8 data = ADG792A_RESETB | ADG792A_LDSW; + + /* ADG792A_RESETB is active low, the chip resets when it is zero. */ + if (reset) + data &= ~ADG792A_RESETB; + + return i2c_smbus_write_byte_data(i2c, cmd, data); +} + +static int adg792a_set(struct mux_control *mux, int state) +{ + struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent); + u8 cmd; + + if (mux->chip->controllers == 1) { + /* parallel mux controller operation */ + if (state == MUX_IDLE_DISCONNECT) + cmd = ADG792A_DISABLE_ALL; + else + cmd = ADG792A_MUX_ALL(state); + } else { + unsigned int controller = mux_control_get_index(mux); + + if (state == MUX_IDLE_DISCONNECT) + cmd = ADG792A_DISABLE(controller); + else + cmd = ADG792A_MUX(controller, state); + } + + return adg792a_write_cmd(i2c, cmd, 0); +} + +static const struct mux_control_ops adg792a_ops = { + .set = adg792a_set, +}; + +static int adg792a_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct mux_chip *mux_chip; + s32 idle_state[3]; + u32 cells; + int ret; + int i; + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + ret = device_property_read_u32(dev, "#mux-control-cells", &cells); + if (ret < 0) + return ret; + if (cells >= 2) + return -EINVAL; + + mux_chip = devm_mux_chip_alloc(dev, cells ? 3 : 1, 0); + if (IS_ERR(mux_chip)) + return PTR_ERR(mux_chip); + + mux_chip->ops = &adg792a_ops; + + ret = adg792a_write_cmd(i2c, ADG792A_DISABLE_ALL, 1); + if (ret < 0) + return ret; + + ret = device_property_read_u32_array(dev, "idle-state", + (u32 *)idle_state, + mux_chip->controllers); + if (ret < 0) { + idle_state[0] = MUX_IDLE_AS_IS; + idle_state[1] = MUX_IDLE_AS_IS; + idle_state[2] = MUX_IDLE_AS_IS; + } + + for (i = 0; i < mux_chip->controllers; ++i) { + struct mux_control *mux = &mux_chip->mux[i]; + + mux->states = 4; + + switch (idle_state[i]) { + case MUX_IDLE_DISCONNECT: + case MUX_IDLE_AS_IS: + case 0 ... 4: + mux->idle_state = idle_state[i]; + break; + default: + dev_err(dev, "invalid idle-state %d\n", idle_state[i]); + return -EINVAL; + } + } + + ret = devm_mux_chip_register(dev, mux_chip); + if (ret < 0) + return ret; + + if (cells) + dev_info(dev, "3x single pole quadruple throw muxes registered\n"); + else + dev_info(dev, "triple pole quadruple throw mux registered\n"); + + return 0; +} + +static const struct i2c_device_id adg792a_id[] = { + { .name = "adg792a", }, + { .name = "adg792g", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adg792a_id); + +static const struct of_device_id adg792a_of_match[] = { + { .compatible = "adi,adg792a", }, + { .compatible = "adi,adg792g", }, + { } +}; +MODULE_DEVICE_TABLE(of, adg792a_of_match); + +static struct i2c_driver adg792a_driver = { + .driver = { + .name = "adg792a", + .of_match_table = of_match_ptr(adg792a_of_match), + }, + .probe = adg792a_probe, + .id_table = adg792a_id, +}; +module_i2c_driver(adg792a_driver); + +MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver"); +MODULE_AUTHOR("Peter Rosin "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mux/core.c b/drivers/mux/core.c new file mode 100644 index 000000000000..aabfb1549d4e --- /dev/null +++ b/drivers/mux/core.c @@ -0,0 +1,547 @@ +/* + * Multiplexer subsystem + * + * Copyright (C) 2017 Axentia Technologies AB + * + * Author: Peter Rosin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "mux-core: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The idle-as-is "state" is not an actual state that may be selected, it + * only implies that the state should not be changed. So, use that state + * as indication that the cached state of the multiplexer is unknown. + */ +#define MUX_CACHE_UNKNOWN MUX_IDLE_AS_IS + +static struct class mux_class = { + .name = "mux", + .owner = THIS_MODULE, +}; + +static DEFINE_IDA(mux_ida); + +static int __init mux_init(void) +{ + ida_init(&mux_ida); + return class_register(&mux_class); +} + +static void __exit mux_exit(void) +{ + class_unregister(&mux_class); + ida_destroy(&mux_ida); +} + +static void mux_chip_release(struct device *dev) +{ + struct mux_chip *mux_chip = to_mux_chip(dev); + + ida_simple_remove(&mux_ida, mux_chip->id); + kfree(mux_chip); +} + +static struct device_type mux_type = { + .name = "mux-chip", + .release = mux_chip_release, +}; + +/** + * mux_chip_alloc() - Allocate a mux-chip. + * @dev: The parent device implementing the mux interface. + * @controllers: The number of mux controllers to allocate for this chip. + * @sizeof_priv: Size of extra memory area for private use by the caller. + * + * After allocating the mux-chip with the desired number of mux controllers + * but before registering the chip, the mux driver is required to configure + * the number of valid mux states in the mux_chip->mux[N].states members and + * the desired idle state in the returned mux_chip->mux[N].idle_state members. + * The default idle state is MUX_IDLE_AS_IS. The mux driver also needs to + * provide a pointer to the operations struct in the mux_chip->ops member + * before registering the mux-chip with mux_chip_register. + * + * Return: A pointer to the new mux-chip, or an ERR_PTR with a negative errno. + */ +struct mux_chip *mux_chip_alloc(struct device *dev, + unsigned int controllers, size_t sizeof_priv) +{ + struct mux_chip *mux_chip; + int i; + + if (WARN_ON(!dev || !controllers)) + return ERR_PTR(-EINVAL); + + mux_chip = kzalloc(sizeof(*mux_chip) + + controllers * sizeof(*mux_chip->mux) + + sizeof_priv, GFP_KERNEL); + if (!mux_chip) + return ERR_PTR(-ENOMEM); + + mux_chip->mux = (struct mux_control *)(mux_chip + 1); + mux_chip->dev.class = &mux_class; + mux_chip->dev.type = &mux_type; + mux_chip->dev.parent = dev; + mux_chip->dev.of_node = dev->of_node; + dev_set_drvdata(&mux_chip->dev, mux_chip); + + mux_chip->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL); + if (mux_chip->id < 0) { + int err = mux_chip->id; + + pr_err("muxchipX failed to get a device id\n"); + kfree(mux_chip); + return ERR_PTR(err); + } + dev_set_name(&mux_chip->dev, "muxchip%d", mux_chip->id); + + mux_chip->controllers = controllers; + for (i = 0; i < controllers; ++i) { + struct mux_control *mux = &mux_chip->mux[i]; + + mux->chip = mux_chip; + sema_init(&mux->lock, 1); + mux->cached_state = MUX_CACHE_UNKNOWN; + mux->idle_state = MUX_IDLE_AS_IS; + } + + device_initialize(&mux_chip->dev); + + return mux_chip; +} +EXPORT_SYMBOL_GPL(mux_chip_alloc); + +static int mux_control_set(struct mux_control *mux, int state) +{ + int ret = mux->chip->ops->set(mux, state); + + mux->cached_state = ret < 0 ? MUX_CACHE_UNKNOWN : state; + + return ret; +} + +/** + * mux_chip_register() - Register a mux-chip, thus readying the controllers + * for use. + * @mux_chip: The mux-chip to register. + * + * Do not retry registration of the same mux-chip on failure. You should + * instead put it away with mux_chip_free() and allocate a new one, if you + * for some reason would like to retry registration. + * + * Return: Zero on success or a negative errno on error. + */ +int mux_chip_register(struct mux_chip *mux_chip) +{ + int i; + int ret; + + for (i = 0; i < mux_chip->controllers; ++i) { + struct mux_control *mux = &mux_chip->mux[i]; + + if (mux->idle_state == mux->cached_state) + continue; + + ret = mux_control_set(mux, mux->idle_state); + if (ret < 0) { + dev_err(&mux_chip->dev, "unable to set idle state\n"); + return ret; + } + } + + ret = device_add(&mux_chip->dev); + if (ret < 0) + dev_err(&mux_chip->dev, + "device_add failed in %s: %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL_GPL(mux_chip_register); + +/** + * mux_chip_unregister() - Take the mux-chip off-line. + * @mux_chip: The mux-chip to unregister. + * + * mux_chip_unregister() reverses the effects of mux_chip_register(). + * But not completely, you should not try to call mux_chip_register() + * on a mux-chip that has been registered before. + */ +void mux_chip_unregister(struct mux_chip *mux_chip) +{ + device_del(&mux_chip->dev); +} +EXPORT_SYMBOL_GPL(mux_chip_unregister); + +/** + * mux_chip_free() - Free the mux-chip for good. + * @mux_chip: The mux-chip to free. + * + * mux_chip_free() reverses the effects of mux_chip_alloc(). + */ +void mux_chip_free(struct mux_chip *mux_chip) +{ + if (!mux_chip) + return; + + put_device(&mux_chip->dev); +} +EXPORT_SYMBOL_GPL(mux_chip_free); + +static void devm_mux_chip_release(struct device *dev, void *res) +{ + struct mux_chip *mux_chip = *(struct mux_chip **)res; + + mux_chip_free(mux_chip); +} + +/** + * devm_mux_chip_alloc() - Resource-managed version of mux_chip_alloc(). + * @dev: The parent device implementing the mux interface. + * @controllers: The number of mux controllers to allocate for this chip. + * @sizeof_priv: Size of extra memory area for private use by the caller. + * + * See mux_chip_alloc() for more details. + * + * Return: A pointer to the new mux-chip, or an ERR_PTR with a negative errno. + */ +struct mux_chip *devm_mux_chip_alloc(struct device *dev, + unsigned int controllers, + size_t sizeof_priv) +{ + struct mux_chip **ptr, *mux_chip; + + ptr = devres_alloc(devm_mux_chip_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + mux_chip = mux_chip_alloc(dev, controllers, sizeof_priv); + if (IS_ERR(mux_chip)) { + devres_free(ptr); + return mux_chip; + } + + *ptr = mux_chip; + devres_add(dev, ptr); + + return mux_chip; +} +EXPORT_SYMBOL_GPL(devm_mux_chip_alloc); + +static void devm_mux_chip_reg_release(struct device *dev, void *res) +{ + struct mux_chip *mux_chip = *(struct mux_chip **)res; + + mux_chip_unregister(mux_chip); +} + +/** + * devm_mux_chip_register() - Resource-managed version mux_chip_register(). + * @dev: The parent device implementing the mux interface. + * @mux_chip: The mux-chip to register. + * + * See mux_chip_register() for more details. + * + * Return: Zero on success or a negative errno on error. + */ +int devm_mux_chip_register(struct device *dev, + struct mux_chip *mux_chip) +{ + struct mux_chip **ptr; + int res; + + ptr = devres_alloc(devm_mux_chip_reg_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + res = mux_chip_register(mux_chip); + if (res) { + devres_free(ptr); + return res; + } + + *ptr = mux_chip; + devres_add(dev, ptr); + + return res; +} +EXPORT_SYMBOL_GPL(devm_mux_chip_register); + +/** + * 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) +{ + return mux->states; +} +EXPORT_SYMBOL_GPL(mux_control_states); + +/* + * The mux->lock must be down when calling this function. + */ +static int __mux_control_select(struct mux_control *mux, int state) +{ + int ret; + + if (WARN_ON(state < 0 || state >= mux->states)) + return -EINVAL; + + if (mux->cached_state == state) + return 0; + + ret = mux_control_set(mux, state); + if (ret >= 0) + return 0; + + /* The mux update failed, try to revert if appropriate... */ + if (mux->idle_state != MUX_IDLE_AS_IS) + mux_control_set(mux, mux->idle_state); + + return ret; +} + +/** + * 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 caller will be blocked + * until mux_control_deselect() is called (by someone else). + * + * 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 mux_control_select(struct mux_control *mux, unsigned int state) +{ + int ret; + + ret = down_killable(&mux->lock); + if (ret < 0) + return ret; + + ret = __mux_control_select(mux, state); + + if (ret < 0) + up(&mux->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(mux_control_select); + +/** + * mux_control_try_select() - Try to 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 + * mux_control_deselect() called. + * + * 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_try_select() fails. + * + * Return: 0 when the mux-control state has the requested state or a negative + * errno on error. Specifically -EBUSY if the mux-control is contended. + */ +int mux_control_try_select(struct mux_control *mux, unsigned int state) +{ + int ret; + + if (down_trylock(&mux->lock)) + return -EBUSY; + + ret = __mux_control_select(mux, state); + + if (ret < 0) + up(&mux->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(mux_control_try_select); + +/** + * 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) +{ + int ret = 0; + + if (mux->idle_state != MUX_IDLE_AS_IS && + mux->idle_state != mux->cached_state) + ret = mux_control_set(mux, mux->idle_state); + + up(&mux->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(mux_control_deselect); + +static int of_dev_node_match(struct device *dev, const void *data) +{ + return dev->of_node == data; +} + +static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np) +{ + struct device *dev; + + dev = class_find_device(&mux_class, NULL, np, of_dev_node_match); + + return dev ? to_mux_chip(dev) : NULL; +} + +/** + * 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. + * + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno. + */ +struct mux_control *mux_control_get(struct device *dev, const char *mux_name) +{ + struct device_node *np = dev->of_node; + struct of_phandle_args args; + struct mux_chip *mux_chip; + unsigned int controller; + int index = 0; + int ret; + + if (mux_name) { + index = of_property_match_string(np, "mux-control-names", + mux_name); + if (index < 0) { + dev_err(dev, "mux controller '%s' not found\n", + mux_name); + return ERR_PTR(index); + } + } + + ret = of_parse_phandle_with_args(np, + "mux-controls", "#mux-control-cells", + index, &args); + if (ret) { + dev_err(dev, "%pOF: failed to get mux-control %s(%i)\n", + np, mux_name ?: "", index); + return ERR_PTR(ret); + } + + mux_chip = of_find_mux_chip_by_node(args.np); + of_node_put(args.np); + if (!mux_chip) + return ERR_PTR(-EPROBE_DEFER); + + if (args.args_count > 1 || + (!args.args_count && (mux_chip->controllers > 1))) { + dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n", + np, args.np); + return ERR_PTR(-EINVAL); + } + + controller = 0; + if (args.args_count) + controller = args.args[0]; + + if (controller >= mux_chip->controllers) { + dev_err(dev, "%pOF: bad mux controller %u specified in %pOF\n", + np, controller, args.np); + return ERR_PTR(-EINVAL); + } + + get_device(&mux_chip->dev); + return &mux_chip->mux[controller]; +} +EXPORT_SYMBOL_GPL(mux_control_get); + +/** + * 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) +{ + put_device(&mux->chip->dev); +} +EXPORT_SYMBOL_GPL(mux_control_put); + +static void devm_mux_control_release(struct device *dev, void *res) +{ + struct mux_control *mux = *(struct mux_control **)res; + + mux_control_put(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 device *dev, + const char *mux_name) +{ + struct mux_control **ptr, *mux; + + ptr = devres_alloc(devm_mux_control_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + mux = mux_control_get(dev, mux_name); + if (IS_ERR(mux)) { + devres_free(ptr); + return mux; + } + + *ptr = mux; + devres_add(dev, ptr); + + return mux; +} +EXPORT_SYMBOL_GPL(devm_mux_control_get); + +/* + * Using subsys_initcall instead of module_init here to try to ensure - for + * the non-modular case - that the subsystem is initialized when mux consumers + * and mux controllers start to use it. + * For the modular case, the ordering is ensured with module dependencies. + */ +subsys_initcall(mux_init); +module_exit(mux_exit); + +MODULE_DESCRIPTION("Multiplexer subsystem"); +MODULE_AUTHOR("Peter Rosin "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c new file mode 100644 index 000000000000..468bf1709606 --- /dev/null +++ b/drivers/mux/gpio.c @@ -0,0 +1,114 @@ +/* + * GPIO-controlled multiplexer driver + * + * Copyright (C) 2017 Axentia Technologies AB + * + * Author: Peter Rosin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct mux_gpio { + struct gpio_descs *gpios; + int *val; +}; + +static int mux_gpio_set(struct mux_control *mux, int state) +{ + struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip); + int i; + + for (i = 0; i < mux_gpio->gpios->ndescs; i++) + mux_gpio->val[i] = (state >> i) & 1; + + gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, + mux_gpio->gpios->desc, + mux_gpio->val); + + return 0; +} + +static const struct mux_control_ops mux_gpio_ops = { + .set = mux_gpio_set, +}; + +static const struct of_device_id mux_gpio_dt_ids[] = { + { .compatible = "gpio-mux", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids); + +static int mux_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mux_chip *mux_chip; + struct mux_gpio *mux_gpio; + int pins; + s32 idle_state; + int ret; + + pins = gpiod_count(dev, "mux"); + if (pins < 0) + return pins; + + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) + + pins * sizeof(*mux_gpio->val)); + if (IS_ERR(mux_chip)) + return PTR_ERR(mux_chip); + + mux_gpio = mux_chip_priv(mux_chip); + mux_gpio->val = (int *)(mux_gpio + 1); + mux_chip->ops = &mux_gpio_ops; + + mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW); + if (IS_ERR(mux_gpio->gpios)) { + ret = PTR_ERR(mux_gpio->gpios); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get gpios\n"); + return ret; + } + WARN_ON(pins != mux_gpio->gpios->ndescs); + mux_chip->mux->states = 1 << pins; + + ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state); + if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) { + if (idle_state < 0 || idle_state >= mux_chip->mux->states) { + dev_err(dev, "invalid idle-state %u\n", idle_state); + return -EINVAL; + } + + mux_chip->mux->idle_state = idle_state; + } + + ret = devm_mux_chip_register(dev, mux_chip); + if (ret < 0) + return ret; + + dev_info(dev, "%u-way mux-controller registered\n", + mux_chip->mux->states); + + return 0; +} + +static struct platform_driver mux_gpio_driver = { + .driver = { + .name = "gpio-mux", + .of_match_table = of_match_ptr(mux_gpio_dt_ids), + }, + .probe = mux_gpio_probe, +}; +module_platform_driver(mux_gpio_driver); + +MODULE_DESCRIPTION("GPIO-controlled multiplexer driver"); +MODULE_AUTHOR("Peter Rosin "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mux/mmio.c b/drivers/mux/mmio.c new file mode 100644 index 000000000000..37c1de359a70 --- /dev/null +++ b/drivers/mux/mmio.c @@ -0,0 +1,141 @@ +/* + * MMIO register bitfield-controlled multiplexer driver + * + * Copyright (C) 2017 Pengutronix, Philipp Zabel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int mux_mmio_set(struct mux_control *mux, int state) +{ + struct regmap_field **fields = mux_chip_priv(mux->chip); + + return regmap_field_write(fields[mux_control_get_index(mux)], state); +} + +static const struct mux_control_ops mux_mmio_ops = { + .set = mux_mmio_set, +}; + +static const struct of_device_id mux_mmio_dt_ids[] = { + { .compatible = "mmio-mux", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids); + +static int mux_mmio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct regmap_field **fields; + struct mux_chip *mux_chip; + struct regmap *regmap; + int num_fields; + int ret; + int i; + + regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(dev, "failed to get regmap: %d\n", ret); + return ret; + } + + ret = of_property_count_u32_elems(np, "mux-reg-masks"); + if (ret == 0 || ret % 2) + ret = -EINVAL; + if (ret < 0) { + dev_err(dev, "mux-reg-masks property missing or invalid: %d\n", + ret); + return ret; + } + num_fields = ret / 2; + + mux_chip = devm_mux_chip_alloc(dev, num_fields, num_fields * + sizeof(*fields)); + if (IS_ERR(mux_chip)) + return PTR_ERR(mux_chip); + + fields = mux_chip_priv(mux_chip); + + for (i = 0; i < num_fields; i++) { + struct mux_control *mux = &mux_chip->mux[i]; + struct reg_field field; + s32 idle_state = MUX_IDLE_AS_IS; + u32 reg, mask; + int bits; + + ret = of_property_read_u32_index(np, "mux-reg-masks", + 2 * i, ®); + if (!ret) + ret = of_property_read_u32_index(np, "mux-reg-masks", + 2 * i + 1, &mask); + if (ret < 0) { + dev_err(dev, "bitfield %d: failed to read mux-reg-masks property: %d\n", + i, ret); + return ret; + } + + field.reg = reg; + field.msb = fls(mask) - 1; + field.lsb = ffs(mask) - 1; + + if (mask != GENMASK(field.msb, field.lsb)) { + dev_err(dev, "bitfield %d: invalid mask 0x%x\n", + i, mask); + return -EINVAL; + } + + fields[i] = devm_regmap_field_alloc(dev, regmap, field); + if (IS_ERR(fields[i])) { + ret = PTR_ERR(fields[i]); + dev_err(dev, "bitfield %d: failed allocate: %d\n", + i, ret); + return ret; + } + + bits = 1 + field.msb - field.lsb; + mux->states = 1 << bits; + + of_property_read_u32_index(np, "idle-states", i, + (u32 *)&idle_state); + if (idle_state != MUX_IDLE_AS_IS) { + if (idle_state < 0 || idle_state >= mux->states) { + dev_err(dev, "bitfield: %d: out of range idle state %d\n", + i, idle_state); + return -EINVAL; + } + + mux->idle_state = idle_state; + } + } + + mux_chip->ops = &mux_mmio_ops; + + return devm_mux_chip_register(dev, mux_chip); +} + +static struct platform_driver mux_mmio_driver = { + .driver = { + .name = "mmio-mux", + .of_match_table = of_match_ptr(mux_mmio_dt_ids), + }, + .probe = mux_mmio_probe, +}; +module_platform_driver(mux_mmio_driver); + +MODULE_DESCRIPTION("MMIO register bitfield-controlled multiplexer driver"); +MODULE_AUTHOR("Philipp Zabel "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mux/mux-adg792a.c b/drivers/mux/mux-adg792a.c deleted file mode 100644 index 12aa221ab90d..000000000000 --- a/drivers/mux/mux-adg792a.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux - * - * Copyright (C) 2017 Axentia Technologies AB - * - * Author: Peter Rosin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#define ADG792A_LDSW BIT(0) -#define ADG792A_RESETB BIT(1) -#define ADG792A_DISABLE(mux) (0x50 | (mux)) -#define ADG792A_DISABLE_ALL (0x5f) -#define ADG792A_MUX(mux, state) (0xc0 | (((mux) + 1) << 2) | (state)) -#define ADG792A_MUX_ALL(state) (0xc0 | (state)) - -static int adg792a_write_cmd(struct i2c_client *i2c, u8 cmd, int reset) -{ - u8 data = ADG792A_RESETB | ADG792A_LDSW; - - /* ADG792A_RESETB is active low, the chip resets when it is zero. */ - if (reset) - data &= ~ADG792A_RESETB; - - return i2c_smbus_write_byte_data(i2c, cmd, data); -} - -static int adg792a_set(struct mux_control *mux, int state) -{ - struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent); - u8 cmd; - - if (mux->chip->controllers == 1) { - /* parallel mux controller operation */ - if (state == MUX_IDLE_DISCONNECT) - cmd = ADG792A_DISABLE_ALL; - else - cmd = ADG792A_MUX_ALL(state); - } else { - unsigned int controller = mux_control_get_index(mux); - - if (state == MUX_IDLE_DISCONNECT) - cmd = ADG792A_DISABLE(controller); - else - cmd = ADG792A_MUX(controller, state); - } - - return adg792a_write_cmd(i2c, cmd, 0); -} - -static const struct mux_control_ops adg792a_ops = { - .set = adg792a_set, -}; - -static int adg792a_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct device *dev = &i2c->dev; - struct mux_chip *mux_chip; - s32 idle_state[3]; - u32 cells; - int ret; - int i; - - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - ret = device_property_read_u32(dev, "#mux-control-cells", &cells); - if (ret < 0) - return ret; - if (cells >= 2) - return -EINVAL; - - mux_chip = devm_mux_chip_alloc(dev, cells ? 3 : 1, 0); - if (IS_ERR(mux_chip)) - return PTR_ERR(mux_chip); - - mux_chip->ops = &adg792a_ops; - - ret = adg792a_write_cmd(i2c, ADG792A_DISABLE_ALL, 1); - if (ret < 0) - return ret; - - ret = device_property_read_u32_array(dev, "idle-state", - (u32 *)idle_state, - mux_chip->controllers); - if (ret < 0) { - idle_state[0] = MUX_IDLE_AS_IS; - idle_state[1] = MUX_IDLE_AS_IS; - idle_state[2] = MUX_IDLE_AS_IS; - } - - for (i = 0; i < mux_chip->controllers; ++i) { - struct mux_control *mux = &mux_chip->mux[i]; - - mux->states = 4; - - switch (idle_state[i]) { - case MUX_IDLE_DISCONNECT: - case MUX_IDLE_AS_IS: - case 0 ... 4: - mux->idle_state = idle_state[i]; - break; - default: - dev_err(dev, "invalid idle-state %d\n", idle_state[i]); - return -EINVAL; - } - } - - ret = devm_mux_chip_register(dev, mux_chip); - if (ret < 0) - return ret; - - if (cells) - dev_info(dev, "3x single pole quadruple throw muxes registered\n"); - else - dev_info(dev, "triple pole quadruple throw mux registered\n"); - - return 0; -} - -static const struct i2c_device_id adg792a_id[] = { - { .name = "adg792a", }, - { .name = "adg792g", }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adg792a_id); - -static const struct of_device_id adg792a_of_match[] = { - { .compatible = "adi,adg792a", }, - { .compatible = "adi,adg792g", }, - { } -}; -MODULE_DEVICE_TABLE(of, adg792a_of_match); - -static struct i2c_driver adg792a_driver = { - .driver = { - .name = "adg792a", - .of_match_table = of_match_ptr(adg792a_of_match), - }, - .probe = adg792a_probe, - .id_table = adg792a_id, -}; -module_i2c_driver(adg792a_driver); - -MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver"); -MODULE_AUTHOR("Peter Rosin "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c deleted file mode 100644 index aabfb1549d4e..000000000000 --- a/drivers/mux/mux-core.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * Multiplexer subsystem - * - * Copyright (C) 2017 Axentia Technologies AB - * - * Author: Peter Rosin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#define pr_fmt(fmt) "mux-core: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The idle-as-is "state" is not an actual state that may be selected, it - * only implies that the state should not be changed. So, use that state - * as indication that the cached state of the multiplexer is unknown. - */ -#define MUX_CACHE_UNKNOWN MUX_IDLE_AS_IS - -static struct class mux_class = { - .name = "mux", - .owner = THIS_MODULE, -}; - -static DEFINE_IDA(mux_ida); - -static int __init mux_init(void) -{ - ida_init(&mux_ida); - return class_register(&mux_class); -} - -static void __exit mux_exit(void) -{ - class_unregister(&mux_class); - ida_destroy(&mux_ida); -} - -static void mux_chip_release(struct device *dev) -{ - struct mux_chip *mux_chip = to_mux_chip(dev); - - ida_simple_remove(&mux_ida, mux_chip->id); - kfree(mux_chip); -} - -static struct device_type mux_type = { - .name = "mux-chip", - .release = mux_chip_release, -}; - -/** - * mux_chip_alloc() - Allocate a mux-chip. - * @dev: The parent device implementing the mux interface. - * @controllers: The number of mux controllers to allocate for this chip. - * @sizeof_priv: Size of extra memory area for private use by the caller. - * - * After allocating the mux-chip with the desired number of mux controllers - * but before registering the chip, the mux driver is required to configure - * the number of valid mux states in the mux_chip->mux[N].states members and - * the desired idle state in the returned mux_chip->mux[N].idle_state members. - * The default idle state is MUX_IDLE_AS_IS. The mux driver also needs to - * provide a pointer to the operations struct in the mux_chip->ops member - * before registering the mux-chip with mux_chip_register. - * - * Return: A pointer to the new mux-chip, or an ERR_PTR with a negative errno. - */ -struct mux_chip *mux_chip_alloc(struct device *dev, - unsigned int controllers, size_t sizeof_priv) -{ - struct mux_chip *mux_chip; - int i; - - if (WARN_ON(!dev || !controllers)) - return ERR_PTR(-EINVAL); - - mux_chip = kzalloc(sizeof(*mux_chip) + - controllers * sizeof(*mux_chip->mux) + - sizeof_priv, GFP_KERNEL); - if (!mux_chip) - return ERR_PTR(-ENOMEM); - - mux_chip->mux = (struct mux_control *)(mux_chip + 1); - mux_chip->dev.class = &mux_class; - mux_chip->dev.type = &mux_type; - mux_chip->dev.parent = dev; - mux_chip->dev.of_node = dev->of_node; - dev_set_drvdata(&mux_chip->dev, mux_chip); - - mux_chip->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL); - if (mux_chip->id < 0) { - int err = mux_chip->id; - - pr_err("muxchipX failed to get a device id\n"); - kfree(mux_chip); - return ERR_PTR(err); - } - dev_set_name(&mux_chip->dev, "muxchip%d", mux_chip->id); - - mux_chip->controllers = controllers; - for (i = 0; i < controllers; ++i) { - struct mux_control *mux = &mux_chip->mux[i]; - - mux->chip = mux_chip; - sema_init(&mux->lock, 1); - mux->cached_state = MUX_CACHE_UNKNOWN; - mux->idle_state = MUX_IDLE_AS_IS; - } - - device_initialize(&mux_chip->dev); - - return mux_chip; -} -EXPORT_SYMBOL_GPL(mux_chip_alloc); - -static int mux_control_set(struct mux_control *mux, int state) -{ - int ret = mux->chip->ops->set(mux, state); - - mux->cached_state = ret < 0 ? MUX_CACHE_UNKNOWN : state; - - return ret; -} - -/** - * mux_chip_register() - Register a mux-chip, thus readying the controllers - * for use. - * @mux_chip: The mux-chip to register. - * - * Do not retry registration of the same mux-chip on failure. You should - * instead put it away with mux_chip_free() and allocate a new one, if you - * for some reason would like to retry registration. - * - * Return: Zero on success or a negative errno on error. - */ -int mux_chip_register(struct mux_chip *mux_chip) -{ - int i; - int ret; - - for (i = 0; i < mux_chip->controllers; ++i) { - struct mux_control *mux = &mux_chip->mux[i]; - - if (mux->idle_state == mux->cached_state) - continue; - - ret = mux_control_set(mux, mux->idle_state); - if (ret < 0) { - dev_err(&mux_chip->dev, "unable to set idle state\n"); - return ret; - } - } - - ret = device_add(&mux_chip->dev); - if (ret < 0) - dev_err(&mux_chip->dev, - "device_add failed in %s: %d\n", __func__, ret); - return ret; -} -EXPORT_SYMBOL_GPL(mux_chip_register); - -/** - * mux_chip_unregister() - Take the mux-chip off-line. - * @mux_chip: The mux-chip to unregister. - * - * mux_chip_unregister() reverses the effects of mux_chip_register(). - * But not completely, you should not try to call mux_chip_register() - * on a mux-chip that has been registered before. - */ -void mux_chip_unregister(struct mux_chip *mux_chip) -{ - device_del(&mux_chip->dev); -} -EXPORT_SYMBOL_GPL(mux_chip_unregister); - -/** - * mux_chip_free() - Free the mux-chip for good. - * @mux_chip: The mux-chip to free. - * - * mux_chip_free() reverses the effects of mux_chip_alloc(). - */ -void mux_chip_free(struct mux_chip *mux_chip) -{ - if (!mux_chip) - return; - - put_device(&mux_chip->dev); -} -EXPORT_SYMBOL_GPL(mux_chip_free); - -static void devm_mux_chip_release(struct device *dev, void *res) -{ - struct mux_chip *mux_chip = *(struct mux_chip **)res; - - mux_chip_free(mux_chip); -} - -/** - * devm_mux_chip_alloc() - Resource-managed version of mux_chip_alloc(). - * @dev: The parent device implementing the mux interface. - * @controllers: The number of mux controllers to allocate for this chip. - * @sizeof_priv: Size of extra memory area for private use by the caller. - * - * See mux_chip_alloc() for more details. - * - * Return: A pointer to the new mux-chip, or an ERR_PTR with a negative errno. - */ -struct mux_chip *devm_mux_chip_alloc(struct device *dev, - unsigned int controllers, - size_t sizeof_priv) -{ - struct mux_chip **ptr, *mux_chip; - - ptr = devres_alloc(devm_mux_chip_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - mux_chip = mux_chip_alloc(dev, controllers, sizeof_priv); - if (IS_ERR(mux_chip)) { - devres_free(ptr); - return mux_chip; - } - - *ptr = mux_chip; - devres_add(dev, ptr); - - return mux_chip; -} -EXPORT_SYMBOL_GPL(devm_mux_chip_alloc); - -static void devm_mux_chip_reg_release(struct device *dev, void *res) -{ - struct mux_chip *mux_chip = *(struct mux_chip **)res; - - mux_chip_unregister(mux_chip); -} - -/** - * devm_mux_chip_register() - Resource-managed version mux_chip_register(). - * @dev: The parent device implementing the mux interface. - * @mux_chip: The mux-chip to register. - * - * See mux_chip_register() for more details. - * - * Return: Zero on success or a negative errno on error. - */ -int devm_mux_chip_register(struct device *dev, - struct mux_chip *mux_chip) -{ - struct mux_chip **ptr; - int res; - - ptr = devres_alloc(devm_mux_chip_reg_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - res = mux_chip_register(mux_chip); - if (res) { - devres_free(ptr); - return res; - } - - *ptr = mux_chip; - devres_add(dev, ptr); - - return res; -} -EXPORT_SYMBOL_GPL(devm_mux_chip_register); - -/** - * 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) -{ - return mux->states; -} -EXPORT_SYMBOL_GPL(mux_control_states); - -/* - * The mux->lock must be down when calling this function. - */ -static int __mux_control_select(struct mux_control *mux, int state) -{ - int ret; - - if (WARN_ON(state < 0 || state >= mux->states)) - return -EINVAL; - - if (mux->cached_state == state) - return 0; - - ret = mux_control_set(mux, state); - if (ret >= 0) - return 0; - - /* The mux update failed, try to revert if appropriate... */ - if (mux->idle_state != MUX_IDLE_AS_IS) - mux_control_set(mux, mux->idle_state); - - return ret; -} - -/** - * 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 caller will be blocked - * until mux_control_deselect() is called (by someone else). - * - * 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 mux_control_select(struct mux_control *mux, unsigned int state) -{ - int ret; - - ret = down_killable(&mux->lock); - if (ret < 0) - return ret; - - ret = __mux_control_select(mux, state); - - if (ret < 0) - up(&mux->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(mux_control_select); - -/** - * mux_control_try_select() - Try to 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 - * mux_control_deselect() called. - * - * 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_try_select() fails. - * - * Return: 0 when the mux-control state has the requested state or a negative - * errno on error. Specifically -EBUSY if the mux-control is contended. - */ -int mux_control_try_select(struct mux_control *mux, unsigned int state) -{ - int ret; - - if (down_trylock(&mux->lock)) - return -EBUSY; - - ret = __mux_control_select(mux, state); - - if (ret < 0) - up(&mux->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(mux_control_try_select); - -/** - * 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) -{ - int ret = 0; - - if (mux->idle_state != MUX_IDLE_AS_IS && - mux->idle_state != mux->cached_state) - ret = mux_control_set(mux, mux->idle_state); - - up(&mux->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(mux_control_deselect); - -static int of_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - -static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np) -{ - struct device *dev; - - dev = class_find_device(&mux_class, NULL, np, of_dev_node_match); - - return dev ? to_mux_chip(dev) : NULL; -} - -/** - * 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. - * - * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno. - */ -struct mux_control *mux_control_get(struct device *dev, const char *mux_name) -{ - struct device_node *np = dev->of_node; - struct of_phandle_args args; - struct mux_chip *mux_chip; - unsigned int controller; - int index = 0; - int ret; - - if (mux_name) { - index = of_property_match_string(np, "mux-control-names", - mux_name); - if (index < 0) { - dev_err(dev, "mux controller '%s' not found\n", - mux_name); - return ERR_PTR(index); - } - } - - ret = of_parse_phandle_with_args(np, - "mux-controls", "#mux-control-cells", - index, &args); - if (ret) { - dev_err(dev, "%pOF: failed to get mux-control %s(%i)\n", - np, mux_name ?: "", index); - return ERR_PTR(ret); - } - - mux_chip = of_find_mux_chip_by_node(args.np); - of_node_put(args.np); - if (!mux_chip) - return ERR_PTR(-EPROBE_DEFER); - - if (args.args_count > 1 || - (!args.args_count && (mux_chip->controllers > 1))) { - dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n", - np, args.np); - return ERR_PTR(-EINVAL); - } - - controller = 0; - if (args.args_count) - controller = args.args[0]; - - if (controller >= mux_chip->controllers) { - dev_err(dev, "%pOF: bad mux controller %u specified in %pOF\n", - np, controller, args.np); - return ERR_PTR(-EINVAL); - } - - get_device(&mux_chip->dev); - return &mux_chip->mux[controller]; -} -EXPORT_SYMBOL_GPL(mux_control_get); - -/** - * 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) -{ - put_device(&mux->chip->dev); -} -EXPORT_SYMBOL_GPL(mux_control_put); - -static void devm_mux_control_release(struct device *dev, void *res) -{ - struct mux_control *mux = *(struct mux_control **)res; - - mux_control_put(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 device *dev, - const char *mux_name) -{ - struct mux_control **ptr, *mux; - - ptr = devres_alloc(devm_mux_control_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - mux = mux_control_get(dev, mux_name); - if (IS_ERR(mux)) { - devres_free(ptr); - return mux; - } - - *ptr = mux; - devres_add(dev, ptr); - - return mux; -} -EXPORT_SYMBOL_GPL(devm_mux_control_get); - -/* - * Using subsys_initcall instead of module_init here to try to ensure - for - * the non-modular case - that the subsystem is initialized when mux consumers - * and mux controllers start to use it. - * For the modular case, the ordering is ensured with module dependencies. - */ -subsys_initcall(mux_init); -module_exit(mux_exit); - -MODULE_DESCRIPTION("Multiplexer subsystem"); -MODULE_AUTHOR("Peter Rosin "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c deleted file mode 100644 index 468bf1709606..000000000000 --- a/drivers/mux/mux-gpio.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * GPIO-controlled multiplexer driver - * - * Copyright (C) 2017 Axentia Technologies AB - * - * Author: Peter Rosin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -struct mux_gpio { - struct gpio_descs *gpios; - int *val; -}; - -static int mux_gpio_set(struct mux_control *mux, int state) -{ - struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip); - int i; - - for (i = 0; i < mux_gpio->gpios->ndescs; i++) - mux_gpio->val[i] = (state >> i) & 1; - - gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, - mux_gpio->gpios->desc, - mux_gpio->val); - - return 0; -} - -static const struct mux_control_ops mux_gpio_ops = { - .set = mux_gpio_set, -}; - -static const struct of_device_id mux_gpio_dt_ids[] = { - { .compatible = "gpio-mux", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids); - -static int mux_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mux_chip *mux_chip; - struct mux_gpio *mux_gpio; - int pins; - s32 idle_state; - int ret; - - pins = gpiod_count(dev, "mux"); - if (pins < 0) - return pins; - - mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) + - pins * sizeof(*mux_gpio->val)); - if (IS_ERR(mux_chip)) - return PTR_ERR(mux_chip); - - mux_gpio = mux_chip_priv(mux_chip); - mux_gpio->val = (int *)(mux_gpio + 1); - mux_chip->ops = &mux_gpio_ops; - - mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW); - if (IS_ERR(mux_gpio->gpios)) { - ret = PTR_ERR(mux_gpio->gpios); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get gpios\n"); - return ret; - } - WARN_ON(pins != mux_gpio->gpios->ndescs); - mux_chip->mux->states = 1 << pins; - - ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state); - if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) { - if (idle_state < 0 || idle_state >= mux_chip->mux->states) { - dev_err(dev, "invalid idle-state %u\n", idle_state); - return -EINVAL; - } - - mux_chip->mux->idle_state = idle_state; - } - - ret = devm_mux_chip_register(dev, mux_chip); - if (ret < 0) - return ret; - - dev_info(dev, "%u-way mux-controller registered\n", - mux_chip->mux->states); - - return 0; -} - -static struct platform_driver mux_gpio_driver = { - .driver = { - .name = "gpio-mux", - .of_match_table = of_match_ptr(mux_gpio_dt_ids), - }, - .probe = mux_gpio_probe, -}; -module_platform_driver(mux_gpio_driver); - -MODULE_DESCRIPTION("GPIO-controlled multiplexer driver"); -MODULE_AUTHOR("Peter Rosin "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mux/mux-mmio.c b/drivers/mux/mux-mmio.c deleted file mode 100644 index 37c1de359a70..000000000000 --- a/drivers/mux/mux-mmio.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * MMIO register bitfield-controlled multiplexer driver - * - * Copyright (C) 2017 Pengutronix, Philipp Zabel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int mux_mmio_set(struct mux_control *mux, int state) -{ - struct regmap_field **fields = mux_chip_priv(mux->chip); - - return regmap_field_write(fields[mux_control_get_index(mux)], state); -} - -static const struct mux_control_ops mux_mmio_ops = { - .set = mux_mmio_set, -}; - -static const struct of_device_id mux_mmio_dt_ids[] = { - { .compatible = "mmio-mux", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids); - -static int mux_mmio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct regmap_field **fields; - struct mux_chip *mux_chip; - struct regmap *regmap; - int num_fields; - int ret; - int i; - - regmap = syscon_node_to_regmap(np->parent); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - dev_err(dev, "failed to get regmap: %d\n", ret); - return ret; - } - - ret = of_property_count_u32_elems(np, "mux-reg-masks"); - if (ret == 0 || ret % 2) - ret = -EINVAL; - if (ret < 0) { - dev_err(dev, "mux-reg-masks property missing or invalid: %d\n", - ret); - return ret; - } - num_fields = ret / 2; - - mux_chip = devm_mux_chip_alloc(dev, num_fields, num_fields * - sizeof(*fields)); - if (IS_ERR(mux_chip)) - return PTR_ERR(mux_chip); - - fields = mux_chip_priv(mux_chip); - - for (i = 0; i < num_fields; i++) { - struct mux_control *mux = &mux_chip->mux[i]; - struct reg_field field; - s32 idle_state = MUX_IDLE_AS_IS; - u32 reg, mask; - int bits; - - ret = of_property_read_u32_index(np, "mux-reg-masks", - 2 * i, ®); - if (!ret) - ret = of_property_read_u32_index(np, "mux-reg-masks", - 2 * i + 1, &mask); - if (ret < 0) { - dev_err(dev, "bitfield %d: failed to read mux-reg-masks property: %d\n", - i, ret); - return ret; - } - - field.reg = reg; - field.msb = fls(mask) - 1; - field.lsb = ffs(mask) - 1; - - if (mask != GENMASK(field.msb, field.lsb)) { - dev_err(dev, "bitfield %d: invalid mask 0x%x\n", - i, mask); - return -EINVAL; - } - - fields[i] = devm_regmap_field_alloc(dev, regmap, field); - if (IS_ERR(fields[i])) { - ret = PTR_ERR(fields[i]); - dev_err(dev, "bitfield %d: failed allocate: %d\n", - i, ret); - return ret; - } - - bits = 1 + field.msb - field.lsb; - mux->states = 1 << bits; - - of_property_read_u32_index(np, "idle-states", i, - (u32 *)&idle_state); - if (idle_state != MUX_IDLE_AS_IS) { - if (idle_state < 0 || idle_state >= mux->states) { - dev_err(dev, "bitfield: %d: out of range idle state %d\n", - i, idle_state); - return -EINVAL; - } - - mux->idle_state = idle_state; - } - } - - mux_chip->ops = &mux_mmio_ops; - - return devm_mux_chip_register(dev, mux_chip); -} - -static struct platform_driver mux_mmio_driver = { - .driver = { - .name = "mmio-mux", - .of_match_table = of_match_ptr(mux_mmio_dt_ids), - }, - .probe = mux_mmio_probe, -}; -module_platform_driver(mux_mmio_driver); - -MODULE_DESCRIPTION("MMIO register bitfield-controlled multiplexer driver"); -MODULE_AUTHOR("Philipp Zabel "); -MODULE_LICENSE("GPL v2"); -- cgit