-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mux: gpio: add mux controller driver for gpio based multiplexers
The driver builds a single multiplexer controller using a number of gpio pins. For N pins, there will be 2^N possible multiplexer states. The GPIO pins can be connected (by the hardware) to several multiplexers, which in that case will be operated in parallel. Reviewed-by: Jonathan Cameron <jic23@kernel.org> Signed-off-by: Peter Rosin <peda@axentia.se> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- Loading branch information
Peter Rosin
authored and
Greg Kroah-Hartman
committed
Jun 3, 2017
1 parent
a3b02a9
commit 2c089f0
Showing
3 changed files
with
133 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
# | ||
|
||
obj-$(CONFIG_MULTIPLEXER) += mux-core.o | ||
obj-$(CONFIG_MUX_GPIO) += mux-gpio.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* GPIO-controlled multiplexer driver | ||
* | ||
* Copyright (C) 2017 Axentia Technologies AB | ||
* | ||
* Author: Peter Rosin <peda@axentia.se> | ||
* | ||
* 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 <linux/err.h> | ||
#include <linux/gpio/consumer.h> | ||
#include <linux/module.h> | ||
#include <linux/mux/driver.h> | ||
#include <linux/of_platform.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/property.h> | ||
|
||
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 <peda@axentia.se>"); | ||
MODULE_LICENSE("GPL v2"); |