* [PATCH v3 4/7] dt-bindings: iio: iio-mux: document iio-mux bindings
From: Peter Rosin @ 2016-11-21 13:17 UTC (permalink / raw)
To: linux-kernel
Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc
In-Reply-To: <1479734235-18837-1-git-send-email-peda@axentia.se>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
.../bindings/iio/multiplexer/iio-mux.txt | 47 ++++++++++++++++++++++
MAINTAINERS | 6 +++
2 files changed, 53 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
new file mode 100644
index 000000000000..2807333ccc86
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
@@ -0,0 +1,47 @@
+IIO multiplexer bindings
+
+If a multiplexer is used to select which hardware signal is fed to
+e.g. an ADC channel, these bindings describe that situation.
+
+Required properties:
+- compatible : "iio-mux"
+- io-channels : Channel node of the parent channel that has multiplexed
+ input.
+- io-channel-names : Should be "parent".
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Required properties for iio-mux child nodes:
+- reg : The multiplexer state as described in ../misc/mux-controller.txt
+
+For each iio-mux child, an iio channel will be created whose number will
+match the mux controller state.
+
+Example:
+ mux {
+ compatible = "mux-gpio";
+
+ mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+ <&pioA 1 GPIO_ACTIVE_HIGH>;
+
+ adc {
+ compatible = "iio-mux";
+ io-channels = <&adc 0>;
+ io-channel-names = "parent";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sync@0 {
+ reg = <0>;
+ };
+
+ in@1 {
+ reg = <1>;
+ };
+
+ system-regulator@2 {
+ reg = <2>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 37974aeee750..3fc0dbbc04ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6124,6 +6124,12 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/rc/iguanair.c
+IIO MULTIPLEXER
+M: Peter Rosin <peda@axentia.se>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+
IIO SUBSYSTEM AND DRIVERS
M: Jonathan Cameron <jic23@kernel.org>
R: Hartmut Knaack <knaack.h@gmx.de>
--
2.1.4
^ permalink raw reply related
* [PATCH v3 3/7] iio: inkern: api for manipulating ext_info of iio channels
From: Peter Rosin @ 2016-11-21 13:17 UTC (permalink / raw)
To: linux-kernel
Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc
In-Reply-To: <1479734235-18837-1-git-send-email-peda@axentia.se>
Extend the inkern api with functions for reading and writing ext_info
of iio channels.
Signed-off-by: Peter Rosin <peda@axentia.se>
---
drivers/iio/inkern.c | 55 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/iio/consumer.h | 37 +++++++++++++++++++++++++++++
2 files changed, 92 insertions(+)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index c4757e6367e7..efe418282cc3 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -746,3 +746,58 @@ int iio_write_channel_raw(struct iio_channel *chan, int val)
return ret;
}
EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+
+int iio_get_channel_ext_info_count(struct iio_channel *chan)
+{
+ const struct iio_chan_spec_ext_info *ext_info;
+ unsigned int i = 0;
+
+ if (!chan->channel->ext_info)
+ return i;
+
+ for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
+ ++i;
+
+ return i;
+}
+EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
+
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+ const char *attr, char *buf)
+{
+ const struct iio_chan_spec_ext_info *ext_info;
+
+ if (!chan->channel->ext_info)
+ return -EINVAL;
+
+ for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
+ if (strcmp(attr, ext_info->name))
+ continue;
+
+ return ext_info->read(chan->indio_dev, ext_info->private,
+ chan->channel, buf);
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
+
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+ const char *buf, size_t len)
+{
+ const struct iio_chan_spec_ext_info *ext_info;
+
+ if (!chan->channel->ext_info)
+ return -EINVAL;
+
+ for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
+ if (strcmp(attr, ext_info->name))
+ continue;
+
+ return ext_info->write(chan->indio_dev, ext_info->private,
+ chan->channel, buf, len);
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 9edccfba1ffb..1e908ccb11f0 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -271,4 +271,41 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
int *processed, unsigned int scale);
+/**
+ * iio_get_channel_ext_info_count() - get number of ext_info attributes
+ * connected to the channel.
+ * @chan: The channel being queried
+ *
+ * Returns the number of ext_info attributes
+ */
+int iio_get_channel_ext_info_count(struct iio_channel *chan);
+
+/**
+ * iio_read_channel_ext_info() - read ext_info attribute from a given channel
+ * @chan: The channel being queried.
+ * @attr: The ext_info attribute to read.
+ * @buf: Where to store the attribute value. Assumed to hold
+ * at least PAGE_SIZE bytes.
+ *
+ * Returns the number of bytes written to buf (perhaps w/o zero termination;
+ * it need not even be a string), or an error code.
+ */
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+ const char *attr, char *buf);
+
+/**
+ * iio_write_channel_ext_info() - write ext_info attribute from a given channel
+ * @chan: The channel being queried.
+ * @attr: The ext_info attribute to read.
+ * @buf: The new attribute value. Strings needs to be zero-
+ * terminated, but the terminator should not be included
+ * in the below len.
+ * @len: The size of the new attribute value.
+ *
+ * Returns the number of accepted bytes, which should be the same as len.
+ * An error code can also be returned.
+ */
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+ const char *buf, size_t len);
+
#endif
--
2.1.4
^ permalink raw reply related
* [PATCH v3 2/7] misc: minimal mux subsystem and gpio-based mux controller
From: Peter Rosin @ 2016-11-21 13:17 UTC (permalink / raw)
To: linux-kernel
Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc
In-Reply-To: <1479734235-18837-1-git-send-email-peda@axentia.se>
Add a new minimalistic subsystem that handles multiplexer controllers.
When multiplexers are used in various places in the kernel, and the
same multiplexer controller can be used for several independent things,
there should be one place to implement support for said multiplexer
controller.
A single multiplexer controller can also be used to control several
parallel multiplexers, that are in turn used by different subsystems
in the kernel, leading to a need to coordinate multiplexer accesses.
The multiplexer subsystem handles this coordination.
This new mux controller subsystem comes with a single backend driver
that controls gpio based multiplexers.
Signed-off-by: Peter Rosin <peda@axentia.se>
---
Documentation/driver-model/devres.txt | 6 +-
MAINTAINERS | 2 +
drivers/misc/Kconfig | 23 +++
drivers/misc/Makefile | 2 +
drivers/misc/mux-core.c | 325 ++++++++++++++++++++++++++++++++++
drivers/misc/mux-gpio.c | 116 ++++++++++++
include/linux/mux.h | 55 ++++++
7 files changed, 528 insertions(+), 1 deletion(-)
create mode 100644 drivers/misc/mux-core.c
create mode 100644 drivers/misc/mux-gpio.c
create mode 100644 include/linux/mux.h
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 167070895498..947bfcfac9ae 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -330,7 +330,11 @@ MEM
devm_kzalloc()
MFD
- devm_mfd_add_devices()
+ devm_mfd_add_devices()
+
+MUX
+ devm_mux_control_get()
+ devm_mux_control_put()
PCI
pcim_enable_device() : after success, all PCI ops become managed
diff --git a/MAINTAINERS b/MAINTAINERS
index 7d797f087822..37974aeee750 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8248,6 +8248,8 @@ MULTIPLEXER SUBSYSTEM
M: Peter Rosin <peda@axentia.se>
S: Maintained
F: Documentation/devicetree/bindings/misc/mux-*
+F: include/linux/mux.h
+F: drivers/misc/mux-*
MULTISOUND SOUND DRIVER
M: Andrew Veliath <andrewtv@usa.net>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 64971baf11fa..a3ca79e082c7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -766,6 +766,29 @@ config PANEL_BOOT_MESSAGE
An empty message will only clear the display at driver init time. Any other
printf()-formatted message is valid with newline and escape codes.
+config MULTIPLEXER
+ tristate "Multiplexer subsystem"
+ help
+ Multiplexer controller subsystem. Multiplexers are used in a
+ variety of settings, and this subsystem abstracts their use
+ so that the rest of the kernel sees a common interface. When
+ multiple parallel multiplexers are controlled by one single
+ multiplexer controller, this subsystem also coordinates the
+ multiplexer accesses.
+
+if MULTIPLEXER
+
+config MUX_GPIO
+ tristate "GPIO-controlled MUX controller"
+ depends on OF && GPIOLIB
+ help
+ GPIO-controlled MUX controller.
+
+ To compile this driver as a module, choose M here: the module will
+ be called mux-gpio.
+
+endif
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 31983366090a..0befa2bba762 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,6 +53,8 @@ obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-$(CONFIG_CXL_BASE) += cxl/
obj-$(CONFIG_PANEL) += panel.o
+obj-$(CONFIG_MULTIPLEXER) += mux-core.o
+obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
diff --git a/drivers/misc/mux-core.c b/drivers/misc/mux-core.c
new file mode 100644
index 000000000000..5142caa19236
--- /dev/null
+++ b/drivers/misc/mux-core.c
@@ -0,0 +1,325 @@
+/*
+ * Multiplexer subsystem
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * 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 <linux/device.h>
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+static struct bus_type mux_bus_type = {
+ .name = "mux",
+};
+
+static int __init mux_init(void)
+{
+ return bus_register(&mux_bus_type);
+}
+
+static void __exit mux_exit(void)
+{
+ bus_unregister(&mux_bus_type);
+}
+
+static DEFINE_IDA(mux_ida);
+
+static void mux_control_release(struct device *dev)
+{
+ struct mux_control *mux = to_mux_control(dev);
+
+ ida_simple_remove(&mux_ida, mux->id);
+ kfree(mux);
+}
+
+static struct device_type mux_control_type = {
+ .name = "mux-control",
+ .release = mux_control_release,
+};
+
+/**
+ * mux_control_alloc - allocate a mux-control
+ * @sizeof_priv: Size of extra memory area for private use by the caller.
+ *
+ * Returns the new mux-control.
+ */
+struct mux_control *mux_control_alloc(size_t sizeof_priv)
+{
+ struct mux_control *mux;
+
+ mux = kzalloc(sizeof(*mux) + sizeof_priv, GFP_KERNEL);
+ if (!mux)
+ return NULL;
+
+ mux->dev.bus = &mux_bus_type;
+ mux->dev.type = &mux_control_type;
+ device_initialize(&mux->dev);
+ dev_set_drvdata(&mux->dev, mux);
+
+ init_rwsem(&mux->lock);
+
+ mux->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL);
+ if (mux->id < 0) {
+ pr_err("mux-controlX failed to get device id\n");
+ kfree(mux);
+ return NULL;
+ }
+ dev_set_name(&mux->dev, "mux:control%d", mux->id);
+
+ mux->cached_state = -1;
+ mux->idle_state = -1;
+
+ return mux;
+}
+EXPORT_SYMBOL_GPL(mux_control_alloc);
+
+/**
+ * mux_control_register - register a mux-control, thus readying it for use
+ * @mux: The mux-control to register.
+ *
+ * Returns zero on success or a negative errno on error.
+ */
+int mux_control_register(struct mux_control *mux)
+{
+ int ret;
+
+ /* If the calling driver did not initialize of_node, do it here */
+ if (!mux->dev.of_node && mux->dev.parent)
+ mux->dev.of_node = mux->dev.parent->of_node;
+
+ ret = device_add(&mux->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = of_platform_populate(mux->dev.of_node, NULL, NULL, &mux->dev);
+ if (ret < 0)
+ device_del(&mux->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mux_control_register);
+
+/**
+ * mux_control_unregister - take the mux-control off-line, reversing the
+ * effexts of mux_control_register
+ * @mux: the mux-control to unregister.
+ */
+void mux_control_unregister(struct mux_control *mux)
+{
+ of_platform_depopulate(&mux->dev);
+ device_del(&mux->dev);
+}
+EXPORT_SYMBOL_GPL(mux_control_unregister);
+
+/**
+ * mux_control_put - put away the mux-control for good, reversing the
+ * effects of either mux_control_alloc or mux_control_get
+ * @mux: The mux-control to put away.
+ */
+void mux_control_put(struct mux_control *mux)
+{
+ if (!mux)
+ return;
+ put_device(&mux->dev);
+}
+EXPORT_SYMBOL_GPL(mux_control_put);
+
+static int mux_control_set(struct mux_control *mux, int state)
+{
+ int ret = mux->ops->set(mux, state);
+
+ mux->cached_state = ret < 0 ? -1 : 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.
+ *
+ * Returns 0 if the requested state was already active, or 1 it the
+ * mux-control state was changed to the requested state. Or a negavive
+ * errno on error.
+ * Note that the difference in return value of zero or one is of
+ * questionable value; especially if the mux-control has several independent
+ * consumers, which is something the consumers should not be making
+ * assumptions about.
+ *
+ * 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.
+ */
+int mux_control_select(struct mux_control *mux, int state)
+{
+ int ret;
+
+ if (down_read_trylock(&mux->lock)) {
+ if (mux->cached_state == state)
+ return 0;
+
+ /* Sigh, the mux needs updating... */
+ up_read(&mux->lock);
+ }
+
+ /* ...or it's just contended. */
+ down_write(&mux->lock);
+
+ if (mux->cached_state == state) {
+ /*
+ * Hmmm, someone else changed the mux to my liking.
+ * That makes me wonder how long I waited for nothing?
+ */
+ downgrade_write(&mux->lock);
+ return 0;
+ }
+
+ ret = mux_control_set(mux, state);
+ if (ret < 0) {
+ if (mux->idle_state != -1)
+ mux_control_set(mux, mux->idle_state);
+
+ up_write(&mux->lock);
+ return ret;
+ }
+
+ downgrade_write(&mux->lock);
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(mux_control_select);
+
+/**
+ * mux_control_deselect - deselect the previously selected multiplexer state
+ * @mux: The mux-control to deselect.
+ *
+ * Returns 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 for others to access.
+ */
+int mux_control_deselect(struct mux_control *mux)
+{
+ int ret = 0;
+
+ if (mux->idle_state != -1 && mux->cached_state != mux->idle_state)
+ ret = mux_control_set(mux, mux->idle_state);
+
+ up_read(&mux->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mux_control_deselect);
+
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static struct mux_control *of_find_mux_by_node(struct device_node *np)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&mux_bus_type, NULL, np, of_dev_node_match);
+
+ return dev ? to_mux_control(dev) : NULL;
+}
+
+/**
+ * mux_control_get - get the mux-control for a device
+ * @dev: The device that needs a mux-control.
+ *
+ * Returns the mux-control.
+ */
+struct mux_control *mux_control_get(struct device *dev)
+{
+ struct mux_control *mux;
+
+ if (!dev->of_node)
+ return ERR_PTR(-ENODEV);
+
+ mux = of_find_mux_by_node(dev->of_node->parent);
+ if (!mux)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return mux;
+}
+EXPORT_SYMBOL_GPL(mux_control_get);
+
+static void devm_mux_control_free(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.
+ *
+ * Returns the mux-control.
+ */
+struct mux_control *devm_mux_control_get(struct device *dev)
+{
+ struct mux_control **ptr, *mux;
+
+ ptr = devres_alloc(devm_mux_control_free, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ mux = mux_control_get(dev);
+ if (IS_ERR(mux)) {
+ devres_free(ptr);
+ return mux;
+ }
+
+ *ptr = mux;
+ devres_add(dev, ptr);
+
+ return mux;
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get);
+
+static int devm_mux_control_match(struct device *dev, void *res, void *data)
+{
+ struct mux_control **r = res;
+
+ if (!r || !*r) {
+ WARN_ON(!r || !*r);
+ return 0;
+ }
+
+ return *r == data;
+}
+
+/**
+ * devm_mux_control_put - resource-managed version mux_control_put
+ * @dev: The device that originally got the mux-control.
+ * @mux: The mux-control to put away.
+ *
+ * Note that you do not normally need to call this function.
+ */
+void devm_mux_control_put(struct device *dev, struct mux_control *mux)
+{
+ WARN_ON(devres_release(dev, devm_mux_control_free,
+ devm_mux_control_match, mux));
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_put);
+
+subsys_initcall(mux_init);
+module_exit(mux_exit);
+
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
+MODULE_DESCRIPTION("MUX subsystem");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mux-gpio.c b/drivers/misc/mux-gpio.c
new file mode 100644
index 000000000000..e9baca35f400
--- /dev/null
+++ b/drivers/misc/mux-gpio.c
@@ -0,0 +1,116 @@
+/*
+ * GPIO-controlled multiplexer driver
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * 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.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+struct mux_gpio {
+ struct gpio_descs *gpios;
+};
+
+static int mux_gpio_set(struct mux_control *mux, int val)
+{
+ struct mux_gpio *mux_gpio = mux_control_priv(mux);
+ int i;
+
+ for (i = 0; i < mux_gpio->gpios->ndescs; i++)
+ gpiod_set_value_cansleep(mux_gpio->gpios->desc[i],
+ val & (1 << i));
+
+ 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 = "mux-gpio", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
+
+static int mux_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct mux_control *mux;
+ struct mux_gpio *mux_gpio;
+ u32 idle_state;
+ int ret;
+
+ if (!np)
+ return -ENODEV;
+
+ mux = mux_control_alloc(sizeof(*mux_gpio));
+ if (!mux)
+ return -ENOMEM;
+ mux_gpio = mux_control_priv(mux);
+ mux->dev.parent = dev;
+ mux->ops = &mux_gpio_ops;
+
+ platform_set_drvdata(pdev, mux);
+
+ mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
+ if (IS_ERR(mux_gpio->gpios)) {
+ if (PTR_ERR(mux_gpio->gpios) != -EPROBE_DEFER)
+ dev_err(dev, "failed to get gpios\n");
+ mux_control_put(mux);
+ return PTR_ERR(mux_gpio->gpios);
+ }
+ mux->states = 1 << mux_gpio->gpios->ndescs;
+
+ ret = of_property_read_u32(np, "idle-state", &idle_state);
+ if (ret >= 0) {
+ if (idle_state >= mux->states) {
+ dev_err(dev, "invalid idle-state %u\n", idle_state);
+ return -EINVAL;
+ }
+ mux->idle_state = idle_state;
+ }
+
+ ret = mux_control_register(mux);
+ if (ret < 0) {
+ dev_err(dev, "failed to register mux_control\n");
+ mux_control_put(mux);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mux_gpio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mux_control *mux = to_mux_control(dev);
+
+ mux_control_unregister(mux);
+ mux_control_put(mux);
+ return 0;
+}
+
+static struct platform_driver mux_gpio_driver = {
+ .driver = {
+ .name = "mux-gpio",
+ .of_match_table = of_match_ptr(mux_gpio_dt_ids),
+ },
+ .probe = mux_gpio_probe,
+ .remove = mux_gpio_remove,
+};
+module_platform_driver(mux_gpio_driver);
+
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
+MODULE_DESCRIPTION("GPIO-controlled multiplexer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mux.h b/include/linux/mux.h
new file mode 100644
index 000000000000..2f1472192d6d
--- /dev/null
+++ b/include/linux/mux.h
@@ -0,0 +1,55 @@
+/*
+ * mux.h - definitions for the multiplexer interface
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_MUX_H
+#define _LINUX_MUX_H
+
+#include <linux/device.h>
+#include <linux/rwsem.h>
+
+struct mux_control;
+
+struct mux_control_ops {
+ int (*set)(struct mux_control *mux, int reg);
+};
+
+struct mux_control {
+ struct rw_semaphore lock; /* protects the state of the mux */
+
+ struct device dev;
+ int id;
+
+ unsigned int states;
+ int cached_state;
+ int idle_state;
+
+ const struct mux_control_ops *ops;
+};
+
+#define to_mux_control(x) container_of((x), struct mux_control, dev)
+
+static inline void *mux_control_priv(struct mux_control *mux)
+{
+ return mux + 1;
+}
+
+struct mux_control *mux_control_alloc(size_t sizeof_priv);
+int mux_control_register(struct mux_control *mux);
+void mux_control_unregister(struct mux_control *mux);
+void mux_control_put(struct mux_control *mux);
+
+int mux_control_select(struct mux_control *mux, int state);
+int mux_control_deselect(struct mux_control *mux);
+
+struct mux_control *mux_control_get(struct device *dev);
+struct mux_control *devm_mux_control_get(struct device *dev);
+void devm_mux_control_put(struct device *dev, struct mux_control *mux);
+
+#endif /* _LINUX_MUX_H */
--
2.1.4
^ permalink raw reply related
* [PATCH v3 1/7] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
From: Peter Rosin @ 2016-11-21 13:17 UTC (permalink / raw)
To: linux-kernel
Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc
In-Reply-To: <1479734235-18837-1-git-send-email-peda@axentia.se>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
.../devicetree/bindings/misc/mux-controller.txt | 76 +++++++++++++++++++++
.../devicetree/bindings/misc/mux-gpio.txt | 78 ++++++++++++++++++++++
MAINTAINERS | 5 ++
3 files changed, 159 insertions(+)
create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
diff --git a/Documentation/devicetree/bindings/misc/mux-controller.txt b/Documentation/devicetree/bindings/misc/mux-controller.txt
new file mode 100644
index 000000000000..6946b5428546
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-controller.txt
@@ -0,0 +1,76 @@
+Common multiplexer controller bindings
+
+A mux controller will have one, or several, child devices that uses (or
+consumes) a mux controller. A mux controller can possibly control several
+parallel multiplexers. The node for a mux controller will have one child
+node for each multiplexer controller consumer.
+
+A mux controller provides a number of states to its consumers, and the
+state space is a simple zero-based enumeration. I.e. 0-1 for a 2-way
+multiplexer, 0-7 for an 8-way multiplexer, etc.
+
+Example:
+
+ /*
+ * Two consumers (one for an ADC line and one for an i2c bus) of
+ * parallel 4-way multiplexers controlled by the same two GPIO-lines.
+ */
+ mux {
+ compatible = "mux-gpio";
+
+ mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+ <&pioA 1 GPIO_ACTIVE_HIGH>;
+
+ adc {
+ compatible = "iio-mux";
+ io-channels = <&adc 0>;
+ io-channel-names = "parent";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sync-1@0 {
+ reg = <0>;
+ };
+
+ in@1 {
+ reg = <1>;
+ };
+
+ out@2 {
+ reg = <2>;
+ };
+
+ sync-2@3 {
+ reg = <3>;
+ };
+ };
+
+ i2c-mux {
+ compatible = "i2c-mux-simple,mux-locked";
+ i2c-parent = <&i2c1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ssd1307: oled@3c {
+ /* ... */
+ };
+ };
+
+ i2c@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pca9555: pca9555@20 {
+ /* ... */
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/misc/mux-gpio.txt b/Documentation/devicetree/bindings/misc/mux-gpio.txt
new file mode 100644
index 000000000000..23b87913f4b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-gpio.txt
@@ -0,0 +1,78 @@
+GPIO-based multiplexer controller bindings
+
+Define what GPIO pins are used to control a multiplexer. Or several
+multiplexers, if the same pins control more than one multiplexer.
+
+Required properties:
+- compatible : "mux-gpio"
+- mux-gpios : list of gpios used to control the multiplexer, least
+ significant bit first.
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- idle-state : if present, the state the mux will have when idle.
+
+The multiplexer state is defined as the number represented by the
+multiplexer GPIO pins, where the first pin is the least significant
+bit. And active pin is a binary 1, an inactive pin is a binary 0.
+
+Example:
+ mux {
+ compatible = "mux-gpio";
+
+ mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+ <&pioA 1 GPIO_ACTIVE_HIGH>;
+
+ adc {
+ compatible = "iio-mux";
+ io-channels = <&adc 0>;
+ io-channel-names = "parent";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sync-1@0 {
+ reg = <0>;
+ };
+
+ in@1 {
+ reg = <1>;
+ };
+
+ out@2 {
+ reg = <2>;
+ };
+
+ sync-2@3 {
+ reg = <3>;
+ };
+ };
+
+ i2c-mux {
+ compatible = "i2c-mux-simple,mux-locked";
+ i2c-parent = <&i2c1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ssd1307: oled@3c {
+ /* ... */
+ };
+ };
+
+ i2c@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pca9555: pca9555@20 {
+ /* ... */
+ };
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index ad9b965e5e44..7d797f087822 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8244,6 +8244,11 @@ S: Orphan
F: drivers/mmc/host/mmc_spi.c
F: include/linux/spi/mmc_spi.h
+MULTIPLEXER SUBSYSTEM
+M: Peter Rosin <peda@axentia.se>
+S: Maintained
+F: Documentation/devicetree/bindings/misc/mux-*
+
MULTISOUND SOUND DRIVER
M: Andrew Veliath <andrewtv@usa.net>
S: Maintained
--
2.1.4
^ permalink raw reply related
* [PATCH v3 0/7] mux controller abstraction and iio/i2c muxes
From: Peter Rosin @ 2016-11-21 13:17 UTC (permalink / raw)
To: linux-kernel
Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc
Hi!
The code depends on the _available work in iio which can
be found in linux-next.
v2 -> v3 changes
- have the mux-controller in the parent node of any mux-controller consumer,
to hopefully satisfy complaint from Rob about dt complexity.
- improve commit message of the mux subsystem commit, making it more
general, as requested by Jonathan.
- remove priv member from struct mux_control and calculate it on the
fly. /Jonathan.
- make the function comments in mux-core.c kernel doc. /Jonathan
- add devm_mux_control_* to Documentation/driver.model/devres.txt. /Jonathan
- add common dt bindings for mux-controllers, refer to them from the
mux-gpio bindings.
- clarify how the gpio pins map to the mux state.
- separate CONFIG_ variables for the mux core and the mux gpio driver.
- improve Kconfig help texts.
- make CONFIG_MUX_GPIO depend on CONFIG_GPIOLIB.
- keep track of the number of mux states in the mux core.
- since the iio channel number is used as mux state, it was possible
to drop the state member from the mux_child struct.
- cleanup dt bindings for i2c-mux-simple, it had some of copy-paste
problems from ots origin (i2c-mux-gpio).
- select the mux control subsystem in config for the i2c-mux-simple driver.
- add entries to MAINTAINERS and my sign-off, I'm now satisfied and know
nothing in this to be ashamed of.
v1 -> v2 changes
- fixup export of mux_control_put reported by kbuild
- drop devicetree iio-ext-info property as noted by Lars-Peter,
and replace the functionality by exposing all ext_info
attributes of the parent channel for each of the muxed
channels. A cache on top of that and each muxed channel
gets its own view of the ext_info of the parent channel.
- implement idle-state for muxes
- clear out the cache on failure in order to force a mux
update on the following use
- cleanup the probe of i2c-mux-simple driver
- fix a bug in the i2c-mux-simple driver, where failure in
the selection of the mux caused a deadlock when the mux
was later unconditionally deselected.
I have a piece of hardware that is using the same 3 GPIO pins
to control four 8-way muxes. Three of them control ADC lines
to an ADS1015 chip with an iio driver, and the last one
controls the SDA line of an i2c bus. We have some deployed
code to handle this, but you do not want to see it or ever
hear about it. I'm not sure why I even mention it. Anyway,
the situation has nagged me to no end for quite some time.
So, after first getting more intimate with the i2c muxing code
and later discovering the drivers/iio/inkern.c file and
writing a couple of drivers making use of it, I came up with
what I think is an acceptable solution; add a generic mux
controller driver (and subsystem) that is shared between all
instances, and combine that with an iio mux driver and a new
generic i2c mux driver. The new i2c mux I called "simple"
since it is only hooking the i2c muxing and the new mux
controller (much like the alsa simple card driver does for ASoC).
My initial (private) version didn't add "mux" as a new bus,
but I couldn't get decent type-checking and nice devicetree
integration with that. It does however feel a bit rich to
add a new bus for something as small as mux controllers?
One thing that I would like to do, but don't see a solution
for, is to move the mux control code that is present in
various drivers in drivers/i2c/muxes to this new minimalistic
muxing subsystem, thus converting all present i2c muxes (but
perhaps not gates and arbitrators) to be i2c-mux-simple muxes.
I'm using an rwsem to lock a mux, but that isn't really a
perfect fit. Is there a better locking primitive that I don't
know about that fits better? I had a mutex at one point, but
that didn't allow any concurrent accesses at all. At least
the rwsem allows concurrent access as long as all users
agree on the mux state, but I suspect that the rwsem will
degrade to the mutex situation pretty quickly if there is
any contention.
Also, the "mux" name feels a bit ambitious, there are many muxes
in the world, and this tiny bit of code is probably not good
enough to be a nice fit for all...
Cheers,
Peter
Peter Rosin (7):
dt-bindings: document devicetree bindings for mux-controllers and
mux-gpio
misc: minimal mux subsystem and gpio-based mux controller
iio: inkern: api for manipulating ext_info of iio channels
dt-bindings: iio: iio-mux: document iio-mux bindings
iio: multiplexer: new iio category and iio-mux driver
dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
i2c: i2c-mux-simple: new driver
.../devicetree/bindings/i2c/i2c-mux-simple.txt | 76 ++++
.../bindings/iio/multiplexer/iio-mux.txt | 47 +++
.../devicetree/bindings/misc/mux-controller.txt | 76 ++++
.../devicetree/bindings/misc/mux-gpio.txt | 78 ++++
Documentation/driver-model/devres.txt | 6 +-
MAINTAINERS | 14 +
drivers/i2c/muxes/Kconfig | 13 +
drivers/i2c/muxes/Makefile | 1 +
drivers/i2c/muxes/i2c-mux-simple.c | 177 ++++++++
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/inkern.c | 55 +++
drivers/iio/multiplexer/Kconfig | 18 +
drivers/iio/multiplexer/Makefile | 6 +
drivers/iio/multiplexer/iio-mux.c | 450 +++++++++++++++++++++
drivers/misc/Kconfig | 23 ++
drivers/misc/Makefile | 2 +
drivers/misc/mux-core.c | 325 +++++++++++++++
drivers/misc/mux-gpio.c | 116 ++++++
include/linux/iio/consumer.h | 37 ++
include/linux/mux.h | 55 +++
21 files changed, 1576 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
create mode 100644 drivers/iio/multiplexer/Kconfig
create mode 100644 drivers/iio/multiplexer/Makefile
create mode 100644 drivers/iio/multiplexer/iio-mux.c
create mode 100644 drivers/misc/mux-core.c
create mode 100644 drivers/misc/mux-gpio.c
create mode 100644 include/linux/mux.h
--
2.1.4
^ permalink raw reply
* [PATCH] dt-bindings: mfd: Improve readability for TPS65217 interrupt sources
From: Milo Kim @ 2016-11-21 13:15 UTC (permalink / raw)
To: bcousson, Tony Lindgren
Cc: Lee Jones, linux-omap, devicetree, linux-arm-kernel, linux-kernel,
Robert Nelson, Milo Kim
AC and USB interrupts are related with external power input.
PB interrupt means push button pressed or released event.
Use better human readable definitions.
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
arch/arm/boot/dts/am335x-bone-common.dtsi | 4 ++--
include/dt-bindings/mfd/tps65217.h | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
index dc561d5..1848d58 100644
--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
+++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
@@ -319,13 +319,13 @@
ti,pmic-shutdown-controller;
charger {
- interrupts = <TPS65217_IRQ_AC>, <TPS65217_IRQ_USB>;
+ interrupts = <TPS65217_IRQ_AC_POWER>, <TPS65217_IRQ_USB_POWER>;
interrupts-names = "AC", "USB";
status = "okay";
};
pwrbutton {
- interrupts = <TPS65217_IRQ_PB>;
+ interrupts = <TPS65217_IRQ_PUSHBUTTON>;
status = "okay";
};
diff --git a/include/dt-bindings/mfd/tps65217.h b/include/dt-bindings/mfd/tps65217.h
index cafb9e6..0293fdd 100644
--- a/include/dt-bindings/mfd/tps65217.h
+++ b/include/dt-bindings/mfd/tps65217.h
@@ -19,8 +19,8 @@
#ifndef __DT_BINDINGS_TPS65217_H__
#define __DT_BINDINGS_TPS65217_H__
-#define TPS65217_IRQ_USB 0
-#define TPS65217_IRQ_AC 1
-#define TPS65217_IRQ_PB 2
+#define TPS65217_IRQ_USB_POWER 0 /* USB power state change */
+#define TPS65217_IRQ_AC_POWER 1 /* AC power state change */
+#define TPS65217_IRQ_PUSHBUTTON 2 /* Push button state change */
#endif
--
2.9.3
^ permalink raw reply related
* Re: [PATCH v2 1/2] regulator: max77620: add support to configure MPOK
From: Lee Jones @ 2016-11-21 13:11 UTC (permalink / raw)
To: Venkat Reddy Talla
Cc: lgirdwood, broonie, robh+dt, mark.rutland, devicetree,
linux-kernel, ldewangan, svelpula
In-Reply-To: <20161121130948.GC3917@dell>
On Mon, 21 Nov 2016, Lee Jones wrote:
> On Thu, 17 Nov 2016, Venkat Reddy Talla wrote:
>
> > Adding support to configure regulator POK mapping bit
> > to control nRST_IO and GPIO1 POK function.
> > In tegra based platform which uses MAX20024 pmic, when
> > some of regulators are configured FPS_NONE(flexible power sequencer)
> > causes PMIC GPIO1 to go low which lead to various other rails turning off,
> > to avoid this MPOK bit of those regulators need to be set to 0
> > so that PMIC GPIO1 will not go low.
> >
> > Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
> >
> > ---
> > changes in v2:
> > - updated commit message for the patch
> > - address review comments
> > ---
> > drivers/regulator/max77620-regulator.c | 46 ++++++++++++++++++++++++++++++++++
> > include/linux/mfd/max77620.h | 2 ++
>
> For my own reference:
> Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
Mark if you want to take this patch, feel free.
> > 2 files changed, 48 insertions(+)
> >
> > diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c
> > index a1b49a6..850b14c 100644
> > --- a/drivers/regulator/max77620-regulator.c
> > +++ b/drivers/regulator/max77620-regulator.c
> > @@ -81,6 +81,7 @@ struct max77620_regulator_pdata {
> > int suspend_fps_pd_slot;
> > int suspend_fps_pu_slot;
> > int current_mode;
> > + int power_ok;
> > int ramp_rate_setting;
> > };
> >
> > @@ -351,11 +352,48 @@ static int max77620_set_slew_rate(struct max77620_regulator *pmic, int id,
> > return 0;
> > }
> >
> > +static int max77620_config_power_ok(struct max77620_regulator *pmic, int id)
> > +{
> > + struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
> > + struct max77620_regulator_info *rinfo = pmic->rinfo[id];
> > + struct max77620_chip *chip = dev_get_drvdata(pmic->dev->parent);
> > + u8 val, mask;
> > + int ret;
> > +
> > + switch (chip->chip_id) {
> > + case MAX20024:
> > + if (rpdata->power_ok >= 0) {
> > + if (rinfo->type == MAX77620_REGULATOR_TYPE_SD)
> > + mask = MAX20024_SD_CFG1_MPOK_MASK;
> > + else
> > + mask = MAX20024_LDO_CFG2_MPOK_MASK;
> > +
> > + val = rpdata->power_ok ? mask : 0;
> > +
> > + ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr,
> > + mask, val);
> > + if (ret < 0) {
> > + dev_err(pmic->dev, "Reg 0x%02x update failed %d\n",
> > + rinfo->cfg_addr, ret);
> > + return ret;
> > + }
> > + }
> > + break;
> > +
> > + default:
> > + break;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > static int max77620_init_pmic(struct max77620_regulator *pmic, int id)
> > {
> > struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
> > int ret;
> >
> > + max77620_config_power_ok(pmic, id);
> > +
> > /* Update power mode */
> > ret = max77620_regulator_get_power_mode(pmic, id);
> > if (ret < 0)
> > @@ -595,6 +633,12 @@ static int max77620_of_parse_cb(struct device_node *np,
> > np, "maxim,suspend-fps-power-down-slot", &pval);
> > rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1;
> >
> > + ret = of_property_read_u32(np, "maxim,power-ok-control", &pval);
> > + if (!ret)
> > + rpdata->power_ok = pval;
> > + else
> > + rpdata->power_ok = -1;
> > +
> > ret = of_property_read_u32(np, "maxim,ramp-rate-setting", &pval);
> > rpdata->ramp_rate_setting = (!ret) ? pval : 0;
> >
> > @@ -807,6 +851,8 @@ static int max77620_regulator_resume(struct device *dev)
> > for (id = 0; id < MAX77620_NUM_REGS; id++) {
> > reg_pdata = &pmic->reg_pdata[id];
> >
> > + max77620_config_power_ok(pmic, id);
> > +
> > max77620_regulator_set_fps_slots(pmic, id, false);
> > if (reg_pdata->active_fps_src < 0)
> > continue;
> > diff --git a/include/linux/mfd/max77620.h b/include/linux/mfd/max77620.h
> > index 3ca0af07..ad2a9a8 100644
> > --- a/include/linux/mfd/max77620.h
> > +++ b/include/linux/mfd/max77620.h
> > @@ -180,6 +180,7 @@
> > #define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2)
> > #define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
> > #define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2)
> > +#define MAX20024_SD_CFG1_MPOK_MASK BIT(1)
> > #define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0)
> > #define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
> > #define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0)
> > @@ -187,6 +188,7 @@
> > /* LDO_CNFG2 */
> > #define MAX77620_LDO_POWER_MODE_MASK 0xC0
> > #define MAX77620_LDO_POWER_MODE_SHIFT 6
> > +#define MAX20024_LDO_CFG2_MPOK_MASK BIT(2)
> > #define MAX77620_LDO_CFG2_ADE_MASK BIT(1)
> > #define MAX77620_LDO_CFG2_ADE_DISABLE 0
> > #define MAX77620_LDO_CFG2_ADE_ENABLE BIT(1)
>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH] PM / Domains: Fix compatible for domain idle state
From: Rafael J. Wysocki @ 2016-11-21 13:11 UTC (permalink / raw)
To: Brendan Jackman
Cc: Lina Iyer, Rafael Wysocki, Ulf Hansson, Kevin Hilman, Linux PM,
linux-arm-kernel@lists.infradead.org, Andy Gross, Stephen Boyd,
linux-arm-msm, Lorenzo Pieralisi, Sudeep Holla, Juri Lelli,
devicetree@vger.kernel.org, Rob Herring
In-Reply-To: <87zikt6mc1.fsf@arm.com>
On Mon, Nov 21, 2016 at 1:37 PM, Brendan Jackman
<brendan.jackman@arm.com> wrote:
> Hi,
>
> On Thu, Nov 03 2016 at 21:54, Lina Iyer <lina.iyer@linaro.org> wrote:
>> Re-using idle state definition provided by arm,idle-state for domain
>> idle states creates a lot of confusion and limits further evolution of
>> the domain idle definition. To keep things clear and simple, define a
>> idle states for domain using a new compatible "domain-idle-state".
>>
>> Fix existing PM domains code to look for the newly defined compatible.
>
> This looks good to me, pinging for review from others/queue for merge.
Well, I need an ACK from at least one DT bindings maintainer so that I
can queue it up.
>> Cc: <devicetree@vger.kernel.org>
>> Cc: Rob Herring <robh@kernel.org>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>> .../bindings/power/domain-idle-state.txt | 33 ++++++++++++++++++++++
>> .../devicetree/bindings/power/power_domain.txt | 8 +++---
>> drivers/base/power/domain.c | 2 +-
>> 3 files changed, 38 insertions(+), 5 deletions(-)
>> create mode 100644 Documentation/devicetree/bindings/power/domain-idle-state.txt
>>
>> diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.txt b/Documentation/devicetree/bindings/power/domain-idle-state.txt
>> new file mode 100644
>> index 0000000..eefc7ed
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/power/domain-idle-state.txt
>> @@ -0,0 +1,33 @@
>> +PM Domain Idle State Node:
>> +
>> +A domain idle state node represents the state parameters that will be used to
>> +select the state when there are no active components in the domain.
>> +
>> +The state node has the following parameters -
>> +
>> +- compatible:
>> + Usage: Required
>> + Value type: <string>
>> + Definition: Must be "domain-idle-state".
>> +
>> +- entry-latency-us
>> + Usage: Required
>> + Value type: <prop-encoded-array>
>> + Definition: u32 value representing worst case latency in
>> + microseconds required to enter the idle state.
>> + The exit-latency-us duration may be guaranteed
>> + only after entry-latency-us has passed.
>> +
>> +- exit-latency-us
>> + Usage: Required
>> + Value type: <prop-encoded-array>
>> + Definition: u32 value representing worst case latency
>> + in microseconds required to exit the idle state.
>> +
>> +- min-residency-us
>> + Usage: Required
>> + Value type: <prop-encoded-array>
>> + Definition: u32 value representing minimum residency duration
>> + in microseconds after which the idle state will yield
>> + power benefits after overcoming the overhead in entering
>> +i the idle state.
>> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
>> index e165036..723e1ad 100644
>> --- a/Documentation/devicetree/bindings/power/power_domain.txt
>> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
>> @@ -31,7 +31,7 @@ Optional properties:
>>
>> - domain-idle-states : A phandle of an idle-state that shall be soaked into a
>> generic domain power state. The idle state definitions are
>> - compatible with arm,idle-state specified in [1].
>> + compatible with domain-idle-state specified in [1].
>> The domain-idle-state property reflects the idle state of this PM domain and
>> not the idle states of the devices or sub-domains in the PM domain. Devices
>> and sub-domains have their own idle-states independent of the parent
>> @@ -85,7 +85,7 @@ Example 3:
>> };
>>
>> DOMAIN_RET: state@0 {
>> - compatible = "arm,idle-state";
>> + compatible = "domain-idle-state";
>> reg = <0x0>;
>> entry-latency-us = <1000>;
>> exit-latency-us = <2000>;
>> @@ -93,7 +93,7 @@ Example 3:
>> };
>>
>> DOMAIN_PWR_DN: state@1 {
>> - compatible = "arm,idle-state";
>> + compatible = "domain-idle-state";
>> reg = <0x1>;
>> entry-latency-us = <5000>;
>> exit-latency-us = <8000>;
>> @@ -118,4 +118,4 @@ The node above defines a typical PM domain consumer device, which is located
>> inside a PM domain with index 0 of a power controller represented by a node
>> with the label "power".
>>
>> -[1]. Documentation/devicetree/bindings/arm/idle-states.txt
>> +[1]. Documentation/devicetree/bindings/power/domain-idle-state.txt
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index 661737c..f0bc672 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -2048,7 +2048,7 @@ int genpd_dev_pm_attach(struct device *dev)
>> EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
>>
>> static const struct of_device_id idle_state_match[] = {
>> - { .compatible = "arm,idle-state", },
>> + { .compatible = "domain-idle-state", },
>> { }
>> };
> --
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH v2 2/2] dt-bindings: max77620: add documentation for MPOK property
From: Lee Jones @ 2016-11-21 13:10 UTC (permalink / raw)
To: Venkat Reddy Talla
Cc: lgirdwood, broonie, robh+dt, mark.rutland, devicetree,
linux-kernel, ldewangan, svelpula
In-Reply-To: <1479405276-26452-2-git-send-email-vreddytalla@nvidia.com>
On Thu, 17 Nov 2016, Venkat Reddy Talla wrote:
> Adding documentation for maxim,power-ok-control dts property
>
> Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
>
> ---
> Changes from V1:
> None
> ---
> Documentation/devicetree/bindings/mfd/max77620.txt | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
For my own reference:
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
> diff --git a/Documentation/devicetree/bindings/mfd/max77620.txt b/Documentation/devicetree/bindings/mfd/max77620.txt
> index 2ad44f7..9c16d51 100644
> --- a/Documentation/devicetree/bindings/mfd/max77620.txt
> +++ b/Documentation/devicetree/bindings/mfd/max77620.txt
> @@ -106,6 +106,18 @@ Here supported time periods by device in microseconds are as follows:
> MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds.
> MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds.
>
> +-maxim,power-ok-control: configure map power ok bit
> + 1: Enables POK(Power OK) to control nRST_IO and GPIO1
> + POK function.
> + 0: Disables POK control.
> + if property missing, do not configure MPOK bit.
> + If POK mapping is enabled for GPIO1/nRST_IO then,
> + GPIO1/nRST_IO pins are HIGH only if all rails
> + that have POK control enabled are HIGH.
> + If any of the rails goes down(which are enabled for POK
> + control) then, GPIO1/nRST_IO goes LOW.
> + this property is valid for max20024 only.
> +
> For DT binding details of different sub modules like GPIO, pincontrol,
> regulator, power, please refer respective device-tree binding document
> under their respective sub-system directories.
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH v2 1/2] regulator: max77620: add support to configure MPOK
From: Lee Jones @ 2016-11-21 13:09 UTC (permalink / raw)
To: Venkat Reddy Talla
Cc: lgirdwood, broonie, robh+dt, mark.rutland, devicetree,
linux-kernel, ldewangan, svelpula
In-Reply-To: <1479405276-26452-1-git-send-email-vreddytalla@nvidia.com>
On Thu, 17 Nov 2016, Venkat Reddy Talla wrote:
> Adding support to configure regulator POK mapping bit
> to control nRST_IO and GPIO1 POK function.
> In tegra based platform which uses MAX20024 pmic, when
> some of regulators are configured FPS_NONE(flexible power sequencer)
> causes PMIC GPIO1 to go low which lead to various other rails turning off,
> to avoid this MPOK bit of those regulators need to be set to 0
> so that PMIC GPIO1 will not go low.
>
> Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
>
> ---
> changes in v2:
> - updated commit message for the patch
> - address review comments
> ---
> drivers/regulator/max77620-regulator.c | 46 ++++++++++++++++++++++++++++++++++
> include/linux/mfd/max77620.h | 2 ++
For my own reference:
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
> 2 files changed, 48 insertions(+)
>
> diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c
> index a1b49a6..850b14c 100644
> --- a/drivers/regulator/max77620-regulator.c
> +++ b/drivers/regulator/max77620-regulator.c
> @@ -81,6 +81,7 @@ struct max77620_regulator_pdata {
> int suspend_fps_pd_slot;
> int suspend_fps_pu_slot;
> int current_mode;
> + int power_ok;
> int ramp_rate_setting;
> };
>
> @@ -351,11 +352,48 @@ static int max77620_set_slew_rate(struct max77620_regulator *pmic, int id,
> return 0;
> }
>
> +static int max77620_config_power_ok(struct max77620_regulator *pmic, int id)
> +{
> + struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
> + struct max77620_regulator_info *rinfo = pmic->rinfo[id];
> + struct max77620_chip *chip = dev_get_drvdata(pmic->dev->parent);
> + u8 val, mask;
> + int ret;
> +
> + switch (chip->chip_id) {
> + case MAX20024:
> + if (rpdata->power_ok >= 0) {
> + if (rinfo->type == MAX77620_REGULATOR_TYPE_SD)
> + mask = MAX20024_SD_CFG1_MPOK_MASK;
> + else
> + mask = MAX20024_LDO_CFG2_MPOK_MASK;
> +
> + val = rpdata->power_ok ? mask : 0;
> +
> + ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr,
> + mask, val);
> + if (ret < 0) {
> + dev_err(pmic->dev, "Reg 0x%02x update failed %d\n",
> + rinfo->cfg_addr, ret);
> + return ret;
> + }
> + }
> + break;
> +
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> static int max77620_init_pmic(struct max77620_regulator *pmic, int id)
> {
> struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
> int ret;
>
> + max77620_config_power_ok(pmic, id);
> +
> /* Update power mode */
> ret = max77620_regulator_get_power_mode(pmic, id);
> if (ret < 0)
> @@ -595,6 +633,12 @@ static int max77620_of_parse_cb(struct device_node *np,
> np, "maxim,suspend-fps-power-down-slot", &pval);
> rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1;
>
> + ret = of_property_read_u32(np, "maxim,power-ok-control", &pval);
> + if (!ret)
> + rpdata->power_ok = pval;
> + else
> + rpdata->power_ok = -1;
> +
> ret = of_property_read_u32(np, "maxim,ramp-rate-setting", &pval);
> rpdata->ramp_rate_setting = (!ret) ? pval : 0;
>
> @@ -807,6 +851,8 @@ static int max77620_regulator_resume(struct device *dev)
> for (id = 0; id < MAX77620_NUM_REGS; id++) {
> reg_pdata = &pmic->reg_pdata[id];
>
> + max77620_config_power_ok(pmic, id);
> +
> max77620_regulator_set_fps_slots(pmic, id, false);
> if (reg_pdata->active_fps_src < 0)
> continue;
> diff --git a/include/linux/mfd/max77620.h b/include/linux/mfd/max77620.h
> index 3ca0af07..ad2a9a8 100644
> --- a/include/linux/mfd/max77620.h
> +++ b/include/linux/mfd/max77620.h
> @@ -180,6 +180,7 @@
> #define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2)
> #define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
> #define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2)
> +#define MAX20024_SD_CFG1_MPOK_MASK BIT(1)
> #define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0)
> #define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
> #define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0)
> @@ -187,6 +188,7 @@
> /* LDO_CNFG2 */
> #define MAX77620_LDO_POWER_MODE_MASK 0xC0
> #define MAX77620_LDO_POWER_MODE_SHIFT 6
> +#define MAX20024_LDO_CFG2_MPOK_MASK BIT(2)
> #define MAX77620_LDO_CFG2_ADE_MASK BIT(1)
> #define MAX77620_LDO_CFG2_ADE_DISABLE 0
> #define MAX77620_LDO_CFG2_ADE_ENABLE BIT(1)
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH V3 2/4] mfd: pv88080: MFD core support
From: Lee Jones @ 2016-11-21 13:09 UTC (permalink / raw)
To: Eric Jeong
Cc: LINUX-KERNEL, Alexandre Courbot, DEVICETREE, LINUX-GPIO,
Liam Girdwood, Linus Walleij, Mark Brown, Mark Rutland,
Rob Herring, Support Opensource
In-Reply-To: <d5a2f377ee9ea7a7b68c9545ada0405b8134a9f4.1479429347.git.eric.jeong@diasemi.com>
On Fri, 18 Nov 2016, Eric Jeong wrote:
>
> From: Eric Jeong <eric.jeong.opensource@diasemi.com>
>
> This patch adds supports for PV88080 MFD core device.
>
> It provides communication through the I2C interface.
> It contains the following components:
> - Regulators
> - Configurable GPIOs
>
> Kconfig and Makefile are updated to reflect support for PV88080 PMIC.
>
> Signed-off-by: Eric Jeong <eric.jeong.opensource@diasemi.com>
>
> ---
> This patch applies against linux-next and next-20161117
>
> Hi,
>
> This patch adds MFD core driver for PV88080 PMIC.
> This is done as part of the existing PV88080 regulator driver by expending
> the driver for GPIO function support.
>
> Change since PATCH V2
> - Make one file insted of usging core and i2c file
> - Use devm_ function to be managed resource automatically
> - Separated mfd_cell and regmap_irq_chip declaration for clarification.
> - Updated Kconfig to use OF and assign yes to I2C
>
> Change since PATCH V1
> - Patch separated from PATCH V1
>
> Regards,
> Eric Jeong, Dialog Semiconductor Ltd.
>
>
> drivers/mfd/Kconfig | 12 ++
> drivers/mfd/Makefile | 1 +
> drivers/mfd/pv88080.c | 331 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/pv88080.h | 222 +++++++++++++++++++++++++++++
> 4 files changed, 566 insertions(+)
> create mode 100644 drivers/mfd/pv88080.c
> create mode 100644 include/linux/mfd/pv88080.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 06dc9b0..75abf2d 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -792,6 +792,18 @@ config MFD_PM8921_CORE
> Say M here if you want to include support for PM8921 chip as a module.
> This will build a module called "pm8921-core".
>
> +config MFD_PV88080
> + tristate "Powerventure Semiconductor PV88080 PMIC Support"
> + select MFD_CORE
> + select REGMAP_I2C
> + select REGMAP_IRQ
> + depends on I2C=y && OF
> + help
> + Say yes here for support for the Powerventure Semiconductor PV88080 PMIC.
> + This includes the I2C driver and core APIs.
> + Additional drivers must be enabled in order to use the functionality
> + of the device.
> +
> config MFD_QCOM_RPM
> tristate "Qualcomm Resource Power Manager (RPM)"
> depends on ARCH_QCOM && OF
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index db39377..e9e16c6 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -173,6 +173,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
> obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
> obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
> obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o
> +obj-$(CONFIG_MFD_PV88080) += pv88080.o
> obj-$(CONFIG_MFD_QCOM_RPM) += qcom_rpm.o
> obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
> obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
> diff --git a/drivers/mfd/pv88080.c b/drivers/mfd/pv88080.c
> new file mode 100644
> index 0000000..518b44f
> --- /dev/null
> +++ b/drivers/mfd/pv88080.c
> @@ -0,0 +1,331 @@
> +/*
> + * pv88080-i2c.c - I2C access driver for PV88080
Remove the filename.
They have a habit of becoming out of date (like now).
> + * Copyright (C) 2016 Powerventure Semiconductor Ltd.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
Alphabetical.
> +#include <linux/mfd/pv88080.h>
This doesn't need to be separated from the rest.
> +#define PV88080_REG_EVENT_A_OFFSET 0
> +#define PV88080_REG_EVENT_B_OFFSET 1
> +#define PV88080_REG_EVENT_C_OFFSET 2
Spaces after 'define'.
> +static const struct resource regulators_aa_resources[] = {
> + {
> + .name = "VDD_TEMP_FAULT",
> + .start = PV88080_AA_IRQ_VDD_FLT,
> + .end = PV88080_AA_IRQ_OVER_TEMP,
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static const struct resource regulators_ba_resources[] = {
> + {
> + .name = "VDD_TEMP_FAULT",
> + .start = PV88080_BA_IRQ_VDD_FLT,
> + .end = PV88080_BA_IRQ_OVER_TEMP,
> + .flags = IORESOURCE_IRQ,
> + },
> +};
Use the DEFINE_RES_* macros.
> +static const struct mfd_cell pv88080_aa_cells[] = {
> + {
> + .name = "pv88080-regulator",
> + .num_resources = ARRAY_SIZE(regulators_aa_resources),
> + .resources = regulators_aa_resources,
> + .of_compatible = "pvs,pv88080-regulator",
> + },
> + {
> + .name = "pv88080-gpio",
> + .of_compatible = "pvs,pv88080-gpio",
> + },
> +};
> +
> +static const struct mfd_cell pv88080_ba_cells[] = {
> + {
> + .name = "pv88080-regulator",
> + .num_resources = ARRAY_SIZE(regulators_ba_resources),
> + .resources = regulators_ba_resources,
> + .of_compatible = "pvs,pv88080-regulator",
> + },
> + {
> + .name = "pv88080-gpio",
> + .of_compatible = "pvs,pv88080-gpio",
> + },
> +};
> +
> +static const struct regmap_irq pv88080_aa_irqs[] = {
> + /* PV88080 event A register for AA/AB silicon */
> + [PV88080_AA_IRQ_VDD_FLT] = {
> + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> + .mask = PV88080_M_VDD_FLT,
> + },
> + [PV88080_AA_IRQ_OVER_TEMP] = {
> + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> + .mask = PV88080_M_OVER_TEMP,
> + },
> + [PV88080_AA_IRQ_SEQ_RDY] = {
> + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> + .mask = PV88080_M_SEQ_RDY,
> + },
> + /* PV88080 event B register for AA/AB silicon */
> + [PV88080_AA_IRQ_HVBUCK_OV] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_HVBUCK_OV,
> + },
> + [PV88080_AA_IRQ_HVBUCK_UV] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_HVBUCK_UV,
> + },
> + [PV88080_AA_IRQ_HVBUCK_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_HVBUCK_SCP,
> + },
> + [PV88080_AA_IRQ_BUCK1_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_BUCK1_SCP,
> + },
> + [PV88080_AA_IRQ_BUCK2_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_BUCK2_SCP,
> + },
> + [PV88080_AA_IRQ_BUCK3_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_BUCK3_SCP,
> + },
> + /* PV88080 event C register for AA/AB silicon */
> + [PV88080_AA_IRQ_GPIO_FLAG0] = {
> + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> + .mask = PV88080_M_GPIO_FLAG0,
> + },
> + [PV88080_AA_IRQ_GPIO_FLAG1] = {
> + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> + .mask = PV88080_M_GPIO_FLAG1,
> + },
> +};
> +
> +static const struct regmap_irq pv88080_ba_irqs[] = {
> + /* PV88080 event A register for BA/BB silicon */
> + [PV88080_BA_IRQ_VDD_FLT] = {
> + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> + .mask = PV88080_M_VDD_FLT,
> + },
> + [PV88080_BA_IRQ_OVER_TEMP] = {
> + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> + .mask = PV88080_M_OVER_TEMP,
> + },
> + [PV88080_BA_IRQ_SEQ_RDY] = {
> + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> + .mask = PV88080_M_SEQ_RDY,
> + },
> + [PV88080_BA_IRQ_EXT_OT] = {
> + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> + .mask = PV88080_M_EXT_OT,
> + },
> + /* PV88080 event B register for BA/BB silicon */
> + [PV88080_BA_IRQ_HVBUCK_OV] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_HVBUCK_OV,
> + },
> + [PV88080_BA_IRQ_HVBUCK_UV] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_HVBUCK_UV,
> + },
> + [PV88080_BA_IRQ_HVBUCK_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_HVBUCK_SCP,
> + },
> + [PV88080_BA_IRQ_BUCK1_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_BUCK1_SCP,
> + },
> + [PV88080_BA_IRQ_BUCK2_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_BUCK2_SCP,
> + },
> + [PV88080_BA_IRQ_BUCK3_SCP] = {
> + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> + .mask = PV88080_M_BUCK3_SCP,
> + },
> + /* PV88080 event C register for BA/BB silicon */
> + [PV88080_BA_IRQ_GPIO_FLAG0] = {
> + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> + .mask = PV88080_M_GPIO_FLAG0,
> + },
> + [PV88080_BA_IRQ_GPIO_FLAG1] = {
> + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> + .mask = PV88080_M_GPIO_FLAG1,
> + },
> + [PV88080_BA_IRQ_BUCK1_DROP_TIMEOUT] = {
> + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> + .mask = PV88080_M_BUCK1_DROP_TIMEOUT,
> + },
> + [PV88080_BA_IRQ_BUCK2_DROP_TIMEOUT] = {
> + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> + .mask = PV88080_M_BUCK2_DROP_TIMEOUT,
> + },
> + [PB88080_BA_IRQ_BUCK3_DROP_TIMEOUT] = {
> + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> + .mask = PV88080_M_BUCk3_DROP_TIMEOUT,
> + },
> +};
> +
> +static const struct regmap_irq_chip pv88080_aa_irq_chip = {
> + .name = "pv88080-irq",
> + .irqs = pv88080_aa_irqs,
> + .num_irqs = ARRAY_SIZE(pv88080_aa_irqs),
> + .num_regs = 3,
> + .status_base = PV88080_REG_EVENT_A,
> + .mask_base = PV88080_REG_MASK_A,
> + .ack_base = PV88080_REG_EVENT_A,
> + .init_ack_masked = true,
> +};
> +
> +static const struct regmap_irq_chip pv88080_ba_irq_chip = {
> + .name = "pv88080-irq",
> + .irqs = pv88080_ba_irqs,
> + .num_irqs = ARRAY_SIZE(pv88080_ba_irqs),
> + .num_regs = 3,
> + .status_base = PV88080_REG_EVENT_A,
> + .mask_base = PV88080_REG_MASK_A,
> + .ack_base = PV88080_REG_EVENT_A,
> + .init_ack_masked = true,
> +};
> +
> +static const struct regmap_config pv88080_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> +};
> +
> +static const struct of_device_id pv88080_of_match_table[] = {
> + { .compatible = "pvs,pv88080", .data = (void *)TYPE_PV88080_AA },
> + { .compatible = "pvs,pv88080-aa", .data = (void *)TYPE_PV88080_AA },
> + { .compatible = "pvs,pv88080-ba", .data = (void *)TYPE_PV88080_BA },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, pv88080_of_match_table);
> +
> +static int pv88080_probe(struct i2c_client *client,
> + const struct i2c_device_id *ids)
> +{
> + struct pv88080 *chip;
> + const struct of_device_id *match;
> + const struct regmap_irq_chip *pv88080_irq_chips;
> + const struct mfd_cell *pv88080_mfd_cells;
> + int ret, n_devs;
> +
> + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> + if (!chip)
> + return -ENOMEM;
> +
> + if (client->dev.of_node) {
> + match = of_match_node(pv88080_of_match_table,
> + client->dev.of_node);
> + if (!match) {
> + dev_err(&client->dev, "Failed to get of_match_node\n");
> + return -EINVAL;
-ENODEV
> + }
> + chip->type = (unsigned long)match->data;
> + } else {
> + chip->type = ids->driver_data;
> + }
> +
> + i2c_set_clientdata(client, chip);
> +
> + chip->irq = client->irq;
> + chip->dev = &client->dev;
> +
> + chip->regmap = devm_regmap_init_i2c(client, &pv88080_regmap_config);
> + if (IS_ERR(chip->regmap)) {
> + dev_err(chip->dev, "Failed to initialize register map\n");
> + return PTR_ERR(chip->regmap);
> + }
> +
> + ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF);
> + if (ret < 0) {
> + dev_err(chip->dev, "Failed to mask A reg: %d\n", ret);
> + return ret;
> + }
> + ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF);
> + if (ret < 0) {
> + dev_err(chip->dev, "Failed to mask B reg: %d\n", ret);
> + return ret;
> + }
> + ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF);
> + if (ret < 0) {
> + dev_err(chip->dev, "Failed to mask C reg: %d\n", ret);
> + return ret;
> + }
What do these calls do?
> + switch (chip->type) {
> + case TYPE_PV88080_AA:
> + pv88080_irq_chips = &pv88080_aa_irq_chip;
> + pv88080_mfd_cells = pv88080_aa_cells;
> + n_devs = ARRAY_SIZE(pv88080_aa_cells);
> + break;
> + case TYPE_PV88080_BA:
> + pv88080_irq_chips = &pv88080_ba_irq_chip;
> + pv88080_mfd_cells = pv88080_ba_cells;
> + n_devs = ARRAY_SIZE(pv88080_ba_cells);
> + break;
> + }
> +
> + ret = devm_regmap_add_irq_chip(chip->dev, chip->regmap,
> + chip->irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> + 0, pv88080_irq_chips, &chip->irq_data);
> + if (ret) {
> + dev_err(chip->dev, "Failed to add IRQ %d: %d\n",
> + chip->irq, ret);
> + return ret;
> + }
> +
> + ret = devm_mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE,
> + pv88080_mfd_cells, n_devs,
> + NULL, 0, NULL);
> + if (ret) {
> + dev_err(chip->dev, "Failed to add MFD devices\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct i2c_device_id pv88080_id_table[] = {
> + { "pv88080", TYPE_PV88080_AA },
> + { "pv88080-aa", TYPE_PV88080_AA },
> + { "pv88080-ba", TYPE_PV88080_BA },
> + { },
> +};
> +MODULE_DEVICE_TABLE(i2c, pv88080_id_table);
> +
> +static struct i2c_driver pv88080_driver = {
> + .driver = {
> + .name = "pv88080",
> + .of_match_table = of_match_ptr(pv88080_of_match_table),
> + },
> + .probe = pv88080_probe,
> + .id_table = pv88080_id_table,
> +};
> +module_i2c_driver(pv88080_driver);
> +
> +MODULE_AUTHOR("Eric Jeong <eric.jeong.opensource@diasemi.com>");
> +MODULE_DESCRIPTION("MFD Driver for Powerventure PV88080");
> +MODULE_LICENSE("GPL");
> +
> diff --git a/include/linux/mfd/pv88080.h b/include/linux/mfd/pv88080.h
> new file mode 100644
> index 0000000..76d6656
> --- /dev/null
> +++ b/include/linux/mfd/pv88080.h
> @@ -0,0 +1,222 @@
> +/*
> + * pv88080.h - Declarations for PV88080.
Remove filename.
> + * Copyright (C) 2016 Powerventure Semiconductor Ltd.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __PV88080_H__
> +#define __PV88080_H__
> +
> +#include <linux/regulator/machine.h>
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +
> +/* System Control and Event Registers */
> +#define PV88080_REG_STATUS_A 0x01
> +#define PV88080_REG_EVENT_A 0x04
> +#define PV88080_REG_MASK_A 0x09
> +#define PV88080_REG_MASK_B 0x0A
> +#define PV88080_REG_MASK_C 0x0B
> +
> +/* GPIO Registers - rev. AA */
> +#define PV88080AA_REG_GPIO_INPUT 0x18
> +#define PV88080AA_REG_GPIO_OUTPUT 0x19
> +#define PV88080AA_REG_GPIO_GPIO0 0x1A
> +
> +/* Regulator Registers - rev. AA */
> +#define PV88080AA_REG_HVBUCK_CONF1 0x2D
> +#define PV88080AA_REG_HVBUCK_CONF2 0x2E
> +#define PV88080AA_REG_BUCK1_CONF0 0x27
> +#define PV88080AA_REG_BUCK1_CONF1 0x28
> +#define PV88080AA_REG_BUCK1_CONF2 0x59
> +#define PV88080AA_REG_BUCK1_CONF5 0x5C
> +#define PV88080AA_REG_BUCK2_CONF0 0x29
> +#define PV88080AA_REG_BUCK2_CONF1 0x2A
> +#define PV88080AA_REG_BUCK2_CONF2 0x61
> +#define PV88080AA_REG_BUCK2_CONF5 0x64
> +#define PV88080AA_REG_BUCK3_CONF0 0x2B
> +#define PV88080AA_REG_BUCK3_CONF1 0x2C
> +#define PV88080AA_REG_BUCK3_CONF2 0x69
> +#define PV88080AA_REG_BUCK3_CONF5 0x6C
> +
> +/* GPIO Registers - rev. BA */
> +#define PV88080BA_REG_GPIO_INPUT 0x17
> +#define PV88080BA_REG_GPIO_OUTPUT 0x18
> +#define PV88080BA_REG_GPIO_GPIO0 0x19
> +
> +/* Regulator Registers - rev. BA */
> +#define PV88080BA_REG_HVBUCK_CONF1 0x33
> +#define PV88080BA_REG_HVBUCK_CONF2 0x34
> +#define PV88080BA_REG_BUCK1_CONF0 0x2A
> +#define PV88080BA_REG_BUCK1_CONF1 0x2C
> +#define PV88080BA_REG_BUCK1_CONF2 0x5A
> +#define PV88080BA_REG_BUCK1_CONF5 0x5D
> +#define PV88080BA_REG_BUCK2_CONF0 0x2D
> +#define PV88080BA_REG_BUCK2_CONF1 0x2F
> +#define PV88080BA_REG_BUCK2_CONF2 0x63
> +#define PV88080BA_REG_BUCK2_CONF5 0x66
> +#define PV88080BA_REG_BUCK3_CONF0 0x30
> +#define PV88080BA_REG_BUCK3_CONF1 0x32
> +#define PV88080BA_REG_BUCK3_CONF2 0x6C
> +#define PV88080BA_REG_BUCK3_CONF5 0x6F
> +
> +/* PV88080_REG_EVENT_A (addr=0x04) */
> +#define PV88080_E_VDD_FLT 0x01
> +#define PV88080_E_OVER_TEMP 0x02
> +#define PV88080_E_SEQ_RDY 0x04
> +#define PV88080_E_EXT_OT 0x08
> +
> +/* PV88080_REG_MASK_A (addr=0x09) */
> +#define PV88080_M_VDD_FLT 0x01
> +#define PV88080_M_OVER_TEMP 0x02
> +#define PV88080_M_SEQ_RDY 0x04
> +#define PV88080_M_EXT_OT 0x08
> +
> +/* PV88080_REG_EVENT_B (addr=0x05) */
> +#define PV88080_E_HVBUCK_OV 0x01
> +#define PV88080_E_HVBUCK_UV 0x02
> +#define PV88080_E_HVBUCK_SCP 0x04
> +#define PV88080_E_BUCK1_SCP 0x08
> +#define PV88080_E_BUCK2_SCP 0x10
> +#define PV88080_E_BUCK3_SCP 0x20
> +
> +/* PV88080_REG_MASK_B (addr=0x0A) */
> +#define PV88080_M_HVBUCK_OV 0x01
> +#define PV88080_M_HVBUCK_UV 0x02
> +#define PV88080_M_HVBUCK_SCP 0x04
> +#define PV88080_M_BUCK1_SCP 0x08
> +#define PV88080_M_BUCK2_SCP 0x10
> +#define PV88080_M_BUCK3_SCP 0x20
> +
> +/* PV88080_REG_EVENT_C (addr=0x06) */
> +#define PV88080_E_GPIO_FLAG0 0x01
> +#define PV88080_E_GPIO_FLAG1 0x02
> +#define PV88080_E_BUCK1_DROP_TIMEOUT 0x08
> +#define PV88080_E_BUCK2_DROP_TIMEOUT 0x10
> +#define PV88080_E_BUCk3_DROP_TIMEOUT 0x20
> +
> +/* PV88080_REG_MASK_C (addr=0x0B) */
> +#define PV88080_M_GPIO_FLAG0 0x01
> +#define PV88080_M_GPIO_FLAG1 0x02
> +#define PV88080_M_BUCK1_DROP_TIMEOUT 0x08
> +#define PV88080_M_BUCK2_DROP_TIMEOUT 0x10
> +#define PV88080_M_BUCk3_DROP_TIMEOUT 0x20
> +
> +/* PV88080xx_REG_GPIO_GPIO0 (addr=0x1A|0x19) */
> +#define PV88080_GPIO_DIRECTION_MASK 0x01
> +#define PV88080_GPIO_SINGLE_ENDED_MASK 0x02
> +
> +/* PV88080_REG_BUCK1_CONF0 (addr=0x27|0x2A) */
> +#define PV88080_BUCK1_EN 0x80
> +#define PV88080_VBUCK1_MASK 0x7F
> +
> +/* PV88080_REG_BUCK2_CONF0 (addr=0x29|0x2D) */
> +#define PV88080_BUCK2_EN 0x80
> +#define PV88080_VBUCK2_MASK 0x7F
> +
> +/* PV88080_REG_BUCK3_CONF0 (addr=0x2B|0x30) */
> +#define PV88080_BUCK3_EN 0x80
> +#define PV88080_VBUCK3_MASK 0x7F
> +
> +/* PV88080_REG_BUCK1_CONF1 (addr=0x28|0x2C) */
> +#define PV88080_BUCK1_ILIM_SHIFT 2
> +#define PV88080_BUCK1_ILIM_MASK 0x0C
> +#define PV88080_BUCK1_MODE_MASK 0x03
> +
> +/* PV88080_REG_BUCK2_CONF1 (addr=0x2A|0x2F) */
> +#define PV88080_BUCK2_ILIM_SHIFT 2
> +#define PV88080_BUCK2_ILIM_MASK 0x0C
> +#define PV88080_BUCK2_MODE_MASK 0x03
> +
> +/* PV88080_REG_BUCK3_CONF1 (addr=0x2C|0x32) */
> +#define PV88080_BUCK3_ILIM_SHIFT 2
> +#define PV88080_BUCK3_ILIM_MASK 0x0C
> +#define PV88080_BUCK3_MODE_MASK 0x03
> +
> +#define PV88080_BUCK_MODE_SLEEP 0x00
> +#define PV88080_BUCK_MODE_AUTO 0x01
> +#define PV88080_BUCK_MODE_SYNC 0x02
> +
> +/* PV88080_REG_HVBUCK_CONF1 (addr=0x2D|0x33) */
> +#define PV88080_VHVBUCK_MASK 0xFF
> +
> +/* PV88080_REG_HVBUCK_CONF1 (addr=0x2E|0x34) */
> +#define PV88080_HVBUCK_EN 0x01
> +
> +/* PV88080_REG_BUCK2_CONF2 (addr=0x61|0x63) */
> +/* PV88080_REG_BUCK3_CONF2 (addr=0x69|0x6C) */
> +#define PV88080_BUCK_VDAC_RANGE_SHIFT 7
> +#define PV88080_BUCK_VDAC_RANGE_MASK 0x01
> +
> +#define PV88080_BUCK_VDAC_RANGE_1 0x00
> +#define PV88080_BUCK_VDAC_RANGE_2 0x01
> +
> +/* PV88080_REG_BUCK2_CONF5 (addr=0x64|0x66) */
> +/* PV88080_REG_BUCK3_CONF5 (addr=0x6C|0x6F) */
> +#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0
> +#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
> +
> +#define PV88080_BUCK_VRANGE_GAIN_1 0x00
> +#define PV88080_BUCK_VRANGE_GAIN_2 0x01
> +
> +#define PV88080_MAX_REGULATORS 4
> +
> +enum pv88080_types {
> + TYPE_PV88080_AA,
> + TYPE_PV88080_BA,
> +};
> +
> +/* Interrupts */
> +enum pv88080_aa_irqs {
> + PV88080_AA_IRQ_VDD_FLT,
> + PV88080_AA_IRQ_OVER_TEMP,
> + PV88080_AA_IRQ_SEQ_RDY,
> + PV88080_AA_IRQ_HVBUCK_OV,
> + PV88080_AA_IRQ_HVBUCK_UV,
> + PV88080_AA_IRQ_HVBUCK_SCP,
> + PV88080_AA_IRQ_BUCK1_SCP,
> + PV88080_AA_IRQ_BUCK2_SCP,
> + PV88080_AA_IRQ_BUCK3_SCP,
> + PV88080_AA_IRQ_GPIO_FLAG0,
> + PV88080_AA_IRQ_GPIO_FLAG1,
> +};
> +
> +enum pv88080_ba_irqs {
> + PV88080_BA_IRQ_VDD_FLT,
> + PV88080_BA_IRQ_OVER_TEMP,
> + PV88080_BA_IRQ_SEQ_RDY,
> + PV88080_BA_IRQ_EXT_OT,
> + PV88080_BA_IRQ_HVBUCK_OV,
> + PV88080_BA_IRQ_HVBUCK_UV,
> + PV88080_BA_IRQ_HVBUCK_SCP,
> + PV88080_BA_IRQ_BUCK1_SCP,
> + PV88080_BA_IRQ_BUCK2_SCP,
> + PV88080_BA_IRQ_BUCK3_SCP,
> + PV88080_BA_IRQ_GPIO_FLAG0,
> + PV88080_BA_IRQ_GPIO_FLAG1,
> + PV88080_BA_IRQ_BUCK1_DROP_TIMEOUT,
> + PV88080_BA_IRQ_BUCK2_DROP_TIMEOUT,
> + PB88080_BA_IRQ_BUCK3_DROP_TIMEOUT,
> +};
> +
> +struct pv88080 {
> + struct device *dev;
> + struct regmap *regmap;
> + unsigned long type;
Does this really need to be in here?
> + /* IRQ Data */
> + int irq;
> + struct regmap_irq_chip_data *irq_data;
> +};
> +
> +#endif /* __PV88080_H__ */
> +
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH v2 5/8] dt-bindings: mfd: Provide human readable defines for TPS65217 interrupts
From: Milo Kim @ 2016-11-21 13:05 UTC (permalink / raw)
To: Tony Lindgren, Lee Jones
Cc: bcousson, linux-omap, devicetree, linux-arm-kernel, linux-kernel,
Robert Nelson
In-Reply-To: <20161118151051.GV4082@atomide.com>
On 11/19/2016 12:10 AM, Tony Lindgren wrote:
>>> +#define TPS65217_IRQ_USB 0
>>> > > +#define TPS65217_IRQ_AC 1
>>> > > +#define TPS65217_IRQ_PB 2
>> >
>> > What are "AC" and "PB". Seeing as these are meant to be "human
>> > readable", let's make them more human friendly.
> Good idea. Milo, please do an incremental single follow-up patch as
> I already have applied this and the dts changes using it.
Thanks for catching this. Let me send a patch soon.
Best regards,
Milo
^ permalink raw reply
* Re: [RFC PATCH v2 2/7] misc: minimal mux subsystem and gpio-based mux controller
From: Peter Rosin @ 2016-11-21 13:03 UTC (permalink / raw)
To: Jonathan Cameron, linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, Arnd Bergmann,
Greg Kroah-Hartman, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <7fad4fd7-fffe-5214-b25f-dca923f8c466-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 2016-11-19 16:34, Jonathan Cameron wrote:
> On 17/11/16 21:48, Peter Rosin wrote:
>> When both the iio subsystem and the i2c subsystem wants to update
>> the same mux, there needs to be some coordination. Invent a new
>> minimal "mux" subsystem that handles this.
> I'd probably put something more general in the description. Lots of things
> may need the same infrastructure. This is just an example.
I'll make it more general for the next round.
> Few bits inline.
>
> Also, I suspect you will fairly rapidly have a need for a strobe signal
> as well. A lot of mux chips that are more than 2 way seem to have them to
> allow multiple chips to be synchronized.
I think that can be easily added later, when/if it's needed.
>>
>> Add a single backend driver for this new subsystem that can
>> control gpio based multiplexers.
>> ---
>> drivers/misc/Kconfig | 6 +
>> drivers/misc/Makefile | 2 +
>> drivers/misc/mux-core.c | 299 ++++++++++++++++++++++++++++++++++++++++++++++++
>> drivers/misc/mux-gpio.c | 115 +++++++++++++++++++
>> include/linux/mux.h | 53 +++++++++
>> 5 files changed, 475 insertions(+)
>> create mode 100644 drivers/misc/mux-core.c
>> create mode 100644 drivers/misc/mux-gpio.c
>> create mode 100644 include/linux/mux.h
>>
>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>> index 64971baf11fa..9e119bb78d82 100644
>> --- a/drivers/misc/Kconfig
>> +++ b/drivers/misc/Kconfig
>> @@ -766,6 +766,12 @@ config PANEL_BOOT_MESSAGE
>> An empty message will only clear the display at driver init time. Any other
>> printf()-formatted message is valid with newline and escape codes.
>>
>> +config MUX_GPIO
>> + tristate "GPIO-controlled MUX controller"
>> + depends on OF
>> + help
>> + GPIO-controlled MUX controller
>> +
>> source "drivers/misc/c2port/Kconfig"
>> source "drivers/misc/eeprom/Kconfig"
>> source "drivers/misc/cb710/Kconfig"
>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>> index 31983366090a..92b547bcbac1 100644
>> --- a/drivers/misc/Makefile
>> +++ b/drivers/misc/Makefile
>> @@ -53,6 +53,8 @@ obj-$(CONFIG_ECHO) += echo/
>> obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
>> obj-$(CONFIG_CXL_BASE) += cxl/
>> obj-$(CONFIG_PANEL) += panel.o
>> +obj-$(CONFIG_MUX_GPIO) += mux-core.o
>> +obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
>>
>> lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
>> lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
>> diff --git a/drivers/misc/mux-core.c b/drivers/misc/mux-core.c
>> new file mode 100644
>> index 000000000000..7a8bf003a92c
>> --- /dev/null
>> +++ b/drivers/misc/mux-core.c
>> @@ -0,0 +1,299 @@
>> +/*
>> + * Multiplexer subsystem
>> + *
>> + * Copyright (C) 2016 Axentia Technologies AB
>> + *
>> + * 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 <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/idr.h>
>> +#include <linux/module.h>
>> +#include <linux/mux.h>
>> +#include <linux/of.h>
>> +#include <linux/slab.h>
>> +
>> +static struct bus_type mux_bus_type = {
>> + .name = "mux",
>> +};
>> +
>> +static int __init mux_init(void)
>> +{
>> + return bus_register(&mux_bus_type);
>> +}
>> +
>> +static void __exit mux_exit(void)
>> +{
>> + bus_unregister(&mux_bus_type);
>> +}
>> +
>> +static DEFINE_IDA(mux_ida);
>> +
>> +static void mux_control_release(struct device *dev)
>> +{
>> + struct mux_control *mux = to_mux_control(dev);
>> +
>> + ida_simple_remove(&mux_ida, mux->id);
>> + kfree(mux);
>> +}
>> +
>> +static struct device_type mux_control_type = {
>> + .name = "mux-control",
>> + .release = mux_control_release,
>> +};
>> +
>> +/*
>> + * Allocate a mux-control, plus an extra memory area for private use
>> + * by the caller.
>> + */
>> +struct mux_control *mux_control_alloc(size_t sizeof_priv)
>> +{
>> + struct mux_control *mux;
>> +
> Worth planning ahead for spi controlled muxes and others that need their
> structures to be carefully aligned to avoid dma cacheline fun?
> Easy enough to add later I guess.
Right, I'll leave it for later when/if it's needed.
>> + mux = kzalloc(sizeof(*mux) + sizeof_priv, GFP_KERNEL);
>> + if (!mux)
>> + return NULL;
>> +
>> + mux->dev.bus = &mux_bus_type;
>> + mux->dev.type = &mux_control_type;
>> + device_initialize(&mux->dev);
>> + dev_set_drvdata(&mux->dev, mux);
>> +
>> + init_rwsem(&mux->lock);
>> + mux->priv = mux + 1;
> Needed? Or just do it with a bit of pointer math where the access is needed?
Good suggestion, I'll add an inline function and drop the priv member.
>> +
>> + mux->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL);
>> + if (mux->id < 0) {
>> + pr_err("mux-controlX failed to get device id\n");
>> + kfree(mux);
>> + return NULL;
>> + }
>> + dev_set_name(&mux->dev, "mux:control%d", mux->id);
>> +
>> + mux->cached_state = -1;
>> + mux->idle_state = -1;
>> +
>> + return mux;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_alloc);
>> +
>> +/*
>> + * Register the mux-control, thus readying it for use.
> Either single line comment style - or perhaps kernel doc the lot...
Kernel doc was the plan from the start, coming up...
>> + */
>> +int mux_control_register(struct mux_control *mux)
>> +{
>> + /* If the calling driver did not initialize of_node, do it here */
>> + if (!mux->dev.of_node && mux->dev.parent)
>> + mux->dev.of_node = mux->dev.parent->of_node;
>> +
>> + return device_add(&mux->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_register);
>> +
>> +/*
>> + * Take the mux-control off-line.
>> + */
>> +void mux_control_unregister(struct mux_control *mux)
>> +{
>> + device_del(&mux->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_unregister);
>> +
>> +/*
>> + * Put away the mux-control for good.
>> + */
>> +void mux_control_put(struct mux_control *mux)
>> +{
>> + if (!mux)
>> + return;
>> + put_device(&mux->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_put);
>> +
>> +static int mux_control_set(struct mux_control *mux, int state)
>> +{
>> + int ret = mux->ops->set(mux, state);
>> +
>> + mux->cached_state = ret < 0 ? -1 : state;
>> +
>> + return ret;
>> +}
>> +
>> +/*
>> + * Select the given multiplexer channel. Call mux_control_deselect()
>> + * when the operation is complete on the multiplexer channel, and the
>> + * multiplexer is free for others to use.
>> + */
>> +int mux_control_select(struct mux_control *mux, int state)
>> +{
>> + int ret;
>> +
>> + if (down_read_trylock(&mux->lock)) {
>> + if (mux->cached_state == state)
>> + return 0;
>> +
>> + /* Sigh, the mux needs updating... */
>> + up_read(&mux->lock);
>> + }
>> +
>> + /* ...or it's just contended. */
>> + down_write(&mux->lock);
>> +
>> + if (mux->cached_state == state) {
>> + /*
>> + * Hmmm, someone else changed the mux to my liking.
>> + * That makes me wonder how long I waited for nothing...
>> + */
>> + downgrade_write(&mux->lock);
>> + return 0;
>> + }
>> +
>> + ret = mux_control_set(mux, state);
>> + if (ret < 0) {
>> + if (mux->idle_state != -1)
>> + mux_control_set(mux, mux->idle_state);
>> +
>> + up_write(&mux->lock);
>> + return ret;
>> + }
>> +
>> + downgrade_write(&mux->lock);
>> +
>> + return 1;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_select);
>> +
>> +/*
>> + * Deselect the previously selected multiplexer channel.
>> + */
>> +int mux_control_deselect(struct mux_control *mux)
>> +{
>> + int ret = 0;
>> +
>> + if (mux->idle_state != -1 && mux->cached_state != mux->idle_state)
>> + ret = mux_control_set(mux, mux->idle_state);
>> +
>> + up_read(&mux->lock);
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_deselect);
>> +
>> +static int of_dev_node_match(struct device *dev, void *data)
>> +{
>> + return dev->of_node == data;
>> +}
>> +
>> +static struct mux_control *of_find_mux_by_node(struct device_node *np)
>> +{
>> + struct device *dev;
>> +
>> + dev = bus_find_device(&mux_bus_type, NULL, np, of_dev_node_match);
>> +
>> + return dev ? to_mux_control(dev) : NULL;
>> +}
>> +
>> +static struct mux_control *of_mux_control_get(struct device_node *np, int index)
>> +{
>> + struct device_node *mux_np;
>> + struct mux_control *mux;
>> +
>> + mux_np = of_parse_phandle(np, "control-muxes", index);
>> + if (!mux_np)
>> + return NULL;
>> +
>> + mux = of_find_mux_by_node(mux_np);
>> + of_node_put(mux_np);
>> +
>> + return mux;
>> +}
>> +
>> +/*
>> + * Get a named mux.
>> + */
>> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>> +{
>> + struct device_node *np = dev->of_node;
>> + struct mux_control *mux;
>> + int index;
>> +
>> + index = of_property_match_string(np, "control-mux-names", mux_name);
>> + if (index < 0) {
>> + dev_err(dev, "failed to get control-mux %s:%s(%i)\n",
>> + np->full_name, mux_name ?: "", index);
>> + return ERR_PTR(index);
>> + }
>> +
>> + mux = of_mux_control_get(np, index);
>> + if (!mux)
>> + return ERR_PTR(-EPROBE_DEFER);
>> +
>> + return mux;
>> +}
>> +EXPORT_SYMBOL_GPL(mux_control_get);
>> +
>> +static void devm_mux_control_free(struct device *dev, void *res)
>> +{
>> + struct mux_control *mux = *(struct mux_control **)res;
>> +
>> + mux_control_put(mux);
>> +}
>> +
>> +/*
>> + * Get a named mux, with resource management.
>> + */
> Guess it might be elsewhere in patch set but remember to add this to
> the global list of devm interfaces (in Documentation somewhere.. IIRC)
Right, now that you mention it, I remember having seen that document
at some point. I'll look it up.
Thanks for all comments!
Cheers,
Peter
>> +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_free, 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);
>> +
>> +static int devm_mux_control_match(struct device *dev, void *res, void *data)
>> +{
>> + struct mux_control **r = res;
>> +
>> + if (!r || !*r) {
>> + WARN_ON(!r || !*r);
>> + return 0;
>> + }
>> +
>> + return *r == data;
>> +}
>> +
>> +/*
>> + * Resource-managed version mux_control_put.
>> + */
>> +void devm_mux_control_put(struct device *dev, struct mux_control *mux)
>> +{
>> + WARN_ON(devres_release(dev, devm_mux_control_free,
>> + devm_mux_control_match, mux));
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_control_put);
>> +
>> +subsys_initcall(mux_init);
>> +module_exit(mux_exit);
>> +
>> +MODULE_AUTHOR("Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org");
>> +MODULE_DESCRIPTION("MUX subsystem");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/misc/mux-gpio.c b/drivers/misc/mux-gpio.c
>> new file mode 100644
>> index 000000000000..2ddd7fb24078
>> --- /dev/null
>> +++ b/drivers/misc/mux-gpio.c
>> @@ -0,0 +1,115 @@
>> +/*
>> + * GPIO-controlled multiplexer driver
>> + *
>> + * Copyright (C) 2016 Axentia Technologies AB
>> + *
>> + * 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.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/platform_device.h>
>> +
>> +struct mux_gpio {
>> + struct gpio_descs *gpios;
>> +};
>> +
>> +static int mux_gpio_set(struct mux_control *mux, int val)
>> +{
>> + struct mux_gpio *mux_gpio = mux->priv;
>> + int i;
>> +
>> + for (i = 0; i < mux_gpio->gpios->ndescs; i++)
>> + gpiod_set_value_cansleep(mux_gpio->gpios->desc[i],
>> + val & (1 << i));
>> +
>> + 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 = "mux-gpio", },
>> + { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
>> +
>> +static int mux_gpio_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct device_node *np = pdev->dev.of_node;
>> + struct mux_control *mux;
>> + struct mux_gpio *mux_gpio;
>> + u32 idle_state;
>> + int ret;
>> +
>> + if (!np)
>> + return -ENODEV;
>> +
>> + mux = mux_control_alloc(sizeof(*mux_gpio));
>> + if (!mux)
>> + return -ENOMEM;
>> + mux_gpio = mux->priv;
>> + mux->dev.parent = dev;
>> + mux->ops = &mux_gpio_ops;
>> +
>> + platform_set_drvdata(pdev, mux);
>> +
>> + mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
>> + if (IS_ERR(mux_gpio->gpios)) {
>> + if (PTR_ERR(mux_gpio->gpios) != -EPROBE_DEFER)
>> + dev_err(dev, "failed to get gpios\n");
>> + mux_control_put(mux);
>> + return PTR_ERR(mux_gpio->gpios);
>> + }
>> +
>> + ret = of_property_read_u32(np, "idle-state", &idle_state);
>> + if (ret >= 0) {
>> + if (idle_state >= (1 << mux_gpio->gpios->ndescs)) {
>> + dev_err(dev, "invalid idle-state %u\n", idle_state);
>> + return -EINVAL;
>> + }
>> + mux->idle_state = idle_state;
>> + }
>> +
>> + ret = mux_control_register(mux);
>> + if (ret < 0) {
>> + dev_err(dev, "failed to register mux_control\n");
>> + mux_control_put(mux);
>> + return ret;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int mux_gpio_remove(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct mux_control *mux = to_mux_control(dev);
>> +
>> + mux_control_unregister(mux);
>> + mux_control_put(mux);
>> + return 0;
>> +}
>> +
>> +static struct platform_driver mux_gpio_driver = {
>> + .driver = {
>> + .name = "mux-gpio",
>> + .of_match_table = of_match_ptr(mux_gpio_dt_ids),
>> + },
>> + .probe = mux_gpio_probe,
>> + .remove = mux_gpio_remove,
>> +};
>> +module_platform_driver(mux_gpio_driver);
>> +
>> +MODULE_AUTHOR("Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org");
>> +MODULE_DESCRIPTION("GPIO-controlled multiplexer driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/mux.h b/include/linux/mux.h
>> new file mode 100644
>> index 000000000000..5b21b8184056
>> --- /dev/null
>> +++ b/include/linux/mux.h
>> @@ -0,0 +1,53 @@
>> +/*
>> + * mux.h - definitions for the multiplexer interface
>> + *
>> + * Copyright (C) 2016 Axentia Technologies AB
>> + *
>> + * 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.
>> + */
>> +
>> +#ifndef _LINUX_MUX_H
>> +#define _LINUX_MUX_H
>> +
>> +#include <linux/device.h>
>> +#include <linux/rwsem.h>
>> +
>> +struct mux_control;
>> +
>> +struct mux_control_ops {
>> + int (*set)(struct mux_control *mux, int reg);
>> +};
>> +
>> +struct mux_control {
>> + struct rw_semaphore lock; /* protects the state of the mux */
>> +
>> + struct device dev;
>> + int id;
>> +
>> + int cached_state;
>> + int idle_state;
>> +
>> + const struct mux_control_ops *ops;
>> +
>> + void *priv;
>> +};
>> +
>> +#define to_mux_control(x) container_of((x), struct mux_control, dev)
>> +
>> +struct mux_control *mux_control_alloc(size_t sizeof_priv);
>> +int mux_control_register(struct mux_control *mux);
>> +void mux_control_unregister(struct mux_control *mux);
>> +void mux_control_put(struct mux_control *mux);
>> +
>> +int mux_control_select(struct mux_control *mux, int state);
>> +int mux_control_deselect(struct mux_control *mux);
>> +
>> +struct mux_control *mux_control_get(struct device *dev,
>> + const char *mux_name);
>> +struct mux_control *devm_mux_control_get(struct device *dev,
>> + const char *mux_name);
>> +void devm_mux_control_put(struct device *dev, struct mux_control *mux);
>> +
>> +#endif /* _LINUX_MUX_H */
>>
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V5 1/3] ARM64 LPC: Indirect ISA port IO introduced
From: John Garry @ 2016-11-21 12:58 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Mark Rutland, zhichang.yuan
Cc: catalin.marinas, will.deacon, robh+dt, bhelgaas, olof, arnd,
linux-arm-kernel, lorenzo.pieralisi, linux-kernel, linuxarm,
devicetree, linux-pci, linux-serial, minyard, liviu.dudau,
zourongrong, gabriele.paoloni, zhichang.yuan02, kantyzc, xuwei5,
marc.zyngier
In-Reply-To: <1478647002.7430.69.camel@kernel.crashing.org>
On 08/11/2016 23:16, Benjamin Herrenschmidt wrote:
> On Tue, 2016-11-08 at 12:03 +0000, Mark Rutland wrote:
>> On Tue, Nov 08, 2016 at 11:47:07AM +0800, zhichang.yuan wrote:
>>>
>>> For arm64, there is no I/O space as other architectural platforms, such as
>>> X86. Most I/O accesses are achieved based on MMIO. But for some arm64 SoCs,
>>> such as Hip06, when accessing some legacy ISA devices connected to LPC, those
>>> known port addresses are used to control the corresponding target devices, for
>>> example, 0x2f8 is for UART, 0xe4 is for ipmi-bt. It is different from the
>>> normal MMIO mode in using.
>>
>> This has nothing to do with arm64. Hardware with this kind of indirect
>> bus access could be integrated with a variety of CPU architectures. It
>> simply hasn't been, yet.
>
> On some ppc's we also use similar indirect access methods for IOs. We
> have a generic infrastructure for re-routing some memory or IO regions
> to hooks.
>
> On POWER8, our PCIe doesn't do IO at all, but we have an LPC bus behind
> firmware calls ;-) We use that infrastructure to plumb in the LPC bus.
>
Hi,
I would like to mention another topic on supporting LPC, and this is
regard to eSPI support.
eSPI is seen as the successor for LPC, and some BMCs already support it.
I had a chat with Arnd on this, and the idea to model LPC as a SPI bus
adpater (and also eSPI).
However it seems to me that most platforms will/should support eSPI as a
transparent bridge, same as LPC on x86. So I don't think that this is
much point in modelling LPC/eSPI as a bus.
So we shall continue with indriect-IO support...
Thanks,
John
^ permalink raw reply
* Re: [PATCH V2 2/2] pinctrl: tegra: Add driver to configure voltage and power of io pads
From: Laxman Dewangan @ 2016-11-21 12:49 UTC (permalink / raw)
To: Jon Hunter, linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
thierry.reding-Re5JQEeQqe8AvxtiuMwx3w
Cc: gnurou-Re5JQEeQqe8AvxtiuMwx3w,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <89eaabf1-c830-3ae9-5f34-a7f6d79e0816-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
On Monday 21 November 2016 04:38 PM, Jon Hunter wrote:
>>
>> I had a discussion with the ASIC on this and as per them
>> 1.8 V nominal is (1.62V, 1.98V)
>> 3.3 V nominal is (2.97V,3.63V)
>>
>> I am working with them to update the TRM document but we can assume that
>> this information will be there in TRM.
> My feeling is that if all use-cases today are using either 1.8V or 3.3V,
> then may be we should not worry about this and only support either 1.8V
> or 3.3V. I would be more in favour of supporting other voltages if there
> is a real need.
Sometimes, the regulator will not return exact 1.8V or 3.3V due to the
PMIC rail resolution. On such cases, it returns nearest voltage to 1.8V
or 3.3V.
That's why the PMIC resolution is considered through IO pad voltage
tolerances.
>
>>>> + const struct pinctrl_pin_desc *pins_desc;
>>>> + int num_pins_desc;
>>>> +};
>>>> +
>>>> +struct tegra_io_pads_regulator_info {
>>>> + struct device *dev;
>>>> + const struct tegra_io_pads_cfg_info *pads_cfg;
>>>> + struct regulator *regulator;
>>>> + struct notifier_block regulator_nb;
>>>> +};
>>> Is this struct necessary? Seems to be a lot of duplicated information
>>> from the other structs. Why not add the regulator and regulator_nb to
>>> the main struct? OK, not all io_pads have a regulator but you are only
>>> saving one pointer.
>> Yes, some of IO pads support multi-voltage.
> Yes, but I am saying why not put this information in the main struct and
> not bother having yet another struct where half of the information is
> duplicated.
For regulator notifier callback, we will need the driver data. If I keep
this in the main structure then I will not able to get proper structure
until I make that as global.
The notifier registration is
ret = devm_regulator_register_notifier(regulator,
&rinfo->regulator_nb);
and from the pointer of rinfo->regulator_nb, I will get the rinfo as
rinfo = container_of(nb, struct tegra_io_pads_regulator_info,
regulator_nb);
if I use this in main structure then I will not be able to get the
driver data.
>
>>> + if ((vdata->old_uV > TEGRA_IO_PAD_1800000UV_UPPER_LIMIT) &&
>>> + (vdata->min_uV <= TEGRA_IO_PAD_1800000UV_UPPER_LIMIT))
>>> + break;
>>> The data-sheet for Tegra210 only lists 1.8V or 3.3V as supported
>>> options. Do we need to support a range? Or does the h/w support a range
>>> of voltages? I am just wondering why we cannot check explicitly for 1.8V
>>> or 3.3V and treat anything else as an error.
>> Two voltage level, not range.
> Ok, then I think it would be much simpler if we just support the
> voltages we are using today.
Regulator resolution is only reason here to use tolerance.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 1/6] arm64: arch_timer: Add device tree binding for hisilicon-161601 erratum
From: Ding Tianhong @ 2016-11-21 12:49 UTC (permalink / raw)
To: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
marc.zyngier-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
oss-fOR+EgIDQEHk1uMJSBkQmQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
shawnguo-DgEjT+Ai2ygdnm+yROfE0A, stuart.yoder-3arQi8VN3Tc,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linuxarm-hv44wF8Li93QT0dZR+AlfA,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <1479212167-5812-1-git-send-email-dingtianhong-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Ping....
On 2016/11/15 20:16, Ding Tianhong wrote:
> This erratum describes a bug in logic outside the core, so MIDR can't be
> used to identify its presence, and reading an SoC-specific revision
> register from common arch timer code would be awkward. So, describe it
> in the device tree.
>
> v2: Use the new erratum name and update the description.
>
> Signed-off-by: Ding Tianhong <dingtianhong-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---
> Documentation/devicetree/bindings/arm/arch_timer.txt | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
> index ef5fbe9..c27b2c4 100644
> --- a/Documentation/devicetree/bindings/arm/arch_timer.txt
> +++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
> @@ -31,6 +31,14 @@ to deliver its interrupts via SPIs.
> This also affects writes to the tval register, due to the implicit
> counter read.
>
> +- hisilicon,erratum-161601 : A boolean property. Indicates the presence of
> + erratum 161601, which says that reading the counter is unreliable unless
> + reading twice on the register and the value of the second read is larger
> + than the first by less than 32. If the verification is unsuccessful, then
> + discard the value of this read and repeat this procedure until the verification
> + is successful. This also affects writes to the tval register, due to the
> + implicit counter read.
> +
> ** Optional properties:
>
> - arm,cpu-registers-not-fw-configured : Firmware does not initialize
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] PM / Domains: Fix compatible for domain idle state
From: Brendan Jackman @ 2016-11-21 12:37 UTC (permalink / raw)
To: Lina Iyer
Cc: ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
khilman-DgEjT+Ai2ygdnm+yROfE0A, rjw-LthD3rsA81gm4RdzfppkhA,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
andy.gross-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
lorenzo.pieralisi-5wv7dgnIgG8, sudeep.holla-5wv7dgnIgG8,
Juri.Lelli-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
Rob Herring
In-Reply-To: <1478210075-92045-2-git-send-email-lina.iyer-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Hi,
On Thu, Nov 03 2016 at 21:54, Lina Iyer <lina.iyer-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> Re-using idle state definition provided by arm,idle-state for domain
> idle states creates a lot of confusion and limits further evolution of
> the domain idle definition. To keep things clear and simple, define a
> idle states for domain using a new compatible "domain-idle-state".
>
> Fix existing PM domains code to look for the newly defined compatible.
This looks good to me, pinging for review from others/queue for merge.
Best,
Brendan
>
> Cc: <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
> Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Lina Iyer <lina.iyer-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> .../bindings/power/domain-idle-state.txt | 33 ++++++++++++++++++++++
> .../devicetree/bindings/power/power_domain.txt | 8 +++---
> drivers/base/power/domain.c | 2 +-
> 3 files changed, 38 insertions(+), 5 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/power/domain-idle-state.txt
>
> diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.txt b/Documentation/devicetree/bindings/power/domain-idle-state.txt
> new file mode 100644
> index 0000000..eefc7ed
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/domain-idle-state.txt
> @@ -0,0 +1,33 @@
> +PM Domain Idle State Node:
> +
> +A domain idle state node represents the state parameters that will be used to
> +select the state when there are no active components in the domain.
> +
> +The state node has the following parameters -
> +
> +- compatible:
> + Usage: Required
> + Value type: <string>
> + Definition: Must be "domain-idle-state".
> +
> +- entry-latency-us
> + Usage: Required
> + Value type: <prop-encoded-array>
> + Definition: u32 value representing worst case latency in
> + microseconds required to enter the idle state.
> + The exit-latency-us duration may be guaranteed
> + only after entry-latency-us has passed.
> +
> +- exit-latency-us
> + Usage: Required
> + Value type: <prop-encoded-array>
> + Definition: u32 value representing worst case latency
> + in microseconds required to exit the idle state.
> +
> +- min-residency-us
> + Usage: Required
> + Value type: <prop-encoded-array>
> + Definition: u32 value representing minimum residency duration
> + in microseconds after which the idle state will yield
> + power benefits after overcoming the overhead in entering
> +i the idle state.
> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
> index e165036..723e1ad 100644
> --- a/Documentation/devicetree/bindings/power/power_domain.txt
> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
> @@ -31,7 +31,7 @@ Optional properties:
>
> - domain-idle-states : A phandle of an idle-state that shall be soaked into a
> generic domain power state. The idle state definitions are
> - compatible with arm,idle-state specified in [1].
> + compatible with domain-idle-state specified in [1].
> The domain-idle-state property reflects the idle state of this PM domain and
> not the idle states of the devices or sub-domains in the PM domain. Devices
> and sub-domains have their own idle-states independent of the parent
> @@ -85,7 +85,7 @@ Example 3:
> };
>
> DOMAIN_RET: state@0 {
> - compatible = "arm,idle-state";
> + compatible = "domain-idle-state";
> reg = <0x0>;
> entry-latency-us = <1000>;
> exit-latency-us = <2000>;
> @@ -93,7 +93,7 @@ Example 3:
> };
>
> DOMAIN_PWR_DN: state@1 {
> - compatible = "arm,idle-state";
> + compatible = "domain-idle-state";
> reg = <0x1>;
> entry-latency-us = <5000>;
> exit-latency-us = <8000>;
> @@ -118,4 +118,4 @@ The node above defines a typical PM domain consumer device, which is located
> inside a PM domain with index 0 of a power controller represented by a node
> with the label "power".
>
> -[1]. Documentation/devicetree/bindings/arm/idle-states.txt
> +[1]. Documentation/devicetree/bindings/power/domain-idle-state.txt
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 661737c..f0bc672 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -2048,7 +2048,7 @@ int genpd_dev_pm_attach(struct device *dev)
> EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
>
> static const struct of_device_id idle_state_match[] = {
> - { .compatible = "arm,idle-state", },
> + { .compatible = "domain-idle-state", },
> { }
> };
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] backlight: arcxcnn: add support for ArticSand devices
From: Lee Jones @ 2016-11-21 11:57 UTC (permalink / raw)
To: Olimpiu Dejeu; +Cc: robh, linux-kernel, linux-fbdev, devicetree, jingoohan1
In-Reply-To: <1479482246-19024-1-git-send-email-olimpiu@arcticsand.com>
On Fri, 18 Nov 2016, Olimpiu Dejeu wrote:
> Re-submission of arcxcnn backlight driver addressing the naming convention
> concerns raised by Rob H.
>
> Signed-off-by: Olimpiu Dejeu <olimpiu@arcticsand.com>
>
> ---
> drivers/video/backlight/Kconfig | 7 +
> drivers/video/backlight/Makefile | 1 +
> drivers/video/backlight/arcxcnn_bl.c | 541 +++++++++++++++++++++++++++++++++++
> include/linux/i2c/arcxcnn.h | 67 +++++
> 4 files changed, 616 insertions(+)
> create mode 100644 drivers/video/backlight/arcxcnn_bl.c
> create mode 100644 include/linux/i2c/arcxcnn.h
Same goes for this patch.
Also, make sure you submit you patches so that they are connected in
people's inboxes.
Use `git send-email` where --thread should be the default.
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index 5ffa4b4..4e1d2ad 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -460,6 +460,13 @@ config BACKLIGHT_BD6107
> help
> If you have a Rohm BD6107 say Y to enable the backlight driver.
>
> +config BACKLIGHT_ARCXCNN
> + tristate "Backlight driver for the Arctic Sands ARCxCnnnn family"
> + depends on I2C
> + help
> + If you have an ARCxCnnnn family backlight say Y to enable
> + the backlight driver.
> +
> endif # BACKLIGHT_CLASS_DEVICE
>
> endif # BACKLIGHT_LCD_SUPPORT
> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
> index 16ec534..8905129 100644
> --- a/drivers/video/backlight/Makefile
> +++ b/drivers/video/backlight/Makefile
> @@ -55,3 +55,4 @@ obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
> obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
> obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
> obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
> +obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
> diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c
> new file mode 100644
> index 0000000..1dad680
> --- /dev/null
> +++ b/drivers/video/backlight/arcxcnn_bl.c
> @@ -0,0 +1,541 @@
> +/*
> + * Backlight driver for ArcticSand ARC_X_C_0N_0N Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/backlight.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/pwm.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include "linux/i2c/arcxcnn.h"
> +
> +#define ARCXCNN_CMD (0x00) /* Command Register */
> +#define ARCXCNN_CMD_STDBY (0x80) /* I2C Standby */
> +#define ARCXCNN_CMD_RESET (0x40) /* Reset */
> +#define ARCXCNN_CMD_BOOST (0x10) /* Boost */
> +#define ARCXCNN_CMD_OVP_MASK (0x0C) /* --- Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_XXV (0x0C) /* <rsvrd> Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_20V (0x08) /* 20v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_24V (0x04) /* 24v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_31V (0x00) /* 31.4v Over Voltage Threshold */
> +#define ARCXCNN_CMD_EXT_COMP (0x01) /* part (0) or full (1) external comp */
> +
> +#define ARCXCNN_CONFIG (0x01) /* Configuration */
> +#define ARCXCNN_STATUS1 (0x02) /* Status 1 */
> +#define ARCXCNN_STATUS2 (0x03) /* Status 2 */
> +#define ARCXCNN_FADECTRL (0x04) /* Fading Control */
> +#define ARCXCNN_ILED_CONFIG (0x05) /* ILED Configuration */
> +
> +#define ARCXCNN_LEDEN (0x06) /* LED Enable Register */
> +#define ARCXCNN_LEDEN_ISETEXT (0x80) /* Full-scale current set externally */
> +#define ARCXCNN_LEDEN_MASK (0x3F) /* LED string enables */
> +#define ARCXCNN_LEDEN_LED1 (0x01)
> +#define ARCXCNN_LEDEN_LED2 (0x02)
> +#define ARCXCNN_LEDEN_LED3 (0x04)
> +#define ARCXCNN_LEDEN_LED4 (0x08)
> +#define ARCXCNN_LEDEN_LED5 (0x10)
> +#define ARCXCNN_LEDEN_LED6 (0x20)
> +
> +#define ARCXCNN_WLED_ISET_LSB (0x07) /* LED ISET LSB (in upper nibble) */
> +#define ARCXCNN_WLED_ISET_MSB (0x08) /* LED ISET MSB (8 bits) */
> +
> +#define ARCXCNN_DIMFREQ (0x09)
> +#define ARCXCNN_COMP_CONFIG (0x0A)
> +#define ARCXCNN_FILT_CONFIG (0x0B)
> +#define ARCXCNN_IMAXTUNE (0x0C)
> +
> +#define DEFAULT_BL_NAME "arctic_bl"
> +#define MAX_BRIGHTNESS 4095
> +
> +static int s_no_reset_on_remove;
> +module_param_named(noreset, s_no_reset_on_remove, int, 0644);
> +MODULE_PARM_DESC(noreset, "No reset on module removal");
> +
> +static int s_ibright = 60;
> +module_param_named(ibright, s_ibright, int, 0644);
> +MODULE_PARM_DESC(ibright, "Initial brightness (when no plat data)");
> +
> +static int s_iledstr = 0x3F;
> +module_param_named(iledstr, s_iledstr, int, 0644);
> +MODULE_PARM_DESC(iledstr, "Initial LED String (when no plat data)");
> +
> +static int s_retries = 2; /* 1 == only one try */
> +module_param_named(retries, s_retries, int, 0644);
> +MODULE_PARM_DESC(retries, "I2C retries attempted");
> +
> +enum arcxcnn_brightness_ctrl_mode {
> + PWM_BASED = 1,
> + REGISTER_BASED,
> +};
> +
> +struct arcxcnn;
> +
> +struct arcxcnn {
> + char chipname[64];
> + enum arcxcnn_chip_id chip_id;
> + enum arcxcnn_brightness_ctrl_mode mode;
> + struct i2c_client *client;
> + struct backlight_device *bl;
> + struct device *dev;
> + struct arcxcnn_platform_data *pdata;
> + struct pwm_device *pwm;
> + struct regulator *supply; /* regulator for VDD input */
> +};
> +
> +static int arcxcnn_write_byte(struct arcxcnn *lp, u8 reg, u8 data)
> +{
> + s32 ret = -1;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + ret = i2c_smbus_write_byte_data(lp->client, reg, data);
> + if (ret >= 0)
> + return 0;
> + }
> + return ret;
> +}
> +
> +static u8 arcxcnn_read_byte(struct arcxcnn *lp, u8 reg)
> +{
> + int val;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + val = i2c_smbus_read_byte_data(lp->client, reg);
> + if (val >= 0)
> + return (u8)val;
> + }
> + return 0;
> +}
> +
> +static int arcxcnn_update_bit(struct arcxcnn *lp, u8 reg, u8 mask, u8 data)
> +{
> + int ret, att;
> + u8 tmp;
> +
> + for (att = 0, ret = -1; att < s_retries; att++) {
> + ret = i2c_smbus_read_byte_data(lp->client, reg);
> + if (ret >= 0)
> + break;
> + }
> + if (ret < 0) {
> + dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
> + return ret;
> + }
> +
> + tmp = (u8)ret;
> + tmp &= ~mask;
> + tmp |= data & mask;
> +
> + return arcxcnn_write_byte(lp, reg, tmp);
> +}
> +
> +static int arcxcnn_set_brightness(struct arcxcnn *lp, u32 brightness)
> +{
> + int ret;
> + u8 val;
> +
> + val = (brightness & 0xF) << 4;
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_LSB, val);
> + if (ret < 0)
> + return ret;
> + val = (brightness >> 4);
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_MSB, val);
> + return ret;
> +}
> +
> +static int arcxcnn_bl_update_status(struct backlight_device *bl)
> +{
> + struct arcxcnn *lp = bl_get_data(bl);
> + u32 brightness = bl->props.brightness;
> +
> + if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
> + brightness = 0;
> +
> + /* set brightness */
> + if (lp->mode == PWM_BASED)
> + ; /* via pwm */
> + else if (lp->mode == REGISTER_BASED)
> + arcxcnn_set_brightness(lp, brightness);
> +
> + /* set power-on/off/save modes */
> + if (bl->props.power == 0)
> + /* take out of standby */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD, ARCXCNN_CMD_STDBY, 0);
> + else
> + /* 1-3 == power save, 4 = off
> + * place in low-power standby mode
> + */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD,
> + ARCXCNN_CMD_STDBY, ARCXCNN_CMD_STDBY);
> + return 0;
> +}
> +
> +static const struct backlight_ops arcxcnn_bl_ops = {
> + .options = BL_CORE_SUSPENDRESUME,
> + .update_status = arcxcnn_bl_update_status,
> +};
> +
> +static int arcxcnn_backlight_register(struct arcxcnn *lp)
> +{
> + struct backlight_device *bl;
> + struct backlight_properties props;
> + struct arcxcnn_platform_data *pdata = lp->pdata;
> + const char *name = pdata->name ? : DEFAULT_BL_NAME;
> +
> + memset(&props, 0, sizeof(props));
> + props.type = BACKLIGHT_PLATFORM;
> + props.max_brightness = MAX_BRIGHTNESS;
> +
> + if (pdata->initial_brightness > props.max_brightness)
> + pdata->initial_brightness = props.max_brightness;
> +
> + props.brightness = pdata->initial_brightness;
> +
> + bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp,
> + &arcxcnn_bl_ops, &props);
> + if (IS_ERR(bl))
> + return PTR_ERR(bl);
> +
> + lp->bl = bl;
> +
> + return 0;
> +}
> +
> +static ssize_t arcxcnn_get_chip_id(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
> +}
> +
> +static ssize_t arcxcnn_get_led_str(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%02X\n", lp->pdata->led_str);
> +}
> +
> +static ssize_t arcxcnn_set_led_str(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t len)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + unsigned long ledstr;
> +
> + if (kstrtoul(buf, 0, &ledstr))
> + return 0;
> +
> + if (ledstr != lp->pdata->led_str) {
> + /* don't allow 0 for ledstr, use power to turn all off */
> + if (ledstr == 0)
> + return 0;
> + lp->pdata->led_str = ledstr & 0x3F;
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> + }
> + return len;
> +}
> +
> +static ssize_t arcxcnn_get_bl_ctl_mode(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + char *strmode = NULL;
> +
> + if (lp->mode == PWM_BASED)
> + strmode = "pwm based";
> + else if (lp->mode == REGISTER_BASED)
> + strmode = "register based";
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
> +}
> +
> +static DEVICE_ATTR(chip_id, 0444, arcxcnn_get_chip_id, NULL);
> +static DEVICE_ATTR(led_str, 0664, arcxcnn_get_led_str, arcxcnn_set_led_str);
> +static DEVICE_ATTR(bl_ctl_mode, 0444, arcxcnn_get_bl_ctl_mode, NULL);
> +
> +static struct attribute *arcxcnn_attributes[] = {
> + &dev_attr_chip_id.attr,
> + &dev_attr_led_str.attr,
> + &dev_attr_bl_ctl_mode.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group arcxcnn_attr_group = {
> + .attrs = arcxcnn_attributes,
> +};
> +
> +#ifdef CONFIG_OF
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + struct device *dev = lp->dev;
> + struct device_node *node = dev->of_node;
> + u32 prog_val, num_entry, sources[6];
> + int ret;
> +
> + if (!node) {
> + dev_err(dev, "no platform data.\n");
> + return -EINVAL;
> + }
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + ret = of_property_read_string(node, "label", &lp->pdata->name);
> + if (ret < 0)
> + lp->pdata->name = NULL;
> +
> + ret = of_property_read_u32(node, "default-brightness", &prog_val);
> + if (ret < 0)
> + prog_val = s_ibright;
> + lp->pdata->initial_brightness = prog_val;
> + if (lp->pdata->initial_brightness > MAX_BRIGHTNESS)
> + lp->pdata->initial_brightness = MAX_BRIGHTNESS;
> +
> + ret = of_property_read_u32(node, "arc,led-config-0", &prog_val);
> + if (ret == 0) {
> + lp->pdata->led_config_0 = (u8)prog_val;
> + lp->pdata->led_config_0_set = true;
> + }
> + ret = of_property_read_u32(node, "arc,led-config-1", &prog_val);
> + if (ret == 0) {
> + lp->pdata->led_config_1 = (u8)prog_val;
> + lp->pdata->led_config_1_set = true;
> + }
> + ret = of_property_read_u32(node, "arc,dim-freq", &prog_val);
> + if (ret == 0) {
> + lp->pdata->dim_freq = (u8)prog_val;
> + lp->pdata->dim_freq_set = true;
> + }
> + ret = of_property_read_u32(node, "arc,comp-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->comp_config = (u8)prog_val;
> + lp->pdata->comp_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arc,filter-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->filter_config = (u8)prog_val;
> + lp->pdata->filter_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arc,trim-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->trim_config = (u8)prog_val;
> + lp->pdata->trim_config_set = true;
> + }
> + ret = of_property_count_u32_elems(node, "led-sources");
> + if (ret < 0)
> + lp->pdata->led_str = 0x3F;
> + else {
> + num_entry = ret;
> + if (num_entry > 6)
> + num_entry = 6;
> +
> + ret = of_property_read_u32_array(node, "led-sources", sources,
> + num_entry);
> + if (ret < 0) {
> + dev_err(dev, "led-sources node is invalid.\n");
> + return -EINVAL;
> + }
> +
> + lp->pdata->led_str = 0;
> + while (num_entry > 0)
> + lp->pdata->led_str |= (1 << sources[--num_entry]);
> + }
> + return 0;
> +}
> +#else
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + return -EINVAL;
> +}
> +#endif
> +
> +static int arcxcnn_probe(struct i2c_client *cl, const struct i2c_device_id *id)
> +{
> + struct arcxcnn *lp;
> + int ret;
> + u8 regval;
> + u16 chipid;
> +
> + if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
> + return -EIO;
> +
> + lp = devm_kzalloc(&cl->dev, sizeof(*lp), GFP_KERNEL);
> + if (!lp)
> + return -ENOMEM;
> +
> + lp->client = cl;
> + lp->dev = &cl->dev;
> + lp->chip_id = id->driver_data;
> + lp->pdata = dev_get_platdata(&cl->dev);
> +
> + if (!lp->pdata) {
> + lp->pdata = devm_kzalloc(lp->dev,
> + sizeof(*lp->pdata), GFP_KERNEL);
> + if (!lp->pdata)
> + return -ENOMEM;
> +
> + /* no platform data, parse the device-tree for info. if there
> + * is no device tree entry, we are being told we exist because
> + * user-land said so, so make up the info we need
> + */
> + ret = arcxcnn_parse_dt(lp);
> + if (ret < 0) {
> + /* no device tree, use defaults based on module params
> + */
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + lp->pdata->name = NULL;
> + lp->pdata->initial_brightness = s_ibright;
> + lp->pdata->led_str = s_iledstr;
> + }
> + }
> +
> + if (lp->pdata->dim_freq_set)
> + lp->mode = PWM_BASED;
> + else
> + lp->mode = REGISTER_BASED;
> +
> + i2c_set_clientdata(cl, lp);
> +
> + /* read device ID */
> + regval = arcxcnn_read_byte(lp, 0x1E);
> + chipid = regval;
> + chipid <<= 8;
> + regval = arcxcnn_read_byte(lp, 0x1F);
> + chipid |= regval;
> +
> + /* make sure it belongs to this driver
> + * TODO - handle specific ids
> + */
> + if (chipid != 0x02A5) {
> + #if 1
> + dev_info(&cl->dev, "Chip Id is %04X\n", chipid);
> + #else
> + dev_err(&cl->dev, "%04X is not ARC2C\n", chipid);
> + return -ENODEV;
> + #endif
> + }
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> +
> + /* set initial brightness */
> + arcxcnn_set_brightness(lp, lp->pdata->initial_brightness);
> +
> + /* if fadectrl set in DT, set the value directly, else leave default */
> + if (lp->pdata->led_config_0_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL,
> + lp->pdata->led_config_0);
> +
> + /* if iled config set in DT, set the value, else internal mode */
> + if (lp->pdata->led_config_1_set)
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG,
> + lp->pdata->led_config_1);
> + else
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG, 0x57);
> +
> + /* other misc DT settings */
> + if (lp->pdata->dim_freq_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL, lp->pdata->dim_freq);
> + if (lp->pdata->comp_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_COMP_CONFIG,
> + lp->pdata->comp_config);
> + if (lp->pdata->filter_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FILT_CONFIG,
> + lp->pdata->filter_config);
> + if (lp->pdata->trim_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_IMAXTUNE,
> + lp->pdata->trim_config);
> +
> + /* set initial LED Strings */
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> +
> + snprintf(lp->chipname, sizeof(lp->chipname),
> + "%s-%04X", id->name, chipid);
> +
> + ret = arcxcnn_backlight_register(lp);
> + if (ret) {
> + dev_err(lp->dev,
> + "failed to register backlight. err: %d\n", ret);
> + return ret;
> + }
> +
> + ret = sysfs_create_group(&lp->dev->kobj, &arcxcnn_attr_group);
> + if (ret) {
> + dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
> + return ret;
> + }
> +
> + backlight_update_status(lp->bl);
> + return 0;
> +}
> +
> +static int arcxcnn_remove(struct i2c_client *cl)
> +{
> + struct arcxcnn *lp = i2c_get_clientdata(cl);
> +
> + if (!s_no_reset_on_remove) {
> + /* disable all strings */
> + arcxcnn_write_byte(lp, ARCXCNN_LEDEN, 0x00);
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> + }
> + lp->bl->props.brightness = 0;
> + backlight_update_status(lp->bl);
> + if (lp->supply)
> + regulator_disable(lp->supply);
> + sysfs_remove_group(&lp->dev->kobj, &arcxcnn_attr_group);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id arcxcnn_dt_ids[] = {
> + { .compatible = "arc,arc2c0608" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, arcxcnn_dt_ids);
> +
> +/* Note that the device/chip ID is not fixed in silicon so
> + * auto-probing of these devices on the bus is most likely
> + * not possible, use device tree to set i2c bus address
> + */
> +static const struct i2c_device_id arcxcnn_ids[] = {
> + {"arc2c0608", ARC2C0608},
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, arcxcnn_ids);
> +
> +static struct i2c_driver arcxcnn_driver = {
> + .driver = {
> + .name = "arcxcnn_bl",
> + .of_match_table = of_match_ptr(arcxcnn_dt_ids),
> + },
> + .probe = arcxcnn_probe,
> + .remove = arcxcnn_remove,
> + .id_table = arcxcnn_ids,
> +};
> +
> +module_i2c_driver(arcxcnn_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Brian Dodge <bdodge09@outlook.com>");
> +MODULE_DESCRIPTION("ARCXCNN Backlight driver");
> diff --git a/include/linux/i2c/arcxcnn.h b/include/linux/i2c/arcxcnn.h
> new file mode 100644
> index 0000000..1c681dd
> --- /dev/null
> +++ b/include/linux/i2c/arcxcnn.h
> @@ -0,0 +1,67 @@
> +/*
> + * Backlight driver for ArcticSand ARC2C0608 Backlight Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#ifndef _ARCXCNN_H
> +#define _ARCXCNN_H
> +
> +enum arcxcnn_chip_id {
> + ARC2C0608
> +};
> +
> +enum arcxcnn_brightness_source {
> + ARCXCNN_PWM_ONLY,
> + ARCXCNN_I2C_ONLY = 2,
> +};
> +
> +#define ARCXCNN_MAX_PROGENTRIES 48 /* max a/v pairs for custom */
> +
> +/**
> + * struct arcxcnn_platform_data
> + * @name : Backlight driver name. If it is not defined, default name is set.
> + * @initial_brightness : initial value of backlight brightness
> + * @led_str : initial LED string enables, upper bit is global on/off
> + * @led_config_0 : fading speed (period between intensity steps)
> + * @led_config_1 : misc settings, see datasheet
> + * @dim_freq : pwm dimming frequency if in pwm mode
> + * @comp_config : misc config, see datasheet
> + * @filter_config: RC/PWM filter config, see datasheet
> + * @trim_config : full scale current trim, see datasheet
> + * @led_config_0_set : the value in led_config_0 is valid
> + * @led_config_1_set : the value in led_config_1 is valid
> + * @dim_freq_set : the value in dim_freq is valid
> + * @comp_config_set : the value in comp_config is valid
> + * @filter_config_set : the value in filter_config is valid
> + * @trim_config_set : the value in trim_config is valid
> + *
> + * the _set flags are used to indicate that the value was explicitly set
> + * in the device tree or platform data. settings not set are left as default
> + * power-on default values of the chip except for led_str and led_config_1
> + * which are set by the driver (led_str is specified indirectly in the
> + * device tree via "led-sources")
> + */
> +struct arcxcnn_platform_data {
> + const char *name;
> + u16 initial_brightness;
> + u8 led_str;
> +
> + u8 led_config_0;
> + u8 led_config_1;
> + u8 dim_freq;
> + u8 comp_config;
> + u8 filter_config;
> + u8 trim_config;
> +
> + bool led_config_0_set;
> + bool led_config_1_set;
> + bool dim_freq_set;
> + bool comp_config_set;
> + bool filter_config_set;
> + bool trim_config_set;
> +};
> +
> +#endif
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH 2/2] backlight: arcxcnn: devicetree bindings for ArticSand devices
From: Lee Jones @ 2016-11-21 11:52 UTC (permalink / raw)
To: Olimpiu Dejeu; +Cc: robh, linux-kernel, linux-fbdev, devicetree, jingoohan1
In-Reply-To: <1479482261-19072-1-git-send-email-olimpiu@arcticsand.com>
Your subject should look something like [PATCH vX 0/Y]
Where X is the number of times you've submitted this set.
On Fri, 18 Nov 2016, Olimpiu Dejeu wrote:
> Re-submission of arcxcnn backlight driver addressing the naming convention
> concerns raised by Rob H. Note that all the device tree properties are
> determined by the board design or IC EPROM settings and are not intended
> to be user adjustable.
This is a change log, not a commit log.
Here is where you tell us about the patch.
Read: Documentation/SubmittingPatches
Documentation/SubmitChecklist
... before submitting again.
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Olimpiu Dejeu <olimpiu@arcticsand.com>
>
> ---
In here (below the ---) you should have a change log which looks like
this:
v3 => v4:
- The changes you made
v2 => v3:
- The changes you made
v1 => v2:
- The changes you made
... etc
> .../bindings/leds/backlight/arcxcnn_bl.txt | 31 ++++++++++++++++++++++
> 1 file changed, 31 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt
>
> diff --git a/Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt b/Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt
> new file mode 100644
> index 0000000..a7b6ff2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt
> @@ -0,0 +1,33 @@
> +Binding for ArcticSand arc2c0608 LED driver
> +
> +Required properties:
> +- compatible: should be "arc,arc2c0608"
> +- reg: slave address
> +
> +Optional properties:
> +- default-brightness: brightness value on boot, value from: 0-4095
> +- label: The name of the backlight device
> + See Documentation/devicetree/bindings/leds/common.txt
> +- led-sources: List of enabled channels from 0 to 5.
> + See Documentation/devicetree/bindings/leds/common.txt
> +
> +- arc,led-config-0: setting for register ILED_CONFIG_0
> +- arc,led-config-1: setting for register ILED_CONFIG_1
> +- arc,dim-freq: PWM mode frequence setting (bits [3:0] used)
> +- arc,comp-config: setting for register CONFIG_COMP
> +- arc,filter-config: setting for register FILTER_CONFIG
> +- arc,trim-config: setting for register IMAXTUNE
> +
> +Note: Optional properties not specified will default to values in IC EPROM
> +
> +Example:
> +
> +arc2c0608@30 {
> + compatible = "arc,arc2c0608";
> + reg = <0x30>;
> + default-brightness = <500>;
> + label = "lcd-backlight";
> + linux,default-trigger = "backlight";
> + led-sources = <0 1 2 5>;
> +};
> +
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH] mfd: cpcap: Add minimal support
From: Lee Jones @ 2016-11-21 11:45 UTC (permalink / raw)
To: Tony Lindgren
Cc: Samuel Ortiz, linux-kernel, linux-omap, devicetree, Marcel Partap,
Mark Rutland, Michael Scott, Rob Herring
In-Reply-To: <20161119012748.17224-1-tony@atomide.com>
On Fri, 18 Nov 2016, Tony Lindgren wrote:
> Many Motorola phones like droid 4 are using a custom PMIC called CPCAP
> or 6556002. We can support it's core features quite easily with regmap_spi
> and regmap_irq.
>
> The children of cpcap, such as regulators, ADC and USB, can be just regular
> device drivers and defined in the dts file. They get probed as we call
> of_platform_populate() at the end of our probe, and then the children
> can just call dev_get_regmap(dev.parent, NULL) to get the regmap.
>
> Cc: devicetree@vger.kernel.org
> Cc: Marcel Partap <mpartap@gmx.net>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Michael Scott <michael.scott@linaro.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
> Documentation/devicetree/bindings/mfd/cpcap.txt | 36 ++++
> drivers/mfd/Kconfig | 8 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/cpcap.c | 255 ++++++++++++++++++++++++
> include/linux/mfd/cpcap.h | 238 ++++++++++++++++++++++
> 5 files changed, 538 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mfd/cpcap.txt
> create mode 100644 drivers/mfd/cpcap.c
> create mode 100644 include/linux/mfd/cpcap.h
>
> diff --git a/Documentation/devicetree/bindings/mfd/cpcap.txt b/Documentation/devicetree/bindings/mfd/cpcap.txt
> new file mode 100644
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/cpcap.txt
> @@ -0,0 +1,36 @@
> +CPCAP PMIC device tree binding
> +
> +Required properties:
> +- compatible : Motorola device "motorola,cpcap", others "st,6556002"
> +- reg : Chip select and size
> +- interrupt-parent : The parent interrupt controller
> +- interrupts : The interrupt line the device is connected to
> +- interrupt-controller : Marks the device node as an interrupt controller
> +- #interrupt-cells : The number of cells to describe an IRQ, should be 2
> +- #address-cells : Child device offset number of cells, typically 1
> +- #size-cells : Child device size number of cells, typically 1
> +- ranges : Child device register range
> +- spi-max-frequency : Typically set to 3000000
> +- spi-cs_high : SPI chip select direction
> +
> +Example:
> +
> +&mcspi1 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> + cpcap: pmic@0 {
> + compatible = "motorola,cpcap", "st,6556002";
> + reg = <0 0>; /* cs0, size 0 */
Is this really correct?
How can ranges have a size of 0x8000 and this 0?
> + interrupt-parent = <&gpio1>;
> + interrupts = <7 IRQ_TYPE_EDGE_RISING>;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0 0x8000>;
> + spi-max-frequency = <3000000>;
> + spi-cs-high;
> + };
> +};
> +
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -713,6 +713,14 @@ config EZX_PCAP
> This enables the PCAP ASIC present on EZX Phones. This is
> needed for MMC, TouchScreen, Sound, USB, etc..
>
> +config MFD_CPCAP
> + tristate "Support for CPCAP"
> + depends on SPI && OF
COMPILE_TEST?
> + help
> + Say yes here if you want to include driver for CPCAP.
> + It is used on many Motorola phones and tablets as a PMIC.
> + At least Motorola Droid 4 is known to use CPCAP.
> +
> config MFD_VIPERBOARD
> tristate "Nano River Technologies Viperboard"
> select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -97,6 +97,7 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
> obj-$(CONFIG_MFD_CORE) += mfd-core.o
>
> obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o
> +obj-$(CONFIG_MFD_CPCAP) += cpcap.o
Who is the manufacturer?
> obj-$(CONFIG_MCP) += mcp-core.o
> obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
> diff --git a/drivers/mfd/cpcap.c b/drivers/mfd/cpcap.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/mfd/cpcap.c
> @@ -0,0 +1,255 @@
> +/*
Description?
Author?
Copyright?
> + * 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/device.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/sysfs.h>
> +
> +#include <linux/mfd/cpcap.h>
> +#include <linux/spi/spi.h>
> +
> +#define CPCAP_NR_IRQ_BANKS 6
> +#define CPCAP_NR_IRQ_DOMAINS 3
> +
> +struct cpcap_device {
s/device/ddata/
It's not really the device. Device is 2 lines down.
> + struct spi_device *spi;
> + struct device *dev;
> + u16 vendor;
> + u16 revision;
Why is this in here?
> + const struct cpcap_platform_data *conf;
What's this? Where is it defined?
> + struct regmap_irq *irqs;
Why does this need to be in here?
> + struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_DOMAINS];
And this? Where is it used again?
> + const struct regmap_config *regmap_conf;
> + struct regmap *regmap;
> +};
> +
> +static int cpcap_check_revision(struct cpcap_device *cpcap)
> +{
> + unsigned int val;
> + int error;
> +
> + error = regmap_read(cpcap->regmap, CPCAP_REG_VERSC1, &val);
> + if (error)
> + return error;
> +
> + cpcap->vendor = (val >> 6) & 0x0007;
> + cpcap->revision = ((val >> 3) & 0x0007) | ((val << 3) & 0x0038);
Lots of magic numbers here. I suggest you define them.
> + dev_info(cpcap->dev, "CPCAP vendor: %s rev: %i.%i (%x)\n",
> + cpcap->vendor ? "TI" : "ST", (cpcap->revision >> 4) + 1,
> + cpcap->revision & 0xf, cpcap->revision);
> +
> + if (cpcap->revision < CPCAP_REVISION_2_1) {
> + dev_info(cpcap->dev,
> + "Please add old CPCAP revision support as needed\n");
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * First domain is the two private macro interrupt banks, the third
> + * domain is for banks 1 - 4 and is available for drivers to use.
> + */
> +static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_DOMAINS] = {
> + {
> + .name = "cpcap-m2",
> + .num_regs = 1,
> + .status_base = CPCAP_REG_MI1,
> + .ack_base = CPCAP_REG_MI1,
> + .mask_base = CPCAP_REG_MIM1,
> + .use_ack = true,
> + },
> + {
> + .name = "cpcap-m2",
> + .num_regs = 1,
> + .status_base = CPCAP_REG_MI2,
> + .ack_base = CPCAP_REG_MI2,
> + .mask_base = CPCAP_REG_MIM2,
> + .use_ack = true,
> + },
> + {
> + .name = "cpcap1-4",
> + .num_regs = 4,
> + .status_base = CPCAP_REG_INT1,
> + .ack_base = CPCAP_REG_INT1,
> + .mask_base = CPCAP_REG_INTM1,
> + .type_base = CPCAP_REG_INTS1,
> + .use_ack = true,
> + },
> +};
> +
> +static int cpcap_init_irq_bank(struct cpcap_device *cpcap, int irq_domain,
> + int irq_start, int nr_irqs)
> +{
> + struct regmap_irq_chip *domain = &cpcap_irq_chip[irq_domain];
I suggest the term 'domain' is not correct here.
In Linux terminology these are 'chips'.
If you wish to create an IRQ domain, that requires a different API.
> + int i, error;
> +
> + for (i = irq_start; i < irq_start + nr_irqs; i++) {
> + struct regmap_irq *cpcap_irq = &cpcap->irqs[i];
> +
> + cpcap_irq->reg_offset =
> + ((i - irq_start) / cpcap->regmap_conf->val_bits) *
> + cpcap->regmap_conf->reg_stride;
> + cpcap_irq->mask = BIT(i % cpcap->regmap_conf->val_bits);
> + }
> + domain->irqs = &cpcap->irqs[irq_start];
> + domain->num_irqs = nr_irqs;
> + domain->irq_drv_data = cpcap;
> +
> + error = devm_regmap_add_irq_chip(cpcap->dev, cpcap->regmap,
> + cpcap->spi->irq,
> + IRQF_TRIGGER_RISING |
> + IRQF_SHARED, -1,
> + domain, &cpcap->irqdata[irq_domain]);
> + if (error) {
> + dev_err(cpcap->dev, "could not add irq domain %i: %i\n",
> + irq_domain, error);
> + return error;
> + }
> +
> + return 0;
> +}
> +
> +static int cpcap_init_irq(struct cpcap_device *cpcap)
> +{
> + int error;
> +
> + cpcap->irqs = devm_kzalloc(cpcap->dev,
> + sizeof(*cpcap->irqs) *
> + CPCAP_NR_IRQ_BANKS *
> + cpcap->regmap_conf->val_bits,
> + GFP_KERNEL);
> + if (!cpcap->irqs)
> + return -ENOMEM;
> +
> + error = cpcap_init_irq_bank(cpcap, 0, 0, 16);
'ret' is more traditional.
> + if (error)
> + return error;
> +
> + error = cpcap_init_irq_bank(cpcap, 1, 16, 16);
> + if (error)
> + return error;
> +
> + error = cpcap_init_irq_bank(cpcap, 2, 32, 64);
> + if (error)
> + return error;
I don't think I've seen this method of adding bulk IRQ chips before.
Isn't there a cleaner or generic way to do this?
> + enable_irq_wake(cpcap->spi->irq);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id cpcap_of_match[] = {
> + {
> + .compatible = "motorola,cpcap",
> + },
Single line please.
> + {
> + .compatible = "st,6556002",
> + },
Single line please.
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, cpcap_of_match);
> +
> +static const struct regmap_config cpcap_regmap_config = {
> + .reg_bits = 16,
> + .reg_stride = 4,
> + .pad_bits = 0,
> + .val_bits = 16,
> + .write_flag_mask = 0x8000,
> + .max_register = CPCAP_REG_ST_TEST2,
> + .cache_type = REGCACHE_NONE,
> + .reg_format_endian = REGMAP_ENDIAN_LITTLE,
> + .val_format_endian = REGMAP_ENDIAN_LITTLE,
> +};
> +
> +static const struct of_device_id cpcap_dt_match_table[] = {
> + { .compatible = "simple-bus", },
> + { },
> +};
> +
> +static int cpcap_probe(struct spi_device *spi)
> +{
> + const struct of_device_id *match;
> + int error = -EINVAL;
ret
> + struct cpcap_device *cpcap;
> +
> + match = of_match_device(of_match_ptr(cpcap_of_match), &spi->dev);
> + if (!match)
> + return -ENODEV;
> +
> + cpcap = devm_kzalloc(&spi->dev, sizeof(*cpcap), GFP_KERNEL);
> + if (!cpcap)
> + return -ENOMEM;
> +
> + cpcap->conf = match->data;
What is contained in the data? Nothing by the looks of it.
> + cpcap->spi = spi;
> + cpcap->dev = &spi->dev;
If you have 'spi' there is no need for 'dev'.
> + spi_set_drvdata(spi, cpcap);
> +
> + spi->bits_per_word = 16;
> + spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
'\n' here.
> + error = spi_setup(spi);
> + if (error < 0)
> + return error;
> +
> + cpcap->regmap_conf = &cpcap_regmap_config;
> + cpcap->regmap = devm_regmap_init_spi(spi, &cpcap_regmap_config);
> + if (IS_ERR(cpcap->regmap)) {
> + error = PTR_ERR(cpcap->regmap);
> + dev_err(cpcap->dev, "Failed to initialize regmap: %d\n",
> + error);
> +
> + return error;
> + }
> +
> + error = cpcap_check_revision(cpcap);
> + if (error)
Are you sure you want to fail silently here?
> + return error;
> +
> + error = cpcap_init_irq(cpcap);
> + if (error)
> + return error;
> +
> + error = of_platform_populate(spi->dev.of_node,
> + cpcap_dt_match_table,
> + NULL, cpcap->dev);
> + if (error)
> + return error;
But don't you just "return of_platform_populate()"?
> + return 0;
> +}
> +
> +static int cpcap_remove(struct spi_device *pdev)
> +{
> + struct cpcap_device *cpcap = spi_get_drvdata(pdev);
> +
> + of_platform_depopulate(cpcap->dev);
> +
> + return 0;
> +}
> +
> +static struct spi_driver cpcap_driver = {
> + .driver = {
> + .name = "cpcap-core",
> + .owner = THIS_MODULE,
No need for this line. It's handled for you.
> + .of_match_table = cpcap_of_match,
> + },
> + .probe = cpcap_probe,
> + .remove = cpcap_remove,
> +};
> +module_spi_driver(cpcap_driver);
> +
> +MODULE_ALIAS("platform:cpcap");
> +MODULE_DESCRIPTION("CPCAP driver");
> +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mfd/cpcap.h b/include/linux/mfd/cpcap.h
> new file mode 100644
> --- /dev/null
> +++ b/include/linux/mfd/cpcap.h
> @@ -0,0 +1,238 @@
> +/*
> + * 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.
> + *
> + * Note that the register defines are based on earlier cpcap.h in
> + * Motorola Linux kernel tree except rewritten for the real register
> + * addresses instead of enumeration so they are usable with regmap.
> + */
Copyright? Author? Description?
> +#define CPCAP_VENDOR_ST 0
> +#define CPCAP_VENDOR_TI 1
> +
> +#define CPCAP_REVISION_1_0 0x08
> +#define CPCAP_REVISION_1_1 0x09
> +#define CPCAP_REVISION_2_0 0x10
> +#define CPCAP_REVISION_2_1 0x11
> +
> +/* CPCAP registers */
> +#define CPCAP_REG_INT1 0x0000 /* Interrupt 1 */
> +#define CPCAP_REG_INT2 0x0004 /* Interrupt 2 */
> +#define CPCAP_REG_INT3 0x0008 /* Interrupt 3 */
> +#define CPCAP_REG_INT4 0x000c /* Interrupt 4 */
> +#define CPCAP_REG_INTM1 0x0010 /* Interrupt Mask 1 */
> +#define CPCAP_REG_INTM2 0x0014 /* Interrupt Mask 2 */
> +#define CPCAP_REG_INTM3 0x0018 /* Interrupt Mask 3 */
> +#define CPCAP_REG_INTM4 0x001c /* Interrupt Mask 4 */
> +#define CPCAP_REG_INTS1 0x0020 /* Interrupt Sense 1 */
> +#define CPCAP_REG_INTS2 0x0024 /* Interrupt Sense 2 */
> +#define CPCAP_REG_INTS3 0x0028 /* Interrupt Sense 3 */
> +#define CPCAP_REG_INTS4 0x002c /* Interrupt Sense 4 */
> +#define CPCAP_REG_ASSIGN1 0x0030 /* Resource Assignment 1 */
> +#define CPCAP_REG_ASSIGN2 0x0034 /* Resource Assignment 2 */
> +#define CPCAP_REG_ASSIGN3 0x0038 /* Resource Assignment 3 */
> +#define CPCAP_REG_ASSIGN4 0x003c /* Resource Assignment 4 */
> +#define CPCAP_REG_ASSIGN5 0x0040 /* Resource Assignment 5 */
> +#define CPCAP_REG_ASSIGN6 0x0044 /* Resource Assignment 6 */
> +#define CPCAP_REG_VERSC1 0x0048 /* Version Control 1 */
> +#define CPCAP_REG_VERSC2 0x004c /* Version Control 2 */
> +
> +#define CPCAP_REG_MI1 0x0200 /* Macro Interrupt 1 */
> +#define CPCAP_REG_MIM1 0x0204 /* Macro Interrupt Mask 1 */
> +#define CPCAP_REG_MI2 0x0208 /* Macro Interrupt 2 */
> +#define CPCAP_REG_MIM2 0x020c /* Macro Interrupt Mask 2 */
> +#define CPCAP_REG_UCC1 0x0210 /* UC Control 1 */
> +#define CPCAP_REG_UCC2 0x0214 /* UC Control 2 */
> +
> +#define CPCAP_REG_PC1 0x021c /* Power Cut 1 */
> +#define CPCAP_REG_PC2 0x0220 /* Power Cut 2 */
> +#define CPCAP_REG_BPEOL 0x0224 /* BP and EOL */
> +#define CPCAP_REG_PGC 0x0228 /* Power Gate and Control */
> +#define CPCAP_REG_MT1 0x022c /* Memory Transfer 1 */
> +#define CPCAP_REG_MT2 0x0230 /* Memory Transfer 2 */
> +#define CPCAP_REG_MT3 0x0234 /* Memory Transfer 3 */
> +#define CPCAP_REG_PF 0x0238 /* Print Format */
> +
> +#define CPCAP_REG_SCC 0x0400 /* System Clock Control */
> +#define CPCAP_REG_SW1 0x0404 /* Stop Watch 1 */
> +#define CPCAP_REG_SW2 0x0408 /* Stop Watch 2 */
> +#define CPCAP_REG_UCTM 0x040c /* UC Turbo Mode */
> +#define CPCAP_REG_TOD1 0x0410 /* Time of Day 1 */
> +#define CPCAP_REG_TOD2 0x0414 /* Time of Day 2 */
> +#define CPCAP_REG_TODA1 0x0418 /* Time of Day Alarm 1 */
> +#define CPCAP_REG_TODA2 0x041c /* Time of Day Alarm 2 */
> +#define CPCAP_REG_DAY 0x0420 /* Day */
> +#define CPCAP_REG_DAYA 0x0424 /* Day Alarm */
> +#define CPCAP_REG_VAL1 0x0428 /* Validity 1 */
> +#define CPCAP_REG_VAL2 0x042c /* Validity 2 */
> +
> +#define CPCAP_REG_SDVSPLL 0x0600 /* Switcher DVS and PLL */
> +#define CPCAP_REG_SI2CC1 0x0604 /* Switcher I2C Control 1 */
> +#define CPCAP_REG_Si2CC2 0x0608 /* Switcher I2C Control 2 */
> +#define CPCAP_REG_S1C1 0x060c /* Switcher 1 Control 1 */
> +#define CPCAP_REG_S1C2 0x0610 /* Switcher 1 Control 2 */
> +#define CPCAP_REG_S2C1 0x0614 /* Switcher 2 Control 1 */
> +#define CPCAP_REG_S2C2 0x0618 /* Switcher 2 Control 2 */
> +#define CPCAP_REG_S3C 0x061c /* Switcher 3 Control */
> +#define CPCAP_REG_S4C1 0x0620 /* Switcher 4 Control 1 */
> +#define CPCAP_REG_S4C2 0x0624 /* Switcher 4 Control 2 */
> +#define CPCAP_REG_S5C 0x0628 /* Switcher 5 Control */
> +#define CPCAP_REG_S6C 0x062c /* Switcher 6 Control */
> +#define CPCAP_REG_VCAMC 0x0630 /* VCAM Control */
> +#define CPCAP_REG_VCSIC 0x0634 /* VCSI Control */
> +#define CPCAP_REG_VDACC 0x0638 /* VDAC Control */
> +#define CPCAP_REG_VDIGC 0x063c /* VDIG Control */
> +#define CPCAP_REG_VFUSEC 0x0640 /* VFUSE Control */
> +#define CPCAP_REG_VHVIOC 0x0644 /* VHVIO Control */
> +#define CPCAP_REG_VSDIOC 0x0648 /* VSDIO Control */
> +#define CPCAP_REG_VPLLC 0x064c /* VPLL Control */
> +#define CPCAP_REG_VRF1C 0x0650 /* VRF1 Control */
> +#define CPCAP_REG_VRF2C 0x0654 /* VRF2 Control */
> +#define CPCAP_REG_VRFREFC 0x0658 /* VRFREF Control */
> +#define CPCAP_REG_VWLAN1C 0x065c /* VWLAN1 Control */
> +#define CPCAP_REG_VWLAN2C 0x0660 /* VWLAN2 Control */
> +#define CPCAP_REG_VSIMC 0x0664 /* VSIM Control */
> +#define CPCAP_REG_VVIBC 0x0668 /* VVIB Control */
> +#define CPCAP_REG_VUSBC 0x066c /* VUSB Control */
> +#define CPCAP_REG_VUSBINT1C 0x0670 /* VUSBINT1 Control */
> +#define CPCAP_REG_VUSBINT2C 0x0674 /* VUSBINT2 Control */
> +#define CPCAP_REG_URT 0x0678 /* Useroff Regulator Trigger */
> +#define CPCAP_REG_URM1 0x067c /* Useroff Regulator Mask 1 */
> +#define CPCAP_REG_URM2 0x0680 /* Useroff Regulator Mask 2 */
> +
> +#define CPCAP_REG_VAUDIOC 0x0800 /* VAUDIO Control */
> +#define CPCAP_REG_CC 0x0804 /* Codec Control */
> +#define CPCAP_REG_CDI 0x0808 /* Codec Digital Interface */
> +#define CPCAP_REG_SDAC 0x080c /* Stereo DAC */
> +#define CPCAP_REG_SDACDI 0x0810 /* Stereo DAC Digital Interface */
> +#define CPCAP_REG_TXI 0x0814 /* TX Inputs */
> +#define CPCAP_REG_TXMP 0x0818 /* TX MIC PGA's */
> +#define CPCAP_REG_RXOA 0x081c /* RX Output Amplifiers */
> +#define CPCAP_REG_RXVC 0x0820 /* RX Volume Control */
> +#define CPCAP_REG_RXCOA 0x0824 /* RX Codec to Output Amps */
> +#define CPCAP_REG_RXSDOA 0x0828 /* RX Stereo DAC to Output Amps */
> +#define CPCAP_REG_RXEPOA 0x082c /* RX External PGA to Output Amps */
> +#define CPCAP_REG_RXLL 0x0830 /* RX Low Latency */
> +#define CPCAP_REG_A2LA 0x0834 /* A2 Loudspeaker Amplifier */
> +#define CPCAP_REG_MIPIS1 0x0838 /* MIPI Slimbus 1 */
> +#define CPCAP_REG_MIPIS2 0x083c /* MIPI Slimbus 2 */
> +#define CPCAP_REG_MIPIS3 0x0840 /* MIPI Slimbus 3. */
> +#define CPCAP_REG_LVAB 0x0844 /* LMR Volume and A4 Balanced. */
> +
> +#define CPCAP_REG_CCC1 0x0a00 /* Coulomb Counter Control 1 */
> +#define CPCAP_REG_CRM 0x0a04 /* Charger and Reverse Mode */
> +#define CPCAP_REG_CCCC2 0x0a08 /* Coincell and Coulomb Ctr Ctrl 2 */
> +#define CPCAP_REG_CCS1 0x0a0c /* Coulomb Counter Sample 1 */
> +#define CPCAP_REG_CCS2 0x0a10 /* Coulomb Counter Sample 2 */
> +#define CPCAP_REG_CCA1 0x0a14 /* Coulomb Counter Accumulator 1 */
> +#define CPCAP_REG_CCA2 0x0a18 /* Coulomb Counter Accumulator 2 */
> +#define CPCAP_REG_CCM 0x0a1c /* Coulomb Counter Mode */
> +#define CPCAP_REG_CCO 0x0a20 /* Coulomb Counter Offset */
> +#define CPCAP_REG_CCI 0x0a24 /* Coulomb Counter Integrator */
> +
> +#define CPCAP_REG_ADCC1 0x0c00 /* A/D Converter Configuration 1 */
> +#define CPCAP_REG_ADCC2 0x0c04 /* A/D Converter Configuration 2 */
> +#define CPCAP_REG_ADCD0 0x0c08 /* A/D Converter Data 0 */
> +#define CPCAP_REG_ADCD1 0x0c0c /* A/D Converter Data 1 */
> +#define CPCAP_REG_ADCD2 0x0c10 /* A/D Converter Data 2 */
> +#define CPCAP_REG_ADCD3 0x0c14 /* A/D Converter Data 3 */
> +#define CPCAP_REG_ADCD4 0x0c18 /* A/D Converter Data 4 */
> +#define CPCAP_REG_ADCD5 0x0c1c /* A/D Converter Data 5 */
> +#define CPCAP_REG_ADCD6 0x0c20 /* A/D Converter Data 6 */
> +#define CPCAP_REG_ADCD7 0x0c24 /* A/D Converter Data 7 */
> +#define CPCAP_REG_ADCAL1 0x0c28 /* A/D Converter Calibration 1 */
> +#define CPCAP_REG_ADCAL2 0x0c2c /* A/D Converter Calibration 2 */
> +
> +#define CPCAP_REG_USBC1 0x0e00 /* USB Control 1 */
> +#define CPCAP_REG_USBC2 0x0e04 /* USB Control 2 */
> +#define CPCAP_REG_USBC3 0x0e08 /* USB Control 3 */
> +#define CPCAP_REG_UVIDL 0x0e0c /* ULPI Vendor ID Low */
> +#define CPCAP_REG_UVIDH 0x0e10 /* ULPI Vendor ID High */
> +#define CPCAP_REG_UPIDL 0x0e14 /* ULPI Product ID Low */
> +#define CPCAP_REG_UPIDH 0x0e18 /* ULPI Product ID High */
> +#define CPCAP_REG_UFC1 0x0e1c /* ULPI Function Control 1 */
> +#define CPCAP_REG_UFC2 0x0e20 /* ULPI Function Control 2 */
> +#define CPCAP_REG_UFC3 0x0e24 /* ULPI Function Control 3 */
> +#define CPCAP_REG_UIC1 0x0e28 /* ULPI Interface Control 1 */
> +#define CPCAP_REG_UIC2 0x0e2c /* ULPI Interface Control 2 */
> +#define CPCAP_REG_UIC3 0x0e30 /* ULPI Interface Control 3 */
> +#define CPCAP_REG_USBOTG1 0x0e34 /* USB OTG Control 1 */
> +#define CPCAP_REG_USBOTG2 0x0e38 /* USB OTG Control 2 */
> +#define CPCAP_REG_USBOTG3 0x0e3c /* USB OTG Control 3 */
> +#define CPCAP_REG_UIER1 0x0e40 /* USB Interrupt Enable Rising 1 */
> +#define CPCAP_REG_UIER2 0x0e44 /* USB Interrupt Enable Rising 2 */
> +#define CPCAP_REG_UIER3 0x0e48 /* USB Interrupt Enable Rising 3 */
> +#define CPCAP_REG_UIEF1 0x0e4c /* USB Interrupt Enable Falling 1 */
> +#define CPCAP_REG_UIEF2 0x0e50 /* USB Interrupt Enable Falling 1 */
> +#define CPCAP_REG_UIEF3 0x0e54 /* USB Interrupt Enable Falling 1 */
> +#define CPCAP_REG_UIS 0x0e58 /* USB Interrupt Status */
> +#define CPCAP_REG_UIL 0x0e5c /* USB Interrupt Latch */
> +#define CPCAP_REG_USBD 0x0e60 /* USB Debug */
> +#define CPCAP_REG_SCR1 0x0e64 /* Scratch 1 */
> +#define CPCAP_REG_SCR2 0x0e68 /* Scratch 2 */
> +#define CPCAP_REG_SCR3 0x0e6c /* Scratch 3 */
> +
> +#define CPCAP_REG_VMC 0x0eac /* Video Mux Control */
> +#define CPCAP_REG_OWDC 0x0eb0 /* One Wire Device Control */
> +#define CPCAP_REG_GPIO0 0x0eb4 /* GPIO 0 Control */
> +
> +#define CPCAP_REG_GPIO1 0x0ebc /* GPIO 1 Control */
> +
> +#define CPCAP_REG_GPIO2 0x0ec4 /* GPIO 2 Control */
> +
> +#define CPCAP_REG_GPIO3 0x0ecc /* GPIO 3 Control */
> +
> +#define CPCAP_REG_GPIO4 0x0ed4 /* GPIO 4 Control */
> +
> +#define CPCAP_REG_GPIO5 0x0edc /* GPIO 5 Control */
> +
> +#define CPCAP_REG_GPIO6 0x0ee4 /* GPIO 6 Control */
> +
> +#define CPCAP_REG_MDLC 0x1000 /* Main Display Lighting Control */
> +#define CPCAP_REG_KLC 0x1004 /* Keypad Lighting Control */
> +#define CPCAP_REG_ADLC 0x1008 /* Aux Display Lighting Control */
> +#define CPCAP_REG_REDC 0x100c /* Red Triode Control */
> +#define CPCAP_REG_GREENC 0x1010 /* Green Triode Control */
> +#define CPCAP_REG_BLUEC 0x1014 /* Blue Triode Control */
> +#define CPCAP_REG_CFC 0x1018 /* Camera Flash Control */
> +#define CPCAP_REG_ABC 0x101c /* Adaptive Boost Control */
> +#define CPCAP_REG_BLEDC 0x1020 /* Bluetooth LED Control */
> +#define CPCAP_REG_CLEDC 0x1024 /* Camera Privacy LED Control */
> +
> +#define CPCAP_REG_OW1C 0x1200 /* One Wire 1 Command */
> +#define CPCAP_REG_OW1D 0x1204 /* One Wire 1 Data */
> +#define CPCAP_REG_OW1I 0x1208 /* One Wire 1 Interrupt */
> +#define CPCAP_REG_OW1IE 0x120c /* One Wire 1 Interrupt Enable */
> +
> +#define CPCAP_REG_OW1 0x1214 /* One Wire 1 Control */
> +
> +#define CPCAP_REG_OW2C 0x1220 /* One Wire 2 Command */
> +#define CPCAP_REG_OW2D 0x1224 /* One Wire 2 Data */
> +#define CPCAP_REG_OW2I 0x1228 /* One Wire 2 Interrupt */
> +#define CPCAP_REG_OW2IE 0x122c /* One Wire 2 Interrupt Enable */
> +
> +#define CPCAP_REG_OW2 0x1234 /* One Wire 2 Control */
> +
> +#define CPCAP_REG_OW3C 0x1240 /* One Wire 3 Command */
> +#define CPCAP_REG_OW3D 0x1244 /* One Wire 3 Data */
> +#define CPCAP_REG_OW3I 0x1248 /* One Wire 3 Interrupt */
> +#define CPCAP_REG_OW3IE 0x124c /* One Wire 3 Interrupt Enable */
> +
> +#define CPCAP_REG_OW3 0x1254 /* One Wire 3 Control */
> +#define CPCAP_REG_GCAIC 0x1258 /* GCAI Clock Control */
> +#define CPCAP_REG_GCAIM 0x125c /* GCAI GPIO Mode */
> +#define CPCAP_REG_LGDIR 0x1260 /* LMR GCAI GPIO Direction */
> +#define CPCAP_REG_LGPU 0x1264 /* LMR GCAI GPIO Pull-up */
> +#define CPCAP_REG_LGPIN 0x1268 /* LMR GCAI GPIO Pin */
> +#define CPCAP_REG_LGMASK 0x126c /* LMR GCAI GPIO Mask */
> +#define CPCAP_REG_LDEB 0x1270 /* LMR Debounce Settings */
> +#define CPCAP_REG_LGDET 0x1274 /* LMR GCAI Detach Detect */
> +#define CPCAP_REG_LMISC 0x1278 /* LMR Misc Bits */
> +#define CPCAP_REG_LMACE 0x127c /* LMR Mace IC Support */
> +
> +#define CPCAP_REG_TEST 0x7c00 /* Test */
> +
> +#define CPCAP_REG_ST_TEST1 0x7d08 /* ST Test1 */
> +
> +#define CPCAP_REG_ST_TEST2 0x7d18 /* ST Test2 */
It would be nice to line up the entire file. #OCD
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH v9 00/16] mmc: sdhci-msm: Add clk-rates, DDR, HS400 support
From: Ritesh Harjani @ 2016-11-21 11:42 UTC (permalink / raw)
To: Ulf Hansson, Stephen Boyd, Andy Gross
Cc: linux-mmc, Adrian Hunter, Shawn Lin, devicetree@vger.kernel.org,
linux-clk, David Brown, linux-arm-msm@vger.kernel.org,
Georgi Djakov, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
Asutosh Das, David Griego, Sahitya Tummala, Venkat Gopalakrishnan,
Rajendra Nayak, Pramod Gurav, jeremymc
In-Reply-To: <CAPDyKFrRbf0+G5K=-jsaevAGbTqhTAss2zJv3QdiyCrv0BG-zA@mail.gmail.com>
On 11/21/2016 3:36 PM, Ulf Hansson wrote:
> On 21 November 2016 at 07:37, Ritesh Harjani <riteshh@codeaurora.org> wrote:
>> Hi,
>>
>> This is v9 version of the patch series which adds support for MSM8996.
>> Adds HS400 driver support as well.
>> These are tested on internal msm8996 & db410c HW.
>>
>> The patch series is ready. Do we think we can apply these
>> patches for next now?
>
> I guess the DTS changes can be picked up by Andy, so they can go via arm-soc?
Yes.
>
> Then, does the mmc changes depend on the clock changes? If so, I can
> pick them as well, but then I need an ack from Stephen....
Ideal and preferable, would be that clk & mmc changes go in together.
But either ways should be fine.
>
> Kind regards
> Uffe
>
>>
>> There are only minor changes in v9.
>> 1. From <&xo_board 0> -> <&xo_board>.
>> 2. Addressed Adrian minor comments on 009.
>> 3. Other minor changes.
>>
>>
>> Older history:-
>>
>> Changes from v7 -> v8 :-
>> 1. Added patch 005 to add dt bindings for xo_clock.
>> 2. Added patch 009 to factor out sdhci_enable_clock as discussed on v7 series.
>> 2.a. Modified patch 010 by making use of sdhci_enable_clock.
>> 2.b. Addressed Stephen's comment on patch 010 to call clk_set_rate unconditionally.
>> 3. Addressed Stephen comments to remove unncessary one line comments, braces and other
>> minor comments.
>> 4. Added changes from Jeremy in patch 002 for gcc-msm8994 as well for sdcc clk_rcg2_floor_ops.
>> minor comments.
>>
>> v7 was verified on my Nexus 5X (msm8992).
>>
>> Older history :-
>> Below are the changes in v7.
>>
>> Changes from v6 -> v7 :-
>> 1. Removed patch "clk: Add clk_hw_get_clk() helper API to be used by clk providers"
>> in v7 as it was not required.
>> 2. Addressed Stephen review comments on -
>> "clk: qcom: Add rcg ops to return floor value closest to the requested rate"
>> 3. Addressed comments from Stephen to add xo_clock entry in the sdhc clock node.
>> Using the same xo_clock entry from DT to get the clk_rate of xo_clock used in
>> sdhci-msm driver. Patch 04 adds this entry into DT.
>> Patch 05 adds the driver support for xo_clock mentioned above.
>> Hence there is a minor change in Patch05, which can be reviewed and taken
>> into the tree.
>>
>> IMHO, almost all patches are almost done and are ready to be accepted.
>> Will below process work out?
>> Patches 001 & 002 :- (clock changes) - Can go via Stephen's Boyd Tree.
>> Patches 004 & 010 :- (DTS changes) - Can go via Andy Gross.
>> Patches 003, 005-009 & 011-014 :- (sdhci-msm changes) - Adrian's tree.
>>
>> Please let me know in case if anything else is required on above.
>>
>>
>> Changes from v5 -> v6 :-
>> 1. Earlier in v5 series DT node was added to get the clk-rates table
>> needed for sdhci-msm driver. But this is removed in this(v6) patch series
>> and instead the clk changes are done in the clk driver as per Rob H comment.
>>
>> 2. Added clk driver changes(patch 1-3) to provide floor rate values of requested
>> clock for sdhc client.
>> For following boards- apq8084, msm8996, msm8916, msm8974.
>>
>> 3. Other minor patch comments were addressed.
>>
>> Changes from v4 -> v5 :-
>> 1. Added HS400 sdhci-msm controller specific changes:- (Patch 10, 11, 12)
>> 2. Addressed comment from Adrian on Patch 07 @[3].
>> 3. Addressed comment from Arnd on Patch 03, to directly add
>> clk_table into sdhci_msm_host. [4]
>> 4. Addressed comment from Bjorn to not enforce having clk-rates property
>> in DT for older targets based on discussion at [5]
>> 5. Retained Acks from Adrian on patches (01 & 02 & 06) where there were no
>> changes made while addressing above comments.
>>
>> Older history:-
>> This is v4 version of the patch series.
>> Patches 01, 02, 05 & 06 were Acked-by Adrian.
>>
>> Changes from v3 -> v4 :-
>> 1. Addressed comments from Adrian on Patch 03, 07, 08.
>> 2. Addressed comments from Bjorn on Patch 03.
>> 3. Added clk-rate support for sdhc DT nodes to all MSM platforms.
>> in Pacth 04.
>> 4. Rebased on next branch of Ulf.
>>
>> Changes from v2 -> v3 :-
>> 1. Addded Patch 01 based on Bjorn comment[2] -
>> This fixes/unrolls the poor coding style of read/writes of
>> registers from base sdhci-msm driver.
>>
>> 2. Fixed/unrolled poor style of reads/writes of registers in Patch 02,
>> based on Bjorn comment[2]. Also changed name of flag from
>> use_updated_dll_reset -> use_14lpp_dll_reset.
>>
>> Changes from v1->v2 :-
>> 1. Removed patch 06 & 08 from v1 patch series[1]
>> (which were introducing unnecessary quirks).
>> Instead have implemented __sdhci_msm_set_clock version of
>> sdhci_set_clock in sdhci_msm driver itself in patch 07 of
>> this patch series.
>> 2. Enabled extra quirk (SDHCI_QUIRK2_PRESET_VALUE_BROKEN) in
>> patch 05 of this patch series.
>>
>>
>> Description of patches :-
>> This patchset adds clk-rates & other required changes to
>> upstream sdhci-msm driver from codeaurora tree.
>> It has been tested on a db410c Dragonboard and msm8996 based
>> platform.
>>
>> Patch 0001-0003- Adds support in qcom clk driver to return
>> floor value of requested clock rate instead of ceil rate
>> for sdhc clients.
>>
>> Patch 0004- Adds updated dll sequence for newer controllers
>> which has minor_version >= 0x42. This is required for msm8996.
>>
>> MSM controller HW recommendation is to use the base MCI clock
>> and directly control this MCI clock at GCC in order to
>> change the clk-rate.
>> Patches 06-08 bring in required change for this to
>> sdhci-msm.
>>
>> MSM controller would require 2x clock rate from source
>> for DDR bus speed modes. Patch 09 adds this support.
>>
>> Patch 0010- adds DDR support in DT for sdhc1 of msm8916.
>>
>> Patches 0011-0014- Adds HS400 support to sdhci-msm.
>>
>>
>> [1]:- http://www.spinics.net/lists/linux-mmc/msg38467.html
>> [2]:- http://www.spinics.net/lists/linux-mmc/msg38578.html
>> [3]:- https://patchwork.kernel.org/patch/9289345/
>> [4]:- https://www.spinics.net/lists/linux-mmc/msg39107.html
>> [5]:- http://www.spinics.net/lists/linux-mmc/msg38749.html
>> [6]:- https://patchwork.kernel.org/patch/9297381/
>>
>>
>> Rajendra Nayak (2):
>> clk: qcom: Add rcg ops to return floor value closest to the requested
>> rate
>> clk: qcom: Move all sdcc rcgs to use clk_rcg2_floor_ops
>>
>> Ritesh Harjani (12):
>> mmc: sdhci-msm: Change poor style writel/readl of registers
>> ARM: dts: Add xo to sdhc clock node on qcom platforms
>> dt-bindings: sdhci-msm: Add xo value
>> mmc: sdhci-msm: Add get_min_clock() and get_max_clock() callback
>> mmc: sdhci-msm: Enable few quirks
>> mmc: sdhci: Factor out sdhci_enable_clk
>> mmc: sdhci-msm: Implement set_clock callback for sdhci-msm
>> mmc: sdhci-msm: Add clock changes for DDR mode.
>> arm64: dts: qcom: msm8916: Add ddr support to sdhc1
>> mmc: sdhci-msm: Save the calculated tuning phase
>> mmc: sdhci-msm: Add calibration tuning for CDCLP533 circuit
>> sdhci: sdhci-msm: update dll configuration
>>
>> Venkat Gopalakrishnan (2):
>> mmc: sdhci-msm: Update DLL reset sequence
>> mmc: sdhci-msm: Add HS400 platform support
>>
>> .../devicetree/bindings/mmc/sdhci-msm.txt | 1 +
>> arch/arm/boot/dts/qcom-apq8084.dtsi | 16 +-
>> arch/arm/boot/dts/qcom-msm8974.dtsi | 16 +-
>> arch/arm64/boot/dts/qcom/msm8916.dtsi | 11 +-
>> arch/arm64/boot/dts/qcom/msm8996.dtsi | 9 +-
>> drivers/clk/qcom/clk-rcg.h | 1 +
>> drivers/clk/qcom/clk-rcg2.c | 76 ++-
>> drivers/clk/qcom/common.c | 16 +
>> drivers/clk/qcom/common.h | 2 +
>> drivers/clk/qcom/gcc-apq8084.c | 8 +-
>> drivers/clk/qcom/gcc-msm8916.c | 4 +-
>> drivers/clk/qcom/gcc-msm8974.c | 8 +-
>> drivers/clk/qcom/gcc-msm8994.c | 8 +-
>> drivers/clk/qcom/gcc-msm8996.c | 8 +-
>> drivers/mmc/host/sdhci-msm.c | 626 +++++++++++++++++++--
>> drivers/mmc/host/sdhci.c | 28 +-
>> drivers/mmc/host/sdhci.h | 1 +
>> 17 files changed, 739 insertions(+), 100 deletions(-)
>>
>> --
>> The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>> a Linux Foundation Collaborative Project.
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v3] ARM: at91/dt: add dts file for sama5d36ek CMP board
From: Nicolas Ferre @ 2016-11-21 11:23 UTC (permalink / raw)
To: Wenyou Yang, Alexandre Belloni, Russell King, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wenyou Yang,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1479705283-3052-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Le 21/11/2016 à 06:14, Wenyou Yang a écrit :
> The sama5d36ek CMP board is the variant of sama5d3xek board.
> It is equipped with the low-power DDR2 SDRAM, PMIC ACT8865 and
> some power rail. Its main purpose is used to measure the power
> consumption.
> The difference of the sama5d36ek CMP dts from sama5d36ek dts is
> listed as below.
> 1. The USB host nodes are removed, that is, the USB host is disabled.
> 2. The gpio_keys node is added to wake up from the sleep.
> 3. The LCD isn't supported due to the pins for LCD are conflicted
> with gpio_keys.
> 4. The adc0 node support the pinctrl sleep state to fix the over
> consumption on VDDANA.
>
> As said in errata, "When the USB host ports are used in high speed
> mode (EHCI), it is not possible to suspend the ports if no device is
> attached on each port. This leads to increased power consumption even
> if the system is in a low power mode." That is why the the USB host
> is disabled.
>
> Signed-off-by: Wenyou Yang <wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Acked-by: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Thanks Wenyou.
Regards,
> ---
>
> Changes in v3:
> - Use a dual license scheme for DT files.
> - Use the proper model name and the compatible string to reflect
> the nature of this new "CMP" board.
> - Change name of wakeup property to "wakeup-source".
> - Remove unnecessary comments.
> - Remove bootargs.
>
> Changes in v2:
> - Add the pinctrl sleep state for adc0 node to fix the over
> consumption on VDDANA.
> - Improve the commit log.
>
> arch/arm/boot/dts/sama5d36ek_cmp.dts | 87 ++++++++++
> arch/arm/boot/dts/sama5d3xcm_cmp.dtsi | 201 +++++++++++++++++++++++
> arch/arm/boot/dts/sama5d3xmb_cmp.dtsi | 301 ++++++++++++++++++++++++++++++++++
> 3 files changed, 589 insertions(+)
> create mode 100644 arch/arm/boot/dts/sama5d36ek_cmp.dts
> create mode 100644 arch/arm/boot/dts/sama5d3xcm_cmp.dtsi
> create mode 100644 arch/arm/boot/dts/sama5d3xmb_cmp.dtsi
>
> diff --git a/arch/arm/boot/dts/sama5d36ek_cmp.dts b/arch/arm/boot/dts/sama5d36ek_cmp.dts
> new file mode 100644
> index 0000000..b632143
> --- /dev/null
> +++ b/arch/arm/boot/dts/sama5d36ek_cmp.dts
> @@ -0,0 +1,87 @@
> +/*
> + * sama5d36ek_cmp.dts - Device Tree file for SAMA5D36-EK CMP board
> + *
> + * Copyright (C) 2016 Atmel,
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This file is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License, or (at your option) any later version.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +/dts-v1/;
> +#include "sama5d36.dtsi"
> +#include "sama5d3xmb_cmp.dtsi"
> +
> +/ {
> + model = "Atmel SAMA5D36EK-CMP";
> + compatible = "atmel,sama5d36ek-cmp", "atmel,sama5d3xmb-cmp", "atmel,sama5d3xcm-cmp", "atmel,sama5d36", "atmel,sama5d3", "atmel,sama5";
> +
> + ahb {
> + apb {
> + spi0: spi@f0004000 {
> + status = "okay";
> + };
> +
> + ssc0: ssc@f0008000 {
> + status = "okay";
> + };
> +
> + can0: can@f000c000 {
> + status = "okay";
> + };
> +
> + i2c0: i2c@f0014000 {
> + status = "okay";
> + };
> +
> + i2c1: i2c@f0018000 {
> + status = "okay";
> + };
> +
> + macb0: ethernet@f0028000 {
> + status = "okay";
> + };
> +
> + macb1: ethernet@f802c000 {
> + status = "okay";
> + };
> + };
> + };
> +
> + sound {
> + status = "okay";
> + };
> +};
> diff --git a/arch/arm/boot/dts/sama5d3xcm_cmp.dtsi b/arch/arm/boot/dts/sama5d3xcm_cmp.dtsi
> new file mode 100644
> index 0000000..dc7572b
> --- /dev/null
> +++ b/arch/arm/boot/dts/sama5d3xcm_cmp.dtsi
> @@ -0,0 +1,201 @@
> +/*
> + * sama5d3xcm_cmp.dtsi - Device Tree Include file for SAMA5D36 CMP CPU Module
> + *
> + * Copyright (C) 2016 Atmel,
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This file is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License, or (at your option) any later version.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/ {
> + compatible = "atmel,sama5d3xcm-cmp", "atmel,sama5d3", "atmel,sama5";
> +
> + chosen {
> + stdout-path = "serial0:115200n8";
> + };
> +
> + memory {
> + reg = <0x20000000 0x20000000>;
> + };
> +
> + clocks {
> + slow_xtal {
> + clock-frequency = <32768>;
> + };
> +
> + main_xtal {
> + clock-frequency = <12000000>;
> + };
> + };
> +
> + ahb {
> + apb {
> + spi0: spi@f0004000 {
> + cs-gpios = <&pioD 13 0>, <0>, <0>, <0>;
> + };
> +
> + macb0: ethernet@f0028000 {
> + phy-mode = "rgmii";
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ethernet-phy@1 {
> + reg = <0x1>;
> + interrupt-parent = <&pioB>;
> + interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
> + txen-skew-ps = <800>;
> + txc-skew-ps = <3000>;
> + rxdv-skew-ps = <400>;
> + rxc-skew-ps = <3000>;
> + rxd0-skew-ps = <400>;
> + rxd1-skew-ps = <400>;
> + rxd2-skew-ps = <400>;
> + rxd3-skew-ps = <400>;
> + };
> +
> + ethernet-phy@7 {
> + reg = <0x7>;
> + interrupt-parent = <&pioB>;
> + interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
> + txen-skew-ps = <800>;
> + txc-skew-ps = <3000>;
> + rxdv-skew-ps = <400>;
> + rxc-skew-ps = <3000>;
> + rxd0-skew-ps = <400>;
> + rxd1-skew-ps = <400>;
> + rxd2-skew-ps = <400>;
> + rxd3-skew-ps = <400>;
> + };
> + };
> +
> + i2c1: i2c@f0018000 {
> + pmic: act8865@5b {
> + compatible = "active-semi,act8865";
> + reg = <0x5b>;
> + status = "disabled";
> +
> + regulators {
> + vcc_1v8_reg: DCDC_REG1 {
> + regulator-name = "VCC_1V8";
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + regulator-always-on;
> + };
> +
> + vcc_1v2_reg: DCDC_REG2 {
> + regulator-name = "VCC_1V2";
> + regulator-min-microvolt = <1100000>;
> + regulator-max-microvolt = <1300000>;
> + regulator-always-on;
> + };
> +
> + vcc_3v3_reg: DCDC_REG3 {
> + regulator-name = "VCC_3V3";
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-always-on;
> + };
> +
> + vddana_reg: LDO_REG1 {
> + regulator-name = "VDDANA";
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-always-on;
> + };
> +
> + vddfuse_reg: LDO_REG2 {
> + regulator-name = "FUSE_2V5";
> + regulator-min-microvolt = <2500000>;
> + regulator-max-microvolt = <2500000>;
> + };
> + };
> + };
> + };
> + };
> +
> + nand0: nand@60000000 {
> + nand-bus-width = <8>;
> + nand-ecc-mode = "hw";
> + atmel,has-pmecc;
> + atmel,pmecc-cap = <4>;
> + atmel,pmecc-sector-size = <512>;
> + nand-on-flash-bbt;
> + status = "okay";
> +
> + at91bootstrap@0 {
> + label = "at91bootstrap";
> + reg = <0x0 0x40000>;
> + };
> +
> + bootloader@40000 {
> + label = "bootloader";
> + reg = <0x40000 0x80000>;
> + };
> +
> + bootloaderenv@c0000 {
> + label = "bootloader env";
> + reg = <0xc0000 0xc0000>;
> + };
> +
> + dtb@180000 {
> + label = "device tree";
> + reg = <0x180000 0x80000>;
> + };
> +
> + kernel@200000 {
> + label = "kernel";
> + reg = <0x200000 0x600000>;
> + };
> +
> + rootfs@800000 {
> + label = "rootfs";
> + reg = <0x800000 0x0f800000>;
> + };
> + };
> + };
> +
> + leds {
> + compatible = "gpio-leds";
> +
> + d2 {
> + label = "d2";
> + gpios = <&pioE 25 GPIO_ACTIVE_LOW>;
> + linux,default-trigger = "heartbeat";
> + };
> + };
> +};
> diff --git a/arch/arm/boot/dts/sama5d3xmb_cmp.dtsi b/arch/arm/boot/dts/sama5d3xmb_cmp.dtsi
> new file mode 100644
> index 0000000..252e0d3
> --- /dev/null
> +++ b/arch/arm/boot/dts/sama5d3xmb_cmp.dtsi
> @@ -0,0 +1,301 @@
> +/*
> + * sama5d3xmb_cmp.dts - Device Tree file for SAMA5D3x CMP mother board
> + *
> + * Copyright (C) 2016 Atmel,
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This file is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License, or (at your option) any later version.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +#include "sama5d3xcm_cmp.dtsi"
> +
> +/ {
> + compatible = "atmel,sama5d3xmb-cmp", "atmel,sama5d3xcm-cmp", "atmel,sama5d3", "atmel,sama5";
> +
> + ahb {
> + apb {
> + mmc0: mmc@f0000000 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_cd>;
> + status = "okay";
> + slot@0 {
> + reg = <0>;
> + bus-width = <4>;
> + cd-gpios = <&pioD 17 GPIO_ACTIVE_HIGH>;
> + };
> + };
> +
> + spi0: spi@f0004000 {
> + dmas = <0>, <0>; /* Do not use DMA for spi0 */
> +
> + m25p80@0 {
> + compatible = "atmel,at25df321a";
> + spi-max-frequency = <50000000>;
> + reg = <0>;
> + };
> + };
> +
> + ssc0: ssc@f0008000 {
> + atmel,clk-from-rk-pin;
> + };
> +
> + /*
> + * i2c0 conflicts with ISI:
> + * disable it to allow the use of ISI
> + * can not enable audio when i2c0 disabled
> + */
> + i2c0: i2c@f0014000 {
> + wm8904: wm8904@1a {
> + compatible = "wlf,wm8904";
> + reg = <0x1a>;
> + clocks = <&pck0>;
> + clock-names = "mclk";
> + };
> + };
> +
> + i2c1: i2c@f0018000 {
> + ov2640: camera@0x30 {
> + compatible = "ovti,ov2640";
> + reg = <0x30>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_pck1_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>;
> + resetb-gpios = <&pioE 24 GPIO_ACTIVE_LOW>;
> + pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>;
> + /* use pck1 for the master clock of ov2640 */
> + clocks = <&pck1>;
> + clock-names = "xvclk";
> + assigned-clocks = <&pck1>;
> + assigned-clock-rates = <25000000>;
> +
> + port {
> + ov2640_0: endpoint {
> + remote-endpoint = <&isi_0>;
> + bus-width = <8>;
> + };
> + };
> + };
> + };
> +
> + usart1: serial@f0020000 {
> + dmas = <0>, <0>; /* Do not use DMA for usart1 */
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>;
> + status = "okay";
> + };
> +
> + isi: isi@f0034000 {
> + port {
> + isi_0: endpoint {
> + remote-endpoint = <&ov2640_0>;
> + bus-width = <8>;
> + vsync-active = <1>;
> + hsync-active = <1>;
> + };
> + };
> + };
> +
> + mmc1: mmc@f8000000 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>;
> + status = "okay";
> + slot@0 {
> + reg = <0>;
> + bus-width = <4>;
> + cd-gpios = <&pioD 18 GPIO_ACTIVE_HIGH>;
> + };
> + };
> +
> + adc0: adc@f8018000 {
> + pinctrl-names = "default", "sleep";
> + pinctrl-0 = <
> + &pinctrl_adc0_adtrg
> + &pinctrl_adc0_ad0
> + &pinctrl_adc0_ad1
> + &pinctrl_adc0_ad2
> + &pinctrl_adc0_ad3
> + &pinctrl_adc0_ad4
> + >;
> + pinctrl-1 = <
> + &pinctrl_adc0_adtrg_sleep
> + &pinctrl_adc0_ad0_sleep
> + &pinctrl_adc0_ad1_sleep
> + &pinctrl_adc0_ad2_sleep
> + &pinctrl_adc0_ad3_sleep
> + &pinctrl_adc0_ad4_sleep
> + >;
> + status = "okay";
> + };
> +
> + macb1: ethernet@f802c000 {
> + phy-mode = "rmii";
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> + phy0: ethernet-phy@1 {
> + /*interrupt-parent = <&pioE>;*/
> + /*interrupts = <30 IRQ_TYPE_EDGE_FALLING>;*/
> + reg = <1>;
> + };
> + };
> +
> + pinctrl@fffff200 {
> + adc0 {
> + pinctrl_adc0_adtrg_sleep: adc0_adtrg_1 {
> + atmel,pins =
> + <AT91_PIOD 19 AT91_PERIPH_GPIO (AT91_PINCTRL_OUTPUT | AT91_PINCTRL_OUTPUT_VAL(0))>;
> + };
> + pinctrl_adc0_ad0_sleep: adc0_ad0_1 {
> + atmel,pins =
> + <AT91_PIOD 20 AT91_PERIPH_GPIO (AT91_PINCTRL_OUTPUT | AT91_PINCTRL_OUTPUT_VAL(0))>;
> + };
> + pinctrl_adc0_ad1_sleep: adc0_ad1_1 {
> + atmel,pins =
> + <AT91_PIOD 21 AT91_PERIPH_GPIO (AT91_PINCTRL_OUTPUT | AT91_PINCTRL_OUTPUT_VAL(0))>;
> + };
> + pinctrl_adc0_ad2_sleep: adc0_ad2_1 {
> + atmel,pins =
> + <AT91_PIOD 22 AT91_PERIPH_GPIO (AT91_PINCTRL_OUTPUT | AT91_PINCTRL_OUTPUT_VAL(0))>;
> + };
> + pinctrl_adc0_ad3_sleep: adc0_ad3_1 {
> + atmel,pins =
> + <AT91_PIOD 23 AT91_PERIPH_GPIO (AT91_PINCTRL_OUTPUT | AT91_PINCTRL_OUTPUT_VAL(0))>;
> + };
> + pinctrl_adc0_ad4_sleep: adc0_ad4_1 {
> + atmel,pins =
> + <AT91_PIOD 24 AT91_PERIPH_GPIO (AT91_PINCTRL_OUTPUT | AT91_PINCTRL_OUTPUT_VAL(0))>;
> + };
> + };
> +
> + board {
> + pinctrl_gpio_keys: gpio_keys {
> + atmel,pins =
> + <AT91_PIOE 27 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP>;
> + };
> +
> + pinctrl_mmc0_cd: mmc0_cd {
> + atmel,pins =
> + <AT91_PIOD 17 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
> + };
> +
> + pinctrl_mmc1_cd: mmc1_cd {
> + atmel,pins =
> + <AT91_PIOD 18 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
> + };
> +
> + pinctrl_pck0_as_audio_mck: pck0_as_audio_mck {
> + atmel,pins =
> + <AT91_PIOD 30 AT91_PERIPH_B AT91_PINCTRL_NONE>;
> + };
> +
> + pinctrl_pck1_as_isi_mck: pck1_as_isi_mck-0 {
> + atmel,pins =
> + <AT91_PIOD 31 AT91_PERIPH_B AT91_PINCTRL_NONE>;
> + };
> +
> + pinctrl_sensor_reset: sensor_reset-0 {
> + atmel,pins =
> + <AT91_PIOE 24 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
> + };
> +
> + pinctrl_sensor_power: sensor_power-0 {
> + atmel,pins =
> + <AT91_PIOE 29 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
> + };
> +
> + pinctrl_usba_vbus: usba_vbus {
> + atmel,pins =
> + <AT91_PIOD 29 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;
> + };
> + };
> + };
> +
> + dbgu: serial@ffffee00 {
> + dmas = <0>, <0>; /* Do not use DMA for dbgu */
> + status = "okay";
> + };
> +
> + watchdog@fffffe40 {
> + status = "okay";
> + };
> + };
> +
> + usb0: gadget@00500000 {
> + atmel,vbus-gpio = <&pioD 29 GPIO_ACTIVE_HIGH>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usba_vbus>;
> + status = "okay";
> + };
> + };
> +
> + sound {
> + compatible = "atmel,asoc-wm8904";
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_pck0_as_audio_mck>;
> +
> + atmel,model = "wm8904 @ SAMA5D3EK";
> + atmel,audio-routing =
> + "Headphone Jack", "HPOUTL",
> + "Headphone Jack", "HPOUTR",
> + "IN2L", "Line In Jack",
> + "IN2R", "Line In Jack",
> + "Mic", "MICBIAS",
> + "IN1L", "Mic";
> +
> + atmel,ssc-controller = <&ssc0>;
> + atmel,audio-codec = <&wm8904>;
> +
> + status = "disabled";
> + };
> +
> + /* Conflict with LCD pins */
> + gpio_keys {
> + compatible = "gpio-keys";
> + status = "okay";
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_gpio_keys>;
> +
> + pb_user1 {
> + label = "pb_user1";
> + gpios = <&pioE 27 GPIO_ACTIVE_HIGH>;
> + linux,code = <0x100>;
> + wakeup-source;
> + };
> + };
> +};
>
--
Nicolas Ferre
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V2 2/2] pinctrl: tegra: Add driver to configure voltage and power of io pads
From: Jon Hunter @ 2016-11-21 11:08 UTC (permalink / raw)
To: Laxman Dewangan, linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
thierry.reding-Re5JQEeQqe8AvxtiuMwx3w
Cc: gnurou-Re5JQEeQqe8AvxtiuMwx3w,
yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <5832C005.3070104-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Hi Laxman,
On 21/11/16 09:36, Laxman Dewangan wrote:
>
> Hi Jon,
> I will update the patch per your comment.
Thanks.
> Here is answer for some of the query.
>
> Thanks,
> Laxman
>
>
> On Tuesday 15 November 2016 08:37 PM, Jon Hunter wrote:
>> On 09/11/16 13:06, Laxman Dewangan wrote:
>>> +/**
>>> + * Macro for 1.8V, keep 200mV as tolerance for deciding that
>>> + * IO pads should be set for 3.3V (high voltage) or 1.8V.
>>> + */
>>> +#define TEGRA_IO_PAD_1800000UV_UPPER_LIMIT 2000000
>> Is there a reference we could add for the source of this information?
>
> I had a discussion with the ASIC on this and as per them
> 1.8 V nominal is (1.62V, 1.98V)
> 3.3 V nominal is (2.97V,3.63V)
>
> I am working with them to update the TRM document but we can assume that
> this information will be there in TRM.
My feeling is that if all use-cases today are using either 1.8V or 3.3V,
then may be we should not worry about this and only support either 1.8V
or 3.3V. I would be more in favour of supporting other voltages if there
is a real need.
>>> + const struct pinctrl_pin_desc *pins_desc;
>>> + int num_pins_desc;
>>> +};
>>> +
>>> +struct tegra_io_pads_regulator_info {
>>> + struct device *dev;
>>> + const struct tegra_io_pads_cfg_info *pads_cfg;
>>> + struct regulator *regulator;
>>> + struct notifier_block regulator_nb;
>>> +};
>> Is this struct necessary? Seems to be a lot of duplicated information
>> from the other structs. Why not add the regulator and regulator_nb to
>> the main struct? OK, not all io_pads have a regulator but you are only
>> saving one pointer.
> Yes, some of IO pads support multi-voltage.
Yes, but I am saying why not put this information in the main struct and
not bother having yet another struct where half of the information is
duplicated.
>>
>> + if ((vdata->old_uV > TEGRA_IO_PAD_1800000UV_UPPER_LIMIT) &&
>> + (vdata->min_uV <= TEGRA_IO_PAD_1800000UV_UPPER_LIMIT))
>> + break;
>> The data-sheet for Tegra210 only lists 1.8V or 3.3V as supported
>> options. Do we need to support a range? Or does the h/w support a range
>> of voltages? I am just wondering why we cannot check explicitly for 1.8V
>> or 3.3V and treat anything else as an error.
>
> Two voltage level, not range.
Ok, then I think it would be much simpler if we just support the
voltages we are using today.
Cheers
Jon
--
nvpublic
^ permalink raw reply
* Re: [PATCH v3 10/10] ARM: dts: da850: add usb device node
From: Axel Haslam @ 2016-11-21 10:53 UTC (permalink / raw)
To: Sekhar Nori
Cc: David Lechner, Kevin Hilman, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
Alexandre Bailon, Alan Stern, Greg KH,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <e8bc1888-4936-7d8e-cf8a-a3f2b5644ef5-l0cyMroinI0@public.gmane.org>
On Mon, Nov 21, 2016 at 11:49 AM, Sekhar Nori <nsekhar-l0cyMroinI0@public.gmane.org> wrote:
> On Monday 21 November 2016 04:16 PM, Sekhar Nori wrote:
>>>> In commit 2957e36e76c836b167e5e0c1edb578d8a9bd7af6 in the linux-davinci
>>>> >> tree, the alias for the musb device is usb0. So, I think we should use usb1
>>>> >> here instead of ohci - or change the usb0 alias to musb.
>>>> >>
>>>> >> https://git.kernel.org/cgit/linux/kernel/git/nsekhar/linux-davinci.git/commit/?h=v4.10/dt&id=2957e36e76c836b167e5e0c1edb578d8a9bd7af6
>>> >
>>> > ok, i will change to usb1, since i will be resubmiting this.
>
>> I have already applied a version of this patch. Please re-base against
>> linux-davinci/master and send a delta patch.
>
> Hmm, no. scratch that. I mixed this up with the musb patch I applied.
> usb1 sounds good. Please also separate out the soc and board specific
> dts additions for your next version.
Ok will do.
>
> Thanks,
> Sekhar
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 10/10] ARM: dts: da850: add usb device node
From: Sekhar Nori @ 2016-11-21 10:49 UTC (permalink / raw)
To: Axel Haslam, David Lechner
Cc: Kevin Hilman, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Alexandre Bailon,
Alan Stern, Greg KH, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <c812d211-fff8-520f-cc1f-6fa69a765498-l0cyMroinI0@public.gmane.org>
On Monday 21 November 2016 04:16 PM, Sekhar Nori wrote:
>>> In commit 2957e36e76c836b167e5e0c1edb578d8a9bd7af6 in the linux-davinci
>>> >> tree, the alias for the musb device is usb0. So, I think we should use usb1
>>> >> here instead of ohci - or change the usb0 alias to musb.
>>> >>
>>> >> https://git.kernel.org/cgit/linux/kernel/git/nsekhar/linux-davinci.git/commit/?h=v4.10/dt&id=2957e36e76c836b167e5e0c1edb578d8a9bd7af6
>> >
>> > ok, i will change to usb1, since i will be resubmiting this.
> I have already applied a version of this patch. Please re-base against
> linux-davinci/master and send a delta patch.
Hmm, no. scratch that. I mixed this up with the musb patch I applied.
usb1 sounds good. Please also separate out the soc and board specific
dts additions for your next version.
Thanks,
Sekhar
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox