From: Harald Geyer <harald-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
To: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Sascha Hauer <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Cc: Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org>,
Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Harald Geyer <harald-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
Subject: [PATCH 1/3] iio: mxs-lradc: Add regulators for current sources
Date: Fri, 22 Apr 2016 13:52:25 +0000 [thread overview]
Message-ID: <1461333147-11873-2-git-send-email-harald@ccbib.org> (raw)
In-Reply-To: <1461333147-11873-1-git-send-email-harald-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
The hardware has two current sources ISRC0 and ISRC1 to allow measuring
resistors without additional circuitry. This commit makes them available
as regulators.
Tested on an imx233-olinuxino board.
Signed-off-by: Harald Geyer <harald-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
---
The current regulator API doesn't fit this type of device very well: Typically
consumers will want to set a defined current, ie. min_uA == max_uA, but they
can't without help from configuration data, because the valid values aren't
reported by the API for current regulators. I have been thinking about
extending the API, but currently AFAIK no such consumers exist and most
users, like myself, will force the regulator to a defined value in
devicetree anyway.
.../bindings/staging/iio/adc/mxs-lradc.txt | 29 ++++
drivers/iio/adc/Kconfig | 1 +
drivers/iio/adc/mxs-lradc.c | 152 +++++++++++++++++++++
3 files changed, 182 insertions(+)
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
index 555fb11..983952c 100644
--- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -19,6 +19,15 @@ Optional properties:
- fsl,settling: delay between plate switch to next sample. Allowed value is
1 ... 2047. It counts at 2 kHz and its default is
10 (= 5 ms)
+- ISRC0: A node describing the regulator of internal current source 0
+- ISRC1: A node describing the regulator of internal current source 1
+
+Required properties for the ISRCx sub-nodes:
+- regulator-max-microamp: See standard regulator binding documentation.
+ Valid values are from 0 to 300 in steps of 20.
+
+Optional properties for the ISRCx sub-nodes:
+Any standard regulator properties that apply to current regulators.
Example for i.MX23 SoC:
@@ -31,6 +40,16 @@ Example for i.MX23 SoC:
fsl,ave-ctrl = <4>;
fsl,ave-delay = <2>;
fsl,settling = <10>;
+
+ isrc_lradc0: ISRC0 {
+ regulator-max-microamp = <300>;
+ };
+
+ isrc_lradc1: ISRC1 {
+ regulator-max-microamp = <120>;
+ regulator-min-microamp = <120>;
+ regulator-always-on;
+ };
};
Example for i.MX28 SoC:
@@ -44,4 +63,14 @@ Example for i.MX28 SoC:
fsl,ave-ctrl = <4>;
fsl,ave-delay = <2>;
fsl,settling = <10>;
+
+ isrc_lradc0: ISRC0 {
+ regulator-max-microamp = <300>;
+ };
+
+ isrc_lradc6: ISRC1 {
+ regulator-max-microamp = <120>;
+ regulator-min-microamp = <120>;
+ regulator-always-on;
+ };
};
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 5937030..1968d1c 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -319,6 +319,7 @@ config MXS_LRADC
tristate "Freescale i.MX23/i.MX28 LRADC"
depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
depends on INPUT
+ depends on REGULATOR
select STMP_DEVICE
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c
index 33051b8..f22f339 100644
--- a/drivers/iio/adc/mxs-lradc.c
+++ b/drivers/iio/adc/mxs-lradc.c
@@ -40,6 +40,10 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
#define DRIVER_NAME "mxs-lradc"
#define LRADC_MAX_DELAY_CHANS 4
@@ -261,6 +265,9 @@ struct mxs_lradc {
unsigned over_sample_delay;
/* time in clocks to wait after the plates where switched */
unsigned settling_delay;
+
+ struct regulator_desc isrc0;
+ struct regulator_desc isrc1;
};
#define LRADC_CTRL0 0x00
@@ -305,6 +312,11 @@ struct mxs_lradc {
#define LRADC_CTRL2 0x20
#define LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET 24
#define LRADC_CTRL2_TEMPSENSE_PWD BIT(15)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE1 BIT(9)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE0 BIT(8)
+#define LRADC_CTRL2_TEMP_ISRC1_OFFSET 4
+#define LRADC_CTRL2_TEMP_ISRC0_OFFSET 0
+#define LRADC_CTRL2_TEMP_ISRC_MASK 0x0f
#define LRADC_STATUS 0x40
#define LRADC_STATUS_TOUCH_DETECT_RAW BIT(0)
@@ -1383,6 +1395,109 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
.validate_scan_mask = &mxs_lradc_validate_scan_mask,
};
+static int mxs_lradc_regulator_is_enabled(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int reg = readl(lradc->base + LRADC_CTRL2);
+
+ if (dev->desc == &lradc->isrc0)
+ return reg & LRADC_CTRL2_TEMP_SENSOR_IENABLE0;
+ else if (dev->desc == &lradc->isrc1)
+ return reg & LRADC_CTRL2_TEMP_SENSOR_IENABLE1;
+
+ /* This should never happen */
+ return -ENODEV;
+}
+
+#define LRADC_REGVALUE2uA(regval, offset) \
+ (20 * ((regval >> offset) & LRADC_CTRL2_TEMP_ISRC_MASK))
+
+static int mxs_lradc_regulator_get_current_limit(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int reg = readl(lradc->base + LRADC_CTRL2);
+
+ if (dev->desc == &lradc->isrc0)
+ return LRADC_REGVALUE2uA(reg, LRADC_CTRL2_TEMP_ISRC0_OFFSET);
+ else if (dev->desc == &lradc->isrc1)
+ return LRADC_REGVALUE2uA(reg, LRADC_CTRL2_TEMP_ISRC1_OFFSET);
+
+ /* This should never happen */
+ return -ENODEV;
+}
+
+static int mxs_lradc_regulator_enable(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+
+ if (dev->desc == &lradc->isrc0)
+ mxs_lradc_reg_set(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
+ LRADC_CTRL2);
+ else if (dev->desc == &lradc->isrc1)
+ mxs_lradc_reg_set(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ return 0;
+}
+
+static int mxs_lradc_regulator_disable(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+
+ if (dev->desc == &lradc->isrc0)
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
+ LRADC_CTRL2);
+ else if (dev->desc == &lradc->isrc1)
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ return 0;
+}
+
+static int mxs_lradc_regulator_set_current_limit(struct regulator_dev *dev,
+ int min_uA, int max_uA)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int offset, value;
+
+ if (dev->desc == &lradc->isrc0)
+ offset = LRADC_CTRL2_TEMP_ISRC0_OFFSET;
+ else if (dev->desc == &lradc->isrc1)
+ offset = LRADC_CTRL2_TEMP_ISRC1_OFFSET;
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ value = min_uA / 20;
+ if (min_uA % 20)
+ value++;
+ if (value * 20 > max_uA)
+ return -EINVAL;
+ if (value & ~LRADC_CTRL2_TEMP_ISRC_MASK)
+ /* This should never happen */
+ return -EPERM;
+
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_ISRC_MASK << offset,
+ LRADC_CTRL2);
+ mxs_lradc_reg_set(lradc, value << offset, LRADC_CTRL2);
+
+ return 0;
+}
+
+static struct regulator_ops mxs_lradc_regulator_current_ops = {
+ .enable = mxs_lradc_regulator_enable,
+ .is_enabled = mxs_lradc_regulator_is_enabled,
+ .disable = mxs_lradc_regulator_disable,
+ .get_current_limit = mxs_lradc_regulator_get_current_limit,
+ .set_current_limit = mxs_lradc_regulator_set_current_limit,
+};
+
/*
* Driver initialization
*/
@@ -1519,6 +1634,10 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(i));
+
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0 |
+ LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
}
static const struct of_device_id mxs_lradc_dt_ids[] = {
@@ -1592,6 +1711,32 @@ static int mxs_lradc_probe_touchscreen(struct mxs_lradc *lradc,
return 0;
}
+static void mxs_lradc_reg_helper(struct device_node *np, const char *name,
+ struct regulator_config *conf,
+ struct regulator_desc *desc)
+{
+ struct regulator_dev *ret;
+
+ conf->of_node = of_get_child_by_name(np, name);
+ if (!conf->of_node)
+ return;
+
+ desc->name = name;
+ desc->owner = THIS_MODULE;
+ desc->type = REGULATOR_CURRENT;
+ desc->ops = &mxs_lradc_regulator_current_ops;
+
+ conf->init_data = of_get_regulator_init_data(conf->dev, conf->of_node,
+ desc);
+ ret = devm_regulator_register(conf->dev, desc, conf);
+ if (IS_ERR(ret))
+ /* Just pretend the regulator isn't there */
+ dev_err(conf->dev, "Failed to register regulator %s: %ld\n",
+ desc->name, PTR_ERR(ret));
+
+ of_node_put(conf->of_node);
+}
+
static int mxs_lradc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@@ -1603,6 +1748,7 @@ static int mxs_lradc_probe(struct platform_device *pdev)
struct mxs_lradc *lradc;
struct iio_dev *iio;
struct resource *iores;
+ struct regulator_config regconf;
int ret = 0, touch_ret;
int i, s;
u64 scale_uv;
@@ -1727,6 +1873,12 @@ static int mxs_lradc_probe(struct platform_device *pdev)
goto err_ts;
}
+ /* Setup regulator devices for current source. */
+ regconf.dev = dev;
+ regconf.driver_data = lradc;
+ mxs_lradc_reg_helper(node, "ISRC0", ®conf, &lradc->isrc0);
+ mxs_lradc_reg_helper(node, "ISRC1", ®conf, &lradc->isrc1);
+
return 0;
err_ts:
--
2.1.4
WARNING: multiple messages have this Message-ID (diff)
From: Harald Geyer <harald@ccbib.org>
To: Jonathan Cameron <jic23@kernel.org>,
devicetree@vger.kernel.org, linux-iio@vger.kernel.org,
Shawn Guo <shawnguo@kernel.org>,
Sascha Hauer <kernel@pengutronix.de>
Cc: Stefan Wahren <stefan.wahren@i2se.com>,
Marek Vasut <marex@denx.de>,
linux-arm-kernel@lists.infradead.org,
Harald Geyer <harald@ccbib.org>
Subject: [PATCH 1/3] iio: mxs-lradc: Add regulators for current sources
Date: Fri, 22 Apr 2016 13:52:25 +0000 [thread overview]
Message-ID: <1461333147-11873-2-git-send-email-harald@ccbib.org> (raw)
In-Reply-To: <1461333147-11873-1-git-send-email-harald@ccbib.org>
The hardware has two current sources ISRC0 and ISRC1 to allow measuring
resistors without additional circuitry. This commit makes them available
as regulators.
Tested on an imx233-olinuxino board.
Signed-off-by: Harald Geyer <harald@ccbib.org>
---
The current regulator API doesn't fit this type of device very well: Typically
consumers will want to set a defined current, ie. min_uA == max_uA, but they
can't without help from configuration data, because the valid values aren't
reported by the API for current regulators. I have been thinking about
extending the API, but currently AFAIK no such consumers exist and most
users, like myself, will force the regulator to a defined value in
devicetree anyway.
.../bindings/staging/iio/adc/mxs-lradc.txt | 29 ++++
drivers/iio/adc/Kconfig | 1 +
drivers/iio/adc/mxs-lradc.c | 152 +++++++++++++++++++++
3 files changed, 182 insertions(+)
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
index 555fb11..983952c 100644
--- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -19,6 +19,15 @@ Optional properties:
- fsl,settling: delay between plate switch to next sample. Allowed value is
1 ... 2047. It counts at 2 kHz and its default is
10 (= 5 ms)
+- ISRC0: A node describing the regulator of internal current source 0
+- ISRC1: A node describing the regulator of internal current source 1
+
+Required properties for the ISRCx sub-nodes:
+- regulator-max-microamp: See standard regulator binding documentation.
+ Valid values are from 0 to 300 in steps of 20.
+
+Optional properties for the ISRCx sub-nodes:
+Any standard regulator properties that apply to current regulators.
Example for i.MX23 SoC:
@@ -31,6 +40,16 @@ Example for i.MX23 SoC:
fsl,ave-ctrl = <4>;
fsl,ave-delay = <2>;
fsl,settling = <10>;
+
+ isrc_lradc0: ISRC0 {
+ regulator-max-microamp = <300>;
+ };
+
+ isrc_lradc1: ISRC1 {
+ regulator-max-microamp = <120>;
+ regulator-min-microamp = <120>;
+ regulator-always-on;
+ };
};
Example for i.MX28 SoC:
@@ -44,4 +63,14 @@ Example for i.MX28 SoC:
fsl,ave-ctrl = <4>;
fsl,ave-delay = <2>;
fsl,settling = <10>;
+
+ isrc_lradc0: ISRC0 {
+ regulator-max-microamp = <300>;
+ };
+
+ isrc_lradc6: ISRC1 {
+ regulator-max-microamp = <120>;
+ regulator-min-microamp = <120>;
+ regulator-always-on;
+ };
};
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 5937030..1968d1c 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -319,6 +319,7 @@ config MXS_LRADC
tristate "Freescale i.MX23/i.MX28 LRADC"
depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
depends on INPUT
+ depends on REGULATOR
select STMP_DEVICE
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c
index 33051b8..f22f339 100644
--- a/drivers/iio/adc/mxs-lradc.c
+++ b/drivers/iio/adc/mxs-lradc.c
@@ -40,6 +40,10 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
#define DRIVER_NAME "mxs-lradc"
#define LRADC_MAX_DELAY_CHANS 4
@@ -261,6 +265,9 @@ struct mxs_lradc {
unsigned over_sample_delay;
/* time in clocks to wait after the plates where switched */
unsigned settling_delay;
+
+ struct regulator_desc isrc0;
+ struct regulator_desc isrc1;
};
#define LRADC_CTRL0 0x00
@@ -305,6 +312,11 @@ struct mxs_lradc {
#define LRADC_CTRL2 0x20
#define LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET 24
#define LRADC_CTRL2_TEMPSENSE_PWD BIT(15)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE1 BIT(9)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE0 BIT(8)
+#define LRADC_CTRL2_TEMP_ISRC1_OFFSET 4
+#define LRADC_CTRL2_TEMP_ISRC0_OFFSET 0
+#define LRADC_CTRL2_TEMP_ISRC_MASK 0x0f
#define LRADC_STATUS 0x40
#define LRADC_STATUS_TOUCH_DETECT_RAW BIT(0)
@@ -1383,6 +1395,109 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
.validate_scan_mask = &mxs_lradc_validate_scan_mask,
};
+static int mxs_lradc_regulator_is_enabled(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int reg = readl(lradc->base + LRADC_CTRL2);
+
+ if (dev->desc == &lradc->isrc0)
+ return reg & LRADC_CTRL2_TEMP_SENSOR_IENABLE0;
+ else if (dev->desc == &lradc->isrc1)
+ return reg & LRADC_CTRL2_TEMP_SENSOR_IENABLE1;
+
+ /* This should never happen */
+ return -ENODEV;
+}
+
+#define LRADC_REGVALUE2uA(regval, offset) \
+ (20 * ((regval >> offset) & LRADC_CTRL2_TEMP_ISRC_MASK))
+
+static int mxs_lradc_regulator_get_current_limit(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int reg = readl(lradc->base + LRADC_CTRL2);
+
+ if (dev->desc == &lradc->isrc0)
+ return LRADC_REGVALUE2uA(reg, LRADC_CTRL2_TEMP_ISRC0_OFFSET);
+ else if (dev->desc == &lradc->isrc1)
+ return LRADC_REGVALUE2uA(reg, LRADC_CTRL2_TEMP_ISRC1_OFFSET);
+
+ /* This should never happen */
+ return -ENODEV;
+}
+
+static int mxs_lradc_regulator_enable(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+
+ if (dev->desc == &lradc->isrc0)
+ mxs_lradc_reg_set(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
+ LRADC_CTRL2);
+ else if (dev->desc == &lradc->isrc1)
+ mxs_lradc_reg_set(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ return 0;
+}
+
+static int mxs_lradc_regulator_disable(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+
+ if (dev->desc == &lradc->isrc0)
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
+ LRADC_CTRL2);
+ else if (dev->desc == &lradc->isrc1)
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ return 0;
+}
+
+static int mxs_lradc_regulator_set_current_limit(struct regulator_dev *dev,
+ int min_uA, int max_uA)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int offset, value;
+
+ if (dev->desc == &lradc->isrc0)
+ offset = LRADC_CTRL2_TEMP_ISRC0_OFFSET;
+ else if (dev->desc == &lradc->isrc1)
+ offset = LRADC_CTRL2_TEMP_ISRC1_OFFSET;
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ value = min_uA / 20;
+ if (min_uA % 20)
+ value++;
+ if (value * 20 > max_uA)
+ return -EINVAL;
+ if (value & ~LRADC_CTRL2_TEMP_ISRC_MASK)
+ /* This should never happen */
+ return -EPERM;
+
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_ISRC_MASK << offset,
+ LRADC_CTRL2);
+ mxs_lradc_reg_set(lradc, value << offset, LRADC_CTRL2);
+
+ return 0;
+}
+
+static struct regulator_ops mxs_lradc_regulator_current_ops = {
+ .enable = mxs_lradc_regulator_enable,
+ .is_enabled = mxs_lradc_regulator_is_enabled,
+ .disable = mxs_lradc_regulator_disable,
+ .get_current_limit = mxs_lradc_regulator_get_current_limit,
+ .set_current_limit = mxs_lradc_regulator_set_current_limit,
+};
+
/*
* Driver initialization
*/
@@ -1519,6 +1634,10 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(i));
+
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0 |
+ LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
}
static const struct of_device_id mxs_lradc_dt_ids[] = {
@@ -1592,6 +1711,32 @@ static int mxs_lradc_probe_touchscreen(struct mxs_lradc *lradc,
return 0;
}
+static void mxs_lradc_reg_helper(struct device_node *np, const char *name,
+ struct regulator_config *conf,
+ struct regulator_desc *desc)
+{
+ struct regulator_dev *ret;
+
+ conf->of_node = of_get_child_by_name(np, name);
+ if (!conf->of_node)
+ return;
+
+ desc->name = name;
+ desc->owner = THIS_MODULE;
+ desc->type = REGULATOR_CURRENT;
+ desc->ops = &mxs_lradc_regulator_current_ops;
+
+ conf->init_data = of_get_regulator_init_data(conf->dev, conf->of_node,
+ desc);
+ ret = devm_regulator_register(conf->dev, desc, conf);
+ if (IS_ERR(ret))
+ /* Just pretend the regulator isn't there */
+ dev_err(conf->dev, "Failed to register regulator %s: %ld\n",
+ desc->name, PTR_ERR(ret));
+
+ of_node_put(conf->of_node);
+}
+
static int mxs_lradc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@@ -1603,6 +1748,7 @@ static int mxs_lradc_probe(struct platform_device *pdev)
struct mxs_lradc *lradc;
struct iio_dev *iio;
struct resource *iores;
+ struct regulator_config regconf;
int ret = 0, touch_ret;
int i, s;
u64 scale_uv;
@@ -1727,6 +1873,12 @@ static int mxs_lradc_probe(struct platform_device *pdev)
goto err_ts;
}
+ /* Setup regulator devices for current source. */
+ regconf.dev = dev;
+ regconf.driver_data = lradc;
+ mxs_lradc_reg_helper(node, "ISRC0", ®conf, &lradc->isrc0);
+ mxs_lradc_reg_helper(node, "ISRC1", ®conf, &lradc->isrc1);
+
return 0;
err_ts:
--
2.1.4
WARNING: multiple messages have this Message-ID (diff)
From: harald@ccbib.org (Harald Geyer)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 1/3] iio: mxs-lradc: Add regulators for current sources
Date: Fri, 22 Apr 2016 13:52:25 +0000 [thread overview]
Message-ID: <1461333147-11873-2-git-send-email-harald@ccbib.org> (raw)
In-Reply-To: <1461333147-11873-1-git-send-email-harald@ccbib.org>
The hardware has two current sources ISRC0 and ISRC1 to allow measuring
resistors without additional circuitry. This commit makes them available
as regulators.
Tested on an imx233-olinuxino board.
Signed-off-by: Harald Geyer <harald@ccbib.org>
---
The current regulator API doesn't fit this type of device very well: Typically
consumers will want to set a defined current, ie. min_uA == max_uA, but they
can't without help from configuration data, because the valid values aren't
reported by the API for current regulators. I have been thinking about
extending the API, but currently AFAIK no such consumers exist and most
users, like myself, will force the regulator to a defined value in
devicetree anyway.
.../bindings/staging/iio/adc/mxs-lradc.txt | 29 ++++
drivers/iio/adc/Kconfig | 1 +
drivers/iio/adc/mxs-lradc.c | 152 +++++++++++++++++++++
3 files changed, 182 insertions(+)
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
index 555fb11..983952c 100644
--- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -19,6 +19,15 @@ Optional properties:
- fsl,settling: delay between plate switch to next sample. Allowed value is
1 ... 2047. It counts at 2 kHz and its default is
10 (= 5 ms)
+- ISRC0: A node describing the regulator of internal current source 0
+- ISRC1: A node describing the regulator of internal current source 1
+
+Required properties for the ISRCx sub-nodes:
+- regulator-max-microamp: See standard regulator binding documentation.
+ Valid values are from 0 to 300 in steps of 20.
+
+Optional properties for the ISRCx sub-nodes:
+Any standard regulator properties that apply to current regulators.
Example for i.MX23 SoC:
@@ -31,6 +40,16 @@ Example for i.MX23 SoC:
fsl,ave-ctrl = <4>;
fsl,ave-delay = <2>;
fsl,settling = <10>;
+
+ isrc_lradc0: ISRC0 {
+ regulator-max-microamp = <300>;
+ };
+
+ isrc_lradc1: ISRC1 {
+ regulator-max-microamp = <120>;
+ regulator-min-microamp = <120>;
+ regulator-always-on;
+ };
};
Example for i.MX28 SoC:
@@ -44,4 +63,14 @@ Example for i.MX28 SoC:
fsl,ave-ctrl = <4>;
fsl,ave-delay = <2>;
fsl,settling = <10>;
+
+ isrc_lradc0: ISRC0 {
+ regulator-max-microamp = <300>;
+ };
+
+ isrc_lradc6: ISRC1 {
+ regulator-max-microamp = <120>;
+ regulator-min-microamp = <120>;
+ regulator-always-on;
+ };
};
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 5937030..1968d1c 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -319,6 +319,7 @@ config MXS_LRADC
tristate "Freescale i.MX23/i.MX28 LRADC"
depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
depends on INPUT
+ depends on REGULATOR
select STMP_DEVICE
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c
index 33051b8..f22f339 100644
--- a/drivers/iio/adc/mxs-lradc.c
+++ b/drivers/iio/adc/mxs-lradc.c
@@ -40,6 +40,10 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
#define DRIVER_NAME "mxs-lradc"
#define LRADC_MAX_DELAY_CHANS 4
@@ -261,6 +265,9 @@ struct mxs_lradc {
unsigned over_sample_delay;
/* time in clocks to wait after the plates where switched */
unsigned settling_delay;
+
+ struct regulator_desc isrc0;
+ struct regulator_desc isrc1;
};
#define LRADC_CTRL0 0x00
@@ -305,6 +312,11 @@ struct mxs_lradc {
#define LRADC_CTRL2 0x20
#define LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET 24
#define LRADC_CTRL2_TEMPSENSE_PWD BIT(15)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE1 BIT(9)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE0 BIT(8)
+#define LRADC_CTRL2_TEMP_ISRC1_OFFSET 4
+#define LRADC_CTRL2_TEMP_ISRC0_OFFSET 0
+#define LRADC_CTRL2_TEMP_ISRC_MASK 0x0f
#define LRADC_STATUS 0x40
#define LRADC_STATUS_TOUCH_DETECT_RAW BIT(0)
@@ -1383,6 +1395,109 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
.validate_scan_mask = &mxs_lradc_validate_scan_mask,
};
+static int mxs_lradc_regulator_is_enabled(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int reg = readl(lradc->base + LRADC_CTRL2);
+
+ if (dev->desc == &lradc->isrc0)
+ return reg & LRADC_CTRL2_TEMP_SENSOR_IENABLE0;
+ else if (dev->desc == &lradc->isrc1)
+ return reg & LRADC_CTRL2_TEMP_SENSOR_IENABLE1;
+
+ /* This should never happen */
+ return -ENODEV;
+}
+
+#define LRADC_REGVALUE2uA(regval, offset) \
+ (20 * ((regval >> offset) & LRADC_CTRL2_TEMP_ISRC_MASK))
+
+static int mxs_lradc_regulator_get_current_limit(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int reg = readl(lradc->base + LRADC_CTRL2);
+
+ if (dev->desc == &lradc->isrc0)
+ return LRADC_REGVALUE2uA(reg, LRADC_CTRL2_TEMP_ISRC0_OFFSET);
+ else if (dev->desc == &lradc->isrc1)
+ return LRADC_REGVALUE2uA(reg, LRADC_CTRL2_TEMP_ISRC1_OFFSET);
+
+ /* This should never happen */
+ return -ENODEV;
+}
+
+static int mxs_lradc_regulator_enable(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+
+ if (dev->desc == &lradc->isrc0)
+ mxs_lradc_reg_set(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
+ LRADC_CTRL2);
+ else if (dev->desc == &lradc->isrc1)
+ mxs_lradc_reg_set(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ return 0;
+}
+
+static int mxs_lradc_regulator_disable(struct regulator_dev *dev)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+
+ if (dev->desc == &lradc->isrc0)
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0,
+ LRADC_CTRL2);
+ else if (dev->desc == &lradc->isrc1)
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ return 0;
+}
+
+static int mxs_lradc_regulator_set_current_limit(struct regulator_dev *dev,
+ int min_uA, int max_uA)
+{
+ struct mxs_lradc *lradc = rdev_get_drvdata(dev);
+ int offset, value;
+
+ if (dev->desc == &lradc->isrc0)
+ offset = LRADC_CTRL2_TEMP_ISRC0_OFFSET;
+ else if (dev->desc == &lradc->isrc1)
+ offset = LRADC_CTRL2_TEMP_ISRC1_OFFSET;
+ else
+ /* This should never happen */
+ return -ENODEV;
+
+ value = min_uA / 20;
+ if (min_uA % 20)
+ value++;
+ if (value * 20 > max_uA)
+ return -EINVAL;
+ if (value & ~LRADC_CTRL2_TEMP_ISRC_MASK)
+ /* This should never happen */
+ return -EPERM;
+
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_ISRC_MASK << offset,
+ LRADC_CTRL2);
+ mxs_lradc_reg_set(lradc, value << offset, LRADC_CTRL2);
+
+ return 0;
+}
+
+static struct regulator_ops mxs_lradc_regulator_current_ops = {
+ .enable = mxs_lradc_regulator_enable,
+ .is_enabled = mxs_lradc_regulator_is_enabled,
+ .disable = mxs_lradc_regulator_disable,
+ .get_current_limit = mxs_lradc_regulator_get_current_limit,
+ .set_current_limit = mxs_lradc_regulator_set_current_limit,
+};
+
/*
* Driver initialization
*/
@@ -1519,6 +1634,10 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(i));
+
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL2_TEMP_SENSOR_IENABLE0 |
+ LRADC_CTRL2_TEMP_SENSOR_IENABLE1,
+ LRADC_CTRL2);
}
static const struct of_device_id mxs_lradc_dt_ids[] = {
@@ -1592,6 +1711,32 @@ static int mxs_lradc_probe_touchscreen(struct mxs_lradc *lradc,
return 0;
}
+static void mxs_lradc_reg_helper(struct device_node *np, const char *name,
+ struct regulator_config *conf,
+ struct regulator_desc *desc)
+{
+ struct regulator_dev *ret;
+
+ conf->of_node = of_get_child_by_name(np, name);
+ if (!conf->of_node)
+ return;
+
+ desc->name = name;
+ desc->owner = THIS_MODULE;
+ desc->type = REGULATOR_CURRENT;
+ desc->ops = &mxs_lradc_regulator_current_ops;
+
+ conf->init_data = of_get_regulator_init_data(conf->dev, conf->of_node,
+ desc);
+ ret = devm_regulator_register(conf->dev, desc, conf);
+ if (IS_ERR(ret))
+ /* Just pretend the regulator isn't there */
+ dev_err(conf->dev, "Failed to register regulator %s: %ld\n",
+ desc->name, PTR_ERR(ret));
+
+ of_node_put(conf->of_node);
+}
+
static int mxs_lradc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@@ -1603,6 +1748,7 @@ static int mxs_lradc_probe(struct platform_device *pdev)
struct mxs_lradc *lradc;
struct iio_dev *iio;
struct resource *iores;
+ struct regulator_config regconf;
int ret = 0, touch_ret;
int i, s;
u64 scale_uv;
@@ -1727,6 +1873,12 @@ static int mxs_lradc_probe(struct platform_device *pdev)
goto err_ts;
}
+ /* Setup regulator devices for current source. */
+ regconf.dev = dev;
+ regconf.driver_data = lradc;
+ mxs_lradc_reg_helper(node, "ISRC0", ®conf, &lradc->isrc0);
+ mxs_lradc_reg_helper(node, "ISRC1", ®conf, &lradc->isrc1);
+
return 0;
err_ts:
--
2.1.4
next prev parent reply other threads:[~2016-04-22 13:52 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-22 13:52 [PATCH 0/3] mxs-lradc: Add support for current sources Harald Geyer
2016-04-22 13:52 ` Harald Geyer
2016-04-22 13:52 ` Harald Geyer
[not found] ` <1461333147-11873-1-git-send-email-harald-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
2016-04-22 13:52 ` Harald Geyer [this message]
2016-04-22 13:52 ` [PATCH 1/3] iio: mxs-lradc: Add regulators " Harald Geyer
2016-04-22 13:52 ` Harald Geyer
[not found] ` <1461333147-11873-2-git-send-email-harald-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
2016-04-22 15:50 ` Marek Vasut
2016-04-22 15:50 ` Marek Vasut
2016-04-22 15:50 ` Marek Vasut
[not found] ` <571A4831.2020604-ynQEQJNshbs@public.gmane.org>
2016-04-22 17:00 ` Ksenija Stanojević
2016-04-22 17:00 ` Ksenija Stanojević
2016-04-22 17:00 ` Ksenija Stanojević
[not found] ` <CAL7P5jKYp0JrF2MHdLkLTBvgYb0KSDwPEMuNPGxcctcxCRnazg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-22 19:23 ` Harald Geyer
2016-04-22 19:23 ` Harald Geyer
2016-04-22 19:23 ` Harald Geyer
[not found] ` <f4c00c5c2242f6a951f1f8d8eca56357-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
2016-04-23 21:08 ` Jonathan Cameron
2016-04-23 21:08 ` Jonathan Cameron
2016-04-23 21:08 ` Jonathan Cameron
2016-04-22 16:11 ` Harald Geyer
2016-04-22 16:11 ` Harald Geyer
2016-04-22 16:11 ` Harald Geyer
2016-05-03 11:07 ` Stefan Wahren
2016-05-03 11:07 ` Stefan Wahren
2016-05-03 11:07 ` Stefan Wahren
[not found] ` <57288674.9050601-eS4NqCHxEME@public.gmane.org>
2016-05-03 11:22 ` Harald Geyer
2016-05-03 11:22 ` Harald Geyer
2016-05-03 11:22 ` Harald Geyer
[not found] ` <6cdd4f858dacf72e192a292f29c12feb-95f8Dae0BrPYtjvyW6yDsg@public.gmane.org>
2016-05-04 7:15 ` Jonathan Cameron
2016-05-04 7:15 ` Jonathan Cameron
2016-05-04 7:15 ` Jonathan Cameron
[not found] ` <1e7d5f3a-22c1-94d4-9620-7aa112602e39-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2016-05-04 11:38 ` Harald Geyer
2016-05-04 11:38 ` Harald Geyer
2016-05-04 11:38 ` Harald Geyer
2016-04-22 13:52 ` [PATCH 2/3] ARM: dts: imx23: Provide regulators for the current sources of the LRADC Harald Geyer
2016-04-22 13:52 ` Harald Geyer
2016-04-22 13:52 ` Harald Geyer
2016-04-22 13:52 ` [PATCH 3/3] ARM: dts: imx28: " Harald Geyer
2016-04-22 13:52 ` Harald Geyer
2016-04-22 13:52 ` Harald Geyer
2016-04-29 15:12 ` [PATCH 0/3] mxs-lradc: Add support for current sources Stefan Wahren
2016-04-29 15:12 ` Stefan Wahren
2016-04-29 15:12 ` Stefan Wahren
[not found] ` <572379F5.8000501-eS4NqCHxEME@public.gmane.org>
2016-04-29 17:45 ` Harald Geyer
2016-04-29 17:45 ` Harald Geyer
2016-04-29 17:45 ` Harald Geyer
2016-05-01 18:02 ` Jonathan Cameron
2016-05-01 18:02 ` Jonathan Cameron
2016-05-01 18:02 ` Jonathan Cameron
[not found] ` <ac57f3e9-f8f2-a6ef-52fa-0a13d7df5d4f-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2016-05-02 12:25 ` Harald Geyer
2016-05-02 12:25 ` Harald Geyer
2016-05-02 12:25 ` Harald Geyer
2016-05-02 12:29 ` Stefan Wahren
2016-05-02 12:29 ` Stefan Wahren
2016-05-02 12:29 ` Stefan Wahren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1461333147-11873-2-git-send-email-harald@ccbib.org \
--to=harald-95f8dae0brpytjvyw6ydsg@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=marex-ynQEQJNshbs@public.gmane.org \
--cc=shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=stefan.wahren-eS4NqCHxEME@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.