Commit | Line | Data |
---|---|---|
0cdbf481 FG |
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 | ||
28 | struct stm32_vrefbuf { | |
29 | void __iomem *base; | |
30 | struct clk *clk; | |
31 | }; | |
32 | ||
33 | static const unsigned int stm32_vrefbuf_voltages[] = { | |
34 | /* Matches resp. VRS = 000b, 001b, 010b, 011b */ | |
35 | 2500000, 2048000, 1800000, 1500000, | |
36 | }; | |
37 | ||
38 | static 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, | |
f63248fa | 54 | val & STM32_VRR, 650, 10000); |
0cdbf481 FG |
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 | ||
65 | static 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 | ||
76 | static 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 | ||
83 | static 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 | ||
95 | static 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 | ||
103 | static 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 | ||
112 | static 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 | ||
122 | static 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 | ||
166 | err_clk_dis: | |
167 | clk_disable_unprepare(priv->clk); | |
168 | ||
169 | return ret; | |
170 | } | |
171 | ||
172 | static 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 | ||
183 | static const struct of_device_id stm32_vrefbuf_of_match[] = { | |
184 | { .compatible = "st,stm32-vrefbuf", }, | |
185 | {}, | |
186 | }; | |
187 | MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match); | |
188 | ||
189 | static 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 | }; | |
197 | module_platform_driver(stm32_vrefbuf_driver); | |
198 | ||
199 | MODULE_LICENSE("GPL v2"); | |
200 | MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); | |
201 | MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver"); | |
202 | MODULE_ALIAS("platform:stm32-vrefbuf"); |