1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019 Nuvoton Technology corporation.
5 #include <linux/device.h>
6 #include <linux/mfd/syscon.h>
8 #include <linux/iio/iio.h>
9 #include <linux/interrupt.h>
10 #include <linux/kernel.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/property.h>
15 #include <linux/regmap.h>
16 #include <linux/regulator/consumer.h>
17 #include <linux/spinlock.h>
18 #include <linux/uaccess.h>
19 #include <linux/reset.h>
21 struct npcm_adc_info
{
34 struct regulator
*vref
;
35 struct reset_control
*reset
;
37 * Lock to protect the device state during a potential concurrent
38 * read access from userspace. Reading a raw value requires a sequence
39 * of register writes, then a wait for a event and finally a register
40 * read, during which userspace could issue another read request.
41 * This lock protects a read access from ocurring before another one
45 const struct npcm_adc_info
*data
;
49 #define NPCM_ADCCON 0x00
50 #define NPCM_ADCDATA 0x04
52 /* ADCCON Register Bits */
53 #define NPCM_ADCCON_ADC_INT_EN BIT(21)
54 #define NPCM_ADCCON_REFSEL BIT(19)
55 #define NPCM_ADCCON_ADC_INT_ST BIT(18)
56 #define NPCM_ADCCON_ADC_EN BIT(17)
57 #define NPCM_ADCCON_ADC_RST BIT(16)
58 #define NPCM_ADCCON_ADC_CONV BIT(13)
60 #define NPCM_ADCCON_CH_MASK GENMASK(27, 24)
61 #define NPCM_ADCCON_CH(x) ((x) << 24)
62 #define NPCM_ADCCON_DIV_SHIFT 1
63 #define NPCM_ADCCON_DIV_MASK GENMASK(8, 1)
65 #define NPCM_ADC_ENABLE (NPCM_ADCCON_ADC_EN | NPCM_ADCCON_ADC_INT_EN)
67 /* ADC General Definition */
68 static const struct npcm_adc_info npxm7xx_adc_info
= {
69 .data_mask
= GENMASK(9, 0),
70 .internal_vref
= 2048,
74 static const struct npcm_adc_info npxm8xx_adc_info
= {
75 .data_mask
= GENMASK(11, 0),
76 .internal_vref
= 1229,
80 #define NPCM_ADC_CHAN(ch) { \
81 .type = IIO_VOLTAGE, \
84 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
85 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
86 BIT(IIO_CHAN_INFO_SAMP_FREQ), \
89 static const struct iio_chan_spec npcm_adc_iio_channels
[] = {
100 static irqreturn_t
npcm_adc_isr(int irq
, void *data
)
103 struct iio_dev
*indio_dev
= data
;
104 struct npcm_adc
*info
= iio_priv(indio_dev
);
106 regtemp
= ioread32(info
->regs
+ NPCM_ADCCON
);
107 if (regtemp
& NPCM_ADCCON_ADC_INT_ST
) {
108 iowrite32(regtemp
, info
->regs
+ NPCM_ADCCON
);
109 wake_up_interruptible(&info
->wq
);
110 info
->int_status
= true;
116 static int npcm_adc_read(struct npcm_adc
*info
, int *val
, u8 channel
)
121 /* Select ADC channel */
122 regtemp
= ioread32(info
->regs
+ NPCM_ADCCON
);
123 regtemp
&= ~NPCM_ADCCON_CH_MASK
;
124 info
->int_status
= false;
125 iowrite32(regtemp
| NPCM_ADCCON_CH(channel
) |
126 NPCM_ADCCON_ADC_CONV
, info
->regs
+ NPCM_ADCCON
);
128 ret
= wait_event_interruptible_timeout(info
->wq
, info
->int_status
,
129 msecs_to_jiffies(10));
131 regtemp
= ioread32(info
->regs
+ NPCM_ADCCON
);
132 if (regtemp
& NPCM_ADCCON_ADC_CONV
) {
133 /* if conversion failed - reset ADC module */
134 reset_control_assert(info
->reset
);
136 reset_control_deassert(info
->reset
);
139 /* Enable ADC and start conversion module */
140 iowrite32(NPCM_ADC_ENABLE
| NPCM_ADCCON_ADC_CONV
,
141 info
->regs
+ NPCM_ADCCON
);
142 dev_err(info
->dev
, "RESET ADC Complete\n");
149 *val
= ioread32(info
->regs
+ NPCM_ADCDATA
);
150 *val
&= info
->data
->data_mask
;
155 static int npcm_adc_read_raw(struct iio_dev
*indio_dev
,
156 struct iio_chan_spec
const *chan
, int *val
,
157 int *val2
, long mask
)
161 struct npcm_adc
*info
= iio_priv(indio_dev
);
164 case IIO_CHAN_INFO_RAW
:
165 mutex_lock(&info
->lock
);
166 ret
= npcm_adc_read(info
, val
, chan
->channel
);
167 mutex_unlock(&info
->lock
);
169 dev_err(info
->dev
, "NPCM ADC read failed\n");
173 case IIO_CHAN_INFO_SCALE
:
174 if (!IS_ERR(info
->vref
)) {
175 vref_uv
= regulator_get_voltage(info
->vref
);
176 *val
= vref_uv
/ 1000;
178 *val
= info
->data
->internal_vref
;
180 *val2
= info
->data
->res_bits
;
181 return IIO_VAL_FRACTIONAL_LOG2
;
182 case IIO_CHAN_INFO_SAMP_FREQ
:
183 *val
= info
->adc_sample_hz
;
192 static const struct iio_info npcm_adc_iio_info
= {
193 .read_raw
= &npcm_adc_read_raw
,
196 static const struct of_device_id npcm_adc_match
[] = {
197 { .compatible
= "nuvoton,npcm750-adc", .data
= &npxm7xx_adc_info
},
198 { .compatible
= "nuvoton,npcm845-adc", .data
= &npxm8xx_adc_info
},
201 MODULE_DEVICE_TABLE(of
, npcm_adc_match
);
203 static int npcm_adc_probe(struct platform_device
*pdev
)
209 struct npcm_adc
*info
;
210 struct iio_dev
*indio_dev
;
211 struct device
*dev
= &pdev
->dev
;
213 indio_dev
= devm_iio_device_alloc(&pdev
->dev
, sizeof(*info
));
216 info
= iio_priv(indio_dev
);
218 info
->data
= device_get_match_data(dev
);
222 mutex_init(&info
->lock
);
224 info
->dev
= &pdev
->dev
;
226 info
->regs
= devm_platform_ioremap_resource(pdev
, 0);
227 if (IS_ERR(info
->regs
))
228 return PTR_ERR(info
->regs
);
230 info
->reset
= devm_reset_control_get(&pdev
->dev
, NULL
);
231 if (IS_ERR(info
->reset
))
232 return PTR_ERR(info
->reset
);
234 info
->adc_clk
= devm_clk_get(&pdev
->dev
, NULL
);
235 if (IS_ERR(info
->adc_clk
)) {
236 dev_warn(&pdev
->dev
, "ADC clock failed: can't read clk\n");
237 return PTR_ERR(info
->adc_clk
);
240 /* calculate ADC clock sample rate */
241 reg_con
= ioread32(info
->regs
+ NPCM_ADCCON
);
242 div
= reg_con
& NPCM_ADCCON_DIV_MASK
;
243 div
= div
>> NPCM_ADCCON_DIV_SHIFT
;
244 info
->adc_sample_hz
= clk_get_rate(info
->adc_clk
) / ((div
+ 1) * 2);
246 irq
= platform_get_irq(pdev
, 0);
249 goto err_disable_clk
;
252 ret
= devm_request_irq(&pdev
->dev
, irq
, npcm_adc_isr
, 0,
253 "NPCM_ADC", indio_dev
);
255 dev_err(dev
, "failed requesting interrupt\n");
256 goto err_disable_clk
;
259 reg_con
= ioread32(info
->regs
+ NPCM_ADCCON
);
260 info
->vref
= devm_regulator_get_optional(&pdev
->dev
, "vref");
261 if (!IS_ERR(info
->vref
)) {
262 ret
= regulator_enable(info
->vref
);
264 dev_err(&pdev
->dev
, "Can't enable ADC reference voltage\n");
265 goto err_disable_clk
;
268 iowrite32(reg_con
& ~NPCM_ADCCON_REFSEL
,
269 info
->regs
+ NPCM_ADCCON
);
272 * Any error which is not ENODEV indicates the regulator
273 * has been specified and so is a failure case.
275 if (PTR_ERR(info
->vref
) != -ENODEV
) {
276 ret
= PTR_ERR(info
->vref
);
277 goto err_disable_clk
;
280 /* Use internal reference */
281 iowrite32(reg_con
| NPCM_ADCCON_REFSEL
,
282 info
->regs
+ NPCM_ADCCON
);
285 init_waitqueue_head(&info
->wq
);
287 reg_con
= ioread32(info
->regs
+ NPCM_ADCCON
);
288 reg_con
|= NPCM_ADC_ENABLE
;
290 /* Enable the ADC Module */
291 iowrite32(reg_con
, info
->regs
+ NPCM_ADCCON
);
293 /* Start ADC conversion */
294 iowrite32(reg_con
| NPCM_ADCCON_ADC_CONV
, info
->regs
+ NPCM_ADCCON
);
296 platform_set_drvdata(pdev
, indio_dev
);
297 indio_dev
->name
= dev_name(&pdev
->dev
);
298 indio_dev
->info
= &npcm_adc_iio_info
;
299 indio_dev
->modes
= INDIO_DIRECT_MODE
;
300 indio_dev
->channels
= npcm_adc_iio_channels
;
301 indio_dev
->num_channels
= ARRAY_SIZE(npcm_adc_iio_channels
);
303 ret
= iio_device_register(indio_dev
);
305 dev_err(&pdev
->dev
, "Couldn't register the device.\n");
306 goto err_iio_register
;
309 pr_info("NPCM ADC driver probed\n");
314 iowrite32(reg_con
& ~NPCM_ADCCON_ADC_EN
, info
->regs
+ NPCM_ADCCON
);
315 if (!IS_ERR(info
->vref
))
316 regulator_disable(info
->vref
);
318 clk_disable_unprepare(info
->adc_clk
);
323 static void npcm_adc_remove(struct platform_device
*pdev
)
325 struct iio_dev
*indio_dev
= platform_get_drvdata(pdev
);
326 struct npcm_adc
*info
= iio_priv(indio_dev
);
329 iio_device_unregister(indio_dev
);
331 regtemp
= ioread32(info
->regs
+ NPCM_ADCCON
);
332 iowrite32(regtemp
& ~NPCM_ADCCON_ADC_EN
, info
->regs
+ NPCM_ADCCON
);
333 if (!IS_ERR(info
->vref
))
334 regulator_disable(info
->vref
);
335 clk_disable_unprepare(info
->adc_clk
);
338 static struct platform_driver npcm_adc_driver
= {
339 .probe
= npcm_adc_probe
,
340 .remove
= npcm_adc_remove
,
343 .of_match_table
= npcm_adc_match
,
347 module_platform_driver(npcm_adc_driver
);
349 MODULE_DESCRIPTION("Nuvoton NPCM ADC Driver");
350 MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
351 MODULE_LICENSE("GPL v2");