Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/iio/dac/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 12 kB image not shown  

Quelle  ad5421.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * AD5421 Digital to analog converters  driver
 *
 * Copyright 2011 Analog Devices Inc.
 */


#include <linux/device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>

#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/dac/ad5421.h>


#define AD5421_REG_DAC_DATA  0x1
#define AD5421_REG_CTRL   0x2
#define AD5421_REG_OFFSET  0x3
#define AD5421_REG_GAIN   0x4
/* load dac and fault shared the same register number. Writing to it will cause
 * a dac load command, reading from it will return the fault status register */

#define AD5421_REG_LOAD_DAC  0x5
#define AD5421_REG_FAULT  0x5
#define AD5421_REG_FORCE_ALARM_CURRENT 0x6
#define AD5421_REG_RESET  0x7
#define AD5421_REG_START_CONVERSION 0x8
#define AD5421_REG_NOOP   0x9

#define AD5421_CTRL_WATCHDOG_DISABLE BIT(12)
#define AD5421_CTRL_AUTO_FAULT_READBACK BIT(11)
#define AD5421_CTRL_MIN_CURRENT  BIT(9)
#define AD5421_CTRL_ADC_SOURCE_TEMP BIT(8)
#define AD5421_CTRL_ADC_ENABLE  BIT(7)
#define AD5421_CTRL_PWR_DOWN_INT_VREF BIT(6)

#define AD5421_FAULT_SPI   BIT(15)
#define AD5421_FAULT_PEC   BIT(14)
#define AD5421_FAULT_OVER_CURRENT  BIT(13)
#define AD5421_FAULT_UNDER_CURRENT  BIT(12)
#define AD5421_FAULT_TEMP_OVER_140  BIT(11)
#define AD5421_FAULT_TEMP_OVER_100  BIT(10)
#define AD5421_FAULT_UNDER_VOLTAGE_6V  BIT(9)
#define AD5421_FAULT_UNDER_VOLTAGE_12V  BIT(8)

/* These bits will cause the fault pin to go high */
#define AD5421_FAULT_TRIGGER_IRQ \
 (AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \
 AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140)

/**
 * struct ad5421_state - driver instance specific data
 * @spi: spi_device
 * @ctrl: control register cache
 * @current_range: current range which the device is configured for
 * @data: spi transfer buffers
 * @fault_mask: software masking of events
 * @lock: lock to protect the data buffer during SPI ops
 */

struct ad5421_state {
 struct spi_device  *spi;
 unsigned int   ctrl;
 enum ad5421_current_range current_range;
 unsigned int   fault_mask;
 struct mutex   lock;

 /*
 * DMA (thus cache coherency maintenance) may require the
 * transfer buffers to live in their own cache lines.
 */

 union {
  __be32 d32;
  u8 d8[4];
 } data[2] __aligned(IIO_DMA_MINALIGN);
};

static const struct iio_event_spec ad5421_current_event[] = {
 {
  .type = IIO_EV_TYPE_THRESH,
  .dir = IIO_EV_DIR_RISING,
  .mask_separate = BIT(IIO_EV_INFO_VALUE) |
   BIT(IIO_EV_INFO_ENABLE),
 }, {
  .type = IIO_EV_TYPE_THRESH,
  .dir = IIO_EV_DIR_FALLING,
  .mask_separate = BIT(IIO_EV_INFO_VALUE) |
   BIT(IIO_EV_INFO_ENABLE),
 },
};

static const struct iio_event_spec ad5421_temp_event[] = {
 {
  .type = IIO_EV_TYPE_THRESH,
  .dir = IIO_EV_DIR_RISING,
  .mask_separate = BIT(IIO_EV_INFO_VALUE) |
   BIT(IIO_EV_INFO_ENABLE),
 },
};

