root/drivers/iio/dac/lpc18xx_dac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lpc18xx_dac_read_raw
  2. lpc18xx_dac_write_raw
  3. lpc18xx_dac_probe
  4. lpc18xx_dac_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * IIO DAC driver for NXP LPC18xx DAC
   4  *
   5  * Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com>
   6  *
   7  * UNSUPPORTED hardware features:
   8  *  - Interrupts
   9  *  - DMA
  10  */
  11 
  12 #include <linux/clk.h>
  13 #include <linux/err.h>
  14 #include <linux/iio/iio.h>
  15 #include <linux/iio/driver.h>
  16 #include <linux/io.h>
  17 #include <linux/iopoll.h>
  18 #include <linux/module.h>
  19 #include <linux/mutex.h>
  20 #include <linux/of.h>
  21 #include <linux/of_device.h>
  22 #include <linux/platform_device.h>
  23 #include <linux/regulator/consumer.h>
  24 
  25 /* LPC18XX DAC registers and bits */
  26 #define LPC18XX_DAC_CR                  0x000
  27 #define  LPC18XX_DAC_CR_VALUE_SHIFT     6
  28 #define  LPC18XX_DAC_CR_VALUE_MASK      0x3ff
  29 #define  LPC18XX_DAC_CR_BIAS            BIT(16)
  30 #define LPC18XX_DAC_CTRL                0x004
  31 #define  LPC18XX_DAC_CTRL_DMA_ENA       BIT(3)
  32 
  33 struct lpc18xx_dac {
  34         struct regulator *vref;
  35         void __iomem *base;
  36         struct mutex lock;
  37         struct clk *clk;
  38 };
  39 
  40 static const struct iio_chan_spec lpc18xx_dac_iio_channels[] = {
  41         {
  42                 .type = IIO_VOLTAGE,
  43                 .output = 1,
  44                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  45                                       BIT(IIO_CHAN_INFO_SCALE),
  46         },
  47 };
  48 
  49 static int lpc18xx_dac_read_raw(struct iio_dev *indio_dev,
  50                                 struct iio_chan_spec const *chan,
  51                                 int *val, int *val2, long mask)
  52 {
  53         struct lpc18xx_dac *dac = iio_priv(indio_dev);
  54         u32 reg;
  55 
  56         switch (mask) {
  57         case IIO_CHAN_INFO_RAW:
  58                 reg = readl(dac->base + LPC18XX_DAC_CR);
  59                 *val = reg >> LPC18XX_DAC_CR_VALUE_SHIFT;
  60                 *val &= LPC18XX_DAC_CR_VALUE_MASK;
  61 
  62                 return IIO_VAL_INT;
  63 
  64         case IIO_CHAN_INFO_SCALE:
  65                 *val = regulator_get_voltage(dac->vref) / 1000;
  66                 *val2 = 10;
  67 
  68                 return IIO_VAL_FRACTIONAL_LOG2;
  69         }
  70 
  71         return -EINVAL;
  72 }
  73 
  74 static int lpc18xx_dac_write_raw(struct iio_dev *indio_dev,
  75                                  struct iio_chan_spec const *chan,
  76                                  int val, int val2, long mask)
  77 {
  78         struct lpc18xx_dac *dac = iio_priv(indio_dev);
  79         u32 reg;
  80 
  81         switch (mask) {
  82         case IIO_CHAN_INFO_RAW:
  83                 if (val < 0 || val > LPC18XX_DAC_CR_VALUE_MASK)
  84                         return -EINVAL;
  85 
  86                 reg = LPC18XX_DAC_CR_BIAS;
  87                 reg |= val << LPC18XX_DAC_CR_VALUE_SHIFT;
  88 
  89                 mutex_lock(&dac->lock);
  90                 writel(reg, dac->base + LPC18XX_DAC_CR);
  91                 writel(LPC18XX_DAC_CTRL_DMA_ENA, dac->base + LPC18XX_DAC_CTRL);
  92                 mutex_unlock(&dac->lock);
  93 
  94                 return 0;
  95         }
  96 
  97         return -EINVAL;
  98 }
  99 
 100 static const struct iio_info lpc18xx_dac_info = {
 101         .read_raw = lpc18xx_dac_read_raw,
 102         .write_raw = lpc18xx_dac_write_raw,
 103 };
 104 
 105 static int lpc18xx_dac_probe(struct platform_device *pdev)
 106 {
 107         struct iio_dev *indio_dev;
 108         struct lpc18xx_dac *dac;
 109         struct resource *res;
 110         int ret;
 111 
 112         indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
 113         if (!indio_dev)
 114                 return -ENOMEM;
 115 
 116         platform_set_drvdata(pdev, indio_dev);
 117         dac = iio_priv(indio_dev);
 118         mutex_init(&dac->lock);
 119 
 120         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 121         dac->base = devm_ioremap_resource(&pdev->dev, res);
 122         if (IS_ERR(dac->base))
 123                 return PTR_ERR(dac->base);
 124 
 125         dac->clk = devm_clk_get(&pdev->dev, NULL);
 126         if (IS_ERR(dac->clk)) {
 127                 dev_err(&pdev->dev, "error getting clock\n");
 128                 return PTR_ERR(dac->clk);
 129         }
 130 
 131         dac->vref = devm_regulator_get(&pdev->dev, "vref");
 132         if (IS_ERR(dac->vref)) {
 133                 dev_err(&pdev->dev, "error getting regulator\n");
 134                 return PTR_ERR(dac->vref);
 135         }
 136 
 137         indio_dev->name = dev_name(&pdev->dev);
 138         indio_dev->dev.parent = &pdev->dev;
 139         indio_dev->info = &lpc18xx_dac_info;
 140         indio_dev->modes = INDIO_DIRECT_MODE;
 141         indio_dev->channels = lpc18xx_dac_iio_channels;
 142         indio_dev->num_channels = ARRAY_SIZE(lpc18xx_dac_iio_channels);
 143 
 144         ret = regulator_enable(dac->vref);
 145         if (ret) {
 146                 dev_err(&pdev->dev, "unable to enable regulator\n");
 147                 return ret;
 148         }
 149 
 150         ret = clk_prepare_enable(dac->clk);
 151         if (ret) {
 152                 dev_err(&pdev->dev, "unable to enable clock\n");
 153                 goto dis_reg;
 154         }
 155 
 156         writel(0, dac->base + LPC18XX_DAC_CTRL);
 157         writel(0, dac->base + LPC18XX_DAC_CR);
 158 
 159         ret = iio_device_register(indio_dev);
 160         if (ret) {
 161                 dev_err(&pdev->dev, "unable to register device\n");
 162                 goto dis_clk;
 163         }
 164 
 165         return 0;
 166 
 167 dis_clk:
 168         clk_disable_unprepare(dac->clk);
 169 dis_reg:
 170         regulator_disable(dac->vref);
 171         return ret;
 172 }
 173 
 174 static int lpc18xx_dac_remove(struct platform_device *pdev)
 175 {
 176         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 177         struct lpc18xx_dac *dac = iio_priv(indio_dev);
 178 
 179         iio_device_unregister(indio_dev);
 180 
 181         writel(0, dac->base + LPC18XX_DAC_CTRL);
 182         clk_disable_unprepare(dac->clk);
 183         regulator_disable(dac->vref);
 184 
 185         return 0;
 186 }
 187 
 188 static const struct of_device_id lpc18xx_dac_match[] = {
 189         { .compatible = "nxp,lpc1850-dac" },
 190         { /* sentinel */ }
 191 };
 192 MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
 193 
 194 static struct platform_driver lpc18xx_dac_driver = {
 195         .probe  = lpc18xx_dac_probe,
 196         .remove = lpc18xx_dac_remove,
 197         .driver = {
 198                 .name = "lpc18xx-dac",
 199                 .of_match_table = lpc18xx_dac_match,
 200         },
 201 };
 202 module_platform_driver(lpc18xx_dac_driver);
 203 
 204 MODULE_DESCRIPTION("LPC18xx DAC driver");
 205 MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
 206 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */