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