/* * Writes the given data to the given register address. * * If the mode is configurable, the device will first be placed in * configuration mode.
*/ staticint ad2s1210_regmap_reg_write(void *context, unsignedint reg, unsignedint val)
{ struct ad2s1210_state *st = context; struct spi_transfer xfers[] = {
{
.len = 1,
.rx_buf = &st->rx[0],
.tx_buf = &st->tx[0],
.cs_change = 1,
}, {
.len = 1,
.rx_buf = &st->rx[1],
.tx_buf = &st->tx[1],
},
}; int ret;
/* values can only be 7 bits, the MSB indicates an address */ if (val & ~0x7F) return -EINVAL;
st->tx[0] = reg;
st->tx[1] = val;
ret = ad2s1210_set_mode(st, MOD_CONFIG); if (ret < 0) return ret;
ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); if (ret < 0) return ret;
/* soft reset also clears the fault register */ if (reg == AD2S1210_REG_SOFT_RESET)
st->prev_fault_flags = 0;
return 0;
}
/* * Reads value from one of the registers. * * If the mode is configurable, the device will first be placed in * configuration mode.
*/ staticint ad2s1210_regmap_reg_read(void *context, unsignedint reg, unsignedint *val)
{ struct ad2s1210_state *st = context; struct spi_transfer xfers[] = {
{
.len = 1,
.rx_buf = &st->rx[0],
.tx_buf = &st->tx[0],
.cs_change = 1,
}, {
.len = 1,
.rx_buf = &st->rx[1],
.tx_buf = &st->tx[1],
},
}; int ret;
ret = ad2s1210_set_mode(st, MOD_CONFIG); if (ret < 0) return ret;
st->tx[0] = reg; /* * Must be valid register address here otherwise this could write data. * It doesn't matter which one as long as reading doesn't have side- * effects.
*/
st->tx[1] = AD2S1210_REG_CONTROL;
ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); if (ret < 0) return ret;
/* reading the fault register also clears it */ if (reg == AD2S1210_REG_FAULT)
st->prev_fault_flags = 0;
/* * If the D7 bit is set on any read/write register, it indicates a * parity error. The fault register is read-only and the D7 bit means * something else there.
*/ if ((reg > AD2S1210_REG_VELOCITY_LSB && reg != AD2S1210_REG_FAULT)
&& st->rx[1] & AD2S1210_ADDRESS_DATA) return -EBADMSG;
*val = st->rx[1];
return 0;
}
/* * Toggles the SAMPLE line on the AD2S1210 to latch in the current position, * velocity, and faults. * * Must be called with lock held.
*/ staticvoid ad2s1210_toggle_sample_line(struct ad2s1210_state *st)
{ /* * Datasheet specifies minimum hold time t16 = 2 * tck + 20 ns. So the * longest time needed is when CLKIN is 6.144 MHz, in which case t16 * ~= 350 ns. The same delay is also needed before re-asserting the * SAMPLE line.
*/
gpiod_set_value(st->sample_gpio, 1);
ndelay(350);
gpiod_set_value(st->sample_gpio, 0);
ndelay(350);
}
/* * Sets the excitation frequency and performs software reset. * * Must be called with lock held.
*/ staticint ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st,
u16 fexcit)
{ /* Map resolution to settle time in milliseconds. */ staticconstint track_time_ms[] = { 10, 20, 25, 60 }; unsignedint ignored; int ret;
u8 fcw;
ret = regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw); if (ret < 0) return ret;
/* * Software reset reinitializes the excitation frequency output. * It does not reset any of the configuration registers.
*/
ret = regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); if (ret < 0) return ret;
/* * Soft reset always triggers some faults due the change in the output * signal so clear the faults too. We need to delay for some time * (what datasheet calls t[track]) to allow things to settle before * clearing the faults.
*/
msleep(track_time_ms[st->resolution] * 8192000 / st->clkin_hz);
/* Reading the fault register clears the faults. */
ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &ignored); if (ret < 0) return ret;
/* Have to toggle sample line to get fault output pins to reset. */
ad2s1210_toggle_sample_line(st);
/* Sine/cosine inputs clipped */ if (FAULT_ONESHOT(AD2S1210_FAULT_CLIP, flags, st->prev_fault_flags)) { /* * The chip does not differentiate between fault on sine vs. * cosine channel so we just send an event on both channels.
*/
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 1,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_EITHER),
timestamp);
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 2,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_EITHER),
timestamp);
}
/* Sine/cosine inputs below LOS threshold */ if (FAULT_ONESHOT(AD2S1210_FAULT_LOS, flags, st->prev_fault_flags))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
timestamp);
/* Sine/cosine inputs exceed DOS overrange threshold */ if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_OVR, flags, st->prev_fault_flags))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
timestamp);
/* Sine/cosine inputs exceed DOS mismatch threshold */ if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_MIS, flags, st->prev_fault_flags))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_RISING),
timestamp);
/* Tracking error exceeds LOT threshold */ if (FAULT_ONESHOT(AD2S1210_FAULT_LOT, flags, st->prev_fault_flags))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_ANGL, 1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
timestamp);
/* Velocity exceeds maximum tracking rate */ if (FAULT_ONESHOT(AD2S1210_FAULT_VELOCITY, flags, st->prev_fault_flags))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_ANGL_VEL, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
timestamp);
/* Phase error exceeds phase lock range */ if (FAULT_ONESHOT(AD2S1210_FAULT_PHASE, flags, st->prev_fault_flags))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PHASE, 0,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_RISING),
timestamp);
/* Configuration parity error */ if (FAULT_ONESHOT(AD2S1210_FAULT_CONFIG_PARITY, flags,
st->prev_fault_flags)) /* * Userspace should also get notified of this via error return * when trying to write to any attribute that writes a register.
*/
dev_err_ratelimited(&indio_dev->dev, "Configuration parity error\n");
st->prev_fault_flags = flags;
}
staticint ad2s1210_single_conversion(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val)
{ struct ad2s1210_state *st = iio_priv(indio_dev);
s64 timestamp; int ret;
staticint ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st, int val, int val2)
{ unsignedint high_reg_val, low_reg_val, hysteresis; int ret;
/* all valid values are between 0 and pi/4 radians */ if (val != 0) return -EINVAL;
guard(mutex)(&st->lock); /* * We need to read both high and low registers first so we can preserve * the hysteresis.
*/
ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); if (ret < 0) return ret;
ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); if (ret < 0) return ret;
staticint ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st, int *val, int *val2)
{ unsignedint high_reg_val, low_reg_val; int ret;
guard(mutex)(&st->lock);
ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); if (ret < 0) return ret;
ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); if (ret < 0) return ret;
/* sysfs value is hysteresis rather than actual low value */
*val = 0;
*val2 = (high_reg_val - low_reg_val) *
ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; return IIO_VAL_INT_PLUS_MICRO;
}
staticint ad2s1210_set_lot_low_threshold(struct ad2s1210_state *st, int val, int val2)
{ unsignedint reg_val, hysteresis; int ret;
/* all valid values are between 0 and pi/4 radians */ if (val != 0) return -EINVAL;
staticint ad2s1210_initial(struct ad2s1210_state *st)
{ unsignedint data; int ret;
guard(mutex)(&st->lock);
/* Use default config register value plus resolution from devicetree. */
data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1);
data |= FIELD_PREP(AD2S1210_ENABLE_HYSTERESIS, 1);
data |= FIELD_PREP(AD2S1210_SET_ENRES, 0x3);
data |= FIELD_PREP(AD2S1210_SET_RES, st->resolution);
ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); if (ret < 0) return ret;
ret = device_property_read_string(dev, "adi,fixed-mode", &str_val); if (ret == -EINVAL)
st->fixed_mode = -1; elseif (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, "failed to read assigned-resolution-bits property\n");
if (val < 10 || val > 16) return dev_err_probe(dev, -EINVAL, "resolution out of range: %u\n", val);
st->resolution = (val - 10) >> 1; /* * These are values that correlate to the hysteresis bit in the Control * register. 0 = disabled, 1 = enabled. When enabled, the actual * hysteresis is +/- 1 LSB of the raw position value. Which bit is the * LSB depends on the specified resolution.
*/
st->hysteresis_available[0] = 0;
st->hysteresis_available[1] = 1 << (2 * (AD2S1210_RES_16 -
st->resolution));
/* should not be sampling on startup */
st->sample_gpio = devm_gpiod_get(dev, "sample", GPIOD_OUT_LOW); if (IS_ERR(st->sample_gpio)) return dev_err_probe(dev, PTR_ERR(st->sample_gpio), "failed to request sample GPIO\n");
/* both pins high means that we start in config mode */
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 && 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 resolution gpios are provided, they get set to the required * resolution, otherwise it is assumed the RES0 and RES1 pins are * hard-wired to match the resolution indicated in the devicetree.
*/
resolution_gpios = devm_gpiod_get_array_optional(dev, "resolution",
GPIOD_ASIS); if (IS_ERR(resolution_gpios)) return dev_err_probe(dev, PTR_ERR(resolution_gpios), "failed to request resolution GPIOs\n");
if (resolution_gpios) { if (resolution_gpios->ndescs != 2) return dev_err_probe(dev, -EINVAL, "requires exactly 2 resolution-gpios\n");
bitmap_write(bitmap, st->resolution, 0, 2);
ret = gpiod_multi_set_value_cansleep(resolution_gpios, bitmap); if (ret < 0) return dev_err_probe(dev, ret, "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);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.