diff options
author | Jonathan Cameron <jic23@cam.ac.uk> | 2011-05-18 14:42:37 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-19 16:15:05 -0700 |
commit | 6fe8135fccd66aedcc55ded70824342587fd2499 (patch) | |
tree | 3afc7acfd0edc052ba93241761e935af9a3b6ebc /drivers/staging/iio/adc/max1363_core.c | |
parent | a3f02370c9fa6d85fbee2c11649ebc9c84bae919 (diff) |
staging:iio: implement an iio_info structure to take some of the constant elements out of iio_dev.
This was suggested by Arnd Bergmann, Other elements may well
move in here in future, but it definitely makes sense for these.
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/max1363_core.c')
-rw-r--r-- | drivers/staging/iio/adc/max1363_core.c | 770 |
1 files changed, 406 insertions, 364 deletions
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 0c80abb7e753..8d09bf3d450a 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -472,47 +472,409 @@ enum { max1361, max11647 }; +static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600, + 8300, 4200, 2000, 1000 }; + +static ssize_t max1363_monitor_show_freq(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct max1363_state *st = iio_priv(dev_get_drvdata(dev)); + return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]); +} + +static ssize_t max1363_monitor_store_freq(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct max1363_state *st = iio_priv(indio_dev); + int i, ret; + unsigned long val; + bool found = false; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++) + if (val == max1363_monitor_speeds[i]) { + found = true; + break; + } + if (!found) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + st->monitor_speed = i; + mutex_unlock(&indio_dev->mlock); + + return 0; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, + max1363_monitor_show_freq, + max1363_monitor_store_freq); + +static IIO_CONST_ATTR(sampling_frequency_available, + "133000 665000 33300 16600 8300 4200 2000 1000"); + +static int max1363_read_thresh(struct iio_dev *indio_dev, + int event_code, + int *val) +{ + struct max1363_state *st = iio_priv(indio_dev); + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) + *val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]; + else + *val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]; + return 0; +} + +static int max1363_write_thresh(struct iio_dev *indio_dev, + int event_code, + int val) +{ + struct max1363_state *st = iio_priv(indio_dev); + /* make it handle signed correctly as well */ + switch (st->chip_info->bits) { + case 10: + if (val > 0x3FF) + return -EINVAL; + break; + case 12: + if (val > 0xFFF) + return -EINVAL; + break; + } + + switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + case IIO_EV_DIR_FALLING: + st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val; + break; + case IIO_EV_DIR_RISING: + st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val; + break; + } + + return 0; +} + +static irqreturn_t max1363_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct max1363_state *st = iio_priv(indio_dev); + s64 timestamp = iio_get_time_ns(); + u8 rx; + u8 tx[2] = { st->setupbyte, + MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 }; + + i2c_master_recv(st->client, &rx, 1); + /* todo - begging for use of for_each_set_bit */ + if (rx & (1 << 0)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(3), + timestamp); + if (rx & (1 << 1)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(3), + timestamp); + if (rx & (1 << 2)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(2), + timestamp); + if (rx & (1 << 3)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(2), + timestamp); + if (rx & (1 << 4)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(1), + timestamp); + if (rx & (1 << 5)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(1), + timestamp); + if (rx & (1 << 6)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_LOW_THRESH(0), + timestamp); + if (rx & (1 << 7)) + iio_push_event(indio_dev, 0, + IIO_EVENT_CODE_IN_HIGH_THRESH(0), + timestamp); + i2c_master_send(st->client, tx, 2); + + return IRQ_HANDLED; +} + +static int max1363_read_event_config(struct iio_dev *indio_dev, + int event_code) +{ + struct max1363_state *st = iio_priv(indio_dev); + + int val; + int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code); + mutex_lock(&indio_dev->mlock); + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) + val = (1 << number) & st->mask_low; + else + val = (1 << number) & st->mask_high; + mutex_unlock(&indio_dev->mlock); + + return val; +} + +static int max1363_monitor_mode_update(struct max1363_state *st, int enabled) +{ + u8 *tx_buf; + int ret, i = 3, j; + unsigned long numelements; + int len; + long modemask; + + if (!enabled) { + /* transition to ring capture is not currently supported */ + st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP; + st->configbyte &= ~MAX1363_SCAN_MASK; + st->monitor_on = false; + return max1363_write_basic_config(st->client, + st->setupbyte, + st->configbyte); + } + + /* Ensure we are in the relevant mode */ + st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP; + st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK + | MAX1363_SCAN_MASK + | MAX1363_SE_DE_MASK); + st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE; + if ((st->mask_low | st->mask_high) & 0x0F) { + st->configbyte |= max1363_mode_table[s0to3].conf; + modemask = max1363_mode_table[s0to3].modemask; + } else if ((st->mask_low | st->mask_high) & 0x30) { + st->configbyte |= max1363_mode_table[d0m1to2m3].conf; + modemask = max1363_mode_table[d0m1to2m3].modemask; + } else { + st->configbyte |= max1363_mode_table[d1m0to3m2].conf; + modemask = max1363_mode_table[d1m0to3m2].modemask; + } + numelements = hweight_long(modemask); + len = 3 * numelements + 3; + tx_buf = kmalloc(len, GFP_KERNEL); + if (!tx_buf) { + ret = -ENOMEM; + goto error_ret; + } + tx_buf[0] = st->configbyte; + tx_buf[1] = st->setupbyte; + tx_buf[2] = (st->monitor_speed << 1); + + /* + * So we need to do yet another bit of nefarious scan mode + * setup to match what we need. + */ + for (j = 0; j < 8; j++) + if (modemask & (1 << j)) { + /* Establish the mode is in the scan */ + if (st->mask_low & (1 << j)) { + tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF; + tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0; + } else if (j < 4) { + tx_buf[i] = 0; + tx_buf[i + 1] = 0; + } else { + tx_buf[i] = 0x80; + tx_buf[i + 1] = 0; + } + if (st->mask_high & (1 << j)) { + tx_buf[i + 1] |= + (st->thresh_high[j] >> 8) & 0x0F; + tx_buf[i + 2] = st->thresh_high[j] & 0xFF; + } else if (j < 4) { + tx_buf[i + 1] |= 0x0F; + tx_buf[i + 2] = 0xFF; + } else { + tx_buf[i + 1] |= 0x07; + tx_buf[i + 2] = 0xFF; + } + i += 3; + } + + + ret = i2c_master_send(st->client, tx_buf, len); + if (ret < 0) + goto error_ret; + if (ret != len) { + ret = -EIO; + goto error_ret; + } + + /* + * Now that we hopefully have sensible thresholds in place it is + * time to turn the interrupts on. + * It is unclear from the data sheet if this should be necessary + * (i.e. whether monitor mode setup is atomic) but it appears to + * be in practice. + */ + tx_buf[0] = st->setupbyte; + tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0; + ret = i2c_master_send(st->client, tx_buf, 2); + if (ret < 0) + goto error_ret; + if (ret != 2) { + ret = -EIO; + goto error_ret; + } + ret = 0; + st->monitor_on = true; +error_ret: + + kfree(tx_buf); + + return ret; +} + +/* + * To keep this manageable we always use one of 3 scan modes. + * Scan 0...3, 0-1,2-3 and 1-0,3-2 + */ + +static inline int __max1363_check_event_mask(int thismask, int checkmask) +{ + int ret = 0; + /* Is it unipolar */ + if (thismask < 4) { + if (checkmask & ~0x0F) { + ret = -EBUSY; + goto error_ret; + } + } else if (thismask < 6) { + if (checkmask & ~0x30) { + ret = -EBUSY; + goto error_ret; + } + } else if (checkmask & ~0xC0) + ret = -EBUSY; +error_ret: + return ret; +} + +static int max1363_write_event_config(struct iio_dev *indio_dev, + int event_code, + int state) +{ + int ret = 0; + struct max1363_state *st = iio_priv(indio_dev); + u16 unifiedmask; + int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code); + + mutex_lock(&indio_dev->mlock); + unifiedmask = st->mask_low | st->mask_high; + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) { + + if (state == 0) + st->mask_low &= ~(1 << number); + else { + ret = __max1363_check_event_mask((1 << number), + unifiedmask); + if (ret) + goto error_ret; + st->mask_low |= (1 << number); + } + } else { + if (state == 0) + st->mask_high &= ~(1 << number); + else { + ret = __max1363_check_event_mask((1 << number), + unifiedmask); + if (ret) + goto error_ret; + st->mask_high |= (1 << number); + } + } + + max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); +error_ret: + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +/* + * As with scan_elements, only certain sets of these can + * be combined. + */ +static struct attribute *max1363_event_attributes[] = { + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static struct attribute_group max1363_event_attribute_group = { + .attrs = max1363_event_attributes, +}; + +#define MAX1363_EVENT_FUNCS \ + + +static const struct iio_info max1238_info = { + .read_raw = &max1363_read_raw, + .driver_module = THIS_MODULE, +}; + +static const struct iio_info max1363_info = { + .read_event_value = &max1363_read_thresh, + .write_event_value = &max1363_write_thresh, + .read_event_config = &max1363_read_event_config, + .write_event_config = &max1363_write_event_config, + .read_raw = &max1363_read_raw, + .driver_module = THIS_MODULE, + .num_interrupt_lines = 1, + .event_attrs = &max1363_event_attribute_group, +}; + /* max1363 and max1368 tested - rest from data sheet */ static const struct max1363_chip_info max1363_chip_info_tbl[] = { [max1361] = { .bits = 10, .int_vref_mv = 2048, - .monitor_mode = 1, .mode_list = max1363_mode_list, .num_modes = ARRAY_SIZE(max1363_mode_list), .default_mode = s0to3, .channels = max1361_channels, .num_channels = ARRAY_SIZE(max1361_channels), + .info = &max1363_info, }, [max1362] = { .bits = 10, .int_vref_mv = 4096, - .monitor_mode = 1, .mode_list = max1363_mode_list, .num_modes = ARRAY_SIZE(max1363_mode_list), .default_mode = s0to3, .channels = max1361_channels, .num_channels = ARRAY_SIZE(max1361_channels), + .info = &max1363_info, }, [max1363] = { .bits = 12, .int_vref_mv = 2048, - .monitor_mode = 1, .mode_list = max1363_mode_list, .num_modes = ARRAY_SIZE(max1363_mode_list), .default_mode = s0to3, .channels = max1363_channels, .num_channels = ARRAY_SIZE(max1363_channels), + .info = &max1363_info, }, [max1364] = { .bits = 12, .int_vref_mv = 4096, - .monitor_mode = 1, .mode_list = max1363_mode_list, .num_modes = ARRAY_SIZE(max1363_mode_list), .default_mode = s0to3, .channels = max1363_channels, .num_channels = ARRAY_SIZE(max1363_channels), + .info = &max1363_info, }, [max1036] = { .bits = 8, @@ -520,6 +882,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1236_mode_list, .num_modes = ARRAY_SIZE(max1236_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1036_channels, .num_channels = ARRAY_SIZE(max1036_channels), }, @@ -529,6 +892,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1236_mode_list, .num_modes = ARRAY_SIZE(max1236_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1036_channels, .num_channels = ARRAY_SIZE(max1036_channels), }, @@ -538,6 +902,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1038_channels, .num_channels = ARRAY_SIZE(max1038_channels), }, @@ -547,6 +912,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1038_channels, .num_channels = ARRAY_SIZE(max1038_channels), }, @@ -556,6 +922,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1236_mode_list, .num_modes = ARRAY_SIZE(max1236_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1136_channels, .num_channels = ARRAY_SIZE(max1136_channels), }, @@ -565,6 +932,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1236_mode_list, .num_modes = ARRAY_SIZE(max1236_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1136_channels, .num_channels = ARRAY_SIZE(max1136_channels), }, @@ -574,6 +942,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1138_channels, .num_channels = ARRAY_SIZE(max1138_channels), }, @@ -583,6 +952,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1138_channels, .num_channels = ARRAY_SIZE(max1138_channels), }, @@ -592,6 +962,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1236_mode_list, .num_modes = ARRAY_SIZE(max1236_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1236_channels, .num_channels = ARRAY_SIZE(max1236_channels), }, @@ -601,6 +972,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1236_mode_list, .num_modes = ARRAY_SIZE(max1236_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1236_channels, .num_channels = ARRAY_SIZE(max1236_channels), }, @@ -610,6 +982,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -619,6 +992,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -628,6 +1002,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11607_mode_list, .num_modes = ARRAY_SIZE(max11607_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1036_channels, .num_channels = ARRAY_SIZE(max1036_channels), }, @@ -637,6 +1012,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11607_mode_list, .num_modes = ARRAY_SIZE(max11607_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1036_channels, .num_channels = ARRAY_SIZE(max1036_channels), }, @@ -646,6 +1022,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11608_mode_list, .num_modes = ARRAY_SIZE(max11608_mode_list), .default_mode = s0to7, + .info = &max1238_info, .channels = max11602_channels, .num_channels = ARRAY_SIZE(max11602_channels), }, @@ -655,6 +1032,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11608_mode_list, .num_modes = ARRAY_SIZE(max11608_mode_list), .default_mode = s0to7, + .info = &max1238_info, .channels = max11602_channels, .num_channels = ARRAY_SIZE(max11602_channels), }, @@ -664,6 +1042,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -673,6 +1052,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -682,6 +1062,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11607_mode_list, .num_modes = ARRAY_SIZE(max11607_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1136_channels, .num_channels = ARRAY_SIZE(max1136_channels), }, @@ -691,6 +1072,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11607_mode_list, .num_modes = ARRAY_SIZE(max11607_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1136_channels, .num_channels = ARRAY_SIZE(max1136_channels), }, @@ -700,6 +1082,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11608_mode_list, .num_modes = ARRAY_SIZE(max11608_mode_list), .default_mode = s0to7, + .info = &max1238_info, .channels = max11608_channels, .num_channels = ARRAY_SIZE(max11608_channels), }, @@ -709,6 +1092,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11608_mode_list, .num_modes = ARRAY_SIZE(max11608_mode_list), .default_mode = s0to7, + .info = &max1238_info, .channels = max11608_channels, .num_channels = ARRAY_SIZE(max11608_channels), }, @@ -718,6 +1102,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -727,6 +1112,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -736,6 +1122,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11607_mode_list, .num_modes = ARRAY_SIZE(max11607_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1363_channels, .num_channels = ARRAY_SIZE(max1363_channels), }, @@ -745,6 +1132,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11607_mode_list, .num_modes = ARRAY_SIZE(max11607_mode_list), .default_mode = s0to3, + .info = &max1238_info, .channels = max1363_channels, .num_channels = ARRAY_SIZE(max1363_channels), }, @@ -754,6 +1142,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11608_mode_list, .num_modes = ARRAY_SIZE(max11608_mode_list), .default_mode = s0to7, + .info = &max1238_info, .channels = max11614_channels, .num_channels = ARRAY_SIZE(max11614_channels), }, @@ -763,6 +1152,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11608_mode_list, .num_modes = ARRAY_SIZE(max11608_mode_list), .default_mode = s0to7, + .info = &max1238_info, .channels = max11614_channels, .num_channels = ARRAY_SIZE(max11614_channels), }, @@ -772,6 +1162,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -781,6 +1172,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, + .info = &max1238_info, .channels = max1238_channels, .num_channels = ARRAY_SIZE(max1238_channels), }, @@ -790,6 +1182,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11644_mode_list, .num_modes = ARRAY_SIZE(max11644_mode_list), .default_mode = s0to1, + .info = &max1238_info, .channels = max11644_channels, .num_channels = ARRAY_SIZE(max11644_channels), }, @@ -799,6 +1192,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11644_mode_list, .num_modes = ARRAY_SIZE(max11644_mode_list), .default_mode = s0to1, + .info = &max1238_info, .channels = max11644_channels, .num_channels = ARRAY_SIZE(max11644_channels), }, @@ -808,7 +1202,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11644_mode_list, .num_modes = ARRAY_SIZE(max11644_mode_list), .default_mode = s0to1, - .channels = max11644_channels, + .info = &max1238_info, + .channels = max11646_channels, .num_channels = ARRAY_SIZE(max11646_channels), }, [max11647] = { @@ -817,353 +1212,13 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { .mode_list = max11644_mode_list, .num_modes = ARRAY_SIZE(max11644_mode_list), .default_mode = s0to1, - .channels = max11644_channels, + .info = &max1238_info, + .channels = max11646_channels, .num_channels = ARRAY_SIZE(max11646_channels), }, }; -static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600, - 8300, 4200, 2000, 1000 }; - -static ssize_t max1363_monitor_show_freq(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct max1363_state *st = iio_priv(dev_get_drvdata(dev)); - return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]); -} - -static ssize_t max1363_monitor_store_freq(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct max1363_state *st = iio_priv(indio_dev); - int i, ret; - unsigned long val; - bool found = false; - - ret = strict_strtoul(buf, 10, &val); - if (ret) - return -EINVAL; - for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++) - if (val == max1363_monitor_speeds[i]) { - found = true; - break; - } - if (!found) - return -EINVAL; - - mutex_lock(&indio_dev->mlock); - st->monitor_speed = i; - mutex_unlock(&indio_dev->mlock); - - return 0; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, - max1363_monitor_show_freq, - max1363_monitor_store_freq); - -static IIO_CONST_ATTR(sampling_frequency_available, - "133000 665000 33300 16600 8300 4200 2000 1000"); - -static int max1363_read_thresh(struct iio_dev *indio_dev, - int event_code, - int *val) -{ - struct max1363_state *st = iio_priv(indio_dev); - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) - *val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]; - else - *val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]; - return 0; -} - -static int max1363_write_thresh(struct iio_dev *indio_dev, - int event_code, - int val) -{ - struct max1363_state *st = iio_priv(indio_dev); - /* make it handle signed correctly as well */ - switch (st->chip_info->bits) { - case 10: - if (val > 0x3FF) - return -EINVAL; - break; - case 12: - if (val > 0xFFF) - return -EINVAL; - break; - } - - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { - case IIO_EV_DIR_FALLING: - st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val; - break; - case IIO_EV_DIR_RISING: - st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val; - break; - } - - return 0; -} -static irqreturn_t max1363_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct max1363_state *st = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(); - u8 rx; - u8 tx[2] = { st->setupbyte, - MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 }; - - i2c_master_recv(st->client, &rx, 1); - /* todo - begging for use of for_each_set_bit */ - if (rx & (1 << 0)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_LOW_THRESH(3), - timestamp); - if (rx & (1 << 1)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_HIGH_THRESH(3), - timestamp); - if (rx & (1 << 2)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_LOW_THRESH(2), - timestamp); - if (rx & (1 << 3)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_HIGH_THRESH(2), - timestamp); - if (rx & (1 << 4)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_LOW_THRESH(1), - timestamp); - if (rx & (1 << 5)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_HIGH_THRESH(1), - timestamp); - if (rx & (1 << 6)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_LOW_THRESH(0), - timestamp); - if (rx & (1 << 7)) - iio_push_event(indio_dev, 0, - IIO_EVENT_CODE_IN_HIGH_THRESH(0), - timestamp); - i2c_master_send(st->client, tx, 2); - - return IRQ_HANDLED; -} - -static int max1363_read_event_config(struct iio_dev *indio_dev, - int event_code) -{ - struct max1363_state *st = iio_priv(indio_dev); - - int val; - int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code); - mutex_lock(&indio_dev->mlock); - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) - val = (1 << number) & st->mask_low; - else - val = (1 << number) & st->mask_high; - mutex_unlock(&indio_dev->mlock); - - return val; -} - -static int max1363_monitor_mode_update(struct max1363_state *st, int enabled) -{ - u8 *tx_buf; - int ret, i = 3, j; - unsigned long numelements; - int len; - long modemask; - - if (!enabled) { - /* transition to ring capture is not currently supported */ - st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP; - st->configbyte &= ~MAX1363_SCAN_MASK; - st->monitor_on = false; - return max1363_write_basic_config(st->client, - st->setupbyte, - st->configbyte); - } - - /* Ensure we are in the relevant mode */ - st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP; - st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK - | MAX1363_SCAN_MASK - | MAX1363_SE_DE_MASK); - st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE; - if ((st->mask_low | st->mask_high) & 0x0F) { - st->configbyte |= max1363_mode_table[s0to3].conf; - modemask = max1363_mode_table[s0to3].modemask; - } else if ((st->mask_low | st->mask_high) & 0x30) { - st->configbyte |= max1363_mode_table[d0m1to2m3].conf; - modemask = max1363_mode_table[d0m1to2m3].modemask; - } else { - st->configbyte |= max1363_mode_table[d1m0to3m2].conf; - modemask = max1363_mode_table[d1m0to3m2].modemask; - } - numelements = hweight_long(modemask); - len = 3 * numelements + 3; - tx_buf = kmalloc(len, GFP_KERNEL); - if (!tx_buf) { - ret = -ENOMEM; - goto error_ret; - } - tx_buf[0] = st->configbyte; - tx_buf[1] = st->setupbyte; - tx_buf[2] = (st->monitor_speed << 1); - - /* - * So we need to do yet another bit of nefarious scan mode - * setup to match what we need. - */ - for (j = 0; j < 8; j++) - if (modemask & (1 << j)) { - /* Establish the mode is in the scan */ - if (st->mask_low & (1 << j)) { - tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF; - tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0; - } else if (j < 4) { - tx_buf[i] = 0; - tx_buf[i + 1] = 0; - } else { - tx_buf[i] = 0x80; - tx_buf[i + 1] = 0; - } - if (st->mask_high & (1 << j)) { - tx_buf[i + 1] |= - (st->thresh_high[j] >> 8) & 0x0F; - tx_buf[i + 2] = st->thresh_high[j] & 0xFF; - } else if (j < 4) { - tx_buf[i + 1] |= 0x0F; - tx_buf[i + 2] = 0xFF; - } else { - tx_buf[i + 1] |= 0x07; - tx_buf[i + 2] = 0xFF; - } - i += 3; - } - - - ret = i2c_master_send(st->client, tx_buf, len); - if (ret < 0) - goto error_ret; - if (ret != len) { - ret = -EIO; - goto error_ret; - } - - /* - * Now that we hopefully have sensible thresholds in place it is - * time to turn the interrupts on. - * It is unclear from the data sheet if this should be necessary - * (i.e. whether monitor mode setup is atomic) but it appears to - * be in practice. - */ - tx_buf[0] = st->setupbyte; - tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0; - ret = i2c_master_send(st->client, tx_buf, 2); - if (ret < 0) - goto error_ret; - if (ret != 2) { - ret = -EIO; - goto error_ret; - } - ret = 0; - st->monitor_on = true; -error_ret: - - kfree(tx_buf); - - return ret; -} - -/* - * To keep this manageable we always use one of 3 scan modes. - * Scan 0...3, 0-1,2-3 and 1-0,3-2 - */ - -static inline int __max1363_check_event_mask(int thismask, int checkmask) -{ - int ret = 0; - /* Is it unipolar */ - if (thismask < 4) { - if (checkmask & ~0x0F) { - ret = -EBUSY; - goto error_ret; - } - } else if (thismask < 6) { - if (checkmask & ~0x30) { - ret = -EBUSY; - goto error_ret; - } - } else if (checkmask & ~0xC0) - ret = -EBUSY; -error_ret: - return ret; -} - -static int max1363_write_event_config(struct iio_dev *indio_dev, - int event_code, - int state) -{ - int ret = 0; - struct max1363_state *st = iio_priv(indio_dev); - u16 unifiedmask; - int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code); - - mutex_lock(&indio_dev->mlock); - unifiedmask = st->mask_low | st->mask_high; - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) { - - if (state == 0) - st->mask_low &= ~(1 << number); - else { - ret = __max1363_check_event_mask((1 << number), - unifiedmask); - if (ret) - goto error_ret; - st->mask_low |= (1 << number); - } - } else { - if (state == 0) - st->mask_high &= ~(1 << number); - else { - ret = __max1363_check_event_mask((1 << number), - unifiedmask); - if (ret) - goto error_ret; - st->mask_high |= (1 << number); - } - } - - max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); -error_ret: - mutex_unlock(&indio_dev->mlock); - - return ret; -} - -/* - * As with scan_elements, only certain sets of these can - * be combined. - */ -static struct attribute *max1363_event_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static struct attribute_group max1363_event_attribute_group = { - .attrs = max1363_event_attributes, -}; static int max1363_initial_setup(struct max1363_state *st) { @@ -1224,22 +1279,9 @@ static int __devinit max1363_probe(struct i2c_client *client, /* Estabilish that the iio_dev is a child of the i2c device */ indio_dev->dev.parent = &client->dev; indio_dev->name = id->name; - indio_dev->read_event_value = &max1363_read_thresh; - indio_dev->write_event_value = &max1363_write_thresh; - indio_dev->read_event_config = &max1363_read_event_config; - indio_dev->write_event_config = &max1363_write_event_config; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = st->chip_info->num_channels; - indio_dev->read_raw = &max1363_read_raw; - /* Todo: this shouldn't be here. */ - indio_dev->driver_module = THIS_MODULE; - indio_dev->modes = INDIO_DIRECT_MODE; - if (st->chip_info->monitor_mode && client->irq) { - indio_dev->num_interrupt_lines = 1; - indio_dev->event_attrs - = &max1363_event_attribute_group; - } + indio_dev->info = st->chip_info->info; + indio_dev->modes = INDIO_DIRECT_MODE; ret = max1363_initial_setup(st); if (ret) goto error_free_available_scan_masks; @@ -1258,7 +1300,7 @@ static int __devinit max1363_probe(struct i2c_client *client, if (ret) goto error_cleanup_ring; - if (st->chip_info->monitor_mode && client->irq) { + if (client->irq) { ret = request_threaded_irq(st->client->irq, NULL, &max1363_event_handler, @@ -1298,7 +1340,7 @@ static int max1363_remove(struct i2c_client *client) struct max1363_state *st = iio_priv(indio_dev); struct regulator *reg = st->reg; - if (st->chip_info->monitor_mode && client->irq) + if (client->irq) free_irq(st->client->irq, indio_dev); iio_ring_buffer_unregister(indio_dev->ring); max1363_ring_cleanup(indio_dev); |