forked from mirrors/linux
		
	regulator: Add support for stm32 power regulators
Add support for 1V1 1V8 USB3V3 power regulators. Signed-off-by: Pascal Paillet <p.paillet@st.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
		
							parent
							
								
									c29687c354
								
							
						
					
					
						commit
						6cdae8173f
					
				
					 3 changed files with 198 additions and 0 deletions
				
			
		|  | @ -840,6 +840,13 @@ config REGULATOR_STM32_VREFBUF | |||
| 	  This driver can also be built as a module. If so, the module | ||||
| 	  will be called stm32-vrefbuf. | ||||
| 
 | ||||
| config REGULATOR_STM32_PWR | ||||
| 	bool "STMicroelectronics STM32 PWR" | ||||
| 	depends on ARCH_STM32 || COMPILE_TEST | ||||
| 	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 | ||||
|  |  | |||
|  | @ -105,6 +105,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o | |||
| obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o | ||||
| obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o | ||||
| obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o | ||||
| obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o | ||||
| obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o | ||||
|  |  | |||
							
								
								
									
										190
									
								
								drivers/regulator/stm32-pwr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								drivers/regulator/stm32-pwr.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,190 @@ | |||
| // SPDX-License-Identifier: GPL-2.0
 | ||||
| // Copyright (C) STMicroelectronics 2019
 | ||||
| // Authors: Gabriel Fernandez <gabriel.fernandez@st.com>
 | ||||
| //          Pascal Paillet <p.paillet@st.com>.
 | ||||
| 
 | ||||
| #include <linux/io.h> | ||||
| #include <linux/iopoll.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of_address.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/regulator/driver.h> | ||||
| #include <linux/regulator/of_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 | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
| 	const struct regulator_desc *desc; | ||||
| 	u32 ready_mask; | ||||
| }; | ||||
| 
 | ||||
| int stm32_pwr_reg_is_ready(struct regulator_dev *rdev) | ||||
| { | ||||
| 	struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	val = readl_relaxed(priv->base + REG_PWR_CR3); | ||||
| 
 | ||||
| 	return (val & priv->ready_mask); | ||||
| } | ||||
| 
 | ||||
| int stm32_pwr_reg_is_enabled(struct regulator_dev *rdev) | ||||
| { | ||||
| 	struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	val = readl_relaxed(priv->base + REG_PWR_CR3); | ||||
| 
 | ||||
| 	return (val & priv->desc->enable_mask); | ||||
| } | ||||
| 
 | ||||
| static int stm32_pwr_reg_enable(struct regulator_dev *rdev) | ||||
| { | ||||
| 	struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); | ||||
| 	int ret; | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	val = readl_relaxed(priv->base + REG_PWR_CR3); | ||||
| 	val |= priv->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, | ||||
| 				 100, 20 * 1000); | ||||
| 	if (ret) | ||||
| 		dev_err(&rdev->dev, "regulator enable timed out!\n"); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int stm32_pwr_reg_disable(struct regulator_dev *rdev) | ||||
| { | ||||
| 	struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); | ||||
| 	int ret; | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	val = readl_relaxed(priv->base + REG_PWR_CR3); | ||||
| 	val &= ~priv->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, | ||||
| 				 100, 20 * 1000); | ||||
| 	if (ret) | ||||
| 		dev_err(&rdev->dev, "regulator disable timed out!\n"); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct regulator_ops stm32_pwr_reg_ops = { | ||||
| 	.list_voltage	= regulator_list_voltage_linear, | ||||
| 	.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] = { \ | ||||
| 		.id = _id, \ | ||||
| 		.name = _name, \ | ||||
| 		.of_match = of_match_ptr(_name), \ | ||||
| 		.n_voltages = 1, \ | ||||
| 		.type = REGULATOR_VOLTAGE, \ | ||||
| 		.min_uV = _volt, \ | ||||
| 		.fixed_uV = _volt, \ | ||||
| 		.ops = &stm32_pwr_reg_ops, \ | ||||
| 		.enable_mask = _en, \ | ||||
| 		.owner = THIS_MODULE, \ | ||||
| 		.supply_name = _supply, \ | ||||
| 	} \ | ||||
| 
 | ||||
| static const 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 stm32_pwr_regulator_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct device_node *np = pdev->dev.of_node; | ||||
| 	struct stm32_pwr_reg *priv; | ||||
| 	void __iomem *base; | ||||
| 	struct regulator_dev *rdev; | ||||
| 	struct regulator_config config = { }; | ||||
| 	int i, ret = 0; | ||||
| 
 | ||||
| 	base = of_iomap(np, 0); | ||||
| 	if (IS_ERR(base)) { | ||||
| 		dev_err(&pdev->dev, "Unable to map IO memory\n"); | ||||
| 		return PTR_ERR(base); | ||||
| 	} | ||||
| 
 | ||||
| 	config.dev = &pdev->dev; | ||||
| 
 | ||||
| 	for (i = 0; i < STM32PWR_REG_NUM_REGS; i++) { | ||||
| 		priv = devm_kzalloc(&pdev->dev, sizeof(struct stm32_pwr_reg), | ||||
| 				    GFP_KERNEL); | ||||
| 		if (!priv) | ||||
| 			return -ENOMEM; | ||||
| 		priv->base = base; | ||||
| 		priv->desc = &stm32_pwr_desc[i]; | ||||
| 		priv->ready_mask = ready_mask_table[i]; | ||||
| 		config.driver_data = priv; | ||||
| 
 | ||||
| 		rdev = devm_regulator_register(&pdev->dev, | ||||
| 					       &stm32_pwr_desc[i], | ||||
| 					       &config); | ||||
| 		if (IS_ERR(rdev)) { | ||||
| 			ret = PTR_ERR(rdev); | ||||
| 			dev_err(&pdev->dev, | ||||
| 				"Failed to register regulator: %d\n", ret); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct of_device_id stm32_pwr_of_match[] = { | ||||
| 	{ .compatible = "st,stm32mp1,pwr-reg", }, | ||||
| 	{}, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, stm32_pwr_of_match); | ||||
| 
 | ||||
| static struct platform_driver stm32_pwr_driver = { | ||||
| 	.probe = stm32_pwr_regulator_probe, | ||||
| 	.driver = { | ||||
| 		.name  = "stm32-pwr-regulator", | ||||
| 		.of_match_table = of_match_ptr(stm32_pwr_of_match), | ||||
| 	}, | ||||
| }; | ||||
| module_platform_driver(stm32_pwr_driver); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("STM32MP1 PWR voltage regulator driver"); | ||||
| MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
		Loading…
	
		Reference in a new issue
	
	 Pascal PAILLET-LME
						Pascal PAILLET-LME