1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * This file is part of STM32 DAC driver |
4 | * |
5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved |
6 | * Author: Fabrice Gasnier <fabrice.gasnier@st.com>. |
7 | * |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/delay.h> |
12 | #include <linux/mod_devicetable.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of_platform.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> |
17 | #include <linux/property.h> |
18 | #include <linux/regulator/consumer.h> |
19 | #include <linux/reset.h> |
20 | |
21 | #include "stm32-dac-core.h" |
22 | |
23 | /** |
24 | * struct stm32_dac_priv - stm32 DAC core private data |
25 | * @pclk: peripheral clock common for all DACs |
26 | * @vref: regulator reference |
27 | * @common: Common data for all DAC instances |
28 | */ |
29 | struct stm32_dac_priv { |
30 | struct clk *pclk; |
31 | struct regulator *vref; |
32 | struct stm32_dac_common common; |
33 | }; |
34 | |
35 | /** |
36 | * struct stm32_dac_cfg - DAC configuration |
37 | * @has_hfsel: DAC has high frequency control |
38 | */ |
39 | struct stm32_dac_cfg { |
40 | bool has_hfsel; |
41 | }; |
42 | |
43 | static struct stm32_dac_priv *to_stm32_dac_priv(struct stm32_dac_common *com) |
44 | { |
45 | return container_of(com, struct stm32_dac_priv, common); |
46 | } |
47 | |
48 | static const struct regmap_config stm32_dac_regmap_cfg = { |
49 | .reg_bits = 32, |
50 | .val_bits = 32, |
51 | .reg_stride = sizeof(u32), |
52 | .max_register = 0x3fc, |
53 | }; |
54 | |
55 | static int stm32_dac_core_hw_start(struct device *dev) |
56 | { |
57 | struct stm32_dac_common *common = dev_get_drvdata(dev); |
58 | struct stm32_dac_priv *priv = to_stm32_dac_priv(com: common); |
59 | int ret; |
60 | |
61 | ret = regulator_enable(regulator: priv->vref); |
62 | if (ret < 0) { |
63 | dev_err(dev, "vref enable failed: %d\n" , ret); |
64 | return ret; |
65 | } |
66 | |
67 | ret = clk_prepare_enable(clk: priv->pclk); |
68 | if (ret < 0) { |
69 | dev_err(dev, "pclk enable failed: %d\n" , ret); |
70 | goto err_regulator_disable; |
71 | } |
72 | |
73 | return 0; |
74 | |
75 | err_regulator_disable: |
76 | regulator_disable(regulator: priv->vref); |
77 | |
78 | return ret; |
79 | } |
80 | |
81 | static void stm32_dac_core_hw_stop(struct device *dev) |
82 | { |
83 | struct stm32_dac_common *common = dev_get_drvdata(dev); |
84 | struct stm32_dac_priv *priv = to_stm32_dac_priv(com: common); |
85 | |
86 | clk_disable_unprepare(clk: priv->pclk); |
87 | regulator_disable(regulator: priv->vref); |
88 | } |
89 | |
90 | static int stm32_dac_probe(struct platform_device *pdev) |
91 | { |
92 | struct device *dev = &pdev->dev; |
93 | const struct stm32_dac_cfg *cfg; |
94 | struct stm32_dac_priv *priv; |
95 | struct regmap *regmap; |
96 | void __iomem *mmio; |
97 | struct reset_control *rst; |
98 | int ret; |
99 | |
100 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
101 | if (!priv) |
102 | return -ENOMEM; |
103 | platform_set_drvdata(pdev, data: &priv->common); |
104 | |
105 | cfg = device_get_match_data(dev); |
106 | |
107 | mmio = devm_platform_ioremap_resource(pdev, index: 0); |
108 | if (IS_ERR(ptr: mmio)) |
109 | return PTR_ERR(ptr: mmio); |
110 | |
111 | regmap = devm_regmap_init_mmio_clk(dev, "pclk" , mmio, |
112 | &stm32_dac_regmap_cfg); |
113 | if (IS_ERR(ptr: regmap)) |
114 | return PTR_ERR(ptr: regmap); |
115 | priv->common.regmap = regmap; |
116 | |
117 | priv->pclk = devm_clk_get(dev, id: "pclk" ); |
118 | if (IS_ERR(ptr: priv->pclk)) |
119 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->pclk), fmt: "pclk get failed\n" ); |
120 | |
121 | priv->vref = devm_regulator_get(dev, id: "vref" ); |
122 | if (IS_ERR(ptr: priv->vref)) |
123 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->vref), fmt: "vref get failed\n" ); |
124 | |
125 | pm_runtime_get_noresume(dev); |
126 | pm_runtime_set_active(dev); |
127 | pm_runtime_enable(dev); |
128 | |
129 | ret = stm32_dac_core_hw_start(dev); |
130 | if (ret) |
131 | goto err_pm_stop; |
132 | |
133 | ret = regulator_get_voltage(regulator: priv->vref); |
134 | if (ret < 0) { |
135 | dev_err(dev, "vref get voltage failed, %d\n" , ret); |
136 | goto err_hw_stop; |
137 | } |
138 | priv->common.vref_mv = ret / 1000; |
139 | dev_dbg(dev, "vref+=%dmV\n" , priv->common.vref_mv); |
140 | |
141 | rst = devm_reset_control_get_optional_exclusive(dev, NULL); |
142 | if (rst) { |
143 | if (IS_ERR(ptr: rst)) { |
144 | ret = dev_err_probe(dev, err: PTR_ERR(ptr: rst), fmt: "reset get failed\n" ); |
145 | goto err_hw_stop; |
146 | } |
147 | |
148 | reset_control_assert(rstc: rst); |
149 | udelay(2); |
150 | reset_control_deassert(rstc: rst); |
151 | } |
152 | |
153 | if (cfg && cfg->has_hfsel) { |
154 | /* When clock speed is higher than 80MHz, set HFSEL */ |
155 | priv->common.hfsel = (clk_get_rate(clk: priv->pclk) > 80000000UL); |
156 | ret = regmap_update_bits(map: regmap, STM32_DAC_CR, |
157 | STM32H7_DAC_CR_HFSEL, |
158 | val: priv->common.hfsel ? |
159 | STM32H7_DAC_CR_HFSEL : 0); |
160 | if (ret) |
161 | goto err_hw_stop; |
162 | } |
163 | |
164 | |
165 | ret = of_platform_populate(root: pdev->dev.of_node, NULL, NULL, parent: dev); |
166 | if (ret < 0) { |
167 | dev_err(dev, "failed to populate DT children\n" ); |
168 | goto err_hw_stop; |
169 | } |
170 | |
171 | pm_runtime_put(dev); |
172 | |
173 | return 0; |
174 | |
175 | err_hw_stop: |
176 | stm32_dac_core_hw_stop(dev); |
177 | err_pm_stop: |
178 | pm_runtime_disable(dev); |
179 | pm_runtime_set_suspended(dev); |
180 | pm_runtime_put_noidle(dev); |
181 | |
182 | return ret; |
183 | } |
184 | |
185 | static void stm32_dac_remove(struct platform_device *pdev) |
186 | { |
187 | pm_runtime_get_sync(dev: &pdev->dev); |
188 | of_platform_depopulate(parent: &pdev->dev); |
189 | stm32_dac_core_hw_stop(dev: &pdev->dev); |
190 | pm_runtime_disable(dev: &pdev->dev); |
191 | pm_runtime_set_suspended(dev: &pdev->dev); |
192 | pm_runtime_put_noidle(dev: &pdev->dev); |
193 | } |
194 | |
195 | static int stm32_dac_core_resume(struct device *dev) |
196 | { |
197 | struct stm32_dac_common *common = dev_get_drvdata(dev); |
198 | struct stm32_dac_priv *priv = to_stm32_dac_priv(com: common); |
199 | int ret; |
200 | |
201 | if (priv->common.hfsel) { |
202 | /* restore hfsel (maybe lost under low power state) */ |
203 | ret = regmap_update_bits(map: priv->common.regmap, STM32_DAC_CR, |
204 | STM32H7_DAC_CR_HFSEL, |
205 | STM32H7_DAC_CR_HFSEL); |
206 | if (ret) |
207 | return ret; |
208 | } |
209 | |
210 | return pm_runtime_force_resume(dev); |
211 | } |
212 | |
213 | static int stm32_dac_core_runtime_suspend(struct device *dev) |
214 | { |
215 | stm32_dac_core_hw_stop(dev); |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | static int stm32_dac_core_runtime_resume(struct device *dev) |
221 | { |
222 | return stm32_dac_core_hw_start(dev); |
223 | } |
224 | |
225 | static const struct dev_pm_ops stm32_dac_core_pm_ops = { |
226 | SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume) |
227 | RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend, |
228 | stm32_dac_core_runtime_resume, |
229 | NULL) |
230 | }; |
231 | |
232 | static const struct stm32_dac_cfg stm32h7_dac_cfg = { |
233 | .has_hfsel = true, |
234 | }; |
235 | |
236 | static const struct of_device_id stm32_dac_of_match[] = { |
237 | { |
238 | .compatible = "st,stm32f4-dac-core" , |
239 | }, { |
240 | .compatible = "st,stm32h7-dac-core" , |
241 | .data = (void *)&stm32h7_dac_cfg, |
242 | }, |
243 | {}, |
244 | }; |
245 | MODULE_DEVICE_TABLE(of, stm32_dac_of_match); |
246 | |
247 | static struct platform_driver stm32_dac_driver = { |
248 | .probe = stm32_dac_probe, |
249 | .remove_new = stm32_dac_remove, |
250 | .driver = { |
251 | .name = "stm32-dac-core" , |
252 | .of_match_table = stm32_dac_of_match, |
253 | .pm = pm_ptr(&stm32_dac_core_pm_ops), |
254 | }, |
255 | }; |
256 | module_platform_driver(stm32_dac_driver); |
257 | |
258 | MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>" ); |
259 | MODULE_DESCRIPTION("STMicroelectronics STM32 DAC core driver" ); |
260 | MODULE_LICENSE("GPL v2" ); |
261 | MODULE_ALIAS("platform:stm32-dac-core" ); |
262 | |