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