root/drivers/iio/adc/xilinx-xadc-events.c

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

DEFINITIONS

This source file includes following definitions.
  1. xadc_event_to_channel
  2. xadc_handle_event
  3. xadc_handle_events
  4. xadc_get_threshold_offset
  5. xadc_get_alarm_mask
  6. xadc_read_event_config
  7. xadc_write_event_config
  8. xadc_read_event_value
  9. xadc_write_event_value

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Xilinx XADC driver
   4  *
   5  * Copyright 2013 Analog Devices Inc.
   6  *  Author: Lars-Peter Clauen <lars@metafoo.de>
   7  */
   8 
   9 #include <linux/iio/events.h>
  10 #include <linux/iio/iio.h>
  11 #include <linux/kernel.h>
  12 
  13 #include "xilinx-xadc.h"
  14 
  15 static const struct iio_chan_spec *xadc_event_to_channel(
  16         struct iio_dev *indio_dev, unsigned int event)
  17 {
  18         switch (event) {
  19         case XADC_THRESHOLD_OT_MAX:
  20         case XADC_THRESHOLD_TEMP_MAX:
  21                 return &indio_dev->channels[0];
  22         case XADC_THRESHOLD_VCCINT_MAX:
  23         case XADC_THRESHOLD_VCCAUX_MAX:
  24                 return &indio_dev->channels[event];
  25         default:
  26                 return &indio_dev->channels[event-1];
  27         }
  28 }
  29 
  30 static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
  31 {
  32         const struct iio_chan_spec *chan;
  33 
  34         /* Temperature threshold error, we don't handle this yet */
  35         if (event == 0)
  36                 return;
  37 
  38         chan = xadc_event_to_channel(indio_dev, event);
  39 
  40         if (chan->type == IIO_TEMP) {
  41                 /*
  42                  * The temperature channel only supports over-temperature
  43                  * events.
  44                  */
  45                 iio_push_event(indio_dev,
  46                         IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
  47                                 IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
  48                         iio_get_time_ns(indio_dev));
  49         } else {
  50                 /*
  51                  * For other channels we don't know whether it is a upper or
  52                  * lower threshold event. Userspace will have to check the
  53                  * channel value if it wants to know.
  54                  */
  55                 iio_push_event(indio_dev,
  56                         IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
  57                                 IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
  58                         iio_get_time_ns(indio_dev));
  59         }
  60 }
  61 
  62 void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
  63 {
  64         unsigned int i;
  65 
  66         for_each_set_bit(i, &events, 8)
  67                 xadc_handle_event(indio_dev, i);
  68 }
  69 
  70 static unsigned int xadc_get_threshold_offset(const struct iio_chan_spec *chan,
  71         enum iio_event_direction dir)
  72 {
  73         unsigned int offset;
  74 
  75         if (chan->type == IIO_TEMP) {
  76                 offset = XADC_THRESHOLD_OT_MAX;
  77         } else {
  78                 if (chan->channel < 2)
  79                         offset = chan->channel + 1;
  80                 else
  81                         offset = chan->channel + 6;
  82         }
  83 
  84         if (dir == IIO_EV_DIR_FALLING)
  85                 offset += 4;
  86 
  87         return offset;
  88 }
  89 
  90 static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
  91 {
  92         if (chan->type == IIO_TEMP)
  93                 return XADC_ALARM_OT_MASK;
  94         switch (chan->channel) {
  95         case 0:
  96                 return XADC_ALARM_VCCINT_MASK;
  97         case 1:
  98                 return XADC_ALARM_VCCAUX_MASK;
  99         case 2:
 100                 return XADC_ALARM_VCCBRAM_MASK;
 101         case 3:
 102                 return XADC_ALARM_VCCPINT_MASK;
 103         case 4:
 104                 return XADC_ALARM_VCCPAUX_MASK;
 105         case 5:
 106                 return XADC_ALARM_VCCODDR_MASK;
 107         default:
 108                 /* We will never get here */
 109                 return 0;
 110         }
 111 }
 112 
 113 int xadc_read_event_config(struct iio_dev *indio_dev,
 114         const struct iio_chan_spec *chan, enum iio_event_type type,
 115         enum iio_event_direction dir)
 116 {
 117         struct xadc *xadc = iio_priv(indio_dev);
 118 
 119         return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan));
 120 }
 121 
 122 int xadc_write_event_config(struct iio_dev *indio_dev,
 123         const struct iio_chan_spec *chan, enum iio_event_type type,
 124         enum iio_event_direction dir, int state)
 125 {
 126         unsigned int alarm = xadc_get_alarm_mask(chan);
 127         struct xadc *xadc = iio_priv(indio_dev);
 128         uint16_t cfg, old_cfg;
 129         int ret;
 130 
 131         mutex_lock(&xadc->mutex);
 132 
 133         if (state)
 134                 xadc->alarm_mask |= alarm;
 135         else
 136                 xadc->alarm_mask &= ~alarm;
 137 
 138         xadc->ops->update_alarm(xadc, xadc->alarm_mask);
 139 
 140         ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg);
 141         if (ret)
 142                 goto err_out;
 143 
 144         old_cfg = cfg;
 145         cfg |= XADC_CONF1_ALARM_MASK;
 146         cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */
 147         cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */
 148         cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */
 149         if (old_cfg != cfg)
 150                 ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg);
 151 
 152 err_out:
 153         mutex_unlock(&xadc->mutex);
 154 
 155         return ret;
 156 }
 157 
 158 /* Register value is msb aligned, the lower 4 bits are ignored */
 159 #define XADC_THRESHOLD_VALUE_SHIFT 4
 160 
 161 int xadc_read_event_value(struct iio_dev *indio_dev,
 162         const struct iio_chan_spec *chan, enum iio_event_type type,
 163         enum iio_event_direction dir, enum iio_event_info info,
 164         int *val, int *val2)
 165 {
 166         unsigned int offset = xadc_get_threshold_offset(chan, dir);
 167         struct xadc *xadc = iio_priv(indio_dev);
 168 
 169         switch (info) {
 170         case IIO_EV_INFO_VALUE:
 171                 *val = xadc->threshold[offset];
 172                 break;
 173         case IIO_EV_INFO_HYSTERESIS:
 174                 *val = xadc->temp_hysteresis;
 175                 break;
 176         default:
 177                 return -EINVAL;
 178         }
 179 
 180         *val >>= XADC_THRESHOLD_VALUE_SHIFT;
 181 
 182         return IIO_VAL_INT;
 183 }
 184 
 185 int xadc_write_event_value(struct iio_dev *indio_dev,
 186         const struct iio_chan_spec *chan, enum iio_event_type type,
 187         enum iio_event_direction dir, enum iio_event_info info,
 188         int val, int val2)
 189 {
 190         unsigned int offset = xadc_get_threshold_offset(chan, dir);
 191         struct xadc *xadc = iio_priv(indio_dev);
 192         int ret = 0;
 193 
 194         val <<= XADC_THRESHOLD_VALUE_SHIFT;
 195 
 196         if (val < 0 || val > 0xffff)
 197                 return -EINVAL;
 198 
 199         mutex_lock(&xadc->mutex);
 200 
 201         switch (info) {
 202         case IIO_EV_INFO_VALUE:
 203                 xadc->threshold[offset] = val;
 204                 break;
 205         case IIO_EV_INFO_HYSTERESIS:
 206                 xadc->temp_hysteresis = val;
 207                 break;
 208         default:
 209                 mutex_unlock(&xadc->mutex);
 210                 return -EINVAL;
 211         }
 212 
 213         if (chan->type == IIO_TEMP) {
 214                 /*
 215                  * According to the datasheet we need to set the lower 4 bits to
 216                  * 0x3, otherwise 125 degree celsius will be used as the
 217                  * threshold.
 218                  */
 219                 val |= 0x3;
 220 
 221                 /*
 222                  * Since we store the hysteresis as relative (to the threshold)
 223                  * value, but the hardware expects an absolute value we need to
 224                  * recalcualte this value whenever the hysteresis or the
 225                  * threshold changes.
 226                  */
 227                 if (xadc->threshold[offset] < xadc->temp_hysteresis)
 228                         xadc->threshold[offset + 4] = 0;
 229                 else
 230                         xadc->threshold[offset + 4] = xadc->threshold[offset] -
 231                                         xadc->temp_hysteresis;
 232                 ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4),
 233                         xadc->threshold[offset + 4]);
 234                 if (ret)
 235                         goto out_unlock;
 236         }
 237 
 238         if (info == IIO_EV_INFO_VALUE)
 239                 ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val);
 240 
 241 out_unlock:
 242         mutex_unlock(&xadc->mutex);
 243 
 244         return ret;
 245 }

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