summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boards/stm32mp157c-dk2/board.c3
-rw-r--r--arch/arm/dts/stm32mp151.dtsi2
-rw-r--r--arch/arm/mach-imx/imx.c2
-rw-r--r--common/reset_source.c6
-rw-r--r--drivers/phy/Kconfig13
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8mq-usb.c2
-rw-r--r--drivers/phy/phy-core.c29
-rw-r--r--drivers/phy/phy-stm32-usbphyc.c434
-rw-r--r--drivers/phy/usb-nop-xceiv.c2
-rw-r--r--drivers/pinctrl/pinctrl-tegra-xusb.c4
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/core.c139
-rw-r--r--drivers/regulator/stm32-pwr.c215
-rw-r--r--drivers/reset/reset-stm32.c117
-rw-r--r--drivers/usb/imx/imx-usb-phy.c2
-rw-r--r--drivers/watchdog/f71808e_wdt.c8
-rw-r--r--drivers/watchdog/stm32_iwdg.c99
-rw-r--r--drivers/watchdog/stpmic1_wdt.c2
-rw-r--r--include/linux/phy/phy.h14
-rw-r--r--include/regulator.h49
-rw-r--r--include/reset_source.h9
23 files changed, 1028 insertions, 132 deletions
diff --git a/arch/arm/boards/stm32mp157c-dk2/board.c b/arch/arm/boards/stm32mp157c-dk2/board.c
index 6da99d9353..4636603121 100644
--- a/arch/arm/boards/stm32mp157c-dk2/board.c
+++ b/arch/arm/boards/stm32mp157c-dk2/board.c
@@ -1,9 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
-#include <linux/sizes.h>
#include <init.h>
-#include <asm/memory.h>
-#include <mach/stm32.h>
#include <mach/bbu.h>
static int dk2_postcore_init(void)
diff --git a/arch/arm/dts/stm32mp151.dtsi b/arch/arm/dts/stm32mp151.dtsi
index e416c89856..8f8249dbc4 100644
--- a/arch/arm/dts/stm32mp151.dtsi
+++ b/arch/arm/dts/stm32mp151.dtsi
@@ -19,6 +19,8 @@
gpio10 = &gpiok;
gpio25 = &gpioz;
mmc0 = &sdmmc1;
+ mmc1 = &sdmmc2;
+ mmc2 = &sdmmc3;
};
psci {
diff --git a/arch/arm/mach-imx/imx.c b/arch/arm/mach-imx/imx.c
index ca2e77befe..0bbe44e4dd 100644
--- a/arch/arm/mach-imx/imx.c
+++ b/arch/arm/mach-imx/imx.c
@@ -206,5 +206,5 @@ void imx_set_reset_reason(void __iomem *srsr,
reset_source_set_prinst(type, RESET_SOURCE_DEFAULT_PRIORITY, instance);
pr_info("i.MX reset reason %s (SRSR: 0x%08x)\n",
- reset_source_name(), reg);
+ reset_source_to_string(type), reg);
}
diff --git a/common/reset_source.c b/common/reset_source.c
index 8fdf052157..343dc08444 100644
--- a/common/reset_source.c
+++ b/common/reset_source.c
@@ -42,11 +42,11 @@ enum reset_src_type reset_source_get(void)
}
EXPORT_SYMBOL(reset_source_get);
-const char *reset_source_name(void)
+const char *reset_source_to_string(enum reset_src_type st)
{
- return reset_src_names[reset_source];
+ return reset_src_names[st];
}
-EXPORT_SYMBOL(reset_source_name);
+EXPORT_SYMBOL(reset_source_to_string);
int reset_source_get_instance(void)
{
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index b5cefb2ff3..b5c8e98b9e 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -24,4 +24,17 @@ config USB_NOP_XCEIV
source "drivers/phy/freescale/Kconfig"
+config PHY_STM32_USBPHYC
+ tristate "STM32 USB HS PHY Controller"
+ depends on ARCH_STM32MP
+ help
+ Enable this to support the High-Speed USB transceivers that are part
+ of some STMicroelectronics STM32 SoCs.
+
+ This driver controls the entire USB PHY block: the USB PHY controller
+ (USBPHYC) and the two 8-bit wide UTMI+ interfaces. First interface is
+ used by an HS USB Host controller, and the second one is shared
+ between an HS USB OTG controller and an HS USB Host controller,
+ selected by a USB switch.
+
endif
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 179c55e60a..684aaed75a 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_USB_NOP_XCEIV) += usb-nop-xceiv.o
obj-y += freescale/
+obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index 1aef2b3004..6d60eacd7f 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -106,7 +106,7 @@ static int imx8mq_usb_phy_probe(struct device_d *dev)
if (IS_ERR(imx_phy->base))
return PTR_ERR(imx_phy->base);
- imx_phy->phy = phy_create(dev, NULL, &imx8mq_usb_phy_ops, NULL);
+ imx_phy->phy = phy_create(dev, NULL, &imx8mq_usb_phy_ops);
if (IS_ERR(imx_phy->phy))
return PTR_ERR(imx_phy->phy);
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 066a887a22..ff6e35d160 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -25,13 +25,11 @@ static int phy_ida;
* @dev: device that is creating the new phy
* @node: device node of the phy
* @ops: function pointers for performing phy operations
- * @init_data: contains the list of PHY consumers or NULL
*
* Called to create a phy using phy framework.
*/
struct phy *phy_create(struct device_d *dev, struct device_node *node,
- const struct phy_ops *ops,
- struct phy_init_data *init_data)
+ const struct phy_ops *ops)
{
int ret;
int id;
@@ -52,7 +50,16 @@ struct phy *phy_create(struct device_d *dev, struct device_node *node,
phy->dev.device_node = node ?: dev->device_node;
phy->id = id;
phy->ops = ops;
- phy->init_data = init_data;
+
+ /* phy-supply */
+ phy->pwr = regulator_get(&phy->dev, "phy");
+ if (IS_ERR(phy->pwr)) {
+ ret = PTR_ERR(phy->pwr);
+ if (ret == -EPROBE_DEFER)
+ goto free_ida;
+
+ phy->pwr = NULL;
+ }
ret = register_device(&phy->dev);
if (ret)
@@ -364,3 +371,17 @@ struct phy *phy_optional_get(struct device_d *dev, const char *string)
return phy;
}
+/**
+ * phy_get_by_index() - lookup and obtain a reference to a phy by index.
+ * @dev: device with node that references this phy
+ * @index: index of the phy
+ *
+ * Gets the phy using _of_phy_get()
+ */
+struct phy *phy_get_by_index(struct device_d *dev, int index)
+{
+ if (!dev->device_node)
+ return ERR_PTR(-ENODEV);
+
+ return _of_phy_get(dev->device_node, index);
+}
diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c
new file mode 100644
index 0000000000..093842fe14
--- /dev/null
+++ b/drivers/phy/phy-stm32-usbphyc.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * STMicroelectronics STM32 USB PHY Controller driver
+ *
+ * Copyright (C) 2018 STMicroelectronics
+ * Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
+ */
+#include <common.h>
+#include <init.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/phy/phy.h>
+#include <linux/reset.h>
+#include <asm-generic/div64.h>
+#include <usb/phy.h>
+
+#define STM32_USBPHYC_PLL 0x0
+#define STM32_USBPHYC_MISC 0x8
+#define STM32_USBPHYC_VERSION 0x3F4
+
+/* STM32_USBPHYC_PLL bit fields */
+#define PLLNDIV GENMASK(6, 0)
+#define PLLFRACIN GENMASK(25, 10)
+#define PLLEN BIT(26)
+#define PLLSTRB BIT(27)
+#define PLLSTRBYP BIT(28)
+#define PLLFRACCTL BIT(29)
+#define PLLDITHEN0 BIT(30)
+#define PLLDITHEN1 BIT(31)
+
+/* STM32_USBPHYC_MISC bit fields */
+#define SWITHOST BIT(0)
+
+/* STM32_USBPHYC_VERSION bit fields */
+#define MINREV GENMASK(3, 0)
+#define MAJREV GENMASK(7, 4)
+
+static const char * const supplies_names[] = {
+ "vdda1v1", /* 1V1 */
+ "vdda1v8", /* 1V8 */
+};
+
+#define NUM_SUPPLIES ARRAY_SIZE(supplies_names)
+
+#define PLL_LOCK_TIME_US 100
+#define PLL_PWR_DOWN_TIME_US 5
+#define PLL_FVCO_MHZ 2880
+#define PLL_INFF_MIN_RATE_HZ 19200000
+#define PLL_INFF_MAX_RATE_HZ 38400000
+#define HZ_PER_MHZ 1000000L
+
+struct pll_params {
+ u8 ndiv;
+ u16 frac;
+};
+
+struct stm32_usbphyc_phy {
+ struct phy *phy;
+ struct stm32_usbphyc *usbphyc;
+ struct regulator_bulk_data supplies[NUM_SUPPLIES];
+ u32 index;
+ bool active;
+};
+
+struct stm32_usbphyc {
+ struct device_d *dev;
+ void __iomem *base;
+ struct clk *clk;
+ struct stm32_usbphyc_phy **phys;
+ int nphys;
+ int switch_setup;
+};
+
+static inline void stm32_usbphyc_set_bits(void __iomem *reg, u32 bits)
+{
+ writel(readl(reg) | bits, reg);
+}
+
+static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits)
+{
+ writel(readl(reg) & ~bits, reg);
+}
+
+static void stm32_usbphyc_get_pll_params(u32 clk_rate,
+ struct pll_params *pll_params)
+{
+ unsigned long long fvco, ndiv, frac;
+
+ /* _
+ * | FVCO = INFF*2*(NDIV + FRACT/2^16) when DITHER_DISABLE[1] = 1
+ * | FVCO = 2880MHz
+ * <
+ * | NDIV = integer part of input bits to set the LDF
+ * |_FRACT = fractional part of input bits to set the LDF
+ * => PLLNDIV = integer part of (FVCO / (INFF*2))
+ * => PLLFRACIN = fractional part of(FVCO / INFF*2) * 2^16
+ * <=> PLLFRACIN = ((FVCO / (INFF*2)) - PLLNDIV) * 2^16
+ */
+ fvco = (unsigned long long)PLL_FVCO_MHZ * HZ_PER_MHZ;
+
+ ndiv = fvco;
+ do_div(ndiv, (clk_rate * 2));
+ pll_params->ndiv = (u8)ndiv;
+
+ frac = fvco * (1 << 16);
+ do_div(frac, (clk_rate * 2));
+ frac = frac - (ndiv * (1 << 16));
+ pll_params->frac = (u16)frac;
+}
+
+static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc)
+{
+ struct pll_params pll_params;
+ u32 clk_rate = clk_get_rate(usbphyc->clk);
+ u32 ndiv, frac;
+ u32 usbphyc_pll;
+
+ if ((clk_rate < PLL_INFF_MIN_RATE_HZ) ||
+ (clk_rate > PLL_INFF_MAX_RATE_HZ)) {
+ dev_err(usbphyc->dev, "input clk freq (%dHz) out of range\n",
+ clk_rate);
+ return -EINVAL;
+ }
+
+ stm32_usbphyc_get_pll_params(clk_rate, &pll_params);
+ ndiv = FIELD_PREP(PLLNDIV, pll_params.ndiv);
+ frac = FIELD_PREP(PLLFRACIN, pll_params.frac);
+
+ usbphyc_pll = PLLDITHEN1 | PLLDITHEN0 | PLLSTRBYP | ndiv;
+
+ if (pll_params.frac)
+ usbphyc_pll |= PLLFRACCTL | frac;
+
+ writel(usbphyc_pll, usbphyc->base + STM32_USBPHYC_PLL);
+
+ dev_dbg(usbphyc->dev, "input clk freq=%dHz, ndiv=%lu, frac=%lu\n",
+ clk_rate, FIELD_GET(PLLNDIV, usbphyc_pll),
+ FIELD_GET(PLLFRACIN, usbphyc_pll));
+
+ return 0;
+}
+
+static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc)
+{
+ int i;
+
+ for (i = 0; i < usbphyc->nphys; i++)
+ if (usbphyc->phys[i]->active)
+ return true;
+
+ return false;
+}
+
+static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc)
+{
+ void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL;
+ bool pllen = (readl(pll_reg) & PLLEN);
+ int ret;
+
+ /* Check if one phy port has already configured the pll */
+ if (pllen && stm32_usbphyc_has_one_phy_active(usbphyc))
+ return 0;
+
+ if (pllen) {
+ stm32_usbphyc_clr_bits(pll_reg, PLLEN);
+ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */
+ udelay(PLL_PWR_DOWN_TIME_US);
+ }
+
+ ret = stm32_usbphyc_pll_init(usbphyc);
+ if (ret)
+ return ret;
+
+ stm32_usbphyc_set_bits(pll_reg, PLLEN);
+
+ /* Wait for maximum lock time */
+ udelay(PLL_LOCK_TIME_US);
+
+ if (!(readl(pll_reg) & PLLEN)) {
+ dev_err(usbphyc->dev, "PLLEN not set\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc)
+{
+ void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL;
+
+ /* Check if other phy port active */
+ if (stm32_usbphyc_has_one_phy_active(usbphyc))
+ return 0;
+
+ stm32_usbphyc_clr_bits(pll_reg, PLLEN);
+ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */
+ udelay(PLL_PWR_DOWN_TIME_US);
+
+ if (readl(pll_reg) & PLLEN) {
+ dev_err(usbphyc->dev, "PLL not reset\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_init(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+ struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc;
+ int ret;
+
+ ret = stm32_usbphyc_pll_enable(usbphyc);
+ if (ret)
+ return ret;
+
+ usbphyc_phy->active = true;
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_exit(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+ struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc;
+
+ usbphyc_phy->active = false;
+
+ return stm32_usbphyc_pll_disable(usbphyc);
+}
+
+static int stm32_usbphyc_phy_power_on(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+
+ return regulator_bulk_enable(NUM_SUPPLIES, usbphyc_phy->supplies);
+}
+
+static int stm32_usbphyc_phy_power_off(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+
+ return regulator_bulk_disable(NUM_SUPPLIES, usbphyc_phy->supplies);
+}
+
+static const struct phy_ops stm32_usbphyc_phy_ops = {
+ .init = stm32_usbphyc_phy_init,
+ .exit = stm32_usbphyc_phy_exit,
+ .power_on = stm32_usbphyc_phy_power_on,
+ .power_off = stm32_usbphyc_phy_power_off,
+};
+
+static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc,
+ u32 utmi_switch)
+{
+ if (!utmi_switch)
+ stm32_usbphyc_clr_bits(usbphyc->base + STM32_USBPHYC_MISC,
+ SWITHOST);
+ else
+ stm32_usbphyc_set_bits(usbphyc->base + STM32_USBPHYC_MISC,
+ SWITHOST);
+ usbphyc->switch_setup = utmi_switch;
+}
+
+static struct phy *stm32_usbphyc_of_xlate(struct device_d *dev,
+ struct of_phandle_args *args)
+{
+ struct stm32_usbphyc *usbphyc = dev->priv;
+ struct stm32_usbphyc_phy *usbphyc_phy = NULL;
+ struct device_node *phynode = args->np;
+ int port = 0;
+
+ for (port = 0; port < usbphyc->nphys; port++) {
+ if (phynode == usbphyc->phys[port]->phy->dev.device_node) {
+ usbphyc_phy = usbphyc->phys[port];
+ break;
+ }
+ }
+
+ if (!usbphyc_phy) {
+ dev_err(dev, "failed to find phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (((usbphyc_phy->index == 0) && (args->args_count != 0)) ||
+ ((usbphyc_phy->index == 1) && (args->args_count != 1))) {
+ dev_err(dev, "invalid number of cells for phy port%d\n",
+ usbphyc_phy->index);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Configure the UTMI switch for PHY port#2 */
+ if (usbphyc_phy->index == 1) {
+ if (usbphyc->switch_setup < 0) {
+ stm32_usbphyc_switch_setup(usbphyc, args->args[0]);
+ } else {
+ if (args->args[0] != usbphyc->switch_setup) {
+ dev_err(dev, "phy port1 already used\n");
+ return ERR_PTR(-EBUSY);
+ }
+ }
+ }
+
+ return usbphyc_phy->phy;
+}
+
+static int stm32_usbphyc_probe(struct device_d *dev)
+{
+ struct stm32_usbphyc *usbphyc;
+ struct device_node *child, *np = dev->device_node;
+ struct resource *iores;
+ struct phy_provider *phy_provider;
+ u32 version;
+ int ret, port = 0;
+
+ usbphyc = xzalloc(sizeof(*usbphyc));
+
+ usbphyc->dev = dev;
+ dev->priv = usbphyc;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ usbphyc->base = IOMEM(iores->start);
+
+ usbphyc->clk = clk_get(dev, 0);
+ if (IS_ERR(usbphyc->clk)) {
+ ret = PTR_ERR(usbphyc->clk);
+ dev_err(dev, "clk get failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(usbphyc->clk);
+ if (ret) {
+ dev_err(dev, "clk enable failed: %d\n", ret);
+ return ret;
+ }
+
+ device_reset_us(dev, 2);
+
+ usbphyc->switch_setup = -EINVAL;
+ usbphyc->nphys = of_get_child_count(np);
+ usbphyc->phys = xzalloc(usbphyc->nphys * sizeof(*usbphyc->phys));
+
+ for_each_child_of_node(np, child) {
+ struct stm32_usbphyc_phy *usbphyc_phy;
+ struct phy *phy;
+ u32 index;
+ int i;
+
+ phy = phy_create(dev, child, &stm32_usbphyc_phy_ops);
+ if (IS_ERR(phy)) {
+ ret = PTR_ERR(phy);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to create phy%d: %d\n",
+ port, ret);
+ goto clk_disable;
+ }
+
+ usbphyc_phy = xzalloc(sizeof(*usbphyc_phy));
+
+ for (i = 0; i < NUM_SUPPLIES; i++)
+ usbphyc_phy->supplies[i].supply = supplies_names[i];
+
+ ret = regulator_bulk_get(&phy->dev, NUM_SUPPLIES,
+ usbphyc_phy->supplies);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&phy->dev,
+ "failed to get regulators: %d\n", ret);
+ goto clk_disable;
+ }
+
+ ret = of_property_read_u32(child, "reg", &index);
+ if (ret || index > usbphyc->nphys) {
+ dev_err(&phy->dev, "invalid reg property: %d\n", ret);
+ goto clk_disable;
+ }
+
+ usbphyc->phys[port] = usbphyc_phy;
+ phy_set_bus_width(phy, 8);
+ phy_set_drvdata(phy, usbphyc_phy);
+
+ usbphyc->phys[port]->phy = phy;
+ usbphyc->phys[port]->usbphyc = usbphyc;
+ usbphyc->phys[port]->index = index;
+ usbphyc->phys[port]->active = false;
+
+ port++;
+ }
+
+ phy_provider = of_phy_provider_register(dev, stm32_usbphyc_of_xlate);
+ if (IS_ERR(phy_provider)) {
+ ret = PTR_ERR(phy_provider);
+ dev_err(dev, "failed to register phy provider: %d\n", ret);
+ goto clk_disable;
+ }
+
+ version = readl(usbphyc->base + STM32_USBPHYC_VERSION);
+ dev_info(dev, "registered rev: %lu.%lu\n",
+ FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version));
+
+ return 0;
+
+clk_disable:
+ clk_disable(usbphyc->clk);
+
+ return ret;
+}
+
+static void stm32_usbphyc_remove(struct device_d *dev)
+{
+ struct stm32_usbphyc *usbphyc = dev->priv;
+
+ clk_disable(usbphyc->clk);
+}
+
+static const struct of_device_id stm32_usbphyc_of_match[] = {
+ { .compatible = "st,stm32mp1-usbphyc", },
+ { /* sentinel */ },
+};
+
+static struct driver_d stm32_usbphyc_driver = {
+ .name = "stm32-usbphyc",
+ .probe = stm32_usbphyc_probe,
+ .remove = stm32_usbphyc_remove,
+ .of_compatible = stm32_usbphyc_of_match,
+};
+device_platform_driver(stm32_usbphyc_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 USBPHYC driver");
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/usb-nop-xceiv.c b/drivers/phy/usb-nop-xceiv.c
index b124e6c0c4..a9031fa7f8 100644
--- a/drivers/phy/usb-nop-xceiv.c
+++ b/drivers/phy/usb-nop-xceiv.c
@@ -107,7 +107,7 @@ static int nop_usbphy_probe(struct device_d *dev)
/* FIXME: Add vbus-detect-gpio support */
nopphy->usb_phy.dev = dev;
- nopphy->phy = phy_create(dev, NULL, &nop_phy_ops, NULL);
+ nopphy->phy = phy_create(dev, NULL, &nop_phy_ops);
if (IS_ERR(nopphy->phy)) {
ret = PTR_ERR(nopphy->phy);
goto release_gpio;
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index e477280e62..c4d3bbe8d4 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -415,7 +415,7 @@ static int pinctrl_tegra_xusb_probe(struct device_d *dev)
goto reset;
}
- phy = phy_create(dev, NULL, &pcie_phy_ops, NULL);
+ phy = phy_create(dev, NULL, &pcie_phy_ops);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
@@ -424,7 +424,7 @@ static int pinctrl_tegra_xusb_probe(struct device_d *dev)
padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
phy_set_drvdata(phy, padctl);
- phy = phy_create(dev, NULL, &sata_phy_ops, NULL);
+ phy = phy_create(dev, NULL, &sata_phy_ops);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f47a115da2..1ce057180a 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -21,6 +21,13 @@ config REGULATOR_PFUZE
depends on I2C
depends on ARCH_IMX6 || ARCH_IMX8MQ
+config REGULATOR_STM32_PWR
+ bool "STMicroelectronics STM32 PWR"
+ depends on ARCH_STM32MP
+ help
+ This driver supports internal regulators (1V1, 1V8, 3V3) in the
+ STMicroelectronics STM32 chips.
+
config REGULATOR_STPMIC1
tristate "STMicroelectronics STPMIC1 PMIC Regulators"
depends on MFD_STPMIC1
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index e27e155cf6..4d0bba6c52 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_REGULATOR_BCM283X) += bcm2835.o
obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o
obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index f0de7a52e3..f459d072a9 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -397,6 +397,145 @@ int regulator_set_voltage(struct regulator *r, int min_uV, int max_uV)
return regulator_set_voltage_internal(r->ri, min_uV, max_uV);
}
+/**
+ * regulator_bulk_get - get multiple regulator consumers
+ *
+ * @dev: Device to supply
+ * @num_consumers: Number of consumers to register
+ * @consumers: Configuration of consumers; clients are stored here.
+ *
+ * @return 0 on success, an errno on failure.
+ *
+ * This helper function allows drivers to get several regulator
+ * consumers in one operation. If any of the regulators cannot be
+ * acquired then any regulators that were allocated will be freed
+ * before returning to the caller.
+ */
+int regulator_bulk_get(struct device_d *dev, int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < num_consumers; i++)
+ consumers[i].consumer = NULL;
+
+ for (i = 0; i < num_consumers; i++) {
+ consumers[i].consumer = regulator_get(dev,
+ consumers[i].supply);
+ if (IS_ERR(consumers[i].consumer)) {
+ ret = PTR_ERR(consumers[i].consumer);
+ consumers[i].consumer = NULL;
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get supply '%s': %d\n",
+ consumers[i].supply, ret);
+ else
+ dev_dbg(dev, "Failed to get supply '%s', deferring\n",
+ consumers[i].supply);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_get);
+
+/**
+ * regulator_bulk_enable - enable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers: Consumer data; clients are stored here.
+ * @return 0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to enable multiple regulator
+ * clients in a single API call. If any consumers cannot be enabled
+ * then any others that were enabled will be disabled again prior to
+ * return.
+ */
+int regulator_bulk_enable(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < num_consumers; i++) {
+ ret = regulator_enable(consumers[i].consumer);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0)
+ regulator_disable(consumers[i].consumer);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_enable);
+
+/**
+ * regulator_bulk_disable - disable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers: Consumer data; clients are stored here.
+ * @return 0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to disable multiple regulator
+ * clients in a single API call. If any consumers cannot be disabled
+ * then any others that were disabled will be enabled again prior to
+ * return.
+ */
+int regulator_bulk_disable(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ int i;
+ int ret, r;
+
+ for (i = num_consumers - 1; i >= 0; --i) {
+ ret = regulator_disable(consumers[i].consumer);
+ if (ret != 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
+ for (++i; i < num_consumers; ++i) {
+ r = regulator_enable(consumers[i].consumer);
+ if (r != 0)
+ pr_err("Failed to re-enable %s: %d\n",
+ consumers[i].supply, r);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_disable);
+
+/**
+ * regulator_bulk_free - free multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers: Consumer data; clients are stored here.
+ *
+ * This convenience API allows consumers to free multiple regulator
+ * clients in a single API call.
+ */
+void regulator_bulk_free(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ int i;
+
+ for (i = 0; i < num_consumers; i++)
+ consumers[i].consumer = NULL;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_free);
+
static void regulator_print_one(struct regulator_internal *ri)
{
struct regulator *r;
diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c
new file mode 100644
index 0000000000..296f95bc4c
--- /dev/null
+++ b/drivers/regulator/stm32-pwr.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2019
+// Authors: Gabriel Fernandez <gabriel.fernandez@st.com>
+// Pascal Paillet <p.paillet@st.com>.
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/iopoll.h>
+#include <of.h>
+#include <regulator.h>
+
+/*
+ * Registers description
+ */
+#define REG_PWR_CR3 0x0C
+
+#define USB_3_3_EN BIT(24)
+#define USB_3_3_RDY BIT(26)
+#define REG_1_8_EN BIT(28)
+#define REG_1_8_RDY BIT(29)
+#define REG_1_1_EN BIT(30)
+#define REG_1_1_RDY BIT(31)
+
+/* list of supported regulators */
+enum {
+ PWR_REG11,
+ PWR_REG18,
+ PWR_USB33,
+ STM32PWR_REG_NUM_REGS
+};
+
+struct stm32_pwr_desc {
+ struct regulator_desc desc;
+ const char *name;
+ const char *supply_name;
+};
+
+static u32 ready_mask_table[STM32PWR_REG_NUM_REGS] = {
+ [PWR_REG11] = REG_1_1_RDY,
+ [PWR_REG18] = REG_1_8_RDY,
+ [PWR_USB33] = USB_3_3_RDY,
+};
+
+struct stm32_pwr_reg {
+ void __iomem *base;
+ struct device_d *dev;
+ u32 ready_mask;
+ struct regulator_dev rdev;
+ struct regulator *supply;
+};
+
+static inline struct stm32_pwr_reg *to_pwr_reg(struct regulator_dev *rdev)
+{
+ return container_of(rdev, struct stm32_pwr_reg, rdev);
+}
+
+static inline struct stm32_pwr_desc *to_desc(struct regulator_dev *rdev)
+{
+ return container_of(rdev->desc, struct stm32_pwr_desc, desc);
+}
+
+static int stm32_pwr_reg_is_ready(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ u32 val;
+
+ val = readl(priv->base + REG_PWR_CR3);
+
+ return (val & priv->ready_mask);
+}
+
+static int stm32_pwr_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ u32 val;
+
+ val = readl(priv->base + REG_PWR_CR3);
+
+ return (val & rdev->desc->enable_mask);
+}
+
+static int stm32_pwr_reg_enable(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ struct stm32_pwr_desc *desc = to_desc(rdev);
+ int ret;
+ u32 val;
+
+ regulator_enable(priv->supply);
+
+ val = readl(priv->base + REG_PWR_CR3);
+ val |= rdev->desc->enable_mask;
+ writel(val, priv->base + REG_PWR_CR3);
+
+ /* use an arbitrary timeout of 20ms */
+ ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, val,
+ 20 * USEC_PER_MSEC);
+ if (ret)
+ dev_err(priv->dev, "%s: regulator enable timed out!\n",
+ desc->name);
+
+ return ret;
+}
+
+static int stm32_pwr_reg_disable(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ struct stm32_pwr_desc *desc = to_desc(rdev);
+ int ret;
+ u32 val;
+
+ val = readl(priv->base + REG_PWR_CR3);
+ val &= ~rdev->desc->enable_mask;
+ writel(val, priv->base + REG_PWR_CR3);
+
+ /* use an arbitrary timeout of 20ms */
+ ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, !val,
+ 20 * USEC_PER_MSEC);
+ if (ret)
+ dev_err(priv->dev, "%s: regulator disable timed out!\n",
+ desc->name);
+
+ regulator_disable(priv->supply);
+
+ return ret;
+}
+
+static const struct regulator_ops stm32_pwr_reg_ops = {
+ .enable = stm32_pwr_reg_enable,
+ .disable = stm32_pwr_reg_disable,
+ .is_enabled = stm32_pwr_reg_is_enabled,
+};
+
+#define PWR_REG(_id, _name, _volt, _en, _supply) \
+ [_id] = { { \
+ .n_voltages = 1, \
+ .ops = &stm32_pwr_reg_ops, \
+ .min_uV = _volt, \
+ .enable_mask = _en, \
+ }, .name = _name, .supply_name = _supply, }
+
+static const struct stm32_pwr_desc stm32_pwr_desc[] = {
+ PWR_REG(PWR_REG11, "reg11", 1100000, REG_1_1_EN, "vdd"),
+ PWR_REG(PWR_REG18, "reg18", 1800000, REG_1_8_EN, "vdd"),
+ PWR_REG(PWR_USB33, "usb33", 3300000, USB_3_3_EN, "vdd_3v3_usbfs"),
+};
+
+static int stm32_pwr_regulator_probe(struct device_d *dev)
+{
+ struct stm32_pwr_reg *priv;
+ struct device_node *child;
+ struct resource *iores;
+ int i, ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ for_each_child_of_node(dev->device_node, child) {
+ const struct stm32_pwr_desc *desc = NULL;
+
+ for (i = 0; i < STM32PWR_REG_NUM_REGS; i++) {
+ const char *name;
+
+ name = of_get_property(child, "regulator-name", NULL);
+ if (name && strcmp(stm32_pwr_desc[i].name, name)) {
+ desc = &stm32_pwr_desc[i];
+ break;
+ }
+ }
+
+ if (!desc) {
+ dev_warn(dev, "Skipping unknown child node %s\n",
+ child->name);
+ continue;
+ }
+
+ priv = xzalloc(sizeof(*priv));
+ priv->base = IOMEM(iores->start);
+ priv->ready_mask = ready_mask_table[i];
+ priv->dev = dev;
+
+ priv->rdev.desc = &desc->desc;
+
+ priv->supply = regulator_get(dev, desc->supply_name);
+ if (IS_ERR(priv->supply))
+ return PTR_ERR(priv->supply);
+
+ ret = of_regulator_register(&priv->rdev, child);
+ if (ret) {
+ dev_err(dev, "%s: Failed to register regulator: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id stm32_pwr_of_match[] = {
+ { .compatible = "st,stm32mp1,pwr-reg", },
+ { /* sentinel */ },
+};
+
+static struct driver_d stm32_pwr_driver = {
+ .probe = stm32_pwr_regulator_probe,
+ .name = "stm32-pwr-regulator",
+ .of_compatible = stm32_pwr_of_match,
+};
+device_platform_driver(stm32_pwr_driver);
+
+MODULE_DESCRIPTION("STM32MP1 PWR voltage regulator driver");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
index 5689dfd488..6c62633563 100644
--- a/drivers/reset/reset-stm32.c
+++ b/drivers/reset/reset-stm32.c
@@ -9,14 +9,48 @@
#include <init.h>
#include <linux/err.h>
#include <linux/reset-controller.h>
+#include <restart.h>
+#include <reset_source.h>
#include <asm/io.h>
#define RCC_CL 0x4
+#define RCC_MP_GRSTCSETR 0x404
+#define RCC_MP_RSTSCLRR 0x408
+
+#define STM32MP_RCC_RSTF_POR BIT(0)
+#define STM32MP_RCC_RSTF_BOR BIT(1)
+#define STM32MP_RCC_RSTF_PAD BIT(2)
+#define STM32MP_RCC_RSTF_HCSS BIT(3)
+#define STM32MP_RCC_RSTF_VCORE BIT(4)
+
+#define STM32MP_RCC_RSTF_MPSYS BIT(6)
+#define STM32MP_RCC_RSTF_MCSYS BIT(7)
+#define STM32MP_RCC_RSTF_IWDG1 BIT(8)
+#define STM32MP_RCC_RSTF_IWDG2 BIT(9)
+
+#define STM32MP_RCC_RSTF_STDBY BIT(11)
+#define STM32MP_RCC_RSTF_CSTDBY BIT(12)
+#define STM32MP_RCC_RSTF_MPUP0 BIT(13)
+#define STM32MP_RCC_RSTF_MPUP1 BIT(14)
+
+struct stm32_reset_reason {
+ uint32_t mask;
+ enum reset_src_type type;
+ int instance;
+};
+
struct stm32_reset {
void __iomem *base;
struct reset_controller_dev rcdev;
+ struct restart_handler restart;
+ const struct stm32_reset_ops *ops;
+};
+
+struct stm32_reset_ops {
void (*reset)(void __iomem *reg, unsigned offset, bool assert);
+ void __noreturn (*sys_reset)(struct restart_handler *rst);
+ const struct stm32_reset_reason *reset_reasons;
};
static struct stm32_reset *to_stm32_reset(struct reset_controller_dev *rcdev)
@@ -40,12 +74,40 @@ static void stm32mcu_reset(void __iomem *reg, unsigned offset, bool assert)
clrbits_le32(reg, BIT(offset));
}
+static u32 stm32_reset_status(struct stm32_reset *priv, unsigned long bank)
+{
+ return readl(priv->base + bank);
+}
+
static void stm32_reset(struct stm32_reset *priv, unsigned long id, bool assert)
{
int bank = (id / BITS_PER_LONG) * 4;
int offset = id % BITS_PER_LONG;
- priv->reset(priv->base + bank, offset, assert);
+ priv->ops->reset(priv->base + bank, offset, assert);
+}
+
+static void stm32_set_reset_reason(struct stm32_reset *priv,
+ const struct stm32_reset_reason *reasons)
+{
+ enum reset_src_type type = RESET_UKWN;
+ u32 reg;
+ int i, instance = 0;
+
+ reg = stm32_reset_status(priv, RCC_MP_RSTSCLRR);
+
+ for (i = 0; reasons[i].mask; i++) {
+ if (reg & reasons[i].mask) {
+ type = reasons[i].type;
+ instance = reasons[i].instance;
+ break;
+ }
+ }
+
+ reset_source_set_prinst(type, RESET_SOURCE_DEFAULT_PRIORITY, instance);
+
+ pr_info("STM32 RCC reset reason %s (MP_RSTSR: 0x%08x)\n",
+ reset_source_to_string(type), reg);
}
static int stm32_reset_assert(struct reset_controller_dev *rcdev,
@@ -74,7 +136,7 @@ static int stm32_reset_probe(struct device_d *dev)
int ret;
priv = xzalloc(sizeof(*priv));
- ret = dev_get_drvdata(dev, (const void **)&priv->reset);
+ ret = dev_get_drvdata(dev, (const void **)&priv->ops);
if (ret)
return ret;
@@ -87,12 +149,59 @@ static int stm32_reset_probe(struct device_d *dev)
priv->rcdev.ops = &stm32_reset_ops;
priv->rcdev.of_node = dev->device_node;
+ if (priv->ops->sys_reset) {
+ priv->restart.name = "stm32-rcc";
+ priv->restart.restart = priv->ops->sys_reset;
+ priv->restart.priority = 200;
+
+ ret = restart_handler_register(&priv->restart);
+ if (ret)
+ dev_warn(dev, "Cannot register restart handler\n");
+ }
+
+ if (priv->ops->reset_reasons)
+ stm32_set_reset_reason(priv, priv->ops->reset_reasons);
+
return reset_controller_register(&priv->rcdev);
}
+static void __noreturn stm32mp_rcc_restart_handler(struct restart_handler *rst)
+{
+ struct stm32_reset *priv = container_of(rst, struct stm32_reset, restart);
+
+ stm32_reset(priv, RCC_MP_GRSTCSETR * BITS_PER_BYTE, true);
+
+ mdelay(1000);
+ hang();
+}
+
+static const struct stm32_reset_reason stm32mp_reset_reasons[] = {
+ { STM32MP_RCC_RSTF_POR, RESET_POR, 0 },
+ { STM32MP_RCC_RSTF_BOR, RESET_BROWNOUT, 0 },
+ { STM32MP_RCC_RSTF_STDBY, RESET_WKE, 0 },
+ { STM32MP_RCC_RSTF_CSTDBY, RESET_WKE, 1 },
+ { STM32MP_RCC_RSTF_MPSYS, RESET_RST, 2 },
+ { STM32MP_RCC_RSTF_MPUP0, RESET_RST, 0 },
+ { STM32MP_RCC_RSTF_MPUP1, RESET_RST, 1 },
+ { STM32MP_RCC_RSTF_IWDG1, RESET_WDG, 0 },
+ { STM32MP_RCC_RSTF_IWDG2, RESET_WDG, 1 },
+ { STM32MP_RCC_RSTF_PAD, RESET_EXT, 1 },
+ { /* sentinel */ }
+};
+
+static const struct stm32_reset_ops stm32mp1_reset_ops = {
+ .reset = stm32mp_reset,
+ .sys_reset = stm32mp_rcc_restart_handler,
+ .reset_reasons = stm32mp_reset_reasons,
+};
+
+static const struct stm32_reset_ops stm32mcu_reset_ops = {
+ .reset = stm32mcu_reset,
+};
+
static const struct of_device_id stm32_rcc_reset_dt_ids[] = {
- { .compatible = "st,stm32mp1-rcc", .data = stm32mp_reset },
- { .compatible = "st,stm32-rcc", .data = stm32mcu_reset },
+ { .compatible = "st,stm32mp1-rcc", .data = &stm32mp1_reset_ops },
+ { .compatible = "st,stm32-rcc", .data = &stm32mcu_reset_ops },
{ /* sentinel */ },
};
diff --git a/drivers/usb/imx/imx-usb-phy.c b/drivers/usb/imx/imx-usb-phy.c
index d4562285c0..069dddcacb 100644
--- a/drivers/usb/imx/imx-usb-phy.c
+++ b/drivers/usb/imx/imx-usb-phy.c
@@ -174,7 +174,7 @@ static int imx_usbphy_probe(struct device_d *dev)
imxphy->usb_phy.dev = dev;
imxphy->usb_phy.notify_connect = imx_usbphy_notify_connect;
imxphy->usb_phy.notify_disconnect = imx_usbphy_notify_disconnect;
- imxphy->phy = phy_create(dev, NULL, &imx_phy_ops, NULL);
+ imxphy->phy = phy_create(dev, NULL, &imx_phy_ops);
if (IS_ERR(imxphy->phy)) {
ret = PTR_ERR(imxphy->phy);
goto err_clk;
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index 5307ab0b3e..6f2d30ec77 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -256,11 +256,11 @@ static int f71808e_wdt_init(struct f71808e_wdt *wd, struct device_d *dev)
wdd->set_timeout = &f71808e_wdt_set_timeout;
wdd->timeout_max = WATCHDOG_MAX_TIMEOUT;
- if (wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS))
- reset_source_set_priority(RESET_WDG,
- RESET_SOURCE_DEFAULT_PRIORITY);
+ if (wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS)) {
+ reset_source_set_priority(RESET_WDG, RESET_SOURCE_DEFAULT_PRIORITY);
+ dev_info(dev, "reset reason: WDT\n");
+ }
- dev_info(dev, "reset reason: %s\n", reset_source_name());
if (test_bit(F71808FG_FLAG_WD_EN, &wdt_conf))
wdd->running = WDOG_HW_RUNNING;
diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c
index c7a5cb9caa..9e38f1a669 100644
--- a/drivers/watchdog/stm32_iwdg.c
+++ b/drivers/watchdog/stm32_iwdg.c
@@ -6,14 +6,11 @@
#include <common.h>
#include <init.h>
#include <watchdog.h>
-#include <restart.h>
#include <asm/io.h>
#include <of_device.h>
#include <linux/log2.h>
#include <linux/iopoll.h>
#include <linux/clk.h>
-#include <mfd/syscon.h>
-#include <reset_source.h>
/* IWDG registers */
#define IWDG_KR 0x00 /* Key register */
@@ -36,40 +33,12 @@
#define SR_PVU BIT(0) /* Watchdog prescaler value update */
#define SR_RVU BIT(1) /* Watchdog counter reload value update */
-#define RCC_MP_GRSTCSETR 0x404
-#define RCC_MP_RSTSCLRR 0x408
-#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0)
-
-#define STM32MP_RCC_RSTF_POR BIT(0)
-#define STM32MP_RCC_RSTF_BOR BIT(1)
-#define STM32MP_RCC_RSTF_PAD BIT(2)
-#define STM32MP_RCC_RSTF_HCSS BIT(3)
-#define STM32MP_RCC_RSTF_VCORE BIT(4)
-
-#define STM32MP_RCC_RSTF_MPSYS BIT(6)
-#define STM32MP_RCC_RSTF_MCSYS BIT(7)
-#define STM32MP_RCC_RSTF_IWDG1 BIT(8)
-#define STM32MP_RCC_RSTF_IWDG2 BIT(9)
-
-#define STM32MP_RCC_RSTF_STDBY BIT(11)
-#define STM32MP_RCC_RSTF_CSTDBY BIT(12)
-#define STM32MP_RCC_RSTF_MPUP0 BIT(13)
-#define STM32MP_RCC_RSTF_MPUP1 BIT(14)
-
/* set timeout to 100 ms */
#define TIMEOUT_US 100000
-struct stm32_reset_reason {
- uint32_t mask;
- enum reset_src_type type;
- int instance;
-};
-
struct stm32_iwdg {
struct watchdog wdd;
- struct restart_handler restart;
void __iomem *iwdg_base;
- struct regmap *rcc_regmap;
unsigned int timeout;
unsigned int rate;
};
@@ -79,17 +48,6 @@ static inline struct stm32_iwdg *to_stm32_iwdg(struct watchdog *wdd)
return container_of(wdd, struct stm32_iwdg, wdd);
}
-static void __noreturn stm32_iwdg_restart_handler(struct restart_handler *rst)
-{
- struct stm32_iwdg *wd = container_of(rst, struct stm32_iwdg, restart);
-
- regmap_update_bits(wd->rcc_regmap, RCC_MP_GRSTCSETR,
- RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR_MPSYSRST);
-
- mdelay(1000);
- hang();
-}
-
static void stm32_iwdg_ping(struct stm32_iwdg *wd)
{
writel(KR_KEY_RELOAD, wd->iwdg_base + IWDG_KR);
@@ -149,47 +107,6 @@ static int stm32_iwdg_set_timeout(struct watchdog *wdd, unsigned int timeout)
return 0;
}
-static const struct stm32_reset_reason stm32_reset_reasons[] = {
- { STM32MP_RCC_RSTF_POR, RESET_POR, 0 },
- { STM32MP_RCC_RSTF_BOR, RESET_BROWNOUT, 0 },
- { STM32MP_RCC_RSTF_STDBY, RESET_WKE, 0 },
- { STM32MP_RCC_RSTF_CSTDBY, RESET_WKE, 1 },
- { STM32MP_RCC_RSTF_MPSYS, RESET_RST, 2 },
- { STM32MP_RCC_RSTF_MPUP0, RESET_RST, 0 },
- { STM32MP_RCC_RSTF_MPUP1, RESET_RST, 1 },
- { STM32MP_RCC_RSTF_IWDG1, RESET_WDG, 0 },
- { STM32MP_RCC_RSTF_IWDG2, RESET_WDG, 1 },
- { STM32MP_RCC_RSTF_PAD, RESET_EXT, 1 },
- { /* sentinel */ }
-};
-
-static int stm32_set_reset_reason(struct regmap *rcc)
-{
- enum reset_src_type type = RESET_UKWN;
- u32 reg;
- int ret;
- int i, instance = 0;
-
- ret = regmap_read(rcc, RCC_MP_RSTSCLRR, &reg);
- if (ret)
- return ret;
-
- for (i = 0; stm32_reset_reasons[i].mask; i++) {
- if (reg & stm32_reset_reasons[i].mask) {
- type = stm32_reset_reasons[i].type;
- instance = stm32_reset_reasons[i].instance;
- break;
- }
- }
-
- reset_source_set_prinst(type, RESET_SOURCE_DEFAULT_PRIORITY, instance);
-
- pr_info("STM32 RCC reset reason %s (MP_RSTSR: 0x%08x)\n",
- reset_source_name(), reg);
-
- return 0;
-}
-
struct stm32_iwdg_data {
bool has_pclk;
u32 max_prescaler;
@@ -264,22 +181,6 @@ static int stm32_iwdg_probe(struct device_d *dev)
return ret;
}
- wd->restart.name = "stm32-iwdg";
- wd->restart.restart = stm32_iwdg_restart_handler;
- wd->restart.priority = 200;
-
- wd->rcc_regmap = syscon_regmap_lookup_by_compatible("st,stm32mp1-rcc");
- if (IS_ERR(wd->rcc_regmap))
- dev_warn(dev, "Cannot register restart handler\n");
-
- ret = restart_handler_register(&wd->restart);
- if (ret)
- dev_warn(dev, "Cannot register restart handler\n");
-
- ret = stm32_set_reset_reason(wd->rcc_regmap);
- if (ret)
- dev_warn(dev, "Cannot determine reset reason\n");
-
dev_info(dev, "probed\n");
return 0;
}
diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c
index 40273ffc4c..458c5c16a3 100644
--- a/drivers/watchdog/stpmic1_wdt.c
+++ b/drivers/watchdog/stpmic1_wdt.c
@@ -152,7 +152,7 @@ static int stpmic1_set_reset_reason(struct regmap *map)
reset_source_set_prinst(type, 400, instance);
pr_info("STPMIC1 reset reason %s (RREQ_STATE_SR: 0x%08x)\n",
- reset_source_name(), reg);
+ reset_source_to_string(type), reg);
return 0;
}
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 5d96e02df4..8a28b8e068 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -49,7 +49,6 @@ struct phy_attrs {
* @dev: phy device
* @id: id of the phy device
* @ops: function pointers for performing phy operations
- * @init_data: list of PHY consumers (non-dt only)
* @mutex: mutex to protect phy_ops
* @init_count: used to protect when the PHY is used by multiple consumers
* @power_count: used to protect when the PHY is used by multiple consumers
@@ -59,7 +58,6 @@ struct phy {
struct device_d dev;
int id;
const struct phy_ops *ops;
- struct phy_init_data *init_data;
int init_count;
int power_count;
struct phy_attrs attrs;
@@ -144,14 +142,14 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id);
struct phy *of_phy_simple_xlate(struct device_d *dev,
struct of_phandle_args *args);
struct phy *phy_create(struct device_d *dev, struct device_node *node,
- const struct phy_ops *ops,
- struct phy_init_data *init_data);
+ const struct phy_ops *ops);
void phy_destroy(struct phy *phy);
struct phy_provider *__of_phy_provider_register(struct device_d *dev,
struct phy * (*of_xlate)(struct device_d *dev,
struct of_phandle_args *args));
void of_phy_provider_unregister(struct phy_provider *phy_provider);
struct usb_phy *phy_to_usbphy(struct phy *phy);
+struct phy *phy_get_by_index(struct device_d *dev, int index);
#else
static inline int phy_init(struct phy *phy)
{
@@ -225,8 +223,7 @@ static inline struct phy *of_phy_simple_xlate(struct device_d *dev,
static inline struct phy *phy_create(struct device_d *dev,
struct device_node *node,
- const struct phy_ops *ops,
- struct phy_init_data *init_data)
+ const struct phy_ops *ops)
{
return ERR_PTR(-ENOSYS);
}
@@ -251,6 +248,11 @@ static inline struct usb_phy *phy_to_usbphy(struct phy *phy)
return NULL;
}
+static struct phy *phy_get_by_index(struct device_d *dev, int index)
+{
+ return ERR_PTR(-ENODEV);
+}
+
#endif
#endif /* __DRIVERS_PHY_H */
diff --git a/include/regulator.h b/include/regulator.h
index d01535df52..dfa808d662 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -6,6 +6,23 @@
struct regulator;
/**
+ * struct regulator_bulk_data - Data used for bulk regulator operations.
+ *
+ * @supply: The name of the supply. Initialised by the user before
+ * using the bulk regulator APIs.
+ * @consumer: The regulator consumer for the supply. This will be managed
+ * by the bulk API.
+ *
+ * The regulator APIs provide a series of regulator_bulk_() API calls as
+ * a convenience to consumers which require multiple supplies. This
+ * structure is used to manage data for these calls.
+ */
+struct regulator_bulk_data {
+ const char *supply;
+ struct regulator *consumer;
+};
+
+/**
* struct regulator_desc - Static regulator descriptor
*
* Each regulator registered with the core is described with a
@@ -136,6 +153,14 @@ int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev);
int regulator_map_voltage_iterate(struct regulator_dev *rdev,
int min_uV, int max_uV);
+int regulator_bulk_get(struct device_d *dev, int num_consumers,
+ struct regulator_bulk_data *consumers);
+int regulator_bulk_enable(int num_consumers,
+ struct regulator_bulk_data *consumers);
+int regulator_bulk_disable(int num_consumers,
+ struct regulator_bulk_data *consumers);
+void regulator_bulk_free(int num_consumers,
+ struct regulator_bulk_data *consumers);
/*
* Helper functions intended to be used by regulator drivers prior registering
@@ -166,6 +191,30 @@ static inline int regulator_set_voltage(struct regulator *regulator,
return 0;
}
+static inline int regulator_bulk_get(struct device_d *dev, int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ return 0;
+}
+
+static inline int regulator_bulk_enable(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ return 0;
+}
+
+static inline int regulator_bulk_disable(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ return 0;
+}
+
+static inline void regulator_bulk_free(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ return 0;
+}
+
#endif
#endif /* __REGULATOR_H */
diff --git a/include/reset_source.h b/include/reset_source.h
index 8795029315..023b1fe4a0 100644
--- a/include/reset_source.h
+++ b/include/reset_source.h
@@ -24,7 +24,7 @@ enum reset_src_type {
#ifdef CONFIG_RESET_SOURCE
enum reset_src_type reset_source_get(void);
-const char *reset_source_name(void);
+const char *reset_source_to_string(enum reset_src_type st);
int reset_source_get_instance(void);
struct device_d *reset_source_get_device(void);
@@ -41,7 +41,7 @@ static inline enum reset_src_type reset_source_get(void)
return RESET_UKWN;
}
-static inline const char *reset_source_name(void)
+static inline const char *reset_source_to_string(enum reset_src_type st)
{
return "unknown";
}
@@ -89,4 +89,9 @@ static inline void reset_source_set(enum reset_src_type type)
reset_source_set_priority(type, RESET_SOURCE_DEFAULT_PRIORITY);
}
+static inline const char *reset_source_name(void)
+{
+ return reset_source_to_string(reset_source_get());
+}
+
#endif /* __INCLUDE_RESET_SOURCE_H */