Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Joachim Eastwood and committed by
Jonathan Cameron
9bbccbe1 edcb2d26

+221
+10
drivers/iio/dac/Kconfig
··· 154 154 To compile this driver as module choose M here: the module will be called 155 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 167 config M62332 158 168 tristate "Mitsubishi M62332 DAC driver" 159 169 depends on I2C
+1
drivers/iio/dac/Makefile
··· 17 17 obj-$(CONFIG_AD5791) += ad5791.o 18 18 obj-$(CONFIG_AD5686) += ad5686.o 19 19 obj-$(CONFIG_AD7303) += ad7303.o 20 + obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o 20 21 obj-$(CONFIG_M62332) += m62332.o 21 22 obj-$(CONFIG_MAX517) += max517.o 22 23 obj-$(CONFIG_MAX5821) += max5821.o
+210
drivers/iio/dac/lpc18xx_dac.c
··· 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");