diff options
author | Joachim Eastwood <manabian@gmail.com> | 2016-03-12 07:30:16 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2016-03-12 13:12:37 -0500 |
commit | 9bbccbe11ab78c74bed9a2bc99943929f49ca565 (patch) | |
tree | eec07f4896bc6a97da6126b817aa551f3b6c7cdc /drivers/iio | |
parent | edcb2d26c10206b35a5736139f5dce02fc4bbdc9 (diff) |
iio: dac: add NXP LPC18xx DAC driver
Add base support for the 10-bit DAC peripheral found
on NXP LPC18xx/43xx SoCs.
This is a minimal driver that does not support DMA or
interrupts.
User manual with register description can be found on:
LPC18xx: www.nxp.com/documents/user_manual/UM10430.pdf
LPC43xx: www.nxp.com/documents/user_manual/UM10503.pdf
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/dac/Kconfig | 10 | ||||
-rw-r--r-- | drivers/iio/dac/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/dac/lpc18xx_dac.c | 210 |
3 files changed, 221 insertions, 0 deletions
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index a995139f907c..210db81ca144 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig | |||
@@ -154,6 +154,16 @@ config AD7303 | |||
154 | To compile this driver as module choose M here: the module will be called | 154 | To compile this driver as module choose M here: the module will be called |
155 | ad7303. | 155 | ad7303. |
156 | 156 | ||
157 | config LPC18XX_DAC | ||
158 | tristate "NXP LPC18xx DAC driver" | ||
159 | depends on ARCH_LPC18XX || COMPILE_TEST | ||
160 | depends on OF && HAS_IOMEM | ||
161 | help | ||
162 | Say yes here to build support for NXP LPC18XX DAC. | ||
163 | |||
164 | To compile this driver as a module, choose M here: the module will be | ||
165 | called lpc18xx_dac. | ||
166 | |||
157 | config M62332 | 167 | config M62332 |
158 | tristate "Mitsubishi M62332 DAC driver" | 168 | tristate "Mitsubishi M62332 DAC driver" |
159 | depends on I2C | 169 | depends on I2C |
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 67b48429686d..420a15cdaa53 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile | |||
@@ -17,6 +17,7 @@ obj-$(CONFIG_AD5764) += ad5764.o | |||
17 | obj-$(CONFIG_AD5791) += ad5791.o | 17 | obj-$(CONFIG_AD5791) += ad5791.o |
18 | obj-$(CONFIG_AD5686) += ad5686.o | 18 | obj-$(CONFIG_AD5686) += ad5686.o |
19 | obj-$(CONFIG_AD7303) += ad7303.o | 19 | obj-$(CONFIG_AD7303) += ad7303.o |
20 | obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o | ||
20 | obj-$(CONFIG_M62332) += m62332.o | 21 | obj-$(CONFIG_M62332) += m62332.o |
21 | obj-$(CONFIG_MAX517) += max517.o | 22 | obj-$(CONFIG_MAX517) += max517.o |
22 | obj-$(CONFIG_MAX5821) += max5821.o | 23 | obj-$(CONFIG_MAX5821) += max5821.o |
diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c new file mode 100644 index 000000000000..55d1456a059d --- /dev/null +++ b/drivers/iio/dac/lpc18xx_dac.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * IIO DAC driver for NXP LPC18xx DAC | ||
3 | * | ||
4 | * Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * UNSUPPORTED hardware features: | ||
11 | * - Interrupts | ||
12 | * - DMA | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/iio/iio.h> | ||
18 | #include <linux/iio/driver.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/iopoll.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/of_device.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | |||
28 | /* LPC18XX DAC registers and bits */ | ||
29 | #define LPC18XX_DAC_CR 0x000 | ||
30 | #define LPC18XX_DAC_CR_VALUE_SHIFT 6 | ||
31 | #define LPC18XX_DAC_CR_VALUE_MASK 0x3ff | ||
32 | #define LPC18XX_DAC_CR_BIAS BIT(16) | ||
33 | #define LPC18XX_DAC_CTRL 0x004 | ||
34 | #define LPC18XX_DAC_CTRL_DMA_ENA BIT(3) | ||
35 | |||
36 | struct lpc18xx_dac { | ||
37 | struct regulator *vref; | ||
38 | void __iomem *base; | ||
39 | struct mutex lock; | ||
40 | struct clk *clk; | ||
41 | }; | ||
42 | |||
43 | static const struct iio_chan_spec lpc18xx_dac_iio_channels[] = { | ||
44 | { | ||
45 | .type = IIO_VOLTAGE, | ||
46 | .output = 1, | ||
47 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
48 | BIT(IIO_CHAN_INFO_SCALE), | ||
49 | }, | ||
50 | }; | ||
51 | |||
52 | static int lpc18xx_dac_read_raw(struct iio_dev *indio_dev, | ||
53 | struct iio_chan_spec const *chan, | ||
54 | int *val, int *val2, long mask) | ||
55 | { | ||
56 | struct lpc18xx_dac *dac = iio_priv(indio_dev); | ||
57 | u32 reg; | ||
58 | |||
59 | switch (mask) { | ||
60 | case IIO_CHAN_INFO_RAW: | ||
61 | reg = readl(dac->base + LPC18XX_DAC_CR); | ||
62 | *val = reg >> LPC18XX_DAC_CR_VALUE_SHIFT; | ||
63 | *val &= LPC18XX_DAC_CR_VALUE_MASK; | ||
64 | |||
65 | return IIO_VAL_INT; | ||
66 | |||
67 | case IIO_CHAN_INFO_SCALE: | ||
68 | *val = regulator_get_voltage(dac->vref) / 1000; | ||
69 | *val2 = 10; | ||
70 | |||
71 | return IIO_VAL_FRACTIONAL_LOG2; | ||
72 | } | ||
73 | |||
74 | return -EINVAL; | ||
75 | } | ||
76 | |||
77 | static int lpc18xx_dac_write_raw(struct iio_dev *indio_dev, | ||
78 | struct iio_chan_spec const *chan, | ||
79 | int val, int val2, long mask) | ||
80 | { | ||
81 | struct lpc18xx_dac *dac = iio_priv(indio_dev); | ||
82 | u32 reg; | ||
83 | |||
84 | switch (mask) { | ||
85 | case IIO_CHAN_INFO_RAW: | ||
86 | if (val < 0 || val > LPC18XX_DAC_CR_VALUE_MASK) | ||
87 | return -EINVAL; | ||
88 | |||
89 | reg = LPC18XX_DAC_CR_BIAS; | ||
90 | reg |= val << LPC18XX_DAC_CR_VALUE_SHIFT; | ||
91 | |||
92 | mutex_lock(&dac->lock); | ||
93 | writel(reg, dac->base + LPC18XX_DAC_CR); | ||
94 | writel(LPC18XX_DAC_CTRL_DMA_ENA, dac->base + LPC18XX_DAC_CTRL); | ||
95 | mutex_unlock(&dac->lock); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | return -EINVAL; | ||
101 | } | ||
102 | |||
103 | static const struct iio_info lpc18xx_dac_info = { | ||
104 | .read_raw = lpc18xx_dac_read_raw, | ||
105 | .write_raw = lpc18xx_dac_write_raw, | ||
106 | .driver_module = THIS_MODULE, | ||
107 | }; | ||
108 | |||
109 | static int lpc18xx_dac_probe(struct platform_device *pdev) | ||
110 | { | ||
111 | struct iio_dev *indio_dev; | ||
112 | struct lpc18xx_dac *dac; | ||
113 | struct resource *res; | ||
114 | int ret; | ||
115 | |||
116 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac)); | ||
117 | if (!indio_dev) | ||
118 | return -ENOMEM; | ||
119 | |||
120 | platform_set_drvdata(pdev, indio_dev); | ||
121 | dac = iio_priv(indio_dev); | ||
122 | mutex_init(&dac->lock); | ||
123 | |||
124 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
125 | dac->base = devm_ioremap_resource(&pdev->dev, res); | ||
126 | if (IS_ERR(dac->base)) | ||
127 | return PTR_ERR(dac->base); | ||
128 | |||
129 | dac->clk = devm_clk_get(&pdev->dev, NULL); | ||
130 | if (IS_ERR(dac->clk)) { | ||
131 | dev_err(&pdev->dev, "error getting clock\n"); | ||
132 | return PTR_ERR(dac->clk); | ||
133 | } | ||
134 | |||
135 | dac->vref = devm_regulator_get(&pdev->dev, "vref"); | ||
136 | if (IS_ERR(dac->vref)) { | ||
137 | dev_err(&pdev->dev, "error getting regulator\n"); | ||
138 | return PTR_ERR(dac->vref); | ||
139 | } | ||
140 | |||
141 | indio_dev->name = dev_name(&pdev->dev); | ||
142 | indio_dev->dev.parent = &pdev->dev; | ||
143 | indio_dev->info = &lpc18xx_dac_info; | ||
144 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
145 | indio_dev->channels = lpc18xx_dac_iio_channels; | ||
146 | indio_dev->num_channels = ARRAY_SIZE(lpc18xx_dac_iio_channels); | ||
147 | |||
148 | ret = regulator_enable(dac->vref); | ||
149 | if (ret) { | ||
150 | dev_err(&pdev->dev, "unable to enable regulator\n"); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | ret = clk_prepare_enable(dac->clk); | ||
155 | if (ret) { | ||
156 | dev_err(&pdev->dev, "unable to enable clock\n"); | ||
157 | goto dis_reg; | ||
158 | } | ||
159 | |||
160 | writel(0, dac->base + LPC18XX_DAC_CTRL); | ||
161 | writel(0, dac->base + LPC18XX_DAC_CR); | ||
162 | |||
163 | ret = iio_device_register(indio_dev); | ||
164 | if (ret) { | ||
165 | dev_err(&pdev->dev, "unable to register device\n"); | ||
166 | goto dis_clk; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | |||
171 | dis_clk: | ||
172 | clk_disable_unprepare(dac->clk); | ||
173 | dis_reg: | ||
174 | regulator_disable(dac->vref); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | static int lpc18xx_dac_remove(struct platform_device *pdev) | ||
179 | { | ||
180 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | ||
181 | struct lpc18xx_dac *dac = iio_priv(indio_dev); | ||
182 | |||
183 | iio_device_unregister(indio_dev); | ||
184 | |||
185 | writel(0, dac->base + LPC18XX_DAC_CTRL); | ||
186 | clk_disable_unprepare(dac->clk); | ||
187 | regulator_disable(dac->vref); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static const struct of_device_id lpc18xx_dac_match[] = { | ||
193 | { .compatible = "nxp,lpc1850-dac" }, | ||
194 | { /* sentinel */ } | ||
195 | }; | ||
196 | MODULE_DEVICE_TABLE(of, lpc18xx_dac_match); | ||
197 | |||
198 | static struct platform_driver lpc18xx_dac_driver = { | ||
199 | .probe = lpc18xx_dac_probe, | ||
200 | .remove = lpc18xx_dac_remove, | ||
201 | .driver = { | ||
202 | .name = "lpc18xx-dac", | ||
203 | .of_match_table = lpc18xx_dac_match, | ||
204 | }, | ||
205 | }; | ||
206 | module_platform_driver(lpc18xx_dac_driver); | ||
207 | |||
208 | MODULE_DESCRIPTION("LPC18xx DAC driver"); | ||
209 | MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); | ||
210 | MODULE_LICENSE("GPL v2"); | ||