Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
[firefly-linux-kernel-4.4.55.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         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 }