static const struct iio_chan_spec ad5421_channels[] = {
 {
  .type = IIO_CURRENT,
  .indexed = 1,
  .output = 1,
  .channel = 0,
  .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
   BIT(IIO_CHAN_INFO_CALIBSCALE) |
   BIT(IIO_CHAN_INFO_CALIBBIAS),
  .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
   BIT(IIO_CHAN_INFO_OFFSET),
  .scan_type = {
   .sign = 'u',
   .realbits = 16,
   .storagebits = 16,
  },
  .event_spec = ad5421_current_event,
  .num_event_specs = ARRAY_SIZE(ad5421_current_event),
 },
 {
  .type = IIO_TEMP,
  .channel = -1,
  .event_spec = ad5421_temp_event,
  .num_event_specs = ARRAY_SIZE(ad5421_temp_event),
 },
};

static int ad5421_write_unlocked(struct iio_dev *indio_dev,
 unsigned int reg, unsigned int val)
{
 struct ad5421_state *st = iio_priv(indio_dev);

 st->data[0].d32 = cpu_to_be32((reg << 16) | val);

 return spi_write(st->spi, &st->data[0].d8[1], 3);
}

static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
 unsigned int val)
{
 struct ad5421_state *st = iio_priv(indio_dev);
 int ret;

 mutex_lock(&st->lock);
 ret = ad5421_write_unlocked(indio_dev, reg, val);
 mutex_unlock(&st->lock);

 return ret;
}

static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
{
 struct ad5421_state *st = iio_priv(indio_dev);
 int ret;
 struct spi_transfer t[] = {
  {
   .tx_buf = &st->data[0].d8[1],
   .len = 3,
   .cs_change = 1,
  }, {
   .rx_buf = &st->data[1].d8[1],
   .len = 3,
  },
 };

 mutex_lock(&st->lock);

 st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));

 ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
 if (ret >= 0)
  ret = be32_to_cpu(st->data[1].d32) & 0xffff;

 mutex_unlock(&st->lock);

 return ret;
}

static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
 unsigned int clr)
{
 struct ad5421_state *st = iio_priv(indio_dev);
 int ret;

 mutex_lock(&st->lock);

 st->ctrl &= ~clr;
 st->ctrl |= set;

 ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl);

 mutex_unlock(&st->lock);

 return ret;
}

static irqreturn_t ad5421_fault_handler(int irq, void *data)
{
 struct iio_dev *indio_dev = data;
 struct ad5421_state *st = iio_priv(indio_dev);
 unsigned int fault;
 unsigned int old_fault = 0;
 unsigned int events;

 fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
 if (!fault)
  return IRQ_NONE;

 /* If we had a fault, this might mean that the DAC has lost its state
 * and has been reset. Make sure that the control register actually
 * contains what we expect it to contain. Otherwise the watchdog might
 * be enabled and we get watchdog timeout faults, which will render the
 * DAC unusable. */

 ad5421_update_ctrl(indio_dev, 0, 0);


 /* The fault pin stays high as long as a fault condition is present and
 * it is not possible to mask fault conditions. For certain fault
 * conditions for example like over-temperature it takes some time
 * until the fault condition disappears. If we would exit the interrupt
 * handler immediately after handling the event it would be entered
 * again instantly. Thus we fall back to polling in case we detect that
 * a interrupt condition is still present.
 */

 do {
  /* 0xffff is a invalid value for the register and will only be
 * read if there has been a communication error */

  if (fault == 0xffff)
   fault = 0;

  /* we are only interested in new events */
  events = (old_fault ^ fault) & fault;
  events &= st->fault_mask;

  if (events & AD5421_FAULT_OVER_CURRENT) {
   iio_push_event(indio_dev,
    IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
     0,
     IIO_EV_TYPE_THRESH,
     IIO_EV_DIR_RISING),
   iio_get_time_ns(indio_dev));
  }

  if (events & AD5421_FAULT_UNDER_CURRENT) {
   iio_push_event(indio_dev,
    IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
     0,
     IIO_EV_TYPE_THRESH,
     IIO_EV_DIR_FALLING),
    iio_get_time_ns(indio_dev));
  }

  if (events & AD5421_FAULT_TEMP_OVER_140) {
   iio_push_event(indio_dev,
    IIO_UNMOD_EVENT_CODE(IIO_TEMP,
     0,
     IIO_EV_TYPE_MAG,
     IIO_EV_DIR_RISING),
    iio_get_time_ns(indio_dev));
  }

  old_fault = fault;
  fault = ad5421_read(indio_dev, AD5421_REG_FAULT);

  /* still active? go to sleep for some time */
  if (fault & AD5421_FAULT_TRIGGER_IRQ)
   msleep(1000);

 } while (fault & AD5421_FAULT_TRIGGER_IRQ);


 return IRQ_HANDLED;
}

