]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - drivers/iio/adc/lpc32xx_adc.c
iio:adc:lpc32xx use SPDX-License-Identifier
[mirror_ubuntu-focal-kernel.git] / drivers / iio / adc / lpc32xx_adc.c
CommitLineData
43058349 1// SPDX-License-Identifier: GPL-2.0+
906ecf69
RS
2/*
3 * lpc32xx_adc.c - Support for ADC in LPC32XX
4 *
5 * 3-channel, 10-bit ADC
6 *
7 * Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de>
906ecf69
RS
8 */
9
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/interrupt.h>
13#include <linux/device.h>
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/io.h>
17#include <linux/clk.h>
18#include <linux/err.h>
19#include <linux/completion.h>
1f9e3494 20#include <linux/of.h>
906ecf69 21
06458e27
JC
22#include <linux/iio/iio.h>
23#include <linux/iio/sysfs.h>
906ecf69
RS
24
25/*
26 * LPC32XX registers definitions
27 */
5023574a
JC
28#define LPC32XXAD_SELECT(x) ((x) + 0x04)
29#define LPC32XXAD_CTRL(x) ((x) + 0x08)
30#define LPC32XXAD_VALUE(x) ((x) + 0x48)
906ecf69 31
5023574a
JC
32/* Bit definitions for LPC32XXAD_SELECT: */
33/* constant, always write this value! */
34#define LPC32XXAD_REFm 0x00000200
35/* constant, always write this value! */
36#define LPC32XXAD_REFp 0x00000080
37 /* multiple of this is the channel number: 0, 1, 2 */
38#define LPC32XXAD_IN 0x00000010
39/* constant, always write this value! */
40#define LPC32XXAD_INTERNAL 0x00000004
906ecf69 41
5023574a
JC
42/* Bit definitions for LPC32XXAD_CTRL: */
43#define LPC32XXAD_STROBE 0x00000002
44#define LPC32XXAD_PDN_CTRL 0x00000004
906ecf69 45
5023574a
JC
46/* Bit definitions for LPC32XXAD_VALUE: */
47#define LPC32XXAD_VALUE_MASK 0x000003FF
906ecf69 48
5023574a 49#define LPC32XXAD_NAME "lpc32xx-adc"
906ecf69 50
7901b2a1 51struct lpc32xx_adc_state {
906ecf69
RS
52 void __iomem *adc_base;
53 struct clk *clk;
54 struct completion completion;
55
56 u32 value;
57};
58
59static int lpc32xx_read_raw(struct iio_dev *indio_dev,
e8ef49f0
IC
60 struct iio_chan_spec const *chan,
61 int *val,
62 int *val2,
63 long mask)
906ecf69 64{
7901b2a1 65 struct lpc32xx_adc_state *st = iio_priv(indio_dev);
42d97ac6 66 int ret;
b11f98ff 67 if (mask == IIO_CHAN_INFO_RAW) {
906ecf69 68 mutex_lock(&indio_dev->mlock);
42d97ac6
AY
69 ret = clk_prepare_enable(st->clk);
70 if (ret) {
71 mutex_unlock(&indio_dev->mlock);
72 return ret;
73 }
906ecf69 74 /* Measurement setup */
5023574a
JC
75 __raw_writel(LPC32XXAD_INTERNAL | (chan->address) |
76 LPC32XXAD_REFp | LPC32XXAD_REFm,
7901b2a1 77 LPC32XXAD_SELECT(st->adc_base));
906ecf69 78 /* Trigger conversion */
5023574a 79 __raw_writel(LPC32XXAD_PDN_CTRL | LPC32XXAD_STROBE,
7901b2a1
JC
80 LPC32XXAD_CTRL(st->adc_base));
81 wait_for_completion(&st->completion); /* set by ISR */
82 clk_disable_unprepare(st->clk);
83 *val = st->value;
906ecf69
RS
84 mutex_unlock(&indio_dev->mlock);
85
86 return IIO_VAL_INT;
87 }
88
89 return -EINVAL;
90}
91
92static const struct iio_info lpc32xx_adc_iio_info = {
93 .read_raw = &lpc32xx_read_raw,
906ecf69
RS
94};
95
b11f98ff
JC
96#define LPC32XX_ADC_CHANNEL(_index) { \
97 .type = IIO_VOLTAGE, \
98 .indexed = 1, \
99 .channel = _index, \
066f9051 100 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
5023574a 101 .address = LPC32XXAD_IN * _index, \
b11f98ff 102 .scan_index = _index, \
906ecf69
RS
103}
104
f4e4b955 105static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
906ecf69
RS
106 LPC32XX_ADC_CHANNEL(0),
107 LPC32XX_ADC_CHANNEL(1),
108 LPC32XX_ADC_CHANNEL(2),
109};
110
111static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id)
112{
7901b2a1 113 struct lpc32xx_adc_state *st = dev_id;
906ecf69
RS
114
115 /* Read value and clear irq */
7901b2a1
JC
116 st->value = __raw_readl(LPC32XXAD_VALUE(st->adc_base)) &
117 LPC32XXAD_VALUE_MASK;
118 complete(&st->completion);
906ecf69
RS
119
120 return IRQ_HANDLED;
121}
122
4ae1c61f 123static int lpc32xx_adc_probe(struct platform_device *pdev)
906ecf69 124{
7901b2a1 125 struct lpc32xx_adc_state *st = NULL;
906ecf69
RS
126 struct resource *res;
127 int retval = -ENODEV;
128 struct iio_dev *iodev = NULL;
129 int irq;
130
131 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
132 if (!res) {
133 dev_err(&pdev->dev, "failed to get platform I/O memory\n");
f6707ef7 134 return -ENXIO;
906ecf69
RS
135 }
136
7901b2a1 137 iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
7d456e4e
SK
138 if (!iodev)
139 return -ENOMEM;
906ecf69 140
7901b2a1 141 st = iio_priv(iodev);
906ecf69 142
7901b2a1
JC
143 st->adc_base = devm_ioremap(&pdev->dev, res->start,
144 resource_size(res));
145 if (!st->adc_base) {
906ecf69 146 dev_err(&pdev->dev, "failed mapping memory\n");
7d456e4e 147 return -EBUSY;
906ecf69
RS
148 }
149
7901b2a1
JC
150 st->clk = devm_clk_get(&pdev->dev, NULL);
151 if (IS_ERR(st->clk)) {
906ecf69 152 dev_err(&pdev->dev, "failed getting clock\n");
7901b2a1 153 return PTR_ERR(st->clk);
906ecf69
RS
154 }
155
156 irq = platform_get_irq(pdev, 0);
2918ad14 157 if (irq <= 0) {
906ecf69 158 dev_err(&pdev->dev, "failed getting interrupt resource\n");
f6707ef7 159 return -ENXIO;
906ecf69
RS
160 }
161
7d456e4e 162 retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
7901b2a1 163 LPC32XXAD_NAME, st);
906ecf69
RS
164 if (retval < 0) {
165 dev_err(&pdev->dev, "failed requesting interrupt\n");
7d456e4e 166 return retval;
906ecf69
RS
167 }
168
169 platform_set_drvdata(pdev, iodev);
170
7901b2a1 171 init_completion(&st->completion);
906ecf69 172
5023574a 173 iodev->name = LPC32XXAD_NAME;
906ecf69
RS
174 iodev->dev.parent = &pdev->dev;
175 iodev->info = &lpc32xx_adc_iio_info;
176 iodev->modes = INDIO_DIRECT_MODE;
177 iodev->channels = lpc32xx_adc_iio_channels;
178 iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
179
afb6fd5f 180 retval = devm_iio_device_register(&pdev->dev, iodev);
906ecf69 181 if (retval)
7d456e4e 182 return retval;
906ecf69
RS
183
184 dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq);
185
186 return 0;
906ecf69
RS
187}
188
1f9e3494
RS
189#ifdef CONFIG_OF
190static const struct of_device_id lpc32xx_adc_match[] = {
191 { .compatible = "nxp,lpc3220-adc" },
192 {},
193};
194MODULE_DEVICE_TABLE(of, lpc32xx_adc_match);
195#endif
196
906ecf69
RS
197static struct platform_driver lpc32xx_adc_driver = {
198 .probe = lpc32xx_adc_probe,
906ecf69 199 .driver = {
5023574a 200 .name = LPC32XXAD_NAME,
1f9e3494 201 .of_match_table = of_match_ptr(lpc32xx_adc_match),
906ecf69
RS
202 },
203};
204
205module_platform_driver(lpc32xx_adc_driver);
206
207MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
208MODULE_DESCRIPTION("LPC32XX ADC driver");
209MODULE_LICENSE("GPL");