All of lore.kernel.org
 help / color / mirror / Atom feed
From: Fabrice Gasnier <fabrice.gasnier@st.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 4/6] adc: Add driver for STM32 ADC
Date: Mon, 23 Jul 2018 14:35:53 +0200	[thread overview]
Message-ID: <1532349355-32671-4-git-send-email-fabrice.gasnier@st.com> (raw)
In-Reply-To: <1532349355-32671-1-git-send-email-fabrice.gasnier@st.com>

This patch adds support for STMicroelectronics STM32 ADC (analog to
digital converter). It's originally based on Linux kernel v4.18-rcs
drivers/iio/adc/stm32-adc*. It's composed of:
- core driver (UCLASS_SIMPLE_BUS) manages common resources (clk, regu).
- child drivers (UCLASS_ADC) declare each ADC, channels and handle
  conversions.
This driver currently supports STM32H7 and STM32MP1 ADC.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---

 drivers/adc/Kconfig          |  16 +++
 drivers/adc/Makefile         |   1 +
 drivers/adc/stm32-adc-core.c | 209 +++++++++++++++++++++++++++++++++++
 drivers/adc/stm32-adc-core.h |  51 +++++++++
 drivers/adc/stm32-adc.c      | 257 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 534 insertions(+)
 create mode 100644 drivers/adc/stm32-adc-core.c
 create mode 100644 drivers/adc/stm32-adc-core.h
 create mode 100644 drivers/adc/stm32-adc.c

diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig
index 93e27f1..e719c38 100644
--- a/drivers/adc/Kconfig
+++ b/drivers/adc/Kconfig
@@ -47,3 +47,19 @@ config SARADC_ROCKCHIP
 	  - 2~6 analog input channels
 	  - 1O or 12 bits resolution
 	  - Up to 1MSPS of sample rate
+
+config STM32_ADC
+	bool "Enable STMicroelectronics STM32 ADC driver"
+	depends on ADC && (STM32H7 || ARCH_STM32MP)
+	help
+	  This enables driver for STMicroelectronics STM32 analog-to-digital
+	  converter (ADC).
+	  A STM32 ADC block can be composed of several individual ADCs.
+	  Each has its own private registers, but shares some resources:
+	  - clock selection and prescaler
+	  - voltage reference
+	  - common registers area.
+	  STM32 ADC driver is composed of:
+	  - core driver to deal with common resources
+	  - child driver to deal with individual ADC resources (declare ADC
+	  device and associated channels, start/stop conversions)
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile
index 95c93d4..cca0fec 100644
--- a/drivers/adc/Makefile
+++ b/drivers/adc/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o
 obj-$(CONFIG_ADC_SANDBOX) += sandbox.o
 obj-$(CONFIG_SARADC_ROCKCHIP) += rockchip-saradc.o
 obj-$(CONFIG_SARADC_MESON) += meson-saradc.o