static void ad5421_get_current_min_max(struct ad5421_state *st,
 unsigned int *min, unsigned int *max)
{
 /* The current range is configured using external pins, which are
 * usually hard-wired and not run-time switchable. */

 switch (st->current_range) {
 case AD5421_CURRENT_RANGE_4mA_20mA:
  *min = 4000;
  *max = 20000;
  break;
 case AD5421_CURRENT_RANGE_3mA8_21mA:
  *min = 3800;
  *max = 21000;
  break;
 case AD5421_CURRENT_RANGE_3mA2_24mA:
  *min = 3200;
  *max = 24000;
  break;
 default:
  *min = 0;
  *max = 1;
  break;
 }
}

static inline unsigned int ad5421_get_offset(struct ad5421_state *st)
{
 unsigned int min, max;

 ad5421_get_current_min_max(st, &min, &max);
 return (min * (1 << 16)) / (max - min);
}

static int ad5421_read_raw(struct iio_dev *indio_dev,
 struct iio_chan_spec const *chan, int *val, int *val2, long m)
{
 struct ad5421_state *st = iio_priv(indio_dev);
 unsigned int min, max;
 int ret;

 if (chan->type != IIO_CURRENT)
  return -EINVAL;

 switch (m) {
 case IIO_CHAN_INFO_RAW:
  ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
  if (ret < 0)
   return ret;
  *val = ret;
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_SCALE:
  ad5421_get_current_min_max(st, &min, &max);
  *val = max - min;
  *val2 = (1 << 16) * 1000;
  return IIO_VAL_FRACTIONAL;
 case IIO_CHAN_INFO_OFFSET:
  *val = ad5421_get_offset(st);
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_CALIBBIAS:
  ret = ad5421_read(indio_dev, AD5421_REG_OFFSET);
  if (ret < 0)
   return ret;
  *val = ret - 32768;
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_CALIBSCALE:
  ret = ad5421_read(indio_dev, AD5421_REG_GAIN);
  if (ret < 0)
   return ret;
  *val = ret;
  return IIO_VAL_INT;
 }

 return -EINVAL;
}

static int ad5421_write_raw(struct iio_dev *indio_dev,
 struct iio_chan_spec const *chan, int val, int val2, long mask)
{
 const unsigned int max_val = 1 << 16;

 switch (mask) {
 case IIO_CHAN_INFO_RAW:
  if (val >= max_val || val < 0)
   return -EINVAL;

  return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val);
 case IIO_CHAN_INFO_CALIBBIAS:
  val += 32768;
  if (val >= max_val || val < 0)
   return -EINVAL;

  return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
 case IIO_CHAN_INFO_CALIBSCALE:
  if (val >= max_val || val < 0)
   return -EINVAL;

  return ad5421_write(indio_dev, AD5421_REG_GAIN, val);
 default:
  break;
 }

 return -EINVAL;
}

static int ad5421_write_event_config(struct iio_dev *indio_dev,
 const struct iio_chan_spec *chan, enum iio_event_type type,
 enum iio_event_direction dir, bool state)
{
 struct ad5421_state *st = iio_priv(indio_dev);
 unsigned int mask;

