Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc2 202 lines 5.4 kB view raw
1/* 2 * Copyright (C) STMicroelectronics 2017 3 * 4 * Author: Fabrice Gasnier <fabrice.gasnier@st.com> 5 * 6 * License terms: GNU General Public License (GPL), version 2 7 */ 8 9#include <linux/bitfield.h> 10#include <linux/clk.h> 11#include <linux/io.h> 12#include <linux/iopoll.h> 13#include <linux/module.h> 14#include <linux/of_device.h> 15#include <linux/platform_device.h> 16#include <linux/regulator/driver.h> 17#include <linux/regulator/of_regulator.h> 18 19/* STM32 VREFBUF registers */ 20#define STM32_VREFBUF_CSR 0x00 21 22/* STM32 VREFBUF CSR bitfields */ 23#define STM32_VRS GENMASK(6, 4) 24#define STM32_VRR BIT(3) 25#define STM32_HIZ BIT(1) 26#define STM32_ENVR BIT(0) 27 28struct stm32_vrefbuf { 29 void __iomem *base; 30 struct clk *clk; 31}; 32 33static const unsigned int stm32_vrefbuf_voltages[] = { 34 /* Matches resp. VRS = 000b, 001b, 010b, 011b */ 35 2500000, 2048000, 1800000, 1500000, 36}; 37 38static int stm32_vrefbuf_enable(struct regulator_dev *rdev) 39{ 40 struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); 41 u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); 42 int ret; 43 44 val = (val & ~STM32_HIZ) | STM32_ENVR; 45 writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); 46 47 /* 48 * Vrefbuf startup time depends on external capacitor: wait here for 49 * VRR to be set. That means output has reached expected value. 50 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as 51 * arbitrary timeout. 52 */ 53 ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val, 54 val & STM32_VRR, 650, 10000); 55 if (ret) { 56 dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n"); 57 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); 58 val = (val & ~STM32_ENVR) | STM32_HIZ; 59 writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); 60 } 61 62 return ret; 63} 64 65static int stm32_vrefbuf_disable(struct regulator_dev *rdev) 66{ 67 struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); 68 u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); 69 70 val = (val & ~STM32_ENVR) | STM32_HIZ; 71 writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); 72 73 return 0; 74} 75 76static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev) 77{ 78 struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); 79 80 return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; 81} 82 83static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev, 84 unsigned sel) 85{ 86 struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); 87 u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); 88 89 val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel); 90 writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); 91 92 return 0; 93} 94 95static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev) 96{ 97 struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); 98 u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); 99 100 return FIELD_GET(STM32_VRS, val); 101} 102 103static const struct regulator_ops stm32_vrefbuf_volt_ops = { 104 .enable = stm32_vrefbuf_enable, 105 .disable = stm32_vrefbuf_disable, 106 .is_enabled = stm32_vrefbuf_is_enabled, 107 .get_voltage_sel = stm32_vrefbuf_get_voltage_sel, 108 .set_voltage_sel = stm32_vrefbuf_set_voltage_sel, 109 .list_voltage = regulator_list_voltage_table, 110}; 111 112static const struct regulator_desc stm32_vrefbuf_regu = { 113 .name = "vref", 114 .supply_name = "vdda", 115 .volt_table = stm32_vrefbuf_voltages, 116 .n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages), 117 .ops = &stm32_vrefbuf_volt_ops, 118 .type = REGULATOR_VOLTAGE, 119 .owner = THIS_MODULE, 120}; 121 122static int stm32_vrefbuf_probe(struct platform_device *pdev) 123{ 124 struct resource *res; 125 struct stm32_vrefbuf *priv; 126 struct regulator_config config = { }; 127 struct regulator_dev *rdev; 128 int ret; 129 130 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 131 if (!priv) 132 return -ENOMEM; 133 134 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 135 priv->base = devm_ioremap_resource(&pdev->dev, res); 136 if (IS_ERR(priv->base)) 137 return PTR_ERR(priv->base); 138 139 priv->clk = devm_clk_get(&pdev->dev, NULL); 140 if (IS_ERR(priv->clk)) 141 return PTR_ERR(priv->clk); 142 143 ret = clk_prepare_enable(priv->clk); 144 if (ret) { 145 dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret); 146 return ret; 147 } 148 149 config.dev = &pdev->dev; 150 config.driver_data = priv; 151 config.of_node = pdev->dev.of_node; 152 config.init_data = of_get_regulator_init_data(&pdev->dev, 153 pdev->dev.of_node, 154 &stm32_vrefbuf_regu); 155 156 rdev = regulator_register(&stm32_vrefbuf_regu, &config); 157 if (IS_ERR(rdev)) { 158 ret = PTR_ERR(rdev); 159 dev_err(&pdev->dev, "register failed with error %d\n", ret); 160 goto err_clk_dis; 161 } 162 platform_set_drvdata(pdev, rdev); 163 164 return 0; 165 166err_clk_dis: 167 clk_disable_unprepare(priv->clk); 168 169 return ret; 170} 171 172static int stm32_vrefbuf_remove(struct platform_device *pdev) 173{ 174 struct regulator_dev *rdev = platform_get_drvdata(pdev); 175 struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); 176 177 regulator_unregister(rdev); 178 clk_disable_unprepare(priv->clk); 179 180 return 0; 181}; 182 183static const struct of_device_id stm32_vrefbuf_of_match[] = { 184 { .compatible = "st,stm32-vrefbuf", }, 185 {}, 186}; 187MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match); 188 189static struct platform_driver stm32_vrefbuf_driver = { 190 .probe = stm32_vrefbuf_probe, 191 .remove = stm32_vrefbuf_remove, 192 .driver = { 193 .name = "stm32-vrefbuf", 194 .of_match_table = of_match_ptr(stm32_vrefbuf_of_match), 195 }, 196}; 197module_platform_driver(stm32_vrefbuf_driver); 198 199MODULE_LICENSE("GPL v2"); 200MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); 201MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver"); 202MODULE_ALIAS("platform:stm32-vrefbuf");