summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/adc/Kconfig10
-rw-r--r--drivers/adc/Makefile1
-rw-r--r--drivers/adc/meson-saradc.c723
-rw-r--r--drivers/clk/clk_stm32f.c36
-rw-r--r--drivers/clk/clk_stm32mp1.c3
-rw-r--r--drivers/core/regmap.c14
-rw-r--r--drivers/gpio/atmel_pio4.c36
-rw-r--r--drivers/led/led_gpio.c25
-rw-r--r--drivers/misc/stm32_rcc.c12
-rw-r--r--drivers/pci/Kconfig7
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/pcie_intel_fpga.c430
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson-gxbb.c12
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson-gxl.c14
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-core.c140
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c11
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c13
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier.h49
-rw-r--r--drivers/power/pmic/stpmu1.c34
-rw-r--r--drivers/power/regulator/Kconfig18
-rw-r--r--drivers/power/regulator/Makefile2
-rw-r--r--drivers/power/regulator/stm32-vrefbuf.c155
-rw-r--r--drivers/power/regulator/stpmu1.c667
23 files changed, 2343 insertions, 70 deletions
diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig
index 8094420548..93e27f131c 100644
--- a/drivers/adc/Kconfig
+++ b/drivers/adc/Kconfig
@@ -29,6 +29,16 @@ config ADC_SANDBOX
- 16-bit resolution
- single and multi-channel conversion mode
+config SARADC_MESON
+ bool "Enable Amlogic Meson SARADC driver"
+ imply REGMAP
+ help
+ This enables driver for Amlogic Meson SARADC.
+ It provides:
+ - 8 analog input channels
+ - 1O or 12 bits resolution
+ - Up to 1MSPS of sample rate
+
config SARADC_ROCKCHIP
bool "Enable Rockchip SARADC driver"
help
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile
index 4b5aa693ec..95c93d4c57 100644
--- a/drivers/adc/Makefile
+++ b/drivers/adc/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_ADC) += adc-uclass.o
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
diff --git a/drivers/adc/meson-saradc.c b/drivers/adc/meson-saradc.c
new file mode 100644
index 0000000000..bcab76d050
--- /dev/null
+++ b/drivers/adc/meson-saradc.c
@@ -0,0 +1,723 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
+ */
+
+#include <common.h>
+#include <adc.h>
+#include <clk.h>
+#include <dm.h>
+#include <regmap.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/math64.h>
+#include <linux/bitfield.h>
+
+#define MESON_SAR_ADC_REG0 0x00
+ #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31)
+ #define MESON_SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28)
+ #define MESON_SAR_ADC_REG0_DELTA_BUSY BIT(30)
+ #define MESON_SAR_ADC_REG0_AVG_BUSY BIT(29)
+ #define MESON_SAR_ADC_REG0_SAMPLE_BUSY BIT(28)
+ #define MESON_SAR_ADC_REG0_FIFO_FULL BIT(27)
+ #define MESON_SAR_ADC_REG0_FIFO_EMPTY BIT(26)
+ #define MESON_SAR_ADC_REG0_FIFO_COUNT_MASK GENMASK(25, 21)
+ #define MESON_SAR_ADC_REG0_ADC_BIAS_CTRL_MASK GENMASK(20, 19)
+ #define MESON_SAR_ADC_REG0_CURR_CHAN_ID_MASK GENMASK(18, 16)
+ #define MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL BIT(15)
+ #define MESON_SAR_ADC_REG0_SAMPLING_STOP BIT(14)
+ #define MESON_SAR_ADC_REG0_CHAN_DELTA_EN_MASK GENMASK(13, 12)
+ #define MESON_SAR_ADC_REG0_DETECT_IRQ_POL BIT(10)
+ #define MESON_SAR_ADC_REG0_DETECT_IRQ_EN BIT(9)
+ #define MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK GENMASK(8, 4)
+ #define MESON_SAR_ADC_REG0_FIFO_IRQ_EN BIT(3)
+ #define MESON_SAR_ADC_REG0_SAMPLING_START BIT(2)
+ #define MESON_SAR_ADC_REG0_CONTINUOUS_EN BIT(1)
+ #define MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE BIT(0)
+
+#define MESON_SAR_ADC_CHAN_LIST 0x04
+ #define MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK GENMASK(26, 24)
+ #define MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(_chan) \
+ (GENMASK(2, 0) << ((_chan) * 3))
+
+#define MESON_SAR_ADC_AVG_CNTL 0x08
+ #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan) \
+ (16 + ((_chan) * 2))
+ #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan) \
+ (GENMASK(17, 16) << ((_chan) * 2))
+ #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan) \
+ (0 + ((_chan) * 2))
+ #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan) \
+ (GENMASK(1, 0) << ((_chan) * 2))
+
+#define MESON_SAR_ADC_REG3 0x0c
+ #define MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY BIT(31)
+ #define MESON_SAR_ADC_REG3_CLK_EN BIT(30)
+ #define MESON_SAR_ADC_REG3_BL30_INITIALIZED BIT(28)
+ #define MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN BIT(27)
+ #define MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE BIT(26)
+ #define MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK GENMASK(25, 23)
+ #define MESON_SAR_ADC_REG3_DETECT_EN BIT(22)
+ #define MESON_SAR_ADC_REG3_ADC_EN BIT(21)
+ #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18)
+ #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16)
+ #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10
+ #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 5
+ #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8)
+ #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0)
+
+#define MESON_SAR_ADC_DELAY 0x10
+ #define MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK GENMASK(25, 24)
+ #define MESON_SAR_ADC_DELAY_BL30_BUSY BIT(15)
+ #define MESON_SAR_ADC_DELAY_KERNEL_BUSY BIT(14)
+ #define MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK GENMASK(23, 16)
+ #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK GENMASK(9, 8)
+ #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK GENMASK(7, 0)
+
+#define MESON_SAR_ADC_LAST_RD 0x14
+ #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK GENMASK(23, 16)
+ #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK GENMASK(9, 0)
+
+#define MESON_SAR_ADC_FIFO_RD 0x18
+ #define MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK GENMASK(14, 12)
+ #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0)
+
+#define MESON_SAR_ADC_AUX_SW 0x1c
+ #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(_chan) \
+ (8 + (((_chan) - 2) * 3))
+ #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX BIT(6)
+ #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX BIT(5)
+ #define MESON_SAR_ADC_AUX_SW_MODE_SEL BIT(4)
+ #define MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW BIT(3)
+ #define MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW BIT(2)
+ #define MESON_SAR_ADC_AUX_SW_YM_DRIVE_SW BIT(1)
+ #define MESON_SAR_ADC_AUX_SW_XM_DRIVE_SW BIT(0)
+
+#define MESON_SAR_ADC_CHAN_10_SW 0x20
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK GENMASK(25, 23)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX BIT(22)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX BIT(21)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL BIT(20)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW BIT(19)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW BIT(18)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW BIT(17)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW BIT(16)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK GENMASK(9, 7)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX BIT(6)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX BIT(5)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL BIT(4)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW BIT(3)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW BIT(2)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW BIT(1)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW BIT(0)
+
+#define MESON_SAR_ADC_DETECT_IDLE_SW 0x24
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN BIT(26)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK GENMASK(25, 23)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_P_MUX BIT(22)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_N_MUX BIT(21)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL BIT(20)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YP_DRIVE_SW BIT(19)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XP_DRIVE_SW BIT(18)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YM_DRIVE_SW BIT(17)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XM_DRIVE_SW BIT(16)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK GENMASK(9, 7)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_P_MUX BIT(6)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_N_MUX BIT(5)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL BIT(4)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YP_DRIVE_SW BIT(3)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XP_DRIVE_SW BIT(2)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YM_DRIVE_SW BIT(1)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XM_DRIVE_SW BIT(0)
+
+#define MESON_SAR_ADC_DELTA_10 0x28
+ #define MESON_SAR_ADC_DELTA_10_TEMP_SEL BIT(27)
+ #define MESON_SAR_ADC_DELTA_10_TS_REVE1 BIT(26)
+ #define MESON_SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK GENMASK(25, 16)
+ #define MESON_SAR_ADC_DELTA_10_TS_REVE0 BIT(15)
+ #define MESON_SAR_ADC_DELTA_10_TS_C_SHIFT 11
+ #define MESON_SAR_ADC_DELTA_10_TS_C_MASK GENMASK(14, 11)
+ #define MESON_SAR_ADC_DELTA_10_TS_VBG_EN BIT(10)
+ #define MESON_SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK GENMASK(9, 0)
+
+/*
+ * NOTE: registers from here are undocumented (the vendor Linux kernel driver
+ * and u-boot source served as reference). These only seem to be relevant on
+ * GXBB and newer.
+ */
+#define MESON_SAR_ADC_REG11 0x2c
+ #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13)
+
+#define MESON_SAR_ADC_REG13 0x34
+ #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8)
+
+#define MESON_SAR_ADC_MAX_FIFO_SIZE 32
+#define MESON_SAR_ADC_TIMEOUT 100 /* ms */
+
+#define NUM_CHANNELS 8
+
+#define MILLION 1000000
+
+struct meson_saradc_data {
+ int num_bits;
+};
+
+struct meson_saradc_priv {
+ const struct meson_saradc_data *data;
+ struct regmap *regmap;
+ struct clk core_clk;
+ struct clk adc_clk;
+ bool initialized;
+ int active_channel;
+ int calibbias;
+ int calibscale;
+};
+
+static unsigned int
+meson_saradc_get_fifo_count(struct meson_saradc_priv *priv)
+{
+ u32 regval;
+
+ regmap_read(priv->regmap, MESON_SAR_ADC_REG0, &regval);
+
+ return FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
+}
+
+static int meson_saradc_lock(struct meson_saradc_priv *priv)
+{
+ uint val, timeout = 10000;
+
+ /* prevent BL30 from using the SAR ADC while we are using it */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY);
+
+ /*
+ * wait until BL30 releases it's lock (so we can use the SAR ADC)
+ */
+ do {
+ udelay(1);
+ regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
+ } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
+
+ if (timeout < 0) {
+ printf("Timeout while waiting for BL30 unlock\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void meson_saradc_unlock(struct meson_saradc_priv *priv)
+{
+ /* allow BL30 to use the SAR ADC again */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
+}
+
+static void meson_saradc_clear_fifo(struct meson_saradc_priv *priv)
+{
+ unsigned int count, tmp;
+
+ for (count = 0; count < MESON_SAR_ADC_MAX_FIFO_SIZE; count++) {
+ if (!meson_saradc_get_fifo_count(priv))
+ break;
+
+ regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, &tmp);
+ }
+}
+
+static int meson_saradc_calib_val(struct meson_saradc_priv *priv, int val)
+{
+ int tmp;
+
+ /* use val_calib = scale * val_raw + offset calibration function */
+ tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias;
+
+ return clamp(tmp, 0, (1 << priv->data->num_bits) - 1);
+}
+
+static int meson_saradc_wait_busy_clear(struct meson_saradc_priv *priv)
+{
+ uint regval, timeout = 10000;
+
+ /*
+ * NOTE: we need a small delay before reading the status, otherwise
+ * the sample engine may not have started internally (which would
+ * seem to us that sampling is already finished).
+ */
+ do {
+ udelay(1);
+ regmap_read(priv->regmap, MESON_SAR_ADC_REG0, &regval);
+ } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
+
+ if (timeout < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int meson_saradc_read_raw_sample(struct meson_saradc_priv *priv,
+ unsigned int channel, uint *val)
+{
+ uint regval, fifo_chan, fifo_val, count;
+ int ret;
+
+ ret = meson_saradc_wait_busy_clear(priv);
+ if (ret)
+ return ret;
+
+ count = meson_saradc_get_fifo_count(priv);
+ if (count != 1) {
+ printf("ADC FIFO has %d element(s) instead of one\n", count);
+ return -EINVAL;
+ }
+
+ regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, &regval);
+ fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
+ if (fifo_chan != channel) {
+ printf("ADC FIFO entry belongs to channel %d instead of %d\n",
+ fifo_chan, channel);
+ return -EINVAL;
+ }
+
+ fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval);
+ fifo_val &= GENMASK(priv->data->num_bits - 1, 0);
+ *val = meson_saradc_calib_val(priv, fifo_val);
+
+ return 0;
+}
+
+static void meson_saradc_start_sample_engine(struct meson_saradc_priv *priv)
+{
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_FIFO_IRQ_EN,
+ MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_START,
+ MESON_SAR_ADC_REG0_SAMPLING_START);
+}
+
+static void meson_saradc_stop_sample_engine(struct meson_saradc_priv *priv)
+{
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_STOP,
+ MESON_SAR_ADC_REG0_SAMPLING_STOP);
+
+ /* wait until all modules are stopped */
+ meson_saradc_wait_busy_clear(priv);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
+}
+
+enum meson_saradc_avg_mode {
+ NO_AVERAGING = 0x0,
+ MEAN_AVERAGING = 0x1,
+ MEDIAN_AVERAGING = 0x2,
+};
+
+enum meson_saradc_num_samples {
+ ONE_SAMPLE = 0x0,
+ TWO_SAMPLES = 0x1,
+ FOUR_SAMPLES = 0x2,
+ EIGHT_SAMPLES = 0x3,
+};
+
+static void meson_saradc_set_averaging(struct meson_saradc_priv *priv,
+ unsigned int channel,
+ enum meson_saradc_avg_mode mode,
+ enum meson_saradc_num_samples samples)
+{
+ int val;
+
+ val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL,
+ MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(channel),
+ val);
+
+ val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL,
+ MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(channel), val);
+}
+
+static void meson_saradc_enable_channel(struct meson_saradc_priv *priv,
+ unsigned int channel)
+{
+ uint regval;
+
+ /*
+ * the SAR ADC engine allows sampling multiple channels at the same
+ * time. to keep it simple we're only working with one *internal*
+ * channel, which starts counting at index 0 (which means: count = 1).
+ */
+ regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST,
+ MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
+
+ /* map channel index 0 to the channel which we want to read */
+ regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST,
+ MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), regval);
+
+ regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK,
+ channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW,
+ MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK,
+ regval);
+
+ regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK,
+ channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW,
+ MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK,
+ regval);
+
+ if (channel == 6)
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0);
+}
+
+static int meson_saradc_get_sample(struct meson_saradc_priv *priv,
+ int chan, uint *val)
+{
+ int ret;
+
+ ret = meson_saradc_lock(priv);
+ if (ret)
+ return ret;
+
+ /* clear the FIFO to make sure we're not reading old values */
+ meson_saradc_clear_fifo(priv);
+
+ meson_saradc_set_averaging(priv, chan, MEAN_AVERAGING, EIGHT_SAMPLES);
+
+ meson_saradc_enable_channel(priv, chan);
+
+ meson_saradc_start_sample_engine(priv);
+ ret = meson_saradc_read_raw_sample(priv, chan, val);
+ meson_saradc_stop_sample_engine(priv);
+
+ meson_saradc_unlock(priv);
+
+ if (ret) {
+ printf("failed to read sample for channel %d: %d\n",
+ chan, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int meson_saradc_channel_data(struct udevice *dev, int channel,
+ unsigned int *data)
+{
+ struct meson_saradc_priv *priv = dev_get_priv(dev);
+
+ if (channel != priv->active_channel) {
+ pr_err("Requested channel is not active!");
+ return -EINVAL;
+ }
+
+ return meson_saradc_get_sample(priv, channel, data);
+}
+
+enum meson_saradc_chan7_mux_sel {
+ CHAN7_MUX_VSS = 0x0,
+ CHAN7_MUX_VDD_DIV4 = 0x1,
+ CHAN7_MUX_VDD_DIV2 = 0x2,
+ CHAN7_MUX_VDD_MUL3_DIV4 = 0x3,
+ CHAN7_MUX_VDD = 0x4,
+ CHAN7_MUX_CH7_INPUT = 0x7,
+};
+
+static void meson_saradc_set_chan7_mux(struct meson_saradc_priv *priv,
+ enum meson_saradc_chan7_mux_sel sel)
+{
+ u32 regval;
+
+ regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
+
+ udelay(20);
+}
+
+static int meson_saradc_calib(struct meson_saradc_priv *priv)
+{
+ uint nominal0, nominal1, value0, value1;
+ int ret;
+
+ /* use points 25% and 75% for calibration */
+ nominal0 = (1 << priv->data->num_bits) / 4;
+ nominal1 = (1 << priv->data->num_bits) * 3 / 4;
+
+ meson_saradc_set_chan7_mux(priv, CHAN7_MUX_VDD_DIV4);
+ udelay(20);
+ ret = meson_saradc_get_sample(priv, 7, &value0);
+ if (ret < 0)
+ goto out;
+
+ meson_saradc_set_chan7_mux(priv, CHAN7_MUX_VDD_MUL3_DIV4);
+ udelay(20);
+ ret = meson_saradc_get_sample(priv, 7, &value1);
+ if (ret < 0)
+ goto out;
+
+ if (value1 <= value0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ priv->calibscale = div_s64((nominal1 - nominal0) * (s64)MILLION,
+ value1 - value0);
+ priv->calibbias = nominal0 - div_s64((s64)value0 * priv->calibscale,
+ MILLION);
+ ret = 0;
+out:
+ meson_saradc_set_chan7_mux(priv, CHAN7_MUX_CH7_INPUT);
+
+ return ret;
+}
+
+static int meson_saradc_init(struct meson_saradc_priv *priv)
+{
+ uint regval;
+ int ret, i;
+
+ priv->calibscale = MILLION;
+
+ /*
+ * make sure we start at CH7 input since the other muxes are only used
+ * for internal calibration.
+ */
+ meson_saradc_set_chan7_mux(priv, CHAN7_MUX_CH7_INPUT);
+
+ /*
+ * leave sampling delay and the input clocks as configured by
+ * BL30 to make sure BL30 gets the values it expects when
+ * reading the temperature sensor.
+ */
+ regmap_read(priv->regmap, MESON_SAR_ADC_REG3, &regval);
+ if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED)
+ return 0;
+
+ meson_saradc_stop_sample_engine(priv);
+
+ /* update the channel 6 MUX to select the temperature sensor */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
+ MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
+
+ /* disable all channels by default */
+ regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY,
+ MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
+
+ /* delay between two samples = (10+1) * 1uS */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK,
+ 10));
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
+ 0));
+
+ /* delay between two samples = (10+1) * 1uS */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+ 10));
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
+ 1));
+
+ /*
+ * set up the input channel muxes in MESON_SAR_ADC_CHAN_10_SW
+ * (0 = SAR_ADC_CH0, 1 = SAR_ADC_CH1)
+ */
+ regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK,
+ regval);
+ regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, 1);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK,
+ regval);
+
+ /*
+ * set up the input channel muxes in MESON_SAR_ADC_AUX_SW
+ * (2 = SAR_ADC_CH2, 3 = SAR_ADC_CH3, ...) and enable
+ * MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW and
+ * MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW like the vendor driver.
+ */
+ regval = 0;
+ for (i = 2; i <= 7; i++)
+ regval |= i << MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(i);
+ regval |= MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW;
+ regval |= MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW;
+ regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval);
+
+ ret = meson_saradc_lock(priv);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_enable(&priv->core_clk);
+ if (ret)
+ return ret;
+#endif
+
+ regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_BANDGAP_EN,
+ MESON_SAR_ADC_REG11_BANDGAP_EN);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN,
+ MESON_SAR_ADC_REG3_ADC_EN);
+
+ udelay(5);
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_enable(&priv->adc_clk);
+ if (ret)
+ return ret;
+#endif
+
+ meson_saradc_unlock(priv);
+
+ ret = meson_saradc_calib(priv);
+ if (ret) {
+ printf("calibration failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int meson_saradc_start_channel(struct udevice *dev, int channel)
+{
+ struct meson_saradc_priv *priv = dev_get_priv(dev);
+
+ if (channel < 0 || channel >= NUM_CHANNELS) {
+ printf("Requested channel is invalid!");
+ return -EINVAL;
+ }
+
+ if (!priv->initialized) {
+ int ret;
+
+ ret = meson_saradc_init(priv);
+ if (ret)
+ return ret;
+
+ priv->initialized = true;
+ }
+
+ priv->active_channel = channel;
+
+ return 0;
+}
+
+static int meson_saradc_stop(struct udevice *dev)
+{
+ struct meson_saradc_priv *priv = dev_get_priv(dev);
+
+ priv->active_channel = -1;
+
+ return 0;
+}
+
+static int meson_saradc_probe(struct udevice *dev)
+{
+ struct meson_saradc_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev, &priv->regmap);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_name(dev, "core", &priv->core_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_name(dev, "adc_clk", &priv->adc_clk);
+ if (ret)
+ return ret;
+#endif
+
+ priv->active_channel = -1;
+
+ return 0;
+}
+
+int meson_saradc_ofdata_to_platdata(struct udevice *dev)
+{
+ struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
+ struct meson_saradc_priv *priv = dev_get_priv(dev);
+
+ priv->data = (struct meson_saradc_data *)dev_get_driver_data(dev);
+
+ uc_pdata->data_mask = GENMASK(priv->data->num_bits - 1, 0);
+ uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
+ uc_pdata->data_timeout_us = MESON_SAR_ADC_TIMEOUT * 1000;
+ uc_pdata->channel_mask = GENMASK(NUM_CHANNELS - 1, 0);
+
+ return 0;
+}
+
+static const struct adc_ops meson_saradc_ops = {
+ .start_channel = meson_saradc_start_channel,
+ .channel_data = meson_saradc_channel_data,
+ .stop = meson_saradc_stop,
+};
+
+static const struct meson_saradc_data gxbb_saradc_data = {
+ .num_bits = 10,
+};
+
+static const struct meson_saradc_data gxl_saradc_data = {
+ .num_bits = 12,
+};
+
+static const struct udevice_id meson_saradc_ids[] = {
+ { .compatible = "amlogic,meson-gxbb-saradc",
+ .data = (ulong)&gxbb_saradc_data },
+ { .compatible = "amlogic,meson-gxl-saradc",
+ .data = (ulong)&gxl_saradc_data },
+ { .compatible = "amlogic,meson-gxm-saradc",
+ .data = (ulong)&gxl_saradc_data },
+ { }
+};
+
+U_BOOT_DRIVER(meson_saradc) = {
+ .name = "meson_saradc",
+ .id = UCLASS_ADC,
+ .of_match = meson_saradc_ids,
+ .ops = &meson_saradc_ops,
+ .probe = meson_saradc_probe,
+ .ofdata_to_platdata = meson_saradc_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct meson_saradc_priv),
+};
diff --git a/drivers/clk/clk_stm32f.c b/drivers/clk/clk_stm32f.c
index 6c1e2575ff..cbcfe3a89d 100644
--- a/drivers/clk/clk_stm32f.c
+++ b/drivers/clk/clk_stm32f.c
@@ -133,6 +133,7 @@ struct stm32_clk {
struct stm32_pwr_regs *pwr_regs;
struct stm32_clk_info info;
unsigned long hse_rate;
+ bool pllsaip;
};
#ifdef CONFIG_VIDEO_STM32
@@ -179,8 +180,12 @@ static int configure_clocks(struct udevice *dev)
/* configure SDMMC clock */
if (priv->info.v2) { /*stm32f7 case */
- /* select PLLQ as 48MHz clock source */
- clrbits_le32(&regs->dckcfgr2, RCC_DCKCFGRX_CK48MSEL);
+ if (priv->pllsaip)
+ /* select PLLSAIP as 48MHz clock source */
+ setbits_le32(&regs->dckcfgr2, RCC_DCKCFGRX_CK48MSEL);
+ else
+ /* select PLLQ as 48MHz clock source */
+ clrbits_le32(&regs->dckcfgr2, RCC_DCKCFGRX_CK48MSEL);
/* select 48MHz as SDMMC1 clock source */
clrbits_le32(&regs->dckcfgr2, RCC_DCKCFGRX_SDMMC1SEL);
@@ -188,17 +193,23 @@ static int configure_clocks(struct udevice *dev)
/* select 48MHz as SDMMC2 clock source */
clrbits_le32(&regs->dckcfgr2, RCC_DCKCFGR2_SDMMC2SEL);
} else { /* stm32f4 case */
- /* select PLLQ as 48MHz clock source */
- clrbits_le32(&regs->dckcfgr, RCC_DCKCFGRX_CK48MSEL);
+ if (priv->pllsaip)
+ /* select PLLSAIP as 48MHz clock source */
+ setbits_le32(&regs->dckcfgr, RCC_DCKCFGRX_CK48MSEL);
+ else
+ /* select PLLQ as 48MHz clock source */
+ clrbits_le32(&regs->dckcfgr, RCC_DCKCFGRX_CK48MSEL);
/* select 48MHz as SDMMC1 clock source */
clrbits_le32(&regs->dckcfgr, RCC_DCKCFGRX_SDMMC1SEL);
}
-#ifdef CONFIG_VIDEO_STM32
/*
- * Configure the SAI PLL to generate LTDC pixel clock
+ * Configure the SAI PLL to generate LTDC pixel clock and
+ * 48 Mhz for SDMMC and USB
*/
+ clrsetbits_le32(&regs->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIP_MASK,
+ RCC_PLLSAICFGR_PLLSAIP_4);
clrsetbits_le32(&regs->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIR_MASK,
RCC_PLLSAICFGR_PLLSAIR_3);
clrsetbits_le32(&regs->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIN_MASK,
@@ -206,18 +217,16 @@ static int configure_clocks(struct udevice *dev)
clrsetbits_le32(&regs->dckcfgr, RCC_DCKCFGR_PLLSAIDIVR_MASK,
RCC_DCKCFGR_PLLSAIDIVR_2 << RCC_DCKCFGR_PLLSAIDIVR_SHIFT);
-#endif
+
/* Enable the main PLL */
setbits_le32(&regs->cr, RCC_CR_PLLON);
while (!(readl(&regs->cr) & RCC_CR_PLLRDY))
;
-#ifdef CONFIG_VIDEO_STM32
-/* Enable the SAI PLL */
+ /* Enable the SAI PLL */
setbits_le32(&regs->cr, RCC_CR_PLLSAION);
while (!(readl(&regs->cr) & RCC_CR_PLLSAIRDY))
;
-#endif
setbits_le32(&regs->apb1enr, RCC_APB1ENR_PWREN);
if (priv->info.has_overdrive) {
@@ -617,12 +626,17 @@ static int stm32_clk_probe(struct udevice *dev)
return -EINVAL;
priv->base = (struct stm32_rcc_regs *)addr;
+ priv->pllsaip = true;
switch (dev_get_driver_data(dev)) {
- case STM32F4:
+ case STM32F42X:
+ priv->pllsaip = false;
+ /* fallback into STM32F469 case */
+ case STM32F469:
memcpy(&priv->info, &stm32f4_clk_info,
sizeof(struct stm32_clk_info));
break;
+
case STM32F7:
memcpy(&priv->info, &stm32f7_clk_info,
sizeof(struct stm32_clk_info));
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index ed32585eb0..1a77eba39c 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -100,6 +100,7 @@
#define RCC_USBCKSELR 0x91C
#define RCC_MP_APB1ENSETR 0xA00
#define RCC_MP_APB2ENSETR 0XA08
+#define RCC_MP_APB3ENSETR 0xA10
#define RCC_MP_AHB2ENSETR 0xA18
#define RCC_MP_AHB4ENSETR 0xA28
@@ -508,6 +509,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
+ STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3),
+
STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index fabcc5f53a..8e5c3bcf61 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -132,3 +132,17 @@ int regmap_write(struct regmap *map, uint offset, uint val)
return 0;
}
+
+int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
+{
+ uint reg;
+ int ret;
+
+ ret = regmap_read(map, offset, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~mask;
+
+ return regmap_write(map, offset, reg | val);
+}
diff --git a/drivers/gpio/atmel_pio4.c b/drivers/gpio/atmel_pio4.c
index 2385dec961..95a189a50f 100644
--- a/drivers/gpio/atmel_pio4.c
+++ b/drivers/gpio/atmel_pio4.c
@@ -43,7 +43,7 @@ static struct atmel_pio4_port *atmel_pio4_port_base(u32 port)
}
static int atmel_pio4_config_io_func(u32 port, u32 pin,
- u32 func, u32 use_pullup)
+ u32 func, u32 config)
{
struct atmel_pio4_port *port_base;
u32 reg, mask;
@@ -57,7 +57,7 @@ static int atmel_pio4_config_io_func(u32 port, u32 pin,
mask = 1 << pin;
reg = func;
- reg |= use_pullup ? ATMEL_PIO_PUEN_MASK : 0;
+ reg |= config;
writel(mask, &port_base->mskr);
writel(reg, &port_base->cfgr);
@@ -65,60 +65,60 @@ static int atmel_pio4_config_io_func(u32 port, u32 pin,
return 0;
}
-int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_gpio(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_GPIO,
- use_pullup);
+ config);
}
-int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_A,
- use_pullup);
+ config);
}
-int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_B,
- use_pullup);
+ config);
}
-int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_C,
- use_pullup);
+ config);
}
-int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_D,
- use_pullup);
+ config);
}
-int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_E,
- use_pullup);
+ config);
}
-int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_F,
- use_pullup);
+ config);
}
-int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup)
+int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_G,
- use_pullup);
+ config);
}
int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value)
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
index b26f7a730c..a36942b934 100644
--- a/drivers/led/led_gpio.c
+++ b/drivers/led/led_gpio.c
@@ -10,6 +10,7 @@
#include <led.h>
#include <asm/gpio.h>
#include <dm/lists.h>
+#include <dm/uclass-internal.h>
struct led_gpio_priv {
struct gpio_desc gpio;
@@ -57,11 +58,25 @@ static int led_gpio_probe(struct udevice *dev)
{
struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
struct led_gpio_priv *priv = dev_get_priv(dev);
+ const char *default_state;
+ int ret;
/* Ignore the top-level LED node */
if (!uc_plat->label)
return 0;
- return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
+
+ ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
+ if (ret)
+ return ret;
+
+ default_state = dev_read_string(dev, "default-state");
+ if (default_state) {
+ if (!strncmp(default_state, "on", 2))
+ gpio_led_set_state(dev, LEDST_ON);
+ else if (!strncmp(default_state, "off", 3))
+ gpio_led_set_state(dev, LEDST_OFF);
+ }
+ return 0;
}
static int led_gpio_remove(struct udevice *dev)
@@ -103,6 +118,14 @@ static int led_gpio_bind(struct udevice *parent)
return ret;
uc_plat = dev_get_uclass_platdata(dev);
uc_plat->label = label;
+
+ if (ofnode_read_bool(node, "default-state")) {
+ struct udevice *devp;
+
+ ret = uclass_get_device_tail(dev, 0, &devp);
+ if (ret)
+ return ret;
+ }
}
return 0;
diff --git a/drivers/misc/stm32_rcc.c b/drivers/misc/stm32_rcc.c
index b436900d7c..dee82c0b7b 100644
--- a/drivers/misc/stm32_rcc.c
+++ b/drivers/misc/stm32_rcc.c
@@ -11,9 +11,14 @@
#include <dm/device-internal.h>
#include <dm/lists.h>
-struct stm32_rcc_clk stm32_rcc_clk_f4 = {
+struct stm32_rcc_clk stm32_rcc_clk_f42x = {
.drv_name = "stm32fx_rcc_clock",
- .soc = STM32F4,
+ .soc = STM32F42X,
+};
+
+struct stm32_rcc_clk stm32_rcc_clk_f469 = {
+ .drv_name = "stm32fx_rcc_clock",
+ .soc = STM32F469,
};
struct stm32_rcc_clk stm32_rcc_clk_f7 = {
@@ -61,7 +66,8 @@ static const struct misc_ops stm32_rcc_ops = {
};
static const struct udevice_id stm32_rcc_ids[] = {
- {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f4 },
+ {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f42x },
+ {.compatible = "st,stm32f469-rcc", .data = (ulong)&stm32_rcc_clk_f469 },
{.compatible = "st,stm32f746-rcc", .data = (ulong)&stm32_rcc_clk_f7 },
{.compatible = "st,stm32h743-rcc", .data = (ulong)&stm32_rcc_clk_h7 },
{ }
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index c20a0cc060..f59803dbd6 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -105,4 +105,11 @@ config PCIE_LAYERSCAPE
PCIe controllers. The PCIe may works in RC or EP mode according to
RCW[HOST_AGT_PEX] setting.
+config PCIE_INTEL_FPGA
+ bool "Intel FPGA PCIe support"
+ depends on DM_PCI
+ help
+ Say Y here if you want to enable PCIe controller support on Intel
+ FPGA, example Stratix 10.
+
endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 72c09f4af8..4923641895 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -33,3 +33,4 @@ obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o
obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o
obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o
obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
+obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
diff --git a/drivers/pci/pcie_intel_fpga.c b/drivers/pci/pcie_intel_fpga.c
new file mode 100644
index 0000000000..3cdf05b314
--- /dev/null
+++ b/drivers/pci/pcie_intel_fpga.c
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel FPGA PCIe host controller driver
+ *
+ * Copyright (C) 2013-2018 Intel Corporation. All rights reserved
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/io.h>
+
+#define RP_TX_REG0 0x2000
+#define RP_TX_CNTRL 0x2004
+#define RP_TX_SOP BIT(0)
+#define RP_TX_EOP BIT(1)
+#define RP_RXCPL_STATUS 0x200C
+#define RP_RXCPL_SOP BIT(0)
+#define RP_RXCPL_EOP BIT(1)
+#define RP_RXCPL_REG 0x2008
+#define P2A_INT_STATUS 0x3060
+#define P2A_INT_STS_ALL 0xf
+#define P2A_INT_ENABLE 0x3070
+#define RP_CAP_OFFSET 0x70
+
+/* TLP configuration type 0 and 1 */
+#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */
+#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */
+#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */
+#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */
+#define TLP_PAYLOAD_SIZE 0x01
+#define TLP_READ_TAG 0x1d
+#define TLP_WRITE_TAG 0x10
+#define RP_DEVFN 0
+
+#define RP_CFG_ADDR(pcie, reg) \
+ ((pcie->hip_base) + (reg) + (1 << 20))
+#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn))
+
+#define TLP_CFGRD_DW0(pcie, bus) \
+ ((((bus != pcie->first_busno) ? TLP_FMTTYPE_CFGRD0 \
+ : TLP_FMTTYPE_CFGRD1) << 24) | \
+ TLP_PAYLOAD_SIZE)
+
+#define TLP_CFGWR_DW0(pcie, bus) \
+ ((((bus != pcie->first_busno) ? TLP_FMTTYPE_CFGWR0 \
+ : TLP_FMTTYPE_CFGWR1) << 24) | \
+ TLP_PAYLOAD_SIZE)
+
+#define TLP_CFG_DW1(pcie, tag, be) \
+ (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be))
+#define TLP_CFG_DW2(bus, dev, fn, offset) \
+ (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset))
+
+#define TLP_COMP_STATUS(s) (((s) >> 13) & 7)
+#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff)
+#define TLP_HDR_SIZE 3
+#define TLP_LOOP 500
+#define DWORD_MASK 3
+
+#define IS_ROOT_PORT(pcie, bdf) \
+ ((PCI_BUS(bdf) == pcie->first_busno) ? true : false)
+
+#define PCI_EXP_LNKSTA 18 /* Link Status */
+#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */
+
+/**
+ * struct intel_fpga_pcie - Intel FPGA PCIe controller state
+ * @bus: Pointer to the PCI bus
+ * @cra_base: The base address of CRA register space
+ * @hip_base: The base address of Rootport configuration space
+ * @first_busno: This driver supports multiple PCIe controllers.
+ * first_busno stores the bus number of the PCIe root-port
+ * number which may vary depending on the PCIe setup.
+ */
+struct intel_fpga_pcie {
+ struct udevice *bus;
+ void __iomem *cra_base;
+ void __iomem *hip_base;
+ int first_busno;
+};
+
+/**
+ * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the
+ * translation from PCI bus to native BUS. Entire DDR region is mapped
+ * into PCIe space using these registers, so it can be reached by DMA from
+ * EP devices.
+ * The BAR0 of bridge should be hidden during enumeration to avoid the
+ * sizing and resource allocation by PCIe core.
+ */
+static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf, int offset)
+{
+ if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 &&
+ PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0)
+ return true;
+
+ return false;
+}
+
+static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value,
+ const u32 reg)
+{
+ writel(value, pcie->cra_base + reg);
+}
+
+static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg)
+{
+ return readl(pcie->cra_base + reg);
+}
+
+static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie)
+{
+ return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA))
+ & PCI_EXP_LNKSTA_DLLLA);
+}
+
+static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf)
+{
+ /* If there is no link, then there is no device */
+ if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie))
+ return false;
+
+ /* access only one slot on each root port */
+ if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0)
+ return false;
+
+ if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0)
+ return false;
+
+ return true;
+}
+
+static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl)
+{
+ cra_writel(pcie, reg0, RP_TX_REG0);
+ cra_writel(pcie, ctrl, RP_TX_CNTRL);
+}
+
+static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value)
+{
+ int i;
+ u32 ctrl;
+ u32 comp_status;
+ u32 dw[4];
+ u32 count = 0;
+
+ for (i = 0; i < TLP_LOOP; i++) {
+ ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
+ if (!(ctrl & RP_RXCPL_SOP))
+ continue;
+
+ /* read first DW */
+ dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
+
+ /* Poll for EOP */
+ for (i = 0; i < TLP_LOOP; i++) {
+ ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
+ dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
+ if (ctrl & RP_RXCPL_EOP) {
+ comp_status = TLP_COMP_STATUS(dw[1]);
+ if (comp_status)
+ return -EFAULT;
+
+ if (value &&
+ TLP_BYTE_COUNT(dw[1]) == sizeof(u32) &&
+ count >= 3)
+ *value = dw[3];
+
+ return 0;
+ }
+ }
+
+ udelay(5);
+ }
+
+ dev_err(pcie->dev, "read TLP packet timed out\n");
+ return -ENODEV;
+}
+
+static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers,
+ u32 data)
+{
+ tlp_write_tx(pcie, headers[0], RP_TX_SOP);
+
+ tlp_write_tx(pcie, headers[1], 0);
+
+ tlp_write_tx(pcie, headers[2], 0);
+
+ tlp_write_tx(pcie, data, RP_TX_EOP);
+}
+
+static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
+ int offset, u8 byte_en, u32 *value)
+{
+ u32 headers[TLP_HDR_SIZE];
+ u8 busno = PCI_BUS(bdf);
+
+ headers[0] = TLP_CFGRD_DW0(pcie, busno);
+ headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en);
+ headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+
+ tlp_write_packet(pcie, headers, 0);
+
+ return tlp_read_packet(pcie, value);
+}
+
+static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
+ int offset, u8 byte_en, u32 value)
+{
+ u32 headers[TLP_HDR_SIZE];
+ u8 busno = PCI_BUS(bdf);
+
+ headers[0] = TLP_CFGWR_DW0(pcie, busno);
+ headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en);
+ headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+
+ tlp_write_packet(pcie, headers, value);
+
+ return tlp_read_packet(pcie, NULL);
+}
+
+int intel_fpga_rp_conf_addr(struct udevice *bus, pci_dev_t bdf,
+ uint offset, void **paddress)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ *paddress = RP_CFG_ADDR(pcie, offset);
+
+ return 0;
+}
+
+static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr,
+ bdf, offset, valuep, size);
+}
+
+static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ int ret;
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr,
+ bdf, offset, value, size);
+ if (!ret) {
+ /* Monitor changes to PCI_PRIMARY_BUS register on root port
+ * and update local copy of root bus number accordingly.
+ */
+ if (offset == PCI_PRIMARY_BUS)
+ pcie->first_busno = (u8)(value);
+ }
+
+ return ret;
+}
+
+static u8 pcie_get_byte_en(uint offset, enum pci_size_t size)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ return 1 << (offset & 3);
+ case PCI_SIZE_16:
+ return 3 << (offset & 3);
+ default:
+ return 0xf;
+ }
+}
+
+static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ int ret;
+ u32 data;
+ u8 byte_en;
+
+ /* Uses memory mapped method to read rootport config registers */
+ if (IS_ROOT_PORT(pcie, bdf))
+ return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf,
+ offset, valuep, size);
+
+ byte_en = pcie_get_byte_en(offset, size);
+ ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK,
+ byte_en, &data);
+ if (ret)
+ return ret;
+
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n",
+ offset, size, data);
+ *valuep = pci_conv_32_to_size(data, offset, size);
+
+ return 0;
+}
+
+static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ u32 data;
+ u8 byte_en;
+
+ dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n",
+ offset, size, value);
+
+ /* Uses memory mapped method to read rootport config registers */
+ if (IS_ROOT_PORT(pcie, bdf))
+ return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset,
+ value, size);
+
+ byte_en = pcie_get_byte_en(offset, size);
+ data = pci_conv_size_to_32(0, value, offset, size);
+
+ return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK,
+ byte_en, data);
+}
+
+static int pcie_intel_fpga_read_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) {
+ *valuep = (u32)pci_get_ff(size);
+ return 0;
+ }
+
+ if (!intel_fpga_pcie_addr_valid(pcie, bdf)) {
+ *valuep = (u32)pci_get_ff(size);
+ return 0;
+ }
+
+ return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size);
+}
+
+static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset))
+ return 0;
+
+ if (!intel_fpga_pcie_addr_valid(pcie, bdf))
+ return 0;
+
+ return _pcie_intel_fpga_write_config(pcie, bdf, offset, value,
+ size);
+}
+
+static int pcie_intel_fpga_probe(struct udevice *dev)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(dev);
+
+ pcie->bus = pci_get_controller(dev);
+ pcie->first_busno = dev->seq;
+
+ /* clear all interrupts */
+ cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
+ /* disable all interrupts */
+ cra_writel(pcie, 0, P2A_INT_ENABLE);
+
+ return 0;
+}
+
+static int pcie_intel_fpga_ofdata_to_platdata(struct udevice *dev)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(dev);
+ struct fdt_resource reg_res;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ DECLARE_GLOBAL_DATA_PTR;
+
+ ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
+ "Cra", &reg_res);
+ if (ret) {
+ dev_err(dev, "resource \"Cra\" not found\n");
+ return ret;
+ }
+
+ pcie->cra_base = map_physmem(reg_res.start,
+ fdt_resource_size(&reg_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
+ "Hip", &reg_res);
+ if (ret) {
+ dev_err(dev, "resource \"Hip\" not found\n");
+ return ret;
+ }
+
+ pcie->hip_base = map_physmem(reg_res.start,
+ fdt_resource_size(&reg_res),
+ MAP_NOCACHE);
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_intel_fpga_ops = {
+ .read_config = pcie_intel_fpga_read_config,
+ .write_config = pcie_intel_fpga_write_config,
+};
+
+static const struct udevice_id pcie_intel_fpga_ids[] = {
+ { .compatible = "altr,pcie-root-port-2.0" },
+ {},
+};
+
+U_BOOT_DRIVER(pcie_intel_fpga) = {
+ .name = "pcie_intel_fpga",
+ .id = UCLASS_PCI,
+ .of_match = pcie_intel_fpga_ids,
+ .ops = &pcie_intel_fpga_ops,
+ .ofdata_to_platdata = pcie_intel_fpga_ofdata_to_platdata,
+ .probe = pcie_intel_fpga_probe,
+ .priv_auto_alloc_size = sizeof(struct intel_fpga_pcie),
+};
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 6e94d3bc28..a8e47e3c4e 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -13,7 +13,7 @@
#include "pinctrl-meson.h"
-#define EE_OFF 14
+#define EE_OFF 15
static const unsigned int emmc_nand_d07_pins[] = {
PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF),
@@ -318,8 +318,6 @@ static const char * const gpio_periphs_groups[] = {
"GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
"GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19",
"GPIOX_20", "GPIOX_21", "GPIOX_22",
-
- "GPIO_TEST_N",
};
static const char * const emmc_groups[] = {
@@ -354,6 +352,8 @@ static const char * const gpio_aobus_groups[] = {
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
"GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
"GPIOAO_10", "GPIOAO_11", "GPIOAO_12", "GPIOAO_13",
+
+ "GPIO_TEST_N",
};
static const char * const uart_ao_groups[] = {
@@ -409,11 +409,11 @@ static struct meson_bank meson_gxbb_aobus_banks[] = {
struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
.name = "periphs-banks",
- .pin_base = 14,
+ .pin_base = 15,
.groups = meson_gxbb_periphs_groups,
.funcs = meson_gxbb_periphs_functions,
.banks = meson_gxbb_periphs_banks,
- .num_pins = 120,
+ .num_pins = 119,
.num_groups = ARRAY_SIZE(meson_gxbb_periphs_groups),
.num_funcs = ARRAY_SIZE(meson_gxbb_periphs_functions),
.num_banks = ARRAY_SIZE(meson_gxbb_periphs_banks),
@@ -425,7 +425,7 @@ struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = {
.groups = meson_gxbb_aobus_groups,
.funcs = meson_gxbb_aobus_functions,
.banks = meson_gxbb_aobus_banks,
- .num_pins = 14,
+ .num_pins = 15,
.num_groups = ARRAY_SIZE(meson_gxbb_aobus_groups),
.num_funcs = ARRAY_SIZE(meson_gxbb_aobus_functions),
.num_banks = ARRAY_SIZE(meson_gxbb_aobus_banks),
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index fd60bc611d..ba6e3531d9 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -13,7 +13,7 @@
#include "pinctrl-meson.h"
-#define EE_OFF 10
+#define EE_OFF 11
static const unsigned int emmc_nand_d07_pins[] = {
PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF),
@@ -289,7 +289,7 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = {
GPIO_GROUP(GPIOCLK_0, EE_OFF),
GPIO_GROUP(GPIOCLK_1, EE_OFF),
- GPIO_GROUP(GPIO_TEST_N, EE_OFF),
+ GPIO_GROUP(GPIO_TEST_N, 0),
/* Bank X */
GROUP(sdio_d0, 5, 31),
@@ -471,8 +471,6 @@ static const char * const gpio_periphs_groups[] = {
"GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
"GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
"GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18",
-
- "GPIO_TEST_N",
};
static const char * const emmc_groups[] = {
@@ -587,6 +585,8 @@ static const char * const tsin_a_groups[] = {
static const char * const gpio_aobus_groups[] = {
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
"GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
+
+ "GPIO_TEST_N",
};
static const char * const uart_ao_groups[] = {
@@ -691,11 +691,11 @@ static struct meson_bank meson_gxl_aobus_banks[] = {
struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data = {
.name = "periphs-banks",
- .pin_base = 10,
+ .pin_base = 11,
.groups = meson_gxl_periphs_groups,
.funcs = meson_gxl_periphs_functions,
.banks = meson_gxl_periphs_banks,
- .num_pins = 101,
+ .num_pins = 100,
.num_groups = ARRAY_SIZE(meson_gxl_periphs_groups),
.num_funcs = ARRAY_SIZE(meson_gxl_periphs_functions),
.num_banks = ARRAY_SIZE(meson_gxl_periphs_banks),
@@ -707,7 +707,7 @@ struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data = {
.groups = meson_gxl_aobus_groups,
.funcs = meson_gxl_aobus_functions,
.banks = meson_gxl_aobus_banks,
- .num_pins = 10,
+ .num_pins = 11,
.num_groups = ARRAY_SIZE(meson_gxl_aobus_groups),
.num_funcs = ARRAY_SIZE(meson_gxl_aobus_functions),
.num_banks = ARRAY_SIZE(meson_gxl_aobus_banks),
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
index 7b427d06ec..a5935e84de 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
@@ -16,11 +16,42 @@
#define UNIPHIER_PINCTRL_PINMUX_BASE 0x1000
#define UNIPHIER_PINCTRL_LOAD_PINMUX 0x1700
+#define UNIPHIER_PINCTRL_DRVCTRL_BASE 0x1800
+#define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x1900
+#define UNIPHIER_PINCTRL_DRV3CTRL_BASE 0x1980
#define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0x1a00
#define UNIPHIER_PINCTRL_IECTRL 0x1d00
static const char *uniphier_pinctrl_dummy_name = "_dummy";
+static int uniphier_pinctrl_get_pins_count(struct udevice *dev)
+{
+ struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
+ int pins_count = priv->socdata->pins_count;
+
+ /*
+ * We do not list all pins in the pin table to save memory footprint.
+ * Report the max pin number + 1 to fake the framework.
+ */
+ return pins[pins_count - 1].number + 1;
+}
+
+static const char *uniphier_pinctrl_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
+ int pins_count = priv->socdata->pins_count;
+ int i;
+
+ for (i = 0; i < pins_count; i++)
+ if (pins[i].number == selector)
+ return pins[i].name;
+
+ return uniphier_pinctrl_dummy_name;
+}
+
static int uniphier_pinctrl_get_groups_count(struct udevice *dev)
{
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
@@ -113,10 +144,25 @@ static const struct pinconf_param uniphier_pinconf_params[] = {
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
};
+static const struct uniphier_pinctrl_pin *
+uniphier_pinctrl_pin_get(struct uniphier_pinctrl_priv *priv, unsigned int pin)
+{
+ const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
+ int pins_count = priv->socdata->pins_count;
+ int i;
+
+ for (i = 0; i < pins_count; i++)
+ if (pins[i].number == pin)
+ return &pins[i];
+
+ return NULL;
+}
+
static int uniphier_pinconf_bias_set(struct udevice *dev, unsigned int pin,
unsigned int param, unsigned int arg)
{
@@ -157,8 +203,88 @@ static int uniphier_pinconf_bias_set(struct udevice *dev, unsigned int pin,
return 0;
}
-static int uniphier_pinconf_set_one(struct udevice *dev, unsigned int pin,
- unsigned int param, unsigned int arg)
+static const unsigned int uniphier_pinconf_drv_strengths_1bit[] = {
+ 4, 8,
+};
+
+static const unsigned int uniphier_pinconf_drv_strengths_2bit[] = {
+ 8, 12, 16, 20,
+};
+
+static const unsigned int uniphier_pinconf_drv_strengths_3bit[] = {
+ 4, 5, 7, 9, 11, 12, 14, 16,
+};
+
+static int uniphier_pinconf_drive_set(struct udevice *dev, unsigned int pin,
+ unsigned int strength)
+{
+ struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct uniphier_pinctrl_pin *desc;
+ const unsigned int *strengths;
+ unsigned int base, stride, width, drvctrl, reg, shift;
+ u32 val, mask, tmp;
+
+ desc = uniphier_pinctrl_pin_get(priv, pin);
+ if (WARN_ON(!desc))
+ return -EINVAL;
+
+ switch (uniphier_pin_get_drv_type(desc->data)) {
+ case UNIPHIER_PIN_DRV_1BIT:
+ strengths = uniphier_pinconf_drv_strengths_1bit;
+ base = UNIPHIER_PINCTRL_DRVCTRL_BASE;
+ stride = 1;
+ width = 1;
+ break;
+ case UNIPHIER_PIN_DRV_2BIT:
+ strengths = uniphier_pinconf_drv_strengths_2bit;
+ base = UNIPHIER_PINCTRL_DRV2CTRL_BASE;
+ stride = 2;
+ width = 2;
+ break;
+ case UNIPHIER_PIN_DRV_3BIT:
+ strengths = uniphier_pinconf_drv_strengths_3bit;
+ base = UNIPHIER_PINCTRL_DRV3CTRL_BASE;
+ stride = 4;
+ width = 3;
+ break;
+ default:
+ /* drive strength control is not supported for this pin */
+ return -EINVAL;
+ }
+
+ drvctrl = uniphier_pin_get_drvctrl(desc->data);
+ drvctrl *= stride;
+
+ reg = base + drvctrl / 32 * 4;
+ shift = drvctrl % 32;
+ mask = (1U << width) - 1;
+
+ for (val = 0; val <= mask; val++) {
+ if (strengths[val] > strength)
+ break;
+ }
+
+ if (val == 0) {
+ dev_err(dev, "unsupported drive strength %u mA for pin %s\n",
+ strength, desc->name);
+ return -EINVAL;
+ }
+
+ if (!mask)
+ return 0;
+
+ val--;
+
+ tmp = readl(priv->base + reg);
+ tmp &= ~(mask << shift);
+ tmp |= (mask & val) << shift;
+ writel(tmp, priv->base + reg);
+
+ return 0;
+}
+
+static int uniphier_pinconf_set(struct udevice *dev, unsigned int pin,
+ unsigned int param, unsigned int arg)
{
int ret;
@@ -169,11 +295,14 @@ static int uniphier_pinconf_set_one(struct udevice *dev, unsigned int pin,
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
ret = uniphier_pinconf_bias_set(dev, pin, param, arg);
break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ret = uniphier_pinconf_drive_set(dev, pin, arg);
+ break;
case PIN_CONFIG_INPUT_ENABLE:
ret = uniphier_pinconf_input_enable(dev, pin, arg);
break;
default:
- printf("unsupported configuration parameter %u\n", param);
+ dev_err(dev, "unsupported configuration parameter %u\n", param);
return -EINVAL;
}
@@ -190,7 +319,7 @@ static int uniphier_pinconf_group_set(struct udevice *dev,
int i, ret;
for (i = 0; i < grp->num_pins; i++) {
- ret = uniphier_pinconf_set_one(dev, grp->pins[i], param, arg);
+ ret = uniphier_pinconf_set(dev, grp->pins[i], param, arg);
if (ret)
return ret;
}
@@ -268,6 +397,8 @@ static int uniphier_pinmux_group_set(struct udevice *dev,
}
const struct pinctrl_ops uniphier_pinctrl_ops = {
+ .get_pins_count = uniphier_pinctrl_get_pins_count,
+ .get_pin_name = uniphier_pinctrl_get_pin_name,
.get_groups_count = uniphier_pinctrl_get_groups_count,
.get_group_name = uniphier_pinctrl_get_group_name,
.get_functions_count = uniphier_pinmux_get_functions_count,
@@ -276,6 +407,7 @@ const struct pinctrl_ops uniphier_pinctrl_ops = {
#if CONFIG_IS_ENABLED(PINCONF)
.pinconf_num_params = ARRAY_SIZE(uniphier_pinconf_params),
.pinconf_params = uniphier_pinconf_params,
+ .pinconf_set = uniphier_pinconf_set,
.pinconf_group_set = uniphier_pinconf_group_set,
#endif
.set_state = pinctrl_generic_set_state,
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
index ecf4355000..8ec87f285e 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
@@ -10,6 +10,15 @@
#include "pinctrl-uniphier.h"
+static const struct uniphier_pinctrl_pin uniphier_ld20_pins[] = {
+ UNIPHIER_PINCTRL_PIN(40, "RGMII_TXCLK", 28, UNIPHIER_PIN_DRV_3BIT),
+ UNIPHIER_PINCTRL_PIN(41, "RGMII_TXD0", 29, UNIPHIER_PIN_DRV_3BIT),
+ UNIPHIER_PINCTRL_PIN(42, "RGMII_TXD1", 30, UNIPHIER_PIN_DRV_3BIT),
+ UNIPHIER_PINCTRL_PIN(43, "RGMII_TXD2", 31, UNIPHIER_PIN_DRV_3BIT),
+ UNIPHIER_PINCTRL_PIN(44, "RGMII_TXD3", 32, UNIPHIER_PIN_DRV_3BIT),
+ UNIPHIER_PINCTRL_PIN(45, "RGMII_TXCTL", 33, UNIPHIER_PIN_DRV_3BIT),
+};
+
static const unsigned emmc_pins[] = {18, 19, 20, 21, 22, 23, 24, 25};
static const int emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0};
static const unsigned emmc_dat8_pins[] = {26, 27, 28, 29};
@@ -102,6 +111,8 @@ static const char * const uniphier_ld20_functions[] = {
};
static struct uniphier_pinctrl_socdata uniphier_ld20_pinctrl_socdata = {
+ .pins = uniphier_ld20_pins,
+ .pins_count = ARRAY_SIZE(uniphier_ld20_pins),
.groups = uniphier_ld20_groups,
.groups_count = ARRAY_SIZE(uniphier_ld20_groups),
.functions = uniphier_ld20_functions,
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c
index b9076678b2..30d411694c 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c
@@ -10,17 +10,6 @@
#include "pinctrl-uniphier.h"
-static const struct uniphier_pinctrl_pin uniphier_ld6b_pins[] = {
- UNIPHIER_PINCTRL_PIN(113, 0),
- UNIPHIER_PINCTRL_PIN(114, 0),
- UNIPHIER_PINCTRL_PIN(115, 0),
- UNIPHIER_PINCTRL_PIN(116, 0),
- UNIPHIER_PINCTRL_PIN(217, 0),
- UNIPHIER_PINCTRL_PIN(218, 0),
- UNIPHIER_PINCTRL_PIN(219, 0),
- UNIPHIER_PINCTRL_PIN(220, 0),
-};
-
static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42};
static const int emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1};
static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46};
@@ -134,8 +123,6 @@ static const char * const uniphier_ld6b_functions[] = {
};
static struct uniphier_pinctrl_socdata uniphier_ld6b_pinctrl_socdata = {
- .pins = uniphier_ld6b_pins,
- .pins_count = ARRAY_SIZE(uniphier_ld6b_pins),
.groups = uniphier_ld6b_groups,
.groups_count = ARRAY_SIZE(uniphier_ld6b_groups),
.functions = uniphier_ld6b_functions,
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h
index 6557f6a6c7..8f83ecae7d 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier.h
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h
@@ -8,15 +8,48 @@
#define __PINCTRL_UNIPHIER_H__
#include <linux/bitops.h>
-#include <linux/bug.h>
+#include <linux/build_bug.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#define UNIPHIER_PIN_ATTR_PACKED(iectrl) (iectrl)
+/* drive strength control register number */
+#define UNIPHIER_PIN_DRVCTRL_SHIFT 0
+#define UNIPHIER_PIN_DRVCTRL_BITS 9
+#define UNIPHIER_PIN_DRVCTRL_MASK ((1U << (UNIPHIER_PIN_DRVCTRL_BITS)) \
+ - 1)
+
+/* drive control type */
+#define UNIPHIER_PIN_DRV_TYPE_SHIFT ((UNIPHIER_PIN_DRVCTRL_SHIFT) + \
+ (UNIPHIER_PIN_DRVCTRL_BITS))
+#define UNIPHIER_PIN_DRV_TYPE_BITS 2
+#define UNIPHIER_PIN_DRV_TYPE_MASK ((1U << (UNIPHIER_PIN_DRV_TYPE_BITS)) \
+ - 1)
+
+/* drive control type */
+enum uniphier_pin_drv_type {
+ UNIPHIER_PIN_DRV_1BIT, /* 2 level control: 4/8 mA */
+ UNIPHIER_PIN_DRV_2BIT, /* 4 level control: 8/12/16/20 mA */
+ UNIPHIER_PIN_DRV_3BIT, /* 8 level control: 4/5/7/9/11/12/14/16 mA */
+};
+
+#define UNIPHIER_PIN_DRVCTRL(x) \
+ (((x) & (UNIPHIER_PIN_DRVCTRL_MASK)) << (UNIPHIER_PIN_DRVCTRL_SHIFT))
+#define UNIPHIER_PIN_DRV_TYPE(x) \
+ (((x) & (UNIPHIER_PIN_DRV_TYPE_MASK)) << (UNIPHIER_PIN_DRV_TYPE_SHIFT))
-static inline unsigned int uniphier_pin_get_iectrl(unsigned long data)
+#define UNIPHIER_PIN_ATTR_PACKED(drvctrl, drv_type) \
+ UNIPHIER_PIN_DRVCTRL(drvctrl) | \
+ UNIPHIER_PIN_DRV_TYPE(drv_type)
+
+static inline unsigned int uniphier_pin_get_drvctrl(unsigned int data)
{
- return data;
+ return (data >> UNIPHIER_PIN_DRVCTRL_SHIFT) & UNIPHIER_PIN_DRVCTRL_MASK;
+}
+
+static inline unsigned int uniphier_pin_get_drv_type(unsigned int data)
+{
+ return (data >> UNIPHIER_PIN_DRV_TYPE_SHIFT) &
+ UNIPHIER_PIN_DRV_TYPE_MASK;
}
/**
@@ -27,7 +60,8 @@ static inline unsigned int uniphier_pin_get_iectrl(unsigned long data)
*/
struct uniphier_pinctrl_pin {
unsigned number;
- unsigned long data;
+ const char *name;
+ unsigned int data;
};
/**
@@ -72,10 +106,11 @@ struct uniphier_pinctrl_socdata {
#define UNIPHIER_PINCTRL_CAPS_MUX_4BIT BIT(0)
};
-#define UNIPHIER_PINCTRL_PIN(a, b) \
+#define UNIPHIER_PINCTRL_PIN(a, b, c, d) \
{ \
.number = a, \
- .data = UNIPHIER_PIN_ATTR_PACKED(b), \
+ .name = b, \
+ .data = UNIPHIER_PIN_ATTR_PACKED(c, d), \
}
#define __UNIPHIER_PINCTRL_GROUP(grp) \
diff --git a/drivers/power/pmic/stpmu1.c b/drivers/power/pmic/stpmu1.c
index a765c4f2e9..82351b6613 100644
--- a/drivers/power/pmic/stpmu1.c
+++ b/drivers/power/pmic/stpmu1.c
@@ -12,6 +12,17 @@
#define STMPU1_NUM_OF_REGS 0x100
+#ifndef CONFIG_SPL_BUILD
+static const struct pmic_child_info stpmu1_children_info[] = {
+ { .prefix = "ldo", .driver = "stpmu1_ldo" },
+ { .prefix = "buck", .driver = "stpmu1_buck" },
+ { .prefix = "vref_ddr", .driver = "stpmu1_vref_ddr" },
+ { .prefix = "pwr_sw", .driver = "stpmu1_pwr_sw" },
+ { .prefix = "boost", .driver = "stpmu1_boost" },
+ { },
+};
+#endif /* CONFIG_SPL_BUILD */
+
static int stpmu1_reg_count(struct udevice *dev)
{
return STMPU1_NUM_OF_REGS;
@@ -42,6 +53,28 @@ static int stpmu1_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
return ret;
}
+static int stpmu1_bind(struct udevice *dev)
+{
+#ifndef CONFIG_SPL_BUILD
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ dev_dbg(dev, "regulators subnode not found!");
+ return -ENXIO;
+ }
+ dev_dbg(dev, "found regulators subnode\n");
+
+ children = pmic_bind_children(dev, regulators_node,
+ stpmu1_children_info);
+ if (!children)
+ dev_dbg(dev, "no child found\n");
+#endif /* CONFIG_SPL_BUILD */
+
+ return 0;
+}
+
static struct dm_pmic_ops stpmu1_ops = {
.reg_count = stpmu1_reg_count,
.read = stpmu1_read,
@@ -57,5 +90,6 @@ U_BOOT_DRIVER(pmic_stpmu1) = {
.name = "stpmu1_pmic",
.id = UCLASS_PMIC,
.of_match = stpmu1_ids,
+ .bind = stpmu1_bind,
.ops = &stpmu1_ops,
};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 5b4ac10462..414f4a53f7 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -197,6 +197,15 @@ config DM_REGULATOR_LP87565
be configured in multi phase modes. The driver implements
get/set api for value and enable.
+config DM_REGULATOR_STM32_VREFBUF
+ bool "Enable driver for STMicroelectronics STM32 VREFBUF"
+ depends on DM_REGULATOR && (STM32H7 || ARCH_STM32MP)
+ help
+ This driver supports STMicroelectronics STM32 VREFBUF (voltage
+ reference buffer) which can be used as voltage reference for
+ internal ADCs, DACs and also for external components through
+ dedicated Vref+ pin.
+
config DM_REGULATOR_TPS65910
bool "Enable driver for TPS65910 PMIC regulators"
depends on DM_PMIC_TPS65910
@@ -204,3 +213,12 @@ config DM_REGULATOR_TPS65910
The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver supports all
regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements
the get/set api for value and enable.
+
+config DM_REGULATOR_STPMU1
+ bool "Enable driver for STPMU1 regulators"
+ depends on DM_REGULATOR && PMIC_STPMU1
+ ---help---
+ Enable support for the regulator functions of the STPMU1 PMIC. The
+ driver implements get/set api for the various BUCKS and LDOs supported
+ by the PMIC device. This driver is controlled by a device tree node
+ which includes voltage limits.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index f7873ad27a..16208af069 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -22,4 +22,6 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMU1) += stpmu1.o
diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c
new file mode 100644
index 0000000000..0ad6833ed0
--- /dev/null
+++ b/drivers/power/regulator/stm32-vrefbuf.c
@@ -0,0 +1,155 @@
+// 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.16 drivers/regulator/stm32-vrefbuf.c
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <power/regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR 0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS GENMASK(6, 4)
+#define STM32_VRS_SHIFT 4
+#define STM32_VRR BIT(3)
+#define STM32_HIZ BIT(1)
+#define STM32_ENVR BIT(0)
+
+struct stm32_vrefbuf {
+ void __iomem *base;
+ struct clk clk;
+ struct udevice *vdda_supply;
+};
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+ /* Matches resp. VRS = 000b, 001b, 010b, 011b */
+ 2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_set_enable(struct udevice *dev, bool enable)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ u32 val;
+ int ret;
+
+ clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_HIZ | STM32_ENVR,
+ enable ? STM32_ENVR : STM32_HIZ);
+ if (!enable)
+ return 0;
+
+ /*
+ * Vrefbuf startup time depends on external capacitor: wait here for
+ * VRR to be set. That means output has reached expected value.
+ * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+ * arbitrary timeout.
+ */
+ ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+ val & STM32_VRR, 10000);
+ if (ret < 0) {
+ dev_err(dev, "stm32 vrefbuf timed out: %d\n", ret);
+ clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_ENVR,
+ STM32_HIZ);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_vrefbuf_get_enable(struct udevice *dev)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+
+ return readl(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_value(struct udevice *dev, int uV)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(stm32_vrefbuf_voltages); i++) {
+ if (uV == stm32_vrefbuf_voltages[i]) {
+ clrsetbits_le32(priv->base + STM32_VREFBUF_CSR,
+ STM32_VRS, i << STM32_VRS_SHIFT);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int stm32_vrefbuf_get_value(struct udevice *dev)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ u32 val;
+
+ val = readl(priv->base + STM32_VREFBUF_CSR) & STM32_VRS;
+ val >>= STM32_VRS_SHIFT;
+
+ return stm32_vrefbuf_voltages[val];
+}
+
+static const struct dm_regulator_ops stm32_vrefbuf_ops = {
+ .get_value = stm32_vrefbuf_get_value,
+ .set_value = stm32_vrefbuf_set_value,
+ .get_enable = stm32_vrefbuf_get_enable,
+ .set_enable = stm32_vrefbuf_set_enable,
+};
+
+static int stm32_vrefbuf_probe(struct udevice *dev)
+{
+ struct stm32_vrefbuf *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret) {
+ dev_err(dev, "Can't get clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&priv->clk);
+ if (ret) {
+ dev_err(dev, "Can't enable clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vdda-supply",
+ &priv->vdda_supply);
+ if (ret) {
+ dev_dbg(dev, "No vdda-supply: %d\n", ret);
+ return 0;
+ }
+
+ ret = regulator_set_enable(priv->vdda_supply, true);
+ if (ret) {
+ dev_err(dev, "Can't enable vdda-supply: %d\n", ret);
+ clk_disable(&priv->clk);
+ }
+
+ return ret;
+}
+
+static const struct udevice_id stm32_vrefbuf_ids[] = {
+ { .compatible = "st,stm32-vrefbuf" },
+ { }
+};
+
+U_BOOT_DRIVER(stm32_vrefbuf) = {
+ .name = "stm32-vrefbuf",
+ .id = UCLASS_REGULATOR,
+ .of_match = stm32_vrefbuf_ids,
+ .probe = stm32_vrefbuf_probe,
+ .ops = &stm32_vrefbuf_ops,
+ .priv_auto_alloc_size = sizeof(struct stm32_vrefbuf),
+};
diff --git a/drivers/power/regulator/stpmu1.c b/drivers/power/regulator/stpmu1.c
new file mode 100644
index 0000000000..2dedb80acc
--- /dev/null
+++ b/drivers/power/regulator/stpmu1.c
@@ -0,0 +1,667 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author: Christophe Kerello <christophe.kerello@st.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/stpmu1.h>
+
+struct stpmu1_range {
+ int min_uv;
+ int min_sel;
+ int max_sel;
+ int step;
+};
+
+struct stpmu1_output_range {
+ const struct stpmu1_range *ranges;
+ int nbranges;
+};
+
+#define STPMU1_MODE(_id, _val, _name) { \
+ .id = _id, \
+ .register_value = _val, \
+ .name = _name, \
+}
+
+#define STPMU1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \
+ .min_uv = _min_uv, \
+ .min_sel = _min_sel, \
+ .max_sel = _max_sel, \
+ .step = _step, \
+}
+
+#define STPMU1_OUTPUT_RANGE(_ranges, _nbranges) { \
+ .ranges = _ranges, \
+ .nbranges = _nbranges, \
+}
+
+static int stpmu1_output_find_uv(int sel,
+ const struct stpmu1_output_range *output_range)
+{
+ const struct stpmu1_range *range;
+ int i;
+
+ for (i = 0, range = output_range->ranges;
+ i < output_range->nbranges; i++, range++) {
+ if (sel >= range->min_sel && sel <= range->max_sel)
+ return range->min_uv +
+ (sel - range->min_sel) * range->step;
+ }
+
+ return -EINVAL;
+}
+
+static int stpmu1_output_find_sel(int uv,
+ const struct stpmu1_output_range *output_range)
+{
+ const struct stpmu1_range *range;
+ int i;
+
+ for (i = 0, range = output_range->ranges;
+ i < output_range->nbranges; i++, range++) {
+ if (uv == range->min_uv && !range->step)
+ return range->min_sel;
+
+ if (uv >= range->min_uv &&
+ uv <= range->min_uv +
+ (range->max_sel - range->min_sel) * range->step)
+ return range->min_sel +
+ (uv - range->min_uv) / range->step;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * BUCK regulators
+ */
+
+static const struct stpmu1_range buck1_ranges[] = {
+ STPMU1_RANGE(600000, 0, 30, 25000),
+ STPMU1_RANGE(1350000, 31, 63, 0),
+};
+
+static const struct stpmu1_range buck2_ranges[] = {
+ STPMU1_RANGE(1000000, 0, 17, 0),
+ STPMU1_RANGE(1050000, 18, 19, 0),
+ STPMU1_RANGE(1100000, 20, 21, 0),
+ STPMU1_RANGE(1150000, 22, 23, 0),
+ STPMU1_RANGE(1200000, 24, 25, 0),
+ STPMU1_RANGE(1250000, 26, 27, 0),
+ STPMU1_RANGE(1300000, 28, 29, 0),
+ STPMU1_RANGE(1350000, 30, 31, 0),
+ STPMU1_RANGE(1400000, 32, 33, 0),
+ STPMU1_RANGE(1450000, 34, 35, 0),
+ STPMU1_RANGE(1500000, 36, 63, 0),
+};
+
+static const struct stpmu1_range buck3_ranges[] = {
+ STPMU1_RANGE(1000000, 0, 19, 0),
+ STPMU1_RANGE(1100000, 20, 23, 0),
+ STPMU1_RANGE(1200000, 24, 27, 0),
+ STPMU1_RANGE(1300000, 28, 31, 0),
+ STPMU1_RANGE(1400000, 32, 35, 0),
+ STPMU1_RANGE(1500000, 36, 55, 100000),
+ STPMU1_RANGE(3400000, 56, 63, 0),
+};
+
+static const struct stpmu1_range buck4_ranges[] = {
+ STPMU1_RANGE(600000, 0, 27, 25000),
+ STPMU1_RANGE(1300000, 28, 29, 0),
+ STPMU1_RANGE(1350000, 30, 31, 0),
+ STPMU1_RANGE(1400000, 32, 33, 0),
+ STPMU1_RANGE(1450000, 34, 35, 0),
+ STPMU1_RANGE(1500000, 36, 60, 100000),
+ STPMU1_RANGE(3900000, 61, 63, 0),
+};
+
+/* BUCK: 1,2,3,4 - voltage ranges */
+static const struct stpmu1_output_range buck_voltage_range[] = {
+ STPMU1_OUTPUT_RANGE(buck1_ranges, ARRAY_SIZE(buck1_ranges)),
+ STPMU1_OUTPUT_RANGE(buck2_ranges, ARRAY_SIZE(buck2_ranges)),
+ STPMU1_OUTPUT_RANGE(buck3_ranges, ARRAY_SIZE(buck3_ranges)),
+ STPMU1_OUTPUT_RANGE(buck4_ranges, ARRAY_SIZE(buck4_ranges)),
+};
+
+/* BUCK modes */
+static const struct dm_regulator_mode buck_modes[] = {
+ STPMU1_MODE(STPMU1_BUCK_MODE_HP, STPMU1_BUCK_MODE_HP, "HP"),
+ STPMU1_MODE(STPMU1_BUCK_MODE_LP, STPMU1_BUCK_MODE_LP, "LP"),
+};
+
+static int stpmu1_buck_get_uv(struct udevice *dev, int buck)
+{
+ int sel;
+
+ sel = pmic_reg_read(dev, STPMU1_BUCKX_CTRL_REG(buck));
+ if (sel < 0)
+ return sel;
+
+ sel &= STPMU1_BUCK_OUTPUT_MASK;
+ sel >>= STPMU1_BUCK_OUTPUT_SHIFT;
+
+ return stpmu1_output_find_uv(sel, &buck_voltage_range[buck]);
+}
+
+static int stpmu1_buck_get_value(struct udevice *dev)
+{
+ return stpmu1_buck_get_uv(dev->parent, dev->driver_data - 1);
+}
+
+static int stpmu1_buck_set_value(struct udevice *dev, int uv)
+{
+ int sel, buck = dev->driver_data - 1;
+
+ sel = stpmu1_output_find_sel(uv, &buck_voltage_range[buck]);
+ if (sel < 0)
+ return sel;
+
+ return pmic_clrsetbits(dev->parent,
+ STPMU1_BUCKX_CTRL_REG(buck),
+ STPMU1_BUCK_OUTPUT_MASK,
+ sel << STPMU1_BUCK_OUTPUT_SHIFT);
+}
+
+static int stpmu1_buck_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent,
+ STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1));
+ if (ret < 0)
+ return false;
+
+ return ret & STPMU1_BUCK_EN ? true : false;
+}
+
+static int stpmu1_buck_set_enable(struct udevice *dev, bool enable)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ int ret, uv;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (stpmu1_buck_get_enable(dev) == enable)
+ return 0;
+
+ if (enable) {
+ uc_pdata = dev_get_uclass_platdata(dev);
+ uv = stpmu1_buck_get_value(dev);
+ if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV))
+ stpmu1_buck_set_value(dev, uc_pdata->min_uV);
+ }
+
+ ret = pmic_clrsetbits(dev->parent,
+ STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1),
+ STPMU1_BUCK_EN, enable ? STPMU1_BUCK_EN : 0);
+ if (enable)
+ mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+ return ret;
+}
+
+static int stpmu1_buck_get_mode(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent,
+ STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1));
+ if (ret < 0)
+ return ret;
+
+ return ret & STPMU1_BUCK_MODE ? STPMU1_BUCK_MODE_LP :
+ STPMU1_BUCK_MODE_HP;
+}
+
+static int stpmu1_buck_set_mode(struct udevice *dev, int mode)
+{
+ return pmic_clrsetbits(dev->parent,
+ STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1),
+ STPMU1_BUCK_MODE,
+ mode ? STPMU1_BUCK_MODE : 0);
+}
+
+static int stpmu1_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ if (!dev->driver_data || dev->driver_data > STPMU1_MAX_BUCK)
+ return -EINVAL;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode = (struct dm_regulator_mode *)buck_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(buck_modes);
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmu1_buck_ops = {
+ .get_value = stpmu1_buck_get_value,
+ .set_value = stpmu1_buck_set_value,
+ .get_enable = stpmu1_buck_get_enable,
+ .set_enable = stpmu1_buck_set_enable,
+ .get_mode = stpmu1_buck_get_mode,
+ .set_mode = stpmu1_buck_set_mode,
+};
+
+U_BOOT_DRIVER(stpmu1_buck) = {
+ .name = "stpmu1_buck",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmu1_buck_ops,
+ .probe = stpmu1_buck_probe,
+};
+
+/*
+ * LDO regulators
+ */
+
+static const struct stpmu1_range ldo12_ranges[] = {
+ STPMU1_RANGE(1700000, 0, 7, 0),
+ STPMU1_RANGE(1700000, 8, 24, 100000),
+ STPMU1_RANGE(3300000, 25, 31, 0),
+};
+
+static const struct stpmu1_range ldo3_ranges[] = {
+ STPMU1_RANGE(1700000, 0, 7, 0),
+ STPMU1_RANGE(1700000, 8, 24, 100000),
+ STPMU1_RANGE(3300000, 25, 30, 0),
+ /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */
+};
+
+static const struct stpmu1_range ldo5_ranges[] = {
+ STPMU1_RANGE(1700000, 0, 7, 0),
+ STPMU1_RANGE(1700000, 8, 30, 100000),
+ STPMU1_RANGE(3900000, 31, 31, 0),
+};
+
+static const struct stpmu1_range ldo6_ranges[] = {
+ STPMU1_RANGE(900000, 0, 24, 100000),
+ STPMU1_RANGE(3300000, 25, 31, 0),
+};
+
+/* LDO: 1,2,3,4,5,6 - voltage ranges */
+static const struct stpmu1_output_range ldo_voltage_range[] = {
+ STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
+ STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
+ STPMU1_OUTPUT_RANGE(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)),
+ STPMU1_OUTPUT_RANGE(NULL, 0),
+ STPMU1_OUTPUT_RANGE(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)),
+ STPMU1_OUTPUT_RANGE(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)),
+};
+
+/* LDO modes */
+static const struct dm_regulator_mode ldo_modes[] = {
+ STPMU1_MODE(STPMU1_LDO_MODE_NORMAL,
+ STPMU1_LDO_MODE_NORMAL, "NORMAL"),
+ STPMU1_MODE(STPMU1_LDO_MODE_BYPASS,
+ STPMU1_LDO_MODE_BYPASS, "BYPASS"),
+ STPMU1_MODE(STPMU1_LDO_MODE_SINK_SOURCE,
+ STPMU1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"),
+};
+
+static int stpmu1_ldo_get_value(struct udevice *dev)
+{
+ int sel, ldo = dev->driver_data - 1;
+
+ sel = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo));
+ if (sel < 0)
+ return sel;
+
+ /* ldo4 => 3,3V */
+ if (ldo == STPMU1_LDO4)
+ return STPMU1_LDO4_UV;
+
+ sel &= STPMU1_LDO12356_OUTPUT_MASK;
+ sel >>= STPMU1_LDO12356_OUTPUT_SHIFT;
+
+ /* ldo3, sel = 31 => BUCK2/2 */
+ if (ldo == STPMU1_LDO3 && sel == STPMU1_LDO3_DDR_SEL)
+ return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2;
+
+ return stpmu1_output_find_uv(sel, &ldo_voltage_range[ldo]);
+}
+
+static int stpmu1_ldo_set_value(struct udevice *dev, int uv)
+{
+ int sel, ldo = dev->driver_data - 1;
+
+ /* ldo4 => not possible */
+ if (ldo == STPMU1_LDO4)
+ return -EINVAL;
+
+ sel = stpmu1_output_find_sel(uv, &ldo_voltage_range[ldo]);
+ if (sel < 0)
+ return sel;
+
+ return pmic_clrsetbits(dev->parent,
+ STPMU1_LDOX_CTRL_REG(ldo),
+ STPMU1_LDO12356_OUTPUT_MASK,
+ sel << STPMU1_LDO12356_OUTPUT_SHIFT);
+}
+
+static int stpmu1_ldo_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent,
+ STPMU1_LDOX_CTRL_REG(dev->driver_data - 1));
+ if (ret < 0)
+ return false;
+
+ return ret & STPMU1_LDO_EN ? true : false;
+}
+
+static int stpmu1_ldo_set_enable(struct udevice *dev, bool enable)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ int ret, uv;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (stpmu1_ldo_get_enable(dev) == enable)
+ return 0;
+
+ if (enable) {
+ uc_pdata = dev_get_uclass_platdata(dev);
+ uv = stpmu1_ldo_get_value(dev);
+ if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV))
+ stpmu1_ldo_set_value(dev, uc_pdata->min_uV);
+ }
+
+ ret = pmic_clrsetbits(dev->parent,
+ STPMU1_LDOX_CTRL_REG(dev->driver_data - 1),
+ STPMU1_LDO_EN, enable ? STPMU1_LDO_EN : 0);
+ if (enable)
+ mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+ return ret;
+}
+
+static int stpmu1_ldo_get_mode(struct udevice *dev)
+{
+ int ret, ldo = dev->driver_data - 1;
+
+ if (ldo != STPMU1_LDO3)
+ return -EINVAL;
+
+ ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo));
+ if (ret < 0)
+ return ret;
+
+ if (ret & STPMU1_LDO3_MODE)
+ return STPMU1_LDO_MODE_BYPASS;
+
+ ret &= STPMU1_LDO12356_OUTPUT_MASK;
+ ret >>= STPMU1_LDO12356_OUTPUT_SHIFT;
+
+ return ret == STPMU1_LDO3_DDR_SEL ? STPMU1_LDO_MODE_SINK_SOURCE :
+ STPMU1_LDO_MODE_NORMAL;
+}
+
+static int stpmu1_ldo_set_mode(struct udevice *dev, int mode)
+{
+ int ret, ldo = dev->driver_data - 1;
+
+ if (ldo != STPMU1_LDO3)
+ return -EINVAL;
+
+ ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo));
+ if (ret < 0)
+ return ret;
+
+ switch (mode) {
+ case STPMU1_LDO_MODE_SINK_SOURCE:
+ ret &= ~STPMU1_LDO12356_OUTPUT_MASK;
+ ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT;
+ case STPMU1_LDO_MODE_NORMAL:
+ ret &= ~STPMU1_LDO3_MODE;
+ break;
+ case STPMU1_LDO_MODE_BYPASS:
+ ret |= STPMU1_LDO3_MODE;
+ break;
+ }
+
+ return pmic_reg_write(dev->parent, STPMU1_LDOX_CTRL_REG(ldo), ret);
+}
+
+static int stpmu1_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ if (!dev->driver_data || dev->driver_data > STPMU1_MAX_LDO)
+ return -EINVAL;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ if (dev->driver_data - 1 == STPMU1_LDO3) {
+ uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(ldo_modes);
+ } else {
+ uc_pdata->mode_count = 0;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmu1_ldo_ops = {
+ .get_value = stpmu1_ldo_get_value,
+ .set_value = stpmu1_ldo_set_value,
+ .get_enable = stpmu1_ldo_get_enable,
+ .set_enable = stpmu1_ldo_set_enable,
+ .get_mode = stpmu1_ldo_get_mode,
+ .set_mode = stpmu1_ldo_set_mode,
+};
+
+U_BOOT_DRIVER(stpmu1_ldo) = {
+ .name = "stpmu1_ldo",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmu1_ldo_ops,
+ .probe = stpmu1_ldo_probe,
+};
+
+/*
+ * VREF DDR regulator
+ */
+
+static int stpmu1_vref_ddr_get_value(struct udevice *dev)
+{
+ /* BUCK2/2 */
+ return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2;
+}
+
+static int stpmu1_vref_ddr_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMU1_VREF_CTRL_REG);
+ if (ret < 0)
+ return false;
+
+ return ret & STPMU1_VREF_EN ? true : false;
+}
+
+static int stpmu1_vref_ddr_set_enable(struct udevice *dev, bool enable)
+{
+ int ret;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (stpmu1_vref_ddr_get_enable(dev) == enable)
+ return 0;
+
+ ret = pmic_clrsetbits(dev->parent, STPMU1_VREF_CTRL_REG,
+ STPMU1_VREF_EN, enable ? STPMU1_VREF_EN : 0);
+ if (enable)
+ mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+ return ret;
+}
+
+static int stpmu1_vref_ddr_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmu1_vref_ddr_ops = {
+ .get_value = stpmu1_vref_ddr_get_value,
+ .get_enable = stpmu1_vref_ddr_get_enable,
+ .set_enable = stpmu1_vref_ddr_set_enable,
+};
+
+U_BOOT_DRIVER(stpmu1_vref_ddr) = {
+ .name = "stpmu1_vref_ddr",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmu1_vref_ddr_ops,
+ .probe = stpmu1_vref_ddr_probe,
+};
+
+/*
+ * BOOST regulator
+ */
+
+static int stpmu1_boost_get_enable(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG);
+ if (ret < 0)
+ return false;
+
+ return ret & STPMU1_USB_BOOST_EN ? true : false;
+}
+
+static int stpmu1_boost_set_enable(struct udevice *dev, bool enable)
+{
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG);
+ if (ret < 0)
+ return ret;
+
+ if (!enable && ret & STPMU1_USB_PWR_SW_EN)
+ return -EINVAL;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (!!(ret & STPMU1_USB_BOOST_EN) == enable)
+ return 0;
+
+ ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG,
+ STPMU1_USB_BOOST_EN,
+ enable ? STPMU1_USB_BOOST_EN : 0);
+ if (enable)
+ mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS);
+
+ return ret;
+}
+
+static int stpmu1_boost_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmu1_boost_ops = {
+ .get_enable = stpmu1_boost_get_enable,
+ .set_enable = stpmu1_boost_set_enable,
+};
+
+U_BOOT_DRIVER(stpmu1_boost) = {
+ .name = "stpmu1_boost",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmu1_boost_ops,
+ .probe = stpmu1_boost_probe,
+};
+
+/*
+ * USB power switch
+ */
+
+static int stpmu1_pwr_sw_get_enable(struct udevice *dev)
+{
+ uint mask = 1 << dev->driver_data;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG);
+ if (ret < 0)
+ return false;
+
+ return ret & mask ? true : false;
+}
+
+static int stpmu1_pwr_sw_set_enable(struct udevice *dev, bool enable)
+{
+ uint mask = 1 << dev->driver_data;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG);
+ if (ret < 0)
+ return ret;
+
+ /* if regulator is already in the wanted state, nothing to do */
+ if (!!(ret & mask) == enable)
+ return 0;
+
+ /* Boost management */
+ if (enable && !(ret & STPMU1_USB_BOOST_EN)) {
+ pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG,
+ STPMU1_USB_BOOST_EN, STPMU1_USB_BOOST_EN);
+ mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS);
+ } else if (!enable && ret & STPMU1_USB_BOOST_EN &&
+ (ret & STPMU1_USB_PWR_SW_EN) != STPMU1_USB_PWR_SW_EN) {
+ pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG,
+ STPMU1_USB_BOOST_EN, 0);
+ }
+
+ ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG,
+ mask, enable ? mask : 0);
+ if (enable)
+ mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+ return ret;
+}
+
+static int stpmu1_pwr_sw_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_platdata *uc_pdata;
+
+ if (!dev->driver_data || dev->driver_data > STPMU1_MAX_PWR_SW)
+ return -EINVAL;
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_FIXED;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops stpmu1_pwr_sw_ops = {
+ .get_enable = stpmu1_pwr_sw_get_enable,
+ .set_enable = stpmu1_pwr_sw_set_enable,
+};
+
+U_BOOT_DRIVER(stpmu1_pwr_sw) = {
+ .name = "stpmu1_pwr_sw",
+ .id = UCLASS_REGULATOR,
+ .ops = &stpmu1_pwr_sw_ops,
+ .probe = stpmu1_pwr_sw_probe,
+};