diff options
author | Jonathan Cameron <jic23@cam.ac.uk> | 2010-06-26 07:54:23 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-07-08 15:25:30 -0400 |
commit | 440a5200347734032f7ad0dc84ac3e9222dab9bd (patch) | |
tree | d33ded4e59a979ec6d38d505ef0b375921bcd0cb /drivers/staging/iio/adc | |
parent | 7e29a0df16ddfcb971a1d498752a782a68e45281 (diff) |
staging:iio:max1363 add theshold event support
Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/iio/adc')
-rw-r--r-- | drivers/staging/iio/adc/adc.h | 3 | ||||
-rw-r--r-- | drivers/staging/iio/adc/max1363.h | 45 | ||||
-rw-r--r-- | drivers/staging/iio/adc/max1363_core.c | 696 |
3 files changed, 721 insertions, 23 deletions
diff --git a/drivers/staging/iio/adc/adc.h b/drivers/staging/iio/adc/adc.h index 04eb16fd0a9..7841e6ad434 100644 --- a/drivers/staging/iio/adc/adc.h +++ b/drivers/staging/iio/adc/adc.h | |||
@@ -26,3 +26,6 @@ | |||
26 | _show, \ | 26 | _show, \ |
27 | NULL, \ | 27 | NULL, \ |
28 | _addr) | 28 | _addr) |
29 | |||
30 | #define IIO_EVENT_CODE_IN_HIGH_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a) | ||
31 | #define IIO_EVENT_CODE_IN_LOW_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a + 32) | ||
diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h index 447000895d6..bd35509b105 100644 --- a/drivers/staging/iio/adc/max1363.h +++ b/drivers/staging/iio/adc/max1363.h | |||
@@ -32,14 +32,6 @@ | |||
32 | 32 | ||
33 | /* Specific to the max1363 */ | 33 | /* Specific to the max1363 */ |
34 | #define MAX1363_MON_RESET_CHAN(a) (1 << ((a) + 4)) | 34 | #define MAX1363_MON_RESET_CHAN(a) (1 << ((a) + 4)) |
35 | #define MAX1363_MON_CONV_RATE_133ksps 0 | ||
36 | #define MAX1363_MON_CONV_RATE_66_5ksps 0x02 | ||
37 | #define MAX1363_MON_CONV_RATE_33_3ksps 0x04 | ||
38 | #define MAX1363_MON_CONV_RATE_16_6ksps 0x06 | ||
39 | #define MAX1363_MON_CONV_RATE_8_3ksps 0x08 | ||
40 | #define MAX1363_MON_CONV_RATE_4_2ksps 0x0A | ||
41 | #define MAX1363_MON_CONV_RATE_2_0ksps 0x0C | ||
42 | #define MAX1363_MON_CONV_RATE_1_0ksps 0x0E | ||
43 | #define MAX1363_MON_INT_ENABLE 0x01 | 35 | #define MAX1363_MON_INT_ENABLE 0x01 |
44 | 36 | ||
45 | /* defined for readability reasons */ | 37 | /* defined for readability reasons */ |
@@ -67,9 +59,8 @@ | |||
67 | 59 | ||
68 | /** | 60 | /** |
69 | * struct max1363_mode - scan mode information | 61 | * struct max1363_mode - scan mode information |
70 | * @name: Name used to identify the scan mode. | ||
71 | * @conf: The corresponding value of the configuration register | 62 | * @conf: The corresponding value of the configuration register |
72 | * @numvals: The number of values returned by a single scan | 63 | * @modemask: Bit mask corresponding to channels enabled in this mode |
73 | */ | 64 | */ |
74 | struct max1363_mode { | 65 | struct max1363_mode { |
75 | int8_t conf; | 66 | int8_t conf; |
@@ -122,15 +113,6 @@ struct max1363_mode { | |||
122 | .modemask = _mask \ | 113 | .modemask = _mask \ |
123 | } | 114 | } |
124 | 115 | ||
125 | /* Not currently handled */ | ||
126 | #define MAX1363_MODE_MONITOR { \ | ||
127 | .name = "monitor", \ | ||
128 | .conf = MAX1363_CHANNEL_SEL(3) \ | ||
129 | | MAX1363_CONFIG_SCAN_MONITOR_MODE \ | ||
130 | | MAX1363_CONFIG_SE, \ | ||
131 | .numvals = 10, \ | ||
132 | } | ||
133 | |||
134 | /* This may seem an overly long winded way to do this, but at least it makes | 116 | /* This may seem an overly long winded way to do this, but at least it makes |
135 | * clear what all the various options actually do. Alternative suggestions | 117 | * clear what all the various options actually do. Alternative suggestions |
136 | * that don't require user to have intimate knowledge of the chip welcomed. | 118 | * that don't require user to have intimate knowledge of the chip welcomed. |
@@ -190,7 +172,6 @@ struct max1363_chip_info { | |||
190 | struct attribute_group *scan_attrs; | 172 | struct attribute_group *scan_attrs; |
191 | }; | 173 | }; |
192 | 174 | ||
193 | |||
194 | /** | 175 | /** |
195 | * struct max1363_state - driver instance specific data | 176 | * struct max1363_state - driver instance specific data |
196 | * @indio_dev: the industrial I/O device | 177 | * @indio_dev: the industrial I/O device |
@@ -203,12 +184,20 @@ struct max1363_chip_info { | |||
203 | * @poll_work: bottom half of polling interrupt handler | 184 | * @poll_work: bottom half of polling interrupt handler |
204 | * @protect_ring: used to ensure only one polling bh running at a time | 185 | * @protect_ring: used to ensure only one polling bh running at a time |
205 | * @reg: supply regulator | 186 | * @reg: supply regulator |
187 | * @monitor_on: whether monitor mode is enabled | ||
188 | * @monitor_speed: parameter corresponding to device monitor speed setting | ||
189 | * @mask_high: bitmask for enabled high thresholds | ||
190 | * @mask_low: bitmask for enabled low thresholds | ||
191 | * @thresh_high: high threshold values | ||
192 | * @thresh_low: low threshold values | ||
193 | * @last_timestamp: timestamp of last event interrupt | ||
194 | * @thresh_work: bh work structure for event handling | ||
206 | */ | 195 | */ |
207 | struct max1363_state { | 196 | struct max1363_state { |
208 | struct iio_dev *indio_dev; | 197 | struct iio_dev *indio_dev; |
209 | struct i2c_client *client; | 198 | struct i2c_client *client; |
210 | char setupbyte; | 199 | u8 setupbyte; |
211 | char configbyte; | 200 | u8 configbyte; |
212 | const struct max1363_chip_info *chip_info; | 201 | const struct max1363_chip_info *chip_info; |
213 | const struct max1363_mode *current_mode; | 202 | const struct max1363_mode *current_mode; |
214 | u32 requestedmask; | 203 | u32 requestedmask; |
@@ -216,6 +205,18 @@ struct max1363_state { | |||
216 | atomic_t protect_ring; | 205 | atomic_t protect_ring; |
217 | struct iio_trigger *trig; | 206 | struct iio_trigger *trig; |
218 | struct regulator *reg; | 207 | struct regulator *reg; |
208 | |||
209 | /* Using monitor modes and buffer at the same time is | ||
210 | currently not supported */ | ||
211 | bool monitor_on; | ||
212 | unsigned int monitor_speed:3; | ||
213 | u8 mask_high; | ||
214 | u8 mask_low; | ||
215 | /* 4x unipolar first then the fours bipolar ones */ | ||
216 | s16 thresh_high[8]; | ||
217 | s16 thresh_low[8]; | ||
218 | s64 last_timestamp; | ||
219 | struct work_struct thresh_work; | ||
219 | }; | 220 | }; |
220 | 221 | ||
221 | const struct max1363_mode | 222 | const struct max1363_mode |
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 31d856375fa..c23485f24c5 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | * Not currently implemented. | 19 | * Not currently implemented. |
20 | * | 20 | * |
21 | * - Monitor interrrupt generation. | ||
22 | * - Control of internal reference. | 21 | * - Control of internal reference. |
23 | */ | 22 | */ |
24 | 23 | ||
@@ -205,6 +204,16 @@ static ssize_t max1363_read_single_channel(struct device *dev, | |||
205 | long mask; | 204 | long mask; |
206 | 205 | ||
207 | mutex_lock(&dev_info->mlock); | 206 | mutex_lock(&dev_info->mlock); |
207 | /* | ||
208 | * If monitor mode is enabled, the method for reading a single | ||
209 | * channel will have to be rather different and has not yet | ||
210 | * been implemented. | ||
211 | */ | ||
212 | if (st->monitor_on) { | ||
213 | ret = -EBUSY; | ||
214 | goto error_ret; | ||
215 | } | ||
216 | |||
208 | /* If ring buffer capture is occuring, query the buffer */ | 217 | /* If ring buffer capture is occuring, query the buffer */ |
209 | if (iio_ring_enabled(dev_info)) { | 218 | if (iio_ring_enabled(dev_info)) { |
210 | mask = max1363_mode_table[this_attr->address].modemask; | 219 | mask = max1363_mode_table[this_attr->address].modemask; |
@@ -897,6 +906,668 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { | |||
897 | } | 906 | } |
898 | }; | 907 | }; |
899 | 908 | ||
909 | static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600, | ||
910 | 8300, 4200, 2000, 1000 }; | ||
911 | |||
912 | static ssize_t max1363_monitor_show_freq(struct device *dev, | ||
913 | struct device_attribute *attr, | ||
914 | char *buf) | ||
915 | { | ||
916 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
917 | struct max1363_state *st = iio_dev_get_devdata(dev_info); | ||
918 | return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]); | ||
919 | } | ||
920 | |||
921 | static ssize_t max1363_monitor_store_freq(struct device *dev, | ||
922 | struct device_attribute *attr, | ||
923 | const char *buf, | ||
924 | size_t len) | ||
925 | { | ||
926 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
927 | struct max1363_state *st = iio_dev_get_devdata(dev_info); | ||
928 | int i, ret; | ||
929 | unsigned long val; | ||
930 | bool found = false; | ||
931 | |||
932 | ret = strict_strtoul(buf, 10, &val); | ||
933 | if (ret) | ||
934 | return -EINVAL; | ||
935 | for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++) | ||
936 | if (val == max1363_monitor_speeds[i]) { | ||
937 | found = true; | ||
938 | break; | ||
939 | } | ||
940 | if (!found) | ||
941 | return -EINVAL; | ||
942 | |||
943 | mutex_lock(&dev_info->mlock); | ||
944 | st->monitor_speed = i; | ||
945 | mutex_unlock(&dev_info->mlock); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, | ||
951 | max1363_monitor_show_freq, | ||
952 | max1363_monitor_store_freq); | ||
953 | |||
954 | static IIO_CONST_ATTR(sampling_frequency_available, | ||
955 | "133000 665000 33300 16600 8300 4200 2000 1000"); | ||
956 | |||
957 | static ssize_t max1363_show_thresh(struct device *dev, | ||
958 | struct device_attribute *attr, | ||
959 | char *buf, | ||
960 | bool high) | ||
961 | { | ||
962 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
963 | struct max1363_state *st = iio_dev_get_devdata(dev_info); | ||
964 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
965 | |||
966 | if (high) | ||
967 | return sprintf(buf, "%d\n", | ||
968 | st->thresh_high[this_attr->address]); | ||
969 | else | ||
970 | return sprintf(buf, "%d\n", | ||
971 | st->thresh_low[this_attr->address & 0x7]); | ||
972 | } | ||
973 | |||
974 | static ssize_t max1363_show_thresh_low(struct device *dev, | ||
975 | struct device_attribute *attr, | ||
976 | char *buf) | ||
977 | { | ||
978 | return max1363_show_thresh(dev, attr, buf, false); | ||
979 | } | ||
980 | |||
981 | static ssize_t max1363_show_thresh_high(struct device *dev, | ||
982 | struct device_attribute *attr, | ||
983 | char *buf) | ||
984 | { | ||
985 | return max1363_show_thresh(dev, attr, buf, true); | ||
986 | } | ||
987 | |||
988 | static ssize_t max1363_store_thresh_unsigned(struct device *dev, | ||
989 | struct device_attribute *attr, | ||
990 | const char *buf, | ||
991 | size_t len, | ||
992 | bool high) | ||
993 | { | ||
994 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
995 | struct max1363_state *st = iio_dev_get_devdata(dev_info); | ||
996 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
997 | unsigned long val; | ||
998 | int ret; | ||
999 | |||
1000 | ret = strict_strtoul(buf, 10, &val); | ||
1001 | if (ret) | ||
1002 | return -EINVAL; | ||
1003 | switch (st->chip_info->bits) { | ||
1004 | case 10: | ||
1005 | if (val > 0x3FF) | ||
1006 | return -EINVAL; | ||
1007 | break; | ||
1008 | case 12: | ||
1009 | if (val > 0xFFF) | ||
1010 | return -EINVAL; | ||
1011 | break; | ||
1012 | } | ||
1013 | |||
1014 | switch (high) { | ||
1015 | case 1: | ||
1016 | st->thresh_high[this_attr->address] = val; | ||
1017 | break; | ||
1018 | case 0: | ||
1019 | st->thresh_low[this_attr->address & 0x7] = val; | ||
1020 | break; | ||
1021 | } | ||
1022 | |||
1023 | return len; | ||
1024 | } | ||
1025 | |||
1026 | static ssize_t max1363_store_thresh_high_unsigned(struct device *dev, | ||
1027 | struct device_attribute *attr, | ||
1028 | const char *buf, | ||
1029 | size_t len) | ||
1030 | { | ||
1031 | return max1363_store_thresh_unsigned(dev, attr, buf, len, true); | ||
1032 | } | ||
1033 | |||
1034 | static ssize_t max1363_store_thresh_low_unsigned(struct device *dev, | ||
1035 | struct device_attribute *attr, | ||
1036 | const char *buf, | ||
1037 | size_t len) | ||
1038 | { | ||
1039 | return max1363_store_thresh_unsigned(dev, attr, buf, len, false); | ||
1040 | } | ||
1041 | |||
1042 | static ssize_t max1363_store_thresh_signed(struct device *dev, | ||
1043 | struct device_attribute *attr, | ||
1044 | const char *buf, | ||
1045 | size_t len, | ||
1046 | bool high) | ||
1047 | { | ||
1048 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
1049 | struct max1363_state *st = iio_dev_get_devdata(dev_info); | ||
1050 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
1051 | long val; | ||
1052 | int ret; | ||
1053 | |||
1054 | ret = strict_strtol(buf, 10, &val); | ||
1055 | if (ret) | ||
1056 | return -EINVAL; | ||
1057 | switch (st->chip_info->bits) { | ||
1058 | case 10: | ||
1059 | if (val < -512 || val > 511) | ||
1060 | return -EINVAL; | ||
1061 | break; | ||
1062 | case 12: | ||
1063 | if (val < -2048 || val > 2047) | ||
1064 | return -EINVAL; | ||
1065 | break; | ||
1066 | } | ||
1067 | |||
1068 | switch (high) { | ||
1069 | case 1: | ||
1070 | st->thresh_high[this_attr->address] = val; | ||
1071 | break; | ||
1072 | case 0: | ||
1073 | st->thresh_low[this_attr->address & 0x7] = val; | ||
1074 | break; | ||
1075 | } | ||
1076 | |||
1077 | return len; | ||
1078 | } | ||
1079 | |||
1080 | static ssize_t max1363_store_thresh_high_signed(struct device *dev, | ||
1081 | struct device_attribute *attr, | ||
1082 | const char *buf, | ||
1083 | size_t len) | ||
1084 | { | ||
1085 | return max1363_store_thresh_signed(dev, attr, buf, len, true); | ||
1086 | } | ||
1087 | |||
1088 | static ssize_t max1363_store_thresh_low_signed(struct device *dev, | ||
1089 | struct device_attribute *attr, | ||
1090 | const char *buf, | ||
1091 | size_t len) | ||
1092 | { | ||
1093 | return max1363_store_thresh_signed(dev, attr, buf, len, false); | ||
1094 | } | ||
1095 | |||
1096 | static IIO_DEVICE_ATTR(in0_thresh_high_value, S_IRUGO | S_IWUSR, | ||
1097 | max1363_show_thresh_high, | ||
1098 | max1363_store_thresh_high_unsigned, 0); | ||
1099 | static IIO_DEVICE_ATTR(in0_thresh_low_value, S_IRUGO | S_IWUSR, | ||
1100 | max1363_show_thresh_low, | ||
1101 | max1363_store_thresh_low_unsigned, 0); | ||
1102 | static IIO_DEVICE_ATTR(in1_thresh_high_value, S_IRUGO | S_IWUSR, | ||
1103 | max1363_show_thresh_high, | ||
1104 | max1363_store_thresh_high_unsigned, 1); | ||
1105 | static IIO_DEVICE_ATTR(in1_thresh_low_value, S_IRUGO | S_IWUSR, | ||
1106 | max1363_show_thresh_low, | ||
1107 | max1363_store_thresh_low_unsigned, 1); | ||
1108 | static IIO_DEVICE_ATTR(in2_thresh_high_value, S_IRUGO | S_IWUSR, | ||
1109 | max1363_show_thresh_high, | ||
1110 | max1363_store_thresh_high_unsigned, 2); | ||
1111 | static IIO_DEVICE_ATTR(in2_thresh_low_value, S_IRUGO | S_IWUSR, | ||
1112 | max1363_show_thresh_low, | ||
1113 | max1363_store_thresh_low_unsigned, 2); | ||
1114 | static IIO_DEVICE_ATTR(in3_thresh_high_value, S_IRUGO | S_IWUSR, | ||
1115 | max1363_show_thresh_high, | ||
1116 | max1363_store_thresh_high_unsigned, 3); | ||
1117 | static IIO_DEVICE_ATTR(in3_thresh_low_value, S_IRUGO | S_IWUSR, | ||
1118 | max1363_show_thresh_low, | ||
1119 | max1363_store_thresh_low_unsigned, 3); | ||
1120 | |||
1121 | static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_high_value, | ||
1122 | in0-in1_thresh_high_value, | ||
1123 | S_IRUGO | S_IWUSR, max1363_show_thresh_high, | ||
1124 | max1363_store_thresh_high_signed, 4); | ||
1125 | static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_low_value, | ||
1126 | in0-in1_thresh_low_value, | ||
1127 | S_IRUGO | S_IWUSR, max1363_show_thresh_low, | ||
1128 | max1363_store_thresh_low_signed, 4); | ||
1129 | static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_high_value, | ||
1130 | in2-in3_thresh_high_value, | ||
1131 | S_IRUGO | S_IWUSR, max1363_show_thresh_high, | ||
1132 | max1363_store_thresh_high_signed, 5); | ||
1133 | static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_low_value, | ||
1134 | in2-in3_thresh_low_value, | ||
1135 | S_IRUGO | S_IWUSR, max1363_show_thresh_low, | ||
1136 | max1363_store_thresh_low_signed, 5); | ||
1137 | static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_high_value, | ||
1138 | in1-in0_thresh_high_value, | ||
1139 | S_IRUGO | S_IWUSR, max1363_show_thresh_high, | ||
1140 | max1363_store_thresh_high_signed, 6); | ||
1141 | static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_low_value, | ||
1142 | in1-in0_thresh_low_value, | ||
1143 | S_IRUGO | S_IWUSR, max1363_show_thresh_low, | ||
1144 | max1363_store_thresh_low_signed, 6); | ||
1145 | static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_high_value, | ||
1146 | in3-in2_thresh_high_value, | ||
1147 | S_IRUGO | S_IWUSR, max1363_show_thresh_high, | ||
1148 | max1363_store_thresh_high_signed, 7); | ||
1149 | static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_low_value, | ||
1150 | in3-in2_thresh_low_value, | ||
1151 | S_IRUGO | S_IWUSR, max1363_show_thresh_low, | ||
1152 | max1363_store_thresh_low_signed, 7); | ||
1153 | |||
1154 | static int max1363_int_th(struct iio_dev *dev_info, | ||
1155 | int index, | ||
1156 | s64 timestamp, | ||
1157 | int not_test) | ||
1158 | { | ||
1159 | struct max1363_state *st = dev_info->dev_data; | ||
1160 | |||
1161 | st->last_timestamp = timestamp; | ||
1162 | schedule_work(&st->thresh_work); | ||
1163 | return 0; | ||
1164 | } | ||
1165 | |||
1166 | static void max1363_thresh_handler_bh(struct work_struct *work_s) | ||
1167 | { | ||
1168 | struct max1363_state *st = container_of(work_s, struct max1363_state, | ||
1169 | thresh_work); | ||
1170 | u8 rx; | ||
1171 | u8 tx[2] = { st->setupbyte, | ||
1172 | MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 }; | ||
1173 | |||
1174 | i2c_master_recv(st->client, &rx, 1); | ||
1175 | if (rx & (1 << 0)) | ||
1176 | iio_push_event(st->indio_dev, 0, | ||
1177 | IIO_EVENT_CODE_IN_LOW_THRESH(3), | ||
1178 | st->last_timestamp); | ||
1179 | if (rx & (1 << 1)) | ||
1180 | iio_push_event(st->indio_dev, 0, | ||
1181 | IIO_EVENT_CODE_IN_HIGH_THRESH(3), | ||
1182 | st->last_timestamp); | ||
1183 | if (rx & (1 << 2)) | ||
1184 | iio_push_event(st->indio_dev, 0, | ||
1185 | IIO_EVENT_CODE_IN_LOW_THRESH(2), | ||
1186 | st->last_timestamp); | ||
1187 | if (rx & (1 << 3)) | ||
1188 | iio_push_event(st->indio_dev, 0, | ||
1189 | IIO_EVENT_CODE_IN_HIGH_THRESH(2), | ||
1190 | st->last_timestamp); | ||
1191 | if (rx & (1 << 4)) | ||
1192 | iio_push_event(st->indio_dev, 0, | ||
1193 | IIO_EVENT_CODE_IN_LOW_THRESH(1), | ||
1194 | st->last_timestamp); | ||
1195 | if (rx & (1 << 5)) | ||
1196 | iio_push_event(st->indio_dev, 0, | ||
1197 | IIO_EVENT_CODE_IN_HIGH_THRESH(1), | ||
1198 | st->last_timestamp); | ||
1199 | if (rx & (1 << 6)) | ||
1200 | iio_push_event(st->indio_dev, 0, | ||
1201 | IIO_EVENT_CODE_IN_LOW_THRESH(0), | ||
1202 | st->last_timestamp); | ||
1203 | if (rx & (1 << 7)) | ||
1204 | iio_push_event(st->indio_dev, 0, | ||
1205 | IIO_EVENT_CODE_IN_HIGH_THRESH(0), | ||
1206 | st->last_timestamp); | ||
1207 | enable_irq(st->client->irq); | ||
1208 | i2c_master_send(st->client, tx, 2); | ||
1209 | } | ||
1210 | |||
1211 | static ssize_t max1363_read_interrupt_config(struct device *dev, | ||
1212 | struct device_attribute *attr, | ||
1213 | char *buf) | ||
1214 | { | ||
1215 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
1216 | struct max1363_state *st = iio_dev_get_devdata(dev_info); | ||
1217 | struct iio_event_attr *this_attr = to_iio_event_attr(attr); | ||
1218 | int val; | ||
1219 | |||
1220 | mutex_lock(&dev_info->mlock); | ||
1221 | if (this_attr->mask & 0x8) | ||
1222 | val = (1 << (this_attr->mask & 0x7)) & st->mask_low; | ||
1223 | else | ||
1224 | val = (1 << this_attr->mask) & st->mask_high; | ||
1225 | mutex_unlock(&dev_info->mlock); | ||
1226 | |||
1227 | return sprintf(buf, "%d\n", !!val); | ||
1228 | } | ||
1229 | |||
1230 | static int max1363_monitor_mode_update(struct max1363_state *st, int enabled) | ||
1231 | { | ||
1232 | u8 *tx_buf; | ||
1233 | int ret, i = 3, j; | ||
1234 | unsigned long numelements; | ||
1235 | int len; | ||
1236 | long modemask; | ||
1237 | |||
1238 | if (!enabled) { | ||
1239 | /* transition to ring capture is not currently supported */ | ||
1240 | st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP; | ||
1241 | st->configbyte &= ~MAX1363_SCAN_MASK; | ||
1242 | st->monitor_on = false; | ||
1243 | return max1363_write_basic_config(st->client, | ||
1244 | st->setupbyte, | ||
1245 | st->configbyte); | ||
1246 | } | ||
1247 | |||
1248 | /* Ensure we are in the relevant mode */ | ||
1249 | st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP; | ||
1250 | st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK | ||
1251 | | MAX1363_SCAN_MASK | ||
1252 | | MAX1363_SE_DE_MASK); | ||
1253 | st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE; | ||
1254 | if ((st->mask_low | st->mask_high) & 0x0F) { | ||
1255 | st->configbyte |= max1363_mode_table[s0to3].conf; | ||
1256 | modemask = max1363_mode_table[s0to3].modemask; | ||
1257 | } else if ((st->mask_low | st->mask_high) & 0x30) { | ||
1258 | st->configbyte |= max1363_mode_table[d0m1to2m3].conf; | ||
1259 | modemask = max1363_mode_table[d0m1to2m3].modemask; | ||
1260 | } else { | ||
1261 | st->configbyte |= max1363_mode_table[d1m0to3m2].conf; | ||
1262 | modemask = max1363_mode_table[d1m0to3m2].modemask; | ||
1263 | } | ||
1264 | numelements = hweight_long(modemask); | ||
1265 | len = 3 * numelements + 3; | ||
1266 | tx_buf = kmalloc(len, GFP_KERNEL); | ||
1267 | if (!tx_buf) { | ||
1268 | ret = -ENOMEM; | ||
1269 | goto error_ret; | ||
1270 | } | ||
1271 | tx_buf[0] = st->configbyte; | ||
1272 | tx_buf[1] = st->setupbyte; | ||
1273 | tx_buf[2] = (st->monitor_speed << 1); | ||
1274 | |||
1275 | /* | ||
1276 | * So we need to do yet another bit of nefarious scan mode | ||
1277 | * setup to match what we need. | ||
1278 | */ | ||
1279 | for (j = 0; j < 8; j++) | ||
1280 | if (modemask & (1 << j)) { | ||
1281 | /* Establish the mode is in the scan */ | ||
1282 | if (st->mask_low & (1 << j)) { | ||
1283 | tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF; | ||
1284 | tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0; | ||
1285 | } else if (j < 4) { | ||
1286 | tx_buf[i] = 0; | ||
1287 | tx_buf[i + 1] = 0; | ||
1288 | } else { | ||
1289 | tx_buf[i] = 0x80; | ||
1290 | tx_buf[i + 1] = 0; | ||
1291 | } | ||
1292 | if (st->mask_high & (1 << j)) { | ||
1293 | tx_buf[i + 1] |= | ||
1294 | (st->thresh_high[j] >> 8) & 0x0F; | ||
1295 | tx_buf[i + 2] = st->thresh_high[j] & 0xFF; | ||
1296 | } else if (j < 4) { | ||
1297 | tx_buf[i + 1] |= 0x0F; | ||
1298 | tx_buf[i + 2] = 0xFF; | ||
1299 | } else { | ||
1300 | tx_buf[i + 1] |= 0x07; | ||
1301 | tx_buf[i + 2] = 0xFF; | ||
1302 | } | ||
1303 | i += 3; | ||
1304 | } | ||
1305 | |||
1306 | |||
1307 | ret = i2c_master_send(st->client, tx_buf, len); | ||
1308 | if (ret < 0) | ||
1309 | goto error_ret; | ||
1310 | if (ret != len) { | ||
1311 | ret = -EIO; | ||
1312 | goto error_ret; | ||
1313 | } | ||
1314 | |||
1315 | /* | ||
1316 | * Now that we hopefully have sensible thresholds in place it is | ||
1317 | * time to turn the interrupts on. | ||
1318 | * It is unclear from the data sheet if this should be necessary | ||
1319 | * (i.e. whether monitor mode setup is atomic) but it appears to | ||
1320 | * be in practice. | ||
1321 | */ | ||
1322 | tx_buf[0] = st->setupbyte; | ||
1323 | tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0; | ||
1324 | ret = i2c_master_send(st->client, tx_buf, 2); | ||
1325 | if (ret < 0) | ||
1326 | goto error_ret; | ||
1327 | if (ret != 2) { | ||
1328 | ret = -EIO; | ||
1329 | goto error_ret; | ||
1330 | } | ||
1331 | ret = 0; | ||
1332 | st->monitor_on = true; | ||
1333 | error_ret: | ||
1334 | |||
1335 | kfree(tx_buf); | ||
1336 | |||
1337 | return ret; | ||
1338 | } | ||
1339 | |||
1340 | /* | ||
1341 | * To keep this managable we always use one of 3 scan modes. | ||
1342 | * Scan 0...3, 0-1,2-3 and 1-0,3-2 | ||
1343 | */ | ||
1344 | static inline int __max1363_check_event_mask(int thismask, int checkmask) | ||
1345 | { | ||
1346 | int ret = 0; | ||
1347 | /* Is it unipolar */ | ||
1348 | if (thismask < 4) { | ||
1349 | if (checkmask & ~0x0F) { | ||
1350 | ret = -EBUSY; | ||
1351 | goto error_ret; | ||
1352 | } | ||
1353 | } else if (thismask < 6) { | ||
1354 | if (checkmask & ~0x30) { | ||
1355 | ret = -EBUSY; | ||
1356 | goto error_ret; | ||
1357 | } | ||
1358 | } else if (checkmask & ~0xC0) | ||
1359 | ret = -EBUSY; | ||
1360 | error_ret: | ||
1361 | return ret; | ||
1362 | } | ||
1363 | |||
1364 | static ssize_t max1363_write_interrupt_config(struct device *dev, | ||
1365 | struct device_attribute *attr, | ||
1366 | const char *buf, | ||
1367 | size_t len) | ||
1368 | { | ||
1369 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
1370 | struct max1363_state *st = iio_dev_get_devdata(dev_info); | ||
1371 | struct iio_event_attr *this_attr = to_iio_event_attr(attr); | ||
1372 | unsigned long val; | ||
1373 | int ret; | ||
1374 | u16 unifiedmask; | ||
1375 | ret = strict_strtoul(buf, 10, &val); | ||
1376 | if (ret) | ||
1377 | return -EINVAL; | ||
1378 | mutex_lock(&st->indio_dev->mlock); | ||
1379 | unifiedmask = st->mask_low | st->mask_high; | ||
1380 | if (this_attr->mask & 0x08) { | ||
1381 | /* If we are disabling no need to test */ | ||
1382 | if (val == 0) | ||
1383 | st->mask_low &= ~(1 << (this_attr->mask & 0x7)); | ||
1384 | else { | ||
1385 | ret = __max1363_check_event_mask(this_attr->mask & 0x7, | ||
1386 | unifiedmask); | ||
1387 | if (ret) | ||
1388 | goto error_ret; | ||
1389 | st->mask_low |= (1 << (this_attr->mask & 0x7)); | ||
1390 | } | ||
1391 | } else { | ||
1392 | if (val == 0) | ||
1393 | st->mask_high &= ~(1 << (this_attr->mask)); | ||
1394 | else { | ||
1395 | ret = __max1363_check_event_mask(this_attr->mask, | ||
1396 | unifiedmask); | ||
1397 | if (ret) | ||
1398 | goto error_ret; | ||
1399 | st->mask_high |= (1 << this_attr->mask); | ||
1400 | } | ||
1401 | } | ||
1402 | if (st->monitor_on && !st->mask_high && !st->mask_low) | ||
1403 | iio_remove_event_from_list(this_attr->listel, | ||
1404 | &dev_info->interrupts[0]->ev_list); | ||
1405 | if (!st->monitor_on && val) | ||
1406 | iio_add_event_to_list(this_attr->listel, | ||
1407 | &dev_info->interrupts[0]->ev_list); | ||
1408 | |||
1409 | max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); | ||
1410 | error_ret: | ||
1411 | mutex_unlock(&st->indio_dev->mlock); | ||
1412 | |||
1413 | return len; | ||
1414 | } | ||
1415 | |||
1416 | IIO_EVENT_SH(max1363_thresh, max1363_int_th); | ||
1417 | |||
1418 | #define MAX1363_HIGH_THRESH(a) a | ||
1419 | #define MAX1363_LOW_THRESH(a) (a | 0x8) | ||
1420 | |||
1421 | IIO_EVENT_ATTR_SH(in0_thresh_high_en, | ||
1422 | iio_event_max1363_thresh, | ||
1423 | max1363_read_interrupt_config, | ||
1424 | max1363_write_interrupt_config, | ||
1425 | MAX1363_HIGH_THRESH(0)); | ||
1426 | |||
1427 | IIO_EVENT_ATTR_SH(in0_thresh_low_en, | ||
1428 | iio_event_max1363_thresh, | ||
1429 | max1363_read_interrupt_config, | ||
1430 | max1363_write_interrupt_config, | ||
1431 | MAX1363_LOW_THRESH(0)); | ||
1432 | |||
1433 | IIO_EVENT_ATTR_SH(in1_thresh_high_en, | ||
1434 | iio_event_max1363_thresh, | ||
1435 | max1363_read_interrupt_config, | ||
1436 | max1363_write_interrupt_config, | ||
1437 | MAX1363_HIGH_THRESH(1)); | ||
1438 | |||
1439 | IIO_EVENT_ATTR_SH(in1_thresh_low_en, | ||
1440 | iio_event_max1363_thresh, | ||
1441 | max1363_read_interrupt_config, | ||
1442 | max1363_write_interrupt_config, | ||
1443 | MAX1363_LOW_THRESH(1)); | ||
1444 | |||
1445 | IIO_EVENT_ATTR_SH(in2_thresh_high_en, | ||
1446 | iio_event_max1363_thresh, | ||
1447 | max1363_read_interrupt_config, | ||
1448 | max1363_write_interrupt_config, | ||
1449 | MAX1363_HIGH_THRESH(2)); | ||
1450 | |||
1451 | IIO_EVENT_ATTR_SH(in2_thresh_low_en, | ||
1452 | iio_event_max1363_thresh, | ||
1453 | max1363_read_interrupt_config, | ||
1454 | max1363_write_interrupt_config, | ||
1455 | MAX1363_LOW_THRESH(2)); | ||
1456 | |||
1457 | IIO_EVENT_ATTR_SH(in3_thresh_high_en, | ||
1458 | iio_event_max1363_thresh, | ||
1459 | max1363_read_interrupt_config, | ||
1460 | max1363_write_interrupt_config, | ||
1461 | MAX1363_HIGH_THRESH(3)); | ||
1462 | |||
1463 | IIO_EVENT_ATTR_SH(in3_thresh_low_en, | ||
1464 | iio_event_max1363_thresh, | ||
1465 | max1363_read_interrupt_config, | ||
1466 | max1363_write_interrupt_config, | ||
1467 | MAX1363_LOW_THRESH(3)); | ||
1468 | |||
1469 | IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_high_en, | ||
1470 | in0-in1_thresh_high_en, | ||
1471 | iio_event_max1363_thresh, | ||
1472 | max1363_read_interrupt_config, | ||
1473 | max1363_write_interrupt_config, | ||
1474 | MAX1363_HIGH_THRESH(4)); | ||
1475 | |||
1476 | IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_low_en, | ||
1477 | in0-in1_thresh_low_en, | ||
1478 | iio_event_max1363_thresh, | ||
1479 | max1363_read_interrupt_config, | ||
1480 | max1363_write_interrupt_config, | ||
1481 | MAX1363_LOW_THRESH(4)); | ||
1482 | |||
1483 | IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_high_en, | ||
1484 | in3-in2_thresh_high_en, | ||
1485 | iio_event_max1363_thresh, | ||
1486 | max1363_read_interrupt_config, | ||
1487 | max1363_write_interrupt_config, | ||
1488 | MAX1363_HIGH_THRESH(5)); | ||
1489 | |||
1490 | IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_low_en, | ||
1491 | in3-in2_thresh_low_en, | ||
1492 | iio_event_max1363_thresh, | ||
1493 | max1363_read_interrupt_config, | ||
1494 | max1363_write_interrupt_config, | ||
1495 | MAX1363_LOW_THRESH(5)); | ||
1496 | |||
1497 | IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_high_en, | ||
1498 | in1-in0_thresh_high_en, | ||
1499 | iio_event_max1363_thresh, | ||
1500 | max1363_read_interrupt_config, | ||
1501 | max1363_write_interrupt_config, | ||
1502 | MAX1363_HIGH_THRESH(6)); | ||
1503 | |||
1504 | IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_low_en, | ||
1505 | in1-in0_thresh_low_en, | ||
1506 | iio_event_max1363_thresh, | ||
1507 | max1363_read_interrupt_config, | ||
1508 | max1363_write_interrupt_config, | ||
1509 | MAX1363_LOW_THRESH(6)); | ||
1510 | |||
1511 | IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_high_en, | ||
1512 | in2-in3_thresh_high_en, | ||
1513 | iio_event_max1363_thresh, | ||
1514 | max1363_read_interrupt_config, | ||
1515 | max1363_write_interrupt_config, | ||
1516 | MAX1363_HIGH_THRESH(7)); | ||
1517 | |||
1518 | IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_low_en, | ||
1519 | in2-in3_thresh_low_en, | ||
1520 | iio_event_max1363_thresh, | ||
1521 | max1363_read_interrupt_config, | ||
1522 | max1363_write_interrupt_config, | ||
1523 | MAX1363_LOW_THRESH(7)); | ||
1524 | |||
1525 | /* | ||
1526 | * As with scan_elements, only certain sets of these can | ||
1527 | * be combined. | ||
1528 | */ | ||
1529 | static struct attribute *max1363_event_attributes[] = { | ||
1530 | &iio_dev_attr_in0_thresh_high_value.dev_attr.attr, | ||
1531 | &iio_dev_attr_in0_thresh_low_value.dev_attr.attr, | ||
1532 | &iio_dev_attr_in1_thresh_high_value.dev_attr.attr, | ||
1533 | &iio_dev_attr_in1_thresh_low_value.dev_attr.attr, | ||
1534 | &iio_dev_attr_in2_thresh_high_value.dev_attr.attr, | ||
1535 | &iio_dev_attr_in2_thresh_low_value.dev_attr.attr, | ||
1536 | &iio_dev_attr_in3_thresh_high_value.dev_attr.attr, | ||
1537 | &iio_dev_attr_in3_thresh_low_value.dev_attr.attr, | ||
1538 | &iio_dev_attr_in0min1_thresh_high_value.dev_attr.attr, | ||
1539 | &iio_dev_attr_in0min1_thresh_low_value.dev_attr.attr, | ||
1540 | &iio_dev_attr_in2min3_thresh_high_value.dev_attr.attr, | ||
1541 | &iio_dev_attr_in2min3_thresh_low_value.dev_attr.attr, | ||
1542 | &iio_dev_attr_in1min0_thresh_high_value.dev_attr.attr, | ||
1543 | &iio_dev_attr_in1min0_thresh_low_value.dev_attr.attr, | ||
1544 | &iio_dev_attr_in3min2_thresh_high_value.dev_attr.attr, | ||
1545 | &iio_dev_attr_in3min2_thresh_low_value.dev_attr.attr, | ||
1546 | &iio_dev_attr_sampling_frequency.dev_attr.attr, | ||
1547 | &iio_const_attr_sampling_frequency_available.dev_attr.attr, | ||
1548 | &iio_event_attr_in0_thresh_high_en.dev_attr.attr, | ||
1549 | &iio_event_attr_in0_thresh_low_en.dev_attr.attr, | ||
1550 | &iio_event_attr_in1_thresh_high_en.dev_attr.attr, | ||
1551 | &iio_event_attr_in1_thresh_low_en.dev_attr.attr, | ||
1552 | &iio_event_attr_in2_thresh_high_en.dev_attr.attr, | ||
1553 | &iio_event_attr_in2_thresh_low_en.dev_attr.attr, | ||
1554 | &iio_event_attr_in3_thresh_high_en.dev_attr.attr, | ||
1555 | &iio_event_attr_in3_thresh_low_en.dev_attr.attr, | ||
1556 | &iio_event_attr_in0min1_thresh_high_en.dev_attr.attr, | ||
1557 | &iio_event_attr_in0min1_thresh_low_en.dev_attr.attr, | ||
1558 | &iio_event_attr_in3min2_thresh_high_en.dev_attr.attr, | ||
1559 | &iio_event_attr_in3min2_thresh_low_en.dev_attr.attr, | ||
1560 | &iio_event_attr_in1min0_thresh_high_en.dev_attr.attr, | ||
1561 | &iio_event_attr_in1min0_thresh_low_en.dev_attr.attr, | ||
1562 | &iio_event_attr_in2min3_thresh_high_en.dev_attr.attr, | ||
1563 | &iio_event_attr_in2min3_thresh_low_en.dev_attr.attr, | ||
1564 | NULL, | ||
1565 | }; | ||
1566 | |||
1567 | static struct attribute_group max1363_event_attribute_group = { | ||
1568 | .attrs = max1363_event_attributes, | ||
1569 | }; | ||
1570 | |||
900 | static int max1363_initial_setup(struct max1363_state *st) | 1571 | static int max1363_initial_setup(struct max1363_state *st) |
901 | { | 1572 | { |
902 | st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD | 1573 | st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD |
@@ -964,6 +1635,11 @@ static int __devinit max1363_probe(struct i2c_client *client, | |||
964 | st->indio_dev->dev_data = (void *)(st); | 1635 | st->indio_dev->dev_data = (void *)(st); |
965 | st->indio_dev->driver_module = THIS_MODULE; | 1636 | st->indio_dev->driver_module = THIS_MODULE; |
966 | st->indio_dev->modes = INDIO_DIRECT_MODE; | 1637 | st->indio_dev->modes = INDIO_DIRECT_MODE; |
1638 | if (st->chip_info->monitor_mode && client->irq) { | ||
1639 | st->indio_dev->num_interrupt_lines = 1; | ||
1640 | st->indio_dev->event_attrs | ||
1641 | = &max1363_event_attribute_group; | ||
1642 | } | ||
967 | 1643 | ||
968 | ret = max1363_initial_setup(st); | 1644 | ret = max1363_initial_setup(st); |
969 | if (ret) | 1645 | if (ret) |
@@ -980,7 +1656,22 @@ static int __devinit max1363_probe(struct i2c_client *client, | |||
980 | ret = max1363_initialize_ring(st->indio_dev->ring); | 1656 | ret = max1363_initialize_ring(st->indio_dev->ring); |
981 | if (ret) | 1657 | if (ret) |
982 | goto error_cleanup_ring; | 1658 | goto error_cleanup_ring; |
1659 | |||
1660 | if (st->chip_info->monitor_mode && client->irq) { | ||
1661 | ret = iio_register_interrupt_line(client->irq, | ||
1662 | st->indio_dev, | ||
1663 | 0, | ||
1664 | IRQF_TRIGGER_RISING, | ||
1665 | client->name); | ||
1666 | if (ret) | ||
1667 | goto error_uninit_ring; | ||
1668 | |||
1669 | INIT_WORK(&st->thresh_work, max1363_thresh_handler_bh); | ||
1670 | } | ||
1671 | |||
983 | return 0; | 1672 | return 0; |
1673 | error_uninit_ring: | ||
1674 | max1363_uninitialize_ring(st->indio_dev->ring); | ||
984 | error_cleanup_ring: | 1675 | error_cleanup_ring: |
985 | max1363_ring_cleanup(st->indio_dev); | 1676 | max1363_ring_cleanup(st->indio_dev); |
986 | error_free_available_scan_masks: | 1677 | error_free_available_scan_masks: |
@@ -1006,6 +1697,9 @@ static int max1363_remove(struct i2c_client *client) | |||
1006 | { | 1697 | { |
1007 | struct max1363_state *st = i2c_get_clientdata(client); | 1698 | struct max1363_state *st = i2c_get_clientdata(client); |
1008 | struct iio_dev *indio_dev = st->indio_dev; | 1699 | struct iio_dev *indio_dev = st->indio_dev; |
1700 | |||
1701 | if (st->chip_info->monitor_mode && client->irq) | ||
1702 | iio_unregister_interrupt_line(st->indio_dev, 0); | ||
1009 | max1363_uninitialize_ring(indio_dev->ring); | 1703 | max1363_uninitialize_ring(indio_dev->ring); |
1010 | max1363_ring_cleanup(indio_dev); | 1704 | max1363_ring_cleanup(indio_dev); |
1011 | kfree(st->indio_dev->available_scan_masks); | 1705 | kfree(st->indio_dev->available_scan_masks); |