From 1670971dadf723ce3bb0e34c27fb7046e64fa74d Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Tue, 31 May 2022 12:05:37 +0200 Subject: [PATCH 16/22] ARM-5.15.24-stm32mp1-r1-PINCTRL-REGULATOR-SPI Signed-off-by: Christophe Priouzeau --- .../bindings/pinctrl/st,stm32-pinctrl.yaml | 8 + .../regulator/protection-consumer.txt | 23 ++ .../bindings/regulator/st,stm32-vrefbuf.yaml | 4 +- drivers/pinctrl/stm32/pinctrl-stm32.c | 201 +++++++++++++----- drivers/pinctrl/stm32/pinctrl-stm32.h | 19 +- drivers/pinctrl/stm32/pinctrl-stm32mp135.c | 3 +- drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 3 +- drivers/regulator/Kconfig | 11 + drivers/regulator/Makefile | 1 + drivers/regulator/protection-consumer.c | 137 ++++++++++++ drivers/regulator/scmi-regulator.c | 99 ++++++--- drivers/regulator/stm32-pwr.c | 85 +++++++- drivers/regulator/stm32-vrefbuf.c | 69 +++++- drivers/regulator/stpmic1_regulator.c | 182 ++++++++++++++-- drivers/spi/spi-stm32-qspi.c | 11 +- include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + 16 files changed, 724 insertions(+), 133 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/protection-consumer.txt create mode 100644 drivers/regulator/protection-consumer.c diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml index dfee6d38a..7348f40d4 100644 --- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml @@ -140,9 +140,13 @@ patternProperties: * ... * 16 : Alternate Function 15 * 17 : Analog + * 18 : Reserved To simplify the usage, macro is available to generate "pinmux" field. This macro is available here: - include/dt-bindings/pinctrl/stm32-pinfunc.h + Setting the pinmux's function to the Reserved (RSVD) value is used to inform + the driver that it shall not apply the mux setting. This can be used to + reserve some pins, for example to a co-processor not running Linux. Some examples of using macro: /* GPIO A9 set as alernate function 2 */ ... { @@ -156,6 +160,10 @@ patternProperties: ... { pinmux = ; }; + /* GPIO A9 reserved for co-processor */ + ... { + pinmux = ; + }; bias-disable: type: boolean diff --git a/Documentation/devicetree/bindings/regulator/protection-consumer.txt b/Documentation/devicetree/bindings/regulator/protection-consumer.txt new file mode 100644 index 000000000..bf8169e00 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/protection-consumer.txt @@ -0,0 +1,23 @@ +regulator protection bindings + + +Required properties: + compatible: "protection-consumer" + protection-supply: the phandle of the regulator to control + +Optional properties: +-------------------- + interrupt + + +Example: + + regulator_protection { + compatible = "protection-consumer"; + protection-supply = <&vdd>; + status = "okay"; + + interrupts = <15 2>; + interrupt-parent = <&gpiof>; + }; + diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.yaml b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.yaml index 3cd4a254e..fe9c5e83c 100644 --- a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.yaml +++ b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.yaml @@ -19,7 +19,9 @@ allOf: properties: compatible: - const: st,stm32-vrefbuf + enum: + - st,stm32-vrefbuf + - st,stm32mp13-vrefbuf reg: maxItems: 1 diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 8934b4878..271dcdbb5 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -43,6 +43,7 @@ #define STM32_GPIO_LCKR 0x1c #define STM32_GPIO_AFRL 0x20 #define STM32_GPIO_AFRH 0x24 +#define STM32_GPIO_SECCFGR 0x30 /* custom bitfield to backup pin status */ #define STM32_GPIO_BKP_MODE_SHIFT 0 @@ -73,6 +74,7 @@ static const char * const stm32_gpio_functions[] = { "af8", "af9", "af10", "af11", "af12", "af13", "af14", "af15", "analog", + "reserved", }; struct stm32_pinctrl_group { @@ -94,6 +96,7 @@ struct stm32_gpio_bank { u32 bank_ioport_nr; u32 pin_backup[STM32_GPIO_PINS_PER_BANK]; u8 irq_type[STM32_GPIO_PINS_PER_BANK]; + bool secure_control; }; struct stm32_pinctrl { @@ -115,6 +118,7 @@ struct stm32_pinctrl { u32 pkg; u16 irqmux_map; spinlock_t irqmux_lock; + u32 pin_base_shift; }; static inline int stm32_gpio_pin(int gpio) @@ -197,11 +201,7 @@ static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank, if (!value) offset += STM32_GPIO_PINS_PER_BANK; - clk_enable(bank->clk); - writel_relaxed(BIT(offset), bank->base + STM32_GPIO_BSRR); - - clk_disable(bank->clk); } static int stm32_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -228,15 +228,8 @@ static void stm32_gpio_free(struct gpio_chip *chip, unsigned offset) static int stm32_gpio_get(struct gpio_chip *chip, unsigned offset) { struct stm32_gpio_bank *bank = gpiochip_get_data(chip); - int ret; - - clk_enable(bank->clk); - - ret = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset)); - - clk_disable(bank->clk); - return ret; + return !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset)); } static void stm32_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -294,6 +287,33 @@ static int stm32_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) return ret; } +static int stm32_gpio_init_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct stm32_gpio_bank *bank = gpiochip_get_data(chip); + struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); + unsigned int i; + u32 sec; + + /* All gpio are valid per default */ + bitmap_fill(valid_mask, ngpios); + + if (bank->secure_control) { + /* Tag secured pins as invalid */ + sec = readl_relaxed(bank->base + STM32_GPIO_SECCFGR); + + for (i = 0; i < ngpios; i++) { + if (sec & BIT(i)) { + clear_bit(i, valid_mask); + dev_dbg(pctl->dev, "No access to gpio %d - %d\n", bank->bank_nr, i); + } + } + } + + return 0; +} + static const struct gpio_chip stm32_gpio_template = { .request = stm32_gpio_request, .free = stm32_gpio_free, @@ -304,6 +324,7 @@ static const struct gpio_chip stm32_gpio_template = { .to_irq = stm32_gpio_to_irq, .get_direction = stm32_gpio_get_direction, .set_config = gpiochip_generic_config, + .init_valid_mask = stm32_gpio_init_valid_mask, }; static void stm32_gpio_irq_trigger(struct irq_data *d) @@ -514,7 +535,7 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, u32 pin_num, u32 fnum) { - int i; + int i, k; for (i = 0; i < pctl->npins; i++) { const struct stm32_desc_pin *pin = pctl->pins + i; @@ -523,7 +544,10 @@ static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, if (pin->pin.number != pin_num) continue; - while (func && func->name) { + if (fnum == STM32_PIN_RSVD) + return true; + + for (k = 0; k < STM32_CONFIG_NUM; k++) { if (func->num == fnum) return true; func++; @@ -750,7 +774,6 @@ static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank, unsigned long flags; int err = 0; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); if (pctl->hwlock) { @@ -779,7 +802,6 @@ static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank, unlock: spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return err; } @@ -792,7 +814,6 @@ void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4; unsigned long flags; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); val = readl_relaxed(bank->base + alt_offset); @@ -804,7 +825,6 @@ void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, *mode = val >> (pin * 2); spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); } static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, @@ -829,6 +849,11 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, return -EINVAL; } + if (function == STM32_PIN_RSVD) { + dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n"); + return 0; + } + bank = gpiochip_get_data(range->gc); pin = stm32_gpio_pin(g->pin); @@ -848,12 +873,32 @@ static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, return stm32_pmx_set_mode(bank, pin, !input, 0); } +static int stm32_pmx_request(struct pinctrl_dev *pctldev, unsigned gpio) +{ + struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct pinctrl_gpio_range *range; + + range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, gpio); + if (!range) { + dev_err(pctl->dev, "No gpio range defined.\n"); + return -EINVAL; + } + + if (!gpiochip_line_is_valid(range->gc, stm32_gpio_pin(gpio))) { + dev_warn(pctl->dev, "Can't access gpio %d\n", gpio); + return -EACCES; + } + + return 0; +} + static const struct pinmux_ops stm32_pmx_ops = { .get_functions_count = stm32_pmx_get_funcs_cnt, .get_function_name = stm32_pmx_get_func_name, .get_function_groups = stm32_pmx_get_func_groups, .set_mux = stm32_pmx_set_mux, .gpio_set_direction = stm32_pmx_gpio_set_direction, + .request = stm32_pmx_request, .strict = true, }; @@ -867,7 +912,6 @@ static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank, u32 val; int err = 0; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); if (pctl->hwlock) { @@ -891,7 +935,6 @@ static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank, unlock: spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return err; } @@ -902,14 +945,12 @@ static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, unsigned long flags; u32 val; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); val = readl_relaxed(bank->base + STM32_GPIO_TYPER); val &= BIT(offset); spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return (val >> offset); } @@ -922,7 +963,6 @@ static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank, u32 val; int err = 0; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); if (pctl->hwlock) { @@ -946,7 +986,6 @@ static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank, unlock: spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return err; } @@ -957,14 +996,12 @@ static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, unsigned long flags; u32 val; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR); val &= GENMASK(offset * 2 + 1, offset * 2); spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return (val >> (offset * 2)); } @@ -977,7 +1014,6 @@ static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank, u32 val; int err = 0; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); if (pctl->hwlock) { @@ -1001,7 +1037,6 @@ static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank, unlock: spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return err; } @@ -1012,14 +1047,12 @@ static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank, unsigned long flags; u32 val; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); val = readl_relaxed(bank->base + STM32_GPIO_PUPDR); val &= GENMASK(offset * 2 + 1, offset * 2); spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return (val >> (offset * 2)); } @@ -1030,7 +1063,6 @@ static bool stm32_pconf_get(struct stm32_gpio_bank *bank, unsigned long flags; u32 val; - clk_enable(bank->clk); spin_lock_irqsave(&bank->lock, flags); if (dir) @@ -1041,7 +1073,6 @@ static bool stm32_pconf_get(struct stm32_gpio_bank *bank, BIT(offset)); spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); return val; } @@ -1064,6 +1095,11 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, bank = gpiochip_get_data(range->gc); offset = stm32_gpio_pin(pin); + if (!gpiochip_line_is_valid(range->gc, offset)) { + dev_warn(pctl->dev, "Can't access gpio %d\n", pin); + return -EACCES; + } + switch (param) { case PIN_CONFIG_DRIVE_PUSH_PULL: ret = stm32_pconf_set_driving(bank, offset, 0); @@ -1143,10 +1179,27 @@ static int stm32_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, return 0; } +static struct stm32_desc_pin * +stm32_pconf_get_pin_desc_by_pin_number(struct stm32_pinctrl *pctl, + unsigned int pin_number) +{ + struct stm32_desc_pin *pins = pctl->pins; + int i; + + for (i = 0; i < pctl->npins; i++) { + if (pins->pin.number == pin_number) + return pins; + pins++; + } + return NULL; +} + static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned int pin) { + struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + const struct stm32_desc_pin *pin_desc; struct pinctrl_gpio_range *range; struct stm32_gpio_bank *bank; int offset; @@ -1166,6 +1219,11 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, bank = gpiochip_get_data(range->gc); offset = stm32_gpio_pin(pin); + if (!gpiochip_line_is_valid(range->gc, offset)) { + seq_puts(s, "NO ACCESS"); + return; + } + stm32_pmx_get_mode(bank, offset, &mode, &alt); bias = stm32_pconf_get_bias(bank, offset); @@ -1196,7 +1254,12 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, case 2: drive = stm32_pconf_get_driving(bank, offset); speed = stm32_pconf_get_speed(bank, offset); - seq_printf(s, "%d - %s - %s - %s %s", alt, + pin_desc = stm32_pconf_get_pin_desc_by_pin_number(pctl, pin); + if (!pin_desc) + return; + + seq_printf(s, "%d (%s) - %s - %s - %s %s", alt, + pin_desc->functions[alt + 1].name, drive ? "open drain" : "push pull", biasing[bias], speeds[speed], "speed"); @@ -1237,9 +1300,9 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, if (IS_ERR(bank->base)) return PTR_ERR(bank->base); - err = clk_prepare(bank->clk); + err = clk_prepare_enable(bank->clk); if (err) { - dev_err(dev, "failed to prepare clk (%d)\n", err); + dev_err(dev, "failed to prepare_enable clk (%d)\n", err); return err; } @@ -1278,26 +1341,35 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, bank->gpio_chip.parent = dev; bank->bank_nr = bank_nr; bank->bank_ioport_nr = bank_ioport_nr; + bank->secure_control = pctl->match_data->secure_control; spin_lock_init(&bank->lock); - /* create irq hierarchical domain */ - bank->fwnode = of_node_to_fwnode(np); + if (pctl->domain) { + /* create irq hierarchical domain */ + bank->fwnode = of_node_to_fwnode(np); - bank->domain = irq_domain_create_hierarchy(pctl->domain, 0, - STM32_GPIO_IRQ_LINE, bank->fwnode, - &stm32_gpio_domain_ops, bank); + bank->domain = irq_domain_create_hierarchy(pctl->domain, 0, STM32_GPIO_IRQ_LINE, + bank->fwnode, &stm32_gpio_domain_ops, + bank); - if (!bank->domain) - return -ENODEV; + if (!bank->domain) { + err = -ENODEV; + goto err_clk; + } + } err = gpiochip_add_data(&bank->gpio_chip, bank); if (err) { dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_nr); - return err; + goto err_clk; } dev_info(dev, "%s bank added\n", bank->gpio_chip.label); return 0; + +err_clk: + clk_disable_unprepare(bank->clk); + return err; } static struct irq_domain *stm32_pctrl_get_irq_domain(struct device_node *np) @@ -1405,7 +1477,8 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, if (pctl->pkg && !(pctl->pkg & p->pkg)) continue; pins->pin = p->pin; - pins->functions = p->functions; + memcpy((struct stm32_desc_pin *)pins->functions, p->functions, + STM32_CONFIG_NUM * sizeof(struct stm32_desc_function)); pins++; nb_pins_available++; } @@ -1415,17 +1488,6 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, return 0; } -static void stm32_pctl_get_package(struct device_node *np, - struct stm32_pinctrl *pctl) -{ - if (of_property_read_u32(np, "st,package", &pctl->pkg)) { - pctl->pkg = 0; - dev_warn(pctl->dev, "No package detected, use default one\n"); - } else { - dev_dbg(pctl->dev, "package detected: %x\n", pctl->pkg); - } -} - int stm32_pctl_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1458,6 +1520,8 @@ int stm32_pctl_probe(struct platform_device *pdev) pctl->domain = stm32_pctrl_get_irq_domain(np); if (IS_ERR(pctl->domain)) return PTR_ERR(pctl->domain); + if (!pctl->domain) + dev_warn(dev, "pinctrl without interrupt support\n"); /* hwspinlock is optional */ hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); @@ -1473,8 +1537,9 @@ int stm32_pctl_probe(struct platform_device *pdev) pctl->dev = dev; pctl->match_data = match->data; - /* get package information */ - stm32_pctl_get_package(np, pctl); + /* get optional package information */ + if (!of_property_read_u32(np, "st,package", &pctl->pkg)) + dev_dbg(pctl->dev, "package detected: %x\n", pctl->pkg); pctl->pins = devm_kcalloc(pctl->dev, pctl->match_data->npins, sizeof(*pctl->pins), GFP_KERNEL); @@ -1514,6 +1579,7 @@ int stm32_pctl_probe(struct platform_device *pdev) pctl->pctl_desc.pctlops = &stm32_pctrl_ops; pctl->pctl_desc.pmxops = &stm32_pmx_ops; pctl->dev = &pdev->dev; + pctl->pin_base_shift = pctl->match_data->pin_base_shift; pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, pctl); @@ -1566,6 +1632,10 @@ int stm32_pctl_probe(struct platform_device *pdev) ret = stm32_gpiolib_register_bank(pctl, child); if (ret) { of_node_put(child); + + for (i = 0; i < pctl->nbanks; i++) + clk_disable_unprepare(pctl->banks[i].clk); + return ret; } @@ -1592,6 +1662,9 @@ static int __maybe_unused stm32_pinctrl_restore_gpio_regs( if (!range) return 0; + if (!gpiochip_line_is_valid(range->gc, offset)) + return 0; + pin_is_irq = gpiochip_line_is_irq(range->gc, offset); if (!desc || (!pin_is_irq && !desc->gpio_owner)) @@ -1638,12 +1711,26 @@ static int __maybe_unused stm32_pinctrl_restore_gpio_regs( return 0; } +int __maybe_unused stm32_pinctrl_suspend(struct device *dev) +{ + struct stm32_pinctrl *pctl = dev_get_drvdata(dev); + int i; + + for (i = 0; i < pctl->nbanks; i++) + clk_disable(pctl->banks[i].clk); + + return 0; +} + int __maybe_unused stm32_pinctrl_resume(struct device *dev) { struct stm32_pinctrl *pctl = dev_get_drvdata(dev); struct stm32_pinctrl_group *g = pctl->groups; int i; + for (i = 0; i < pctl->nbanks; i++) + clk_enable(pctl->banks[i].clk); + for (i = 0; i < pctl->ngroups; i++, g++) stm32_pinctrl_restore_gpio_regs(pctl, g->pin); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h index b0882d120..319dff763 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.h +++ b/drivers/pinctrl/stm32/pinctrl-stm32.h @@ -17,6 +17,8 @@ #define STM32_PIN_GPIO 0 #define STM32_PIN_AF(x) ((x) + 1) #define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1) +#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1) +#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1) /* package information */ #define STM32MP_PKG_AA BIT(0) @@ -24,6 +26,8 @@ #define STM32MP_PKG_AC BIT(2) #define STM32MP_PKG_AD BIT(3) +#define STM32MP157_Z_BASE_SHIFT 400 + struct stm32_desc_function { const char *name; const unsigned char num; @@ -31,26 +35,26 @@ struct stm32_desc_function { struct stm32_desc_pin { struct pinctrl_pin_desc pin; - const struct stm32_desc_function *functions; + const struct stm32_desc_function functions[STM32_CONFIG_NUM]; const unsigned int pkg; }; #define STM32_PIN(_pin, ...) \ { \ .pin = _pin, \ - .functions = (struct stm32_desc_function[]){ \ - __VA_ARGS__, { } }, \ + .functions = { \ + __VA_ARGS__}, \ } #define STM32_PIN_PKG(_pin, _pkg, ...) \ { \ .pin = _pin, \ .pkg = _pkg, \ - .functions = (struct stm32_desc_function[]){ \ - __VA_ARGS__, { } }, \ + .functions = { \ + __VA_ARGS__}, \ } #define STM32_FUNCTION(_num, _name) \ - { \ + [_num] = { \ .num = _num, \ .name = _name, \ } @@ -58,6 +62,8 @@ struct stm32_desc_pin { struct stm32_pinctrl_match_data { const struct stm32_desc_pin *pins; const unsigned int npins; + bool secure_control; + const unsigned int pin_base_shift; }; struct stm32_gpio_bank; @@ -65,6 +71,7 @@ struct stm32_gpio_bank; int stm32_pctl_probe(struct platform_device *pdev); void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, u32 *alt); +int stm32_pinctrl_suspend(struct device *dev); int stm32_pinctrl_resume(struct device *dev); #endif /* __PINCTRL_STM32_H */ diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp135.c b/drivers/pinctrl/stm32/pinctrl-stm32mp135.c index 4ab03520c..fde1df191 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32mp135.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32mp135.c @@ -1649,6 +1649,7 @@ static const struct stm32_desc_pin stm32mp135_pins[] = { static struct stm32_pinctrl_match_data stm32mp135_match_data = { .pins = stm32mp135_pins, .npins = ARRAY_SIZE(stm32mp135_pins), + .secure_control = true, }; static const struct of_device_id stm32mp135_pctrl_match[] = { @@ -1660,7 +1661,7 @@ static const struct of_device_id stm32mp135_pctrl_match[] = { }; static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume) + SET_LATE_SYSTEM_SLEEP_PM_OPS(stm32_pinctrl_suspend, stm32_pinctrl_resume) }; static struct platform_driver stm32mp135_pinctrl_driver = { diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c index 2ccb99d64..2d4f8c1e6 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c @@ -2328,6 +2328,7 @@ static struct stm32_pinctrl_match_data stm32mp157_match_data = { static struct stm32_pinctrl_match_data stm32mp157_z_match_data = { .pins = stm32mp157_z_pins, .npins = ARRAY_SIZE(stm32mp157_z_pins), + .pin_base_shift = STM32MP157_Z_BASE_SHIFT, }; static const struct of_device_id stm32mp157_pctrl_match[] = { @@ -2343,7 +2344,7 @@ static const struct of_device_id stm32mp157_pctrl_match[] = { }; static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume) + SET_LATE_SYSTEM_SLEEP_PM_OPS(stm32_pinctrl_suspend, stm32_pinctrl_resume) }; static struct platform_driver stm32mp157_pinctrl_driver = { diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4fd13b062..285931c18 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -37,6 +37,17 @@ config REGULATOR_FIXED_VOLTAGE useful for systems which use a combination of software managed regulators and simple non-configurable regulators. +config REGULATOR_PROTECTION_CONSUMER + tristate "Regulator protection consumer" + depends on OF + help + This driver handles regulator over-current detection in order to + protect regulators from crashing. In case of over-current event + or any IRQ, the protection consumer forces disable the regulator + that was declared as supply. + + If unsure, say no. + config REGULATOR_VIRTUAL_CONSUMER tristate "Virtual regulator consumer support" help diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 9e382b50a..543e04fa2 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o irq_helpers.o obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o +obj-$(CONFIG_REGULATOR_PROTECTION_CONSUMER) += protection-consumer.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o diff --git a/drivers/regulator/protection-consumer.c b/drivers/regulator/protection-consumer.c new file mode 100644 index 000000000..a4d299f85 --- /dev/null +++ b/drivers/regulator/protection-consumer.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2021 +// Author: Pascal Paillet for STMicroelectronics. + +#include +#include +#include +#include +#include +#include + +/** + * struct protection_data - regulator driver data + * @reg: regulator consumer structure + * @nb: notifier_block structure + * @dev: device driver + */ +struct protection_data { + struct regulator *reg; + struct notifier_block nb; + struct device *dev; +}; + +/** + * protection_irq_handler() - irq handler + * @irq: irq number + * @dev: struct protection_data + * + * force disable the regulator + */ +static irqreturn_t protection_irq_handler(int irq, void *dev) +{ + struct protection_data *protection = (struct protection_data *)dev; + + dev_warn(protection->dev, "Interrupt received on regulator\n"); + if (regulator_is_enabled(protection->reg)) + regulator_force_disable(protection->reg); + + return IRQ_HANDLED; +} + +/** + * regulator_event() - regulator framework callback + * @nb: notifier_block + * @event: regulator framework event + * @data: struct protection_data + * + * force disable the regulator in case of regulator event + * + * Return: 0 for successful probe else appropriate error + */ +static int regulator_event(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct protection_data *protection = + container_of(nb, struct protection_data, nb); + + if ((event & REGULATOR_EVENT_OVER_CURRENT) || + (event & REGULATOR_EVENT_OVER_TEMP)) { + dev_warn(protection->dev, "Event received on regulator\n"); + if (regulator_is_enabled(protection->reg)) + regulator_force_disable(protection->reg); + } + + return 0; +} + +/** + * protection_probe() - probe + * @pdev: platform_device + * + * Return: 0 for successful probe else appropriate error + */ +static int protection_probe(struct platform_device *pdev) +{ + struct protection_data *protection; + int irq, ret; + + protection = devm_kzalloc(&pdev->dev, sizeof(struct protection_data), GFP_KERNEL); + if (!protection) + return -ENOMEM; + + protection->dev = &pdev->dev; + + protection->reg = devm_regulator_get(&pdev->dev, "protection"); + if (IS_ERR(protection->reg)) + return PTR_ERR(protection->reg); + + protection->nb.notifier_call = regulator_event; + ret = devm_regulator_register_notifier(protection->reg, &protection->nb); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register regulator notifier: %d\n", ret); + return ret; + } + + /* irq is optional, the driver can be used with regulator events */ + irq = platform_get_irq_optional(pdev, 0); + if (irq <= 0 && (irq != -ENXIO)) + return irq ? : -ENOENT; + + if (irq > 0) { + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + protection_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + pdev->name, protection); + if (ret) { + dev_err(&pdev->dev, "Request IRQ failed\n"); + return ret; + } + } + platform_set_drvdata(pdev, protection); + dev_dbg(&pdev->dev, "protection probed\n"); + + return 0; +} + +static const struct of_device_id protection_dt_match[] = { + { .compatible = "protection-consumer" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, protection_dt_match); + +static struct platform_driver protection_driver = { + .driver = { + .name = "protection-consumer", + .owner = THIS_MODULE, + .of_match_table = protection_dt_match, + }, + .probe = protection_probe, +}; + +module_platform_driver(protection_driver); + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("protection consumer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c index 1f02f60ad..dffd9f5ce 100644 --- a/drivers/regulator/scmi-regulator.c +++ b/drivers/regulator/scmi-regulator.c @@ -219,10 +219,11 @@ static int scmi_regulator_common_init(struct scmi_regulator *sreg) */ if (vinfo->negative_volts_allowed) { dev_warn(dev, "Negative voltages NOT supported...skip %s\n", - sreg->of_node->full_name); + vinfo->name); return -EOPNOTSUPP; } + sreg->desc.name = devm_kasprintf(dev, GFP_KERNEL, "%s", vinfo->name); if (!sreg->desc.name) return -ENOMEM; @@ -230,8 +231,6 @@ static int scmi_regulator_common_init(struct scmi_regulator *sreg) sreg->desc.id = sreg->id; sreg->desc.type = REGULATOR_VOLTAGE; sreg->desc.owner = THIS_MODULE; - sreg->desc.of_match_full_name = true; - sreg->desc.of_match = sreg->of_node->full_name; sreg->desc.regulators_node = "regulators"; if (vinfo->segmented) ret = scmi_config_linear_regulator_mappings(sreg, vinfo); @@ -239,7 +238,6 @@ static int scmi_regulator_common_init(struct scmi_regulator *sreg) ret = scmi_config_discrete_regulator_mappings(sreg, vinfo); if (ret) return ret; - /* * Using the scmi device here to have DT searched from Voltage * protocol node down. @@ -252,40 +250,59 @@ static int scmi_regulator_common_init(struct scmi_regulator *sreg) return 0; } +static int scmi_find_domain_from_name(struct scmi_device *sdev, + struct device_node *np, + struct scmi_regulator_info *rinfo, + u32 *dom) +{ + const char *name = of_get_property(np, "voltd-name", NULL); + int d; + + if (!name) + return -EINVAL; + + for (d = 0; d < rinfo->num_doms; d++) { + struct scmi_regulator *sreg = rinfo->sregv[d]; + + if (!sreg || !sreg->desc.name || strcmp(sreg->desc.name, name)) + continue; + + *dom=d; + return 0; + } + + dev_warn(&sdev->dev, "scmi voltage domain %s not found\n", name); + return -ENODEV; +} + static int process_scmi_regulator_of_node(struct scmi_device *sdev, - struct scmi_protocol_handle *ph, struct device_node *np, struct scmi_regulator_info *rinfo) { u32 dom, ret; ret = of_property_read_u32(np, "reg", &dom); - if (ret) - return ret; + if (ret == -EINVAL) { + ret = scmi_find_domain_from_name(sdev, np, rinfo, &dom); + if (ret < 0) { + return ret; + } + } if (dom >= rinfo->num_doms) return -ENODEV; - if (rinfo->sregv[dom]) { - dev_err(&sdev->dev, - "SCMI Voltage Domain %d already in use. Skipping: %s\n", - dom, np->full_name); - return -EINVAL; - } - - rinfo->sregv[dom] = devm_kzalloc(&sdev->dev, - sizeof(struct scmi_regulator), - GFP_KERNEL); if (!rinfo->sregv[dom]) - return -ENOMEM; + return -EINVAL; rinfo->sregv[dom]->id = dom; rinfo->sregv[dom]->sdev = sdev; - rinfo->sregv[dom]->ph = ph; /* get hold of good nodes */ of_node_get(np); rinfo->sregv[dom]->of_node = np; + rinfo->sregv[dom]->desc.of_match_full_name = true; + rinfo->sregv[dom]->desc.of_match = rinfo->sregv[dom]->of_node->name; dev_dbg(&sdev->dev, "Found SCMI Regulator entry -- OF node [%d] -> %s\n", @@ -338,21 +355,38 @@ static int scmi_regulator_probe(struct scmi_device *sdev) rinfo->num_doms = num_doms; /* - * Start collecting into rinfo->sregv possibly good SCMI Regulators as - * described by a well-formed DT entry and associated with an existing - * plausible SCMI Voltage Domain number, all belonging to this SCMI - * platform instance node (handle->dev->of_node). + * Start collecting into rinfo->sregv for each regulator that we + * can successfully reach via SCMI. */ - np = of_find_node_by_name(handle->dev->of_node, "regulators"); - for_each_child_of_node(np, child) { - ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo); - /* abort on any mem issue */ - if (ret == -ENOMEM) { - of_node_put(child); - return ret; + for (d = 0; d < num_doms; d++) { + struct scmi_regulator *sreg; + + sreg = devm_kzalloc(&sdev->dev, sizeof(struct scmi_regulator), + GFP_KERNEL); + if (!sreg) + return -ENOMEM; + + sreg->sdev = sdev; + sreg->id = d; + sreg->ph = ph; + + ret = scmi_regulator_common_init(sreg); + if (ret) { + devm_kfree(&sdev->dev, sreg); + continue; } + + rinfo->sregv[d] = sreg; } + /* + * Map each DT entry with an existing SCMI Voltage Domain number + * all belonging to this SCMI platform instance node (handle->dev->of_node). + */ + np = of_find_node_by_name(handle->dev->of_node, "regulators"); + for_each_child_of_node(np, child) + process_scmi_regulator_of_node(sdev, child, rinfo); + /* * Register a regulator for each valid regulator-DT-entry that we * can successfully reach via SCMI and has a valid associated voltage @@ -365,9 +399,8 @@ static int scmi_regulator_probe(struct scmi_device *sdev) if (!sreg) continue; - ret = scmi_regulator_common_init(sreg); - /* Skip invalid voltage domains */ - if (ret) + /* Skip if not described in the device-tree */ + if (!sreg->of_node) continue; sreg->rdev = devm_regulator_register(&sdev->dev, &sreg->desc, diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c index 2a42acb7c..2b328b970 100644 --- a/drivers/regulator/stm32-pwr.c +++ b/drivers/regulator/stm32-pwr.c @@ -3,12 +3,15 @@ // Authors: Gabriel Fernandez // Pascal Paillet . +#include #include #include +#include #include #include #include #include +#include #include #include @@ -24,6 +27,11 @@ #define REG_1_1_EN BIT(30) #define REG_1_1_RDY BIT(31) +#define STM32_SMC_PWR 0x82001001 +#define STM32_WRITE 0x1 +#define STM32_SMC_REG_SET 0x2 +#define STM32_SMC_REG_CLEAR 0x3 + /* list of supported regulators */ enum { PWR_REG11, @@ -39,10 +47,18 @@ static u32 ready_mask_table[STM32PWR_REG_NUM_REGS] = { }; struct stm32_pwr_reg { + int tzen; void __iomem *base; u32 ready_mask; }; +#define SMC(class, op, address, val)\ + ({\ + struct arm_smccc_res res;\ + arm_smccc_smc(class, op, address, val,\ + 0, 0, 0, 0, &res);\ + }) + static int stm32_pwr_reg_is_ready(struct regulator_dev *rdev) { struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); @@ -69,9 +85,15 @@ static int stm32_pwr_reg_enable(struct regulator_dev *rdev) int ret; u32 val; - val = readl_relaxed(priv->base + REG_PWR_CR3); - val |= rdev->desc->enable_mask; - writel_relaxed(val, priv->base + REG_PWR_CR3); + if (priv->tzen) { + SMC(STM32_SMC_PWR, STM32_SMC_REG_SET, REG_PWR_CR3, + rdev->desc->enable_mask); + } else { + val = readl_relaxed(priv->base + REG_PWR_CR3); + val |= rdev->desc->enable_mask; + writel_relaxed(val, priv->base + REG_PWR_CR3); + } + /* use an arbitrary timeout of 20ms */ ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, val, @@ -88,9 +110,14 @@ static int stm32_pwr_reg_disable(struct regulator_dev *rdev) int ret; u32 val; - val = readl_relaxed(priv->base + REG_PWR_CR3); - val &= ~rdev->desc->enable_mask; - writel_relaxed(val, priv->base + REG_PWR_CR3); + if (priv->tzen) { + SMC(STM32_SMC_PWR, STM32_SMC_REG_CLEAR, REG_PWR_CR3, + rdev->desc->enable_mask); + } else { + val = readl_relaxed(priv->base + REG_PWR_CR3); + val &= ~rdev->desc->enable_mask; + writel_relaxed(val, priv->base + REG_PWR_CR3); + } /* use an arbitrary timeout of 20ms */ ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, !val, @@ -121,12 +148,50 @@ static const struct regulator_ops stm32_pwr_reg_ops = { .supply_name = _supply, \ } \ -static const struct regulator_desc stm32_pwr_desc[] = { +static struct regulator_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 is_stm32_soc_secured(struct platform_device *pdev, int *val) +{ + struct device_node *np = pdev->dev.of_node; + struct regmap *syscon; + u32 reg, mask; + int tzc_val = 0; + int err; + + syscon = syscon_regmap_lookup_by_phandle(np, "st,tzcr"); + if (IS_ERR(syscon)) { + if (PTR_ERR(syscon) != -EPROBE_DEFER) + dev_err(&pdev->dev, "tzcr syscon required\n"); + return PTR_ERR(syscon); + } + + err = of_property_read_u32_index(np, "st,tzcr", 1, ®); + if (err) { + dev_err(&pdev->dev, "tzcr offset required !\n"); + return err; + } + + err = of_property_read_u32_index(np, "st,tzcr", 2, &mask); + if (err) { + dev_err(&pdev->dev, "tzcr mask required !\n"); + return err; + } + + err = regmap_read(syscon, reg, &tzc_val); + if (err) { + dev_err(&pdev->dev, "failed to read tzcr status !\n"); + return err; + } + + *val = tzc_val & mask; + + return 0; +} + static int stm32_pwr_regulator_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -135,6 +200,11 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct regulator_config config = { }; int i, ret = 0; + int tzen = 0; + + ret = is_stm32_soc_secured(pdev, &tzen); + if (ret) + return ret; base = of_iomap(np, 0); if (!base) { @@ -149,6 +219,7 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) GFP_KERNEL); if (!priv) return -ENOMEM; + priv->tzen = tzen; priv->base = base; priv->ready_mask = ready_mask_table[i]; config.driver_data = priv; diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c index 161622ea7..d7eb7607b 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -31,6 +31,7 @@ struct stm32_vrefbuf { void __iomem *base; struct clk *clk; struct device *dev; + u32 backup_val; }; static const unsigned int stm32_vrefbuf_voltages[] = { @@ -38,6 +39,11 @@ static const unsigned int stm32_vrefbuf_voltages[] = { 2500000, 2048000, 1800000, 1500000, }; +static const unsigned int stm32mp13_vrefbuf_voltages[] = { + /* Matches resp. VRS = 000b, 001b, 010b, 011b */ + 2500000, 2048000, 1800000, 1650000, +}; + static int stm32_vrefbuf_enable(struct regulator_dev *rdev) { struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); @@ -180,11 +186,24 @@ static const struct regulator_desc stm32_vrefbuf_regu = { .owner = THIS_MODULE, }; +static const struct regulator_desc stm32mp13_vrefbuf_regu = { + .name = "vref", + .supply_name = "vdda", + .volt_table = stm32mp13_vrefbuf_voltages, + .n_voltages = ARRAY_SIZE(stm32mp13_vrefbuf_voltages), + .ops = &stm32_vrefbuf_volt_ops, + .off_on_delay = 1000, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + static int stm32_vrefbuf_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct stm32_vrefbuf *priv; struct regulator_config config = { }; struct regulator_dev *rdev; + const struct regulator_desc *desc; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -213,14 +232,19 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) goto err_pm_stop; } + desc = (const struct regulator_desc *) + of_match_device(dev->driver->of_match_table, dev)->data; + if (!desc) + return -EINVAL; + config.dev = &pdev->dev; config.driver_data = priv; config.of_node = pdev->dev.of_node; config.init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, - &stm32_vrefbuf_regu); + desc); - rdev = regulator_register(&stm32_vrefbuf_regu, &config); + rdev = regulator_register(desc, &config); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&pdev->dev, "register failed with error %d\n", ret); @@ -276,16 +300,51 @@ static int __maybe_unused stm32_vrefbuf_runtime_resume(struct device *dev) return clk_prepare_enable(priv->clk); } +#if defined(CONFIG_PM_SLEEP) +static int stm32_vrefbuf_suspend(struct device *dev) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); + int ret; + + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); + return ret; + } + + priv->backup_val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + + return pm_runtime_force_suspend(dev); +} + +static int stm32_vrefbuf_resume(struct device *dev) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + + writel_relaxed(priv->backup_val, priv->base + STM32_VREFBUF_CSR); + + return 0; +} +#endif + static const struct dev_pm_ops stm32_vrefbuf_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SET_SYSTEM_SLEEP_PM_OPS(stm32_vrefbuf_suspend, + stm32_vrefbuf_resume) SET_RUNTIME_PM_OPS(stm32_vrefbuf_runtime_suspend, stm32_vrefbuf_runtime_resume, NULL) }; static const struct of_device_id __maybe_unused stm32_vrefbuf_of_match[] = { - { .compatible = "st,stm32-vrefbuf", }, + { .compatible = "st,stm32-vrefbuf", .data = (void *)&stm32_vrefbuf_regu }, + { .compatible = "st,stm32mp13-vrefbuf", .data = (void *)&stm32mp13_vrefbuf_regu }, {}, }; MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match); diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c index 2d7597c76..c2cddba6d 100644 --- a/drivers/regulator/stpmic1_regulator.c +++ b/drivers/regulator/stpmic1_regulator.c @@ -2,7 +2,9 @@ // Copyright (C) STMicroelectronics 2018 // Author: Pascal Paillet for STMicroelectronics. +#include #include +#include #include #include #include @@ -30,11 +32,27 @@ struct stpmic1_regulator_cfg { u8 icc_mask; }; +/** + * struct boost_data - this structure is used as driver data for the usb boost + * @boost_rdev: device for boost regulator + * @vbus_otg_rdev: device for vbus_otg regulator + * @sw_out_rdev: device for sw_out regulator + * @occ_timeout: overcurrent detection timeout + */ +struct boost_data { + struct regulator_dev *boost_rdev; + struct regulator_dev *vbus_otg_rdev; + struct regulator_dev *sw_out_rdev; + ktime_t occ_timeout; +}; + static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity, bool enable); static unsigned int stpmic1_map_mode(unsigned int mode); +static int regulator_enable_boost(struct regulator_dev *rdev); +static int regulator_disable_boost(struct regulator_dev *rdev); enum { STPMIC1_BUCK1 = 0, @@ -182,8 +200,8 @@ static const struct regulator_ops stpmic1_vref_ddr_ops = { static const struct regulator_ops stpmic1_boost_regul_ops = { .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, + .enable = regulator_enable_boost, + .disable = regulator_disable_boost, .set_over_current_protection = stpmic1_set_icc, }; @@ -529,6 +547,79 @@ static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static int regulator_enable_boost(struct regulator_dev *rdev) +{ + struct boost_data *usb_data = rdev_get_drvdata(rdev); + + usb_data->occ_timeout = ktime_add_us(ktime_get(), 100000); + + return regulator_enable_regmap(rdev); +} + +static int regulator_disable_boost(struct regulator_dev *rdev) +{ + struct boost_data *usb_data = rdev_get_drvdata(rdev); + + usb_data->occ_timeout = 0; + + return regulator_disable_regmap(rdev); +} + +static void stpmic1_reset_boost(struct boost_data *usb_data) +{ + int otg_on = 0; + int sw_out_on = 0; + + dev_dbg(rdev_get_dev(usb_data->boost_rdev), "reset usb boost\n"); + + /* the boost was actually disabled by the over-current protection */ + regulator_disable_regmap(usb_data->boost_rdev); + + if (usb_data->vbus_otg_rdev) + otg_on = regulator_is_enabled_regmap(usb_data->vbus_otg_rdev); + if (otg_on) + regulator_disable_regmap(usb_data->vbus_otg_rdev); + + if (usb_data->sw_out_rdev) + sw_out_on = regulator_is_enabled_regmap(usb_data->sw_out_rdev); + if (sw_out_on) + regulator_disable_regmap(usb_data->sw_out_rdev); + + regulator_enable_regmap(usb_data->boost_rdev); + + /* sleep at least 5ms */ + usleep_range(5000, 10000); + + if (otg_on) + regulator_enable_regmap(usb_data->vbus_otg_rdev); + + if (sw_out_on) + regulator_enable_regmap(usb_data->sw_out_rdev); + +} + +static irqreturn_t stpmic1_boost_irq_handler(int irq, void *data) +{ + struct boost_data *usb_data = (struct boost_data *)data; + + dev_dbg(rdev_get_dev(usb_data->boost_rdev), "usb boost irq handler\n"); + + /* overcurrent detected on boost after timeout */ + if (usb_data->occ_timeout != 0 && + ktime_compare(ktime_get(), usb_data->occ_timeout) > 0) { + /* reset usb boost and usb power switches */ + stpmic1_reset_boost(usb_data); + return IRQ_HANDLED; + } + + /* Send an overcurrent notification */ + regulator_notifier_call_chain(usb_data->boost_rdev, + REGULATOR_EVENT_OVER_CURRENT, + NULL); + + return IRQ_HANDLED; +} + #define MATCH(_name, _id) \ [STPMIC1_##_id] = { \ .name = #_name, \ @@ -552,9 +643,10 @@ static struct of_regulator_match stpmic1_matches[] = { MATCH(pwr_sw2, SW_OUT), }; -static int stpmic1_regulator_register(struct platform_device *pdev, int id, - struct of_regulator_match *match, - const struct stpmic1_regulator_cfg *cfg) +static struct regulator_dev * +stpmic1_regulator_register(struct platform_device *pdev, int id, + struct of_regulator_match *match, + const struct stpmic1_regulator_cfg *cfg) { struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); struct regulator_dev *rdev; @@ -572,7 +664,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", cfg->desc.name); - return PTR_ERR(rdev); + return rdev; } /* set mask reset */ @@ -584,7 +676,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, cfg->mask_reset_mask); if (ret) { dev_err(&pdev->dev, "set mask reset failed\n"); - return ret; + return ERR_PTR(ret); } } @@ -598,15 +690,60 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, pdev->name, rdev); if (ret) { dev_err(&pdev->dev, "Request IRQ failed\n"); - return ret; + return ERR_PTR(ret); } } - return 0; + + return rdev; +} + +static struct regulator_dev * +stpmic1_boost_register(struct platform_device *pdev, int id, + struct of_regulator_match *match, + const struct stpmic1_regulator_cfg *cfg, + struct boost_data *usb_data) +{ + struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); + struct regulator_dev *rdev; + struct regulator_config config = {}; + int ret = 0; + int irq; + + config.dev = &pdev->dev; + config.init_data = match->init_data; + config.of_node = match->of_node; + config.regmap = pmic_dev->regmap; + config.driver_data = (void *)usb_data; + + rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s regulator\n", + cfg->desc.name); + return rdev; + } + + /* setup an irq handler for over-current detection */ + irq = of_irq_get(config.of_node, 0); + if (irq > 0) { + ret = devm_request_threaded_irq(&pdev->dev, + irq, NULL, + stpmic1_boost_irq_handler, + IRQF_ONESHOT, pdev->name, + usb_data); + if (ret) { + dev_err(&pdev->dev, "Request IRQ failed\n"); + return ERR_PTR(ret); + } + } + + return rdev; } static int stpmic1_regulator_probe(struct platform_device *pdev) { int i, ret; + struct boost_data *usb_data; + struct regulator_dev *rdev; ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, ARRAY_SIZE(stpmic1_matches)); @@ -616,11 +753,30 @@ static int stpmic1_regulator_probe(struct platform_device *pdev) return ret; } + usb_data = devm_kzalloc(&pdev->dev, sizeof(*usb_data), GFP_KERNEL); + if (!usb_data) + return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { - ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], - &stpmic1_regulator_cfgs[i]); - if (ret < 0) - return ret; + if (i == STPMIC1_BOOST) { + rdev = + stpmic1_boost_register(pdev, i, &stpmic1_matches[i], + &stpmic1_regulator_cfgs[i], + usb_data); + + usb_data->boost_rdev = rdev; + } else { + rdev = + stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], + &stpmic1_regulator_cfgs[i]); + + if (i == STPMIC1_VBUS_OTG) + usb_data->vbus_otg_rdev = rdev; + else if (i == STPMIC1_SW_OUT) + usb_data->sw_out_rdev = rdev; + } + if (IS_ERR(rdev)) + return PTR_ERR(rdev); } dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index ffdc55f87..1948a0090 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -305,10 +305,8 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, u32 cr, sr; int err = 0; - if (!op->data.nbytes) - goto wait_nobusy; - - if (readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) + if ((readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) || + qspi->fmode == CCR_FMODE_APM) goto out; reinit_completion(&qspi->data_completion); @@ -327,7 +325,6 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, out: /* clear flags */ writel_relaxed(FCR_CTCF | FCR_CTEF, qspi->io_base + QSPI_FCR); -wait_nobusy: if (!err) err = stm32_qspi_wait_nobusy(qspi); @@ -372,10 +369,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) op->dummy.buswidth, op->data.buswidth, op->addr.val, op->data.nbytes); - err = stm32_qspi_wait_nobusy(qspi); - if (err) - goto abort; - cr = readl_relaxed(qspi->io_base + QSPI_CR); cr &= ~CR_PRESC_MASK & ~CR_FSEL; cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h index e6fb8ada3..370a25a93 100644 --- a/include/dt-bindings/pinctrl/stm32-pinfunc.h +++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h @@ -26,6 +26,7 @@ #define AF14 0xf #define AF15 0x10 #define ANALOG 0x11 +#define RSVD 0x12 /* define Pins number*/ #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) -- 2.25.1