Blame view

drivers/regulator/stm32-vrefbuf.c 7.69 KB
af873fcec   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
0cdbf481e   Fabrice Gasnier   regulator: Add su...
2
3
4
5
  /*
   * Copyright (C) STMicroelectronics 2017
   *
   * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
0cdbf481e   Fabrice Gasnier   regulator: Add su...
6
7
8
9
10
11
12
13
14
15
16
   */
  
  #include <linux/bitfield.h>
  #include <linux/clk.h>
  #include <linux/io.h>
  #include <linux/iopoll.h>
  #include <linux/module.h>
  #include <linux/of_device.h>
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/of_regulator.h>
be5295f8a   Fabrice Gasnier   regulator: stm32-...
17
  #include <linux/pm_runtime.h>
0cdbf481e   Fabrice Gasnier   regulator: Add su...
18
19
20
21
22
23
24
25
26
  
  /* STM32 VREFBUF registers */
  #define STM32_VREFBUF_CSR		0x00
  
  /* STM32 VREFBUF CSR bitfields */
  #define STM32_VRS			GENMASK(6, 4)
  #define STM32_VRR			BIT(3)
  #define STM32_HIZ			BIT(1)
  #define STM32_ENVR			BIT(0)
be5295f8a   Fabrice Gasnier   regulator: stm32-...
27
  #define STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS	10
0cdbf481e   Fabrice Gasnier   regulator: Add su...
28
29
30
  struct stm32_vrefbuf {
  	void __iomem *base;
  	struct clk *clk;
be5295f8a   Fabrice Gasnier   regulator: stm32-...
31
  	struct device *dev;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
32
33
34
35
36
37
38
39
40
41
  };
  
  static const unsigned int stm32_vrefbuf_voltages[] = {
  	/* Matches resp. VRS = 000b, 001b, 010b, 011b */
  	2500000, 2048000, 1800000, 1500000,
  };
  
  static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
  {
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
42
  	u32 val;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
43
  	int ret;
be5295f8a   Fabrice Gasnier   regulator: stm32-...
44
45
46
47
48
49
50
  	ret = pm_runtime_get_sync(priv->dev);
  	if (ret < 0) {
  		pm_runtime_put_noidle(priv->dev);
  		return ret;
  	}
  
  	val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
51
52
53
54
55
56
57
58
59
60
  	val = (val & ~STM32_HIZ) | STM32_ENVR;
  	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
  
  	/*
  	 * Vrefbuf startup time depends on external capacitor: wait here for
  	 * VRR to be set. That means output has reached expected value.
  	 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
  	 * arbitrary timeout.
  	 */
  	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
f63248fac   Fabrice Gasnier   regulator: stm32-...
61
  				 val & STM32_VRR, 650, 10000);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
