Merge tag 'sched-urgent-2022-08-06' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / iio / dac / vf610_dac.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Freescale Vybrid vf610 DAC driver
4  *
5  * Copyright 2016 Toradex AG
6  */
7
8 #include <linux/clk.h>
9 #include <linux/err.h>
10 #include <linux/interrupt.h>
11 #include <linux/io.h>
12 #include <linux/kernel.h>
13 #include <linux/mod_devicetable.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/regulator/consumer.h>
17 #include <linux/slab.h>
18
19 #include <linux/iio/iio.h>
20 #include <linux/iio/sysfs.h>
21
22 #define VF610_DACx_STATCTRL             0x20
23
24 #define VF610_DAC_DACEN                 BIT(15)
25 #define VF610_DAC_DACRFS                BIT(14)
26 #define VF610_DAC_LPEN                  BIT(11)
27
28 #define VF610_DAC_DAT0(x)               ((x) & 0xFFF)
29
30 enum vf610_conversion_mode_sel {
31         VF610_DAC_CONV_HIGH_POWER,
32         VF610_DAC_CONV_LOW_POWER,
33 };
34
35 struct vf610_dac {
36         struct clk *clk;
37         struct device *dev;
38         enum vf610_conversion_mode_sel conv_mode;
39         void __iomem *regs;
40         struct mutex lock;
41 };
42
43 static void vf610_dac_init(struct vf610_dac *info)
44 {
45         int val;
46
47         info->conv_mode = VF610_DAC_CONV_LOW_POWER;
48         val = VF610_DAC_DACEN | VF610_DAC_DACRFS |
49                 VF610_DAC_LPEN;
50         writel(val, info->regs + VF610_DACx_STATCTRL);
51 }
52
53 static void vf610_dac_exit(struct vf610_dac *info)
54 {
55         int val;
56
57         val = readl(info->regs + VF610_DACx_STATCTRL);
58         val &= ~VF610_DAC_DACEN;
59         writel(val, info->regs + VF610_DACx_STATCTRL);
60 }
61
62 static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
63                                 const struct iio_chan_spec *chan,
64                                 unsigned int mode)
65 {
66         struct vf610_dac *info = iio_priv(indio_dev);
67         int val;
68
69         mutex_lock(&info->lock);
70         info->conv_mode = mode;
71         val = readl(info->regs + VF610_DACx_STATCTRL);
72         if (mode)
73                 val |= VF610_DAC_LPEN;
74         else
75                 val &= ~VF610_DAC_LPEN;
76         writel(val, info->regs + VF610_DACx_STATCTRL);
77         mutex_unlock(&info->lock);
78
79         return 0;
80 }
81
82 static int vf610_get_conversion_mode(struct iio_dev *indio_dev,
83                                 const struct iio_chan_spec *chan)
84 {
85         struct vf610_dac *info = iio_priv(indio_dev);
86
87         return info->conv_mode;
88 }
89
90 static const char * const vf610_conv_modes[] = { "high-power", "low-power" };
91
92 static const struct iio_enum vf610_conversion_mode = {
93         .items = vf610_conv_modes,
94         .num_items = ARRAY_SIZE(vf610_conv_modes),
95         .get = vf610_get_conversion_mode,
96         .set = vf610_set_conversion_mode,
97 };
98
99 static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
100         IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR,
101                 &vf610_conversion_mode),
102         {},
103 };
104
105 #define VF610_DAC_CHAN(_chan_type) { \
106         .type = (_chan_type), \
107         .output = 1, \
108         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
109         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
110         .ext_info = vf610_ext_info, \
111 }
112
113 static const struct iio_chan_spec vf610_dac_iio_channels[] = {
114         VF610_DAC_CHAN(IIO_VOLTAGE),
115 };
116
117 static int vf610_read_raw(struct iio_dev *indio_dev,
118                         struct iio_chan_spec const *chan,
119                         int *val, int *val2,
120                         long mask)
121 {
122         struct vf610_dac *info = iio_priv(indio_dev);
123
124         switch (mask) {
125         case IIO_CHAN_INFO_RAW:
126                 *val = VF610_DAC_DAT0(readl(info->regs));
127                 return IIO_VAL_INT;
128         case IIO_CHAN_INFO_SCALE:
129                 /*
130                  * DACRFS is always 1 for valid reference and typical
131                  * reference voltage as per Vybrid datasheet is 3.3V
132                  * from section 9.1.2.1 of Vybrid datasheet
133                  */
134                 *val = 3300 /* mV */;
135                 *val2 = 12;
136                 return IIO_VAL_FRACTIONAL_LOG2;
137
138         default:
139                 return -EINVAL;
140         }
141 }
142
143 static int vf610_write_raw(struct iio_dev *indio_dev,
144                         struct iio_chan_spec const *chan,
145                         int val, int val2,
146                         long mask)
147 {
148         struct vf610_dac *info = iio_priv(indio_dev);
149
150         switch (mask) {
151         case IIO_CHAN_INFO_RAW:
152                 mutex_lock(&info->lock);
153                 writel(VF610_DAC_DAT0(val), info->regs);
154                 mutex_unlock(&info->lock);
155                 return 0;
156
157         default:
158                 return -EINVAL;
159         }
160 }
161
162 static const struct iio_info vf610_dac_iio_info = {
163         .read_raw = &vf610_read_raw,
164         .write_raw = &vf610_write_raw,
165 };
166
167 static const struct of_device_id vf610_dac_match[] = {
168         { .compatible = "fsl,vf610-dac", },
169         { /* sentinel */ }
170 };
171 MODULE_DEVICE_TABLE(of, vf610_dac_match);
172
173 static int vf610_dac_probe(struct platform_device *pdev)
174 {
175         struct iio_dev *indio_dev;
176         struct vf610_dac *info;
177         int ret;
178
179         indio_dev = devm_iio_device_alloc(&pdev->dev,
180                                         sizeof(struct vf610_dac));
181         if (!indio_dev) {
182                 dev_err(&pdev->dev, "Failed allocating iio device\n");
183                 return -ENOMEM;
184         }
185
186         info = iio_priv(indio_dev);
187         info->dev = &pdev->dev;
188
189         info->regs = devm_platform_ioremap_resource(pdev, 0);
190         if (IS_ERR(info->regs))
191                 return PTR_ERR(info->regs);
192
193         info->clk = devm_clk_get(&pdev->dev, "dac");
194         if (IS_ERR(info->clk)) {
195                 dev_err(&pdev->dev, "Failed getting clock, err = %ld\n",
196                         PTR_ERR(info->clk));
197                 return PTR_ERR(info->clk);
198         }
199
200         platform_set_drvdata(pdev, indio_dev);
201
202         indio_dev->name = dev_name(&pdev->dev);
203         indio_dev->info = &vf610_dac_iio_info;
204         indio_dev->modes = INDIO_DIRECT_MODE;
205         indio_dev->channels = vf610_dac_iio_channels;
206         indio_dev->num_channels = ARRAY_SIZE(vf610_dac_iio_channels);
207
208         mutex_init(&info->lock);
209
210         ret = clk_prepare_enable(info->clk);
211         if (ret) {
212                 dev_err(&pdev->dev,
213                         "Could not prepare or enable the clock\n");
214                 return ret;
215         }
216
217         vf610_dac_init(info);
218
219         ret = iio_device_register(indio_dev);
220         if (ret) {
221                 dev_err(&pdev->dev, "Couldn't register the device\n");
222                 goto error_iio_device_register;
223         }
224
225         return 0;
226
227 error_iio_device_register:
228         vf610_dac_exit(info);
229         clk_disable_unprepare(info->clk);
230
231         return ret;
232 }
233
234 static int vf610_dac_remove(struct platform_device *pdev)
235 {
236         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
237         struct vf610_dac *info = iio_priv(indio_dev);
238
239         iio_device_unregister(indio_dev);
240         vf610_dac_exit(info);
241         clk_disable_unprepare(info->clk);
242
243         return 0;
244 }
245
246 static int vf610_dac_suspend(struct device *dev)
247 {
248         struct iio_dev *indio_dev = dev_get_drvdata(dev);
249         struct vf610_dac *info = iio_priv(indio_dev);
250
251         vf610_dac_exit(info);
252         clk_disable_unprepare(info->clk);
253
254         return 0;
255 }
256
257 static int vf610_dac_resume(struct device *dev)
258 {
259         struct iio_dev *indio_dev = dev_get_drvdata(dev);
260         struct vf610_dac *info = iio_priv(indio_dev);
261         int ret;
262
263         ret = clk_prepare_enable(info->clk);
264         if (ret)
265                 return ret;
266
267         vf610_dac_init(info);
268
269         return 0;
270 }
271
272 static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
273                                 vf610_dac_resume);
274
275 static struct platform_driver vf610_dac_driver = {
276         .probe          = vf610_dac_probe,
277         .remove         = vf610_dac_remove,
278         .driver         = {
279                 .name   = "vf610-dac",
280                 .of_match_table = vf610_dac_match,
281                 .pm     = pm_sleep_ptr(&vf610_dac_pm_ops),
282         },
283 };
284 module_platform_driver(vf610_dac_driver);
285
286 MODULE_AUTHOR("Sanchayan Maity <sanchayan.maity@toradex.com>");
287 MODULE_DESCRIPTION("Freescale VF610 DAC driver");
288 MODULE_LICENSE("GPL v2");