xilinx-xadc-events.c (5829B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Xilinx XADC driver 4 * 5 * Copyright 2013 Analog Devices Inc. 6 * Author: Lars-Peter Clausen <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 15static 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 30static 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 62void 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 70static 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 90static 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 113int 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 122int 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 152err_out: 153 mutex_unlock(&xadc->mutex); 154 155 return ret; 156} 157 158int xadc_read_event_value(struct iio_dev *indio_dev, 159 const struct iio_chan_spec *chan, enum iio_event_type type, 160 enum iio_event_direction dir, enum iio_event_info info, 161 int *val, int *val2) 162{ 163 unsigned int offset = xadc_get_threshold_offset(chan, dir); 164 struct xadc *xadc = iio_priv(indio_dev); 165 166 switch (info) { 167 case IIO_EV_INFO_VALUE: 168 *val = xadc->threshold[offset]; 169 break; 170 case IIO_EV_INFO_HYSTERESIS: 171 *val = xadc->temp_hysteresis; 172 break; 173 default: 174 return -EINVAL; 175 } 176 177 /* MSB aligned */ 178 *val >>= 16 - chan->scan_type.realbits; 179 180 return IIO_VAL_INT; 181} 182 183int xadc_write_event_value(struct iio_dev *indio_dev, 184 const struct iio_chan_spec *chan, enum iio_event_type type, 185 enum iio_event_direction dir, enum iio_event_info info, 186 int val, int val2) 187{ 188 unsigned int offset = xadc_get_threshold_offset(chan, dir); 189 struct xadc *xadc = iio_priv(indio_dev); 190 int ret = 0; 191 192 /* MSB aligned */ 193 val <<= 16 - chan->scan_type.realbits; 194 195 if (val < 0 || val > 0xffff) 196 return -EINVAL; 197 198 mutex_lock(&xadc->mutex); 199 200 switch (info) { 201 case IIO_EV_INFO_VALUE: 202 xadc->threshold[offset] = val; 203 break; 204 case IIO_EV_INFO_HYSTERESIS: 205 xadc->temp_hysteresis = val; 206 break; 207 default: 208 mutex_unlock(&xadc->mutex); 209 return -EINVAL; 210 } 211 212 if (chan->type == IIO_TEMP) { 213 /* 214 * According to the datasheet we need to set the lower 4 bits to 215 * 0x3, otherwise 125 degree celsius will be used as the 216 * threshold. 217 */ 218 val |= 0x3; 219 220 /* 221 * Since we store the hysteresis as relative (to the threshold) 222 * value, but the hardware expects an absolute value we need to 223 * recalcualte this value whenever the hysteresis or the 224 * threshold changes. 225 */ 226 if (xadc->threshold[offset] < xadc->temp_hysteresis) 227 xadc->threshold[offset + 4] = 0; 228 else 229 xadc->threshold[offset + 4] = xadc->threshold[offset] - 230 xadc->temp_hysteresis; 231 ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4), 232 xadc->threshold[offset + 4]); 233 if (ret) 234 goto out_unlock; 235 } 236 237 if (info == IIO_EV_INFO_VALUE) 238 ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val); 239 240out_unlock: 241 mutex_unlock(&xadc->mutex); 242 243 return ret; 244}