62
63
64
65
66
67
68
  	if (ret) {
  		dev_err(&rdev->dev, "stm32 vrefbuf timed out!
  ");
  		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
  		val = (val & ~STM32_ENVR) | STM32_HIZ;
  		writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
  	}
be5295f8a   Fabrice Gasnier   regulator: stm32-...
69
70
  	pm_runtime_mark_last_busy(priv->dev);
  	pm_runtime_put_autosuspend(priv->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
71
72
73
74
75
76
  	return ret;
  }
  
  static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
  {
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
77
78
  	u32 val;
  	int ret;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
79

be5295f8a   Fabrice Gasnier   regulator: stm32-...
80
81
82
83
84
85
86
  	ret = pm_runtime_get_sync(priv->dev);
  	if (ret < 0) {
  		pm_runtime_put_noidle(priv->dev);
  		return ret;
  	}
  
  	val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
3d5d75f8c   Fabrice Gasnier   regulator: stm32-...
87
  	val &= ~STM32_ENVR;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
88
  	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
89
90
  	pm_runtime_mark_last_busy(priv->dev);
  	pm_runtime_put_autosuspend(priv->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
91
92
93
94
95
96
  	return 0;
  }
  
  static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
  {
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
97
98
99
100
101
102
103
104
105
  	int ret;
  
  	ret = pm_runtime_get_sync(priv->dev);
  	if (ret < 0) {
  		pm_runtime_put_noidle(priv->dev);
  		return ret;
  	}
  
  	ret = readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
106

be5295f8a   Fabrice Gasnier   regulator: stm32-...
107
108
109
110
  	pm_runtime_mark_last_busy(priv->dev);
  	pm_runtime_put_autosuspend(priv->dev);
  
  	return ret;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
111
112
113
114
115
116
  }
  
  static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
  					 unsigned sel)
  {
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
117
118
  	u32 val;
  	int ret;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
119

be5295f8a   Fabrice Gasnier   regulator: stm32-...
120
121
122
123
124
125
126
  	ret = pm_runtime_get_sync(priv->dev);
  	if (ret < 0) {
  		pm_runtime_put_noidle(priv->dev);
  		return ret;
  	}
  
  	val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
127
128
  	val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
  	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
129
130
  	pm_runtime_mark_last_busy(priv->dev);
  	pm_runtime_put_autosuspend(priv->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
131
132
133
134
135
136
  	return 0;
  }
  
  static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
  {
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
137
138
  	u32 val;
  	int ret;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
139

be5295f8a   Fabrice Gasnier   regulator: stm32-...
140
141
142
143
144
145
146
147
148
149
150
151
152
  	ret = pm_runtime_get_sync(priv->dev);
  	if (ret < 0) {
  		pm_runtime_put_noidle(priv->dev);
  		return ret;
  	}
  
  	val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
  	ret = FIELD_GET(STM32_VRS, val);
  
  	pm_runtime_mark_last_busy(priv->dev);
  	pm_runtime_put_autosuspend(priv->dev);
  
  	return ret;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  }
  
  static const struct regulator_ops stm32_vrefbuf_volt_ops = {
  	.enable		= stm32_vrefbuf_enable,
  	.disable	= stm32_vrefbuf_disable,
  	.is_enabled	= stm32_vrefbuf_is_enabled,
  	.get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
  	.set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
  	.list_voltage	= regulator_list_voltage_table,
  };
  
  static const struct regulator_desc stm32_vrefbuf_regu = {
  	.name = "vref",
  	.supply_name = "vdda",
  	.volt_table = stm32_vrefbuf_voltages,
  	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
  	.ops = &stm32_vrefbuf_volt_ops,
3d5d75f8c   Fabrice Gasnier   regulator: stm32-...
170
  	.off_on_delay = 1000,
0cdbf481e   Fabrice Gasnier   regulator: Add su...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  	.type = REGULATOR_VOLTAGE,
  	.owner = THIS_MODULE,
  };
  
  static int stm32_vrefbuf_probe(struct platform_device *pdev)
  {
  	struct resource *res;
  	struct stm32_vrefbuf *priv;
  	struct regulator_config config = { };
  	struct regulator_dev *rdev;
  	int ret;
  
  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  	if (!priv)
  		return -ENOMEM;
be5295f8a   Fabrice Gasnier   regulator: stm32-...
186
  	priv->dev = &pdev->dev;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
187
188
189
190
191
192
193
194
195
  
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	priv->base = devm_ioremap_resource(&pdev->dev, res);
  	if (IS_ERR(priv->base))
  		return PTR_ERR(priv->base);
  
  	priv->clk = devm_clk_get(&pdev->dev, NULL);
  	if (IS_ERR(priv->clk))
  		return PTR_ERR(priv->clk);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
196
197
198
199
200
201
  	pm_runtime_get_noresume(&pdev->dev);
  	pm_runtime_set_active(&pdev->dev);
  	pm_runtime_set_autosuspend_delay(&pdev->dev,
  					 STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS);
  	pm_runtime_use_autosuspend(&pdev->dev);
  	pm_runtime_enable(&pdev->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
202
203
204
205
  	ret = clk_prepare_enable(priv->clk);
  	if (ret) {
  		dev_err(&pdev->dev, "clk prepare failed with error %d
  ", ret);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
206
  		goto err_pm_stop;
0cdbf481e   Fabrice Gasnier   regulator: Add su...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  	}
  
  	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);
  
  	rdev = regulator_register(&stm32_vrefbuf_regu, &config);
  	if (IS_ERR(rdev)) {
  		ret = PTR_ERR(rdev);
  		dev_err(&pdev->dev, "register failed with error %d
  ", ret);
  		goto err_clk_dis;
  	}
  	platform_set_drvdata(pdev, rdev);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
224
225
  	pm_runtime_mark_last_busy(&pdev->dev);
  	pm_runtime_put_autosuspend(&pdev->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
226
227
228
229
  	return 0;
  
  err_clk_dis:
  	clk_disable_unprepare(priv->clk);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
230
231
232
233
  err_pm_stop:
  	pm_runtime_disable(&pdev->dev);
  	pm_runtime_set_suspended(&pdev->dev);
  	pm_runtime_put_noidle(&pdev->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
234
235
236
237
238
239
240
241
  
  	return ret;
  }
  
  static int stm32_vrefbuf_remove(struct platform_device *pdev)
  {
  	struct regulator_dev *rdev = platform_get_drvdata(pdev);
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
242
  	pm_runtime_get_sync(&pdev->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
243
244
  	regulator_unregister(rdev);
  	clk_disable_unprepare(priv->clk);
be5295f8a   Fabrice Gasnier   regulator: stm32-...
245
246
247
  	pm_runtime_disable(&pdev->dev);
  	pm_runtime_set_suspended(&pdev->dev);
  	pm_runtime_put_noidle(&pdev->dev);
0cdbf481e   Fabrice Gasnier   regulator: Add su...
248
249
250
  
  	return 0;
  };
be5295f8a   Fabrice Gasnier   regulator: stm32-...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  static int __maybe_unused stm32_vrefbuf_runtime_suspend(struct device *dev)
  {
  	struct regulator_dev *rdev = dev_get_drvdata(dev);
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
  
  	clk_disable_unprepare(priv->clk);
  
  	return 0;
  }
  
  static int __maybe_unused stm32_vrefbuf_runtime_resume(struct device *dev)
  {
  	struct regulator_dev *rdev = dev_get_drvdata(dev);
  	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
  
  	return clk_prepare_enable(priv->clk);
  }
  
  static const struct dev_pm_ops stm32_vrefbuf_pm_ops = {
  	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
  				pm_runtime_force_resume)
  	SET_RUNTIME_PM_OPS(stm32_vrefbuf_runtime_suspend,
  			   stm32_vrefbuf_runtime_resume,
  			   NULL)
  };
0cdbf481e   Fabrice Gasnier   regulator: Add su...
276
277
278
279
280
281
282
283
284
285
286
287
  static const struct of_device_id stm32_vrefbuf_of_match[] = {
  	{ .compatible = "st,stm32-vrefbuf", },
  	{},
  };
  MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
  
  static struct platform_driver stm32_vrefbuf_driver = {
  	.probe = stm32_vrefbuf_probe,
  	.remove = stm32_vrefbuf_remove,
  	.driver = {
  		.name  = "stm32-vrefbuf",
  		.of_match_table = of_match_ptr(stm32_vrefbuf_of_match),
be5295f8a   Fabrice Gasnier   regulator: stm32-...
288
  		.pm = &stm32_vrefbuf_pm_ops,
0cdbf481e   Fabrice Gasnier   regulator: Add su...
289
290
291
292
293
294
295
296
  	},
  };
  module_platform_driver(stm32_vrefbuf_driver);
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
  MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
  MODULE_ALIAS("platform:stm32-vrefbuf");