summaryrefslogtreecommitdiffstats
path: root/drivers/iio/resolver/ad2s1210.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
commit01a69402cf9d38ff180345d55c2ee51c7e89fbc7 (patch)
treeb406c5242a088c4f59c6e4b719b783f43aca6ae9 /drivers/iio/resolver/ad2s1210.c
parentAdding upstream version 6.7.12. (diff)
downloadlinux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.tar.xz
linux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.zip
Adding upstream version 6.8.9.upstream/6.8.9
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/iio/resolver/ad2s1210.c')
-rw-r--r--drivers/iio/resolver/ad2s1210.c162
1 files changed, 131 insertions, 31 deletions
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
index 1bd1b950e7..a414eef12e 100644
--- a/drivers/iio/resolver/ad2s1210.c
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -141,7 +141,7 @@ struct ad2s1210_state {
struct spi_device *sdev;
/** GPIO pin connected to SAMPLE line. */
struct gpio_desc *sample_gpio;
- /** GPIO pins connected to A0 and A1 lines. */
+ /** GPIO pins connected to A0 and A1 lines (optional). */
struct gpio_descs *mode_gpios;
/** Used to access config registers. */
struct regmap *regmap;
@@ -149,6 +149,8 @@ struct ad2s1210_state {
unsigned long clkin_hz;
/** Available raw hysteresis values based on resolution. */
int hysteresis_available[2];
+ /* adi,fixed-mode property - only valid when mode_gpios == NULL. */
+ enum ad2s1210_mode fixed_mode;
/** The selected resolution */
enum ad2s1210_resolution resolution;
/** Copy of fault register from the previous read. */
@@ -175,6 +177,9 @@ static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode mode)
struct gpio_descs *gpios = st->mode_gpios;
DECLARE_BITMAP(bitmap, 2);
+ if (!gpios)
+ return mode == st->fixed_mode ? 0 : -EOPNOTSUPP;
+
bitmap[0] = mode;
return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info,
@@ -276,7 +281,8 @@ static int ad2s1210_regmap_reg_read(void *context, unsigned int reg,
* parity error. The fault register is read-only and the D7 bit means
* something else there.
*/
- if (reg != AD2S1210_REG_FAULT && st->rx[1] & AD2S1210_ADDRESS_DATA)
+ if ((reg > AD2S1210_REG_VELOCITY_LSB && reg != AD2S1210_REG_FAULT)
+ && st->rx[1] & AD2S1210_ADDRESS_DATA)
return -EBADMSG;
*val = st->rx[1];
@@ -450,21 +456,53 @@ static int ad2s1210_single_conversion(struct iio_dev *indio_dev,
ad2s1210_toggle_sample_line(st);
timestamp = iio_get_time_ns(indio_dev);
- switch (chan->type) {
- case IIO_ANGL:
- ret = ad2s1210_set_mode(st, MOD_POS);
- break;
- case IIO_ANGL_VEL:
- ret = ad2s1210_set_mode(st, MOD_VEL);
- break;
- default:
- return -EINVAL;
+ if (st->fixed_mode == MOD_CONFIG) {
+ unsigned int reg_val;
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_POSITION_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ return ret;
+
+ break;
+ case IIO_ANGL_VEL:
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_VELOCITY_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ return ret;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ st->sample.fault = reg_val;
+ } else {
+ switch (chan->type) {
+ case IIO_ANGL:
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ break;
+ case IIO_ANGL_VEL:
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret < 0)
+ return ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ return ret;
}
- if (ret < 0)
- return ret;
- ret = spi_read(st->sdev, &st->sample, 3);
- if (ret < 0)
- return ret;
switch (chan->type) {
case IIO_ANGL:
@@ -1252,27 +1290,53 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
ad2s1210_toggle_sample_line(st);
if (test_bit(0, indio_dev->active_scan_mask)) {
- ret = ad2s1210_set_mode(st, MOD_POS);
- if (ret < 0)
- goto error_ret;
-
- ret = spi_read(st->sdev, &st->sample, 3);
- if (ret < 0)
- goto error_ret;
+ if (st->fixed_mode == MOD_CONFIG) {
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_POSITION_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ goto error_ret;
+ } else {
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+ }
memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
}
if (test_bit(1, indio_dev->active_scan_mask)) {
- ret = ad2s1210_set_mode(st, MOD_VEL);
- if (ret < 0)
- goto error_ret;
+ if (st->fixed_mode == MOD_CONFIG) {
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_VELOCITY_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ goto error_ret;
+ } else {
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+ }
- ret = spi_read(st->sdev, &st->sample, 3);
+ memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ }
+
+ if (st->fixed_mode == MOD_CONFIG) {
+ unsigned int reg_val;
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &reg_val);
if (ret < 0)
- goto error_ret;
+ return ret;
- memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ st->sample.fault = reg_val;
}
ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp);
@@ -1299,9 +1363,24 @@ static const struct iio_info ad2s1210_info = {
static int ad2s1210_setup_properties(struct ad2s1210_state *st)
{
struct device *dev = &st->sdev->dev;
+ const char *str_val;
u32 val;
int ret;
+ ret = device_property_read_string(dev, "adi,fixed-mode", &str_val);
+ if (ret == -EINVAL)
+ st->fixed_mode = -1;
+ else if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to read adi,fixed-mode property\n");
+ else {
+ if (strcmp(str_val, "config"))
+ return dev_err_probe(dev, -EINVAL,
+ "only adi,fixed-mode=\"config\" is supported\n");
+
+ st->fixed_mode = MOD_CONFIG;
+ }
+
ret = device_property_read_u32(dev, "assigned-resolution-bits", &val);
if (ret < 0)
return dev_err_probe(dev, ret,
@@ -1347,6 +1426,7 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
{
struct device *dev = &st->sdev->dev;
struct gpio_descs *resolution_gpios;
+ struct gpio_desc *reset_gpio;
DECLARE_BITMAP(bitmap, 2);
int ret;
@@ -1357,12 +1437,21 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
"failed to request sample GPIO\n");
/* both pins high means that we start in config mode */
- st->mode_gpios = devm_gpiod_get_array(dev, "mode", GPIOD_OUT_HIGH);
+ st->mode_gpios = devm_gpiod_get_array_optional(dev, "mode",
+ GPIOD_OUT_HIGH);
if (IS_ERR(st->mode_gpios))
return dev_err_probe(dev, PTR_ERR(st->mode_gpios),
"failed to request mode GPIOs\n");
- if (st->mode_gpios->ndescs != 2)
+ if (!st->mode_gpios && st->fixed_mode == -1)
+ return dev_err_probe(dev, -EINVAL,
+ "must specify either adi,fixed-mode or mode-gpios\n");
+
+ if (st->mode_gpios && st->fixed_mode != -1)
+ return dev_err_probe(dev, -EINVAL,
+ "must specify only one of adi,fixed-mode or mode-gpios\n");
+
+ if (st->mode_gpios && st->mode_gpios->ndescs != 2)
return dev_err_probe(dev, -EINVAL,
"requires exactly 2 mode-gpios\n");
@@ -1393,6 +1482,17 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
"failed to set resolution gpios\n");
}
+ /* If the optional reset GPIO is present, toggle it to do a hard reset. */
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(reset_gpio),
+ "failed to request reset GPIO\n");
+
+ if (reset_gpio) {
+ udelay(10);
+ gpiod_set_value(reset_gpio, 0);
+ }
+
return 0;
}