+obj-$(CONFIG_STM32_ADC) += stm32-adc.o stm32-adc-core.o
diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c
new file mode 100644
index 0000000..a9aa143
--- /dev/null
+++ b/drivers/adc/stm32-adc-core.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc-core.c.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <power/regulator.h>
+#include "stm32-adc-core.h"
+
+/* STM32H7 - common registers for all ADC instances */
+#define STM32H7_ADC_CCR			(STM32_ADCX_COMN_OFFSET + 0x08)
+
+/* STM32H7_ADC_CCR - bit fields */
+#define STM32H7_PRESC_SHIFT		18
+#define STM32H7_PRESC_MASK		GENMASK(21, 18)
+#define STM32H7_CKMODE_SHIFT		16
+#define STM32H7_CKMODE_MASK		GENMASK(17, 16)
+
+/* STM32 H7 maximum analog clock rate (from datasheet) */
+#define STM32H7_ADC_MAX_CLK_RATE	36000000
+
+/**
+ * struct stm32h7_adc_ck_spec - specification for stm32h7 adc clock
+ * @ckmode: ADC clock mode, Async or sync with prescaler.
+ * @presc: prescaler bitfield for async clock mode
+ * @div: prescaler division ratio
+ */
+struct stm32h7_adc_ck_spec {
+	u32 ckmode;
+	u32 presc;
+	int div;
+};
+
+static const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
+	/* 00: CK_ADC[1..3]: Asynchronous clock modes */
+	{ 0, 0, 1 },
+	{ 0, 1, 2 },
+	{ 0, 2, 4 },
+	{ 0, 3, 6 },
+	{ 0, 4, 8 },
+	{ 0, 5, 10 },
+	{ 0, 6, 12 },
+	{ 0, 7, 16 },
+	{ 0, 8, 32 },
+	{ 0, 9, 64 },
+	{ 0, 10, 128 },
+	{ 0, 11, 256 },
+	/* HCLK used: Synchronous clock modes (1, 2 or 4 prescaler) */
+	{ 1, 0, 1 },
+	{ 2, 0, 2 },
+	{ 3, 0, 4 },
+};
+
+static int stm32h7_adc_clk_sel(struct udevice *dev,
+			       struct stm32_adc_common *common)
+{
+	u32 ckmode, presc;
+	unsigned long rate;
+	int i, div;
+
+	/* stm32h7 bus clock is common for all ADC instances (mandatory) */
+	if (!clk_valid(&common->bclk)) {
+		dev_err(dev, "No bclk clock found\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * stm32h7 can use either 'bus' or 'adc' clock for analog circuitry.
+	 * So, choice is to have bus clock mandatory and adc clock optional.
+	 * If optional 'adc' clock has been found, then try to use it first.
+	 */
+	if (clk_valid(&common->aclk)) {
+		/*
+		 * Asynchronous clock modes (e.g. ckmode == 0)
+		 * From spec: PLL output musn't exceed max rate
+		 */
+		rate = clk_get_rate(&common->aclk);
+		if (!rate) {
+			dev_err(dev, "Invalid aclk rate: 0\n");
+			return -EINVAL;
+		}
+
+		for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
+			ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
+			presc = stm32h7_adc_ckmodes_spec[i].presc;
+			div = stm32h7_adc_ckmodes_spec[i].div;
+
+			if (ckmode)
+				continue;
+
+			if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
+				goto out;
+		}
+	}
+
+	/* Synchronous clock modes (e.g. ckmode is 1, 2 or 3) */
+	rate = clk_get_rate(&common->bclk);
+	if (!rate) {
+		dev_err(dev, "Invalid bus clock rate: 0\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
+		ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
+		presc = stm32h7_adc_ckmodes_spec[i].presc;
+		div = stm32h7_adc_ckmodes_spec[i].div;
+
+		if (!ckmode)
+			continue;
+
+		if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
+			goto out;
+	}
+
+	dev_err(dev, "clk selection failed\n");
+	return -EINVAL;
+
+out:
+	/* rate used later by each ADC instance to control BOOST mode */
+	common->rate = rate / div;
+
+	/* Set common clock mode and prescaler */
+	clrsetbits_le32(common->base + STM32H7_ADC_CCR,
+			STM32H7_CKMODE_MASK | STM32H7_PRESC_MASK,
+			ckmode << STM32H7_CKMODE_SHIFT |
+			presc << STM32H7_PRESC_SHIFT);
+
+	dev_dbg(dev, "Using %s clock/%d source@%ld kHz\n",
+		ckmode ? "bus" : "adc", div, common->rate / 1000);
+
+	return 0;
+}
+
+static int stm32_adc_core_probe(struct udevice *dev)
+{
+	struct stm32_adc_common *common = dev_get_priv(dev);
+	int ret;
+
+	common->base = dev_read_addr_ptr(dev);
+	if (!common->base) {
+		dev_err(dev, "can't get address\n");
+		return -ENOENT;
+	}
+
+	ret = device_get_supply_regulator(dev, "vref-supply", &common->vref);
+	if (ret) {
+		dev_err(dev, "can't get vref-supply: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_get_value(common->vref);
+	if (ret < 0) {
+		dev_err(dev, "can't get vref-supply value: %d\n", ret);
+		return ret;
+	}
+	common->vref_uv = ret;
+
+	ret = clk_get_by_name(dev, "adc", &common->aclk);
+	if (!ret) {
+		ret = clk_enable(&common->aclk);
+		if (ret) {
+			dev_err(dev, "Can't enable aclk: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = clk_get_by_name(dev, "bus", &common->bclk);
+	if (!ret) {
+		ret = clk_enable(&common->bclk);
+		if (ret) {
+			dev_err(dev, "Can't enable bclk: %d\n", ret);
+			goto err_aclk_disable;
+		}
+	}
+
+	ret = stm32h7_adc_clk_sel(dev, common);
+	if (ret)
+		goto err_bclk_disable;
+
+	return ret;
+
+err_bclk_disable:
+	if (clk_valid(&common->bclk))
+		clk_disable(&common->bclk);
+
+err_aclk_disable:
+	if (clk_valid(&common->aclk))
+		clk_disable(&common->aclk);
+
+	return ret;
+}
+
+static const struct udevice_id stm32_adc_core_ids[] = {
+	{ .compatible = "st,stm32h7-adc-core" },
+	{ .compatible = "st,stm32mp1-adc-core" },
+	{}
+};
+
+U_BOOT_DRIVER(stm32_adc_core) = {
+	.name  = "stm32-adc-core",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = stm32_adc_core_ids,
+	.probe = stm32_adc_core_probe,
+	.priv_auto_alloc_size = sizeof(struct stm32_adc_common),
+};
diff --git a/drivers/adc/stm32-adc-core.h b/drivers/adc/stm32-adc-core.h
new file mode 100644
index 0000000..ba0e10e
--- /dev/null
+++ b/drivers/adc/stm32-adc-core.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
+ *
+ * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc-core.h.
+ */
+
+#ifndef __STM32_ADC_H
+#define __STM32_ADC_H
+
+/*
+ * STM32 - ADC global register map
+ * ________________________________________________________
+ * | Offset |                 Register                    |
+ * --------------------------------------------------------
+ * | 0x000  |                Master ADC1                  |
+ * --------------------------------------------------------
+ * | 0x100  |                Slave ADC2                   |
+ * --------------------------------------------------------
+ * | 0x200  |                Slave ADC3                   |
+ * --------------------------------------------------------
+ * | 0x300  |         Master & Slave common regs          |
+ * --------------------------------------------------------
+ */
+#define STM32_ADC_MAX_ADCS		3
+#define STM32_ADCX_COMN_OFFSET		0x300
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+
+/**
+ * struct stm32_adc_common - stm32 ADC driver common data (for all instances)
+ * @base:		control registers base cpu addr
+ * @rate:		clock rate used for analog circuitry
+ * @aclk:		clock for the analog circuitry
+ * @bclk:		bus clock common for all ADCs
+ * @vref:		regulator reference
+ * @vref_uv:		reference supply voltage (uV)
+ */
+struct stm32_adc_common {
+	void __iomem *base;
+	unsigned long rate;
+	struct clk aclk;
+	struct clk bclk;
+	struct udevice *vref;
+	int vref_uv;
+};
+
+#endif
diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c
new file mode 100644
index 0000000..e108062
--- /dev/null
+++ b/drivers/adc/stm32-adc.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc.c.
+ */
+
+#include <common.h>
+#include <adc.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include "stm32-adc-core.h"
+
+/* STM32H7 - Registers for each ADC instance */
+#define STM32H7_ADC_ISR			0x00
+#define STM32H7_ADC_CR			0x08
+#define STM32H7_ADC_CFGR		0x0C
+#define STM32H7_ADC_SMPR1		0x14
+#define STM32H7_ADC_SMPR2		0x18
+#define STM32H7_ADC_PCSEL		0x1C
+#define STM32H7_ADC_SQR1		0x30
+#define STM32H7_ADC_DR			0x40
+#define STM32H7_ADC_DIFSEL		0xC0
+
+/* STM32H7_ADC_ISR - bit fields */
+#define STM32MP1_VREGREADY		BIT(12)
+#define STM32H7_EOC			BIT(2)
+#define STM32H7_ADRDY			BIT(0)
+
+/* STM32H7_ADC_CR - bit fields */
+#define STM32H7_DEEPPWD			BIT(29)
+#define STM32H7_ADVREGEN		BIT(28)
+#define STM32H7_BOOST			BIT(8)
+#define STM32H7_ADSTART			BIT(2)
+#define STM32H7_ADDIS			BIT(1)
+#define STM32H7_ADEN			BIT(0)
+
+/* STM32H7_ADC_CFGR bit fields */
+#define STM32H7_EXTEN			GENMASK(11, 10)
+#define STM32H7_DMNGT			GENMASK(1, 0)
+
+/* STM32H7_ADC_SQR1 - bit fields */
+#define STM32H7_SQ1_SHIFT		6
+
+/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
+#define STM32H7_BOOST_CLKRATE		20000000UL
+
+#define STM32_ADC_CH_MAX		20	/* max number of channels */
+#define STM32_ADC_TIMEOUT_US		100000
+
+struct stm32_adc_cfg {
+	unsigned int max_channels;
+	unsigned int num_bits;
+	bool has_vregready;
+};
+
+struct stm32_adc {
+	void __iomem *regs;
+	int active_channel;
+	const struct stm32_adc_cfg *cfg;
+};
+
+static int stm32_adc_stop(struct udevice *dev)
+{
+	struct stm32_adc *adc = dev_get_priv(dev);
+
+	setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS);
+	clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
+	/* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
+	setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
+	adc->active_channel = -1;
+
+	return 0;
+}
+
+static int stm32_adc_start_channel(struct udevice *dev, int channel)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
+	struct stm32_adc *adc = dev_get_priv(dev);
+	int ret;
+	u32 val;
+
+	/* Exit deep power down, then enable ADC voltage regulator */
+	clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
+	setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN);
+	if (common->rate > STM32H7_BOOST_CLKRATE)
+		setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
+
+	/* Wait for startup time */
+	if (!adc->cfg->has_vregready) {
+		udelay(20);
+	} else {
+		ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
+					 val & STM32MP1_VREGREADY,
+					 STM32_ADC_TIMEOUT_US);
+		if (ret < 0) {
+			stm32_adc_stop(dev);
+			dev_err(dev, "Failed to enable vreg: %d\n", ret);
+			return ret;
+		}
+	}
+
+	/* Only use single ended channels */
+	writel(0, adc->regs + STM32H7_ADC_DIFSEL);
+
+	/* Enable ADC, Poll for ADRDY to be set (after adc startup time) */
+	setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN);
+	ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
+				 val & STM32H7_ADRDY, STM32_ADC_TIMEOUT_US);
+	if (ret < 0) {
+		stm32_adc_stop(dev);
+		dev_err(dev, "Failed to enable ADC: %d\n", ret);
+		return ret;
+	}
+
+	/* Preselect channels */
+	writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL);
+
+	/* Set sampling time to max value by default */
+	writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1);
+	writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR2);
+
+	/* Program regular sequence: chan in SQ1 & len = 0 for one channel */
+	writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1);
+
+	/* Trigger detection disabled (conversion can be launched in SW) */
+	clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN |
+		     STM32H7_DMNGT);
+	adc->active_channel = channel;
+
+	return 0;
+}
+
+static int stm32_adc_channel_data(struct udevice *dev, int channel,
+				  unsigned int *data)
+{
+	struct stm32_adc *adc = dev_get_priv(dev);
+	int ret;
+	u32 val;
+
+	if (channel != adc->active_channel) {
+		dev_err(dev, "Requested channel is not active!\n");
+		return -EINVAL;
+	}
+
+	setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADSTART);
+	ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
+				 val & STM32H7_EOC, STM32_ADC_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(dev, "conversion timed out: %d\n", ret);
+		return ret;
+	}
+
+	*data = readl(adc->regs + STM32H7_ADC_DR);
+
+	return 0;
+}
+
+static int stm32_adc_chan_of_init(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	struct stm32_adc *adc = dev_get_priv(dev);
+	u32 chans[STM32_ADC_CH_MAX];
+	int i, num_channels, ret;
+
+	/* Retrieve single ended channels listed in device tree */
+	num_channels = dev_read_size(dev, "st,adc-channels");
+	if (num_channels < 0) {
+		dev_err(dev, "can't get st,adc-channels: %d\n", num_channels);
+		return num_channels;
+	}
+	num_channels /= sizeof(u32);
+
+	if (num_channels > adc->cfg->max_channels) {
+		dev_err(dev, "too many st,adc-channels: %d\n", num_channels);
+		return -EINVAL;
+	}
+
+	ret = dev_read_u32_array(dev, "st,adc-channels", chans, num_channels);
+	if (ret < 0) {
+		dev_err(dev, "can't read st,adc-channels: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < num_channels; i++) {
+		if (chans[i] >= adc->cfg->max_channels) {
+			dev_err(dev, "bad channel %u\n", chans[i]);
+			return -EINVAL;
+		}
+		uc_pdata->channel_mask |= 1 << chans[i];
+	}
+
+	uc_pdata->data_mask = (1 << adc->cfg->num_bits) - 1;
+	uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
+	uc_pdata->data_timeout_us = 100000;
+
+	return 0;
+}
+
+static int stm32_adc_probe(struct udevice *dev)
+{
+	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+	struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
+	struct stm32_adc *adc = dev_get_priv(dev);
+	int offset;
+
+	offset = dev_read_u32_default(dev, "reg", -ENODATA);
+	if (offset < 0) {
+		dev_err(dev, "Can't read reg property\n");
+		return offset;
+	}
+	adc->regs = common->base + offset;
+	adc->cfg = (const struct stm32_adc_cfg *)dev_get_driver_data(dev);
+
+	/* VDD supplied by common vref pin */
+	uc_pdata->vdd_supply = common->vref;
+	uc_pdata->vdd_microvolts = common->vref_uv;
+	uc_pdata->vss_microvolts = 0;
+
+	return stm32_adc_chan_of_init(dev);
+}
+
+static const struct adc_ops stm32_adc_ops = {
+	.start_channel = stm32_adc_start_channel,
+	.channel_data = stm32_adc_channel_data,
+	.stop = stm32_adc_stop,
+};
+
+static const struct stm32_adc_cfg stm32h7_adc_cfg = {
+	.num_bits = 16,
+	.max_channels = STM32_ADC_CH_MAX,
+};
+
+static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
+	.num_bits = 16,
+	.max_channels = STM32_ADC_CH_MAX,
+	.has_vregready = true,
+};
+
+static const struct udevice_id stm32_adc_ids[] = {
+	{ .compatible = "st,stm32h7-adc",
+	  .data = (ulong)&stm32h7_adc_cfg },
+	{ .compatible = "st,stm32mp1-adc",
+	  .data = (ulong)&stm32mp1_adc_cfg },
+	{}
+};
+
+U_BOOT_DRIVER(stm32_adc) = {
+	.name  = "stm32-adc",
+	.id = UCLASS_ADC,
+	.of_match = stm32_adc_ids,
+	.probe = stm32_adc_probe,
+	.ops = &stm32_adc_ops,
+	.priv_auto_alloc_size = sizeof(struct stm32_adc),
+};
-- 
1.9.1

  parent reply	other threads:[~2018-07-23 12:35 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-23 12:35 [U-Boot] [PATCH 1/6] clk: add clk_valid() Fabrice Gasnier
2018-07-23 12:35 ` [U-Boot] [PATCH 2/6] dm: adc: uclass: get reference regulator once Fabrice Gasnier
2018-07-23 23:48   ` Simon Glass
2018-07-24 14:37     ` Fabrice Gasnier
2018-07-23 12:35 ` [U-Boot] [PATCH 3/6] dt-bindings: Document STM32 ADC DT bindings Fabrice Gasnier
2018-07-23 23:48   ` Simon Glass
2018-07-23 12:35 ` Fabrice Gasnier [this message]
2018-07-23 23:48   ` [U-Boot] [PATCH 4/6] adc: Add driver for STM32 ADC Simon Glass
2018-07-23 12:35 ` [U-Boot] [PATCH 5/6] configs: stm32mp15: enable ADC Fabrice Gasnier
2018-07-23 23:48   ` Simon Glass
2018-07-23 12:35 ` [U-Boot] [PATCH 6/6] ARM: dts: stm32mp157: Add ADC DT node Fabrice Gasnier
2018-07-23 23:48 ` [U-Boot] [PATCH 1/6] clk: add clk_valid() Simon Glass

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=1532349355-32671-4-git-send-email-fabrice.gasnier@st.com \
    --to=fabrice.gasnier@st.com \
    --cc=u-boot@lists.denx.de \
    /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.