diff options
-rw-r--r-- | drivers/staging/iio/resolver/ad2s1210.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 66ef35fbb6fe..83f6ac890dbc 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -56,6 +56,13 @@ #define AD2S1210_MIN_FCW 0x4 #define AD2S1210_MAX_FCW 0x50 +/* 44 degrees ~= 0.767945 radians */ +#define PHASE_44_DEG_TO_RAD_INT 0 +#define PHASE_44_DEG_TO_RAD_MICRO 767945 +/* 360 degrees ~= 6.283185 radians */ +#define PHASE_360_DEG_TO_RAD_INT 6 +#define PHASE_360_DEG_TO_RAD_MICRO 283185 + enum ad2s1210_mode { MOD_POS = 0b00, MOD_VEL = 0b01, @@ -379,6 +386,54 @@ static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val) return ret; } +static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st, + int *val, int *val2) +{ + int ret; + + mutex_lock(&st->lock); + ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44); + mutex_unlock(&st->lock); + + if (ret < 0) + return ret; + + if (ret) { + /* 44 degrees as radians */ + *val = PHASE_44_DEG_TO_RAD_INT; + *val2 = PHASE_44_DEG_TO_RAD_MICRO; + } else { + /* 360 degrees as radians */ + *val = PHASE_360_DEG_TO_RAD_INT; + *val2 = PHASE_360_DEG_TO_RAD_MICRO; + } + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st, + int val, int val2) +{ + int deg, ret; + + /* convert radians to degrees - only two allowable values */ + if (val == PHASE_44_DEG_TO_RAD_INT && val2 == PHASE_44_DEG_TO_RAD_MICRO) + deg = 44; + else if (val == PHASE_360_DEG_TO_RAD_INT && + val2 == PHASE_360_DEG_TO_RAD_MICRO) + deg = 360; + else + return -EINVAL; + + mutex_lock(&st->lock); + ret = regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44, + deg == 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0); + mutex_unlock(&st->lock); + return ret; +} + static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val) { unsigned int reg_val; @@ -551,6 +606,16 @@ static IIO_DEVICE_ATTR(lot_low_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_LOT_LOW_THRD); +static const struct iio_event_spec ad2s1210_phase_event_spec[] = { + { + /* Phase error fault. */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + /* Phase lock range. */ + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, +}; + static const struct iio_chan_spec ad2s1210_channels[] = { { .type = IIO_ANGL, @@ -568,6 +633,14 @@ static const struct iio_chan_spec ad2s1210_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), }, { + /* used to configure phase lock range and get phase lock error */ + .type = IIO_PHASE, + .indexed = 1, + .channel = 0, + .scan_index = -1, + .event_spec = ad2s1210_phase_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_phase_event_spec), + }, { /* excitation frequency output */ .type = IIO_ALTVOLTAGE, .indexed = 1, @@ -595,6 +668,21 @@ static const struct attribute_group ad2s1210_attribute_group = { .attrs = ad2s1210_attributes, }; +static IIO_CONST_ATTR(in_phase0_mag_rising_value_available, + __stringify(PHASE_44_DEG_TO_RAD_INT) "." + __stringify(PHASE_44_DEG_TO_RAD_MICRO) " " + __stringify(PHASE_360_DEG_TO_RAD_INT) "." + __stringify(PHASE_360_DEG_TO_RAD_MICRO)); + +static struct attribute *ad2s1210_event_attributes[] = { + &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad2s1210_event_attribute_group = { + .attrs = ad2s1210_event_attributes, +}; + static int ad2s1210_initial(struct ad2s1210_state *st) { unsigned char data; @@ -619,6 +707,40 @@ error_ret: return ret; } +static int ad2s1210_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_PHASE: + return ad2s1210_get_phase_lock_range(st, val, val2); + default: + return -EINVAL; + } +} + +static int ad2s1210_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_PHASE: + return ad2s1210_set_phase_lock_range(st, val, val2); + default: + return -EINVAL; + } +} + static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) @@ -639,10 +761,13 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, } static const struct iio_info ad2s1210_info = { + .event_attrs = &ad2s1210_event_attribute_group, .read_raw = ad2s1210_read_raw, .read_avail = ad2s1210_read_avail, .write_raw = ad2s1210_write_raw, .attrs = &ad2s1210_attribute_group, + .read_event_value = ad2s1210_read_event_value, + .write_event_value = ad2s1210_write_event_value, .debugfs_reg_access = &ad2s1210_debugfs_reg_access, }; |