 switch (chan->type) {
 case IIO_CURRENT:
  if (dir == IIO_EV_DIR_RISING)
   mask = AD5421_FAULT_OVER_CURRENT;
  else
   mask = AD5421_FAULT_UNDER_CURRENT;
  break;
 case IIO_TEMP:
  mask = AD5421_FAULT_TEMP_OVER_140;
  break;
 default:
  return -EINVAL;
 }

 mutex_lock(&st->lock);
 if (state)
  st->fault_mask |= mask;
 else
  st->fault_mask &= ~mask;
 mutex_unlock(&st->lock);

 return 0;
}

static int ad5421_read_event_config(struct iio_dev *indio_dev,
 const struct iio_chan_spec *chan, enum iio_event_type type,
 enum iio_event_direction dir)
{
 struct ad5421_state *st = iio_priv(indio_dev);
 unsigned int mask;

 switch (chan->type) {
 case IIO_CURRENT:
  if (dir == IIO_EV_DIR_RISING)
   mask = AD5421_FAULT_OVER_CURRENT;
  else
   mask = AD5421_FAULT_UNDER_CURRENT;
  break;
 case IIO_TEMP:
  mask = AD5421_FAULT_TEMP_OVER_140;
  break;
 default:
  return -EINVAL;
 }

 return (bool)(st->fault_mask & mask);
}

static int ad5421_read_event_value(struct iio_dev *indio_dev,
 const struct iio_chan_spec *chan, enum iio_event_type type,
 enum iio_event_direction dir, enum iio_event_info info, int *val,
 int *val2)
{
 int ret;

 switch (chan->type) {
 case IIO_CURRENT:
  ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
  if (ret < 0)
   return ret;
  *val = ret;
  break;
 case IIO_TEMP:
  *val = 140000;
  break;
 default:
  return -EINVAL;
 }

 return IIO_VAL_INT;
}

static const struct iio_info ad5421_info = {
 .read_raw =  ad5421_read_raw,
 .write_raw =  ad5421_write_raw,
 .read_event_config = ad5421_read_event_config,
 .write_event_config = ad5421_write_event_config,
 .read_event_value = ad5421_read_event_value,
};

static int ad5421_probe(struct spi_device *spi)
{
 struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev);
 struct iio_dev *indio_dev;
 struct ad5421_state *st;
 int ret;

 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 if (indio_dev == NULL) {
  dev_err(&spi->dev, "Failed to allocate iio device\n");
  return  -ENOMEM;
 }

 st = iio_priv(indio_dev);
 spi_set_drvdata(spi, indio_dev);

 st->spi = spi;

 indio_dev->name = "ad5421";
 indio_dev->info = &ad5421_info;
 indio_dev->modes = INDIO_DIRECT_MODE;
 indio_dev->channels = ad5421_channels;
 indio_dev->num_channels = ARRAY_SIZE(ad5421_channels);

 mutex_init(&st->lock);

 st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE |
   AD5421_CTRL_AUTO_FAULT_READBACK;

 if (pdata) {
  st->current_range = pdata->current_range;
  if (pdata->external_vref)
   st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF;
 } else {
  st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
 }

 /* write initial ctrl register value */
 ad5421_update_ctrl(indio_dev, 0, 0);

 if (spi->irq) {
  ret = devm_request_threaded_irq(&spi->dev, spi->irq,
        NULL,
        ad5421_fault_handler,
        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
        "ad5421 fault",
        indio_dev);
  if (ret)
   return ret;
 }

 return devm_iio_device_register(&spi->dev, indio_dev);
}

static struct spi_driver ad5421_driver = {
 .driver = {
     .name = "ad5421",
 },
 .probe = ad5421_probe,
};
module_spi_driver(ad5421_driver);

MODULE_AUTHOR("Lars-Peter Clausen ");
MODULE_DESCRIPTION("Analog Devices AD5421 DAC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:ad5421");

Messung V0.5
C=98 H=99 G=98

¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.